diff --git a/SystemTools.cxx b/SystemTools.cxx
index 7eecde7d04f950add01d59411682863c590abba4..9b40e17e76f6d550d931c803f9a4bd571072244f 100644
--- a/SystemTools.cxx
+++ b/SystemTools.cxx
@@ -1252,6 +1252,43 @@ bool SystemTools::FileExists(const kwsys_stl::string& filename, bool isFile)
   return false;
 }
 
+//----------------------------------------------------------------------------
+bool SystemTools::TestFileAccess(const char* filename,
+                                 TestFilePermissions permissions)
+{
+  if(!filename)
+    {
+    return false;
+    }
+  return SystemTools::TestFileAccess(kwsys_stl::string(filename),
+                                     permissions);
+}
+
+//----------------------------------------------------------------------------
+bool SystemTools::TestFileAccess(const kwsys_stl::string& filename,
+                                 TestFilePermissions permissions)
+{
+  if(filename.empty())
+    {
+    return false;
+    }
+#if defined(_WIN32) && !defined(__CYGWIN__)
+  // If execute set, change to read permission (all files on Windows
+  // are executable if they are readable).  The CRT will always fail
+  // if you pass an execute bit.
+  if(permissions & TEST_FILE_EXECUTE)
+    {
+    permissions &= ~TEST_FILE_EXECUTE;
+    permissions |= TEST_FILE_READ;
+    }
+  return _waccess(
+    SystemTools::ConvertToWindowsExtendedPath(filename).c_str(),
+    permissions) == 0;
+#else
+  return access(filename.c_str(), permissions) == 0;
+#endif
+}
+
 //----------------------------------------------------------------------------
 #ifdef __CYGWIN__
 bool SystemTools::PathCygwinToWin32(const char *path, char *win32_path)
diff --git a/SystemTools.hxx.in b/SystemTools.hxx.in
index ca22b6c192c16c3bb959b5a145ab85954af0355d..d181dc024d53d4fe7e89a97b6160d06bed22bb40 100644
--- a/SystemTools.hxx.in
+++ b/SystemTools.hxx.in
@@ -21,6 +21,9 @@
 #include <@KWSYS_NAMESPACE@/String.hxx>
 
 #include <sys/types.h>
+#if !defined(_WIN32) || defined(__CYGWIN__)
+# include <unistd.h> // For access permissions for use with access()
+#endif
 
 // Required for va_list
 #include <stdarg.h>
@@ -72,6 +75,24 @@ public:
 // before it is used and is the last static object destroyed.
 static SystemToolsManager SystemToolsManagerInstance;
 
+// Flags for use with TestFileAccess.  Use a typedef in case any operating
+// system in the future needs a special type.  These are flags that may be
+// combined using the | operator.
+typedef int TestFilePermissions;
+#if defined(_WIN32) && !defined(__CYGWIN__)
+  // On Windows (VC and Borland), no system header defines these constants...
+  static const TestFilePermissions TEST_FILE_OK = 0;
+  static const TestFilePermissions TEST_FILE_READ = 4;
+  static const TestFilePermissions TEST_FILE_WRITE = 2;
+  static const TestFilePermissions TEST_FILE_EXECUTE = 1;
+#else
+  // Standard POSIX constants
+  static const TestFilePermissions TEST_FILE_OK = F_OK;
+  static const TestFilePermissions TEST_FILE_READ = R_OK;
+  static const TestFilePermissions TEST_FILE_WRITE = W_OK;
+  static const TestFilePermissions TEST_FILE_EXECUTE = X_OK;
+#endif
+
 /** \class SystemTools
  * \brief A collection of useful platform-independent system functions.
  */
@@ -301,6 +322,21 @@ public:
   static bool FileExists(const char* filename);
   static bool FileExists(const kwsys_stl::string& filename);
 
+  /**
+   * Test if a file exists and can be accessed with the requested
+   * permissions.  Symbolic links are followed.  Returns true if
+   * the access test was successful.
+   *
+   * On POSIX systems (including Cygwin), this maps to the access
+   * function.  On Windows systems, all existing files are
+   * considered readable, and writable files are considered to
+   * have the read-only file attribute cleared.
+   */
+  static bool TestFileAccess(const char* filename,
+                             TestFilePermissions permissions);
+  static bool TestFileAccess(const kwsys_stl::string& filename,
+                             TestFilePermissions permissions);
+
   /**
    * Converts Cygwin path to Win32 path. Uses dictionary container for
    * caching and calls to cygwin_conv_to_win32_path from Cygwin dll