Example #1
0
        /// <summary>
        /// Performs one-way synchronization from source directory tree to destination directory tree
        /// </summary>
        public virtual SyncResults Start()
        {
            SyncResults results = new SyncResults();

            if (Validate(this.SourceDirectory.FullName, this.DestinationDirectory.FullName, this.Configuration))
            {
                // recursively process directories
                ProcessDirectory(this.SourceDirectory.FullName, this.DestinationDirectory.FullName, this.Configuration, ref results);

            }

            return results;
        }
Example #2
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;
        }
Example #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, 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);
        }
Example #4
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();
        }
Example #5
0
        /// <summary>
        /// Gets list of subdirectories of specified directory, optionally filtered by specified input parameters
        /// </summary>
        /// <param name="results"></param>
        /// <param name="inputParams"></param>
        /// <param name="directoryInfo"></param>
        public virtual DirectoryInfo[] GetDirectories(DirectoryInfo directoryInfo, InputParams inputParams, ref SyncResults results)
        {
            // get all directories
            List <DirectoryInfo> directoryList = new List <DirectoryInfo>(directoryInfo.GetDirectories());

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

            if (needFilter)
            {
                for (int i = 0; i < directoryList.Count; i++)
                {
                    DirectoryInfo subdirInfo = directoryList[i];

                    // filter out directories based on hiddenness and exclude/include filespecs
                    if ((inputParams.ExcludeHidden && ((subdirInfo.Attributes & FileAttributes.Hidden) > 0)) ||
                        ShouldExclude(inputParams.ExcludeDirs, inputParams.IncludeDirs, subdirInfo.Name))
                    {
                        directoryList.RemoveAt(i);
                        results.DirectoriesIgnored++;
                        i--;
                    }
                }
            }

            return(directoryList.ToArray());
        }
Example #6
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
            var fileInfos = directoryInfo.GetFiles();

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

            if (!needFilter)
            {
                return(fileInfos);
            }

            var fileList = new List <FileInfo>(fileInfos.Length);

            foreach (var fileInfo in fileInfos)
            {
                // 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))
                {
                    results.FilesIgnored++;
                }
                else
                {
                    fileList.Add(fileInfo);
                }
            }
            return(fileList.ToArray());
        }
Example #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);
        }
Example #8
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);
            }
        }
Example #9
0
 public void Initialization()
 {
     inputParams = new InputParams();
     expectedResults = new SyncResults();
 }