代码之家  ›  专栏  ›  技术社区  ›  Biff MaGriff

如何获取长路径的安全详细信息?

  •  4
  • Biff MaGriff  · 技术社区  · 16 年前

    我正在进行文件服务器迁移,我正在编写一个小的C应用程序来帮助我映射用户权限,以便我们可以将它们放入用户组中。

    我正在使用

    Directory.GetAccessControl(path);
    

    但是当它到达263个字符的文件路径时失败。

    无效名称。
    参数名称:名称

    当我使用 DirectoryInfo.GetAccessControl();

    这种方法是否有解决方法或替代方法?

    谢谢!

    5 回复  |  直到 16 年前
        1
  •  2
  •   Gabe Timothy Khouri    16 年前

    另一种选择是使用 subst . 在命令提示下,可以执行

    subst X: "D:\really really really\long path\that you can shorten"
    

    然后在x:drive上执行操作,整个开始部分将不计入260个字符的限制。

        2
  •  2
  •   Michael Burr    16 年前

    在路径前面加上\?\“指定“扩展长度路径”。我无法测试directory.getaccesscontrol()`是否可以使用扩展长度路径,但值得一试:

    http://msdn.microsoft.com/en-us/library/aa365247.aspx :

    最大路径长度限制

    在Windows API中(以下段落中讨论了一些例外情况),路径的最大长度为 MAX_PATH ,定义为260个字符。本地路径的结构顺序如下:驱动器号、冒号、反斜杠、由反斜杠分隔的名称组件和终止的空字符。例如,驱动器D上的最大路径是 "D:\<some 256-character path string><NUL>" 在哪里? "<NUL>" 表示当前系统代码页的不可见终止空字符。(人物) < > 此处用于视觉清晰,不能是有效路径字符串的一部分。)

    注意Windows API转换中的文件I/O函数 "/" "\" 作为将名称转换为NT样式名称的一部分,除非使用 "\\?\" 前缀见以下章节。

    Windows API有许多函数,它们也有Unicode版本,允许扩展长度路径的最大路径长度为32767个字符。此类型的路径由反斜杠分隔的组件组成,每个组件的值都达到GetVolumeInformation函数的lpMaximumComponentLength参数中返回的值(此值通常为255个字符)。要指定扩展长度路径,请使用 “\”?“ 前缀。例如, "\\?\D:\<very long path>" . (人物) <gt; 此处用于视觉清晰,不能是有效路径字符串的一部分。)

        3
  •  1
  •   Paul Ruane    16 年前

    如果这是库中的任意限制,那么您可以尝试使用8个字符的目录名。要确定这些名称是什么,请使用/x选项运行dir:

    
    C:\>dir /x
    
    29/12/2009  23:33              PROGRA~1     Program Files
    23/02/2010  21:26              PROGRA~2     Program Files (x86
    05/12/2009  20:57                           Users
    02/02/2010  09:23                           Windows
    

    简称是那些有颚化符的。尝试将这些传递给函数以缩短字符串长度。我不保证这会奏效的。

        4
  •  1
  •   Filburt kukabuka    16 年前

    应该使用directoryinfo递归地处理目录树,这样可以避免传递完整路径。

        5
  •  1
  •   Biff MaGriff    16 年前

    使用我上面提到的库,这可以很好地完成这个技巧。我想我应该根据需要抓取更多的映射驱动器号,但我的最大目录长度只有300个字符。

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.IO;
    using System.Security;
    using System.Security.AccessControl;
    using aejw.Network;
    
    namespace SecurityScanner
    {
        class Program
        {
            static void Main(string[] args)
            {
                string path = @"\\mynetworkdir";
                DirectoryInfo di = new DirectoryInfo(path);
                List<DirSec> dirs = new List<DirSec>();
                RecordSecurityData(di, dirs, path, path);
    
                //Grouping up my users
                List<List<DirSec>> groups = new List<List<DirSec>>();
                foreach (DirSec d in dirs)
                {
                    bool IsNew = true;
                    foreach (List<DirSec> group in groups)
                    {
                        if (d.IsSameUserList(group[0]))
                        {
                            group.Add(d);
                            IsNew = false;
                            break;
                        }
                    }
                    if (IsNew)
                    {
                        List<DirSec> newGroup = new List<DirSec>();
                        newGroup.Add(d);
                        groups.Add(newGroup);
                    }
                }
    
                //Outputting my potential user groups
                StringBuilder sb = new StringBuilder();
                foreach (List<DirSec> group in groups)
                {
                    foreach (DirSec d in group)
                    {
                        sb.AppendLine(d.DirectoryName);
                    }
                    foreach (string s in group[0].UserList)
                    {
                        sb.AppendLine("\t" + s);
                    }
                    sb.AppendLine();
                }
                File.WriteAllText(@"c:\security.txt", sb.ToString());
            }
    
            public static void RecordSecurityData(DirectoryInfo di, List<DirSec> dirs, string path, string fullPath)
            {
                DirSec me = new DirSec(fullPath);
                DirectorySecurity ds;
                NetworkDrive nd = null;
                if(path.Length <= 248)
                    ds = Directory.GetAccessControl(path);
                else
                {
                    nd = new NetworkDrive();
                    nd.LocalDrive = "X:";
                    nd.ShareName = path;
                    nd.MapDrive();
                    path = @"X:\";
                    di = new DirectoryInfo(path);
                    ds = Directory.GetAccessControl(path);
                }
                foreach (AuthorizationRule ar in ds.GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount)))
                {
                    me.AddUser(ar.IdentityReference.Value);
                }
                dirs.Add(me);
                foreach (DirectoryInfo child in di.GetDirectories())
                {
                    RecordSecurityData(child, dirs, path + @"\" + child.Name, fullPath + @"\" + child.Name);
                }
                if (nd != null)
                    nd.UnMapDrive();
            }
    
            public struct DirSec
            {
                public string DirectoryName;
                public List<string> UserList;
    
                public DirSec(string directoryName)
                {
                    DirectoryName = directoryName;
                    UserList = new List<string>();
                }
    
                public void AddUser(string UserName)
                {
                    UserList.Add(UserName);
                }
    
                public bool IsSameUserList(DirSec other)
                {
                    bool isSame = false;
                    if (this.UserList.Count == other.UserList.Count)
                    {
                        isSame = true;
                        foreach (string myUser in this.UserList)
                        {
                            if (!other.UserList.Contains(myUser))
                            {
                                isSame = false;
                                break;
                            }
                        }
                    }
                    return isSame;
                }
            }
        }
    }