MSVC2015 上的实验性 C++17 文件系统:权限不一致

Experimental C++17 filesystem on MSVC2015: inconsistencies with permissions

我正在尝试使用实验性 <filesystem> library that should become part of C++17 (See draft technical spec N4100) on MSVC2015(更新 1)。

我可以设法递归显示目录的全部内容:

    using namespace std::tr2::sys;
    ...
    path dir = canonical(".");
    for (auto& p : recursive_directory_iterator(dir)) {
        if (is_regular_file(p))                
            cout << file_size(p);               
        perms pe = p.status().permissions();  // get authorisations
        cout <<"\t"<< (pe & perms::owner_read ? "r" : "-") // <== error should be allowed
            << (pe & perms::owner_write ? "w" : "-");
        cout <<"\t" << p << endl;     
    }

问题与疑问:

  1. perms object: The compiler complains with a C2440 error 上的按位 & 关于缺少从 perms 到 bool 的转换。但根据规范,这应该是允许的。这是一个错误还是我错过了什么?

  2. 我通过将 pe 转换为无符号来绕过这个问题。在那里我注意到每个文件的值总是 0xffff,包括我故意撤回写作授权的文件。系统会为 windows 上的权限返回一个恒定的虚拟值,还是我忘记了一些东西来获得有效权限?

更新:我在下面所说的关于 Windows' 权限的内容是正确的,但由于某些原因甚至 FILE_ATTRIBUTE_READONLY 位似乎也不是在职的。我会提交错误 :)

作为目前的解决方法,您可以对生成的路径记录执行 status(),例如

#include <filesystem>
#include <iostream>
using namespace std;
using namespace std::tr2::sys;

int main() {
    path dir = canonical(".");
    for (auto& p : recursive_directory_iterator(dir)) {
        if (is_regular_file(p))
            cout << file_size(p);
        file_status stat = status(p); // Workaround bug in MSVC++2015
        perms pe = stat.permissions();  // get authorizations
        cout <<"\t"<< ((pe & perms::owner_read) != perms::none ? "r" : "-")
            << ((pe & perms::owner_write) != perms::none ? "w" : "-");
        cout <<"\t" << p << endl;
    }
}

在我的系统上产生:

PS C:\Users\bion\Desktop\test> ..\fs.exe
68494859        r-      C:\Users\bion\Desktop\test\read-only.mp3
93805063        rw      C:\Users\bion\Desktop\test\read-write.mp3
PS C:\Users\bion\Desktop\test>

Bitwise & on the perms object: The compiler complains with a C2440 error about a missing conversion from perms to bool. But this should be allowed according to specs. Is this a bug or did I miss something ?

按位 & 通过重载 operator& 得到支持,应该可以正常工作。没有转换为 bool。如果你想转换为 bool,正确的方法是与 enum class 声明的常量进行比较,例如:

if ((permsVar & perms::owner_read) != perms::none)

或使用该枚举的 direct-initialized 实例 class:

if ((permsVar & perms::owner_read) != perms{})

[bitmask.types] 只会说:

The value Y is set in the object X if the expression X & Y is nonzero.

并不是说有一些文字 0 的转换可以用来与 enum class 进行比较。

I cirumvented the issue by converting pe an unsigned. There I noted that the value is always 0xffff, for every files, including a file where I have intentionally withdrawn writing authorisations. Will a constant dummy value be returned for permissions on windows systematically or did I forget something to get the valid permissions ?

Windows' 权限模型确实与 Unix 权限模型没有类似之处——安全描述符确实具有所有者和组所有者值,但是没有普遍接受的约定来映射 Windows DACL(它可以表达比 Unix 权限更多的 finer-grained 权限结构)和 Unix 权限。

因此,目前我们只查找 readonly 属性,或者一组特定的属性,如果不是,我们 "punt" 并说权限未知。如果你想便携,你需要用未知常量做一些事情。

        // FILE STATUS FUNCTIONS
_FS_DLL _File_type __CLRCALL_PURE_OR_CDECL _Stat(const TCHAR *_Fname, _Perms *_Pmode)
    {   // get file status
    WIN32_FILE_ATTRIBUTE_DATA _Data;

    if (TFUN(GetFileAttributesEx)(_Fname, GetFileExInfoStandard, &_Data))
        {   // get file type and return permissions
        // !!! Here's where we check
        if (_Pmode != 0)
            *_Pmode = _Data.dwFileAttributes & FILE_ATTRIBUTE_READONLY
                ? READONLY_PERMS : perms::all;
        return (_Map_mode(_Data.dwFileAttributes));
        }
    else
        {   // invalid, get error code
        // error mapping code omitted
        }
    }

您希望我们使用以下安全描述符做什么:

O:BAG:SYD:PAI(A;;WD;;;WD)(A;;FA;;;S-1-5-21-2127521184-1604012920-1887927527-9342113)(A;;0x4;;;BA)

上面写着:

O:BA: 拥有者是BUILTIN\ADMINISTRATORS.
G:SY: 群主是NT AUTHORITY\LOCAL SYSTEM。请注意,在 Windows 权限中通常根本不使用该组,它的存在只是为了与 Interix 兼容,在这种情况下,Interix 是唯一一个读取或写入安全描述符的组,因此可以为所欲为。 :)
D:PAI:DACL为DACL_PROTECTED(不继承parents的权限)和DACL_AUTO_INHERIT(参与正常的权限继承系统;例如,此文件系统 object 的 children 将从中继承权限)

  • (A;;WD;;;WD):授予WRITE_DAC(更改安全描述符的DACL部分的权限)访问WORLD\EVERYONE.嗯,WRITE_DAC 不是读取、写入或执行,那么我们在那里做什么?
  • (A;;FA;;;S-1-5-21-2127521184-1604012920-1887927527-9342113): 将 FILE_ALL_ACCESS 授予 REDMOND\bion.请注意,我不是所有者、组所有者或 "others" 那么您将如何映射它?
  • (A;;0x4;;;BA)FILE_APPEND_DATA 授予 BUILTIN\ADMINISTRATORS。这有点像写入,但不允许您更改文件中已有的内容...

(我遗漏了一堆东西,比如强制访问控制....)

我并不是说我们不能尝试在这个映射上做得更好,但是如果你需要做重要的权限工作,<filesystem> TS 不能在支持访问的系统上真正帮助你控制列表。