使用C#复制文件夹到其他目的地并保留安全/权限设置

5

我正在制作一个程序,在该程序中可以复制文件夹并将其转移到另一个位置,包括属性、权限和安全设置。

到目前为止,我已经让属性生效了,但是在权限/安全设置方面遇到了问题。以下是我的代码:

Directory.CreateDirectory(Destination);
DirectoryInfo DestAttribute = new DirectoryInfo(Destination);
DestAttribute.Attributes = Source.Attributes; // Copies Attributes from Source to Dest

AuthorizationRuleCollection Rule;
DirectorySecurity DestSecurity = Source.GetAccessControl();
Rule = DestSecurity.GetAccessRules(true, true, typeof(NTAccount));
DestSecurity.AddAccessRule(Rule);
DestAttribute.SetAccessControl(DestSecurity);

有没有人对让这个工作有什么建议? 感谢大家的帮助。


看起来是重复的? - Chris Keller
4个回答

4

MSDN:如何从一个文件复制ACL信息到另一个文件

SetAccessControl方法只会保留在对象创建后被修改过的DirectorySecurity对象。如果一个DirectorySecurity对象没有被修改过,它就不会被保存到文件中。因此,无法从一个文件中检索DirectorySecurity对象并将相同的对象应用于另一个文件。

要从一个文件复制ACL信息到另一个文件,请按照以下步骤操作:

  1. 使用GetAccessControl方法检索源文件中的DirectorySecurity对象。

  2. 为目标文件创建一个新的DirectorySecurity对象。

  3. 使用源DirectorySecurity对象的GetSecurityDescriptorBinaryForm或GetSecurityDescriptorSddlForm方法检索ACL信息。

  4. 使用SetSecurityDescriptorBinaryForm或SetSecurityDescriptorSddlForm方法将步骤3中检索到的信息复制到目标DirectorySecurity对象中。

  5. 使用SetAccessControl方法将目标DirectorySecurity对象设置到目标文件中。

示例:

DirectoryInfo dir1 = new DirectoryInfo(@"C:\Temp\Dir1");
DirectoryInfo dir2 = new DirectoryInfo(@"C:\Temp\Dir2");  


DirectorySecurity ds1 = dir1.GetAccessControl();
DirectorySecurity ds2 = new DirectorySecurity();
ds2.SetSecurityDescriptorBinaryForm(ds1.GetSecurityDescriptorBinaryForm());
dir2.SetAccessControl(ds2);

3
这似乎是一个重复的问题: 原始问题... (来自原始问题的代码示例)
FileInfo file1 = new FileInfo(@"c:\test.txt");
FileInfo file2 = new FileInfo(@"c:\test2.txt");
StreamReader sr1 = new StreamReader(file1.Open(FileMode.Open));
StreamWriter sw1 = new StreamWriter(file2.Open(FileMode.Create));
sw1.Write(sr1.ReadToEnd());
sr1.Close();
sw1.Close();
FileSecurity ac1 = file1.GetAccessControl();
ac1.SetAccessRuleProtection(true, true);
file2.SetAccessControl(ac1);

我整理了以下方法,并且看起来可以实现你想要的功能...
private static void FolderCopy(String sourceFolder, String destinationFolder)
{
    DirectoryInfo sourceDirectory = new DirectoryInfo(sourceFolder);
    DirectoryInfo destinationDirectory;

    if (!sourceDirectory.Exists)
    {
        throw new DirectoryNotFoundException("Source folder not found: " + sourceFolder);
    }

    if (!Directory.Exists(destinationFolder))
    {
        destinationDirectory = Directory.CreateDirectory(destinationFolder);
    }
    else
    {
        destinationDirectory = new DirectoryInfo(destinationFolder);
    }

    DirectorySecurity security = sourceDirectory.GetAccessControl();

    security.SetAccessRuleProtection(true, true);
    destinationDirectory.SetAccessControl(security);

    var filesToCopy = sourceDirectory.GetFiles();

    foreach (FileInfo file in filesToCopy)
    {
        String path = Path.Combine(destinationFolder, file.Name);
        FileSecurity fileSecurity = file.GetAccessControl();

        fileSecurity.SetAccessRuleProtection(true, true);

        file.CopyTo(path, false);

        FileInfo copiedFile = new FileInfo(path);

        copiedFile.SetAccessControl(fileSecurity);
    }
}

