]> git.saurik.com Git - wxWidgets.git/commitdiff
Allow testing for existence of specific file types in wxFileName.
authorVadim Zeitlin <vadim@wxwidgets.org>
Fri, 19 Oct 2012 22:02:15 +0000 (22:02 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Fri, 19 Oct 2012 22:02:15 +0000 (22:02 +0000)
Add "flags" parameter to wxFileName::Exists() to allow testing for the
existing of files of specific type: not only regular or directory but also
symlink, device, FIFO or socket.

And also to pass wxFILE_EXISTS_NO_FOLLOW flag inhibiting following the
symlinks without using DontFollowLink().

Closes #14542.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@72707 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

docs/changes.txt
include/wx/filename.h
interface/wx/filename.h
src/common/filename.cpp
tests/filename/filenametest.cpp

index 1de66ed679ee8780b0577561f68b30a1580afbab..6688351757154ca5939d6f54eea9f8836c3ea999 100644 (file)
@@ -530,6 +530,7 @@ Major new features in this release
 All:
 
 - Add support for symlinks to wxFileName (David Hart).
+- Allow testing for symlink/FIFO/socket existence in wxFileName (David Hart).
 - Many important bug fixes in wxFileSystemWatcher (David Hart).
 - Add separate read/written bytes counters and per-direction NOWAIT and WAITALL
   flags to wxSocket (Rob Bresalier).
index 8da9903cd1c07e2f9d2b3c234685cad15960c186..967077393fecda063156e340ff54a813b8be2a8c 100644 (file)
@@ -108,6 +108,20 @@ enum
     wxPATH_RMDIR_RECURSIVE  = 0x0002   // delete all recursively (dangerous!)
 };
 
+// FileExists flags
+enum
+{
+    wxFILE_EXISTS_REGULAR   = 0x0001,  // check for existence of a regular file
+    wxFILE_EXISTS_DIR       = 0x0002,  // check for existence of a directory
+    wxFILE_EXISTS_SYMLINK   = 0x0004,  // check for existence of a symbolic link
+    wxFILE_EXISTS_DEVICE    = 0x0008,  // check for existence of a device
+    wxFILE_EXISTS_FIFO      = 0x0016,  // check for existence of a FIFO
+    wxFILE_EXISTS_SOCKET    = 0x0032,  // check for existence of a socket
+                                       // gap for future types
+    wxFILE_EXISTS_ANY       = 0x0FFF,  // check for existence of anything
+    wxFILE_EXISTS_NO_FOLLOW = 0x1000   // don't dereference a contained symlink
+};
+
 #if wxUSE_LONGLONG
 // error code of wxFileName::GetSize()
 extern WXDLLIMPEXP_DATA_BASE(const wxULongLong) wxInvalidSize;
@@ -224,8 +238,8 @@ public:
 
         // does anything at all with this name (i.e. file, directory or some
         // other file system object such as a device, socket, ...) exist?
-    bool Exists() const;
-    static bool Exists(const wxString& path);
+    bool Exists(int flags = wxFILE_EXISTS_ANY) const;
+    static bool Exists(const wxString& path, int flags = wxFILE_EXISTS_ANY);
 
 
         // checks on most common flags for files/directories;
index cc6ccc9d5aee2b846f382acbbeae292c14d5b7aa..ffa57df4438b75e3bcdf5eaeb66a30fc077de508 100644 (file)
@@ -90,6 +90,23 @@ enum
     wxPATH_RMDIR_RECURSIVE = 2
 };
 
+/**
+    Flags for wxFileName::Exists().
+
+    @since 2.9.5
+ */
+enum
+{
+    wxFILE_EXISTS_REGULAR   = 0x0001,  //!< Check for existence of a regular file
+    wxFILE_EXISTS_DIR       = 0x0002,  //!< Check for existence of a directory
+    wxFILE_EXISTS_SYMLINK   = 0x0004,  //!< Check for existence of a symbolic link
+    wxFILE_EXISTS_DEVICE    = 0x0008,  //!< Check for existence of a device
+    wxFILE_EXISTS_FIFO      = 0x0016,  //!< Check for existence of a FIFO
+    wxFILE_EXISTS_SOCKET    = 0x0032,  //!< Check for existence of a socket
+    wxFILE_EXISTS_ANY       = 0x0FFF,  //!< Check for existence of anything
+    wxFILE_EXISTS_NO_FOLLOW = 0x1000   //!< Don't dereference a contained symbolic link
+};
+
 /**
     The return value of wxFileName::GetSize() in case of error.
 */
@@ -509,24 +526,32 @@ public:
         Calls the static overload of this function with the full path of this
         object.
 
-        @since 2.9.4
+        @since 2.9.4 (@a flags is new since 2.9.5)
      */
