Exemple #1
0
        /// <summary>
        /// Validate folder and parameters
        /// </summary>
        /// <param name="destDir"></param>
        /// <param name="parameters"></param>
        /// <param name="srcDir"></param>
        private bool Validate(string srcDir, string destDir, InputParams parameters)
        {
            if (((parameters.IncludeFiles != null) && (parameters.ExcludeFiles != null)) ||
                ((parameters.IncludeDirs != null) && (parameters.ExcludeDirs != null)))
            {
                PrintUsage();
                return false;
            }

            string fullSrcDir = Path.GetFullPath(srcDir);
            string fullDestDir = Path.GetFullPath(destDir);
            if (destDir.StartsWith(fullSrcDir) || srcDir.StartsWith(fullDestDir))
            {
                Trace("Error: source directory {0} and destination directory {1} cannot contain each other", fullSrcDir, fullDestDir);
                return false;
            }

            if (((parameters.DeleteExcludeFiles != null) || (parameters.DeleteExcludeDirs != null)) &&
                (!parameters.DeleteFromDest))
            {
                Trace("Error: exclude-from-deletion options (-ndf and -ndd) require deletion (-d) enabled.");
                return false;
            }

            // ensure source directory exists
            if (!Directory.Exists(srcDir))
            {
                this.Trace("Error: source directory {0} not found", srcDir);
                return false;
            }

            return true;
        }
Exemple #2
0
 /// <summary>
 /// Performs one-way synchronization from source directory tree to destination directory tree
 /// </summary>
 /// <param name="configuration"></param>
 public virtual SyncResults Start(InputParams configuration)
 {
     this.Configuration = configuration;
     return this.Start();
 }
