]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/filefn.cpp
added explanatory comment
[wxWidgets.git] / src / common / filefn.cpp
index 5824391e0f770f77d747f32643406b284113a96c..636e3d9aacacf9eddf280dcff0e4c2a1d4a0d4dc 100644 (file)
     #pragma hdrstop
 #endif
 
+#include "wx/filefn.h"
+
 #ifndef WX_PRECOMP
     #include "wx/intl.h"
     #include "wx/log.h"
     #include "wx/utils.h"
 #endif
 
-#include "wx/file.h" // This does include filefn.h
+#include "wx/file.h"
 #include "wx/filename.h"
 #include "wx/dir.h"
 
+#include "wx/tokenzr.h"
+
 // there are just too many of those...
 #ifdef __VISUALC__
     #pragma warning(disable:4706)   // assignment within conditional expression
@@ -113,13 +117,17 @@ const int wxInvalidOffset = -1;
 // macros
 // ----------------------------------------------------------------------------
 
-// we need to translate Mac filenames before passing them to OS functions
+// translate the filenames before passing them to OS functions
 #define OS_FILENAME(s) (s.fn_str())
 
 // ============================================================================
 // implementation
 // ============================================================================
 
+// ----------------------------------------------------------------------------
+// wrappers around standard POSIX functions
+// ----------------------------------------------------------------------------
+
 #ifdef wxNEED_WX_UNISTD_H
 
 WXDLLEXPORT int wxStat( const wxChar *file_name, wxStructStat *buf )
@@ -127,6 +135,11 @@ WXDLLEXPORT int wxStat( const wxChar *file_name, wxStructStat *buf )
     return stat( wxConvFile.cWX2MB( file_name ), buf );
 }
 
+WXDLLEXPORT int wxLstat( const wxChar *file_name, wxStructStat *buf )
+{
+    return lstat( wxConvFile.cWX2MB( file_name ), buf );
+}
+
 WXDLLEXPORT int wxAccess( const wxChar *pathname, int mode )
 {
     return access( wxConvFile.cWX2MB( pathname ), mode );
@@ -137,30 +150,75 @@ WXDLLEXPORT int wxOpen( const wxChar *pathname, int flags, mode_t mode )
     return open( wxConvFile.cWX2MB( pathname ), flags, mode );
 }
 
+#endif // wxNEED_WX_UNISTD_H
+
+#if wxUSE_UNICODE && defined __BORLANDC__ \
+    && __BORLANDC__ >= 0x550 && __BORLANDC__ <= 0x551
+
+// BCC 5.5 and 5.5.1 have a bug in _wopen where files are created read only
+// regardless of the mode parameter. This hack works around the problem by
+// setting the mode with _wchmod.
+//
+int wxOpen(const wchar_t *pathname, int flags, mode_t mode)
+{
+    int moreflags = 0;
+
+    // we only want to fix the mode when the file is actually created, so
+    // when creating first try doing it O_EXCL so we can tell if the file
+    // was already there.
+    if ((flags & O_CREAT) && !(flags & O_EXCL) && (mode & wxS_IWUSR) != 0)
+        moreflags = O_EXCL;
+
+    int fd = _wopen(pathname, flags | moreflags, mode);
+
+    // the file was actually created and needs fixing
+    if (fd != -1 && (flags & O_CREAT) != 0 && (mode & wxS_IWUSR) != 0)
+    {
+        close(fd);
+        _wchmod(pathname, mode);
+        fd = _wopen(pathname, flags & ~(O_EXCL | O_CREAT));
+    }
+    // the open failed, but it may have been because the added O_EXCL stopped
+    // the opening of an existing file, so try again without.
+    else if (fd == -1 && moreflags != 0)
+    {
+        fd = _wopen(pathname, flags & ~O_CREAT);
+    }
+
+    return fd;
+}
+
 #endif
-   // wxNEED_WX_UNISTD_H
 
 // ----------------------------------------------------------------------------
 // wxPathList
 // ----------------------------------------------------------------------------
 
