示例#1
0
        /// <summary>
        /// Compares <paramref name="directoryA"/> with <paramref name="directoryB"/> using the comparison
        /// options as defined in the constructor of this class.
        /// </summary>
        /// <param name="directoryA"></param>
        /// <param name="directoryB"></param>
        /// <param name="source"></param>
        /// <returns>Null if an unkown error occured or if either directory cannot be accessed
        /// (or does not exist), otherwise the <see cref="IDirectoryDiffRoot"/> data structure
        /// that describes the directory differences.</returns>
        public IDirectoryDiffRoot Execute(IDirectoryInfo directoryA, IDirectoryInfo directoryB,
                                          IDataSource source)
        {
            try
            {
                // Create a faux base entry to pass to Execute
                var diffRoot = new DirectoryDiffRoot(directoryA.FullName,
                                                     directoryB.FullName,
                                                     _Recursive, _Filter, _DiffMode, source);

                if (directoryA.Exists == false || directoryB.Exists == false)
                {
                    return(null);
                }

                // directory diff match
                this.BuildSubDirs(directoryA, directoryB, _Recursive, _Filter, diffRoot);
                this.AddFiles(diffRoot);

                return(diffRoot);
            }
            catch
            {
                return(null);
            }
        }
示例#2
0
        /// <summary>
        /// Compares <paramref name="directoryA"/> with <paramref name="directoryB"/> using the comparison
        /// options as defined in the constructor of this class.
        /// </summary>
        /// <param name="directoryA"></param>
        /// <param name="directoryB"></param>
        /// <param name="progress"></param>
        /// <param name="source"></param>
        /// <returns>Null if an unkown error occured or if either directory cannot be accessed
        /// (or does not exist), otherwise returns a <see cref="IDiffProgress"/> object
        /// where the <see cref="IDiffProgress.ResultData"/> property contains a
        /// <see cref="IDirectoryDiffRoot"/> data structure that describes the directory
        /// differences in detail.</returns>
        public IDiffProgress Execute(IDirectoryInfo directoryA,
                                     IDirectoryInfo directoryB,
                                     IDiffProgress progress,
                                     IDataSource source)
        {
            try
            {
                // Create a faux base entry to pass to Execute
                var diffRoot = new DirectoryDiffRoot(directoryA.FullName,
                                                     directoryB.FullName,
                                                     _Recursive, _Filter, _DiffMode, source);

                progress.ResultData = diffRoot;
                progress.ShowIndeterminatedProgress();

                if (directoryA.Exists == false || directoryB.Exists == false)
                {
                    return(null);
                }

                // directory diff match
                int directories = this.BuildSubDirs(directoryA, directoryB,
                                                    _Recursive, _Filter, diffRoot);

                progress.ShowDeterminatedProgress(0, 0, directories);
                this.AddFiles(diffRoot, progress);

                return(progress);
            }
            catch (Exception exp)
            {
                progress.LogException(exp);
                return(null);
            }
            finally
            {
                progress.ProgressDisplayOff();
            }
        }
