Archive for the 'Uncategorized' Category

Restoring a backup. Wait, where are my permissions? or “How to replace all permissions in one directory tree with the permissions from another identical tree”

Ok, I’m starting to get fond of these “a slice of reality” or “what am I going to show you” title blog posts…

So once again this piece of code is a bit drastic. It’s neatly written if you ask me and should show you how you can replace the file security settings (ACLs) with some other files security settings (same for directories). The only meaningfull place to do this (off the top of my head) is when you have two identical files and for some reason the one file has the correct permissions and the other doesn’t. But daily developer business is always full of these little request, and it’s like a personal search for the holy grail - you just have to give it a try.

So if you ever want to copy the exact permission structure from one directory tree to another (for example you used some copy tool that doesn’t copy the permissions) then you can use this little tool to do just that.

A word of warning (as always). Have a backup of your permissions (most probably you will, because you need to copy them from somewhere) and of course run this tool at your own risk. The binary is available here and is compiled from the source you see below. Have fun and tell me if you find bugs or if it’s useful.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Security.AccessControl;
using System.Diagnostics;
using System.Security.Principal;

namespace AlexDuggleby.Tools.MirrorNTFSPermissions
{
    class Program
    {
        #region Properties

        /// <summary>
        /// The root we are copying from
        /// </summary>
        private static DirectoryInfo m_diFromRoot;

        /// <summary>
        /// The root we are copying to
        /// </summary>
        private static DirectoryInfo m_diToRoot;

        /// <summary>
        /// The log file to write to
        /// </summary>
        private static FileInfo m_fiLog;

        #endregion

        #region Main Operation

        static void Main(string[] args)
        {
            // Check args and output usage if required
            if (args.Length != 3)
            {
                OutputUsage();
                System.Environment.Exit(-1);
                return;
            }

            if (PopulateAndCheckDirectoriesExist(args) && ConfirmUserAction())
            {
                try
                {
                    Trace.Listeners.Add(new ConsoleTraceListener());
                    Trace.Listeners.Add(new TextWriterTraceListener(m_fiLog.FullName));

                    WriteTraceHeader();

                    Console.Clear();
                    CopyPermissions(m_diFromRoot, m_diToRoot, true);
                    WriteTraceFooter();
                }
                catch (ApplicationException aex)
                {
                    OutputError("Application", aex);
                }
                catch (Exception ex)
                {
                    OutputError("Critical", ex);
                }
            }

        }

        private static void CopyDirectorySecurity(DirectoryInfo diFrom, DirectoryInfo diTo, bool skipRootNameCheck, out bool continueInThisDirectory)
        {
            continueInThisDirectory = true;

            try
            {
                // Name comparison
                if (diFrom.Name != diTo.Name && !skipRootNameCheck)
                    throw new ApplicationException(string.Format("During processing the directory names changed! '{0}'-'{1}'",
                        diFrom.Name, diTo.Name));

                // Set my own permissions
                DirectorySecurity _dsFrom = Directory.GetAccessControl(diFrom.FullName, AccessControlSections.All);
                DirectorySecurity _dsTo = new DirectorySecurity();
                _dsTo.SetSecurityDescriptorSddlForm(_dsFrom.GetSecurityDescriptorSddlForm(AccessControlSections.All));
                Directory.SetAccessControl(diTo.FullName, _dsTo);

                // Tell the user what we are doing
                Trace.WriteLine(string.Format("Copying directory security from {0} to {1}",
                        diFrom.FullName, diTo.FullName));
            }
            catch (PathTooLongException _plex)
            {
                Trace.WriteLine(string.Format("[WARN] Path too long do continue with this directory '{0}'",
                        diFrom.FullName));
                continueInThisDirectory = false; // Abort because all files and subdirs will be affected
            }
            catch (Exception _ex) // General catch here, because we would like the batch to continue
            {
                Trace.WriteLine(string.Format("[ERROR] Error while doing current directory '{0}': {1}",
                        diFrom.FullName, _ex.ToString()));
                // We will continue here, since error type is undefined.
                continueInThisDirectory = true;
            }
        }

