Как мне получить информацию о безопасности для длинного пути? - PullRequest
4 голосов
/ 16 марта 2010

Я выполняю миграцию файлового сервера и пишу небольшое приложение на C #, чтобы помочь мне сопоставить разрешения пользователей, чтобы мы могли поместить их в группы пользователей.

Я сейчас использую

Directory.GetAccessControl(path);

Однако это не удается, когда он попадает в этот путь к файлу из 263 символов.

Неверное имя.
Имя параметра: имя

Я получаю ту же ошибку при использовании DirectoryInfo.GetAccessControl();

Есть ли обходной путь или альтернатива этому методу?

Спасибо!

Ответы [ 5 ]

2 голосов
/ 16 марта 2010

Префикс пути к «\? \» Для указания «пути расширенной длины». Я не смог проверить, будет ли 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 преобразуют "/" в "\" как часть преобразования имени в имя в стиле NT, за исключением случаев использования префикса "\\?\", как описано в следующих разделах.

Windows API имеет много функций, которые также имеют версии Unicode, чтобы разрешить путь расширенной длины для максимальной общей длины пути 32 767 символов. Этот тип пути состоит из компонентов, разделенных обратной косой чертой, каждая из которых соответствует значению, возвращенному в параметре lpMaximumComponentLength функции GetVolumeInformation (обычно это значение составляет 255 символов). Чтобы указать путь расширенной длины, используйте префикс "\\?\". Например, "\\?\D:\<very long path>". (Символы < > используются здесь для наглядности и не могут быть частью допустимой строки пути.)

2 голосов
/ 16 марта 2010

Одной из альтернатив является использование subst. Из командной строки вы можете выполнить

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

Затем выполните ваши действия на диске X: и весь начальный раздел не будет учитываться при вашем ограничении в 260 символов.

1 голос
/ 19 марта 2010

Используя библиотеку, о которой я упоминал выше, это хорошо работает. Я полагаю, что при необходимости мне нужно было получить больше сопоставленных букв дисков, но максимальная длина моего каталога составляла всего 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;
            }
        }
    }
}
1 голос
/ 16 марта 2010

Вы должны рекурсивно обрабатывать дерево каталогов, используя DirectoryInfo - таким образом вы не пропустите полный путь.

1 голос
/ 16 марта 2010

Если это произвольный предел в библиотеке, то вы можете попробовать использовать 8 имен символов для каталогов. Чтобы понять, что это за имена, запустите dir с параметром / X:


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

Короткие имена - это имена с тильдами. Попробуйте передать их в функцию, чтобы уменьшить длину строки. Нет гарантий, это сработает, ум.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...