如何正确使用MAXIMUM_ALLOWED?

问题描述 投票:0回答:1

我创建了一个小型框架,为多个文件系统/API(即 Win32、Posix、NFS)提供统一的 API。所述API有点类似于Posix——要访问文件,您需要“打开”它,它提供了预期目的的提示(

r
w
rw
)。类似于
open_file("/abc/log.txt", access::rw)

在这个框架中支持 Win32 API 让我很头疼,因为 Win32 的“声明性”性质——你应该预先知道你计划在给定的句柄上执行哪些操作,并将相关的

dwDesiredAccess
传递到相关的
(Nt)CreateFile()
调用中。不幸的是,除了通用的
r/w/rw
提示之外,框架不知道客户端将执行什么操作(即更改所有者、写入属性等)。而且我不愿意让 Win32 概念泄漏到我的框架中(即我不喜欢将
dwDesiredAccess
等效项添加到我的
open_file()
中)。

这是我尝试过的:

1。 MAXIMUM_ALLOWED

想法: 使用 MAXIMUM_ALLOWED 打开相关句柄——我将得到我能得到的一切,如果缺少某些权限,相关操作(例如

set_mtime()
)将简单地失败,并显示
access denied

问题:

  • 它不适用于只读文件或卷(
    (Nt)CreateFile()
    失败并显示
    access denied
  • MSDN 警告,如果 FAT 卷上正在进行碎片整理 - 尝试以这种方式打开目录将会失败
  • 总的来说,由于某种原因,使用
    MAXIMUM_ALLOWED
    似乎不受欢迎

2。必要时重新打开对象

想法: 虽然

r/w/rw
GENERIC_READ
表示
GENERIC_WRITE
,并且对于需要额外访问权限的所有操作(例如
delete()
需要
DELETE
),以所需的访问权限重新打开对象。

问题:

  • 重新开放对象并不便宜
  • 通过第二个对象所做的更改可以被静默覆盖,例如:
    • set_mtime()
      使用
      FILE_WRITE_ATTRIBUTES|SYNCHRONIZE
    • 重新打开文件
    • 调用
      NtSetInformationFile(... FileBasicInformation)
      更新元数据并关闭句柄
    • 后来原始句柄被关闭,它会导致数据刷新并默默地覆盖之前由
      ModifiedTime
       设置的 
      set_mtime()

3.复制句柄而不是重新打开对象

想法:与上一节相同,但不是重新打开对象——复制原始句柄(请求新的访问权限):

HANDLE h;
HANDLE hp = GetCurrentProcess();
CHECK_WIN32( DuplicateHandle(hp, hFile, hp, &h, FILE_WRITE_ATTRIBUTES|SYNCHRONIZE, FALSE, 0) );

问题:

  • 每次需要执行(非普通读/写)操作时复制(并关闭)文件句柄似乎过多且有些昂贵
  • DuplicateHandle()
    文档警告(未提供任何详细信息)请求额外访问权限可能失败。它在我检查过的所有用例中都工作得很好(通常要求在用
    DELETE
    打开的句柄上使用
    FILE_WRITE_ATTRIBUTES
    /
    GENERIC_READ
    之类的东西),但显然 Win32 API 不提供任何保证:-/

...否则方法似乎有效。

底线:

我正在寻找解决

MAXIMUM_ALLOWED
问题的方法。 (或者对替代方法的建议,也许?)

c++ winapi windows-kernel nt-native-api
1个回答
0
投票

编辑:这是另一个原因为什么重新打开文件不是一个好主意。

无法可靠地使用

MAXIMUM_ALLOWED
——R/O 文件和卷会导致其出错。设计不佳的功能。

另一种方法是获得最小访问权限并根据需要“扩展”它(通过使用新的

dwAccessRequired
标志重新打开文件)。这不起作用:

  • 如果您临时打开文件,通过新句柄所做的一些更改(例如

    mtime
    修改)将在稍后原始句柄关闭时被清除(并且底层内核对象将数据刷新到磁盘)

  • 如果您尝试用新句柄替换旧句柄,这意味着昂贵的刷新(在旧句柄关闭时)+ MT 同步,这意味着我无法从多个线程有效地使用我的

    file
    对象(我知道现在由于
     FILE_SYNCHRONOUS_IO_NONALERT
    无论如何,所有操作都会序列化,但会在短期内修复)

唉,

DuplicateHandle()
无法授予新的访问权限——所以这也无济于事。

基本上,我需要的是一个线程安全的

BOOL ExtendAccess(HANDLE h, DWORD dwAdditionalAccess)
函数。看起来即使通过 NT API 也无法获得它——只能在内核模式下实现。

幸运的是,这个框架始终在特权帐户下使用,这意味着我可以启用

SE_BACKUP_NAME
、使用
FILE_OPEN_FOR_BACKUP_INTENT
、过度请求访问(在只读量的情况下具有最小的回退)并避免处理限制性 DACL。啊,是的,处理
ReadOnly
中的
delete()
属性。还没决定如果用户想打开只读文件进行写入该怎么办...

我最终得到了这个:

W32Handle open_file_(HANDLE hparent, UNICODE_STRING zwpath, access a, disposition d, truncate t)
{
    ...
    ACCESS_MASK access = [a]() -> ACCESS_MASK {
        switch(a)
        {
        case access::r  : return GENERIC_READ;
        case access::w  : [[fallthrough]];                      // MSDN suggests to use GENERIC_READ with GENERIC_WRITE over network (performance reasons)
        case access::rw : return GENERIC_READ|GENERIC_WRITE;
        }
        UNREACHEABLE;
    }();

    constexpr DWORD write_access = FILE_WRITE_ATTRIBUTES|DELETE|WRITE_OWNER;    // we want to always have these (for apply, unlink, chown, etc)

    access |= write_access;
    access |= SYNCHRONIZE|READ_CONTROL|ACCESS_SYSTEM_SECURITY;                  // add "read DACL/SACL" rights (for full_metadata)

    ULONG flags = FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE|FILE_OPEN_FOR_BACKUP_INTENT;

    OBJECT_ATTRIBUTES oa;
    InitializeObjectAttributes(&oa, &zwpath, 0, hparent, NULL);

    HANDLE h;
    IO_STATUS_BLOCK io;
    NTSTATUS r = ZwCreateFile(&h, access, &oa, &io, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_VALID_FLAGS, disposition, flags, NULL, 0);
    if (r == STATUS_SUCCESS) return W32Handle(h);

    if (r == STATUS_MEDIA_WRITE_PROTECTED)      // try again without write flags
    {
        access &= ~write_access;
        r = ZwCreateFile(&h, access, &oa, &io, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_VALID_FLAGS, disposition, flags, NULL, 0);
        if (r == STATUS_SUCCESS) return W32Handle(h);
    }

    HR_THROW_(HRESULT_FROM_NT(r), "%s: Failed to open file", __func__);
}

总体来说 API 很糟糕,特殊情况就像意大利面条一样。我希望我有自己的 SMB 客户端。

© www.soinside.com 2019 - 2024. All rights reserved.