Exemple #1
0
        /// <summary>
        /// Filter supplied <c>folders</c>, removing any folder which itself, or one
        /// of its ancestors, is excluded by the <c>filter</c>.
        /// </summary>
        /// <param name="folders">Folder to filter</param>
        /// <param name="filter">Exclusion filter</param>
        /// <param name="cache">Cache of excluded folders (optional)</param>
        /// <param name="errorCallback"></param>
        /// <returns>Filtered folders</returns>
        private IEnumerable <string> FilterExcludedFolders(IEnumerable <string> folders,
                                                           Utility.Utility.EnumerationFilterDelegate filter, IDictionary <string, bool> cache, Utility.Utility.ReportAccessError errorCallback = null)
        {
            var result = new List <string>();

            foreach (var folder in folders)
            {
                if (m_token.IsCancellationRequested)
                {
                    break;
                }

                try
                {
                    if (!IsFolderOrAncestorsExcluded(folder, filter, cache))
                    {
                        result.Add(folder);
                    }
                }
                catch (System.Threading.ThreadAbortException)
                {
                    throw;
                }
                catch (Exception ex)
                {
                    errorCallback?.Invoke(folder, folder, ex);
                    filter(folder, folder, FileAttributes.Directory | Utility.Utility.ATTRIBUTE_ERROR);
                }
            }

            return(result);
        }
Exemple #2
0
        /// <summary>
        /// Filter supplied <c>files</c>, removing any files which itself, or one
        /// of its parent folders, is excluded by the <c>filter</c>.
        /// </summary>
        /// <param name="files">Files to filter</param>
        /// <param name="filter">Exclusion filter</param>
        /// <param name="cache">Cache of included and exculded files / folders</param>
        /// <param name="errorCallback"></param>
        /// <returns>Filtered files</returns>
        private IEnumerable <string> FilterExcludedFiles(IEnumerable <string> files,
                                                         Utility.Utility.EnumerationFilterDelegate filter, IDictionary <string, bool> cache, Utility.Utility.ReportAccessError errorCallback = null)
        {
            var result = new List <string>();

            foreach (var file in files)
            {
                var attr = m_snapshot.FileExists(file) ? m_snapshot.GetAttributes(file) : FileAttributes.Normal;
                try
                {
                    if (!filter(file, file, attr))
                    {
                        continue;
                    }

                    if (!IsFolderOrAncestorsExcluded(Utility.Utility.GetParent(file, true), filter, cache))
                    {
                        result.Add(file);
                    }
                }
                catch (System.Threading.ThreadAbortException)
                {
                    throw;
                }
                catch (Exception ex)
                {
                    errorCallback?.Invoke(file, file, ex);
                    filter(file, file, attr | Utility.Utility.ATTRIBUTE_ERROR);
                }
            }

            return(result);
        }
Exemple #3
0
        /// <summary>
        /// Filters sources, returning sub-set having been modified since last
        /// change, as specified by <c>journalData</c>.
        /// </summary>
        /// <param name="filter">Filter callback to exclude filtered items</param>
        /// <returns>Filtered sources</returns>
        public IEnumerable <string> GetModifiedSources(Utility.Utility.EnumerationFilterDelegate filter)
        {
            // iterate over volumes
            foreach (var volumeData in m_volumeDataDict)
            {
                // prepare cache for includes (value = true) and excludes (value = false, will be populated
                // on-demand)
                var cache = new Dictionary <string, bool>();
                foreach (var source in m_sources)
                {
                    if (m_token.IsCancellationRequested)
                    {
                        break;
                    }

                    cache[source] = true;
                }

                // Check the simplified folders, and their parent folders  against the exclusion filter.
                // This is needed because the filter may exclude "C:\A\", but this won't match the more
                // specific "C:\A\B\" in our list, even though it's meant to be excluded.
                // The reason why the filter doesn't exclude it is because during a regular (non-USN) full scan,
                // FilterHandler.EnumerateFilesAndFolders() works top-down, and won't even enumerate child
                // folders.
                // The sources are needed to stop evaluating parent folders above the specified source folders
                if (volumeData.Value.Folders != null)
                {
                    foreach (var folder in FilterExcludedFolders(volumeData.Value.Folders, filter, cache).Where(m_snapshot.DirectoryExists))
                    {
                        if (m_token.IsCancellationRequested)
                        {
                            break;
                        }

                        yield return(folder);
                    }
                }

                // The simplified file list also needs to be checked against the exclusion filter, as it
                // may contain entries excluded due to attributes, but also because they are below excluded
                // folders, which themselves aren't in the folder list from step 1.
                // Note that the simplified file list may contain entries that have been deleted! They need to
                // be kept in the list (unless excluded by the filter) in order for the backup handler to record their
                // deletion.
                if (volumeData.Value.Files != null)
                {
                    foreach (var files in FilterExcludedFiles(volumeData.Value.Files, filter, cache).Where(m_snapshot.FileExists))
                    {
                        if (m_token.IsCancellationRequested)
                        {
                            break;
                        }

                        yield return(files);
                    }
                }
            }
        }