-    bool Exists() const;
+    bool Exists(int flags = wxFILE_EXISTS_ANY) const;
 
     /**
         Returns @true if either a file or a directory or something else with
         this name exists in the file system.
 
+        Don't dereference @a path if it is a symbolic link and @a flags
+        argument contains ::wxFILE_EXISTS_NO_FOLLOW.
+
         This method is equivalent to @code FileExists() || DirExists() @endcode
-        under most systems but under Unix it also returns true if the file
+        under Windows, but under Unix it also returns true if the file
         identifies a special file system object such as a device, a socket or a
         FIFO.
 
+        Alternatively you may check for the existence of a file system entry of
+        a specific type by passing the appropriate @a flags (this parameter is
+        new since wxWidgets 2.9.5). E.g. to test for a symbolic link existence
+        you could use ::wxFILE_EXISTS_SYMLINK.
+
         @since 2.9.4
 
         @see FileExists(), DirExists()
      */
-    static bool Exists(const wxString& path);
+    static bool Exists(const wxString& path, int flags = wxFILE_EXISTS_ANY);
 
     /**
         Returns @true if the file with this name exists.
index d21a7e50172bd4da2ad80158665b8ddb610863ad..47cd363d88b74c94107ed02260eaaa90fef24384 100644 (file)
@@ -335,14 +335,14 @@ static bool IsUNCPath(const wxString& path, wxPathFormat format)
 #ifndef __WIN32__
 
 // Under Unix-ish systems (basically everything except Windows) we may work
-// either with the file itself or its target in case it's a symbolic link, as
-// determined by wxFileName::ShouldFollowLink(). StatAny() can be used to stat
-// the appropriate file with an extra twist that it also works (by following
-// the symlink by default) when there is no wxFileName object at all, as is the
-// case in static methods.
+// either with the file itself or its target if it's a symbolic link and we
+// should dereference it, as determined by wxFileName::ShouldFollowLink() and
+// the absence of the wxFILE_EXISTS_NO_FOLLOW flag. StatAny() can be used to
+// stat the appropriate file with an extra twist that it also works when there
+// is no wxFileName object at all, as is the case in static methods.
 
 // Private implementation, don't call directly, use one of the overloads below.
-bool DoStatAny(wxStructStat& st, wxString path, const wxFileName* fn)
+bool DoStatAny(wxStructStat& st, wxString path, bool dereference)
 {
     // We need to remove any trailing slashes from the path because they could
     // interfere with the symlink following decision: even if we use lstat(),
@@ -362,23 +362,22 @@ bool DoStatAny(wxStructStat& st, wxString path, const wxFileName* fn)
         path.erase(posLast);
     }
 
-    int ret = !fn || fn->ShouldFollowLink() ? wxStat(path, &st)
-                                            : wxLstat(path, &st);
+    int ret = dereference ? wxStat(path, &st) : wxLstat(path, &st);
     return ret == 0;
 }
 
 // Overloads to use for a case when we don't have wxFileName object and when we
 // do have one.
 inline
-bool StatAny(wxStructStat& st, const wxString& path)
+bool StatAny(wxStructStat& st, const wxString& path, int flags)
 {
-    return DoStatAny(st, path, NULL);
+    return DoStatAny(st, path, !(flags & wxFILE_EXISTS_NO_FOLLOW));
 }
 
 inline
 bool StatAny(wxStructStat& st, const wxFileName& fn)
 {
-    return DoStatAny(st, fn.GetFullPath(), &fn);
+    return DoStatAny(st, fn.GetFullPath(), fn.ShouldFollowLink());
 }
 
 #endif // !__WIN32__
@@ -644,16 +643,6 @@ wxFileName wxFileName::DirName(const wxString& dir, wxPathFormat format)
 namespace
 {
 
-// Flags for wxFileSystemObjectExists() asking it to check for:
-enum
-{
-    wxFileSystemObject_File  = 1,   // file existence
-    wxFileSystemObject_Dir   = 2,   // directory existence
-    wxFileSystemObject_Other = 4,   // existence of something else, e.g.
-                                    // device, socket, FIFO under Unix
-    wxFileSystemObject_Any   = 7    // existence of anything at all
-};
-
 #if defined(__WINDOWS__) && !defined(__WXMICROWIN__)
 
 void RemoveTrailingSeparatorsFromPath(wxString& strPath)
@@ -679,15 +668,13 @@ void RemoveTrailingSeparatorsFromPath(wxString& strPath)
 #endif // __WINDOWS__ || __OS2__
 
 bool
-wxFileSystemObjectExists(const wxString& path, int flags,
-                         const wxFileName* fn = NULL)
+wxFileSystemObjectExists(const wxString& path, int flags)
 {
-    wxUnusedVar(fn);    // It's only used under Unix
 
     // Should the existence of file/directory with this name be accepted, i.e.
     // result in the true return value from this function?
-    const bool acceptFile = (flags & wxFileSystemObject_File) != 0;
-    const bool acceptDir  = (flags & wxFileSystemObject_Dir) != 0;
+    const bool acceptFile = (flags & wxFILE_EXISTS_REGULAR) != 0;
+    const bool acceptDir  = (flags & wxFILE_EXISTS_DIR)  != 0;
 
     wxString strPath(path);
 
@@ -735,22 +722,30 @@ wxFileSystemObjectExists(const wxString& path, int flags,
     // We consider that the path must exist if we get a sharing violation for
     // it but we don't know what is it in this case.
     if ( rc == ERROR_SHARING_VIOLATION )
-        return flags & wxFileSystemObject_Other;
+        return flags & wxFILE_EXISTS_ANY;
 
     // Any other error (usually ERROR_PATH_NOT_FOUND), means there is nothing
     // there.
     return false;
 #else // Non-MSW, non-OS/2
     wxStructStat st;
-    if ( !DoStatAny(st, strPath, fn) )
+    if ( !StatAny(st, strPath, flags) )
         return false;
 
     if ( S_ISREG(st.st_mode) )
         return acceptFile;
     if ( S_ISDIR(st.st_mode) )
         return acceptDir;
-
-    return flags & wxFileSystemObject_Other;
+    if ( S_ISLNK(st.st_mode) )
+        return (flags & wxFILE_EXISTS_SYMLINK) != 0;
+    if ( S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode) )
+        return (flags & wxFILE_EXISTS_DEVICE) != 0;
+    if ( S_ISFIFO(st.st_mode) )
+        return (flags & wxFILE_EXISTS_FIFO) != 0;
+    if ( S_ISSOCK(st.st_mode) )
+        return (flags & wxFILE_EXISTS_SOCKET) != 0;
+
+    return flags & wxFILE_EXISTS_ANY;
 #endif // Platforms
 }
 
@@ -758,35 +753,50 @@ wxFileSystemObjectExists(const wxString& path, int flags,
 
 bool wxFileName::FileExists() const
 {
-    return wxFileSystemObjectExists(GetFullPath(), wxFileSystemObject_File, this);
+    int flags = wxFILE_EXISTS_REGULAR;
+    if ( !ShouldFollowLink() )
+        flags |= wxFILE_EXISTS_NO_FOLLOW;
+
+    return wxFileSystemObjectExists(GetFullPath(), flags);
 }
 
 /* static */
 bool wxFileName::FileExists( const wxString &filePath )
 {
-    return wxFileSystemObjectExists(filePath, wxFileSystemObject_File);
+    return wxFileSystemObjectExists(filePath, wxFILE_EXISTS_REGULAR);
 }
 
 bool wxFileName::DirExists() const
 {
-    return wxFileSystemObjectExists(GetPath(), wxFileSystemObject_Dir, this);
+    int flags = wxFILE_EXISTS_DIR;
+    if ( !ShouldFollowLink() )
+        flags |= wxFILE_EXISTS_NO_FOLLOW;
+
+    return Exists(GetFullPath(), flags);
 }
 
 /* static */
 bool wxFileName::DirExists( const wxString &dirPath )
 {
-    return wxFileSystemObjectExists(dirPath, wxFileSystemObject_Dir);
+    return wxFileSystemObjectExists(dirPath, wxFILE_EXISTS_DIR);
 }
 
