如何设置文件权限(跨平台)
我正在使用C ++ ofstream
来写出一个文件。 我想将权限设置为只能由用户访问:700.在unix中; 我想我可以发出一个system("chmod 700 file.txt");
但是我需要这个代码来在Windows上工作。 我可以使用一些Windows API; 但是什么是最好的c ++跨平台的方式来做到这一点?
具有讽刺意味的是,我今天早些时候也遇到了同样的需求。
就我而言,答案归结为Windows和Linux所需的权限级别。 就我而言,我只关心Linux上的用户,组和其他权限。 在Windows上,从DOS剩余的基本读/写权限对我来说足够好,即我不需要在Windows上处理ACL。
一般来说,Windows有两种特权模式:基本的DOS模式和较新的访问控制模式。 在DOS模式下,有一种特权:写权限。 所有文件都可以被读取,所以没有办法closures读取权限(因为它不存在)。 也没有执行权限的概念。 如果一个文件可以被读取(答案是肯定的)并且是二进制的,那么它可以被执行; 否则不能。
基本的DOS模型对于大多数Windows环境是足够的,即在一个可以被认为是相对安全的物理位置的单个用户使用系统的环境。 访问控制模型更复杂几个数量级。
访问控制模型使用访问控制列表(ACL)来授予权限。 特权只能由具有必要特权的进程授予。 这个模型不仅允许用户,组和其他用户具有读,写和执行权限的控制,还允许通过networking和Windows域之间的文件控制。 (你也可以用Unix在Unix系统上得到这样的疯狂程度。)
注意:只有在使用FAT分区的情况下,访问控制模型才可用于NTFS分区。
使用ACL是一个很大的麻烦。 这不是一件小事,它需要您学习不仅仅是ACL,还要学习所有关于安全描述符,访问令牌和其他高级Windows安全概念的知识。
幸运的是,对于我目前的需求,我不需要访问控制模型提供的真正的安全性。 我可以基本上假装在Windows上设置权限,只要我真的在Linux上设置权限。
Windows支持他们称之为“ISO C ++一致性”版本的chmod(2)。 这个API被称为_chmod,它和chmod(2)类似,但是更受限制,而不是types或名称兼容(当然)。 Windows也有一个不推荐使用的chmod,所以你不能简单的把chmod添加到Windows上,而是在Linux上直接使用chmod(2)。
我写了以下内容:
#include <sys/stat.h> #include <sys/types.h> #ifdef _WIN32 # include <io.h> typedef int mode_t; /// @Note If STRICT_UGO_PERMISSIONS is not defined, then setting Read for any /// of User, Group, or Other will set Read for User and setting Write /// will set Write for User. Otherwise, Read and Write for Group and /// Other are ignored. /// /// @Note For the POSIX modes that do not have a Windows equivalent, the modes /// defined here use the POSIX values left shifted 16 bits. static const mode_t S_ISUID = 0x08000000; ///< does nothing static const mode_t S_ISGID = 0x04000000; ///< does nothing static const mode_t S_ISVTX = 0x02000000; ///< does nothing static const mode_t S_IRUSR = mode_t(_S_IREAD); ///< read by user static const mode_t S_IWUSR = mode_t(_S_IWRITE); ///< write by user static const mode_t S_IXUSR = 0x00400000; ///< does nothing # ifndef STRICT_UGO_PERMISSIONS static const mode_t S_IRGRP = mode_t(_S_IREAD); ///< read by *USER* static const mode_t S_IWGRP = mode_t(_S_IWRITE); ///< write by *USER* static const mode_t S_IXGRP = 0x00080000; ///< does nothing static const mode_t S_IROTH = mode_t(_S_IREAD); ///< read by *USER* static const mode_t S_IWOTH = mode_t(_S_IWRITE); ///< write by *USER* static const mode_t S_IXOTH = 0x00010000; ///< does nothing # else static const mode_t S_IRGRP = 0x00200000; ///< does nothing static const mode_t S_IWGRP = 0x00100000; ///< does nothing static const mode_t S_IXGRP = 0x00080000; ///< does nothing static const mode_t S_IROTH = 0x00040000; ///< does nothing static const mode_t S_IWOTH = 0x00020000; ///< does nothing static const mode_t S_IXOTH = 0x00010000; ///< does nothing # endif static const mode_t MS_MODE_MASK = 0x0000ffff; ///< low word static inline int my_chmod(const char * path, mode_t mode) { int result = _chmod(path, (mode & MS_MODE_MASK)); if (result != 0) { result = errno; } return (result); } #else static inline int my_chmod(const char * path, mode_t mode) { int result = chmod(path, mode); if (result != 0) { result = errno; } return (result); } #endif
记住我的解决scheme只提供DOStypes的安全性是很重要的。 这也被称为无安全性,但这是大多数应用程序在Windows上提供的安全性。
另外,在我的解决scheme中,如果您没有定义STRICT_UGO_PERMISSIONS,那么当您授予组或其他权限(或将其删除)时,您确实正在更改所有者。 如果您不想这样做,但您仍然不需要完整的Windows ACL权限,只需定义STRICT_UGO_PERMISSIONS即可。
没有跨平台的方式来做到这一点。 Windows不支持Unix风格的文件权限。 为了做你想做的,你必须考虑为该文件创build一个访问控制列表,这将允许你明确定义用户和组的访问权限。
替代scheme可能是在安全设置已被设置为排除除用户之外的所有人的目录中创build文件。
system()
调用是一个奇怪的野兽。 在很多个月前的Mac上,我一直被NOP系统()的实现所咬。 它的实现定义意味着标准没有定义实现(平台/编译器)应该做什么。 不幸的是,这也是在你的函数范围之外做一些事情的唯一标准方法(在你的情况下 – 更改权限)。
更新:一个提议的黑客:
- 在您的系统上创build一个具有适当权限的非空文件。
-
使用Boost Filesystem的
copy_file
将这个文件复制到你想要的输出。void copy_file(const path& frompath, const path& topath)
:void copy_file(const path& frompath, const path& topath)
的文件的内容和属性被复制到由topath引用的文件中。 这个例程期望目标文件不存在; 如果目标文件存在,则会引发exception。 因此,这不等同于UNIX中的系统指定的cp命令。 还期望frompathvariables将引用一个适当的常规文件。 考虑这个例子:frompath引用一个符号链接/ tmp / file1,后者又引用一个文件/ tmp / file2; topath就是/ tmp / file3。 在这种情况下,copy_file将会失败。 与cp命令相比,这是另一个区别。 -
现在,用实际内容覆盖输出。
但是,这只是我在午夜之后很久才想到的一个黑客。 把它与一撮盐,并试试这:)
不知道它是否可以工作,但是可以使用Cygwin附带的chmod.exe
可执行文件。
在C ++中没有这样做的标准方法,但是对于这个特殊的需求,你可能应该使用#ifdef _WIN32编写一个自定义的包装器。 Qt在QFile类中有一个权限包装,但这当然意味着取决于Qt …
我刚刚从Windows命令行中find了一些方法来轻松地执行chmod 700 。 我要发布另一个问题,要求提供一个相同的win32安全描述符结构来帮助使用(如果在接下来的几个小时内我不能弄明白的话)。
Windows 2000和XP(凌乱,似乎总是提示):
echo Y|cacls *onlyme.txt* /g %username%:F
Windows 2003+:
icacls *onlyme.txt* /inheritance:r /grant %username%:r
编辑:
如果你有能力使用ATL,这篇文章涵盖了它(我没有Visual Studio可用): http : //www.codeproject.com/KB/winsdk/accessctrl2.aspx
实际上,它表示示例代码也包含非ATL示例代码 – 它应该有一些适用于您(和我!)的东西
需要记住的重要一点是,只有在win32上才能得到r / w / x的所有者,只需要从文件中清除所有的安全描述符,并为自己添加一个完全控制的描述符。
你不能以跨平台的方式进行。 在Linux中,你应该使用函数chmod(2)
而不是使用system(2)
来产生一个新的shell。 在Windows上,您必须使用各种授权function来创build具有适当权限的ACL(访问控制列表)。
使用C ++ 17及其std::filesystem
为文件设置0700的跨平台示例。
#include <exception> //#include <filesystem> #include <experimental/filesystem> // Use this for most compilers as of yet. //namespace fs = std::filesystem; namespace fs = std::experimental::filesystem; // Use this for most compilers as of yet. int main() { fs::path myFile = "path/to/file.ext"; try { fs::permissions(myFile, fs::perms::owner_all); // Uses fs::perm_options::replace. } catch (std::exception& e) { // Handle exception or use another overload of fs::permissions() // with std::error_code. } }
请参阅std::filesystem::permissions
, std::filesystem::perms
和std::filesystem::perm_options
。