-// IMPLEMENT_DYNAMIC_CLASS(wxPathList, wxStringList)
-
-static inline wxChar* MYcopystring(const wxString& s)
+bool wxPathList::Add(const wxString& path)
 {
-    wxChar* copy = new wxChar[s.length() + 1];
-    return wxStrcpy(copy, s.c_str());
-}
+    // add a path separator to force wxFileName to interpret it always as a directory
+    // (i.e. if we are called with '/home/user' we want to consider it a folder and
+    // not, as wxFileName would consider, a filename).
+    wxFileName fn(path + wxFileName::GetPathSeparator());
+
+    // add only normalized relative/absolute paths
+    // NB: we won't do wxPATH_NORM_DOTS in order to avoid problems when trying to
+    //     normalize paths which starts with ".." (which can be normalized only if
+    //     we use also wxPATH_NORM_ABSOLUTE - which we don't want to use).
+    if (!fn.Normalize(wxPATH_NORM_TILDE|wxPATH_NORM_LONG|wxPATH_NORM_ENV_VARS))
+        return false;
 
-static inline wxChar* MYcopystring(const wxChar* s)
-{
-    wxChar* copy = new wxChar[wxStrlen(s) + 1];
-    return wxStrcpy(copy, s);
+    wxString toadd = fn.GetPath();
+    if (Index(toadd) == wxNOT_FOUND)
+        wxArrayString::Add(toadd);      // do not add duplicates
+
+    return true;
 }
 
-void wxPathList::Add (const wxString& path)
+void wxPathList::Add(const wxArrayString &arr)
 {
-    wxStringList::Add (WXSTRINGCAST path);
+    for (size_t j=0; j < arr.GetCount(); j++)
+        Add(arr[j]);
 }
 
 // Add paths e.g. from the PATH environment variable
@@ -168,43 +226,24 @@ void wxPathList::AddEnvList (const wxString& WXUNUSED_IN_WINCE(envVariable))
 {
     // No environment variables on WinCE
 #ifndef __WXWINCE__
+
+    // The space has been removed from the tokenizers, otherwise a
+    // path such as "C:\Program Files" would be split into 2 paths:
+    // "C:\Program" and "Files"; this is true for both Windows and Unix.
+
     static const wxChar PATH_TOKS[] =
 #if defined(__WINDOWS__) || defined(__OS2__)
-        /*
-        The space has been removed from the tokenizers, otherwise a
-        path such as "C:\Program Files" would be split into 2 paths:
-        "C:\Program" and "Files"
-        */
-//        wxT(" ;"); // Don't separate with colon in DOS (used for drive)
         wxT(";"); // Don't separate with colon in DOS (used for drive)
 #else
-        wxT(" :;");
+        wxT(":;");
 #endif
 
-    wxString val ;
-    if (wxGetEnv (WXSTRINGCAST envVariable, &val))
+    wxString val;
+    if ( wxGetEnv(envVariable, &val) )
     {
-        wxChar *s = MYcopystring (val);
-        wxChar *save_ptr, *token = wxStrtok (s, PATH_TOKS, &save_ptr);
-
-        if (token)
-        {
-            Add(token);
-            while (token)
-            {
-                if ( (token = wxStrtok ((wxChar *) NULL, PATH_TOKS, &save_ptr))
-                    != NULL )
-                {
-                    Add(token);
-                }
-            }
-        }
-
-        // suppress warning about unused variable save_ptr when wxStrtok() is a
-        // macro which throws away its third argument
-        save_ptr = token;
-
-        delete [] s;
+        // split into an array of string the value of the env var
+        wxArrayString arr = wxStringTokenize(val, PATH_TOKS);
+        WX_APPEND_ARRAY(*this, arr);
     }
 #endif // !__WXWINCE__
 }
@@ -212,65 +251,53 @@ void wxPathList::AddEnvList (const wxString& WXUNUSED_IN_WINCE(envVariable))
 // Given a full filename (with path), ensure that that file can
 // be accessed again USING FILENAME ONLY by adding the path
 // to the list if not already there.
-void wxPathList::EnsureFileAccessible (const wxString& path)
+bool wxPathList::EnsureFileAccessible (const wxString& path)
 {
-    wxString path_only(wxPathOnly(path));
-    if ( !path_only.empty() )
-    {
-        if ( !Member(path_only) )
-            Add(path_only);
-    }
+    return Add(wxPathOnly(path));
 }
 
