4

私はファイルサーバーの移行を行っており、ユーザー権限をマップしてユーザーグループに配置できるようにするための小さなC#アプリを作成しています。

私は現在使用しています

Directory.GetAccessControl(path);

ただし、この263文字のファイルパスに到達すると失敗します。

無効な名前。
パラメータ名:name

使用しても同じエラーが発生しますDirectoryInfo.GetAccessControl();

この方法の回避策または代替手段はありますか?

ありがとう!

4

5 に答える 5

2

1つの代替手段は、を使用することsubstです。コマンドプロンプトから、実行できます

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

次に、X:ドライブで操作を実行すると、最初のセクション全体が260文字の制限にカウントされなくなります。

于 2010-03-15T21:37:30.767 に答える
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>"(文字< >は視覚的にわかりやすくするためにここで使用されており、有効なパス文字列の一部にすることはできません。)

注WindowsAPIのファイルI/O関数は、名前をNTスタイルの名前に変換する一環として変換されます。ただし、次のセクションで詳しく説明するプレフィックスを使用する場合は除き"/"ます。"\""\\?\"

Windows APIには、最大合計パス長32,767文字の拡張長パスを許可するUnicodeバージョンを備えた多くの関数があります。このタイプのパスは、バックスラッシュで区切られたコンポーネントで構成され、各コンポーネントは、GetVolumeInformation関数のlpMaximumComponentLengthパラメーターで返される値(この値は通常255文字)までです。拡張長パスを指定するには、"\\?\"プレフィックスを使用します。たとえば、"\\?\D:\<very long path>"。(文字< >は視覚的にわかりやすくするためにここで使用されており、有効なパス文字列の一部にすることはできません。)

于 2010-03-15T21:50:30.950 に答える
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 に答える
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

DirectoryInfoを使用してディレクトリツリーを再帰的に処理する必要があります。そうすることで、フルパスを渡さないようにすることができます。

于 2010-03-15T21:35:17.970 に答える