Exemple #4
0
        /// <summary>
        /// Tests if specified folder, or any of its ancestors, is excluded by the filter
        /// </summary>
        /// <param name="folder">Folder to test</param>
        /// <param name="filter">Filter</param>
        /// <param name="cache">Cache of excluded folders (optional)</param>
        /// <returns>True if excluded, false otherwise</returns>
        private bool IsFolderOrAncestorsExcluded(string folder, Utility.Utility.EnumerationFilterDelegate filter, IDictionary <string, bool> cache)
        {
            List <string> parents = null;

            while (folder != null)
            {
                if (m_token.IsCancellationRequested)
                {
                    break;
                }

                // first check cache
                if (cache.TryGetValue(folder, out var include))
                {
                    if (include)
                    {
                        return(false);
                    }

                    break; // hit!
                }

                // remember folder for cache
                if (parents == null)
                {
                    parents = new List <string>(); // create on-demand
                }
                parents.Add(folder);


                var attr = m_snapshot.DirectoryExists(folder) ? m_snapshot.GetAttributes(folder) : FileAttributes.Directory;

                if (!filter(folder, folder, attr))
                {
                    break; // excluded
                }
                folder = Utility.Utility.GetParent(folder, true);
            }

            if (folder != null)
            {
                // update cache
                parents?.ForEach(p => cache[p] = false);
            }

            return(folder != null);
        }
Exemple #5
0
 /// <summary>
 /// Enumerates all files and folders in the shadow copy
 /// </summary>
 /// <param name="sources">Source paths to enumerate</param>
 /// <param name="callback">The callback to invoke with each found path</param>
 /// <param name="errorCallback">The callback used to report errors</param>
 public IEnumerable <string> EnumerateFilesAndFolders(IEnumerable <string> sources, Utility.Utility.EnumerationFilterDelegate callback, Utility.Utility.ReportAccessError errorCallback)
 {
     return(sources.SelectMany(s => Utility.Utility.EnumerateFileSystemEntries(s, callback, ListFolders, ListFiles, GetAttributes, errorCallback)));
 }
Exemple #6
0
        /// <summary>
        /// Enumerates all files and folders in the shadow copy
        /// </summary>
        /// <param name="sources">Source paths to enumerate</param>
        /// <param name="callback">The callback to invoke with each found path</param>
        /// <param name="errorCallback">The callback used to report errors</param>
        public IEnumerable <string> EnumerateFilesAndFolders(IEnumerable <string> sources, Utility.Utility.EnumerationFilterDelegate callback, Utility.Utility.ReportAccessError errorCallback)
        {
            // Add trailing slashes to folders
            var sanitizedSources = sources.Select(x => DirectoryExists(x) ? Utility.Utility.AppendDirSeparator(x) : x).ToList();

            return(sanitizedSources.SelectMany(
                       s => Utility.Utility.EnumerateFileSystemEntries(s, callback, ListFolders, ListFiles, GetAttributes, errorCallback)
                       ));
        }
 /// <summary>
 /// Enumerates all files and folders in the snapshot, restricted to sources
 /// </summary>
 /// <param name="sources">Sources to enumerate</param>
 /// <param name="callback">The callback to invoke with each found path</param>
 /// <param name="errorCallback">The callback used to report errors</param>
 public override IEnumerable <string> EnumerateFilesAndFolders(IEnumerable <string> sources, Utility.Utility.EnumerationFilterDelegate callback, Utility.Utility.ReportAccessError errorCallback)
 {
     // For Windows, ensure we don't store paths with UNC prefix
     return(base.EnumerateFilesAndFolders(sources.Select(SystemIOWindows.StripUNCPrefix), callback, errorCallback));
 }
Exemple #8
0
 /// <summary>
 /// Enumerates all files and folders in the snapshot, restricted to sources
 /// </summary>
 /// <param name="sources">Sources to enumerate</param>
 /// <param name="callback">The callback to invoke with each found path</param>
 /// <param name="errorCallback">The callback used to report errors</param>
 public override IEnumerable <string> EnumerateFilesAndFolders(IEnumerable <string> sources, Utility.Utility.EnumerationFilterDelegate callback, Utility.Utility.ReportAccessError errorCallback)
 {
     // For Windows, ensure we don't store paths with extended device path prefixes (i.e., @"\\?\" or @"\\?\UNC\")
     return(base.EnumerateFilesAndFolders(sources.Select(SystemIOWindows.RemoveExtendedDevicePathPrefix), callback, errorCallback));
 }