Exemple #3
0
        /// <summary>
        /// Recursively performs one-way synchronization from a single source to destination directory
        /// </summary>
        /// <param name="srcDir"></param>
        /// <param name="destDir"></param>
        /// <param name="inputParams"></param>
        /// <param name="results"></param>
        private bool ProcessDirectory(string srcDir, string destDir, InputParams inputParams, ref SyncResults results)
        {
            DirectoryInfo diSrc = new DirectoryInfo(srcDir);
            DirectoryInfo diDest = new DirectoryInfo(destDir);

            // create destination directory if it doesn't exist
            if (!diDest.Exists)
            {
                try
                {
                    Trace("Creating directory: {0}", diDest.FullName);

                    // create the destination directory
                    diDest.Create();
                    results.DirectoriesCreated++;
                }
                catch (Exception ex)
                {
                    Trace("Error: failed to create directory {0}. {1}", destDir, ex.Message);
                    return false;
                }
            }

            // get list of selected files from source directory
            FileInfo[] fiSrc = GetFiles(diSrc, inputParams, ref results);
            // get list of files in destination directory
            FileInfo[] fiDest = GetFiles(diDest, null, ref results);

            // put the source files and destination files into hash tables
            Hashtable hashSrc = new Hashtable(fiSrc.Length);
            foreach (FileInfo srcFile in fiSrc)
            {
                hashSrc.Add(srcFile.Name, srcFile);
            }
            Hashtable hashDest = new Hashtable(fiDest.Length);
            foreach (FileInfo destFile in fiDest)
            {
                hashDest.Add(destFile.Name, destFile);
            }

            // make sure all the selected source files exist in destination
            foreach (FileInfo srcFile in fiSrc)
            {
                bool isUpToDate = false;

                // look up in hash table to see if file exists in destination
                FileInfo destFile = (FileInfo)hashDest[srcFile.Name];
                // if file exists and length, write time and attributes match, it's up to date
                if ((destFile != null) && (srcFile.Length == destFile.Length) &&
                    (srcFile.LastWriteTime == destFile.LastWriteTime) &&
                    (srcFile.Attributes == destFile.Attributes))
                {
                    isUpToDate = true;
                    results.FilesUpToDate++;
                }

                // if the file doesn't exist or is different, copy the source file to destination
                if (!isUpToDate)
                {
                    string destPath = Path.Combine(destDir, srcFile.Name);
                    // make sure destination is not read-only
                    if (destFile != null && destFile.IsReadOnly)
                    {
                        destFile.IsReadOnly = false;
                    }

                    try
                    {
                        Trace("Copying: {0} -> {1}", srcFile.FullName, Path.GetFullPath(destPath));

                        // copy the file
                        srcFile.CopyTo(destPath, true);
                        // set attributes appropriately
                        File.SetAttributes(destPath, srcFile.Attributes);
                        results.FilesCopied++;
                    }
                    catch (Exception ex)
                    {
                        Trace("Error: failed to copy file from {0} to {1}. {2}", srcFile.FullName, destPath, ex.Message);
                        return false;
                    }
                }
            }

            // delete extra files in destination directory if specified
            if (inputParams.DeleteFromDest)
            {
                foreach (FileInfo destFile in fiDest)
                {
                    FileInfo srcFile = (FileInfo)hashSrc[destFile.Name];
                    if (srcFile == null)
                    {
                        // if this file is specified in exclude-from-deletion list, don't delete it
                        if (ShouldExclude(inputParams.DeleteExcludeFiles, null, destFile.Name))
                            continue;

                        try
                        {

                            Trace("Deleting: {0} ", destFile.FullName);

                            destFile.IsReadOnly = false;
                            // delete the file
                            destFile.Delete();
                            results.FilesDeleted++;
                        }
                        catch (Exception ex)
                        {
                            Trace("Error: failed to delete file from {0}. {1}", destFile.FullName, ex.Message);
                            return false;
                        }
                    }
                }
            }

            // Get list of selected subdirectories in source directory
            DirectoryInfo[] diSrcSubdirs = GetDirectories(diSrc, inputParams, ref results);
            // Get list of subdirectories in destination directory
            DirectoryInfo[] diDestSubdirs = GetDirectories(diDest, null, ref results);

            // add selected source subdirectories to hash table, and recursively process them
            Hashtable hashSrcSubdirs = new Hashtable(diSrcSubdirs.Length);
            foreach (DirectoryInfo diSrcSubdir in diSrcSubdirs)
            {
                hashSrcSubdirs.Add(diSrcSubdir.Name, diSrcSubdir);
                // recurse into this directory
                if (!ProcessDirectory(diSrcSubdir.FullName, Path.Combine(destDir, diSrcSubdir.Name), inputParams, ref results))
                    return false;
            }

            // delete extra directories in destination if specified
            if (inputParams.DeleteFromDest)
            {
                foreach (DirectoryInfo diDestSubdir in diDestSubdirs)
                {
                    // does this destination subdirectory exist in the source subdirs?
                    if (!hashSrcSubdirs.ContainsKey(diDestSubdir.Name))
                    {
                        // if this directory is specified in exclude-from-deletion list, don't delete it
                        if (ShouldExclude(inputParams.DeleteExcludeDirs, null, diDestSubdir.Name))
                            continue;

                        try
                        {
                            Trace("Deleting directory: {0} ", diDestSubdir.FullName);

                            // delete directory
                            DeleteDirectory(diDestSubdir);
                            results.DirectoriesDeleted++;
                        }
                        catch (Exception ex)
                        {
                            Trace("Error: failed to delete directory {0}. {1}", diDestSubdir.FullName, ex.Message);
                            return false;
                        }
                    }
                }
            }
            return true;
        }
        /// <summary>
        /// Recursively performs one-way synchronization from a single source to destination directory
        /// </summary>
        /// <param name="srcDir"></param>
        /// <param name="destDir"></param>
        /// <param name="inputParams"></param>
        /// <param name="results"></param>
        private bool ProcessDirectory(string srcDir, string destDir, InputParams inputParams, ref SyncResults results)
        {
            DirectoryInfo diSrc  = new DirectoryInfo(srcDir);
            DirectoryInfo diDest = new DirectoryInfo(destDir);

            // create destination directory if it doesn't exist
            if (!diDest.Exists)
            {
                try
                {
                    Trace("Creating directory: {0}", diDest.FullName);

                    // create the destination directory
                    diDest.Create();
                    results.DirectoriesCreated++;
                }
                catch (Exception ex)
                {
                    Trace("Error: failed to create directory {0}. {1}", destDir, ex.Message);
                    return(false);
                }
            }

            // get list of selected files from source directory
            FileInfo[] fiSrc = GetFiles(diSrc, inputParams, ref results);
            // get list of files in destination directory
            FileInfo[] fiDest = GetFiles(diDest, inputParams.IncludesApplyToDest ? inputParams : null, ref results);

            // put the source files and destination files into hash tables
            Hashtable hashSrc = new Hashtable(fiSrc.Length);

            foreach (FileInfo srcFile in fiSrc)
            {
                hashSrc.Add(srcFile.Name, srcFile);
            }
            Hashtable hashDest = new Hashtable(fiDest.Length);

            foreach (FileInfo destFile in fiDest)
            {
                hashDest.Add(destFile.Name, destFile);
            }

            // make sure all the selected source files exist in destination
            var compareMethod = inputParams.CompareMethod;

            foreach (FileInfo srcFile in fiSrc)
            {
                bool isUpToDate = false;

                // look up in hash table to see if file exists in destination
                FileInfo destFile = (FileInfo)hashDest[srcFile.Name];
                // if file exists and length, write time and attributes match, it's up to date
                if ((destFile != null) && CompareFile.AreEqual(srcFile, destFile, compareMethod))
                {
                    isUpToDate = true;
                    results.FilesUpToDate++;
                }

                // if the file doesn't exist or is different, copy the source file to destination
                if (!isUpToDate)
                {
                    string destPath = Path.Combine(destDir, srcFile.Name);
                    // make sure destination is not read-only
                    if (destFile != null && destFile.IsReadOnly)
                    {
                        destFile.IsReadOnly = false;
                    }

                    try
                    {
                        Trace("Copying: {0} -> {1}", srcFile.FullName, Path.GetFullPath(destPath));

                        // copy the file
                        srcFile.CopyTo(destPath, true);
                        // set attributes appropriately
                        File.SetAttributes(destPath, srcFile.Attributes);
                        results.FilesCopied++;
                    }
                    catch (Exception ex)
                    {
                        Trace("Error: failed to copy file from {0} to {1}. {2}", srcFile.FullName, destPath, ex.Message);
                        return(false);
                    }
                }
            }

            // delete extra files in destination directory if specified
            if (inputParams.DeleteFromDest)
            {
                foreach (FileInfo destFile in fiDest)
                {
                    FileInfo srcFile = (FileInfo)hashSrc[destFile.Name];
                    if (srcFile == null)
                    {
                        // if this file is specified in exclude-from-deletion list, don't delete it
                        if (ShouldExclude(inputParams.DeleteExcludeFiles, null, destFile.Name))
                        {
                            continue;
                        }

                        try
                        {
                            Trace("Deleting: {0} ", destFile.FullName);

                            destFile.IsReadOnly = false;
                            // delete the file
                            destFile.Delete();
                            results.FilesDeleted++;
                        }
                        catch (Exception ex)
                        {
                            Trace("Error: failed to delete file from {0}. {1}", destFile.FullName, ex.Message);
                            return(false);
                        }
                    }
                }
            }

            // Get list of selected subdirectories in source directory
            DirectoryInfo[] diSrcSubdirs = GetDirectories(diSrc, inputParams, ref results);
            // Get list of subdirectories in destination directory
            DirectoryInfo[] diDestSubdirs = GetDirectories(diDest, inputParams.IncludesApplyToDest ? inputParams : null, ref results);

            // add selected source subdirectories to hash table, and recursively process them
            Hashtable hashSrcSubdirs = new Hashtable(diSrcSubdirs.Length);

            foreach (DirectoryInfo diSrcSubdir in diSrcSubdirs)
            {
                hashSrcSubdirs.Add(diSrcSubdir.Name, diSrcSubdir);
                // recurse into this directory
                if (!ProcessDirectory(diSrcSubdir.FullName, Path.Combine(destDir, diSrcSubdir.Name), inputParams, ref results))
                {
                    return(false);
                }
            }

            // delete extra directories in destination if specified
            if (inputParams.DeleteFromDest)
            {
                foreach (DirectoryInfo diDestSubdir in diDestSubdirs)
                {
                    // does this destination subdirectory exist in the source subdirs?
                    if (!hashSrcSubdirs.ContainsKey(diDestSubdir.Name))
                    {
                        // if this directory is specified in exclude-from-deletion list, don't delete it
                        if (ShouldExclude(inputParams.DeleteExcludeDirs, null, diDestSubdir.Name))
                        {
                            continue;
                        }

                        try
                        {
                            Trace("Deleting directory: {0} ", diDestSubdir.FullName);

                            // delete directory
                            DeleteDirectory(diDestSubdir);
                            results.DirectoriesDeleted++;
                        }
                        catch (Exception ex)
                        {
                            Trace("Error: failed to delete directory {0}. {1}", diDestSubdir.FullName, ex.Message);
                            return(false);
                        }
                    }
                }
            }
            return(true);
        }
