diff --git a/Duplicati/Library/Backend/File/FileBackend.cs b/Duplicati/Library/Backend/File/FileBackend.cs index a2b005458..a49d0a05e 100644 --- a/Duplicati/Library/Backend/File/FileBackend.cs +++ b/Duplicati/Library/Backend/File/FileBackend.cs @@ -176,15 +176,7 @@ namespace Duplicati.Library.Backend if (!systemIO.DirectoryExists(m_path)) throw new FolderMissingException(Strings.FileBackend.FolderMissingError(m_path)); - foreach (string s in systemIO.EnumerateFiles(m_path)) - { - yield return systemIO.FileEntry(s); - } - - foreach (string s in systemIO.EnumerateDirectories(m_path)) - { - yield return systemIO.DirectoryEntry(s); - } + return systemIO.EnumerateFileEntries(m_path); } #if DEBUG_RETRY diff --git a/Duplicati/Library/Common/IO/ISystemIO.cs b/Duplicati/Library/Common/IO/ISystemIO.cs index 654e72449..c0fb6affc 100644 --- a/Duplicati/Library/Common/IO/ISystemIO.cs +++ b/Duplicati/Library/Common/IO/ISystemIO.cs @@ -28,6 +28,7 @@ namespace Duplicati.Library.Common.IO public interface ISystemIO { IFileEntry DirectoryEntry(string path); + IFileEntry DirectoryEntry(DirectoryInfo dirInfo); void DirectoryCreate(string path); void DirectoryDelete(string path, bool recursive); bool DirectoryExists(string path); @@ -36,6 +37,7 @@ namespace Duplicati.Library.Common.IO void DirectorySetCreationTimeUtc(string path, DateTime time); IFileEntry FileEntry(string path); + IFileEntry FileEntry(FileInfo fileInfo); void FileMove(string source, string target); void FileDelete(string path); void FileCopy(string source, string target, bool overwrite); @@ -69,6 +71,10 @@ namespace Duplicati.Library.Common.IO IEnumerable EnumerateFiles(string path, string searchPattern, SearchOption searchOption); IEnumerable EnumerateDirectories(string path); + // Enumerate FileEntries of files and directories + // This is more efficient than enumerating file names when metadata is needed + IEnumerable EnumerateFileEntries(string path); + void SetMetadata(string path, Dictionary metdata, bool restorePermissions); Dictionary GetMetadata(string path, bool isSymlink, bool followSymlink); } diff --git a/Duplicati/Library/Common/IO/SystemIOLinux.cs b/Duplicati/Library/Common/IO/SystemIOLinux.cs index 1acb95b47..6ac013cc1 100644 --- a/Duplicati/Library/Common/IO/SystemIOLinux.cs +++ b/Duplicati/Library/Common/IO/SystemIOLinux.cs @@ -132,6 +132,22 @@ namespace Duplicati.Library.Common.IO return Directory.EnumerateFiles(path, searchPattern, searchOption); } + public IEnumerable EnumerateFileEntries(string path) + { + // For consistency with previous implementation, enumerate files first and directories after + DirectoryInfo dir = new DirectoryInfo(path); + + foreach (FileInfo file in dir.EnumerateFiles()) + { + yield return FileEntry(file); + } + + foreach (DirectoryInfo d in dir.EnumerateDirectories()) + { + yield return DirectoryEntry(d); + } + } + public string PathGetFileName(string path) { return Path.GetFileName(path); @@ -293,7 +309,10 @@ namespace Duplicati.Library.Common.IO public IFileEntry DirectoryEntry(string path) { - var dInfo = new DirectoryInfo(path); + return DirectoryEntry(new DirectoryInfo(path)); + } + public IFileEntry DirectoryEntry(DirectoryInfo dInfo) + { return new FileEntry(dInfo.Name, 0, dInfo.LastAccessTime, dInfo.LastWriteTime) { IsFolder = true @@ -302,7 +321,10 @@ namespace Duplicati.Library.Common.IO public IFileEntry FileEntry(string path) { - var fileInfo = new FileInfo(path); + return FileEntry(new FileInfo(path)); + } + public IFileEntry FileEntry(FileInfo fileInfo) + { return new FileEntry(fileInfo.Name, fileInfo.Length, fileInfo.LastAccessTime, fileInfo.LastWriteTime); } } diff --git a/Duplicati/Library/Common/IO/SystemIOWindows.cs b/Duplicati/Library/Common/IO/SystemIOWindows.cs index 343dcb78e..cb16831e6 100644 --- a/Duplicati/Library/Common/IO/SystemIOWindows.cs +++ b/Duplicati/Library/Common/IO/SystemIOWindows.cs @@ -75,7 +75,7 @@ namespace Duplicati.Library.Common.IO } } } - + /// /// Returns true if prefixed with @"\\" or @"//". /// @@ -361,7 +361,7 @@ namespace Duplicati.Library.Common.IO public IEnumerable EnumerateFiles(string path, string searchPattern, SearchOption searchOption) { - return System.IO.Directory.EnumerateFiles(AddExtendedDevicePathPrefix(path), searchPattern, searchOption).Select(RemoveExtendedDevicePathPrefix); + return System.IO.Directory.EnumerateFiles(AddExtendedDevicePathPrefix(path), searchPattern, searchOption).Select(RemoveExtendedDevicePathPrefix); } public string PathGetFileName(string path) @@ -474,6 +474,30 @@ namespace Duplicati.Library.Common.IO } } + public IEnumerable EnumerateFileEntries(string path) + { + // For consistency with previous implementation, enumerate files first and directories after + DirectoryInfo dir; + if (IsPrefixedWithExtendedDevicePathPrefix(path)) + { + dir = new DirectoryInfo(path); + } + else + { + dir = new DirectoryInfo(AddExtendedDevicePathPrefix(path)); + } + + foreach (FileInfo file in dir.EnumerateFiles()) + { + yield return FileEntry(file); + } + + foreach (DirectoryInfo d in dir.EnumerateDirectories()) + { + yield return DirectoryEntry(d); + } + } + public void FileCopy(string source, string target, bool overwrite) { File.Copy(AddExtendedDevicePathPrefix(source), AddExtendedDevicePathPrefix(target), overwrite); @@ -498,7 +522,10 @@ namespace Duplicati.Library.Common.IO public IFileEntry DirectoryEntry(string path) { - var dInfo = new DirectoryInfo(AddExtendedDevicePathPrefix(path)); + return DirectoryEntry(new DirectoryInfo(AddExtendedDevicePathPrefix(path))); + } + public IFileEntry DirectoryEntry(DirectoryInfo dInfo) + { return new FileEntry(dInfo.Name, 0, dInfo.LastAccessTime, dInfo.LastWriteTime) { IsFolder = true @@ -507,7 +534,10 @@ namespace Duplicati.Library.Common.IO public IFileEntry FileEntry(string path) { - var fileInfo = new FileInfo(AddExtendedDevicePathPrefix(path)); + return FileEntry(new FileInfo(AddExtendedDevicePathPrefix(path))); + } + public IFileEntry FileEntry(FileInfo fileInfo) + { var lastAccess = new DateTime(); try {