示例#3
0
        /// <summary>
        /// Compares 2 sets of aligned <see cref="FileSystemInfo"/> objects and returns their
        /// status in terms of difference in the <paramref name="node"/> parameter.
        /// </summary>
        /// <param name="root"></param>
        /// <param name="mergeIndex">Contains the 2 sets of objects to compare in a merged sorted list</param>
        /// <param name="node">Contains the directory base entry and resulting list of files</param>
        /// <param name="checkIfFilesAreDifferent"></param>
        /// <param name="lengthSumA"></param>
        /// <param name="lengthSumB"></param>
        private void DiffFiles(DirectoryDiffRoot root,
                               Merge.MergeIndex mergeIndex,
                               IDirectoryDiffEntry node,
                               bool checkIfFilesAreDifferent,
                               out double lengthSumA, out double lengthSumB)
        {
            lengthSumA = 0;
            lengthSumB = 0;

            foreach (var item in mergeIndex.MergedEntries)
            {
                DateTime lastUpdateA = default(DateTime);
                DateTime lastUpdateB = default(DateTime);
                double   lengthA = 0.0, lengthB = 0.0;

                if (item.InfoA != null)
                {
                    lastUpdateA = item.InfoA.LastWriteTime;

                    try
                    {
                        if (item.InfoA is IFileInfo)
                        {
                            lengthA     = ((IFileInfo)item.InfoA).Length;
                            lengthSumA += lengthA;
                        }
                    }
                    catch
                    {
                        lengthA = 0;
                    }
                }

                if (item.InfoB != null)
                {
                    lastUpdateB = item.InfoB.LastWriteTime;

                    try
                    {
                        if (item.InfoB is IFileInfo)
                        {
                            lengthB     = ((IFileInfo)item.InfoB).Length;
                            lengthSumB += lengthB;
                        }
                    }
                    catch
                    {
                        lengthB = 0;
                    }
                }

                string basePath              = GetBasePath(root.RootPathA, item.InfoA, root.RootPathB, item.InfoB);
                IDirectoryDiffEntry newEntry = null;

                // The item is in both directories
                if (item.InfoA != null && item.InfoB != null)
                {
                    if (_ShowDifferent || _ShowSame)
                    {
                        bool different = false;

                        // Are these different by byte length and/or time stamp already?
                        if ((root.DiffMode & DiffDirFileMode.ByteLength) != 0)
                        {
                            if (Math.Abs(lengthA - lengthB) > _epsilon)
                            {
                                different = true;
                            }
                        }

                        if ((root.DiffMode & DiffDirFileMode.LastUpdate) != 0)
                        {
                            // Precision of TimeStamp depends on backend filesystem
                            // https://superuser.com/questions/937380/get-creation-time-of-file-in-milliseconds
                            if (Math.Abs(Math.Round((lastUpdateA - lastUpdateB).TotalSeconds)) > this._LastUpDatePrecision)
                            {
                                different = true;
                            }
                        }

                        Exception except = null;

                        // Byte by Byte checking is rather slow. Do it only if faster checks have not
                        // determined in-equality and byte-by-byte diff mode is active
                        if (checkIfFilesAreDifferent &&
                            different == false &&
                            (root.DiffMode & DiffDirFileMode.AllBytes) != 0)
                        {
                            try
                            {
                                if (root.Source.AreFilesDifferent(item.InfoA.FullName, item.InfoB.FullName) == true)
                                {
                                    different = true;
                                }
                            }
                            catch (System.IO.IOException ex)
                            {
                                except = ex;
                            }
                            catch (UnauthorizedAccessException ex)
                            {
                                except = ex;
                            }
                        }

                        if ((different && _ShowDifferent) || (!different && _ShowSame))
                        {
                            newEntry = new DirectoryDiffEntry(basePath, item.InfoA.Name, true, true, true,
                                                              lastUpdateA, lastUpdateB, lengthA, lengthB);

                            newEntry.Different = different;

                            if (except != null)
                            {
                                newEntry.Error = string.Format("'{0}' -> '{1}'", except.Message, except.StackTrace);
                            }
                        }
                    }
                }
                else if (item.InfoA != null && item.InfoB == null)
                {
                    // The item is only in A
                    if (this._ShowOnlyInA)
                    {
                        newEntry = new DirectoryDiffEntry(basePath, item.InfoA.Name, true, true, false,
                                                          lastUpdateA, default(DateTime), lengthA, 0.0);
                    }
                }
                else
                {
                    // The item is only in B
                    if (this._ShowOnlyInB)
                    {
                        newEntry = new DirectoryDiffEntry(basePath, item.InfoB.Name, true, false, true,
                                                          default(DateTime), lastUpdateB, 0.0, lengthB);
                    }
                }

                if (newEntry != null)
                {
                    // Mark directory as different if containing files are different
                    if (newEntry.Different == true)
                    {
                        node.Different = true;
                        root.AddDiffFile(newEntry);                           // Add into collection of different files
                    }

                    node.AddSubEntry(newEntry);
                }
            }
        }
