Skip to content

Commit 36e8651

Browse files
author
mgricken
committed
Rewrote makeRelativeTo so that it does not return bogus paths
on Windows (or platforms with multiple file system roots anymore). If a path on drive D:\ should be made relative to something on path D:\, the function now simply returns the absolute path of the file to be made relative. That's as relative as it can get with multiple file systems. Updated properties to benefit from that. M src/edu/rice/cs/drjava/config/EagerFileListProperty.java M src/edu/rice/cs/drjava/ui/MainFrame.java M src/edu/rice/cs/util/FileOps.java git-svn-id: file:///tmp/test-svn/trunk@4390 fe72c1cf-3628-48e9-8b72-1c46755d3cff
1 parent 3b64166 commit 36e8651

File tree

3 files changed

+44
-8
lines changed

3 files changed

+44
-8
lines changed

drjava/src/edu/rice/cs/drjava/config/EagerFileListProperty.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import java.util.List;
4545
import java.io.File;
4646
import java.io.IOException;
47+
import edu.rice.cs.util.StringOps;
4748

4849
/** Class representing values that are always up-to-date and that
4950
* can be inserted as variables in external processes.
@@ -96,7 +97,8 @@ public void update() {
9697
for(OpenDefinitionsDocument odd: l) {
9798
sb.append(_attributes.get("sep"));
9899
try {
99-
File f = FileOps.makeRelativeTo(odd.getRawFile(), new File(_attributes.get("dir")));
100+
File f = FileOps.makeRelativeTo(odd.getRawFile(),
101+
new File(StringOps.unescapeSpacesWith1bHex(StringOps.replaceVariables(_attributes.get("dir"), PropertyMaps.ONLY, PropertyMaps.GET_CURRENT))));
100102
try {
101103
f = f.getCanonicalFile();
102104
}

drjava/src/edu/rice/cs/drjava/ui/MainFrame.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@
105105
import edu.rice.cs.util.swing.Utilities;
106106
import edu.rice.cs.util.swing.*;
107107
import edu.rice.cs.util.text.AbstractDocumentInterface;
108+
import edu.rice.cs.util.StringOps;
108109

109110
import static edu.rice.cs.drjava.config.OptionConstants.*;
110111
import edu.rice.cs.drjava.RemoteControlClient;
@@ -3344,7 +3345,7 @@ public void setUpDrJavaProperties() {
33443345
public void update() {
33453346
try {
33463347
File f = FileOps.makeRelativeTo(_model.getActiveDocument().getRawFile(),
3347-
new File(_attributes.get("dir")));
3348+
new File(StringOps.unescapeSpacesWith1bHex(StringOps.replaceVariables(_attributes.get("dir"), PropertyMaps.ONLY, PropertyMaps.GET_CURRENT))));
33483349
try {
33493350
f = f.getCanonicalFile();
33503351
}
@@ -3373,7 +3374,7 @@ public void update() {
33733374
}
33743375
else {
33753376
f = FileOps.makeRelativeTo(_model.getInteractionsModel().getWorkingDirectory(),
3376-
new File(_attributes.get("dir")));
3377+
new File(StringOps.unescapeSpacesWith1bHex(StringOps.replaceVariables(_attributes.get("dir"), PropertyMaps.ONLY, PropertyMaps.GET_CURRENT))));
33773378
_value = edu.rice.cs.util.StringOps.escapeSpacesWith1bHex(f.toString());
33783379
}
33793380
}
@@ -3445,13 +3446,14 @@ public void update() {
34453446
}
34463447
f = new File(dir, "DrJava-Execute-"+System.currentTimeMillis()+"-"+(_r.nextInt() & 0xffff)+".tmp");
34473448
if (!_attributes.get("dir").equals("")) {
3448-
f = new File(new File(_attributes.get("dir")),f.getName());
3449+
f = new File(StringOps.unescapeSpacesWith1bHex(StringOps.replaceVariables(_attributes.get("dir"), PropertyMaps.ONLY, PropertyMaps.GET_CURRENT)),
3450+
f.getName());
34493451
}
34503452
}
34513453
else {
34523454
File dir = new File(System.getProperty("java.io.tmpdir"));
34533455
if (!_attributes.get("dir").equals("")) {
3454-
dir = new File(_attributes.get("dir"));
3456+
dir = new File(StringOps.unescapeSpacesWith1bHex((StringOps.replaceVariables(_attributes.get("dir"), PropertyMaps.ONLY, PropertyMaps.GET_CURRENT))));
34553457
}
34563458
f = new File(dir, _attributes.get("name"));
34573459
}

drjava/src/edu/rice/cs/util/FileOps.java

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,19 @@ public void deleteOnExit() {}
139139
catch(IOException e) { return false; }
140140
}
141141

142+
/** Return true if the directory ancestor is an ancestor of the file f, i.e.
143+
* you can get from f to ancestor by using getParentFile zero or more times.
144+
* @param b the ancestor
145+
* @param f the file to test
146+
* @param true if b is an ancestor of f. */
147+
public static boolean isAncestorOf(File ancestor, File f) {
148+
ancestor = ancestor.getAbsoluteFile();
149+
f = f.getAbsoluteFile();
150+
while ((!ancestor.equals(f)) && (f!=null)) {
151+
f = f.getParentFile();
152+
}
153+
return (ancestor.equals(f));
154+
}
142155

