You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

C#获取路径超260字符的文件/目录安全信息问题

解决超长路径文件/目录的安全信息获取问题

我来帮你搞定这个头疼的超长路径安全信息获取问题!你提到的遍历方法能处理长路径但拿不到权限数据,核心是常规安全API默认不支持超长路径,下面给你几个实用的落地方案:

方案1:直接调用支持长路径的Win32 P/Invoke API

Win32的GetNamedSecurityInfoW原生支持带\\?\前缀的超长路径,我们可以把它封装成C#方法来用。这里给你一段可直接复用的代码:

using System;
using System.Runtime.InteropServices;
using System.Security.AccessControl;

public static class LongPathSecurityHelper
{
    // Win32常量定义
    private const int ERROR_SUCCESS = 0;
    private const int OWNER_SECURITY_INFORMATION = 0x00000001;
    private const int DACL_SECURITY_INFORMATION = 0x00000004;
    private const uint SE_FILE_OBJECT = 1;

    // 导入GetNamedSecurityInfoW API
    [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    private static extern uint GetNamedSecurityInfoW(
        string pObjectName,
        uint ObjectType,
        uint SecurityInfo,
        out IntPtr ppsidOwner,
        out IntPtr ppsidGroup,
        out IntPtr ppDacl,
        out IntPtr ppSacl,
        out IntPtr ppSecurityDescriptor);

    // 导入内存释放API
    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern IntPtr LocalFree(IntPtr hMem);

    // 获取文件/目录的安全信息
    public static FileSecurity GetFileOrDirectorySecurity(string path)
    {
        // 处理超长路径:自动添加\\?\前缀(UNC路径要转成\\?\UNC\server\share格式)
        string longPath = path.StartsWith(@"\\?\") 
            ? path 
            : path.StartsWith(@"\") 
                ? @"\\?\UNC\" + path.TrimStart('\\').Replace('\\', '/') 
                : @"\\?\" + path;

        IntPtr ownerSid, groupSid, dacl, sacl, securityDescriptor;
        uint result = GetNamedSecurityInfoW(
            longPath,
            SE_FILE_OBJECT,
            OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
            out ownerSid,
            out groupSid,
            out dacl,
            out sacl,
            out securityDescriptor);

        if (result != ERROR_SUCCESS)
        {
            throw new System.ComponentModel.Win32Exception((int)result);
        }

        try
        {
            // 将Win32安全描述符转换为.NET的FileSecurity对象
            FileSecurity security = new FileSecurity();
            byte[] sdBytes = new byte[Marshal.ReadInt32(securityDescriptor)];
            Marshal.Copy(securityDescriptor, sdBytes, 0, sdBytes.Length);
            security.SetSecurityDescriptorBinaryForm(sdBytes);
            return security;
        }
        finally
        {
            // 释放Win32分配的内存,避免泄漏
            LocalFree(securityDescriptor);
        }
    }
}

使用时直接调用LongPathSecurityHelper.GetFileOrDirectorySecurity("你的超长路径"),返回的FileSecurity对象里就能拿到所有者、访问权限列表等所有安全信息。

方案2:启用.NET原生长路径支持(.NET Framework 4.6.2+/.NET Core 2.0+)

如果你的项目用的是支持长路径的.NET版本,先通过配置开启长路径支持,就能直接用原生的安全API了:

.NET Framework 配置

app.config<runtime>节点里添加:

<runtime>
    <AppContextSwitchOverrides value="Switch.System.IO.UseLegacyPathHandling=false;Switch.System.IO.BlockLongPaths=false" />
</runtime>

.NET Core/.NET 5+ 配置

runtimeconfig.json里添加:

{
  "runtimeOptions": {
    "configProperties": {
      "System.IO.UseLegacyPathHandling": false,
      "System.IO.BlockLongPaths": false
    }
  }
}

配置完成后,你可以用Directory.EnumerateFileSystemEntries遍历超长路径,然后对每个路径调用File.GetAccessControlDirectory.GetAccessControl。不过要注意,遇到极端长路径时,还是手动加上\\?\前缀更稳妥。

方案3:与现有遍历代码集成

如果你已经在用Kim Hamilton的遍历代码,只需要在遍历到每个文件/目录时,把路径传入上面的GetFileOrDirectorySecurity方法即可,完美适配现有逻辑。

关键注意事项

  • 权限要求:程序需要有读取目标文件/目录安全信息的权限,部分场景下可能需要管理员权限。
  • UNC路径处理:共享目录的超长路径要转成\\?\UNC\server\share\...格式,不能直接加\\?\前缀。
  • 内存管理:调用Win32 API后一定要释放分配的内存,上面的代码已经帮你处理了,但自己写P/Invoke时别忘这点。

内容的提问来源于stack exchange,提问作者Merin Nakarmi

火山引擎 最新活动