Exemple #5
0
        /// <summary>
        /// Gets list of files in specified directory, optionally filtered by specified input parameters
        /// </summary>
        /// <param name="directoryInfo"></param>
        /// <param name="inputParams"></param>
        /// <param name="results"></param>
        public virtual FileInfo[] GetFiles(DirectoryInfo directoryInfo, InputParams inputParams, ref SyncResults results)
        {
            // get all files
            List<FileInfo> fileList = new List<FileInfo>(directoryInfo.GetFiles());

            // do we need to do any filtering?
            bool needFilter = (inputParams != null) && (inputParams.AreSourceFilesFiltered);

            if (needFilter)
            {
                for (int i = 0; i < fileList.Count; i++)
                {
                    FileInfo fileInfo = fileList[i];

                    // filter out any files based on hiddenness and exclude/include filespecs
                    if ((inputParams.ExcludeHidden && ((fileInfo.Attributes & FileAttributes.Hidden) > 0)) ||
                         ShouldExclude(inputParams.ExcludeFiles, inputParams.IncludeFiles, fileInfo.Name))
                    {
                        fileList.RemoveAt(i);
                        results.FilesIgnored++;
                        i--;
                    }
                }
            }

            return fileList.ToArray();
        }
 /// <summary>
 /// Performs one-way synchronization from source directory tree to destination directory tree
 /// </summary>
 /// <param name="configuration"></param>
 public virtual SyncResults Start(InputParams configuration)
 {
     this.Configuration = configuration;
     return(this.Start());
 }