        #endregion

        #region File/Directory I/O and Security

        private static void CopyPermissions(DirectoryInfo diFrom, DirectoryInfo diTo, bool skipRootNameCheck)
        {
            bool _continueInThisDirectory;

            CopyDirectorySecurity(diFrom, diTo, skipRootNameCheck, out _continueInThisDirectory);

            if (_continueInThisDirectory)
            {
                // Now set files
                foreach (FileInfo _fiTo in diTo.GetFiles())
                {
                    CopyFileSecurity(diFrom, _fiTo);
                }

                // Get all the -to- subdirs ...
                foreach (DirectoryInfo _toSubDir in diTo.GetDirectories())
                {
                    // ... and check if they also exist in the from directory
                    DirectoryInfo _fromSubDir = diFrom.GetDirectories(_toSubDir.Name, SearchOption.TopDirectoryOnly).FirstOrDefault(d => d.Name == _toSubDir.Name);
                    if (_fromSubDir != null)
                    {
                        // Recursive
                        CopyPermissions(_fromSubDir, _toSubDir, false);
                    }
                }
            }
        }

        private static void CopyFileSecurity(DirectoryInfo diFrom, FileInfo fiTo)
        {
            // Turn the paths into relative paths based on the root dirs we started from
            string _relativeFromPath = fiTo.Directory.FullName.ToLower()
                .Replace(m_diToRoot.FullName.ToLower(), "");
            string _relativeToPath = diFrom.FullName.ToLower()
                .Replace(m_diFromRoot.FullName.ToLower(), "");

            // now compare those relative paths, just to be sure
            if (_relativeFromPath != _relativeToPath)
                throw new ApplicationException(string.Format(
                    "Subdirectories went out of sync during processing! '{0}'-'{1}'", _relativeFromPath, _relativeToPath));

            FileInfo _fiFrom = new FileInfo(Path.Combine(diFrom.FullName, fiTo.Name));

            if (_fiFrom.Exists) // if it doesn't exist in the from we will ignore...
            {
                // Copy the file permissions
                FileSecurity _fsFrom = File.GetAccessControl(_fiFrom.FullName);

                // Sometimes there are now access rules on the item, so only the owner can access it
                if (File.GetAccessControl(fiTo.FullName).GetAccessRules(true, true, typeof(NTAccount)).Count == 0)
                {
                    // Tell the user what we are doing
                    Trace.WriteLine(string.Format("File can only be accessed by owner: {0}", fiTo.FullName));
                }
                else
                {
                    try
                    {
                        // Copy the file permissions
                        FileSecurity _fsTo = new FileSecurity();
                        _fsTo.SetSecurityDescriptorSddlForm(_fsFrom.GetSecurityDescriptorSddlForm(AccessControlSections.All));
                        File.SetAccessControl(fiTo.FullName, _fsTo);

                        // Tell the user what we are doing
                        Trace.WriteLine(string.Format("Copying file security from {0} to {1}",
                            _fiFrom.FullName, fiTo.FullName));
                    }
                    catch (Exception _ex)
                    {
                        // Tell the user what went wrong
                        Trace.WriteLine(string.Format("[ERROR] Error while copying file security from {0} to {1}: {2}",
                            _fiFrom.FullName, fiTo.FullName, _ex.ToString()));
                    }
                }
            }
            else
            {
                Trace.WriteLine(string.Format("File did not exist in original tree: {0}",
                 fiTo.FullName));
            }
        }

        #endregion

        #region User I/O and Tracing

        private static void WriteTraceHeader()
        {
            Trace.WriteLine("*****************************************");
            Trace.WriteLine("Mirror NTFS Permissions");
            Trace.WriteLine("Version 1.0 - 27.05.2008");
            Trace.WriteLine("Alex Duggleby - http://alexduggleby.com");
            Trace.WriteLine("*****************************************");
            Trace.WriteLine("== New run @ " + DateTime.Now.ToString() + "");
            Trace.WriteLine("== From : " + m_diFromRoot.FullName + "");
            Trace.WriteLine("== To   : " + m_diToRoot.FullName + "");
            Trace.WriteLine("=========================================");
        }

