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



我正在尝试使用实验性<filesystem>库,该库应该成为MSVC2015(更新 1)上的 C++17(请参阅技术规范 N4100 草案)的一部分。

我可以设法递归显示目录的完整内容:

    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对象上的按位&:编译器抱怨 C2440 错误,指出缺少从 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:UsersbionDesktoptest> ..fs.exe
68494859        r-      C:UsersbionDesktoptestread-only.mp3
93805063        rw      C:UsersbionDesktoptestread-write.mp3
PS C:UsersbionDesktoptest>

按位和在perms对象上:编译器抱怨C2440错误,关于缺少从perms到bool的转换。但根据规格,这应该是允许的。这是一个错误还是我错过了什么?

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

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

或者使用该枚举类的直接初始化实例:

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

[bitmask.types] 只说:

如果表达式 X 和 Y 不为零,则在对象 X 中设置值 Y。

并不是说您可以使用文字0进行一些转换 与enum class进行比较.

我通过将 pe 转换为未签名来解决这个问题。在那里,我注意到对于每个文件,该值始终是0xffff的,包括我故意撤回写作授权的文件。是否会系统地为Windows上的权限返回常量虚拟值,还是我忘记了获取有效权限的内容?

Windows的权限模型实际上与Unix权限模型没有类似之处 - 安全描述符确实具有所有者和组所有者值,但是在Windows DACL(可以表达比Unix权限更细粒度的权限构造)和Unix权限之间没有普遍接受的约定。

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

        // 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:主人BUILTINADMINISTRATORS
G:SY:组所有者是NT AUTHORITYLOCAL SYSTEM。请注意,该组通常根本不在Windows权限中使用,并且仅用于与Interix兼容,在这种情况下,Interix是唯一读取或写入安全描述符的人,因此可以执行任何它想要的操作。
:)D:PAI:DACL 是DACL_PROTECTED的(不从父级继承权限)和DACL_AUTO_INHERIT(参与正常的权限继承系统;例如,此文件系统对象的子对象将从中继承权限)

  • (一;;白矮星;;;WD):授予WRITE_DAC(更改安全描述符的 DACL 部分的权限)对WORLDEVERYONE的访问权限。嗯,WRITE_DAC不是读、写或执行,那么我们会在那里做什么?
  • (一;;发;;;S-1-5-21-2127521184-1604012920-1887927527-9342113):授予FILE_ALL_ACCESS REDMONDbion。请注意,我不是所有者、组所有者或"其他人",那么您将如何映射它?
  • (A;;0x4;;;BA) 授予FILE_APPEND_DATA BUILTINADMINISTRATORS。这有点像写入,但不允许您更改文件中已有的内容......

(而且我省略了一堆东西,比如强制访问控制......

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

最新更新