Exemple #7
0
        /// <summary>
        /// Runs a test case
        /// </summary>
        private static void TestOneCase(string[] srcDirectories, string[] srcFiles, string[] destDirectories, string[] destFiles, InputParams inputParams, SyncResults expectedResults)
        {
            // delete base directories in case they were hanging around from a previous failed test
            DeleteTestDirectory(baseDirSrc);
            DeleteTestDirectory(baseDirDest);

            // create source directories and files specified by test
            CreateTestDirectories(baseDirSrc, srcDirectories);
            CreateTestFiles(baseDirSrc, null, srcFiles);
            // create destination directories and files specified by test
            if (destDirectories != null)
            {
                CreateTestDirectories(baseDirDest, destDirectories);
            }
            if (destFiles != null)
            {
                CreateTestFiles(baseDirDest, baseDirSrc, destFiles);
            }

            // perform the directory sync
            SyncResults results = new SyncResults();
            results = new Sync(baseDirSrc, baseDirDest).Start(inputParams);

            // Assert we have expected results
            Assert.IsTrue(SyncTools.CompareTo(expectedResults, results));

            // If we are deleting extra files from destination, verify we have exactly the same files as filtered source files
            if (inputParams.DeleteFromDest &&
                (!(inputParams.DeleteExcludeFiles != null) && !(inputParams.DeleteExcludeDirs != null)))
            {
                // calc hash of filtered files & directories in source tree
                byte[] hashSrc = CalcHash(baseDirSrc, inputParams);
                // calc hash of all files & directories in destination tree
                byte[] hashDest = CalcHash(baseDirDest, null);
                // hashes must match
                bool hashesMatch = SyncTools.CompareByteArrays(hashSrc, hashDest);
                Assert.IsTrue(hashesMatch);
            }

            DeleteTestDirectory(baseDirSrc);
            DeleteTestDirectory(baseDirDest);
        }
Exemple #8
0
        /// <summary>
        /// Calculate a hash of the specified directory tree, filtered by inputParams if non-null
        /// </summary>
        private static byte[] CalcHash(string directory, InputParams inputParams)
        {
            MemoryStream memoryStream = new MemoryStream();

            // build a stream of the directory contents we want to hash
            BuildCRCStream(directory, inputParams, ref memoryStream);

            // create the hash
            MD5 md5 = MD5.Create();
            return md5.ComputeHash(memoryStream.GetBuffer());
        }
Exemple #9
0
        /// <summary>
        /// Fill a stream with relevant contents of directory tree for hashing.  Directory tree is filtered by
        /// inputParams if non-null.
        /// </summary>
        private static void BuildCRCStream(string directory, InputParams inputParams, ref MemoryStream memoryStream)
        {
            DirectoryInfo directoryInfo = new DirectoryInfo(directory);
            SyncResults results = new SyncResults();
            // get filtered list of files in this directory
            FileInfo[] files = new Sync().GetFiles(directoryInfo, inputParams, ref results);
            // sort by name for deterministic order
            Array.Sort(files, new FileInfoComparer());
            // write information about each file to stream
            foreach (FileInfo fileInfo in files)
            {
                byte[] bytes = ASCIIEncoding.UTF8.GetBytes(fileInfo.Name);
                memoryStream.Write(bytes, 0, bytes.Length);
                bytes = BitConverter.GetBytes(fileInfo.Length);
                memoryStream.Write(bytes, 0, bytes.Length);
                bytes = BitConverter.GetBytes(fileInfo.LastWriteTime.ToBinary());
                memoryStream.Write(bytes, 0, bytes.Length);
                bytes = ASCIIEncoding.UTF8.GetBytes(fileInfo.Attributes.ToString());
                memoryStream.Write(bytes, 0, bytes.Length);
            }

            // get filtered list of subdirectories
            DirectoryInfo[] subdirs = new Sync().GetDirectories(directoryInfo, inputParams, ref results);
            // sort by name for deterministic order
            Array.Sort(subdirs, new DirectoryInfoComparer());

            foreach (DirectoryInfo subdir in subdirs)
            {
                // write information about each subdirectory to stream
                byte[] bytes = ASCIIEncoding.UTF8.GetBytes(subdir.Name);
                memoryStream.Write(bytes, 0, bytes.Length);
                // recurse
                BuildCRCStream(Path.Combine(directory, subdir.Name), inputParams, ref memoryStream);
            }
        }
Exemple #10
0
 public void Initialization()
 {
     inputParams = new InputParams();
     expectedResults = new SyncResults();
 }