Compare file inodes if possible in wxFileName::SameAs().

This allows to correctly return when the two files with different names
actually refer to the same file system object.

Closes #910.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@70687 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin 2012-02-25 23:49:35 +00:00
parent 41fec01fa9
commit 7c9b6c9111
2 changed files with 64 additions and 2 deletions

View File

@ -1794,8 +1794,16 @@ bool wxFileName::SameAs(const wxFileName& filepath, wxPathFormat format) const
if ( fn1.GetFullPath() == fn2.GetFullPath() )
return true;
// TODO: compare inodes for Unix, this works even when filenames are
// different but files are the same (symlinks) (VZ)
#if defined(__UNIX__)
wxStructStat st1, st2;
if ( wxStat(fn1.GetFullPath(), &st1) == 0 &&
wxStat(fn2.GetFullPath(), &st2) == 0 )
{
if ( st1.st_ino == st2.st_ino && st1.st_dev == st2.st_dev )
return true;
}
//else: It's not an error if one or both files don't exist.
#endif // defined __UNIX__
return false;
}

View File

@ -30,6 +30,10 @@
#include "wx/msw/registry.h"
#endif // __WXMSW__
#ifdef __UNIX__
#include <unistd.h>
#endif // __UNIX__
#include "testfile.h"
// ----------------------------------------------------------------------------
@ -136,6 +140,7 @@ private:
CPPUNIT_TEST( TestCreateTempFileName );
CPPUNIT_TEST( TestGetTimes );
CPPUNIT_TEST( TestExists );
CPPUNIT_TEST( TestIsSame );
CPPUNIT_TEST_SUITE_END();
void TestConstruction();
@ -154,6 +159,7 @@ private:
void TestCreateTempFileName();
void TestGetTimes();
void TestExists();
void TestIsSame();
DECLARE_NO_COPY_CLASS(FileNameTestCase)
};
@ -673,3 +679,51 @@ void FileNameTestCase::TestExists()
CPPUNIT_ASSERT( wxFileName::Exists("/dev/null") );
#endif // __UNIX__
}
void FileNameTestCase::TestIsSame()
{
wxFileName fn1( wxFileName::CreateTempFileName( "filenametest1" ) );
CPPUNIT_ASSERT( fn1.IsOk() );
wxON_BLOCK_EXIT1( wxRemoveFile, fn1.GetFullPath() );
wxFileName fn2( wxFileName::CreateTempFileName( "filenametest2" ) );
CPPUNIT_ASSERT( fn2.IsOk() );
wxON_BLOCK_EXIT1( wxRemoveFile, fn2.GetFullPath() );
CPPUNIT_ASSERT( fn1.SameAs( fn1 ) );
CPPUNIT_ASSERT( !fn1.SameAs( fn2 ) );
#if defined(__UNIX__)
// We need to create a temporary directory and a temporary link.
// Unfortunately we can't use wxFileName::CreateTempFileName() for neither
// as it creates plain files, so use tempnam() explicitly instead.
char* tn = tempnam(NULL, "wxfn1");
const wxString tempdir1 = wxString::From8BitData(tn);
free(tn);
CPPUNIT_ASSERT( wxFileName::Mkdir(tempdir1) );
// Unfortunately the casts are needed to select the overload we need here.
wxON_BLOCK_EXIT2( static_cast<bool (*)(const wxString&, int)>(wxFileName::Rmdir),
tempdir1, static_cast<int>(wxPATH_RMDIR_RECURSIVE) );
tn = tempnam(NULL, "wxfn2");
const wxString tempdir2 = wxString::From8BitData(tn);
free(tn);
CPPUNIT_ASSERT_EQUAL( 0, symlink(tempdir1, tempdir2) );
wxON_BLOCK_EXIT1( wxRemoveFile, tempdir2 );
wxFileName fn3(tempdir1, "foo");
wxFileName fn4(tempdir2, "foo");
// These files have different paths, hence are different.
CPPUNIT_ASSERT( !fn3.SameAs(fn4) );
// Create and close a file to trigger creating it.
wxFile(fn3.GetFullPath(), wxFile::write);
// Now that both files do exist we should be able to detect that they are
// actually the same file.
CPPUNIT_ASSERT( fn3.SameAs(fn4) );
#endif // __UNIX__
}