-bool wxFileName::Exists() const
+bool wxFileName::Exists(int flags) const
 {
-    return wxFileSystemObjectExists(GetFullPath(), wxFileSystemObject_Any, this);
+    // Notice that wxFILE_EXISTS_NO_FOLLOW may be specified in the flags even
+    // if our DontFollowLink() hadn't been called and we do honour it then. But
+    // if the user took the care of calling DontFollowLink(), it is always
+    // taken into account.
+    if ( !ShouldFollowLink() )
+        flags |= wxFILE_EXISTS_NO_FOLLOW;
+
+    return wxFileSystemObjectExists(GetFullPath(), flags);
 }
 
 /* static */
-bool wxFileName::Exists(const wxString& path)
+bool wxFileName::Exists(const wxString& path, int flags)
 {
-    return wxFileSystemObjectExists(path, wxFileSystemObject_Any);
+    return wxFileSystemObjectExists(path, flags);
 }
 
 // ----------------------------------------------------------------------------
index 5cd5ed98e7ae3f4c9b7f403213318299fe245be4..510cc642485b047603378cbf4435e39aecbaaba8 100644 (file)
@@ -672,17 +672,38 @@ void FileNameTestCase::TestExists()
 
     CPPUNIT_ASSERT( fn.FileExists() );
     CPPUNIT_ASSERT( !wxFileName::DirExists(fn.GetFullPath()) );