-bool wxPathList::Member (const wxString& path)
+#if WXWIN_COMPATIBILITY_2_6
+bool wxPathList::Member (const wxString& path) const
 {
-  for (wxStringList::compatibility_iterator node = GetFirst(); node; node = node->GetNext())
-  {
-      wxString path2( node->GetData() );
-      if (
-#if defined(__WINDOWS__) || defined(__OS2__) || defined(__VMS__) || defined(__WXMAC__)
-      // Case INDEPENDENT
-          path.CompareTo (path2, wxString::ignoreCase) == 0
-#else
-      // Case sensitive File System
-          path.CompareTo (path2) == 0
-#endif
-        )
-        return true;
-  }
-  return false;
+    return Index(path) != wxNOT_FOUND;
 }
+#endif
 
-wxString wxPathList::FindValidPath (const wxString& file)
+wxString wxPathList::FindValidPath (const wxString& file) const
 {
-  wxExpandPath(wxFileFunctionsBuffer, file);
-
-  wxChar buf[_MAXPATHLEN];
-  wxStrcpy(buf, wxFileFunctionsBuffer);
+    // normalize the given string as it could be a path + a filename
+    // and not only a filename
+    wxFileName fn(file);
+    wxString strend;
+
+    // NB: normalize without making absolute otherwise calling this function with
+    //     e.g. "b/c.txt" would result in removing the directory 'b' and the for loop
+    //     below would only add to the paths of this list the 'c.txt' part when doing
+    //     the existence checks...
+    // NB: we don't use wxPATH_NORM_DOTS here, too (see wxPathList::Add for more info)
+    if (!fn.Normalize(wxPATH_NORM_TILDE|wxPATH_NORM_LONG|wxPATH_NORM_ENV_VARS))
+        return wxEmptyString;
 
-  wxChar *filename = wxIsAbsolutePath (buf) ? wxFileNameFromPath (buf) : (wxChar *)buf;
+    wxASSERT_MSG(!fn.IsDir(), wxT("Cannot search for directories; only for files"));
+    if (fn.IsAbsolute())
+        strend = fn.GetFullName();      // search for the file name and ignore the path part
+    else
+        strend = fn.GetFullPath();
 
-  for (wxStringList::compatibility_iterator node = GetFirst(); node; node = node->GetNext())
+    for (size_t i=0; i<GetCount(); i++)
     {
-      const wxString path(node->GetData());
-      wxStrcpy (wxFileFunctionsBuffer, path);
-      wxChar ch = wxFileFunctionsBuffer[wxStrlen(wxFileFunctionsBuffer)-1];
-      if (ch != wxT('\\') && ch != wxT('/'))
-        wxStrcat (wxFileFunctionsBuffer, wxT("/"));
-      wxStrcat (wxFileFunctionsBuffer, filename);
-#ifdef __WINDOWS__
-      wxUnix2DosFilename (wxFileFunctionsBuffer);
-#endif
-      if (wxFileExists (wxFileFunctionsBuffer))
-      {
-        return wxString(wxFileFunctionsBuffer);        // Found!
-      }
-    }                                // for()
+        wxString strstart = Item(i);
+        if (!strstart.IsEmpty() && strstart.Last() != wxFileName::GetPathSeparator())
+            strstart += wxFileName::GetPathSeparator();
 
-  return wxEmptyString;                    // Not found
+        if (wxFileExists(strstart + strend))
+            return strstart + strend;        // Found!
+    }
+
+    return wxEmptyString;                    // Not found
 }
 
-wxString wxPathList::FindAbsoluteValidPath (const wxString& file)
+wxString wxPathList::FindAbsoluteValidPath (const wxString& file) const
 {
     wxString f = FindValidPath(file);
     if ( f.empty() || wxIsAbsolutePath(f) )
@@ -287,6 +314,23 @@ wxString wxPathList::FindAbsoluteValidPath (const wxString& file)
     return buf;
 }
 
