On Mon, Mar 2, 2009 at 4:54 PM, Niklas Gustavsson <nik...@protocol7.com> wrote: > Let me whip up a prototype and we can test it on the available platforms.
Alright, here's a prototype that I would much appreciate if all of you would take the time to test. First of all, you need to set the FILE_SYSTEM_TYPE to the correct value (this is only used for verification in the tests). On case sensitive file systems (most of the *nix file systems), this should be set to FileSystemType.CaseSensitive. On NTFS it should be set to CaseInsensitiveMissingAsTrue, and on case-insensitive HFS to CaseInsensitiveMissingAsFalse. It would be very interesting to have this code tested on other file systems. If you do, please report the file system and the test results. /niklas package org.apache.ftpserver.filesystem.nativefs.impl; import java.io.File; import java.io.FilenameFilter; import java.io.IOException; import junit.framework.TestCase; public class FileEqualsTest extends TestCase { private enum FileSystemType { CaseSensitive, // non-existing files with different casing are equal // e.g. NTFS CaseInsensitiveMissingAsTrue, // non-existing files with different casing are non-equal // e.g. HFS CaseInsensitiveMissingAsFalse }; private static final FileSystemType FILE_SYSTEM_TYPE = FileSystemType.CaseSensitive; private boolean isCaseSensitive() { return FILE_SYSTEM_TYPE == FileSystemType.CaseSensitive; } private boolean isCaseInsensitive() { return FILE_SYSTEM_TYPE != FileSystemType.CaseSensitive; } @Override protected void setUp() throws Exception { System.out.println("File system type: " + FILE_SYSTEM_TYPE); super.setUp(); } public void testSimple() throws IOException { File f1 = new File("foo"); assertTrue(f1.createNewFile()); File f2 = new File("foo"); assertTrue(equals(f1, f2)); } public void testNonExistingButSimple() { File f1 = new File("foo"); File f2 = new File("foo"); assertTrue(equals(f1, f2)); } public void testDifferentCase() throws IOException { File f1 = new File("foo"); assertTrue(f1.createNewFile()); File f2 = new File("FOO"); // if this succeeds, we have two different files assertEquals(isCaseSensitive(), f2.createNewFile()); assertEquals(isCaseInsensitive(), equals(f1, f2)); } public void testDifferentCaseNonExisting() throws IOException { File f1 = new File("foo"); File f2 = new File("FOO"); assertEquals(FILE_SYSTEM_TYPE == FileSystemType.CaseInsensitiveMissingAsTrue, equals(f1, f2)); } public void testSameNameDifferentParent() throws IOException { File f1 = new File("foo"); assertTrue(f1.createNewFile()); File dir2 = new File("dir"); assertTrue(dir2.mkdir()); File f2 = new File(dir2, "foo"); assertTrue(f2.createNewFile()); assertFalse(equals(f1, f2)); } public boolean equals(final File f1, final File f2) { if (f1 == null || f2 == null) { return false; } if (f1.equals(f2)) { // file equals, valid on all file systems return true; } else { boolean f1Exists = f1.exists(); boolean f2Exists = f2.exists(); if (f1.getName().equalsIgnoreCase(f2.getName())) { // same name, do both exist? if (f1Exists && f2Exists) { // both files exists, do they have the same parent? // TODO should we use canonical or absolute path? File f1Parent = f1.getAbsoluteFile().getParentFile(); File f2Parent = f2.getAbsoluteFile().getParentFile(); if (f1Parent != null && f2Parent != null) { if (equals(f1Parent, f2Parent)) { // okay, if we got here, the parents are the same, // the file names are the same and both files exists // let's check if there are multiple files or only one in the parent // with that name // choosing either parent should be fine, they are equal String[] files = f1Parent .list(new FilenameFilter() { public boolean accept(File dir, String name) { return name.equalsIgnoreCase(f1 .getName()); } }); if (files.length == 1) { // exactly one file matched the name, the files must be equal return true; } else if (files.length > 1) { return false; } else { // no file matching, must be a bug somewhere throw new RuntimeException("Should not happen"); } } else { // different parents, return false return false; } } else if (f1Parent == null && f2Parent == null) { // no parents, we can do nothing more and thus have to return false return false; } else { // different parents return false; } } else if (!f1Exists && !f2Exists) { // none of the file exists, we can only trust the equals result (which by now must be false) return false; } else { // only one of the files exists, return false return false; } } else { // file names not equal return false; } } } @Override protected void tearDown() throws Exception { new File("foo").delete(); new File("FOO").delete(); new File("dir/foo").delete(); new File("dir").delete(); } }