克里斯


你好,如果你觉得这是重复的,我很抱歉。 那个方法是针对文件的,我尝试将其转换为目录版本,但没有太多的运气。我也查看了该线程以及所有其他链接,然而,错误仍然存在。 - FerX32
我刚刚在我的原始答案中添加了一个示例方法。也许结合您的原始代码,您可以完成您的任务。 - Chris Keller
哇,非常感谢! 我简直不敢相信这么简单的 "AccessRuleProtection"。 你的代码实现了我的代码的功能,但只用了两行代码(: 干得好! - FerX32
哇,这真是救了我的命。我添加了递归复制文件夹的代码 - 但是,我没有权限创建子文件夹,所以我不得不强制添加一个新的访问规则,以授予当前用户完全控制权来执行此操作。 - Andez

2

基于Chris Keller的回答,递归版本

    /// <summary>
    /// Copy directory recursive with permissions, overwrite existing
    /// </summary>
    /// <param name="sourceFolder"></param>
    /// <param name="destinationFolder"></param>
    public static void CopyDirectory(string sourceFolder, string destinationFolder)
    {
        var sourceDirectory = new DirectoryInfo(sourceFolder);
        if (!sourceDirectory.Exists) throw new DirectoryNotFoundException("Source folder not found: " + sourceFolder);

        var destinationDirectory = !Directory.Exists(destinationFolder) ? Directory.CreateDirectory(destinationFolder) : new DirectoryInfo(destinationFolder);

        CopyDirectory(sourceDirectory,destinationDirectory);
    }

    public static void CopyDirectory(DirectoryInfo sourceDirectory, DirectoryInfo destinationDirectory)
    {
        if(sourceDirectory == null) throw new ArgumentException("sourceDirectory");
        if(destinationDirectory == null) throw new ArgumentException("destinationDirectory");

        var security = sourceDirectory.GetAccessControl();

        security.SetAccessRuleProtection(true, true);
        destinationDirectory.SetAccessControl(security);

        var dirsToCopy = sourceDirectory.GetDirectories();
        foreach (var dirToCopy in dirsToCopy)
        {
            var destSubDirPath = Path.Combine(destinationDirectory.FullName,dirToCopy.Name);
            var destinationSubDir = !Directory.Exists(destSubDirPath) ? Directory.CreateDirectory(destSubDirPath) : new DirectoryInfo(destSubDirPath);
            CopyDirectory(dirToCopy,destinationSubDir);
        }

        var filesToCopy = sourceDirectory.GetFiles();

        foreach (var file in filesToCopy)
        {
            CopyFile(file, destinationDirectory.FullName);
        }
    }

    private static void CopyFile(FileInfo file, string destinationDirectory)
    {
        var path = Path.Combine(destinationDirectory, file.Name);
        var fileSecurity = file.GetAccessControl();

        fileSecurity.SetAccessRuleProtection(true, true);

        file.CopyTo(path, true);

        var copiedFile = new FileInfo(path);

        copiedFile.SetAccessControl(fileSecurity);
    }

0

经过一段时间的努力,我终于弄清楚了如何让它工作。

目标是:从一个文件夹(而不是文件)复制权限,并将其转移到另一个文件夹。(权限:帐户设置、访问规则等)

这是我做到的方法:(得到了http://forums.asp.net/t/1390009.aspx/1的帮助)

    private void PermissionGet(DirectoryInfo Source, DirectoryInfo Destination)
    {
        string Username;
        DirectorySecurity SourceSecurity = Source.GetAccessControl();

        foreach (FileSystemAccessRule Rules in SourceSecurity.GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount)))
        {
            Username = Rules.IdentityReference.Value;
            PermissionSet(Username, Rules.FileSystemRights, Rules.AccessControlType, Destination);
        }
    }

    private void PermissionSet(string Username, FileSystemRights Permission, AccessControlType Access, DirectoryInfo Destination)
    {
        DirectorySecurity Security = Destination.GetAccessControl();
        Security.AddAccessRule(new FileSystemAccessRule(Username, Permission, Access));
        Destination.SetAccessControl(Security);
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接