+// ----------------------------------------------------------------------------
+// miscellaneous global functions (TOFIX!)
+// ----------------------------------------------------------------------------
+
+static inline wxChar* MYcopystring(const wxString& s)
+{
+    wxChar* copy = new wxChar[s.length() + 1];
+    return wxStrcpy(copy, s.c_str());
+}
+
+static inline wxChar* MYcopystring(const wxChar* s)
+{
+    wxChar* copy = new wxChar[wxStrlen(s) + 1];
+    return wxStrcpy(copy, s);
+}
+
+
 bool
 wxFileExists (const wxString& filename)
 {
@@ -883,15 +927,15 @@ wxString wxMacFSRefToPath( const FSRef *fsRef , CFStringRef additionalPathCompon
     CFRelease( fullURLRef ) ;
     CFMutableStringRef cfMutableString = CFStringCreateMutableCopy(NULL, 0, cfString);
     CFRelease( cfString );
-    CFStringNormalize(cfMutableString,kCFStringNormalizationFormC);    
-    return wxMacCFStringHolder(cfMutableString).AsString(wxLocale::GetSystemEncoding());
+    CFStringNormalize(cfMutableString,kCFStringNormalizationFormC);
+    return wxMacCFStringHolder(cfMutableString).AsString();
 }
 
 OSStatus wxMacPathToFSRef( const wxString&path , FSRef *fsRef )
 {
     OSStatus err = noErr ;
-    CFMutableStringRef cfMutableString = CFStringCreateMutableCopy(NULL, 0, wxMacCFStringHolder(path ,wxLocale::GetSystemEncoding() ) ) ;
-    CFStringNormalize(cfMutableString,kCFStringNormalizationFormD);    
+    CFMutableStringRef cfMutableString = CFStringCreateMutableCopy(NULL, 0, wxMacCFStringHolder(path));
+    CFStringNormalize(cfMutableString,kCFStringNormalizationFormD);
     CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, cfMutableString , kDefaultPathStyle, false);
     CFRelease( cfMutableString );
     if ( NULL != url )
@@ -914,10 +958,12 @@ wxString wxMacHFSUniStrToString( ConstHFSUniStr255Param uniname )
                                                       uniname->length );
     CFMutableStringRef cfMutableString = CFStringCreateMutableCopy(NULL, 0, cfname);
     CFRelease( cfname );
-    CFStringNormalize(cfMutableString,kCFStringNormalizationFormC);    
+    CFStringNormalize(cfMutableString,kCFStringNormalizationFormC);
     return wxMacCFStringHolder(cfMutableString).AsString() ;
 }
 
+#ifndef __LP64__
+
 wxString wxMacFSSpec2MacFilename( const FSSpec *spec )
 {
     FSRef fsRef ;
@@ -935,6 +981,7 @@ void wxMacFilename2FSSpec( const wxString& path , FSSpec *spec )
     wxMacPathToFSRef( path , &fsRef ) ;
     err = FSRefMakeFSSpec( &fsRef , spec ) ;
 }
+#endif
 
 #endif // __WXMAC__
 
@@ -1011,6 +1058,51 @@ wxConcatFiles (const wxString& file1, const wxString& file2, const wxString& fil
 #endif
 }
 
+// helper of generic implementation of wxCopyFile()
+#if !(defined(__WIN32__) || defined(__OS2__) || defined(__PALMOS__)) && \
+    wxUSE_FILE
+
+static bool
+wxDoCopyFile(wxFile& fileIn,
+             const wxStructStat& fbuf,
+             const wxString& filenameDst,
+             bool overwrite)
+{
+    // reset the umask as we want to create the file with exactly the same
+    // permissions as the original one
+    wxCHANGE_UMASK(0);
+
+    // create file2 with the same permissions than file1 and open it for
+    // writing
+
+    wxFile fileOut;
+    if ( !fileOut.Create(filenameDst, overwrite, fbuf.st_mode & 0777) )
+        return false;
+
+    // copy contents of file1 to file2
+    char buf[4096];
+    for ( ;; )
+    {
+        ssize_t count = fileIn.Read(buf, WXSIZEOF(buf));
+        if ( count == wxInvalidOffset )
+            return false;
+
+        // end of file?
+        if ( !count )
+            break;
+
+        if ( fileOut.Write(buf, count) < (size_t)count )
+            return false;
+    }
+
+    // we can expect fileIn to be closed successfully, but we should ensure
+    // that fileOut was closed as some write errors (disk full) might not be
+    // detected before doing this
+    return fileIn.Close() && fileOut.Close();
+}
+
+#endif // generic implementation of wxCopyFile
+
 // Copy files
 bool
 wxCopyFile (const wxString& file1, const wxString& file2, bool overwrite)
@@ -1028,7 +1120,7 @@ wxCopyFile (const wxString& file1, const wxString& file2, bool overwrite)
         return false;
     }
 #elif defined(__OS2__)