+
+    CPPUNIT_ASSERT( fn.Exists(wxFILE_EXISTS_REGULAR) );
+    CPPUNIT_ASSERT( !fn.Exists(wxFILE_EXISTS_DIR) );
     CPPUNIT_ASSERT( fn.Exists() );
 
     wxFileName dirTemp(wxFileName::DirName(wxFileName::GetTempDir()));
     CPPUNIT_ASSERT( !dirTemp.FileExists() );
     CPPUNIT_ASSERT( dirTemp.DirExists() );
+
+    CPPUNIT_ASSERT( dirTemp.Exists(wxFILE_EXISTS_DIR) );
+    CPPUNIT_ASSERT( !dirTemp.Exists(wxFILE_EXISTS_REGULAR) );
     CPPUNIT_ASSERT( dirTemp.Exists() );
 
 #ifdef __UNIX__
     CPPUNIT_ASSERT( !wxFileName::FileExists("/dev/null") );
     CPPUNIT_ASSERT( !wxFileName::DirExists("/dev/null") );
     CPPUNIT_ASSERT( wxFileName::Exists("/dev/null") );
+    CPPUNIT_ASSERT( wxFileName::Exists("/dev/null", wxFILE_EXISTS_DEVICE) );
+#ifdef __LINUX__
+    // These files are only guaranteed to exist under Linux.
+    CPPUNIT_ASSERT( !wxFileName::Exists("/dev/core", wxFILE_EXISTS_SYMLINK) );
+    CPPUNIT_ASSERT( wxFileName::Exists("/dev/core",
+                    wxFILE_EXISTS_SYMLINK | wxFILE_EXISTS_NO_FOLLOW) );
+    CPPUNIT_ASSERT( wxFileName::Exists("/dev/log", wxFILE_EXISTS_SOCKET) );
+#endif // __LINUX__
+    wxString fifo = dirTemp.GetPath() + "/fifo";
+    if (mkfifo(fifo, 0600) == 0)
+    {
+        wxON_BLOCK_EXIT1(wxRemoveFile, fifo);
+
+        CPPUNIT_ASSERT( wxFileName::Exists(fifo, wxFILE_EXISTS_FIFO) );
+    }
 #endif // __UNIX__
 }
 
@@ -838,7 +859,7 @@ void FileNameTestCase::TestSymlinks()
             equal
         );
 
-        // Test Exists()
+        // Test (File|Dir)Exists()
         CPPUNIT_ASSERT_EQUAL_MESSAGE
         (
             "Testing file existence" + msg,
@@ -851,6 +872,46 @@ void FileNameTestCase::TestSymlinks()
             deref,
             linktodir.DirExists()
         );
+
+        // Test wxFileName::Exists
+        // The wxFILE_EXISTS_NO_FOLLOW flag should override DontFollowLink()
+        CPPUNIT_ASSERT_EQUAL_MESSAGE
+        (
+            "Testing file existence" + msg,
+            false,
+            linktofile.Exists(wxFILE_EXISTS_REGULAR | wxFILE_EXISTS_NO_FOLLOW)
+        );
+        CPPUNIT_ASSERT_EQUAL_MESSAGE
+        (
+            "Testing directory existence" + msg,
+            false,
+            linktodir.Exists(wxFILE_EXISTS_DIR | wxFILE_EXISTS_NO_FOLLOW)
+        );
+        // and the static versions
+        CPPUNIT_ASSERT_EQUAL_MESSAGE
+        (
+            "Testing file existence" + msg,
+            false,
+            wxFileName::Exists(linktofile.GetFullPath(), wxFILE_EXISTS_REGULAR | wxFILE_EXISTS_NO_FOLLOW)
+        );
+        CPPUNIT_ASSERT_EQUAL_MESSAGE
+        (
+            "Testing file existence" + msg,
+            true,
+            wxFileName::Exists(linktofile.GetFullPath(), wxFILE_EXISTS_REGULAR)
+        );
+        CPPUNIT_ASSERT_EQUAL_MESSAGE
+        (
+            "Testing directory existence" + msg,
+            false,
+            wxFileName::Exists(linktodir.GetFullPath(), wxFILE_EXISTS_DIR | wxFILE_EXISTS_NO_FOLLOW)
+        );
+        CPPUNIT_ASSERT_EQUAL_MESSAGE
+        (
+            "Testing directory existence" + msg,
+            true,
+            wxFileName::Exists(linktodir.GetFullPath(), wxFILE_EXISTS_DIR)
+        );
     }
 
     // Finally test Exists() after removing the file.