示例#4
0
        /// <summary>
        /// Adds files into a given <paramref name="root"/> directory structure of sub-directories
        /// and re-evaluates their status in terms of difference.
        ///
        /// The algorithm used implements a Post-Order traversal algorithm which also allows us
        /// to aggregate results (sub-directory is different, size) up-wards through the hierarchy.
        /// </summary>
        /// <param name="root"></param>
        private void AddFiles(DirectoryDiffRoot root,
                              IDiffProgress progress)
        {
            int CountDirs = 0;

            // If the base paths are the same, we don't need to check for file differences.
            bool checkIfFilesAreDifferent = string.Compare(root.RootPathA, root.RootPathB, true) != 0;

            var toVisit          = new Stack <IDirectoryDiffEntry>();
            var visitedAncestors = new Stack <IDirectoryDiffEntry>();

            toVisit.Push(root.RootEntry);
            while (toVisit.Count > 0)
            {
                if (progress != null)
                {
                    if (progress.Token.IsCancellationRequested)
                    {
                        progress.Token.ThrowIfCancellationRequested();
                    }
                }

                var node = toVisit.Peek();
                if (node.CountSubDirectories() > 0)
                {
                    if (PeekOrDefault(visitedAncestors) != node)
                    {
                        visitedAncestors.Push(node);
                        PushReverse(toVisit, node.Subentries.ToList());
                        continue;
                    }

                    visitedAncestors.Pop();
                }

                // Load files only if either directory is available and recursion is on
                // -> Load files only for root directory if recursion is turned off
                if ((node.InA == true || node.InB == true) && (this._Recursive || string.IsNullOrEmpty(node.BasePath)))
                {
                    if (node.CountSubDirectories() > 0)
                    {
                        foreach (var item in node.Subentries)                         // Aggregate size of sub-directories up
                        {
                            if (progress != null)
                            {
                                if (progress.Token.IsCancellationRequested)
                                {
                                    progress.Token.ThrowIfCancellationRequested();
                                }
                            }

                            CountDirs++;
                            if (progress != null)
                            {
                                if (progress != null)
                                {
                                    progress.UpdateDeterminatedProgress(CountDirs);
                                }
                            }

                            if (node.InA == true)
                            {
                                node.LengthA += item.LengthA;
                            }

                            if (node.InB == true)
                            {
                                node.LengthB += item.LengthB;
                            }
                        }
                    }

                    string         sDirA, sDirB;
                    IDirectoryInfo dirA = null, dirB = null;
                    bool           dirA_Exists = false;
                    bool           dirB_Exists = false;

                    try
                    {
                        if (node.InA)
                        {
                            sDirA       = root.Source.Combine(root.RootPathA, node.BasePath);
                            dirA        = root.Source.CreateDirectory(sDirA);
                            dirA_Exists = dirA.Exists;
                        }
                    }
                    catch                    // This may throw on non-existing, authorization issues
                    {                        // So, we catch it it and ignore these for now
                        dirA_Exists = false;
                    }

                    try
                    {
                        if (node.InB)
                        {
                            sDirB       = root.Source.Combine(root.RootPathB, node.BasePath);
                            dirB        = root.Source.CreateDirectory(sDirB);
                            dirB_Exists = dirB.Exists;
                        }
                    }
                    catch                    // This may throw on non-existing, authorization issues
                    {                        // So, we catch it it and ignore these for now
                        dirB_Exists = false;
                    }

                    if (dirA_Exists == true || dirB_Exists == true)
                    {
                        // Get the arrays of files and merge them into 1 list
                        IFileInfo[]      filesA, filesB;
                        Merge.MergeIndex mergeIdx = null;
                        if (root.Filter == null)
                        {
                            if (dirA_Exists)
                            {
                                filesA = dirA.GetFiles();
                            }
                            else
                            {
                                filesA = null;
                            }

                            if (dirB_Exists)
                            {
                                filesB = dirB.GetFiles();
                            }
                            else
                            {
                                filesB = null;
                            }

                            mergeIdx = new Merge.MergeIndex(filesA, filesB, false, _ShowOnlyInA, _ShowOnlyInB);
                        }
                        else
                        {
                            if (dirA_Exists)
                            {
                                filesA = root.Filter.Filter(dirA);
                            }
                            else
                            {
                                filesA = null;
                            }

                            if (dirB_Exists)
                            {
                                filesB = root.Filter.Filter(dirB);
                            }
                            else
                            {
                                filesB = null;
                            }

                            // Assumption: Filter generates sorted entries
                            mergeIdx = new Merge.MergeIndex(filesA, filesB, true, _ShowOnlyInA, _ShowOnlyInB);
                        }

                        // Merge and Diff them
                        mergeIdx.Merge();

                        double lengthSumA, lengthSumB;
                        DiffFiles(root, mergeIdx, node, checkIfFilesAreDifferent, out lengthSumA, out lengthSumB);

                        // Add size of files to size of this directory (which includes size of sub-directories)
                        if (dirA_Exists)
                        {
                            node.LengthA += lengthSumA;
                        }

                        if (dirB_Exists)
                        {
                            node.LengthB += lengthSumB;
                        }

                        node.SetDiffBasedOnChildren(_IgnoreDirectoryComparison);
                    }
                }

                toVisit.Pop();
            }
        }
