From 7c9b6c91116553da4546c1407e1c6dbc44c7f1b6 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 25 Feb 2012 23:49:35 +0000 Subject: [PATCH] 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 --- src/common/filename.cpp | 12 ++++++-- tests/filename/filenametest.cpp | 54 +++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/src/common/filename.cpp b/src/common/filename.cpp index a3f8ac3c5d..0cacb63e47 100644 --- a/src/common/filename.cpp +++ b/src/common/filename.cpp @@ -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; } diff --git a/tests/filename/filenametest.cpp b/tests/filename/filenametest.cpp index 5647448345..aefd7fee57 100644 --- a/tests/filename/filenametest.cpp +++ b/tests/filename/filenametest.cpp @@ -30,6 +30,10 @@ #include "wx/msw/registry.h" #endif // __WXMSW__ +#ifdef __UNIX__ + #include +#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(wxFileName::Rmdir), + tempdir1, static_cast(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__ +}