WinAPI判断文件是否可访问/私有的方法

3
在win32的c++中,有没有一种方法可以确定文件夹/文件是否可访问?您知道如果尝试访问C:/ Windows目录中的某个文件夹,您将收到一个弹出窗口,显示“此文件夹不可访问”。
也许有一个文件属性常量表示文件是私有的吗?也许类似于FILE_ATTRIBUTE_PRIVATE这样的东西?
WIN32_FIND_DATA dirData;

while (FindNextFile( dir, &dirData ) != 0 )
{
    // I made the following constant up
    if ( !(fileData.dwFileAttributes & FILE_ATTRIBUTE_PRIVATE) )
    {
        // file is accessible so store filepath
        files.push_back( fileData.cFileName );
    }
    else // file is not accessible so dont store
}

或者说唯一了解的方法就是去试一试:

dir = FindFirstFileEx( (LPCTSTR)directory.c_str(), FindExInfoStandard, &dirData, FindExSearchNameMatch, NULL, 0 );

if ( dir == ??? ) { the file is inaccessible } [/code]
4个回答

9

最好的方法就是尝试访问它。

你可以计算特定用户帐户的访问控制列表所授予的访问权限,但这相当复杂,而且在进行访问检查后权限可能会发生更改。因此,只需打开文件并处理访问被拒绝的错误即可。


2
"Access Denied" 意味着 GetLastError()==5. - MSalters

4
这不会是文件本身的标志,因为不同的帐户可能有访问不同文件/目录的权限。相反,Windows使用ACL(访问控制列表),这些数据结构确定谁可以访问什么。
在Windows中,ACL可与由句柄引用的任何内容一起使用(文件、目录、进程、互斥对象、命名管道...)。您可以通过转到文件属性并查看“安全”选项卡来查看文件ACL。
因此,在您的应用程序中,您不真正想检查标志,而是要将文件的ACL与您的应用程序正在运行的用户帐户进行比较。查看AccessCheck Win32函数。我认为这正是您要寻找的。
个人而言,我从未使用过该函数,但如果您正在寻找 Win32 解决方案并且需要一个函数调用,那可能是您最好的选择。但是,正如其他人指出的那样,它可能太复杂了。我一直使用 _access(或 _waccess),它是 CRT 的一部分,非常容易使用,并且您不需要获取文件句柄才能关闭它(根据您的循环有多紧密,这些调用实际上可能会增加)。

2
是的,AccessCheck 可以工作,但使用起来比较复杂和棘手。如果你想知道是否可以打开文件,最简单的方法就是尝试打开文件并查看是否成功。 - Adam Rosenfield
是的,我也不会使用它,但OP正在寻找win32调用 :) 已更新帖子,提供另一种选择。 - DXM
仅获取文件句柄就关闭它吗?不,你应该使用文件句柄进行有用的操作。如果你不打算使用资源,那么它的权限为什么要重要呢? - Ben Voigt
1
@Ben - 我可以想到很多场景。比如,在启动时服务器检查以确保接收客户端文件的目录可访问。或者配置实用程序检查文件是否可写,因为稍后完全不同的进程将需要该文件,但是在检查时,同一实用程序并没有真正读取该文件的意图。 - DXM
你想获取一个文件夹的访问权限怎么办?如何打开一个文件夹以进行写入访问。 - user13947194

1

这个对我在Win7中无法访问的文件夹的情况没有进行处理。 - Jonathan Paullin

0

是的,Aaron Ballman,你很棒!哦,天啊!我希望能够使用一些有用的咒骂来表达我现在的喜悦。

https://blog.aaronballman.com/2011/08/how-to-check-access-rights/ 是一个链接,指向在win32上检查文件路径的访问权限示例,以及关于文档不充分的AccessCheck win32函数背后的解释。以下是代码。

bool canAccessPath( LPCTSTR folderName, DWORD genericAccessRights )
{
    bool bRet = 0;
    DWORD length = 0;

    if (!::GetFileSecurity( folderName, OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION, NULL, 0, &length ) &&
            ERROR_INSUFFICIENT_BUFFER == ::GetLastError())
    {
        PSECURITY_DESCRIPTOR security = static_cast< PSECURITY_DESCRIPTOR >( ::malloc( length ) );

        if (security && ::GetFileSecurity( folderName, OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION, security, length, &length ))
        {
            HANDLE hToken = NULL;

            if (::OpenProcessToken( ::GetCurrentProcess(), TOKEN_IMPERSONATE|TOKEN_QUERY|TOKEN_DUPLICATE|STANDARD_RIGHTS_READ, &hToken ))
            {
                HANDLE hImpersonatedToken = NULL;

                if (::DuplicateToken( hToken, SecurityImpersonation, &hImpersonatedToken ))
                {
                    GENERIC_MAPPING mapping = { 0xFFFFFFFF };
                    PRIVILEGE_SET privileges = { 0 };
                    DWORD grantedAccess = 0, privilegesLength = sizeof( privileges );
                    BOOL result = FALSE;

                    mapping.GenericRead = FILE_GENERIC_READ;
                    mapping.GenericWrite = FILE_GENERIC_WRITE;
                    mapping.GenericExecute = FILE_GENERIC_EXECUTE;
                    mapping.GenericAll = FILE_ALL_ACCESS;

                    ::MapGenericMask( &genericAccessRights, &mapping );

                    if (::AccessCheck( security, hImpersonatedToken, genericAccessRights,
                            &mapping, &privileges, &privilegesLength, &grantedAccess, &result ))
                    {
                     bRet = result == TRUE;
                    }

                    ::CloseHandle( hImpersonatedToken );
                }

                ::CloseHandle( hToken );
            }

            ::free( security );
        }
    }

    return bRet;
}

不要害羞,进入他的网站查看他的作品。我相信他还有更有趣的东西。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接