143156
/** Makes a file equivalent to the given file f that is relative to base file b. In other words,
144157
* <code>new File(b,makeRelativeTo(base,abs)).getCanonicalPath()</code> equals
@@ -148,16 +161,35 @@ public void deleteOnExit() {}
148161
* <code>/home/username/folder/sublevel/file2.java</code>, then the resulting File path from this method would be
149162
* <code>../file.java</code> while its canoncial path would be <code>/home/username/folder/file.java</code>.</p>
150163
*
151-
* <p>Warning: this method is inherently broken, because it assumes a relative path exists between all
152-
* files. The Java file system model, however, supports multiple system roots (see {@link File#listRoots}).
153-
* Thus, two files from different "file systems" (in Windows, different drives) have no common parent.</p>
164+
* <p>Warning: making paths relative is inherently broken on some file systems, because a relative path
165+
* requires that both the file and the base have the same root. The Windows file system, and therefore also
166+
* the Java file system model, however, support multiple system roots (see {@link File#listRoots}).
167+
* Thus, two files with different roots cannot have a relative path. In that case the absolute path of
168+
* the file will be returned</p>
154169
*
155170
* @param f The path that is to be made relative to the base file
156171
* @param b The file to make the next file relative to
157172
* @return A new file whose path is relative to the base file while the value of <code>getCanonicalPath()</code>
158173
* for the returned file is the same as the result of <code>getCanonicalPath()</code> for the given file.
159174
*/
160175
public static File makeRelativeTo(File f, File b) throws IOException, SecurityException {
176+
try {
177+
File[] roots = File.listRoots();
178+
File fRoot = null;
179+
File bRoot = null;
180+
for(File r: roots) {
181+
if (isAncestorOf(r, f)) { fRoot = r; }
182+
if (isAncestorOf(r, b)) { bRoot = r; }
183+
if ((fRoot!=null) && (bRoot!=null)) { break; }
184+
}
185+
if ((fRoot==null) || (!fRoot.equals(bRoot))) {
186+
// f and b have different file system roots
187+
// just make f absolute and canonical
188+
return f.getAbsoluteFile().getCanonicalFile();
189+
}
190+
}
191+
catch(Exception e) { /* ignore, follow previous procedure */ }
192+
161193
File base = b.getCanonicalFile();
162194
File abs = f.getCanonicalFile(); // If f is relative, uses current working directory ("user.dir")
163195
if (! base.isDirectory()) base = base.getParentFile();

0 commit comments

Comments
 (0)