-    if ( ::DosCopy((PSZ)file1.c_str(), (PSZ)file2.c_str(), overwrite ? DCPY_EXISTING : 0) != 0 )
+    if ( ::DosCopy(file1.c_str(), file2.c_str(), overwrite ? DCPY_EXISTING : 0) != 0 )
         return false;
 #elif defined(__PALMOS__)
     // TODO with http://www.palmos.com/dev/support/docs/protein_books/Memory_Databases_Files/
@@ -1060,39 +1152,49 @@ wxCopyFile (const wxString& file1, const wxString& file2, bool overwrite)
         return false;
     }
 
-    // reset the umask as we want to create the file with exactly the same
-    // permissions as the original one
-    wxCHANGE_UMASK(0);
-
-    // create file2 with the same permissions than file1 and open it for
-    // writing
+    wxDoCopyFile(fileIn, fbuf, file2, overwrite);
 
-    wxFile fileOut;
-    if ( !fileOut.Create(file2, overwrite, fbuf.st_mode & 0777) )
-        return false;
+#if defined(__WXMAC__) || defined(__WXCOCOA__)
+    // copy the resource fork of the file too if it's present
+    wxString pathRsrcOut;
+    wxFile fileRsrcIn;
 
-    // copy contents of file1 to file2
-    char buf[4096];
-    size_t count;
-    for ( ;; )
     {
-        count = fileIn.Read(buf, WXSIZEOF(buf));
-        if ( fileIn.Error() )
-            return false;
+        // suppress error messages from this block as resource forks don't have
+        // to exist
+        wxLogNull noLog;
+
+        // it's not enough to check for file existence: it always does on HFS
+        // but is empty for files without resources
+        if ( fileRsrcIn.Open(file1 + wxT("/..namedfork/rsrc")) &&
+                fileRsrcIn.Length() > 0 )
+        {
+            // we must be using HFS or another filesystem with resource fork
+            // support, suppose that destination file system also is HFS[-like]
+            pathRsrcOut = file2 + wxT("/..namedfork/rsrc");
+        }
+        else // check if we have resource fork in separate file (non-HFS case)
+        {
+            wxFileName fnRsrc(file1);
+            fnRsrc.SetName(wxT("._") + fnRsrc.GetName());
 
-        // end of file?
-        if ( !count )
-            break;
+            fileRsrcIn.Close();
+            if ( fileRsrcIn.Open( fnRsrc.GetFullPath() ) )
+            {
+                fnRsrc = file2;
+                fnRsrc.SetName(wxT("._") + fnRsrc.GetName());
 
-        if ( fileOut.Write(buf, count) < count )
-            return false;
+                pathRsrcOut = fnRsrc.GetFullPath();
+            }
+        }
     }
 
-    // we can expect fileIn to be closed successfully, but we should ensure
-    // that fileOut was closed as some write errors (disk full) might not be
-    // detected before doing this
-    if ( !fileIn.Close() || !fileOut.Close() )
-        return false;
+    if ( !pathRsrcOut.empty() )
+    {
+        if ( !wxDoCopyFile(fileRsrcIn, fbuf, pathRsrcOut, overwrite) )
+            return false;
+    }
+#endif // wxMac || wxCocoa
 
 #if !defined(__VISAGECPP__) && !defined(__WXMAC__) || defined(__UNIX__)
     // no chmod in VA.  Should be some permission API for HPFS386 partitions
@@ -1221,9 +1323,9 @@ bool wxRmdir(const wxString& dir, int WXUNUSED(flags))
 #if defined(__VMS__)
     return false; //to be changed since rmdir exists in VMS7.x
 #elif defined(__OS2__)
-    return (::DosDeleteDir((PSZ)dir.c_str()) == 0);
+    return (::DosDeleteDir(dir.c_str()) == 0);
 #elif defined(__WXWINCE__)
-    return (CreateDirectory(dir, NULL) != 0);
+    return (RemoveDirectory(dir) != 0);
 #elif defined(__WXPALMOS__)
     // TODO with VFSFileRename()
     return false;
@@ -1233,14 +1335,14 @@ bool wxRmdir(const wxString& dir, int WXUNUSED(flags))
 }
 
 // does the path exists? (may have or not '/' or '\\' at the end)