        private static void WriteTraceFooter()
        {
            Console.ForegroundColor = ConsoleColor.Green;
            Trace.WriteLine("=========================================");
            Trace.WriteLine("Finished!");
            Trace.WriteLine("=========================================");
            Console.ForegroundColor = ConsoleColor.White;
            Trace.Flush();
        }

        private static void OutputError(string errType, Exception ex)
        {
            Console.ForegroundColor = ConsoleColor.Red;
            string _s = string.Format("***********************{1}{2} error: {0}", ex.ToString(), Environment.NewLine, errType);
            Trace.WriteLine(_s);
            Console.ForegroundColor = ConsoleColor.White;
            OutputPressKeyToExit();
            Trace.Flush();
        }

        private static void OutputPressKeyToExit()
        {
            Console.WriteLine();
            Console.ForegroundColor = ConsoleColor.White;
            Console.WriteLine("{0}Press any key to exit", Environment.NewLine);
            Console.ReadKey();
        }

        private static void OutputUsage()
        {
            Console.WriteLine("Mirror NTFS Permissions");
            Console.WriteLine("by Alex Duggleby - http://alexduggleby.com");
            Console.WriteLine();
            Console.WriteLine("Usage: application.exe <path1> <path2> <log-file>");
            Console.WriteLine("Replaces all permissions on all subdirectory and files in path2 with those from path1 if they exist there.");
            Console.WriteLine("The <log-file> is used to write the appplications trace output.");
            Console.WriteLine();
        }

        private static bool ConfirmUserAction()
        {
            Console.WriteLine("Do you wish to copy all permissions form '{0}' to '{1}'? [y/n]",
                m_diFromRoot.FullName,
                m_diToRoot.FullName);

            if (Console.ReadKey().KeyChar.ToString().ToLower() != "y")
            {
                Console.WriteLine("User aborted!");
                OutputPressKeyToExit();
                System.Environment.Exit(-1);
                return false;
            }

            return true;
        }

        #endregion

        #region Prechecks

        private static bool PopulateAndCheckDirectoriesExist(string[] args)
        {
            string _dirFrom = args[0];
            string _dirTo = args[1];
            string _logFile = args[2];

            if (_dirFrom.EndsWith("\\")) _dirFrom = _dirFrom.Substring(0, _dirFrom.Length - 1);
            if (_dirTo.EndsWith("\\")) _dirTo = _dirTo.Substring(0, _dirTo.Length - 1);

            m_diFromRoot = new DirectoryInfo(_dirFrom);
            m_diToRoot = new DirectoryInfo(_dirTo);
            m_fiLog = new FileInfo(_logFile);

            if (!m_fiLog.Exists)
            {
                try
                {
                    m_fiLog.Create().Close();
                }
                catch (Exception _ex)
                {
                    Console.WriteLine("Could not create log file: " + _ex.ToString());
                }

                m_fiLog.Refresh();
            }

            if (!m_diFromRoot.Exists)
                Console.WriteLine("Directory '{0}' does not exist", m_diFromRoot.FullName);

            if (!m_diToRoot.Exists)
                Console.WriteLine("Directory '{0}' does not exist", m_diToRoot.FullName);

            if (!m_fiLog.Exists)
                Console.WriteLine("File '{0}' does not exist", m_fiLog.FullName);

            return m_diFromRoot.Exists && m_diToRoot.Exists && m_fiLog.Exists;
        }

        #endregion
    }
}

Sync Framework Interview on Channel 8

While I am getting prepared to speak about the Sync Framework at the german conference VSone, my colleague Christian has put up an interview from TechEd with the lead program manager on the Sync Framework team: Moe Khosravy

Check it out here: http://channel8.msdn.com/Posts/425/


Subscribe / Search

Imagine Cup 2009 - Egypt
msplogo_small.jpg
mcprgb.png

 

July 2008
M T W T F S S
« Jun    
 123456
78910111213
14151617181920
21222324252627
28293031  

Blog Stats

  • 10,824 hits