示例#5
0
 /// <summary>
 /// Adds files into a given <paramref name="root"/> directory structure of sub-directories
 /// and re-evaluates their status in terms of difference.
 ///
 /// The algorithm used implements a Post-Order traversal algorithm which also allows us
 /// to aggregate results (sub-directory is different, size) up-wards through the hierarchy.
 /// </summary>
 /// <param name="root"></param>
 private void AddFiles(DirectoryDiffRoot root)
 {
     AddFiles(root, null);
 }
示例#6
0
        /// <summary>
        /// Builds an initial directory structure that contains all sub-directories being contained
        /// in A and B (the structure ends at any point where a given directory occurs only in A or
        /// only in B).
        ///
        /// The structure is build with a Level Order traversal algorithm.
        ///
        /// Tip: Use a Post Order algorithm to look at each directory in the structure and aggregate
        ///      results up-wards within the directory structure.
        /// </summary>
        /// <param name="dirA"></param>
        /// <param name="dirB"></param>
        /// <param name="recursive"></param>
        /// <param name="filter"></param>
        /// <param name="diffRoot"></param>
        /// <returns>A root diff entry that describes directory differences through its properties.</returns>
        private int BuildSubDirs(IDirectoryInfo dirA,
                                 IDirectoryInfo dirB,
                                 bool recursive,
                                 DirectoryDiffFileFilter filter,
                                 DirectoryDiffRoot diffRoot)
        {
            var queue = new Queue <Tuple <int, MergedEntry> >();
            var index = new Dictionary <string, IDirectoryDiffEntry>();

            // Associate root level entry with empty path since path associations
            // below works with RELATIVE path references to given root entries
            index.Add(string.Empty, diffRoot.RootEntry);

            // Assign base directories of level order traversal
            var root = new MergedEntry(dirA, dirB);

            queue.Enqueue(new Tuple <int, MergedEntry>(0, root));

            while (queue.Count() > 0)
            {
                var         queueItem = queue.Dequeue();
                int         iLevel    = queueItem.Item1;
                MergedEntry current   = queueItem.Item2;

                if (iLevel > 0)
                {
                    string basePath = GetBasePath(diffRoot.RootPathA, current.InfoA,
                                                  diffRoot.RootPathB, current.InfoB);

                    string parentPath = GetParentPath(basePath);

                    IDirectoryDiffEntry parentItem;
                    if (index.TryGetValue(parentPath, out parentItem) == true)
                    {
                        var entry = ConvertDirEntry(basePath, current);
                        if (entry != null)
                        {
                            index.Add(basePath, entry);
                            parentItem.AddSubEntry(entry);
                            parentItem.SetDiffBasedOnChildren(_IgnoreDirectoryComparison);
                        }
                    }
                    else
                    {
                        // FIXME
                        continue;
                        // There are conditions for this case but these needs to be specified and tested here
                        //
                        // parentPath should always been pushed before since we do Level Order Traversal
                        // So, it must be available here - something is horribly wrong if we ever got here
                        ////throw new NotSupportedException(string.Format("ParentPath '{0}', BasePath '{1}'"
                        ////                                            , parentPath, basePath));
                    }
                }

                if (_Recursive || iLevel == 0)
                {
                    // Process the node if either sub-directory has children
                    IDirectoryInfo[] directoriesA = null;
                    IDirectoryInfo[] directoriesB = null;

                    // Get the arrays of subdirectories and merge them into 1 list
                    if (current.InfoA != null)
                    {
                        directoriesA = ((IDirectoryInfo)current.InfoA).GetDirectories();
                    }
                    else
                    {
                        directoriesA = null;
                    }

                    if (current.InfoB != null)
                    {
                        directoriesB = ((IDirectoryInfo)current.InfoB).GetDirectories();
                    }
                    else
                    {
                        directoriesB = null;
                    }

                    // Merge them and Diff them
                    var mergeIdx = new Merge.MergeIndex(directoriesA, directoriesB, false, _ShowOnlyInA, _ShowOnlyInB);
                    mergeIdx.Merge();

                    foreach (var item in mergeIdx.MergedEntries)
                    {
                        queue.Enqueue(new Tuple <int, MergedEntry>(iLevel + 1, item));
                    }
                }
            }

            return(index.Count);
        }