From cdaf522ce72f975f924903192aa9116d314a72c4 Mon Sep 17 00:00:00 2001 From: James Johnston <johnstonj.public@codenest.com> Date: Sun, 16 Aug 2015 19:47:11 -0400 Subject: [PATCH] SystemTools: Add honor_umask parameter to SetPermissions. If honor_umask is set, the umask is queried and applied to the given permissions when calling SetPermissions. Change-Id: I302231a2ae7f0c4610eb47fdb256fa02934ecd8c --- SystemTools.cxx | 26 ++++++-- SystemTools.hxx.in | 16 ++++- testSystemTools.cxx | 140 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 175 insertions(+), 7 deletions(-) diff --git a/SystemTools.cxx b/SystemTools.cxx index 9b40e17e..f12a06c4 100644 --- a/SystemTools.cxx +++ b/SystemTools.cxx @@ -68,6 +68,10 @@ #include <sys/stat.h> #include <time.h> +#ifdef _MSC_VER +# define umask _umask // Note this is still umask on Borland +#endif + // support for realpath call #ifndef _WIN32 #include <sys/time.h> @@ -4780,21 +4784,35 @@ bool SystemTools::GetPermissions(const kwsys_stl::string& file, mode_t& mode) return true; } -bool SystemTools::SetPermissions(const char* file, mode_t mode) +bool SystemTools::SetPermissions(const char* file, + mode_t mode, + bool honor_umask) { if ( !file ) { return false; } - return SystemTools::SetPermissions(kwsys_stl::string(file), mode); + return SystemTools::SetPermissions( + kwsys_stl::string(file), mode, honor_umask); } -bool SystemTools::SetPermissions(const kwsys_stl::string& file, mode_t mode) +bool SystemTools::SetPermissions(const kwsys_stl::string& file, + mode_t mode, + bool honor_umask) { - if ( !SystemTools::FileExists(file) ) + // TEMPORARY / TODO: After FileExists calls lstat() instead of + // access(), change this call to FileExists instead of + // TestFileAccess so that we don't follow symlinks. + if ( !SystemTools::TestFileAccess(file, TEST_FILE_OK) ) { return false; } + if (honor_umask) + { + mode_t currentMask = umask(0); + umask(currentMask); + mode &= ~currentMask; + } #ifdef _WIN32 if ( _wchmod(SystemTools::ConvertToWindowsExtendedPath(file).c_str(), mode) < 0 ) diff --git a/SystemTools.hxx.in b/SystemTools.hxx.in index d181dc02..164c5e04 100644 --- a/SystemTools.hxx.in +++ b/SystemTools.hxx.in @@ -758,17 +758,27 @@ public: */ static long int CreationTime(const kwsys_stl::string& filename); + /** + * Visual C++ does not define mode_t (note that Borland does, however). + */ #if defined( _MSC_VER ) typedef unsigned short mode_t; #endif /** - * Get and set permissions of the file. + * Get and set permissions of the file. If honor_umask is set, the umask + * is queried and applied to the given permissions. Returns false if + * failure. + * + * WARNING: A non-thread-safe method is currently used to get the umask + * if a honor_umask parameter is set to true. */ static bool GetPermissions(const char* file, mode_t& mode); static bool GetPermissions(const kwsys_stl::string& file, mode_t& mode); - static bool SetPermissions(const char* file, mode_t mode); - static bool SetPermissions(const kwsys_stl::string& file, mode_t mode); + static bool SetPermissions( + const char* file, mode_t mode, bool honor_umask = false); + static bool SetPermissions( + const kwsys_stl::string& file, mode_t mode, bool honor_umask = false); /** ----------------------------------------------------------------- * Time Manipulation Routines diff --git a/testSystemTools.cxx b/testSystemTools.cxx index ce8ec8b1..bc9ca5e5 100644 --- a/testSystemTools.cxx +++ b/testSystemTools.cxx @@ -30,6 +30,17 @@ #include <testSystemTools.h> #include <string.h> /* strcmp */ +#if defined(_WIN32) && !defined(__CYGWIN__) +# include <io.h> /* _umask (MSVC) / umask (Borland) */ +# ifdef _MSC_VER +# define umask _umask // Note this is still umask on Borland +# endif +#endif +#include <sys/stat.h> /* umask (POSIX), _S_I* constants (Windows) */ +// Visual C++ does not define mode_t (note that Borland does, however). +#if defined( _MSC_VER ) +typedef unsigned short mode_t; +#endif //---------------------------------------------------------------------------- static const char* toUnixPaths[][2] = @@ -170,6 +181,135 @@ static bool CheckFileOperations() res = false; } + // Reset umask +#if defined(_WIN32) && !defined(__CYGWIN__) + // NOTE: Windows doesn't support toggling _S_IREAD. + mode_t fullMask = _S_IWRITE; +#else + // On a normal POSIX platform, we can toggle all permissions. + mode_t fullMask = S_IRWXU | S_IRWXG | S_IRWXO; +#endif + mode_t orig_umask = umask(fullMask); + + // Test file permissions without umask + mode_t origPerm, thisPerm; + if (!kwsys::SystemTools::GetPermissions(testNewFile, origPerm)) + { + kwsys_ios::cerr + << "Problem with GetPermissions (1) for: " + << testNewFile << kwsys_ios::endl; + res = false; + } + + if (!kwsys::SystemTools::SetPermissions(testNewFile, 0)) + { + kwsys_ios::cerr + << "Problem with SetPermissions (1) for: " + << testNewFile << kwsys_ios::endl; + res = false; + } + + if (!kwsys::SystemTools::GetPermissions(testNewFile, thisPerm)) + { + kwsys_ios::cerr + << "Problem with GetPermissions (2) for: " + << testNewFile << kwsys_ios::endl; + res = false; + } + + if ((thisPerm & fullMask) != 0) + { + kwsys_ios::cerr + << "SetPermissions failed to set permissions (1) for: " + << testNewFile << ": actual = " << thisPerm << "; expected = " + << 0 << kwsys_ios::endl; + res = false; + } + + // While we're at it, check proper TestFileAccess functionality. + if (kwsys::SystemTools::TestFileAccess(testNewFile, + kwsys::TEST_FILE_WRITE)) + { + kwsys_ios::cerr + << "TestFileAccess incorrectly indicated that this is a writable file:" + << testNewFile << kwsys_ios::endl; + res = false; + } + + if (!kwsys::SystemTools::TestFileAccess(testNewFile, + kwsys::TEST_FILE_OK)) + { + kwsys_ios::cerr + << "TestFileAccess incorrectly indicated that this file does not exist:" + << testNewFile << kwsys_ios::endl; + res = false; + } + + // Test restoring/setting full permissions. + if (!kwsys::SystemTools::SetPermissions(testNewFile, fullMask)) + { + kwsys_ios::cerr + << "Problem with SetPermissions (2) for: " + << testNewFile << kwsys_ios::endl; + res = false; + } + + if (!kwsys::SystemTools::GetPermissions(testNewFile, thisPerm)) + { + kwsys_ios::cerr + << "Problem with GetPermissions (3) for: " + << testNewFile << kwsys_ios::endl; + res = false; + } + + if ((thisPerm & fullMask) != fullMask) + { + kwsys_ios::cerr + << "SetPermissions failed to set permissions (2) for: " + << testNewFile << ": actual = " << thisPerm << "; expected = " + << fullMask << kwsys_ios::endl; + res = false; + } + + // Test setting file permissions while honoring umask + if (!kwsys::SystemTools::SetPermissions(testNewFile, fullMask, true)) + { + kwsys_ios::cerr + << "Problem with SetPermissions (3) for: " + << testNewFile << kwsys_ios::endl; + res = false; + } + + if (!kwsys::SystemTools::GetPermissions(testNewFile, thisPerm)) + { + kwsys_ios::cerr + << "Problem with GetPermissions (4) for: " + << testNewFile << kwsys_ios::endl; + res = false; + } + + if ((thisPerm & fullMask) != 0) + { + kwsys_ios::cerr + << "SetPermissions failed to honor umask for: " + << testNewFile << ": actual = " << thisPerm << "; expected = " + << 0 << kwsys_ios::endl; + res = false; + } + + // Restore umask + umask(orig_umask); + + // Restore file permissions + if (!kwsys::SystemTools::SetPermissions(testNewFile, origPerm)) + { + kwsys_ios::cerr + << "Problem with SetPermissions (4) for: " + << testNewFile << kwsys_ios::endl; + res = false; + } + + // Remove the test file if (!kwsys::SystemTools::RemoveFile(testNewFile)) { kwsys_ios::cerr -- GitLab