-bool wxDirExists(const wxChar *pszPathName)
+bool wxDirExists(const wxString& pathName)
 {
-    wxString strPath(pszPathName);
+    wxString strPath(pathName);
 
 #if defined(__WINDOWS__) || defined(__OS2__)
     // Windows fails to find directory named "c:\dir\" even if "c:\dir" exists,
     // so remove all trailing backslashes from the path - but don't do this for
-    // the pathes "d:\" (which are different from "d:") nor for just "\"
+    // the paths "d:\" (which are different from "d:") nor for just "\"
     while ( wxEndsWithPathSeparator(strPath) )
     {
         size_t len = strPath.length();
@@ -1279,7 +1381,7 @@ bool wxDirExists(const wxChar *pszPathName)
     return wxStat(strPath.c_str(), &st) == 0 && ((st.st_mode & S_IFMT) == S_IFDIR);
 #else
     // S_IFMT not supported in VA compilers.. st_mode is a 2byte value only
-    return wxStat(pszPathName, &st) == 0 && (st.st_mode == S_IFDIR);
+    return wxStat(strPath.c_str(), &st) == 0 && (st.st_mode == S_IFDIR);
 #endif
 
 #endif // __WIN32__/!__WIN32__
@@ -1288,9 +1390,8 @@ bool wxDirExists(const wxChar *pszPathName)
 // Get a temporary filename, opening and closing the file.
 wxChar *wxGetTempFileName(const wxString& prefix, wxChar *buf)
 {
-#if wxUSE_FILE
-    wxString filename = wxFileName::CreateTempFileName(prefix);
-    if ( filename.empty() )
+    wxString filename;
+    if ( !wxGetTempFileName(prefix, filename) )
         return NULL;
 
     if ( buf )
@@ -1299,19 +1400,20 @@ wxChar *wxGetTempFileName(const wxString& prefix, wxChar *buf)
         buf = MYcopystring(filename);
 
     return buf;
-#else
-    wxUnusedVar(prefix);
-    wxUnusedVar(buf);
-    // wxFileName::CreateTempFileName needs wxFile class enabled
-    return NULL;
-#endif
 }
 
 bool wxGetTempFileName(const wxString& prefix, wxString& buf)
 {
-    buf = wxGetTempFileName(prefix);
+#if wxUSE_FILE
+    buf = wxFileName::CreateTempFileName(prefix);
 
     return !buf.empty();
+#else // !wxUSE_FILE
+    wxUnusedVar(prefix);
+    wxUnusedVar(buf);
+
+    return false;
+#endif // wxUSE_FILE/!wxUSE_FILE
 }
 
 // Get first file name matching given wild card.
@@ -1411,7 +1513,7 @@ wxChar *wxDoGetCwd(wxChar *buf, int sz)
 
     #ifdef HAVE_WGETCWD
         #if wxUSE_UNICODE_MSLU
-            if ( wxGetOsVersion() != wxWIN95 )
+            if ( wxGetOsVersion() != wxOS_WINDOWS_9X )
         #else
             char *cbuf = NULL; // never really used because needsANSI will always be false
         #endif
@@ -1528,7 +1630,15 @@ wxString wxGetCwd()
 bool wxSetWorkingDirectory(const wxString& d)
 {
 #if defined(__OS2__)
-    return (::DosSetCurrentDir((PSZ)d.c_str()) == 0);
+    if (d[1] == ':')
+    {
+        ::DosSetDefaultDisk(1 + wxToupper(d[0]) - _T('A'));
+       // do not call DosSetCurrentDir when just changing drive,
+       // since it requires e.g. "d:." instead of "d:"!
+       if (d.length() == 2)
+           return true;
+    }
+    return (::DosSetCurrentDir(d.c_str()) == 0);
 #elif defined(__UNIX__) || defined(__WXMAC__) || defined(__DOS__)
     return (chdir(wxFNSTRINGCAST d.fn_str()) == 0);
 #elif defined(__WINDOWS__)
@@ -1645,6 +1755,8 @@ void WXDLLEXPORT wxSplitPath(const wxChar *pszFileName,
     wxFileName::SplitPath(pszFileName, pstrPath, pstrName, pstrExt);
 }
 
+#if wxUSE_DATETIME
+
 time_t WXDLLEXPORT wxFileModificationTime(const wxString& filename)
 {
     wxDateTime mtime;
@@ -1654,6 +1766,8 @@ time_t WXDLLEXPORT wxFileModificationTime(const wxString& filename)
     return mtime.GetTicks();
 }
 
+#endif // wxUSE_DATETIME
+
 
 // Parses the filterStr, returning the number of filters.
 // Returns 0 if none or if there's a problem.
@@ -1766,6 +1880,152 @@ int WXDLLEXPORT wxParseCommonDialogsFilter(const wxString& filterStr,
     return filters.GetCount();
 }
 
+#if defined(__WINDOWS__) && !(defined(__UNIX__) || defined(__OS2__))
+static bool wxCheckWin32Permission(const wxString& path, DWORD access)
+{
+    // quoting the MSDN: "To obtain a handle to a directory, call the
+    // CreateFile function with the FILE_FLAG_BACKUP_SEMANTICS flag", but this
+    // doesn't work under Win9x/ME but then it's not needed there anyhow
+    bool isdir = wxDirExists(path);
+    if ( isdir && wxGetOsVersion() == wxOS_WINDOWS_9X )
+    {
+        // FAT directories always allow all access, even if they have the
+        // readonly flag set
+        return true;
+    }
+
+    HANDLE h = ::CreateFile
+                 (
+                    path.c_str(),
+                    access,
+                    FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                    NULL,
+                    OPEN_EXISTING,
+                    isdir ? FILE_FLAG_BACKUP_SEMANTICS : 0,
+                    NULL
+                 );
+    if ( h != INVALID_HANDLE_VALUE )
+        CloseHandle(h);
+
+    return h != INVALID_HANDLE_VALUE;
+}
+#endif // __WINDOWS__
+
+bool wxIsWritable(const wxString &path)
+{
+#if defined( __UNIX__ ) || defined(__OS2__)
+    // access() will take in count also symbolic links
+    return access(wxConvFile.cWX2MB(path), W_OK) == 0;
+#elif defined( __WINDOWS__ )
+    return wxCheckWin32Permission(path, GENERIC_WRITE);
+#else
+    wxUnusedVar(path);
+    // TODO
+    return false;
+#endif
+}
+
+bool wxIsReadable(const wxString &path)
+{
+#if defined( __UNIX__ ) || defined(__OS2__)
+    // access() will take in count also symbolic links
+    return access(wxConvFile.cWX2MB(path), R_OK) == 0;
+#elif defined( __WINDOWS__ )
+    return wxCheckWin32Permission(path, GENERIC_READ);
+#else
+    wxUnusedVar(path);
+    // TODO
+    return false;
+#endif
+}
+
+bool wxIsExecutable(const wxString &path)
+{
+#if defined( __UNIX__ ) || defined(__OS2__)
+    // access() will take in count also symbolic links
+    return access(wxConvFile.cWX2MB(path), X_OK) == 0;
+#elif defined( __WINDOWS__ )
+   return wxCheckWin32Permission(path, GENERIC_EXECUTE);
+#else
+    wxUnusedVar(path);
+    // TODO
+    return false;
+#endif
+}
+
+// Return the type of an open file
+//
+// Some file types on some platforms seem seekable but in fact are not.
+// The main use of this function is to allow such cases to be detected
+// (IsSeekable() is implemented as wxGetFileKind() == wxFILE_KIND_DISK).
+//
+// This is important for the archive streams, which benefit greatly from
+// being able to seek on a stream, but which will produce corrupt archives
+// if they unknowingly seek on a non-seekable stream.
+//
+// wxFILE_KIND_DISK is a good catch all return value, since other values
+// disable features of the archive streams. Some other value must be returned
+// for a file type that appears seekable but isn't.
+//
+// Known examples:
+//   *  Pipes on Windows
+//   *  Files on VMS with a record format other than StreamLF
+//
+wxFileKind wxGetFileKind(int fd)
+{
+#if defined __WXMSW__ && !defined __WXWINCE__ && defined wxGetOSFHandle
+    switch (::GetFileType(wxGetOSFHandle(fd)) & ~FILE_TYPE_REMOTE)
+    {
+        case FILE_TYPE_CHAR:
+            return wxFILE_KIND_TERMINAL;
+        case FILE_TYPE_DISK:
+            return wxFILE_KIND_DISK;
+        case FILE_TYPE_PIPE:
+            return wxFILE_KIND_PIPE;
+    }
+
+    return wxFILE_KIND_UNKNOWN;
+
+#elif defined(__UNIX__)
+    if (isatty(fd))
+        return wxFILE_KIND_TERMINAL;
+
+    struct stat st;
+    fstat(fd, &st);
+
+    if (S_ISFIFO(st.st_mode))
+        return wxFILE_KIND_PIPE;
+    if (!S_ISREG(st.st_mode))
+        return wxFILE_KIND_UNKNOWN;
+
+    #if defined(__VMS__)
+        if (st.st_fab_rfm != FAB$C_STMLF)
+            return wxFILE_KIND_UNKNOWN;
+    #endif
+
+    return wxFILE_KIND_DISK;
+
+#else
+    #define wxFILEKIND_STUB
+    (void)fd;
+    return wxFILE_KIND_DISK;
+#endif
+}
+
+wxFileKind wxGetFileKind(FILE *fp)
+{
+    // Note: The watcom rtl dll doesn't have fileno (the static lib does).
+    //       Should be fixed in version 1.4.
+#if defined(wxFILEKIND_STUB) || wxONLY_WATCOM_EARLIER_THAN(1,4)
+    (void)fp;
+    return wxFILE_KIND_DISK;
+#elif defined(__WINDOWS__) && !defined(__CYGWIN__) && !defined(__WATCOMC__) && !defined(__WINE__)
+    return fp ? wxGetFileKind(_fileno(fp)) : wxFILE_KIND_UNKNOWN;
+#else
+    return fp ? wxGetFileKind(fileno(fp)) : wxFILE_KIND_UNKNOWN;
+#endif
+}
+
 
 //------------------------------------------------------------------------
 // wild character routines
@@ -1898,77 +2158,6 @@ bool wxMatchWild( const wxString& pat, const wxString& text, bool dot_special )
     }
 }
 
-// Return the type of an open file
-//
-// Some file types on some platforms seem seekable but in fact are not.
-// The main use of this function is to allow such cases to be detected
-// (IsSeekable() is implemented as wxGetFileKind() == wxFILE_KIND_DISK).
-//
-// This is important for the archive streams, which benefit greatly from
-// being able to seek on a stream, but which will produce corrupt archives
-// if they unknowingly seek on a non-seekable stream.
-//
-// wxFILE_KIND_DISK is a good catch all return value, since other values
-// disable features of the archive streams. Some other value must be returned
-// for a file type that appears seekable but isn't.
-//
-// Known examples:
-//   *  Pipes on Windows
-//   *  Files on VMS with a record format other than StreamLF
-//
-wxFileKind wxGetFileKind(int fd)
-{
-#if defined __WXMSW__ && !defined __WXWINCE__ && defined wxGetOSFHandle
-    switch (::GetFileType(wxGetOSFHandle(fd)) & ~FILE_TYPE_REMOTE)
-    {
-        case FILE_TYPE_CHAR:
-            return wxFILE_KIND_TERMINAL;
-        case FILE_TYPE_DISK:
-            return wxFILE_KIND_DISK;
-        case FILE_TYPE_PIPE:
-            return wxFILE_KIND_PIPE;
-    }
-
-    return wxFILE_KIND_UNKNOWN;
-
-#elif defined(__UNIX__)
-    if (isatty(fd))
-        return wxFILE_KIND_TERMINAL;
-
-    struct stat st;
-    fstat(fd, &st);
-
-    if (S_ISFIFO(st.st_mode))
-        return wxFILE_KIND_PIPE;
-    if (!S_ISREG(st.st_mode))
-        return wxFILE_KIND_UNKNOWN;
-
-    #if defined(__VMS__)
-        if (st.st_fab_rfm != FAB$C_STMLF)
-            return wxFILE_KIND_UNKNOWN;
-    #endif
-
-    return wxFILE_KIND_DISK;
-
-#else
-    #define wxFILEKIND_STUB
-    (void)fd;
-    return wxFILE_KIND_DISK;
-#endif
-}
-
-wxFileKind wxGetFileKind(FILE *fp)
-{
-    // Note: The watcom rtl dll doesn't have fileno (the static lib does).
-    //       Should be fixed in version 1.4.
-#if defined(wxFILEKIND_STUB) || wxONLY_WATCOM_EARLIER_THAN(1,4)
-    (void)fp;
-    return wxFILE_KIND_DISK;
-#else
-    return fp ? wxGetFileKind(fileno(fp)) : wxFILE_KIND_UNKNOWN;
-#endif
-}
-
 #ifdef __VISUALC__
     #pragma warning(default:4706)   // assignment within conditional expression
 #endif // VC++