Details
Description
Name: nt126004 Date: 12/02/2002
FULL PRODUCT VERSION :
java version "1.4.1"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1-b21)
Java HotSpot(TM) Client VM (build 1.4.1-b21, mixed mode)
FULL OPERATING SYSTEM VERSION :
SunOS mammoth 5.8 Generic_108528-15 sun4u sparc SUNW,Ultra-80
A DESCRIPTION OF THE PROBLEM :
The documentation for java.io.File.equals() states that the
method "Returns true if and only if the argument is not null
and is an abstract pathname that denotes the same file or
directory as this abstract pathname." However, a look at the
source reveals that it delegates to the FileSystem class (same
package), whose compare() method states "Compare two abstract
pathnames lexicographically." These two contracts contradict
one another.
Refer to the sample program below and its output.
On UNIX, at least, /dir1/dir2/../dir3/myfile and
/dir1/dir3/myfile "denote the same file or directory."
However, the strings are not lexicographically equal and
File.equals() returns false.
Either File.equals() should be changed to use canonical files
to meet the contract set out in its documentation or the
documentation should be changed to state explicitly that
the files are compared using their path strings without
reference to whether or not they refer to the same physical
file.
This bug is similar to a general case of bug #4143695. That
bug's author asked for a change to File to assist with a
permissions issue. I am not interested in permissions or in
the specific case he mentions, however; I am concerned with
the misleading inconsistency between what is implied in the
method's documentation and what its implementation in fact
does.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile and run the sample code below.
EXPECTED VERSUS ACTUAL BEHAVIOR :
The sample program outputs:
File #1: /dir1/dir2/../dir3/myfile
File #2: /dir1/dir3/myfile
Equals: false
Based on the File.equals() docs, I expected:
File #1: /dir1/dir2/../dir3/myfile
File #2: /dir1/dir3/myfile
Equals: true
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.io.File;
public class FileTest {
public static void main(String[] args) {
File f1 = new File("/dir1/dir2/../dir3/myfile");
File f2 = new File("/dir1/dir3/myfile");
System.out.println("File #1: " + f1);
System.out.println("File #2: " + f2);
System.out.println("Equals: " + f1.equals(f2));
}
}
---------- END SOURCE ----------
CUSTOMER WORKAROUND :
Always compare canonical files:
public static boolean equals(File f1, File f2) {
File canonical1;
try {
canonical1 = f1.getCanonicalFile();
} catch (IOException iox) {
canonical1 = f1.getAbsoluteFile();
}
File canonical2;
try {
canonical2 = f2.getCanonicalFile();
} catch (IOException iox) {
canonical2 = f2.getAbsoluteFile();
}
return canonical1.equals(canonical2);
}
There are a couple of issues with the above:
1.) It involves a couple object instatiations, and is hence
relatively slow, and
2.) In the event that an IOException occurs in
getCanonicalFile(), the output is not guaranteed to be
correct. However, it is *more likely* to be correct than
the current code.
(Review ID: 165782)
======================================================================
FULL PRODUCT VERSION :
java version "1.4.1"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1-b21)
Java HotSpot(TM) Client VM (build 1.4.1-b21, mixed mode)
FULL OPERATING SYSTEM VERSION :
SunOS mammoth 5.8 Generic_108528-15 sun4u sparc SUNW,Ultra-80
A DESCRIPTION OF THE PROBLEM :
The documentation for java.io.File.equals() states that the
method "Returns true if and only if the argument is not null
and is an abstract pathname that denotes the same file or
directory as this abstract pathname." However, a look at the
source reveals that it delegates to the FileSystem class (same
package), whose compare() method states "Compare two abstract
pathnames lexicographically." These two contracts contradict
one another.
Refer to the sample program below and its output.
On UNIX, at least, /dir1/dir2/../dir3/myfile and
/dir1/dir3/myfile "denote the same file or directory."
However, the strings are not lexicographically equal and
File.equals() returns false.
Either File.equals() should be changed to use canonical files
to meet the contract set out in its documentation or the
documentation should be changed to state explicitly that
the files are compared using their path strings without
reference to whether or not they refer to the same physical
file.
This bug is similar to a general case of bug #4143695. That
bug's author asked for a change to File to assist with a
permissions issue. I am not interested in permissions or in
the specific case he mentions, however; I am concerned with
the misleading inconsistency between what is implied in the
method's documentation and what its implementation in fact
does.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile and run the sample code below.
EXPECTED VERSUS ACTUAL BEHAVIOR :
The sample program outputs:
File #1: /dir1/dir2/../dir3/myfile
File #2: /dir1/dir3/myfile
Equals: false
Based on the File.equals() docs, I expected:
File #1: /dir1/dir2/../dir3/myfile
File #2: /dir1/dir3/myfile
Equals: true
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.io.File;
public class FileTest {
public static void main(String[] args) {
File f1 = new File("/dir1/dir2/../dir3/myfile");
File f2 = new File("/dir1/dir3/myfile");
System.out.println("File #1: " + f1);
System.out.println("File #2: " + f2);
System.out.println("Equals: " + f1.equals(f2));
}
}
---------- END SOURCE ----------
CUSTOMER WORKAROUND :
Always compare canonical files:
public static boolean equals(File f1, File f2) {
File canonical1;
try {
canonical1 = f1.getCanonicalFile();
} catch (IOException iox) {
canonical1 = f1.getAbsoluteFile();
}
File canonical2;
try {
canonical2 = f2.getCanonicalFile();
} catch (IOException iox) {
canonical2 = f2.getAbsoluteFile();
}
return canonical1.equals(canonical2);
}
There are a couple of issues with the above:
1.) It involves a couple object instatiations, and is hence
relatively slow, and
2.) In the event that an IOException occurs in
getCanonicalFile(), the output is not guaranteed to be
correct. However, it is *more likely* to be correct than
the current code.
(Review ID: 165782)
======================================================================
Attachments
Issue Links
- relates to
-
JDK-8267569 java.io.File.equals contains misleading Javadoc
-
- Closed
-