FerX32
FerX32

Reputation: 1407

C# Copying a Folder to another destination with Security/Permission Settings

I am making a program where it could copy a Folder and Transfer it to another location, including the attribute, permissions, security settings.

So Far I got the Attribution to work, but am having problems with the permissions/security settings. Here are my code:

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);

Anyone have any suggestion on getting this to work ? Thank you everyone for all the help.

Upvotes: 5

Views: 11114

Answers (4)

Zar Shardan
Zar Shardan

Reputation: 5921

Recursive version based on Chris Keller's answer

    /// <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);
    }

Upvotes: 2

Faisal Mansoor
Faisal Mansoor

Reputation: 2041

MSDN: How To copy ACL information from one file to another

The SetAccessControl method persists only DirectorySecurity objects that have been modified after object creation. If a DirectorySecurity object has not been modified, it will not be persisted to a file. Therefore, it is not possible to retrieve a DirectorySecurity object from one file and reapply the same object to another file.

To copy ACL information from one file to another:

  1. Use the GetAccessControl method to retrieve the DirectorySecurity object from the source file.

  2. Create a new DirectorySecurity object for the destination file.

  3. Use the GetSecurityDescriptorBinaryForm or GetSecurityDescriptorSddlForm method of the source DirectorySecurity object to retrieve the ACL information.

  4. Use the SetSecurityDescriptorBinaryForm or SetSecurityDescriptorSddlForm method to copy the information retrieved in step 3 to the destination DirectorySecurity object.

  5. Set the destination DirectorySecurity object to the destination file using the SetAccessControl method.

Example:

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);

Upvotes: 4

FerX32
FerX32

Reputation: 1407

After awhile, I finally figured out on how to get it working. The objective was: To Copy Permissions from one Folder(Not Files), and transfer it to another Folder. (Permission: Account Settings, Access Rules, Etc...)

This is how I've done it: (Help from: 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);
    }

Upvotes: 0

Chris Keller
Chris Keller

Reputation: 253

This appears to be a duplicate of:

Original Question...

(code sample from original question)

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);

I put together the following method and it appears to do what you want...

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);
    }
}

Chris

Upvotes: 3

Related Questions