4

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

我目前正在使用

Directory.GetAccessControl(path);

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

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

我使用时遇到同样的错误DirectoryInfo.GetAccessControl();

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

谢谢!

4

5 回答 5

2

在路径前加上“\?\”以指定“扩展长度路径”。我无法测试 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 版本,以允许最大总路径长度为 32,767 个字符的扩展长度路径。这种类型的路径由由反斜杠分隔的组件组成,每个组件都达到 GetVolumeInformation 函数的 lpMaximumComponentLength 参数中返回的值(该值通常为 255 个字符)。要指定扩展长度的路径,请使用"\\?\"前缀。例如,"\\?\D:\<very long path>"。(此处使用的字符< >是为了清晰起见,不能作为有效路径字符串的一部分。)

于 2010-03-15T21:50:30.950 回答
2

一种替代方法是使用subst. 在命令提示符下,您可以执行

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

然后在 X: 驱动器上执行您的操作,整个开始部分将不计入您的 260 字符限制。

于 2010-03-15T21:37:30.767 回答
1

您应该使用 DirectoryInfo 递归处理您的目录树 - 这样做可以避免传递完整路径。

于 2010-03-15T21:35:17.970 回答
1

如果它是库中的任意限制,那么您可以尝试使用 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

短名称是带有波浪线的名称。尝试将它们传递给函数以减少字符串长度。请注意,不保证这会起作用。

于 2010-03-15T21:32:08.570 回答
1

使用我上面提到的库可以很好地解决问题。我想我应该根据需要获取更多映射的驱动器号,但我的最大目录长度只有 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;
            }
        }
    }
}
于 2010-03-19T16:37:21.573 回答