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

时间:2010-03-15 21:24:19

标签: c# windows folder-security

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

我正在使用

Directory.GetAccessControl(path);

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

  

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

使用DirectoryInfo.GetAccessControl();

时出现同样的错误

是否有解决方法或替代此方法?

谢谢!

5 个答案:

答案 0 :(得分:2)

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

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

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

答案 1 :(得分: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>"。 (此处使用字符< >是为了清晰可见,并且不能成为有效路径字符串的一部分。)

答案 2 :(得分: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

短名称是具有波浪号的那些。尝试将这些名称传递给函数以减少字符串长度。请注意,不保证这会有效。

答案 3 :(得分:1)

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

答案 4 :(得分: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;
            }
        }
    }
}