From b2cc18426c5297a3da4cf1164a846091d1f9f457 Mon Sep 17 00:00:00 2001 From: verhoek <30193551+verhoek@users.noreply.github.com> Date: Fri, 2 Nov 2018 21:34:07 +0100 Subject: Renamed Library.IO to Library.Common.IO. Moved basic Platform functions to Library.Common.Platform. Turned IO_OS into property within Library.Common. --- Duplicati.sln | 10 +- Duplicati/CommandLine/Commands.cs | 2 +- Duplicati/CommandLine/Duplicati.CommandLine.csproj | 2 +- .../Duplicati.CommandLine.RecoveryTool.csproj | 2 +- Duplicati/CommandLine/RecoveryTool/Restore.cs | 2 +- .../Duplicati.GUI.TrayIcon/AppIndicatorRunner.cs | 8 +- .../Duplicati.GUI.TrayIcon.csproj | 2 +- .../Duplicati.GUI.TrayIcon/HttpServerConnection.cs | 2 +- .../Duplicati.Library.AutoUpdater.csproj | 2 +- Duplicati/Library/AutoUpdater/Program.cs | 2 +- Duplicati/Library/AutoUpdater/UpdaterManager.cs | 4 +- .../AlternativeFTP/AlternativeFTPBackend.cs | 4 +- ...Duplicati.Library.Backend.AlternativeFTP.csproj | 2 +- .../Library/Backend/AmazonCloudDrive/AmzCD.cs | 4 +- ...plicati.Library.Backend.AmazonCloudDrive.csproj | 2 +- .../Library/Backend/AzureBlob/AzureBlobWrapper.cs | 2 +- .../Duplicati.Library.Backend.AzureBlob.csproj | 2 +- Duplicati/Library/Backend/Backblaze/B2.cs | 2 +- .../Duplicati.Library.Backend.Backblaze.csproj | 2 +- Duplicati/Library/Backend/Box/BoxBackend.cs | 2 +- .../Box/Duplicati.Library.Backend.Box.csproj | 2 +- Duplicati/Library/Backend/CloudFiles/CloudFiles.cs | 2 +- .../Duplicati.Library.Backend.CloudFiles.csproj | 2 +- Duplicati/Library/Backend/Dropbox/Dropbox.cs | 2 +- .../Duplicati.Library.Backend.Dropbox.csproj | 2 +- .../FTP/Duplicati.Library.Backend.FTP.csproj | 2 +- Duplicati/Library/Backend/FTP/FTPBackend.cs | 2 +- .../File/Duplicati.Library.Backend.File.csproj | 2 +- Duplicati/Library/Backend/File/FileBackend.cs | 4 +- ...Duplicati.Library.Backend.GoogleServices.csproj | 2 +- .../Backend/GoogleServices/GoogleCloudStorage.cs | 2 +- .../Library/Backend/GoogleServices/GoogleDrive.cs | 2 +- .../Duplicati.Library.Backend.Jottacloud.csproj | 2 +- Duplicati/Library/Backend/Jottacloud/Jottacloud.cs | 2 +- .../Mega/Duplicati.Library.Backend.Mega.csproj | 2 +- Duplicati/Library/Backend/Mega/MegaBackend.cs | 2 +- .../Duplicati.Library.Backend.OneDrive.csproj | 2 +- .../Backend/OneDrive/MicrosoftGraphBackend.cs | 2 +- Duplicati/Library/Backend/OneDrive/OneDrive.cs | 2 +- .../Duplicati.Library.Backend.OpenStack.csproj | 2 +- .../Library/Backend/OpenStack/OpenStackStorage.cs | 2 +- .../Rclone/Duplicati.Library.Backend.Rclone.csproj | 2 +- Duplicati/Library/Backend/Rclone/Rclone.cs | 2 +- .../Backend/S3/Duplicati.Library.Backend.S3.csproj | 2 +- Duplicati/Library/Backend/S3/S3Backend.cs | 2 +- Duplicati/Library/Backend/S3/S3Wrapper.cs | 2 +- .../SSHv2/Duplicati.Library.Backend.SSHv2.csproj | 2 +- Duplicati/Library/Backend/SSHv2/SSHv2Backend.cs | 2 +- .../Duplicati.Library.Backend.SharePoint.csproj | 2 +- .../Backend/SharePoint/SharePointBackend.cs | 2 +- .../Sia/Duplicati.Library.Backend.Sia.csproj | 2 +- Duplicati/Library/Backend/Sia/Sia.cs | 2 +- .../Duplicati.Library.Backend.TahoeLAFS.csproj | 2 +- .../Library/Backend/TahoeLAFS/TahoeBackend.cs | 2 +- .../WEBDAV/Duplicati.Library.Backend.WEBDAV.csproj | 2 +- Duplicati/Library/Backend/WEBDAV/WEBDAV.cs | 2 +- .../Duplicati.Library.Compression.csproj | 2 +- .../Library/Compression/FileArchiveDirectory.cs | 2 +- Duplicati/Library/IO/DefineDosDevice.cs | 167 ----- .../Library/IO/Duplicati.Library.Common.csproj | 101 +++ Duplicati/Library/IO/Duplicati.Library.IO.csproj | 96 --- Duplicati/Library/IO/FileEntry.cs | 130 ---- Duplicati/Library/IO/IO/DefineDosDevice.cs | 167 +++++ Duplicati/Library/IO/IO/FileEntry.cs | 130 ++++ Duplicati/Library/IO/IO/ISystemIO.cs | 79 +++ Duplicati/Library/IO/IO/SystemIO.cs | 54 ++ Duplicati/Library/IO/IO/SystemIOLinux.cs | 314 +++++++++ Duplicati/Library/IO/IO/SystemIOWindows.cs | 782 ++++++++++++++++++++ Duplicati/Library/IO/IO/Util.cs | 65 ++ Duplicati/Library/IO/IO/VssBackupComponents.cs | 308 ++++++++ Duplicati/Library/IO/ISystemIO.cs | 79 --- Duplicati/Library/IO/Platform/Platform.cs | 32 + Duplicati/Library/IO/SystemIO.cs | 54 -- Duplicati/Library/IO/SystemIOLinux.cs | 314 --------- Duplicati/Library/IO/SystemIOWindows.cs | 783 --------------------- Duplicati/Library/IO/Util.cs | 65 -- Duplicati/Library/IO/VssBackupComponents.cs | 308 -------- Duplicati/Library/Main/Controller.cs | 2 +- .../Main/Database/LocalBugReportDatabase.cs | 2 +- .../Library/Main/Database/LocalListDatabase.cs | 2 +- .../Library/Main/Database/LocalRestoreDatabase.cs | 2 +- .../Library/Main/Database/PathLookupHelper.cs | 2 +- .../Library/Main/Duplicati.Library.Main.csproj | 2 +- .../Operation/Backup/FileEnumerationProcess.cs | 4 +- Duplicati/Library/Main/Operation/BackupHandler.cs | 2 +- Duplicati/Library/Main/Operation/RestoreHandler.cs | 98 ++- .../Snapshots/Duplicati.Library.Snapshots.csproj | 2 +- Duplicati/Library/Snapshots/HyperVUtility.cs | 2 +- Duplicati/Library/Snapshots/LinuxSnapshot.cs | 2 +- Duplicati/Library/Snapshots/MSSQLUtility.cs | 2 +- Duplicati/Library/Snapshots/NoSnapshotLinux.cs | 2 +- Duplicati/Library/Snapshots/NoSnapshotWindows.cs | 2 +- Duplicati/Library/Snapshots/SnapshotBase.cs | 2 +- Duplicati/Library/Snapshots/SnapshotUtility.cs | 2 +- Duplicati/Library/Snapshots/USNJournal.cs | 2 +- Duplicati/Library/Snapshots/UsnJournalService.cs | 2 +- Duplicati/Library/Snapshots/WindowsSnapshot.cs | 2 +- .../Utility/Duplicati.Library.Utility.csproj | 2 +- Duplicati/Library/Utility/FilterGroups.cs | 2 +- Duplicati/Library/Utility/TempFile.cs | 6 +- Duplicati/Library/Utility/TempFolder.cs | 2 +- Duplicati/Library/Utility/Utility.cs | 6 +- Duplicati/License/Duplicati.License.csproj | 2 +- Duplicati/License/LicenseReader.cs | 6 +- Duplicati/Server/Duplicati.Server.csproj | 2 +- Duplicati/Server/Program.cs | 2 +- Duplicati/Server/SingleInstance.cs | 6 +- Duplicati/Server/SpecialFolders.cs | 6 +- Duplicati/Server/WebServer/IndexHtmlHandler.cs | 2 +- .../WebServer/RESTMethods/Acknowledgements.cs | 4 +- .../Server/WebServer/RESTMethods/BackupDefaults.cs | 4 +- .../Server/WebServer/RESTMethods/Filesystem.cs | 12 +- Duplicati/Server/WebServer/Server.cs | 2 +- Duplicati/UnitTest/Duplicati.UnitTest.csproj | 2 +- Duplicati/UnitTest/FilterTest.cs | 2 +- Duplicati/UnitTest/IOTests.cs | 12 +- Duplicati/UnitTest/PurgeTesting.cs | 4 +- Duplicati/UnitTest/SVNCheckoutsTest.cs | 2 +- Duplicati/UnitTest/SizeOmittingBackend.cs | 2 +- Duplicati/UnitTest/TestUtils.cs | 2 +- Duplicati/UnitTest/UtilityTests.cs | 2 +- 121 files changed, 2214 insertions(+), 2184 deletions(-) delete mode 100644 Duplicati/Library/IO/DefineDosDevice.cs create mode 100644 Duplicati/Library/IO/Duplicati.Library.Common.csproj delete mode 100644 Duplicati/Library/IO/Duplicati.Library.IO.csproj delete mode 100644 Duplicati/Library/IO/FileEntry.cs create mode 100644 Duplicati/Library/IO/IO/DefineDosDevice.cs create mode 100644 Duplicati/Library/IO/IO/FileEntry.cs create mode 100644 Duplicati/Library/IO/IO/ISystemIO.cs create mode 100644 Duplicati/Library/IO/IO/SystemIO.cs create mode 100644 Duplicati/Library/IO/IO/SystemIOLinux.cs create mode 100644 Duplicati/Library/IO/IO/SystemIOWindows.cs create mode 100644 Duplicati/Library/IO/IO/Util.cs create mode 100644 Duplicati/Library/IO/IO/VssBackupComponents.cs delete mode 100644 Duplicati/Library/IO/ISystemIO.cs create mode 100644 Duplicati/Library/IO/Platform/Platform.cs delete mode 100644 Duplicati/Library/IO/SystemIO.cs delete mode 100644 Duplicati/Library/IO/SystemIOLinux.cs delete mode 100644 Duplicati/Library/IO/SystemIOWindows.cs delete mode 100644 Duplicati/Library/IO/Util.cs delete mode 100644 Duplicati/Library/IO/VssBackupComponents.cs diff --git a/Duplicati.sln b/Duplicati.sln index d28480b36..1723a2f78 100644 --- a/Duplicati.sln +++ b/Duplicati.sln @@ -99,7 +99,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Library.Backend.S EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Library.Backend.Rclone", "Duplicati\Library\Backend\Rclone\Duplicati.Library.Backend.Rclone.csproj", "{851A1CB8-3CEB-41B4-956F-34D760D2A8E5}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Library.IO", "Duplicati\Library\IO\Duplicati.Library.IO.csproj", "{771272DA-3219-43D1-9AFC-0E808B5776C8}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Library.Common", "Duplicati\Library\IO\Duplicati.Library.Common.csproj", "{D63E53E4-A458-4C2F-914D-92F715F58ACF}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -299,10 +299,10 @@ Global {851A1CB8-3CEB-41B4-956F-34D760D2A8E5}.Debug|Any CPU.Build.0 = Debug|Any CPU {851A1CB8-3CEB-41B4-956F-34D760D2A8E5}.Release|Any CPU.ActiveCfg = Release|Any CPU {851A1CB8-3CEB-41B4-956F-34D760D2A8E5}.Release|Any CPU.Build.0 = Release|Any CPU - {771272DA-3219-43D1-9AFC-0E808B5776C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {771272DA-3219-43D1-9AFC-0E808B5776C8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {771272DA-3219-43D1-9AFC-0E808B5776C8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {771272DA-3219-43D1-9AFC-0E808B5776C8}.Release|Any CPU.Build.0 = Release|Any CPU + {D63E53E4-A458-4C2F-914D-92F715F58ACF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D63E53E4-A458-4C2F-914D-92F715F58ACF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D63E53E4-A458-4C2F-914D-92F715F58ACF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D63E53E4-A458-4C2F-914D-92F715F58ACF}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Duplicati/CommandLine/Commands.cs b/Duplicati/CommandLine/Commands.cs index 6a8a5d2bf..7091d1498 100644 --- a/Duplicati/CommandLine/Commands.cs +++ b/Duplicati/CommandLine/Commands.cs @@ -19,7 +19,7 @@ using System; using System.Linq; using System.Collections.Generic; using System.IO; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.CommandLine { diff --git a/Duplicati/CommandLine/Duplicati.CommandLine.csproj b/Duplicati/CommandLine/Duplicati.CommandLine.csproj index 8c3f35112..d2a885f7b 100644 --- a/Duplicati/CommandLine/Duplicati.CommandLine.csproj +++ b/Duplicati/CommandLine/Duplicati.CommandLine.csproj @@ -210,7 +210,7 @@ {D63E53E4-A458-4C2F-914D-92F715F58ACF} - Duplicati.Library.IO + Duplicati.Library.Common diff --git a/Duplicati/CommandLine/RecoveryTool/Duplicati.CommandLine.RecoveryTool.csproj b/Duplicati/CommandLine/RecoveryTool/Duplicati.CommandLine.RecoveryTool.csproj index 53796323f..85971d613 100644 --- a/Duplicati/CommandLine/RecoveryTool/Duplicati.CommandLine.RecoveryTool.csproj +++ b/Duplicati/CommandLine/RecoveryTool/Duplicati.CommandLine.RecoveryTool.csproj @@ -173,7 +173,7 @@ {D63E53E4-A458-4C2F-914D-92F715F58ACF} - Duplicati.Library.IO + Duplicati.Library.Common diff --git a/Duplicati/CommandLine/RecoveryTool/Restore.cs b/Duplicati/CommandLine/RecoveryTool/Restore.cs index 7faf024f1..c9fd8586a 100644 --- a/Duplicati/CommandLine/RecoveryTool/Restore.cs +++ b/Duplicati/CommandLine/RecoveryTool/Restore.cs @@ -18,7 +18,7 @@ using System; using System.IO; using System.Linq; using System.Collections.Generic; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.CommandLine.RecoveryTool { diff --git a/Duplicati/GUI/Duplicati.GUI.TrayIcon/AppIndicatorRunner.cs b/Duplicati/GUI/Duplicati.GUI.TrayIcon/AppIndicatorRunner.cs index 1bf0d98b0..0fee81b47 100644 --- a/Duplicati/GUI/Duplicati.GUI.TrayIcon/AppIndicatorRunner.cs +++ b/Duplicati/GUI/Duplicati.GUI.TrayIcon/AppIndicatorRunner.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2015, The Duplicati Team +// Copyright (C) 2015, The Duplicati Team // http://www.duplicati.com, info@duplicati.com // // This library is free software; you can redistribute it and/or modify @@ -20,7 +20,7 @@ using AppIndicator; using Gtk; using System.Collections.Generic; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; using Duplicati.Library.Utility; using Duplicati.Server.Serialization; @@ -34,8 +34,8 @@ namespace Duplicati.GUI.TrayIcon protected override void CreateTrayInstance() { - m_themeFolder = SystemIO.IO_OS(Utility.IsClientWindows).PathCombine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "SVGIcons"); - m_themeFolder = SystemIO.IO_OS(Utility.IsClientWindows).PathCombine(m_themeFolder, "dark"); + m_themeFolder = SystemIO.IO_OS.PathCombine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "SVGIcons"); + m_themeFolder = SystemIO.IO_OS.PathCombine(m_themeFolder, "dark"); m_appIndicator = new ApplicationIndicator("duplicati", "normal", Category.ApplicationStatus, m_themeFolder); } diff --git a/Duplicati/GUI/Duplicati.GUI.TrayIcon/Duplicati.GUI.TrayIcon.csproj b/Duplicati/GUI/Duplicati.GUI.TrayIcon/Duplicati.GUI.TrayIcon.csproj index adc121222..a6d294f64 100644 --- a/Duplicati/GUI/Duplicati.GUI.TrayIcon/Duplicati.GUI.TrayIcon.csproj +++ b/Duplicati/GUI/Duplicati.GUI.TrayIcon/Duplicati.GUI.TrayIcon.csproj @@ -342,7 +342,7 @@ {D63E53E4-A458-4C2F-914D-92F715F58ACF} - Duplicati.Library.IO + Duplicati.Library.Common diff --git a/Duplicati/GUI/Duplicati.GUI.TrayIcon/HttpServerConnection.cs b/Duplicati/GUI/Duplicati.GUI.TrayIcon/HttpServerConnection.cs index 8a7615b23..9bd9b4a19 100644 --- a/Duplicati/GUI/Duplicati.GUI.TrayIcon/HttpServerConnection.cs +++ b/Duplicati/GUI/Duplicati.GUI.TrayIcon/HttpServerConnection.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Net; using System.Text; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; using Duplicati.Server.Serialization; using Duplicati.Server.Serialization.Interface; diff --git a/Duplicati/Library/AutoUpdater/Duplicati.Library.AutoUpdater.csproj b/Duplicati/Library/AutoUpdater/Duplicati.Library.AutoUpdater.csproj index 2588f027f..798eb19a4 100644 --- a/Duplicati/Library/AutoUpdater/Duplicati.Library.AutoUpdater.csproj +++ b/Duplicati/Library/AutoUpdater/Duplicati.Library.AutoUpdater.csproj @@ -69,7 +69,7 @@ {D63E53E4-A458-4C2F-914D-92F715F58ACF} - Duplicati.Library.IO + Duplicati.Library.Common diff --git a/Duplicati/Library/AutoUpdater/Program.cs b/Duplicati/Library/AutoUpdater/Program.cs index fd9d31ba1..92ced508c 100644 --- a/Duplicati/Library/AutoUpdater/Program.cs +++ b/Duplicati/Library/AutoUpdater/Program.cs @@ -18,7 +18,7 @@ using System; using System.Linq; using System.Collections.Generic; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.Library.AutoUpdater { diff --git a/Duplicati/Library/AutoUpdater/UpdaterManager.cs b/Duplicati/Library/AutoUpdater/UpdaterManager.cs index 852eff04c..e17f1464b 100644 --- a/Duplicati/Library/AutoUpdater/UpdaterManager.cs +++ b/Duplicati/Library/AutoUpdater/UpdaterManager.cs @@ -21,7 +21,7 @@ using System.Collections.Generic; using System.IO; using System.Threading.Tasks; using Duplicati.Library.Interface; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.Library.AutoUpdater { @@ -406,7 +406,7 @@ namespace Duplicati.Library.AutoUpdater { var res = new List>(); if (INSTALLDIR != null) - foreach (var folder in SystemIO.IO_OS(Utility.Utility.IsClientWindows).GetDirectories(INSTALLDIR)) + foreach (var folder in SystemIO.IO_OS.GetDirectories(INSTALLDIR)) { var r = ReadInstalledManifest(folder); if (r != null) diff --git a/Duplicati/Library/Backend/AlternativeFTP/AlternativeFTPBackend.cs b/Duplicati/Library/Backend/AlternativeFTP/AlternativeFTPBackend.cs index 02557152b..0c4a9fbb3 100644 --- a/Duplicati/Library/Backend/AlternativeFTP/AlternativeFTPBackend.cs +++ b/Duplicati/Library/Backend/AlternativeFTP/AlternativeFTPBackend.cs @@ -27,7 +27,7 @@ using System.Security.Authentication; using Duplicati.Library.Interface; using Uri = System.Uri; using CoreUtility = Duplicati.Library.Utility.Utility; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.Library.Backend.AlternativeFTP { @@ -148,7 +148,7 @@ namespace Duplicati.Library.Backend.AlternativeFTP _userInfo.Domain = ""; _url = u.SetScheme("ftp").SetQuery(null).SetCredentials(null, null).ToString(); - _url = IO.Util.AppendDirSeparator(_url, "/"); + _url = Common.IO.Util.AppendDirSeparator(_url, "/"); _listVerify = !CoreUtility.ParseBoolOption(options, "disable-upload-verify"); // Process the aftp-data-connection-type option diff --git a/Duplicati/Library/Backend/AlternativeFTP/Duplicati.Library.Backend.AlternativeFTP.csproj b/Duplicati/Library/Backend/AlternativeFTP/Duplicati.Library.Backend.AlternativeFTP.csproj index fbf41f3ff..5e6b22f57 100644 --- a/Duplicati/Library/Backend/AlternativeFTP/Duplicati.Library.Backend.AlternativeFTP.csproj +++ b/Duplicati/Library/Backend/AlternativeFTP/Duplicati.Library.Backend.AlternativeFTP.csproj @@ -74,7 +74,7 @@ {D63E53E4-A458-4C2F-914D-92F715F58ACF} - Duplicati.Library.IO + Duplicati.Library.Common diff --git a/Duplicati/Library/Backend/AmazonCloudDrive/AmzCD.cs b/Duplicati/Library/Backend/AmazonCloudDrive/AmzCD.cs index 93de36b9f..27245c1e0 100644 --- a/Duplicati/Library/Backend/AmazonCloudDrive/AmzCD.cs +++ b/Duplicati/Library/Backend/AmazonCloudDrive/AmzCD.cs @@ -21,7 +21,7 @@ using Duplicati.Library.Interface; using Newtonsoft.Json; using System.IO; using System.Net; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.Library.Backend.AmazonCloudDrive { @@ -155,7 +155,7 @@ namespace Duplicati.Library.Backend.AmazonCloudDrive System.Threading.Thread.Sleep(wait); } - private string CacheFilePath { get { return SystemIO.IO_OS(Utility.Utility.IsClientWindows).PathCombine(Utility.TempFolder.SystemTempPath, string.Format(CACHE_FILE_NAME_TEMPLATE, m_userid)); } } + private string CacheFilePath { get { return SystemIO.IO_OS.PathCombine(Utility.TempFolder.SystemTempPath, string.Format(CACHE_FILE_NAME_TEMPLATE, m_userid)); } } private void RefreshMetadataAndContentUrl() { diff --git a/Duplicati/Library/Backend/AmazonCloudDrive/Duplicati.Library.Backend.AmazonCloudDrive.csproj b/Duplicati/Library/Backend/AmazonCloudDrive/Duplicati.Library.Backend.AmazonCloudDrive.csproj index 805de12ae..55628374b 100644 --- a/Duplicati/Library/Backend/AmazonCloudDrive/Duplicati.Library.Backend.AmazonCloudDrive.csproj +++ b/Duplicati/Library/Backend/AmazonCloudDrive/Duplicati.Library.Backend.AmazonCloudDrive.csproj @@ -60,7 +60,7 @@ {D63E53E4-A458-4C2F-914D-92F715F58ACF} - Duplicati.Library.IO + Duplicati.Library.Common diff --git a/Duplicati/Library/Backend/AzureBlob/AzureBlobWrapper.cs b/Duplicati/Library/Backend/AzureBlob/AzureBlobWrapper.cs index 7e7f74501..590caa9cd 100644 --- a/Duplicati/Library/Backend/AzureBlob/AzureBlobWrapper.cs +++ b/Duplicati/Library/Backend/AzureBlob/AzureBlobWrapper.cs @@ -21,7 +21,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; using Duplicati.Library.Interface; using Duplicati.Library.Utility; using Microsoft.WindowsAzure.Storage; diff --git a/Duplicati/Library/Backend/AzureBlob/Duplicati.Library.Backend.AzureBlob.csproj b/Duplicati/Library/Backend/AzureBlob/Duplicati.Library.Backend.AzureBlob.csproj index 74abcb7f4..02f18ceb9 100644 --- a/Duplicati/Library/Backend/AzureBlob/Duplicati.Library.Backend.AzureBlob.csproj +++ b/Duplicati/Library/Backend/AzureBlob/Duplicati.Library.Backend.AzureBlob.csproj @@ -81,7 +81,7 @@ {D63E53E4-A458-4C2F-914D-92F715F58ACF} - Duplicati.Library.IO + Duplicati.Library.Common diff --git a/Duplicati/Library/Backend/Backblaze/B2.cs b/Duplicati/Library/Backend/Backblaze/B2.cs index 593aac30a..b286fde1d 100644 --- a/Duplicati/Library/Backend/Backblaze/B2.cs +++ b/Duplicati/Library/Backend/Backblaze/B2.cs @@ -19,7 +19,7 @@ using System.Linq; using System.Collections.Generic; using Duplicati.Library.Utility; using Duplicati.Library.Interface; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; using Newtonsoft.Json; using System.Net; diff --git a/Duplicati/Library/Backend/Backblaze/Duplicati.Library.Backend.Backblaze.csproj b/Duplicati/Library/Backend/Backblaze/Duplicati.Library.Backend.Backblaze.csproj index b8f1945a5..300bfb9da 100644 --- a/Duplicati/Library/Backend/Backblaze/Duplicati.Library.Backend.Backblaze.csproj +++ b/Duplicati/Library/Backend/Backblaze/Duplicati.Library.Backend.Backblaze.csproj @@ -61,7 +61,7 @@ {D63E53E4-A458-4C2F-914D-92F715F58ACF} - Duplicati.Library.IO + Duplicati.Library.Common diff --git a/Duplicati/Library/Backend/Box/BoxBackend.cs b/Duplicati/Library/Backend/Box/BoxBackend.cs index 4d5fdbf19..9f2b828fc 100644 --- a/Duplicati/Library/Backend/Box/BoxBackend.cs +++ b/Duplicati/Library/Backend/Box/BoxBackend.cs @@ -17,7 +17,7 @@ using System; using System.Linq; using Duplicati.Library.Interface; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; using System.Collections.Generic; using Newtonsoft.Json; using System.Net; diff --git a/Duplicati/Library/Backend/Box/Duplicati.Library.Backend.Box.csproj b/Duplicati/Library/Backend/Box/Duplicati.Library.Backend.Box.csproj index 36ebc3838..4c66b8ab8 100644 --- a/Duplicati/Library/Backend/Box/Duplicati.Library.Backend.Box.csproj +++ b/Duplicati/Library/Backend/Box/Duplicati.Library.Backend.Box.csproj @@ -64,7 +64,7 @@ {D63E53E4-A458-4C2F-914D-92F715F58ACF} - Duplicati.Library.IO + Duplicati.Library.Common diff --git a/Duplicati/Library/Backend/CloudFiles/CloudFiles.cs b/Duplicati/Library/Backend/CloudFiles/CloudFiles.cs index eba81377e..2fdd12738 100644 --- a/Duplicati/Library/Backend/CloudFiles/CloudFiles.cs +++ b/Duplicati/Library/Backend/CloudFiles/CloudFiles.cs @@ -23,7 +23,7 @@ using System.Linq; using System.Text; using System.Net; using Duplicati.Library.Interface; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.Library.Backend { diff --git a/Duplicati/Library/Backend/CloudFiles/Duplicati.Library.Backend.CloudFiles.csproj b/Duplicati/Library/Backend/CloudFiles/Duplicati.Library.Backend.CloudFiles.csproj index 9a785568a..6572b397e 100644 --- a/Duplicati/Library/Backend/CloudFiles/Duplicati.Library.Backend.CloudFiles.csproj +++ b/Duplicati/Library/Backend/CloudFiles/Duplicati.Library.Backend.CloudFiles.csproj @@ -59,7 +59,7 @@ {D63E53E4-A458-4C2F-914D-92F715F58ACF} - Duplicati.Library.IO + Duplicati.Library.Common diff --git a/Duplicati/Library/Backend/Dropbox/Dropbox.cs b/Duplicati/Library/Backend/Dropbox/Dropbox.cs index 9a4e055de..e31c4f522 100644 --- a/Duplicati/Library/Backend/Dropbox/Dropbox.cs +++ b/Duplicati/Library/Backend/Dropbox/Dropbox.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.IO; using Duplicati.Library.Interface; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.Library.Backend { diff --git a/Duplicati/Library/Backend/Dropbox/Duplicati.Library.Backend.Dropbox.csproj b/Duplicati/Library/Backend/Dropbox/Duplicati.Library.Backend.Dropbox.csproj index 8fe7a70be..7fdbb9670 100644 --- a/Duplicati/Library/Backend/Dropbox/Duplicati.Library.Backend.Dropbox.csproj +++ b/Duplicati/Library/Backend/Dropbox/Duplicati.Library.Backend.Dropbox.csproj @@ -63,7 +63,7 @@ {D63E53E4-A458-4C2F-914D-92F715F58ACF} - Duplicati.Library.IO + Duplicati.Library.Common diff --git a/Duplicati/Library/Backend/FTP/Duplicati.Library.Backend.FTP.csproj b/Duplicati/Library/Backend/FTP/Duplicati.Library.Backend.FTP.csproj index abc65f7f7..dc794ebda 100644 --- a/Duplicati/Library/Backend/FTP/Duplicati.Library.Backend.FTP.csproj +++ b/Duplicati/Library/Backend/FTP/Duplicati.Library.Backend.FTP.csproj @@ -63,7 +63,7 @@ {D63E53E4-A458-4C2F-914D-92F715F58ACF} - Duplicati.Library.IO + Duplicati.Library.Common diff --git a/Duplicati/Library/Backend/FTP/FTPBackend.cs b/Duplicati/Library/Backend/FTP/FTPBackend.cs index 0182fdb2b..84b43f19a 100644 --- a/Duplicati/Library/Backend/FTP/FTPBackend.cs +++ b/Duplicati/Library/Backend/FTP/FTPBackend.cs @@ -22,7 +22,7 @@ using System.Collections.Generic; using System.Text.RegularExpressions; using Duplicati.Library.Interface; using System.Linq; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.Library.Backend { diff --git a/Duplicati/Library/Backend/File/Duplicati.Library.Backend.File.csproj b/Duplicati/Library/Backend/File/Duplicati.Library.Backend.File.csproj index 6ddefc88c..79ec333b5 100644 --- a/Duplicati/Library/Backend/File/Duplicati.Library.Backend.File.csproj +++ b/Duplicati/Library/Backend/File/Duplicati.Library.Backend.File.csproj @@ -59,7 +59,7 @@ {D63E53E4-A458-4C2F-914D-92F715F58ACF} - Duplicati.Library.IO + Duplicati.Library.Common diff --git a/Duplicati/Library/Backend/File/FileBackend.cs b/Duplicati/Library/Backend/File/FileBackend.cs index 93eadccda..b61b68fb4 100644 --- a/Duplicati/Library/Backend/File/FileBackend.cs +++ b/Duplicati/Library/Backend/File/FileBackend.cs @@ -21,7 +21,7 @@ using System; using System.Collections.Generic; using System.Runtime.InteropServices; using Duplicati.Library.Interface; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.Library.Backend { @@ -41,7 +41,7 @@ namespace Duplicati.Library.Backend private readonly byte[] m_copybuffer = new byte[Utility.Utility.DEFAULT_BUFFER_SIZE]; - private static ISystemIO systemIO = SystemIO.IO_OS(Utility.Utility.IsClientWindows); + private static ISystemIO systemIO = SystemIO.IO_OS; public File() { diff --git a/Duplicati/Library/Backend/GoogleServices/Duplicati.Library.Backend.GoogleServices.csproj b/Duplicati/Library/Backend/GoogleServices/Duplicati.Library.Backend.GoogleServices.csproj index d5371d2ab..2593539ed 100644 --- a/Duplicati/Library/Backend/GoogleServices/Duplicati.Library.Backend.GoogleServices.csproj +++ b/Duplicati/Library/Backend/GoogleServices/Duplicati.Library.Backend.GoogleServices.csproj @@ -63,7 +63,7 @@ {D63E53E4-A458-4C2F-914D-92F715F58ACF} - Duplicati.Library.IO + Duplicati.Library.Common diff --git a/Duplicati/Library/Backend/GoogleServices/GoogleCloudStorage.cs b/Duplicati/Library/Backend/GoogleServices/GoogleCloudStorage.cs index e92cde381..59b87a924 100644 --- a/Duplicati/Library/Backend/GoogleServices/GoogleCloudStorage.cs +++ b/Duplicati/Library/Backend/GoogleServices/GoogleCloudStorage.cs @@ -24,7 +24,7 @@ using Newtonsoft.Json; using Duplicati.Library.Backend.GoogleServices; using Duplicati.Library.Interface; using Duplicati.Library.Utility; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.Library.Backend.GoogleCloudStorage { diff --git a/Duplicati/Library/Backend/GoogleServices/GoogleDrive.cs b/Duplicati/Library/Backend/GoogleServices/GoogleDrive.cs index 96daa158b..bca240c3f 100644 --- a/Duplicati/Library/Backend/GoogleServices/GoogleDrive.cs +++ b/Duplicati/Library/Backend/GoogleServices/GoogleDrive.cs @@ -25,7 +25,7 @@ using Newtonsoft.Json; using Duplicati.Library.Backend.GoogleServices; using Duplicati.Library.Interface; using Duplicati.Library.Utility; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.Library.Backend.GoogleDrive { diff --git a/Duplicati/Library/Backend/Jottacloud/Duplicati.Library.Backend.Jottacloud.csproj b/Duplicati/Library/Backend/Jottacloud/Duplicati.Library.Backend.Jottacloud.csproj index d6a6c4159..33be3c12b 100644 --- a/Duplicati/Library/Backend/Jottacloud/Duplicati.Library.Backend.Jottacloud.csproj +++ b/Duplicati/Library/Backend/Jottacloud/Duplicati.Library.Backend.Jottacloud.csproj @@ -63,7 +63,7 @@ {D63E53E4-A458-4C2F-914D-92F715F58ACF} - Duplicati.Library.IO + Duplicati.Library.Common diff --git a/Duplicati/Library/Backend/Jottacloud/Jottacloud.cs b/Duplicati/Library/Backend/Jottacloud/Jottacloud.cs index be1cc2bf3..472043acf 100644 --- a/Duplicati/Library/Backend/Jottacloud/Jottacloud.cs +++ b/Duplicati/Library/Backend/Jottacloud/Jottacloud.cs @@ -20,7 +20,7 @@ using System; using System.Collections.Generic; using Duplicati.Library.Interface; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.Library.Backend { diff --git a/Duplicati/Library/Backend/Mega/Duplicati.Library.Backend.Mega.csproj b/Duplicati/Library/Backend/Mega/Duplicati.Library.Backend.Mega.csproj index 3247ba94a..ccae2aeb9 100644 --- a/Duplicati/Library/Backend/Mega/Duplicati.Library.Backend.Mega.csproj +++ b/Duplicati/Library/Backend/Mega/Duplicati.Library.Backend.Mega.csproj @@ -61,7 +61,7 @@ {D63E53E4-A458-4C2F-914D-92F715F58ACF} - Duplicati.Library.IO + Duplicati.Library.Common diff --git a/Duplicati/Library/Backend/Mega/MegaBackend.cs b/Duplicati/Library/Backend/Mega/MegaBackend.cs index 5e7358d40..2a5859922 100644 --- a/Duplicati/Library/Backend/Mega/MegaBackend.cs +++ b/Duplicati/Library/Backend/Mega/MegaBackend.cs @@ -19,7 +19,7 @@ using System.Linq; using System.Collections.Generic; using Duplicati.Library.Interface; using CG.Web.MegaApiClient; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.Library.Backend.Mega { diff --git a/Duplicati/Library/Backend/OneDrive/Duplicati.Library.Backend.OneDrive.csproj b/Duplicati/Library/Backend/OneDrive/Duplicati.Library.Backend.OneDrive.csproj index 5c36586ca..fcea5a894 100644 --- a/Duplicati/Library/Backend/OneDrive/Duplicati.Library.Backend.OneDrive.csproj +++ b/Duplicati/Library/Backend/OneDrive/Duplicati.Library.Backend.OneDrive.csproj @@ -83,7 +83,7 @@ {D63E53E4-A458-4C2F-914D-92F715F58ACF} - Duplicati.Library.IO + Duplicati.Library.Common diff --git a/Duplicati/Library/Backend/OneDrive/MicrosoftGraphBackend.cs b/Duplicati/Library/Backend/OneDrive/MicrosoftGraphBackend.cs index 954b4872b..d3d80836a 100644 --- a/Duplicati/Library/Backend/OneDrive/MicrosoftGraphBackend.cs +++ b/Duplicati/Library/Backend/OneDrive/MicrosoftGraphBackend.cs @@ -10,7 +10,7 @@ using System.Threading; using Duplicati.Library.Backend.MicrosoftGraph; using Duplicati.Library.Interface; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; using Duplicati.Library.Utility; using Newtonsoft.Json; diff --git a/Duplicati/Library/Backend/OneDrive/OneDrive.cs b/Duplicati/Library/Backend/OneDrive/OneDrive.cs index a1cd14969..a355db687 100644 --- a/Duplicati/Library/Backend/OneDrive/OneDrive.cs +++ b/Duplicati/Library/Backend/OneDrive/OneDrive.cs @@ -4,7 +4,7 @@ using System.Text; using System.Text.RegularExpressions; using System.Net; using Duplicati.Library.Interface; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.Library.Backend { diff --git a/Duplicati/Library/Backend/OpenStack/Duplicati.Library.Backend.OpenStack.csproj b/Duplicati/Library/Backend/OpenStack/Duplicati.Library.Backend.OpenStack.csproj index 7a29c14b8..9dd73469f 100644 --- a/Duplicati/Library/Backend/OpenStack/Duplicati.Library.Backend.OpenStack.csproj +++ b/Duplicati/Library/Backend/OpenStack/Duplicati.Library.Backend.OpenStack.csproj @@ -61,7 +61,7 @@ {D63E53E4-A458-4C2F-914D-92F715F58ACF} - Duplicati.Library.IO + Duplicati.Library.Common diff --git a/Duplicati/Library/Backend/OpenStack/OpenStackStorage.cs b/Duplicati/Library/Backend/OpenStack/OpenStackStorage.cs index 7217ed41a..05e1a03d1 100644 --- a/Duplicati/Library/Backend/OpenStack/OpenStackStorage.cs +++ b/Duplicati/Library/Backend/OpenStack/OpenStackStorage.cs @@ -25,7 +25,7 @@ using Newtonsoft.Json.Converters; using Duplicati.Library.Strings; using System.Net; using System.Text; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.Library.Backend.OpenStack { diff --git a/Duplicati/Library/Backend/Rclone/Duplicati.Library.Backend.Rclone.csproj b/Duplicati/Library/Backend/Rclone/Duplicati.Library.Backend.Rclone.csproj index dfc3d2e2e..e4a642064 100644 --- a/Duplicati/Library/Backend/Rclone/Duplicati.Library.Backend.Rclone.csproj +++ b/Duplicati/Library/Backend/Rclone/Duplicati.Library.Backend.Rclone.csproj @@ -56,7 +56,7 @@ {D63E53E4-A458-4C2F-914D-92F715F58ACF} - Duplicati.Library.IO + Duplicati.Library.Common diff --git a/Duplicati/Library/Backend/Rclone/Rclone.cs b/Duplicati/Library/Backend/Rclone/Rclone.cs index 9f73b324f..a7c344caa 100644 --- a/Duplicati/Library/Backend/Rclone/Rclone.cs +++ b/Duplicati/Library/Backend/Rclone/Rclone.cs @@ -27,7 +27,7 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System.Globalization; using System.IO; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.Library.Backend { diff --git a/Duplicati/Library/Backend/S3/Duplicati.Library.Backend.S3.csproj b/Duplicati/Library/Backend/S3/Duplicati.Library.Backend.S3.csproj index f236681b0..646350f5b 100644 --- a/Duplicati/Library/Backend/S3/Duplicati.Library.Backend.S3.csproj +++ b/Duplicati/Library/Backend/S3/Duplicati.Library.Backend.S3.csproj @@ -74,7 +74,7 @@ {D63E53E4-A458-4C2F-914D-92F715F58ACF} - Duplicati.Library.IO + Duplicati.Library.Common diff --git a/Duplicati/Library/Backend/S3/S3Backend.cs b/Duplicati/Library/Backend/S3/S3Backend.cs index 8776f95d8..a0d7be2d8 100644 --- a/Duplicati/Library/Backend/S3/S3Backend.cs +++ b/Duplicati/Library/Backend/S3/S3Backend.cs @@ -23,7 +23,7 @@ using System.Collections.Generic; using System.Text; using System.Text.RegularExpressions; using Duplicati.Library.Interface; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.Library.Backend { diff --git a/Duplicati/Library/Backend/S3/S3Wrapper.cs b/Duplicati/Library/Backend/S3/S3Wrapper.cs index 5288dfbd4..fd577b5fb 100644 --- a/Duplicati/Library/Backend/S3/S3Wrapper.cs +++ b/Duplicati/Library/Backend/S3/S3Wrapper.cs @@ -169,7 +169,7 @@ namespace Duplicati.Library.Backend { if (alreadyReturned.Add(obj.Key)) { - yield return new IO.FileEntry( + yield return new Common.IO.FileEntry( obj.Key, obj.Size, obj.LastModified, diff --git a/Duplicati/Library/Backend/SSHv2/Duplicati.Library.Backend.SSHv2.csproj b/Duplicati/Library/Backend/SSHv2/Duplicati.Library.Backend.SSHv2.csproj index da2e9242f..9cc164115 100644 --- a/Duplicati/Library/Backend/SSHv2/Duplicati.Library.Backend.SSHv2.csproj +++ b/Duplicati/Library/Backend/SSHv2/Duplicati.Library.Backend.SSHv2.csproj @@ -64,7 +64,7 @@ {D63E53E4-A458-4C2F-914D-92F715F58ACF} - Duplicati.Library.IO + Duplicati.Library.Common diff --git a/Duplicati/Library/Backend/SSHv2/SSHv2Backend.cs b/Duplicati/Library/Backend/SSHv2/SSHv2Backend.cs index 4b7e8d791..af0801f53 100644 --- a/Duplicati/Library/Backend/SSHv2/SSHv2Backend.cs +++ b/Duplicati/Library/Backend/SSHv2/SSHv2Backend.cs @@ -22,7 +22,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using Duplicati.Library.Interface; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; using Renci.SshNet; using Renci.SshNet.Common; diff --git a/Duplicati/Library/Backend/SharePoint/Duplicati.Library.Backend.SharePoint.csproj b/Duplicati/Library/Backend/SharePoint/Duplicati.Library.Backend.SharePoint.csproj index 534f08e56..ea0b38118 100644 --- a/Duplicati/Library/Backend/SharePoint/Duplicati.Library.Backend.SharePoint.csproj +++ b/Duplicati/Library/Backend/SharePoint/Duplicati.Library.Backend.SharePoint.csproj @@ -78,7 +78,7 @@ {D63E53E4-A458-4C2F-914D-92F715F58ACF} - Duplicati.Library.IO + Duplicati.Library.Common diff --git a/Duplicati/Library/Backend/SharePoint/SharePointBackend.cs b/Duplicati/Library/Backend/SharePoint/SharePointBackend.cs index 5bd913d92..5c6337fa5 100644 --- a/Duplicati/Library/Backend/SharePoint/SharePointBackend.cs +++ b/Duplicati/Library/Backend/SharePoint/SharePointBackend.cs @@ -29,7 +29,7 @@ using Duplicati.Library.Interface; using SP = Microsoft.SharePoint.Client; using Microsoft.SharePoint.Client; // Plain 'using' for extension methods -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.Library.Backend { diff --git a/Duplicati/Library/Backend/Sia/Duplicati.Library.Backend.Sia.csproj b/Duplicati/Library/Backend/Sia/Duplicati.Library.Backend.Sia.csproj index d632c39a7..cde63c034 100644 --- a/Duplicati/Library/Backend/Sia/Duplicati.Library.Backend.Sia.csproj +++ b/Duplicati/Library/Backend/Sia/Duplicati.Library.Backend.Sia.csproj @@ -60,7 +60,7 @@ {D63E53E4-A458-4C2F-914D-92F715F58ACF} - Duplicati.Library.IO + Duplicati.Library.Common diff --git a/Duplicati/Library/Backend/Sia/Sia.cs b/Duplicati/Library/Backend/Sia/Sia.cs index c23892317..cac4ab2f4 100644 --- a/Duplicati/Library/Backend/Sia/Sia.cs +++ b/Duplicati/Library/Backend/Sia/Sia.cs @@ -6,7 +6,7 @@ using System.Net; using Duplicati.Library.Interface; using Duplicati.Library.Utility; using Newtonsoft.Json; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.Library.Backend.Sia { diff --git a/Duplicati/Library/Backend/TahoeLAFS/Duplicati.Library.Backend.TahoeLAFS.csproj b/Duplicati/Library/Backend/TahoeLAFS/Duplicati.Library.Backend.TahoeLAFS.csproj index ccaceef36..7889305f0 100644 --- a/Duplicati/Library/Backend/TahoeLAFS/Duplicati.Library.Backend.TahoeLAFS.csproj +++ b/Duplicati/Library/Backend/TahoeLAFS/Duplicati.Library.Backend.TahoeLAFS.csproj @@ -70,7 +70,7 @@ {D63E53E4-A458-4C2F-914D-92F715F58ACF} - Duplicati.Library.IO + Duplicati.Library.Common diff --git a/Duplicati/Library/Backend/TahoeLAFS/TahoeBackend.cs b/Duplicati/Library/Backend/TahoeLAFS/TahoeBackend.cs index 480c254aa..f253a2686 100644 --- a/Duplicati/Library/Backend/TahoeLAFS/TahoeBackend.cs +++ b/Duplicati/Library/Backend/TahoeLAFS/TahoeBackend.cs @@ -24,7 +24,7 @@ using Duplicati.Library.Interface; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System.Linq; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.Library.Backend { diff --git a/Duplicati/Library/Backend/WEBDAV/Duplicati.Library.Backend.WEBDAV.csproj b/Duplicati/Library/Backend/WEBDAV/Duplicati.Library.Backend.WEBDAV.csproj index 41c556bbc..35a22eeb1 100644 --- a/Duplicati/Library/Backend/WEBDAV/Duplicati.Library.Backend.WEBDAV.csproj +++ b/Duplicati/Library/Backend/WEBDAV/Duplicati.Library.Backend.WEBDAV.csproj @@ -63,7 +63,7 @@ {D63E53E4-A458-4C2F-914D-92F715F58ACF} - Duplicati.Library.IO + Duplicati.Library.Common diff --git a/Duplicati/Library/Backend/WEBDAV/WEBDAV.cs b/Duplicati/Library/Backend/WEBDAV/WEBDAV.cs index b7afcc79e..8d175cc4b 100644 --- a/Duplicati/Library/Backend/WEBDAV/WEBDAV.cs +++ b/Duplicati/Library/Backend/WEBDAV/WEBDAV.cs @@ -21,7 +21,7 @@ using System; using System.Collections.Generic; using System.Text; using Duplicati.Library.Interface; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.Library.Backend { diff --git a/Duplicati/Library/Compression/Duplicati.Library.Compression.csproj b/Duplicati/Library/Compression/Duplicati.Library.Compression.csproj index 3629e000e..4c961097a 100644 --- a/Duplicati/Library/Compression/Duplicati.Library.Compression.csproj +++ b/Duplicati/Library/Compression/Duplicati.Library.Compression.csproj @@ -72,7 +72,7 @@ {D63E53E4-A458-4C2F-914D-92F715F58ACF} - Duplicati.Library.IO + Duplicati.Library.Common diff --git a/Duplicati/Library/Compression/FileArchiveDirectory.cs b/Duplicati/Library/Compression/FileArchiveDirectory.cs index 17ff48576..da28d545a 100644 --- a/Duplicati/Library/Compression/FileArchiveDirectory.cs +++ b/Duplicati/Library/Compression/FileArchiveDirectory.cs @@ -24,7 +24,7 @@ using System; using System.Collections.Generic; using System.Text; using Duplicati.Library.Interface; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.Library.Compression { diff --git a/Duplicati/Library/IO/DefineDosDevice.cs b/Duplicati/Library/IO/DefineDosDevice.cs deleted file mode 100644 index fcd787c52..000000000 --- a/Duplicati/Library/IO/DefineDosDevice.cs +++ /dev/null @@ -1,167 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.IO; - -namespace Duplicati.Library.IO -{ - /// - /// Implements a convenient wrapping for mapping a path to a drive letter - /// - public class DefineDosDevice : IDisposable - { - /// - /// Encapsulation of Win32 calls - /// - private static class Win32API - { - /// - /// Flags that can be used with DefineDosDevice - /// - [Flags] - public enum DDD_Flags : uint - { - /// - /// Uses the targetpath string as is. Otherwise, it is converted from an MS-DOS path to a path. - /// - DDD_RAW_TARGET_PATH = 0x1, - /// - /// Removes the specified definition for the specified device. To determine which definition to remove, the function walks the list of mappings for the device, looking for a match of targetpath against a prefix of each mapping associated with this device. The first mapping that matches is the one removed, and then the function returns. - /// If targetpath is NULL or a pointer to a NULL string, the function will remove the first mapping associated with the device and pop the most recent one pushed. If there is nothing left to pop, the device name will be removed. - /// If this value is not specified, the string pointed to by the targetpath parameter will become the new mapping for this device. - /// - DDD_REMOVE_DEFINITION = 0x2, - /// - /// If this value is specified along with DDD_REMOVE_DEFINITION, the function will use an exact match to determine which mapping to remove. Use this value to ensure that you do not delete something that you did not define. - /// - DDD_EXACT_MATCH_ON_REMOVE = 0x4, - /// - /// Do not broadcast the WM_SETTINGCHANGE message. By default, this message is broadcast to notify the shell and applications of the change. - /// - DDD_NO_BROADCAST_SYSTEM = 0x8 - } - - /// - /// Defines, redefines, or deletes MS-DOS device names. - /// - /// The controllable aspects of the DefineDosDevice function - /// A pointer to an MS-DOS device name string specifying the device the function is defining, redefining, or deleting. The device name string must not have a colon as the last character, unless a drive letter is being defined, redefined, or deleted. For example, drive C would be the string "C:". In no case is a trailing backslash ("\") allowed. - /// A pointer to a path string that will implement this device. The string is an MS-DOS path string unless the DDD_RAW_TARGET_PATH flag is specified, in which case this string is a path string. - /// True on success, false otherwise - [System.Runtime.InteropServices.DllImport("kernel32", CharSet = System.Runtime.InteropServices.CharSet.Auto, SetLastError = true)] - public static extern bool DefineDosDevice(DDD_Flags flags, string devicename, string targetpath); - } - - /// - /// The drive the path is mapped to - /// - private string m_drive; - /// - /// The path that is mapped to the drive - /// - private readonly string m_targetPath; - /// - /// A value indicating if the shell should be notified of changes - /// - private readonly bool m_shellBroadcast; - - /// - /// Gets the drive that this mapping represents - /// - public string Drive { get { return m_drive; } } - - /// - /// Gets the path that this mapping represents - /// - public string Targetpath { get { return m_targetPath; } } - - /// - /// Creates a new mapping, using default settings - /// - /// The path to map - public DefineDosDevice(string path) - : this(path, null, false) - { - } - - /// - /// Creates a new mapping - /// - /// The path to map - /// The drive to map to, use null to get a free drive letter - /// True to notify the shell of the change, false otherwise - public DefineDosDevice(string path, string drive, bool notifyShell) - { - if (string.IsNullOrEmpty(drive)) - { - List drives = new List("DEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray()); - foreach (DriveInfo di in DriveInfo.GetDrives()) - { - if ((di.RootDirectory.FullName.Length == 2 && di.RootDirectory.FullName[1] == ':') || ((di.RootDirectory.FullName.Length == 3 && di.RootDirectory.FullName.EndsWith(":\\", StringComparison.Ordinal)))) - { - int i = drives.IndexOf(di.RootDirectory.FullName[0]); - if (i >= 0) - drives.RemoveAt(i); - } - } - - if (drives.Count == 0) - throw new IOException("No drive letters available"); - drive = drives[0].ToString() + ':'; - } - - while (drive.EndsWith("\\", StringComparison.Ordinal)) - drive = drive.Substring(0, drive.Length - 1); - - if (!drive.EndsWith(":", StringComparison.Ordinal)) - throw new ArgumentException("The drive specification must end with a colon.", nameof(drive)); - - Win32API.DDD_Flags flags = 0; - if (!notifyShell) - flags |= Win32API.DDD_Flags.DDD_NO_BROADCAST_SYSTEM; - - if (!Win32API.DefineDosDevice(flags, drive, path)) - throw new System.ComponentModel.Win32Exception(); - - m_drive = drive; - m_targetPath = path; - m_shellBroadcast = notifyShell; - } - - /// - /// Disposes all resources held - /// - public void Dispose() - { - Dispose(true); - } - - /// - /// Disposes all resources - /// - /// True if called from Disposing, false otherwise - protected void Dispose(bool disposing) - { - if (m_drive != null) - { - Win32API.DDD_Flags flags = Win32API.DDD_Flags.DDD_REMOVE_DEFINITION | Win32API.DDD_Flags.DDD_EXACT_MATCH_ON_REMOVE; - if (m_shellBroadcast) - flags |= Win32API.DDD_Flags.DDD_NO_BROADCAST_SYSTEM; - Win32API.DefineDosDevice(flags, m_drive, m_targetPath); - m_drive = null; - } - - if (disposing) - GC.SuppressFinalize(this); - } - - /// - /// Destroys the object and releases all held resources - /// - ~DefineDosDevice() - { - Dispose(false); - } - - } -} diff --git a/Duplicati/Library/IO/Duplicati.Library.Common.csproj b/Duplicati/Library/IO/Duplicati.Library.Common.csproj new file mode 100644 index 000000000..0b8bd0289 --- /dev/null +++ b/Duplicati/Library/IO/Duplicati.Library.Common.csproj @@ -0,0 +1,101 @@ + + + + Debug + AnyCPU + {D63E53E4-A458-4C2F-914D-92F715F58ACF} + Library + Properties + Duplicati.Library.IO + Duplicati.Library.IO + 512 + Duplicati.snk + + + 3.5 + + v4.5 + + false + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + false + + + + + ..\..\..\thirdparty\UnixSupport\UnixSupport.dll + + + + + + + + ..\..\..\packages\AlphaVSS.1.4.0\lib\net45\AlphaVSS.Common.dll + + + ..\..\..\packages\AlphaFS.2.1.3\lib\net45\AlphaFS.dll + + + ..\..\..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll + + + + + + + + + + + + + + + + + + + + + + + + + {D10A5FC0-11B4-4E70-86AA-8AEA52BD9798} + Duplicati.Library.Logging + + + {C5899F45-B0FF-483C-9D38-24A9FCAAB237} + Duplicati.Library.Interface + + + + + + + + diff --git a/Duplicati/Library/IO/Duplicati.Library.IO.csproj b/Duplicati/Library/IO/Duplicati.Library.IO.csproj deleted file mode 100644 index a784ae16c..000000000 --- a/Duplicati/Library/IO/Duplicati.Library.IO.csproj +++ /dev/null @@ -1,96 +0,0 @@ - - - - Debug - AnyCPU - {D63E53E4-A458-4C2F-914D-92F715F58ACF} - Library - Properties - Duplicati.Library.IO - Duplicati.Library.IO - 512 - Duplicati.snk - - - 3.5 - - v4.5 - - false - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - false - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - false - - - - - ..\..\..\thirdparty\UnixSupport\UnixSupport.dll - - - - - - - - ..\..\..\packages\AlphaVSS.1.4.0\lib\net45\AlphaVSS.Common.dll - - - ..\..\..\packages\AlphaFS.2.1.3\lib\net45\AlphaFS.dll - - - ..\..\..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll - - - - - - - - - - - - - - - - - - - - - - - - {D10A5FC0-11B4-4E70-86AA-8AEA52BD9798} - Duplicati.Library.Logging - - - {C5899F45-B0FF-483C-9D38-24A9FCAAB237} - Duplicati.Library.Interface - - - - diff --git a/Duplicati/Library/IO/FileEntry.cs b/Duplicati/Library/IO/FileEntry.cs deleted file mode 100644 index aafeddf0f..000000000 --- a/Duplicati/Library/IO/FileEntry.cs +++ /dev/null @@ -1,130 +0,0 @@ -#region Disclaimer / License -// Copyright (C) 2015, The Duplicati Team -// http://www.duplicati.com, info@duplicati.com -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -// -#endregion -using System; -using Duplicati.Library.Interface; - -namespace Duplicati.Library.IO -{ - /// - /// The primary implementation of the file interface - /// - public class FileEntry : IFileEntry - { - private string m_name; - private DateTime m_lastAccess; - private DateTime m_lastModification; - private long m_size; - private bool m_isFolder; - - /// - /// Gets or sets the file or folder name - /// - public string Name - { - get { return m_name; } - set { m_name = value; } - } - - /// - /// Gets or sets the time the file or folder was last accessed - /// - public DateTime LastAccess - { - get { return m_lastAccess; } - set { m_lastAccess = value; } - } - - /// - /// Gets or sets the time the file or folder was last modified - /// - public DateTime LastModification - { - get { return m_lastModification; } - set { m_lastModification = value; } - } - - /// - /// Gets or sets the size of the file or folder - /// - public long Size - { - get { return m_size; } - set { m_size = value; } - } - - /// - /// Gets or sets a value indicating if the entry is a folder - /// - public bool IsFolder - { - get { return m_isFolder; } - set { m_isFolder = value; } - } - - /// - /// Helper function to initialize the instance to default values - /// - private FileEntry() - { - m_name = null; - m_lastAccess = new DateTime(); - m_lastModification = new DateTime(); - m_size = -1; - m_isFolder = false; - } - - /// - /// Constructs an entry using only the name. - /// The entry is assumed to be a file. - /// - /// The name of the file - public FileEntry(string filename) - : this() - { - m_name = filename; - } - - /// - /// Constructs an entry using only the name and size. - /// The entry is assumed to be a file. - /// - /// The name of the file - /// The size of the file - public FileEntry(string filename, long size) - : this(filename) - { - m_size = size; - } - - /// - /// Construcs an entry supplying all information - /// - /// The name of the file or folder - /// The size of the file or folder - /// The time the file or folder was last accessed - /// The time the file or folder was last modified - public FileEntry(string filename, long size, DateTime lastAccess, DateTime lastModified) - : this(filename, size) - { - m_lastModification = lastModified; - m_lastAccess = lastAccess; - } - } -} diff --git a/Duplicati/Library/IO/IO/DefineDosDevice.cs b/Duplicati/Library/IO/IO/DefineDosDevice.cs new file mode 100644 index 000000000..f6149bc04 --- /dev/null +++ b/Duplicati/Library/IO/IO/DefineDosDevice.cs @@ -0,0 +1,167 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.IO; + +namespace Duplicati.Library.Common.IO +{ + /// + /// Implements a convenient wrapping for mapping a path to a drive letter + /// + public class DefineDosDevice : IDisposable + { + /// + /// Encapsulation of Win32 calls + /// + private static class Win32API + { + /// + /// Flags that can be used with DefineDosDevice + /// + [Flags] + public enum DDD_Flags : uint + { + /// + /// Uses the targetpath string as is. Otherwise, it is converted from an MS-DOS path to a path. + /// + DDD_RAW_TARGET_PATH = 0x1, + /// + /// Removes the specified definition for the specified device. To determine which definition to remove, the function walks the list of mappings for the device, looking for a match of targetpath against a prefix of each mapping associated with this device. The first mapping that matches is the one removed, and then the function returns. + /// If targetpath is NULL or a pointer to a NULL string, the function will remove the first mapping associated with the device and pop the most recent one pushed. If there is nothing left to pop, the device name will be removed. + /// If this value is not specified, the string pointed to by the targetpath parameter will become the new mapping for this device. + /// + DDD_REMOVE_DEFINITION = 0x2, + /// + /// If this value is specified along with DDD_REMOVE_DEFINITION, the function will use an exact match to determine which mapping to remove. Use this value to ensure that you do not delete something that you did not define. + /// + DDD_EXACT_MATCH_ON_REMOVE = 0x4, + /// + /// Do not broadcast the WM_SETTINGCHANGE message. By default, this message is broadcast to notify the shell and applications of the change. + /// + DDD_NO_BROADCAST_SYSTEM = 0x8 + } + + /// + /// Defines, redefines, or deletes MS-DOS device names. + /// + /// The controllable aspects of the DefineDosDevice function + /// A pointer to an MS-DOS device name string specifying the device the function is defining, redefining, or deleting. The device name string must not have a colon as the last character, unless a drive letter is being defined, redefined, or deleted. For example, drive C would be the string "C:". In no case is a trailing backslash ("\") allowed. + /// A pointer to a path string that will implement this device. The string is an MS-DOS path string unless the DDD_RAW_TARGET_PATH flag is specified, in which case this string is a path string. + /// True on success, false otherwise + [System.Runtime.InteropServices.DllImport("kernel32", CharSet = System.Runtime.InteropServices.CharSet.Auto, SetLastError = true)] + public static extern bool DefineDosDevice(DDD_Flags flags, string devicename, string targetpath); + } + + /// + /// The drive the path is mapped to + /// + private string m_drive; + /// + /// The path that is mapped to the drive + /// + private readonly string m_targetPath; + /// + /// A value indicating if the shell should be notified of changes + /// + private readonly bool m_shellBroadcast; + + /// + /// Gets the drive that this mapping represents + /// + public string Drive { get { return m_drive; } } + + /// + /// Gets the path that this mapping represents + /// + public string Targetpath { get { return m_targetPath; } } + + /// + /// Creates a new mapping, using default settings + /// + /// The path to map + public DefineDosDevice(string path) + : this(path, null, false) + { + } + + /// + /// Creates a new mapping + /// + /// The path to map + /// The drive to map to, use null to get a free drive letter + /// True to notify the shell of the change, false otherwise + public DefineDosDevice(string path, string drive, bool notifyShell) + { + if (string.IsNullOrEmpty(drive)) + { + List drives = new List("DEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray()); + foreach (DriveInfo di in DriveInfo.GetDrives()) + { + if ((di.RootDirectory.FullName.Length == 2 && di.RootDirectory.FullName[1] == ':') || ((di.RootDirectory.FullName.Length == 3 && di.RootDirectory.FullName.EndsWith(":\\", StringComparison.Ordinal)))) + { + int i = drives.IndexOf(di.RootDirectory.FullName[0]); + if (i >= 0) + drives.RemoveAt(i); + } + } + + if (drives.Count == 0) + throw new IOException("No drive letters available"); + drive = drives[0].ToString() + ':'; + } + + while (drive.EndsWith("\\", StringComparison.Ordinal)) + drive = drive.Substring(0, drive.Length - 1); + + if (!drive.EndsWith(":", StringComparison.Ordinal)) + throw new ArgumentException("The drive specification must end with a colon.", nameof(drive)); + + Win32API.DDD_Flags flags = 0; + if (!notifyShell) + flags |= Win32API.DDD_Flags.DDD_NO_BROADCAST_SYSTEM; + + if (!Win32API.DefineDosDevice(flags, drive, path)) + throw new System.ComponentModel.Win32Exception(); + + m_drive = drive; + m_targetPath = path; + m_shellBroadcast = notifyShell; + } + + /// + /// Disposes all resources held + /// + public void Dispose() + { + Dispose(true); + } + + /// + /// Disposes all resources + /// + /// True if called from Disposing, false otherwise + protected void Dispose(bool disposing) + { + if (m_drive != null) + { + Win32API.DDD_Flags flags = Win32API.DDD_Flags.DDD_REMOVE_DEFINITION | Win32API.DDD_Flags.DDD_EXACT_MATCH_ON_REMOVE; + if (m_shellBroadcast) + flags |= Win32API.DDD_Flags.DDD_NO_BROADCAST_SYSTEM; + Win32API.DefineDosDevice(flags, m_drive, m_targetPath); + m_drive = null; + } + + if (disposing) + GC.SuppressFinalize(this); + } + + /// + /// Destroys the object and releases all held resources + /// + ~DefineDosDevice() + { + Dispose(false); + } + + } +} diff --git a/Duplicati/Library/IO/IO/FileEntry.cs b/Duplicati/Library/IO/IO/FileEntry.cs new file mode 100644 index 000000000..689163ba9 --- /dev/null +++ b/Duplicati/Library/IO/IO/FileEntry.cs @@ -0,0 +1,130 @@ +#region Disclaimer / License +// Copyright (C) 2015, The Duplicati Team +// http://www.duplicati.com, info@duplicati.com +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// +#endregion +using System; +using Duplicati.Library.Interface; + +namespace Duplicati.Library.Common.IO +{ + /// + /// The primary implementation of the file interface + /// + public class FileEntry : IFileEntry + { + private string m_name; + private DateTime m_lastAccess; + private DateTime m_lastModification; + private long m_size; + private bool m_isFolder; + + /// + /// Gets or sets the file or folder name + /// + public string Name + { + get { return m_name; } + set { m_name = value; } + } + + /// + /// Gets or sets the time the file or folder was last accessed + /// + public DateTime LastAccess + { + get { return m_lastAccess; } + set { m_lastAccess = value; } + } + + /// + /// Gets or sets the time the file or folder was last modified + /// + public DateTime LastModification + { + get { return m_lastModification; } + set { m_lastModification = value; } + } + + /// + /// Gets or sets the size of the file or folder + /// + public long Size + { + get { return m_size; } + set { m_size = value; } + } + + /// + /// Gets or sets a value indicating if the entry is a folder + /// + public bool IsFolder + { + get { return m_isFolder; } + set { m_isFolder = value; } + } + + /// + /// Helper function to initialize the instance to default values + /// + private FileEntry() + { + m_name = null; + m_lastAccess = new DateTime(); + m_lastModification = new DateTime(); + m_size = -1; + m_isFolder = false; + } + + /// + /// Constructs an entry using only the name. + /// The entry is assumed to be a file. + /// + /// The name of the file + public FileEntry(string filename) + : this() + { + m_name = filename; + } + + /// + /// Constructs an entry using only the name and size. + /// The entry is assumed to be a file. + /// + /// The name of the file + /// The size of the file + public FileEntry(string filename, long size) + : this(filename) + { + m_size = size; + } + + /// + /// Construcs an entry supplying all information + /// + /// The name of the file or folder + /// The size of the file or folder + /// The time the file or folder was last accessed + /// The time the file or folder was last modified + public FileEntry(string filename, long size, DateTime lastAccess, DateTime lastModified) + : this(filename, size) + { + m_lastModification = lastModified; + m_lastAccess = lastAccess; + } + } +} diff --git a/Duplicati/Library/IO/IO/ISystemIO.cs b/Duplicati/Library/IO/IO/ISystemIO.cs new file mode 100644 index 000000000..8fe034b19 --- /dev/null +++ b/Duplicati/Library/IO/IO/ISystemIO.cs @@ -0,0 +1,79 @@ +// Copyright (C) 2015, The Duplicati Team + +// http://www.duplicati.com, info@duplicati.com +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +using System; +using System.IO; +using System.Collections.Generic; +using Duplicati.Library.Interface; + +namespace Duplicati.Library.Common.IO +{ + /// + /// Interface for wrapping System.IO operations. + /// + public interface ISystemIO + { + IFileEntry DirectoryEntry(string path); + void DirectoryDelete(string path); + void DirectoryDelete(string path, bool recursive); + void DirectoryCreate(string path); + bool DirectoryExists(string path); + void DirectorySetLastWriteTimeUtc(string path, DateTime time); + void DirectorySetCreationTimeUtc(string path, DateTime time); + DateTime DirectoryGetLastWriteTimeUtc(string path); + DateTime DirectoryGetCreationTimeUtc(string path); + + + IFileEntry FileEntry(string path); + void FileMove(string source, string target); + void FileDelete(string path); + void FileCopy(string source, string target, bool overwrite); + void FileSetLastWriteTimeUtc(string path, DateTime time); + void FileSetCreationTimeUtc(string path, DateTime time); + DateTime FileGetLastWriteTimeUtc(string path); + DateTime FileGetCreationTimeUtc(string path); + bool FileExists(string path); + long FileLength(string path); + FileStream FileOpenRead(string path); + FileStream FileOpenWrite(string path); + FileStream FileOpenReadWrite(string path); + FileStream FileCreate(string path); + FileAttributes GetFileAttributes(string path); + void SetFileAttributes(string path, FileAttributes attributes); + void CreateSymlink(string symlinkfile, string target, bool asDir); + string GetSymlinkTarget(string path); + string PathGetDirectoryName(string path); + string PathGetFileName(string path); + string PathGetExtension(string path); + string PathChangeExtension(string path, string extension); + string PathCombine(params string[] paths); + string PathGetFullPath(string path); + string GetPathRoot(string path); + string[] GetDirectories(string path); + string[] GetFiles(string path); + string[] GetFiles(string path, string searchPattern); + DateTime GetCreationTimeUtc(string path); + DateTime GetLastWriteTimeUtc(string path); + IEnumerable EnumerateFileSystemEntries(string path); + IEnumerable EnumerateDirectories(string path); + + void SetMetadata(string path, Dictionary metdata, bool restorePermissions); + Dictionary GetMetadata(string path, bool isSymlink, bool followSymlink); + } + +} + diff --git a/Duplicati/Library/IO/IO/SystemIO.cs b/Duplicati/Library/IO/IO/SystemIO.cs new file mode 100644 index 000000000..0dc1a1d5b --- /dev/null +++ b/Duplicati/Library/IO/IO/SystemIO.cs @@ -0,0 +1,54 @@ +// Copyright (C) 2018, The Duplicati Team +// http://www.duplicati.com, info@duplicati.com +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +using System; +namespace Duplicati.Library.Common.IO +{ + public static class SystemIO + { + + /// + /// A cached lookup for windows methods for dealing with long filenames + /// + private static readonly ISystemIO _IO_WIN = new SystemIOWindows(); + + private static readonly ISystemIO _IO_SYS = new SystemIOLinux(); + + public static ISystemIO IO_WIN + { + get + { + return _IO_WIN; + } + } + + public static ISystemIO IO_SYS + { + get + { + return _IO_SYS; + } + } + + + public static ISystemIO IO_OS + { + get { + return Platform.IsClientWindows ? _IO_WIN : _IO_SYS; + } + } + } +} \ No newline at end of file diff --git a/Duplicati/Library/IO/IO/SystemIOLinux.cs b/Duplicati/Library/IO/IO/SystemIOLinux.cs new file mode 100644 index 000000000..fecdf5f5f --- /dev/null +++ b/Duplicati/Library/IO/IO/SystemIOLinux.cs @@ -0,0 +1,314 @@ +// Copyright (C) 2015, The Duplicati Team + +// http://www.duplicati.com, info@duplicati.com +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +using System; +using System.IO; +using System.Linq; +using System.Collections.Generic; +using Duplicati.Library.Interface; + +namespace Duplicati.Library.Common.IO +{ + public struct SystemIOLinux : ISystemIO + { + #region ISystemIO implementation + public void DirectoryDelete(string path) + { + Directory.Delete(NormalizePath(path)); + } + + public void DirectoryCreate(string path) + { + Directory.CreateDirectory(NormalizePath(path)); + } + + public bool DirectoryExists(string path) + { + return Directory.Exists(NormalizePath(path)); + } + + public void FileDelete(string path) + { + File.Delete(path); + } + + public void FileSetLastWriteTimeUtc(string path, DateTime time) + { + File.SetLastWriteTimeUtc(path, time); + } + + public void FileSetCreationTimeUtc(string path, DateTime time) + { + File.SetCreationTimeUtc(path, time); + } + + public DateTime FileGetLastWriteTimeUtc(string path) + { + return File.GetLastWriteTimeUtc(path); + } + + public DateTime FileGetCreationTimeUtc(string path) + { + return File.GetCreationTimeUtc(path); + } + + public bool FileExists(string path) + { + return File.Exists(path); + } + + public FileStream FileOpenRead(string path) + { + return File.OpenRead(path); + } + + public FileStream FileOpenWrite(string path) + { + return File.OpenWrite(path); + } + + public FileStream FileOpenReadWrite(string path) + { + return File.Open(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read); + } + + public FileStream FileCreate(string path) + { + return File.Create(path); + } + + public FileAttributes GetFileAttributes(string path) + { + return File.GetAttributes(NormalizePath(path)); + } + + public void SetFileAttributes(string path, FileAttributes attributes) + { + File.SetAttributes(path, attributes); + } + + public void CreateSymlink(string symlinkfile, string target, bool asDir) + { + UnixSupport.File.CreateSymlink(symlinkfile, target); + } + + public string GetSymlinkTarget(string path) + { + return UnixSupport.File.GetSymlinkTarget(NormalizePath(path)); + } + + public string PathGetDirectoryName(string path) + { + return Path.GetDirectoryName(NormalizePath(path)); + } + + public IEnumerable EnumerateFileSystemEntries(string path) + { + return Directory.EnumerateFileSystemEntries(path); + } + + public string PathGetFileName(string path) + { + return Path.GetFileName(path); + } + + public string PathGetExtension(string path) + { + return Path.GetExtension(path); + } + + public string PathChangeExtension(string path, string extension) + { + return Path.ChangeExtension(path, extension); + } + + public string PathCombine(params string[] paths) + { + return Path.Combine(paths); + } + + public void DirectorySetLastWriteTimeUtc(string path, DateTime time) + { + Directory.SetLastWriteTimeUtc(NormalizePath(path), time); + } + + public void DirectorySetCreationTimeUtc(string path, DateTime time) + { + Directory.SetCreationTimeUtc(NormalizePath(path), time); + } + + public DateTime DirectoryGetLastWriteTimeUtc(string path) + { + return Directory.GetLastWriteTimeUtc(NormalizePath(path)); + } + + public DateTime DirectoryGetCreationTimeUtc(string path) + { + return Directory.GetCreationTimeUtc(NormalizePath(path)); + } + + public void FileMove(string source, string target) + { + File.Move(source, target); + } + + public long FileLength(string path) + { + return new FileInfo(path).Length; + } + + public void DirectoryDelete(string path, bool recursive) + { + Directory.Delete(NormalizePath(path), recursive); + } + + public Dictionary GetMetadata(string file, bool isSymlink, bool followSymlink) + { + var f = NormalizePath(file); + var dict = new Dictionary(); + + var n = UnixSupport.File.GetExtendedAttributes(f, isSymlink, followSymlink); + if (n != null) + foreach(var x in n) + dict["unix-ext:" + x.Key] = Convert.ToBase64String(x.Value); + + var fse = UnixSupport.File.GetUserGroupAndPermissions(f); + dict["unix:uid-gid-perm"] = string.Format("{0}-{1}-{2}", fse.UID, fse.GID, fse.Permissions); + if (fse.OwnerName != null) + { + dict["unix:owner-name"] = fse.OwnerName; + } + if (fse.GroupName != null) + { + dict["unix:group-name"] = fse.GroupName; + } + + return dict; + } + + public void SetMetadata(string file, Dictionary data, bool restorePermissions) + { + if (data == null) + return; + + var f = NormalizePath(file); + + foreach(var x in data.Where(x => x.Key.StartsWith("unix-ext:", StringComparison.Ordinal)).Select(x => new KeyValuePair(x.Key.Substring("unix-ext:".Length), Convert.FromBase64String(x.Value)))) + UnixSupport.File.SetExtendedAttribute(f, x.Key, x.Value); + + if (restorePermissions && data.ContainsKey("unix:uid-gid-perm")) + { + var parts = data["unix:uid-gid-perm"].Split(new char[] { '-' }); + if (parts.Length == 3) + { + long uid; + long gid; + long perm; + + if (long.TryParse(parts[0], out uid) && long.TryParse(parts[1], out gid) && long.TryParse(parts[2], out perm)) + { + if (data.ContainsKey("unix:owner-name")) + try { uid = UnixSupport.File.GetUserID(data["unix:owner-name"]); } + catch { } + + if (data.ContainsKey("unix:group-name")) + try { gid = UnixSupport.File.GetGroupID(data["unix:group-name"]); } + catch { } + + UnixSupport.File.SetUserGroupAndPermissions(f, uid, gid, perm); + } + } + } + } + + public string GetPathRoot(string path) + { + return Path.GetPathRoot(path); + } + + public string[] GetDirectories(string path) + { + return Directory.GetDirectories(path); + } + + public string[] GetFiles(string path) + { + return Directory.GetFiles(path); + } + + public string[] GetFiles(string path, string searchPattern) + { + return Directory.GetFiles(path, searchPattern); + } + + public DateTime GetCreationTimeUtc(string path) + { + return File.GetCreationTimeUtc(path); + } + + public DateTime GetLastWriteTimeUtc(string path) + { + return File.GetLastWriteTimeUtc(path); + } + + public IEnumerable EnumerateDirectories(string path) + { + return Directory.EnumerateDirectories(path); + } + + public void FileCopy(string source, string target, bool overwrite) + { + File.Copy(source, target, overwrite); + } + + public string PathGetFullPath(string path) + { + return Path.GetFullPath(path); + } + + #endregion + + /// + /// Normalizes a path, by removing any trailing slash, before calling system methods + /// + /// The path to normalize. + /// The normalized path. + public static string NormalizePath(string path) + { + var p = Path.GetFullPath(path); + + // This should not be required, but some versions of Mono apperently do not strip the trailing slash + return p.Length > 1 && p[p.Length - 1] == Path.DirectorySeparatorChar ? p.Substring(0, p.Length - 1) : p; + } + + public IFileEntry DirectoryEntry(string path) + { + var dInfo = new DirectoryInfo(path); + return new FileEntry(dInfo.Name, 0, dInfo.LastAccessTime, dInfo.LastWriteTime) + { + IsFolder = true + }; + } + + public IFileEntry FileEntry(string path) + { + var fileInfo = new FileInfo(path); + return new FileEntry(fileInfo.Name, fileInfo.Length, fileInfo.LastAccessTime, fileInfo.LastWriteTime); + } + } +} + diff --git a/Duplicati/Library/IO/IO/SystemIOWindows.cs b/Duplicati/Library/IO/IO/SystemIOWindows.cs new file mode 100644 index 000000000..f6d641b64 --- /dev/null +++ b/Duplicati/Library/IO/IO/SystemIOWindows.cs @@ -0,0 +1,782 @@ +// Copyright (C) 2015, The Duplicati Team + +// http://www.duplicati.com, info@duplicati.com +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +using System; +using System.Collections.Generic; +using System.Security.AccessControl; +using System.IO; + +using AlphaFS = Alphaleonis.Win32.Filesystem; +using Duplicati.Library.Interface; + +namespace Duplicati.Library.Common.IO +{ + public struct SystemIOWindows : ISystemIO + { + private const string UNCPREFIX = @"\\?\"; + private const string UNCPREFIX_SERVER = @"\\?\UNC\"; + private const string PATHPREFIX_SERVER = @"\\"; + private static readonly string DIRSEP = Util.DirectorySeparatorString; + + private static bool IsPathTooLong(string path) + { + if (path.StartsWith(UNCPREFIX, StringComparison.Ordinal) || path.StartsWith(UNCPREFIX_SERVER, StringComparison.Ordinal) || path.Length > 260) + return true; + + return false; + } + + public static string PrefixWithUNC(string path) + { + if (path.StartsWith(UNCPREFIX_SERVER, StringComparison.Ordinal)) + return path; + + if (path.StartsWith(UNCPREFIX, StringComparison.Ordinal)) + return path; + + if (path.StartsWith(PATHPREFIX_SERVER, StringComparison.Ordinal)) + return UNCPREFIX_SERVER + path.Remove(0, PATHPREFIX_SERVER.Length); + + return UNCPREFIX + path; + } + + public static string StripUNCPrefix(string path) + { + if (path.StartsWith(UNCPREFIX, StringComparison.Ordinal)) + return path.Substring(UNCPREFIX.Length); + else + return path; + } + + #region ISystemIO implementation + public void DirectoryDelete(string path) + { + if (!IsPathTooLong(path)) + try + { + System.IO.Directory.Delete(path); + return; + } + catch (System.IO.PathTooLongException) { } + catch (System.ArgumentException) { } + + Alphaleonis.Win32.Filesystem.Directory.Delete(PrefixWithUNC(path)); + } + + public void DirectoryCreate(string path) + { + if (!IsPathTooLong(path)) + try + { + System.IO.Directory.CreateDirectory(path); + return; + } + catch (System.IO.PathTooLongException) { } + catch (System.ArgumentException) { } + + Alphaleonis.Win32.Filesystem.Directory.CreateDirectory(PrefixWithUNC(path)); + } + + public bool DirectoryExists(string path) + { + if (!IsPathTooLong(path)) + try { return System.IO.Directory.Exists(path); } + catch (System.IO.PathTooLongException) { } + catch (System.ArgumentException) { } + + return Alphaleonis.Win32.Filesystem.Directory.Exists(PrefixWithUNC(path)); + } + + public void FileDelete(string path) + { + if (!IsPathTooLong(path)) + try + { + System.IO.File.Delete(path); + return; + } + catch (System.IO.PathTooLongException) { } + catch (System.ArgumentException) { } + + Alphaleonis.Win32.Filesystem.File.Delete(PrefixWithUNC(path)); + } + + public void FileSetLastWriteTimeUtc(string path, DateTime time) + { + if (!IsPathTooLong(path)) + try + { + System.IO.File.SetLastWriteTimeUtc(path, time); + return; + } + catch (System.IO.PathTooLongException) { } + catch (System.ArgumentException) { } + + Alphaleonis.Win32.Filesystem.File.SetLastWriteTimeUtc(PrefixWithUNC(path), time); + } + + public void FileSetCreationTimeUtc(string path, DateTime time) + { + if (!IsPathTooLong(path)) + try + { + System.IO.File.SetCreationTimeUtc(path, time); + return; + } + catch (System.IO.PathTooLongException) { } + catch (System.ArgumentException) { } + + Alphaleonis.Win32.Filesystem.File.SetCreationTimeUtc(PrefixWithUNC(path), time); + } + + public DateTime FileGetLastWriteTimeUtc(string path) + { + if (!IsPathTooLong(path)) + try + { + return System.IO.File.GetLastWriteTimeUtc(path); + } + catch (System.IO.PathTooLongException) { } + catch (System.ArgumentException) { } + + return Alphaleonis.Win32.Filesystem.File.GetLastWriteTimeUtc(PrefixWithUNC(path)); + } + + public DateTime FileGetCreationTimeUtc(string path) + { + if (!IsPathTooLong(path)) + try + { + return System.IO.File.GetCreationTimeUtc(path); + } + catch (System.IO.PathTooLongException) { } + catch (System.ArgumentException) { } + + return Alphaleonis.Win32.Filesystem.File.GetCreationTimeUtc(PrefixWithUNC(path)); + } + + public bool FileExists(string path) + { + if (!IsPathTooLong(path)) + try { return System.IO.File.Exists(path); } + catch (System.IO.PathTooLongException) { } + catch (System.ArgumentException) { } + + return Alphaleonis.Win32.Filesystem.File.Exists(PrefixWithUNC(path)); + } + + public System.IO.FileStream FileOpenRead(string path) + { + if (!IsPathTooLong(path)) + try { return System.IO.File.Open(path, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.ReadWrite); } + catch (System.IO.PathTooLongException) { } + catch (System.ArgumentException) { } + + return Alphaleonis.Win32.Filesystem.File.Open(PrefixWithUNC(path), FileMode.Open, FileAccess.Read, FileShare.ReadWrite); + } + + public System.IO.FileStream FileOpenWrite(string path) + { + if (!IsPathTooLong(path)) + try { return System.IO.File.OpenWrite(path); } + catch (System.IO.PathTooLongException) { } + catch (System.ArgumentException) { } + + if (FileExists(path)) + return Alphaleonis.Win32.Filesystem.File.OpenWrite(PrefixWithUNC(path)); + else + return FileCreate(path); + } + + public System.IO.FileStream FileOpenReadWrite(string path) + { + if (!IsPathTooLong(path)) + try { return System.IO.File.Open(path, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.ReadWrite, System.IO.FileShare.Read); } + catch (System.IO.PathTooLongException) { } + catch (System.ArgumentException) { } + + return Alphaleonis.Win32.Filesystem.File.Open(PrefixWithUNC(path), FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read); + } + + public System.IO.FileStream FileCreate(string path) + { + if (!IsPathTooLong(path)) + try { return System.IO.File.Create(path); } + catch (System.IO.PathTooLongException) { } + catch (System.ArgumentException) { } + + return Alphaleonis.Win32.Filesystem.File.Create(PrefixWithUNC(path)); + } + + public System.IO.FileAttributes GetFileAttributes(string path) + { + if (!IsPathTooLong(path)) + try { return System.IO.File.GetAttributes(path); } + catch (System.IO.PathTooLongException) { } + catch (System.ArgumentException) { } + + return (System.IO.FileAttributes)Alphaleonis.Win32.Filesystem.File.GetAttributes(PrefixWithUNC(path)); + } + + public void SetFileAttributes(string path, System.IO.FileAttributes attributes) + { + if (!IsPathTooLong(path)) + try + { + System.IO.File.SetAttributes(path, attributes); + return; + } + catch (System.IO.PathTooLongException) { } + catch (System.ArgumentException) { } + + Alphaleonis.Win32.Filesystem.File.SetAttributes(PrefixWithUNC(path), (FileAttributes)attributes); + } + + public void CreateSymlink(string symlinkfile, string target, bool asDir) + { + if (FileExists(symlinkfile) || DirectoryExists(symlinkfile)) + throw new System.IO.IOException(string.Format("File already exists: {0}", symlinkfile)); + Alphaleonis.Win32.Filesystem.File.CreateSymbolicLink(PrefixWithUNC(symlinkfile), target, asDir ? Alphaleonis.Win32.Filesystem.SymbolicLinkTarget.Directory : Alphaleonis.Win32.Filesystem.SymbolicLinkTarget.File, AlphaFS.PathFormat.LongFullPath); + + //Sadly we do not get a notification if the creation fails :( + System.IO.FileAttributes attr = 0; + if ((!asDir && FileExists(symlinkfile)) || (asDir && DirectoryExists(symlinkfile))) + try { attr = GetFileAttributes(symlinkfile); } + catch { } + + if ((attr & System.IO.FileAttributes.ReparsePoint) == 0) + throw new System.IO.IOException(string.Format("Unable to create symlink, check account permissions: {0}", symlinkfile)); + } + + /// + /// Returns the symlink target if the entry is a symlink, and null otherwise + /// + /// The file or folder to examine + /// The symlink target + public string GetSymlinkTarget(string file) + { + try + { + try + { + return AlphaFS.File.GetLinkTargetInfo(file).PrintName; + } + catch (PathTooLongException) { } + + return AlphaFS.File.GetLinkTargetInfo(SystemIOWindows.PrefixWithUNC(file)).PrintName; + } + catch (AlphaFS.NotAReparsePointException) { } + catch (AlphaFS.UnrecognizedReparsePointException) { } + + // This path looks like it isn't actually a symlink + // (Note that some reparse points aren't actually symlinks - + // things like the OneDrive folder in the Windows 10 Fall Creator's Update for example) + return null; + } + + public IEnumerable EnumerateFileSystemEntries(string path) + { + if (!IsPathTooLong(path)) + try { return System.IO.Directory.EnumerateFileSystemEntries(path); } + catch (System.IO.PathTooLongException) { } + catch (System.ArgumentException) { } + + var r = Alphaleonis.Win32.Filesystem.Directory.GetFileSystemEntries(PrefixWithUNC(path)); + for (var i = 0; i < r.Length; i++) + r[i] = StripUNCPrefix(r[i]); + + return r; + } + + public string PathGetFileName(string path) + { + if (!IsPathTooLong(path)) + try { return System.IO.Path.GetFileName(path); } + catch (System.IO.PathTooLongException) { } + catch (System.ArgumentException) { } + + return StripUNCPrefix(Alphaleonis.Win32.Filesystem.Path.GetFileName(PrefixWithUNC(path))); + } + + public string PathGetDirectoryName(string path) + { + if (!IsPathTooLong(path)) + try { return System.IO.Path.GetDirectoryName(path); } + catch (System.IO.PathTooLongException) { } + catch (System.ArgumentException) { } + + return StripUNCPrefix(Alphaleonis.Win32.Filesystem.Path.GetDirectoryName(PrefixWithUNC(path))); + } + + public string PathGetExtension(string path) + { + if (!IsPathTooLong(path)) + try { return System.IO.Path.GetExtension(path); } + catch (System.IO.PathTooLongException) { } + catch (System.ArgumentException) { } + + return StripUNCPrefix(Alphaleonis.Win32.Filesystem.Path.GetExtension(PrefixWithUNC(path))); + } + + public string PathChangeExtension(string path, string extension) + { + if (!IsPathTooLong(path)) + try { return System.IO.Path.ChangeExtension(path, extension); } + catch (System.IO.PathTooLongException) { } + catch (System.ArgumentException) { } + + return StripUNCPrefix(Alphaleonis.Win32.Filesystem.Path.ChangeExtension(PrefixWithUNC(path), extension)); + } + + public string PathCombine(params string[] paths) + { + var combinedPath = ""; + for (int i = 0; i < paths.Length; i++) + { + if (i == 0) + { + combinedPath = paths[i]; + } + else + { + if (!IsPathTooLong(combinedPath + "\\" + paths[i])) + { + try + { + combinedPath = Path.Combine(combinedPath, paths[i]); + } + catch (Exception ex) when (ex is System.IO.PathTooLongException || ex is System.ArgumentException) { + //TODO: Explain why we need to keep prefixing and stripping UNC's. + combinedPath = StripUNCPrefix(Alphaleonis.Win32.Filesystem.Path.Combine(PrefixWithUNC(combinedPath), paths[i])); + } + } + } + } + + return combinedPath; + } + + public void DirectorySetLastWriteTimeUtc(string path, DateTime time) + { + if (!IsPathTooLong(path)) + try + { + System.IO.Directory.SetLastWriteTimeUtc(path, time); + return; + } + catch (System.IO.PathTooLongException) { } + catch (System.ArgumentException) { } + + + Alphaleonis.Win32.Filesystem.File.SetLastWriteTimeUtc(PrefixWithUNC(path), time); + } + + public void DirectorySetCreationTimeUtc(string path, DateTime time) + { + if (!IsPathTooLong(path)) + try + { + System.IO.Directory.SetCreationTimeUtc(path, time); + return; + } + catch (System.IO.PathTooLongException) { } + catch (System.ArgumentException) { } + + Alphaleonis.Win32.Filesystem.File.SetCreationTimeUtc(PrefixWithUNC(path), time); + } + + public DateTime DirectoryGetLastWriteTimeUtc(string path) + { + if (!IsPathTooLong(path)) + try + { + return System.IO.Directory.GetLastWriteTimeUtc(path); + } + catch (System.IO.PathTooLongException) { } + catch (System.ArgumentException) { } + + return Alphaleonis.Win32.Filesystem.Directory.GetLastWriteTimeUtc(PrefixWithUNC(path)); + } + + public DateTime DirectoryGetCreationTimeUtc(string path) + { + if (!IsPathTooLong(path)) + try + { + return System.IO.Directory.GetCreationTimeUtc(path); + } + catch (System.IO.PathTooLongException) { } + catch (System.ArgumentException) { } + + return Alphaleonis.Win32.Filesystem.Directory.GetCreationTimeUtc(PrefixWithUNC(path)); + } + + public void FileMove(string source, string target) + { + if (!IsPathTooLong(source) && !IsPathTooLong(target)) + try + { + System.IO.File.Move(source, target); + return; + } + catch (System.IO.PathTooLongException) { } + catch (System.ArgumentException) { } + + Alphaleonis.Win32.Filesystem.File.Move(PrefixWithUNC(source), PrefixWithUNC(target)); + } + + public long FileLength(string path) + { + if (!IsPathTooLong(path)) + try { return new System.IO.FileInfo(path).Length; } + catch (System.IO.PathTooLongException) { } + catch (System.ArgumentException) { } + + return new Alphaleonis.Win32.Filesystem.FileInfo(PrefixWithUNC(path)).Length; + } + + public void DirectoryDelete(string path, bool recursive) + { + if (!IsPathTooLong(path)) + try + { + System.IO.Directory.Delete(path, recursive); + return; + } + catch (System.IO.PathTooLongException) { } + catch (System.ArgumentException) { } + + Alphaleonis.Win32.Filesystem.Directory.Delete(PrefixWithUNC(path), recursive); + } + + private class FileSystemAccess + { + public FileSystemRights Rights; + public AccessControlType ControlType; + public string SID; + public bool Inherited; + public InheritanceFlags Inheritance; + public PropagationFlags Propagation; + + public FileSystemAccess() + { + } + + public FileSystemAccess(FileSystemAccessRule rule) + { + Rights = rule.FileSystemRights; + ControlType = rule.AccessControlType; + SID = rule.IdentityReference.Value; + Inherited = rule.IsInherited; + Inheritance = rule.InheritanceFlags; + Propagation = rule.PropagationFlags; + } + + public FileSystemAccessRule Create(System.Security.AccessControl.FileSystemSecurity owner) + { + return (FileSystemAccessRule)owner.AccessRuleFactory( + new System.Security.Principal.SecurityIdentifier(SID), + (int)Rights, + Inherited, + Inheritance, + Propagation, + ControlType); + } + } + + private string SerializeObject(T o) + { + using(var tw = new System.IO.StringWriter()) + { + Newtonsoft.Json.JsonSerializer.Create(new Newtonsoft.Json.JsonSerializerSettings() { Culture = System.Globalization.CultureInfo.InvariantCulture }).Serialize(tw, o); + tw.Flush(); + return tw.ToString(); + } + } + + private T DeserializeObject(string data) + { + using(var tr = new System.IO.StringReader(data)) + return (T)Newtonsoft.Json.JsonSerializer.Create(new Newtonsoft.Json.JsonSerializerSettings() { Culture = System.Globalization.CultureInfo.InvariantCulture }).Deserialize(tr, typeof(T)); + + } + + private System.Security.AccessControl.FileSystemSecurity GetAccessControlDir(string path) + { + if (!IsPathTooLong(path)) + try { return System.IO.Directory.GetAccessControl(path); } + catch (System.IO.PathTooLongException) { } + catch (System.ArgumentException) { } + + return Alphaleonis.Win32.Filesystem.Directory.GetAccessControl(PrefixWithUNC(path)); + } + + private System.Security.AccessControl.FileSystemSecurity GetAccessControlFile(string path) + { + if (!IsPathTooLong(path)) + try { return System.IO.File.GetAccessControl(path); } + catch (System.IO.PathTooLongException) { } + catch (System.ArgumentException) { } + + return Alphaleonis.Win32.Filesystem.File.GetAccessControl(PrefixWithUNC(path)); + } + + private void SetAccessControlFile(string path, FileSecurity rules) + { + if (!IsPathTooLong(path)) + try + { + System.IO.File.SetAccessControl(path, rules); + return; + } + catch (System.IO.PathTooLongException) { } + catch (System.ArgumentException) { } + + Alphaleonis.Win32.Filesystem.File.SetAccessControl(PrefixWithUNC(path), rules, AccessControlSections.All); + } + + private void SetAccessControlDir(string path, DirectorySecurity rules) + { + if (!IsPathTooLong(path)) + try + { + System.IO.Directory.SetAccessControl(path, rules); + return; + } + catch (System.IO.PathTooLongException) { } + catch (System.ArgumentException) { } + + Alphaleonis.Win32.Filesystem.Directory.SetAccessControl(PrefixWithUNC(path), rules, AccessControlSections.All); + } + + public Dictionary GetMetadata(string path, bool isSymlink, bool followSymlink) + { + var isDirTarget = path.EndsWith(DIRSEP, StringComparison.Ordinal); + var targetpath = isDirTarget ? path.Substring(0, path.Length - 1) : path; + var dict = new Dictionary(); + + System.Security.AccessControl.FileSystemSecurity rules; + + if (isDirTarget) + rules = GetAccessControlDir(targetpath); + else + rules = GetAccessControlFile(targetpath); + + var objs = new List(); + foreach(var f in rules.GetAccessRules(true, false, typeof(System.Security.Principal.SecurityIdentifier))) + objs.Add(new FileSystemAccess((FileSystemAccessRule)f)); + + dict["win-ext:accessrules"] = SerializeObject(objs); + + return dict; + } + + public void SetMetadata(string path, Dictionary data, bool restorePermissions) + { + var isDirTarget = path.EndsWith(DIRSEP, StringComparison.Ordinal); + var targetpath = isDirTarget ? path.Substring(0, path.Length - 1) : path; + + System.Security.AccessControl.FileSystemSecurity rules; + + if (isDirTarget) + rules = GetAccessControlDir(targetpath); + else + rules = GetAccessControlFile(targetpath); + + if (restorePermissions && data.ContainsKey("win-ext:accessrules")) + { + var content = DeserializeObject(data["win-ext:accessrules"]); + var c = rules.GetAccessRules(true, false, typeof(System.Security.Principal.SecurityIdentifier)); + for(var i = c.Count - 1; i >= 0; i--) + rules.RemoveAccessRule((System.Security.AccessControl.FileSystemAccessRule)c[i]); + + Exception ex = null; + + foreach (var r in content) + { + // Attempt to apply as many rules as we can + try + { + rules.AddAccessRule((System.Security.AccessControl.FileSystemAccessRule)r.Create(rules)); + } + catch(Exception e) + { + ex = e; + } + } + + if (ex != null) + throw ex; + + if (isDirTarget) + SetAccessControlDir(targetpath, (DirectorySecurity)rules); + else + SetAccessControlFile(targetpath, (FileSecurity)rules); + } + } + + public string GetPathRoot(string path) + { + if (!IsPathTooLong(path)) + { + try { return Path.GetPathRoot(path); } + catch (System.IO.PathTooLongException) { } + catch (System.ArgumentException) { } + } + return AlphaFS.Path.GetPathRoot(path); + } + + public string[] GetDirectories(string path) + { + if (!IsPathTooLong(path)) + { + try { return Directory.GetDirectories(path); } + catch (System.IO.PathTooLongException) { } + catch (System.ArgumentException) { } + } + + return AlphaFS.Directory.GetDirectories(path); + } + + public string[] GetFiles(string path) + { + if (!IsPathTooLong(path)) + { + try { return Directory.GetFiles(path); } + catch (System.IO.PathTooLongException) { } + catch (System.ArgumentException) { } + } + + return AlphaFS.Directory.GetFiles(path); + } + + public string[] GetFiles(string path, string searchPattern) + { + if (!IsPathTooLong(path)) + { + try { return Directory.GetFiles(path, searchPattern); } + catch (System.IO.PathTooLongException) { } + catch (System.ArgumentException) { } + } + + return AlphaFS.Directory.GetFiles(path, searchPattern); + } + + public DateTime GetCreationTimeUtc(string path) + { + if (!IsPathTooLong(path)) + { + try { return Directory.GetCreationTimeUtc(path); } + catch (System.IO.PathTooLongException) { } + catch (System.ArgumentException) { } + } + + return AlphaFS.File.GetCreationTimeUtc(path); + } + + public DateTime GetLastWriteTimeUtc(string path) + { + if (!IsPathTooLong(path)) + { + try { return Directory.GetLastWriteTimeUtc(path); } + catch (System.IO.PathTooLongException) { } + catch (System.ArgumentException) { } + } + + return AlphaFS.File.GetLastWriteTimeUtc(path); + } + + public IEnumerable EnumerateDirectories(string path) + { + if (!IsPathTooLong(path)) + { + try { return Directory.EnumerateDirectories(path); } + catch (System.IO.PathTooLongException) { } + catch (System.ArgumentException) { } + } + + return AlphaFS.Directory.EnumerateDirectories(path); + } + + public void FileCopy(string source, string target, bool overwrite) + { + if (!IsPathTooLong(source) && !IsPathTooLong(target)) + { + try { File.Copy(source, target, overwrite); } + catch (System.IO.PathTooLongException) { } + catch (System.ArgumentException) { } + } + + AlphaFS.File.Copy(source, target, overwrite); + } + + public string PathGetFullPath(string path) + { + if (!IsPathTooLong(path)) + { + try { return System.IO.Path.GetFullPath(path); } + catch (System.IO.PathTooLongException) { } + catch (System.ArgumentException) { } + } + + return AlphaFS.Path.GetFullPath(path); + } + + public IFileEntry DirectoryEntry(string path) + { + if (!IsPathTooLong(path)) + { + try + { + var dInfo = new DirectoryInfo(path); + return new FileEntry(dInfo.Name, 0, dInfo.LastAccessTime, dInfo.LastWriteTime) + { + IsFolder = true + }; + } + catch (System.IO.PathTooLongException) { } + catch (System.ArgumentException) { } + } + + var dInfoAlphaFS = new AlphaFS.DirectoryInfo(path); + return new FileEntry(dInfoAlphaFS.Name, 0, dInfoAlphaFS.LastAccessTime, dInfoAlphaFS.LastWriteTime) + { + IsFolder = true + }; + } + + public IFileEntry FileEntry(string path) + { + if (!IsPathTooLong(path)) + { + try + { + var fileInfo = new FileInfo(path); + return new FileEntry(fileInfo.Name, fileInfo.Length, fileInfo.LastAccessTime, fileInfo.LastWriteTime); + } + catch (System.IO.PathTooLongException) { } + catch (System.ArgumentException) { } + } + + var fInfoAlphaFS = new AlphaFS.FileInfo(path); + return new FileEntry(fInfoAlphaFS.Name, fInfoAlphaFS.Length, fInfoAlphaFS.LastAccessTime, fInfoAlphaFS.LastWriteTime); + } + + #endregion + } +} + diff --git a/Duplicati/Library/IO/IO/Util.cs b/Duplicati/Library/IO/IO/Util.cs new file mode 100644 index 000000000..879da2609 --- /dev/null +++ b/Duplicati/Library/IO/IO/Util.cs @@ -0,0 +1,65 @@ +// Copyright (C) 2018, The Duplicati Team +// http://www.duplicati.com, info@duplicati.com +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +using System; +using System.IO; + +namespace Duplicati.Library.Common.IO +{ + public static class Util + { + /// + /// A cached instance of the directory separator as a string + /// + public static readonly string DirectorySeparatorString = Path.DirectorySeparatorChar.ToString(); + + public static readonly string AltDirectorySeparatorString = Path.AltDirectorySeparatorChar.ToString(); + + /// + /// Appends the appropriate directory separator to paths, depending on OS. + /// Does not append the separator if the path already ends with it. + /// + /// The path to append to + /// The path with the directory separator appended + public static string AppendDirSeparator(string path) + { + return AppendDirSeparator(path, DirectorySeparatorString); + } + + /// + /// Appends the specified directory separator to paths. + /// Does not append the separator if the path already ends with it. + /// + /// The path to append to + /// The directory separator to use + /// The path with the directory separator appended + public static string AppendDirSeparator(string path, string separator) + { + return !path.EndsWith(separator, StringComparison.Ordinal) ? path + separator : path; + } + + + /// + /// Guesses the directory separator from the path + /// + /// The path to guess the separator from + /// The guessed directory separator + public static string GuessDirSeparator(string path) + { + return string.IsNullOrWhiteSpace(path) || path.StartsWith("/", StringComparison.Ordinal) ? "/" : "\\"; + } + } +} diff --git a/Duplicati/Library/IO/IO/VssBackupComponents.cs b/Duplicati/Library/IO/IO/VssBackupComponents.cs new file mode 100644 index 000000000..e236aff8c --- /dev/null +++ b/Duplicati/Library/IO/IO/VssBackupComponents.cs @@ -0,0 +1,308 @@ +// Copyright (C) 2018, The Duplicati Team +// http://www.duplicati.com, info@duplicati.com +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Alphaleonis.Win32.Vss; + +namespace Duplicati.Library.Common.IO +{ + public class WriterMetaData + { + public string Name { get; set; } + public string LogicalPath { get; set; } + public Guid Guid { get; set; } + public List Paths { get; set; } + } + + public class VssBackupComponents : IDisposable + { + /// + /// The tag used for logging messages + /// + public static readonly string LOGTAG = Logging.Log.LogTagFromType(); + + + private IVssBackupComponents _vssBackupComponents; + + /// + /// The list of snapshot ids for each volume, key is the path root, eg C:\. + /// The dictionary is case insensitive + /// + private Dictionary _volumes; + + /// + /// The mapping of snapshot sources to their snapshot entries , key is the path root, eg C:\. + /// The dictionary is case insensitive + /// + private Dictionary _volumeMap; + + /// + /// Reverse mapping for speed up. + /// + private Dictionary _volumeReverseMap; + + /// + /// A list of mapped drives + /// + private List _mappedDrives; + + public VssBackupComponents() + { + _vssBackupComponents = VssBackupComponentsHelper.GetVssBackupComponents(); + } + + public void SetupWriters(Guid[] includedWriters, Guid[] excludedWriters) + { + if (includedWriters != null && includedWriters.Length > 0) + _vssBackupComponents.EnableWriterClasses(includedWriters); + + if (excludedWriters != null && excludedWriters.Length > 0) + _vssBackupComponents.DisableWriterClasses(excludedWriters.ToArray()); + + try + { + _vssBackupComponents.GatherWriterMetadata(); + } + finally + { + _vssBackupComponents.FreeWriterMetadata(); + } + + // check if writers got enabled + foreach (var writerGUID in includedWriters) + { + if (!_vssBackupComponents.WriterMetadata.Any(o => o.WriterId.Equals(writerGUID))) + { + throw new Exception(string.Format("Writer with GUID {0} was not added to VSS writer set.", writerGUID.ToString())); + } + } + } + + public void MapDrives() + { + _mappedDrives = new List(); + foreach (var k in new List(_volumeMap.Keys)) + { + try + { + DefineDosDevice d = new DefineDosDevice(_volumeMap[k]); + _mappedDrives.Add(d); + _volumeMap[k] = Util.AppendDirSeparator(d.Drive); + } + catch (Exception ex) + { + Logging.Log.WriteVerboseMessage(LOGTAG, "SubstMappingfailed", ex, "Failed to map VSS path {0} to drive", k); + } + } + } + + public void MapVolumesToSnapShots() + { + _volumeMap = new Dictionary(StringComparer.OrdinalIgnoreCase); + foreach (var kvp in _volumes) + { + _volumeMap.Add(kvp.Key, _vssBackupComponents.GetSnapshotProperties(kvp.Value).SnapshotDeviceObject); + } + + _volumeReverseMap = _volumeMap.ToDictionary(x => x.Value, x => x.Key); + } + + public Dictionary SnapshotDeviceAndVolumes + { + get { + return _volumeReverseMap; + } + + } + + private List GetPathsFromComponent(IVssWMComponent component) + { + var paths = new List(); + + foreach (var file in component.Files) + { + if (file.FileSpecification.Contains("*")) + { + if (Directory.Exists(Util.AppendDirSeparator(file.Path))) + paths.Add(Util.AppendDirSeparator(file.Path)); + } + else + { + var fileWithSpec = SystemIO.IO_WIN.PathCombine(file.Path, file.FileSpecification); + if (File.Exists(fileWithSpec)) + paths.Add(fileWithSpec); + } + } + return paths; + + } + + /// + /// Enumerable to iterate over components of the given writers. + /// Returns an WriterMetaData object containing GUID, component name, logical path and paths of the component. + /// + /// Anonymous object containing GUID, component name, logical path and paths of the component. + /// Writers. + public IEnumerable ParseWriterMetaData(Guid[] writers) + { + // check if writers got enabled + foreach (var writerGUID in writers) + { + var writer = _vssBackupComponents.WriterMetadata.First(o => o.WriterId.Equals(writerGUID)); + foreach (var component in writer.Components) + { + yield return new WriterMetaData{ Guid = writerGUID, + Name = component.ComponentName, + LogicalPath = component.LogicalPath, + Paths = GetPathsFromComponent(component) }; + } + } + } + + + public void InitShadowVolumes(IEnumerable sources) + { + _vssBackupComponents.StartSnapshotSet(); + + CheckSupportedVolumes(sources); + + //Make all writers aware that we are going to do the backup + _vssBackupComponents.PrepareForBackup(); + + //Create the shadow volumes + _vssBackupComponents.DoSnapshotSet(); + } + + public string GetVolumeFromCache(string path) + { + if (!_volumeMap.TryGetValue(path, out var volumePath)) + throw new InvalidOperationException(); + + return volumePath; + } + + + public void CheckSupportedVolumes(IEnumerable sources) + { + //Figure out which volumes are in the set + _volumes = new Dictionary(StringComparer.OrdinalIgnoreCase); + foreach (var s in sources) + { + var drive = SystemIO.IO_WIN.GetPathRoot(s); + if (!_volumes.ContainsKey(drive)) + { + if (!_vssBackupComponents.IsVolumeSupported(drive)) + { + throw new VssVolumeNotSupportedException(drive); + } + + _volumes.Add(drive, _vssBackupComponents.AddToSnapshotSet(drive)); + } + } + } + + public void Dispose() + { + try + { + if (_mappedDrives != null) + { + foreach (var d in _mappedDrives) + { + d.Dispose(); + } + + _mappedDrives = null; + } + } + catch (Exception ex) + { + Logging.Log.WriteVerboseMessage(LOGTAG, "MappedDriveCleanupError", ex, "Failed during VSS mapped drive unmapping"); + } + + try + { + _vssBackupComponents?.BackupComplete(); + } + catch (Exception ex) + { + Logging.Log.WriteVerboseMessage(LOGTAG, "VSSTerminateError", ex, "Failed to signal VSS completion"); + } + + try + { + if (_vssBackupComponents != null) + { + foreach (var g in _volumes.Values) + { + try + { + _vssBackupComponents.DeleteSnapshot(g, false); + } + catch (Exception ex) + { + Logging.Log.WriteVerboseMessage(LOGTAG, "VSSSnapShotDeleteError", ex, "Failed to close VSS snapshot"); + } + } + } + } + catch (Exception ex) + { + Logging.Log.WriteVerboseMessage(LOGTAG, "VSSSnapShotDeleteCleanError", ex, "Failed during VSS esnapshot closing"); + } + + if (_vssBackupComponents != null) + { + _vssBackupComponents.Dispose(); + _vssBackupComponents = null; + } + } + } + + + public static class VssBackupComponentsHelper + { + public static IVssBackupComponents GetVssBackupComponents() + { + //Prepare the backup + IVssBackupComponents m_backup = CreateVssBackupComponents(); + m_backup.InitializeForBackup(null); + m_backup.SetContext(VssSnapshotContext.Backup); + m_backup.SetBackupState(false, true, VssBackupType.Full, false); + + return m_backup; + } + + public static IVssBackupComponents CreateVssBackupComponents() + { + // Substitute for calling VssUtils.LoadImplementation(), as we have the dlls outside the GAC + var assemblyLocation = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); + if (assemblyLocation == null) + throw new InvalidOperationException(); + + //Here we don't need a custom Path.Combine: we need unconditional access to alphaFS + var alphadll = Path.Combine(assemblyLocation, "alphavss", VssUtils.GetPlatformSpecificAssemblyShortName() + ".dll"); + var vss = (IVssImplementation)System.Reflection.Assembly.LoadFile(alphadll).CreateInstance("Alphaleonis.Win32.Vss.VssImplementation"); + if (vss == null) + throw new InvalidOperationException(); + + return vss.CreateVssBackupComponents(); + } + } +} diff --git a/Duplicati/Library/IO/ISystemIO.cs b/Duplicati/Library/IO/ISystemIO.cs deleted file mode 100644 index e53d2339f..000000000 --- a/Duplicati/Library/IO/ISystemIO.cs +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (C) 2015, The Duplicati Team - -// http://www.duplicati.com, info@duplicati.com -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -using System; -using System.IO; -using System.Collections.Generic; -using Duplicati.Library.Interface; - -namespace Duplicati.Library.IO -{ - /// - /// Interface for wrapping System.IO operations. - /// - public interface ISystemIO - { - IFileEntry DirectoryEntry(string path); - void DirectoryDelete(string path); - void DirectoryDelete(string path, bool recursive); - void DirectoryCreate(string path); - bool DirectoryExists(string path); - void DirectorySetLastWriteTimeUtc(string path, DateTime time); - void DirectorySetCreationTimeUtc(string path, DateTime time); - DateTime DirectoryGetLastWriteTimeUtc(string path); - DateTime DirectoryGetCreationTimeUtc(string path); - - - IFileEntry FileEntry(string path); - void FileMove(string source, string target); - void FileDelete(string path); - void FileCopy(string source, string target, bool overwrite); - void FileSetLastWriteTimeUtc(string path, DateTime time); - void FileSetCreationTimeUtc(string path, DateTime time); - DateTime FileGetLastWriteTimeUtc(string path); - DateTime FileGetCreationTimeUtc(string path); - bool FileExists(string path); - long FileLength(string path); - FileStream FileOpenRead(string path); - FileStream FileOpenWrite(string path); - FileStream FileOpenReadWrite(string path); - FileStream FileCreate(string path); - FileAttributes GetFileAttributes(string path); - void SetFileAttributes(string path, FileAttributes attributes); - void CreateSymlink(string symlinkfile, string target, bool asDir); - string GetSymlinkTarget(string path); - string PathGetDirectoryName(string path); - string PathGetFileName(string path); - string PathGetExtension(string path); - string PathChangeExtension(string path, string extension); - string PathCombine(params string[] paths); - string PathGetFullPath(string path); - string GetPathRoot(string path); - string[] GetDirectories(string path); - string[] GetFiles(string path); - string[] GetFiles(string path, string searchPattern); - DateTime GetCreationTimeUtc(string path); - DateTime GetLastWriteTimeUtc(string path); - IEnumerable EnumerateFileSystemEntries(string path); - IEnumerable EnumerateDirectories(string path); - - void SetMetadata(string path, Dictionary metdata, bool restorePermissions); - Dictionary GetMetadata(string path, bool isSymlink, bool followSymlink); - } - -} - diff --git a/Duplicati/Library/IO/Platform/Platform.cs b/Duplicati/Library/IO/Platform/Platform.cs new file mode 100644 index 000000000..47974a1f5 --- /dev/null +++ b/Duplicati/Library/IO/Platform/Platform.cs @@ -0,0 +1,32 @@ +// Copyright (C) 2018, The Duplicati Team +// http://www.duplicati.com, info@duplicati.com +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +using System; +namespace Duplicati.Library.Common +{ + public static class Platform + { + /// + /// Gets or sets a value indicating if the client is Linux/Unix based + /// + public static bool IsClientLinux => Environment.OSVersion.Platform == PlatformID.Unix || Environment.OSVersion.Platform == PlatformID.MacOSX; + + /// + /// Gets a value indicating if the client is Windows based + /// + public static bool IsClientWindows => !IsClientLinux; + } +} diff --git a/Duplicati/Library/IO/SystemIO.cs b/Duplicati/Library/IO/SystemIO.cs deleted file mode 100644 index e5a6c71ec..000000000 --- a/Duplicati/Library/IO/SystemIO.cs +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (C) 2018, The Duplicati Team -// http://www.duplicati.com, info@duplicati.com -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -using System; -namespace Duplicati.Library.IO -{ - public static class SystemIO - { - - /// - /// A cached lookup for windows methods for dealing with long filenames - /// - private static readonly ISystemIO _IO_WIN = new SystemIOWindows(); - - private static readonly ISystemIO _IO_SYS = new SystemIOLinux(); - - public static ISystemIO IO_WIN - { - get - { - return _IO_WIN; - } - } - - public static ISystemIO IO_SYS - { - get - { - return _IO_SYS; - } - } - - - public static ISystemIO IO_OS(bool useWindowsIO) - { - { - return useWindowsIO ? _IO_WIN : _IO_SYS; - } - } - } -} \ No newline at end of file diff --git a/Duplicati/Library/IO/SystemIOLinux.cs b/Duplicati/Library/IO/SystemIOLinux.cs deleted file mode 100644 index 41586abe3..000000000 --- a/Duplicati/Library/IO/SystemIOLinux.cs +++ /dev/null @@ -1,314 +0,0 @@ -// Copyright (C) 2015, The Duplicati Team - -// http://www.duplicati.com, info@duplicati.com -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -using System; -using System.IO; -using System.Linq; -using System.Collections.Generic; -using Duplicati.Library.Interface; - -namespace Duplicati.Library.IO -{ - public struct SystemIOLinux : ISystemIO - { - #region ISystemIO implementation - public void DirectoryDelete(string path) - { - Directory.Delete(NormalizePath(path)); - } - - public void DirectoryCreate(string path) - { - Directory.CreateDirectory(NormalizePath(path)); - } - - public bool DirectoryExists(string path) - { - return Directory.Exists(NormalizePath(path)); - } - - public void FileDelete(string path) - { - File.Delete(path); - } - - public void FileSetLastWriteTimeUtc(string path, DateTime time) - { - File.SetLastWriteTimeUtc(path, time); - } - - public void FileSetCreationTimeUtc(string path, DateTime time) - { - File.SetCreationTimeUtc(path, time); - } - - public DateTime FileGetLastWriteTimeUtc(string path) - { - return File.GetLastWriteTimeUtc(path); - } - - public DateTime FileGetCreationTimeUtc(string path) - { - return File.GetCreationTimeUtc(path); - } - - public bool FileExists(string path) - { - return File.Exists(path); - } - - public FileStream FileOpenRead(string path) - { - return File.OpenRead(path); - } - - public FileStream FileOpenWrite(string path) - { - return File.OpenWrite(path); - } - - public FileStream FileOpenReadWrite(string path) - { - return File.Open(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read); - } - - public FileStream FileCreate(string path) - { - return File.Create(path); - } - - public FileAttributes GetFileAttributes(string path) - { - return File.GetAttributes(NormalizePath(path)); - } - - public void SetFileAttributes(string path, FileAttributes attributes) - { - File.SetAttributes(path, attributes); - } - - public void CreateSymlink(string symlinkfile, string target, bool asDir) - { - UnixSupport.File.CreateSymlink(symlinkfile, target); - } - - public string GetSymlinkTarget(string path) - { - return UnixSupport.File.GetSymlinkTarget(NormalizePath(path)); - } - - public string PathGetDirectoryName(string path) - { - return Path.GetDirectoryName(NormalizePath(path)); - } - - public IEnumerable EnumerateFileSystemEntries(string path) - { - return Directory.EnumerateFileSystemEntries(path); - } - - public string PathGetFileName(string path) - { - return Path.GetFileName(path); - } - - public string PathGetExtension(string path) - { - return Path.GetExtension(path); - } - - public string PathChangeExtension(string path, string extension) - { - return Path.ChangeExtension(path, extension); - } - - public string PathCombine(params string[] paths) - { - return Path.Combine(paths); - } - - public void DirectorySetLastWriteTimeUtc(string path, DateTime time) - { - Directory.SetLastWriteTimeUtc(NormalizePath(path), time); - } - - public void DirectorySetCreationTimeUtc(string path, DateTime time) - { - Directory.SetCreationTimeUtc(NormalizePath(path), time); - } - - public DateTime DirectoryGetLastWriteTimeUtc(string path) - { - return Directory.GetLastWriteTimeUtc(NormalizePath(path)); - } - - public DateTime DirectoryGetCreationTimeUtc(string path) - { - return Directory.GetCreationTimeUtc(NormalizePath(path)); - } - - public void FileMove(string source, string target) - { - File.Move(source, target); - } - - public long FileLength(string path) - { - return new FileInfo(path).Length; - } - - public void DirectoryDelete(string path, bool recursive) - { - Directory.Delete(NormalizePath(path), recursive); - } - - public Dictionary GetMetadata(string file, bool isSymlink, bool followSymlink) - { - var f = NormalizePath(file); - var dict = new Dictionary(); - - var n = UnixSupport.File.GetExtendedAttributes(f, isSymlink, followSymlink); - if (n != null) - foreach(var x in n) - dict["unix-ext:" + x.Key] = Convert.ToBase64String(x.Value); - - var fse = UnixSupport.File.GetUserGroupAndPermissions(f); - dict["unix:uid-gid-perm"] = string.Format("{0}-{1}-{2}", fse.UID, fse.GID, fse.Permissions); - if (fse.OwnerName != null) - { - dict["unix:owner-name"] = fse.OwnerName; - } - if (fse.GroupName != null) - { - dict["unix:group-name"] = fse.GroupName; - } - - return dict; - } - - public void SetMetadata(string file, Dictionary data, bool restorePermissions) - { - if (data == null) - return; - - var f = NormalizePath(file); - - foreach(var x in data.Where(x => x.Key.StartsWith("unix-ext:", StringComparison.Ordinal)).Select(x => new KeyValuePair(x.Key.Substring("unix-ext:".Length), Convert.FromBase64String(x.Value)))) - UnixSupport.File.SetExtendedAttribute(f, x.Key, x.Value); - - if (restorePermissions && data.ContainsKey("unix:uid-gid-perm")) - { - var parts = data["unix:uid-gid-perm"].Split(new char[] { '-' }); - if (parts.Length == 3) - { - long uid; - long gid; - long perm; - - if (long.TryParse(parts[0], out uid) && long.TryParse(parts[1], out gid) && long.TryParse(parts[2], out perm)) - { - if (data.ContainsKey("unix:owner-name")) - try { uid = UnixSupport.File.GetUserID(data["unix:owner-name"]); } - catch { } - - if (data.ContainsKey("unix:group-name")) - try { gid = UnixSupport.File.GetGroupID(data["unix:group-name"]); } - catch { } - - UnixSupport.File.SetUserGroupAndPermissions(f, uid, gid, perm); - } - } - } - } - - public string GetPathRoot(string path) - { - return Path.GetPathRoot(path); - } - - public string[] GetDirectories(string path) - { - return Directory.GetDirectories(path); - } - - public string[] GetFiles(string path) - { - return Directory.GetFiles(path); - } - - public string[] GetFiles(string path, string searchPattern) - { - return Directory.GetFiles(path, searchPattern); - } - - public DateTime GetCreationTimeUtc(string path) - { - return File.GetCreationTimeUtc(path); - } - - public DateTime GetLastWriteTimeUtc(string path) - { - return File.GetLastWriteTimeUtc(path); - } - - public IEnumerable EnumerateDirectories(string path) - { - return Directory.EnumerateDirectories(path); - } - - public void FileCopy(string source, string target, bool overwrite) - { - File.Copy(source, target, overwrite); - } - - public string PathGetFullPath(string path) - { - return Path.GetFullPath(path); - } - - #endregion - - /// - /// Normalizes a path, by removing any trailing slash, before calling system methods - /// - /// The path to normalize. - /// The normalized path. - public static string NormalizePath(string path) - { - var p = Path.GetFullPath(path); - - // This should not be required, but some versions of Mono apperently do not strip the trailing slash - return p.Length > 1 && p[p.Length - 1] == Path.DirectorySeparatorChar ? p.Substring(0, p.Length - 1) : p; - } - - public IFileEntry DirectoryEntry(string path) - { - var dInfo = new DirectoryInfo(path); - return new FileEntry(dInfo.Name, 0, dInfo.LastAccessTime, dInfo.LastWriteTime) - { - IsFolder = true - }; - } - - public IFileEntry FileEntry(string path) - { - var fileInfo = new FileInfo(path); - return new FileEntry(fileInfo.Name, fileInfo.Length, fileInfo.LastAccessTime, fileInfo.LastWriteTime); - } - } -} - diff --git a/Duplicati/Library/IO/SystemIOWindows.cs b/Duplicati/Library/IO/SystemIOWindows.cs deleted file mode 100644 index 8fd7ee28c..000000000 --- a/Duplicati/Library/IO/SystemIOWindows.cs +++ /dev/null @@ -1,783 +0,0 @@ -// Copyright (C) 2015, The Duplicati Team - -// http://www.duplicati.com, info@duplicati.com -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -using System; -using System.Collections.Generic; -using System.Security.AccessControl; -using System.IO; - -using Alphaleonis.Win32.Vss; -using AlphaFS = Alphaleonis.Win32.Filesystem; -using Duplicati.Library.Interface; - -namespace Duplicati.Library.IO -{ - public struct SystemIOWindows : ISystemIO - { - private const string UNCPREFIX = @"\\?\"; - private const string UNCPREFIX_SERVER = @"\\?\UNC\"; - private const string PATHPREFIX_SERVER = @"\\"; - private static readonly string DIRSEP = Util.DirectorySeparatorString; - - private static bool IsPathTooLong(string path) - { - if (path.StartsWith(UNCPREFIX, StringComparison.Ordinal) || path.StartsWith(UNCPREFIX_SERVER, StringComparison.Ordinal) || path.Length > 260) - return true; - - return false; - } - - public static string PrefixWithUNC(string path) - { - if (path.StartsWith(UNCPREFIX_SERVER, StringComparison.Ordinal)) - return path; - - if (path.StartsWith(UNCPREFIX, StringComparison.Ordinal)) - return path; - - if (path.StartsWith(PATHPREFIX_SERVER, StringComparison.Ordinal)) - return UNCPREFIX_SERVER + path.Remove(0, PATHPREFIX_SERVER.Length); - - return UNCPREFIX + path; - } - - public static string StripUNCPrefix(string path) - { - if (path.StartsWith(UNCPREFIX, StringComparison.Ordinal)) - return path.Substring(UNCPREFIX.Length); - else - return path; - } - - #region ISystemIO implementation - public void DirectoryDelete(string path) - { - if (!IsPathTooLong(path)) - try - { - System.IO.Directory.Delete(path); - return; - } - catch (System.IO.PathTooLongException) { } - catch (System.ArgumentException) { } - - Alphaleonis.Win32.Filesystem.Directory.Delete(PrefixWithUNC(path)); - } - - public void DirectoryCreate(string path) - { - if (!IsPathTooLong(path)) - try - { - System.IO.Directory.CreateDirectory(path); - return; - } - catch (System.IO.PathTooLongException) { } - catch (System.ArgumentException) { } - - Alphaleonis.Win32.Filesystem.Directory.CreateDirectory(PrefixWithUNC(path)); - } - - public bool DirectoryExists(string path) - { - if (!IsPathTooLong(path)) - try { return System.IO.Directory.Exists(path); } - catch (System.IO.PathTooLongException) { } - catch (System.ArgumentException) { } - - return Alphaleonis.Win32.Filesystem.Directory.Exists(PrefixWithUNC(path)); - } - - public void FileDelete(string path) - { - if (!IsPathTooLong(path)) - try - { - System.IO.File.Delete(path); - return; - } - catch (System.IO.PathTooLongException) { } - catch (System.ArgumentException) { } - - Alphaleonis.Win32.Filesystem.File.Delete(PrefixWithUNC(path)); - } - - public void FileSetLastWriteTimeUtc(string path, DateTime time) - { - if (!IsPathTooLong(path)) - try - { - System.IO.File.SetLastWriteTimeUtc(path, time); - return; - } - catch (System.IO.PathTooLongException) { } - catch (System.ArgumentException) { } - - Alphaleonis.Win32.Filesystem.File.SetLastWriteTimeUtc(PrefixWithUNC(path), time); - } - - public void FileSetCreationTimeUtc(string path, DateTime time) - { - if (!IsPathTooLong(path)) - try - { - System.IO.File.SetCreationTimeUtc(path, time); - return; - } - catch (System.IO.PathTooLongException) { } - catch (System.ArgumentException) { } - - Alphaleonis.Win32.Filesystem.File.SetCreationTimeUtc(PrefixWithUNC(path), time); - } - - public DateTime FileGetLastWriteTimeUtc(string path) - { - if (!IsPathTooLong(path)) - try - { - return System.IO.File.GetLastWriteTimeUtc(path); - } - catch (System.IO.PathTooLongException) { } - catch (System.ArgumentException) { } - - return Alphaleonis.Win32.Filesystem.File.GetLastWriteTimeUtc(PrefixWithUNC(path)); - } - - public DateTime FileGetCreationTimeUtc(string path) - { - if (!IsPathTooLong(path)) - try - { - return System.IO.File.GetCreationTimeUtc(path); - } - catch (System.IO.PathTooLongException) { } - catch (System.ArgumentException) { } - - return Alphaleonis.Win32.Filesystem.File.GetCreationTimeUtc(PrefixWithUNC(path)); - } - - public bool FileExists(string path) - { - if (!IsPathTooLong(path)) - try { return System.IO.File.Exists(path); } - catch (System.IO.PathTooLongException) { } - catch (System.ArgumentException) { } - - return Alphaleonis.Win32.Filesystem.File.Exists(PrefixWithUNC(path)); - } - - public System.IO.FileStream FileOpenRead(string path) - { - if (!IsPathTooLong(path)) - try { return System.IO.File.Open(path, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.ReadWrite); } - catch (System.IO.PathTooLongException) { } - catch (System.ArgumentException) { } - - return Alphaleonis.Win32.Filesystem.File.Open(PrefixWithUNC(path), FileMode.Open, FileAccess.Read, FileShare.ReadWrite); - } - - public System.IO.FileStream FileOpenWrite(string path) - { - if (!IsPathTooLong(path)) - try { return System.IO.File.OpenWrite(path); } - catch (System.IO.PathTooLongException) { } - catch (System.ArgumentException) { } - - if (FileExists(path)) - return Alphaleonis.Win32.Filesystem.File.OpenWrite(PrefixWithUNC(path)); - else - return FileCreate(path); - } - - public System.IO.FileStream FileOpenReadWrite(string path) - { - if (!IsPathTooLong(path)) - try { return System.IO.File.Open(path, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.ReadWrite, System.IO.FileShare.Read); } - catch (System.IO.PathTooLongException) { } - catch (System.ArgumentException) { } - - return Alphaleonis.Win32.Filesystem.File.Open(PrefixWithUNC(path), FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read); - } - - public System.IO.FileStream FileCreate(string path) - { - if (!IsPathTooLong(path)) - try { return System.IO.File.Create(path); } - catch (System.IO.PathTooLongException) { } - catch (System.ArgumentException) { } - - return Alphaleonis.Win32.Filesystem.File.Create(PrefixWithUNC(path)); - } - - public System.IO.FileAttributes GetFileAttributes(string path) - { - if (!IsPathTooLong(path)) - try { return System.IO.File.GetAttributes(path); } - catch (System.IO.PathTooLongException) { } - catch (System.ArgumentException) { } - - return (System.IO.FileAttributes)Alphaleonis.Win32.Filesystem.File.GetAttributes(PrefixWithUNC(path)); - } - - public void SetFileAttributes(string path, System.IO.FileAttributes attributes) - { - if (!IsPathTooLong(path)) - try - { - System.IO.File.SetAttributes(path, attributes); - return; - } - catch (System.IO.PathTooLongException) { } - catch (System.ArgumentException) { } - - Alphaleonis.Win32.Filesystem.File.SetAttributes(PrefixWithUNC(path), (FileAttributes)attributes); - } - - public void CreateSymlink(string symlinkfile, string target, bool asDir) - { - if (FileExists(symlinkfile) || DirectoryExists(symlinkfile)) - throw new System.IO.IOException(string.Format("File already exists: {0}", symlinkfile)); - Alphaleonis.Win32.Filesystem.File.CreateSymbolicLink(PrefixWithUNC(symlinkfile), target, asDir ? Alphaleonis.Win32.Filesystem.SymbolicLinkTarget.Directory : Alphaleonis.Win32.Filesystem.SymbolicLinkTarget.File, AlphaFS.PathFormat.LongFullPath); - - //Sadly we do not get a notification if the creation fails :( - System.IO.FileAttributes attr = 0; - if ((!asDir && FileExists(symlinkfile)) || (asDir && DirectoryExists(symlinkfile))) - try { attr = GetFileAttributes(symlinkfile); } - catch { } - - if ((attr & System.IO.FileAttributes.ReparsePoint) == 0) - throw new System.IO.IOException(string.Format("Unable to create symlink, check account permissions: {0}", symlinkfile)); - } - - /// - /// Returns the symlink target if the entry is a symlink, and null otherwise - /// - /// The file or folder to examine - /// The symlink target - public string GetSymlinkTarget(string file) - { - try - { - try - { - return AlphaFS.File.GetLinkTargetInfo(file).PrintName; - } - catch (PathTooLongException) { } - - return AlphaFS.File.GetLinkTargetInfo(SystemIOWindows.PrefixWithUNC(file)).PrintName; - } - catch (AlphaFS.NotAReparsePointException) { } - catch (AlphaFS.UnrecognizedReparsePointException) { } - - // This path looks like it isn't actually a symlink - // (Note that some reparse points aren't actually symlinks - - // things like the OneDrive folder in the Windows 10 Fall Creator's Update for example) - return null; - } - - public IEnumerable EnumerateFileSystemEntries(string path) - { - if (!IsPathTooLong(path)) - try { return System.IO.Directory.EnumerateFileSystemEntries(path); } - catch (System.IO.PathTooLongException) { } - catch (System.ArgumentException) { } - - var r = Alphaleonis.Win32.Filesystem.Directory.GetFileSystemEntries(PrefixWithUNC(path)); - for (var i = 0; i < r.Length; i++) - r[i] = StripUNCPrefix(r[i]); - - return r; - } - - public string PathGetFileName(string path) - { - if (!IsPathTooLong(path)) - try { return System.IO.Path.GetFileName(path); } - catch (System.IO.PathTooLongException) { } - catch (System.ArgumentException) { } - - return StripUNCPrefix(Alphaleonis.Win32.Filesystem.Path.GetFileName(PrefixWithUNC(path))); - } - - public string PathGetDirectoryName(string path) - { - if (!IsPathTooLong(path)) - try { return System.IO.Path.GetDirectoryName(path); } - catch (System.IO.PathTooLongException) { } - catch (System.ArgumentException) { } - - return StripUNCPrefix(Alphaleonis.Win32.Filesystem.Path.GetDirectoryName(PrefixWithUNC(path))); - } - - public string PathGetExtension(string path) - { - if (!IsPathTooLong(path)) - try { return System.IO.Path.GetExtension(path); } - catch (System.IO.PathTooLongException) { } - catch (System.ArgumentException) { } - - return StripUNCPrefix(Alphaleonis.Win32.Filesystem.Path.GetExtension(PrefixWithUNC(path))); - } - - public string PathChangeExtension(string path, string extension) - { - if (!IsPathTooLong(path)) - try { return System.IO.Path.ChangeExtension(path, extension); } - catch (System.IO.PathTooLongException) { } - catch (System.ArgumentException) { } - - return StripUNCPrefix(Alphaleonis.Win32.Filesystem.Path.ChangeExtension(PrefixWithUNC(path), extension)); - } - - public string PathCombine(params string[] paths) - { - var combinedPath = ""; - for (int i = 0; i < paths.Length; i++) - { - if (i == 0) - { - combinedPath = paths[i]; - } - else - { - if (!IsPathTooLong(combinedPath + "\\" + paths[i])) - { - try - { - combinedPath = Path.Combine(combinedPath, paths[i]); - } - catch (Exception ex) when (ex is System.IO.PathTooLongException || ex is System.ArgumentException) { - //TODO: Explain why we need to keep prefixing and stripping UNC's. - combinedPath = StripUNCPrefix(Alphaleonis.Win32.Filesystem.Path.Combine(PrefixWithUNC(combinedPath), paths[i])); - } - } - } - } - - return combinedPath; - } - - public void DirectorySetLastWriteTimeUtc(string path, DateTime time) - { - if (!IsPathTooLong(path)) - try - { - System.IO.Directory.SetLastWriteTimeUtc(path, time); - return; - } - catch (System.IO.PathTooLongException) { } - catch (System.ArgumentException) { } - - - Alphaleonis.Win32.Filesystem.File.SetLastWriteTimeUtc(PrefixWithUNC(path), time); - } - - public void DirectorySetCreationTimeUtc(string path, DateTime time) - { - if (!IsPathTooLong(path)) - try - { - System.IO.Directory.SetCreationTimeUtc(path, time); - return; - } - catch (System.IO.PathTooLongException) { } - catch (System.ArgumentException) { } - - Alphaleonis.Win32.Filesystem.File.SetCreationTimeUtc(PrefixWithUNC(path), time); - } - - public DateTime DirectoryGetLastWriteTimeUtc(string path) - { - if (!IsPathTooLong(path)) - try - { - return System.IO.Directory.GetLastWriteTimeUtc(path); - } - catch (System.IO.PathTooLongException) { } - catch (System.ArgumentException) { } - - return Alphaleonis.Win32.Filesystem.Directory.GetLastWriteTimeUtc(PrefixWithUNC(path)); - } - - public DateTime DirectoryGetCreationTimeUtc(string path) - { - if (!IsPathTooLong(path)) - try - { - return System.IO.Directory.GetCreationTimeUtc(path); - } - catch (System.IO.PathTooLongException) { } - catch (System.ArgumentException) { } - - return Alphaleonis.Win32.Filesystem.Directory.GetCreationTimeUtc(PrefixWithUNC(path)); - } - - public void FileMove(string source, string target) - { - if (!IsPathTooLong(source) && !IsPathTooLong(target)) - try - { - System.IO.File.Move(source, target); - return; - } - catch (System.IO.PathTooLongException) { } - catch (System.ArgumentException) { } - - Alphaleonis.Win32.Filesystem.File.Move(PrefixWithUNC(source), PrefixWithUNC(target)); - } - - public long FileLength(string path) - { - if (!IsPathTooLong(path)) - try { return new System.IO.FileInfo(path).Length; } - catch (System.IO.PathTooLongException) { } - catch (System.ArgumentException) { } - - return new Alphaleonis.Win32.Filesystem.FileInfo(PrefixWithUNC(path)).Length; - } - - public void DirectoryDelete(string path, bool recursive) - { - if (!IsPathTooLong(path)) - try - { - System.IO.Directory.Delete(path, recursive); - return; - } - catch (System.IO.PathTooLongException) { } - catch (System.ArgumentException) { } - - Alphaleonis.Win32.Filesystem.Directory.Delete(PrefixWithUNC(path), recursive); - } - - private class FileSystemAccess - { - public FileSystemRights Rights; - public AccessControlType ControlType; - public string SID; - public bool Inherited; - public InheritanceFlags Inheritance; - public PropagationFlags Propagation; - - public FileSystemAccess() - { - } - - public FileSystemAccess(FileSystemAccessRule rule) - { - Rights = rule.FileSystemRights; - ControlType = rule.AccessControlType; - SID = rule.IdentityReference.Value; - Inherited = rule.IsInherited; - Inheritance = rule.InheritanceFlags; - Propagation = rule.PropagationFlags; - } - - public FileSystemAccessRule Create(System.Security.AccessControl.FileSystemSecurity owner) - { - return (FileSystemAccessRule)owner.AccessRuleFactory( - new System.Security.Principal.SecurityIdentifier(SID), - (int)Rights, - Inherited, - Inheritance, - Propagation, - ControlType); - } - } - - private string SerializeObject(T o) - { - using(var tw = new System.IO.StringWriter()) - { - Newtonsoft.Json.JsonSerializer.Create(new Newtonsoft.Json.JsonSerializerSettings() { Culture = System.Globalization.CultureInfo.InvariantCulture }).Serialize(tw, o); - tw.Flush(); - return tw.ToString(); - } - } - - private T DeserializeObject(string data) - { - using(var tr = new System.IO.StringReader(data)) - return (T)Newtonsoft.Json.JsonSerializer.Create(new Newtonsoft.Json.JsonSerializerSettings() { Culture = System.Globalization.CultureInfo.InvariantCulture }).Deserialize(tr, typeof(T)); - - } - - private System.Security.AccessControl.FileSystemSecurity GetAccessControlDir(string path) - { - if (!IsPathTooLong(path)) - try { return System.IO.Directory.GetAccessControl(path); } - catch (System.IO.PathTooLongException) { } - catch (System.ArgumentException) { } - - return Alphaleonis.Win32.Filesystem.Directory.GetAccessControl(PrefixWithUNC(path)); - } - - private System.Security.AccessControl.FileSystemSecurity GetAccessControlFile(string path) - { - if (!IsPathTooLong(path)) - try { return System.IO.File.GetAccessControl(path); } - catch (System.IO.PathTooLongException) { } - catch (System.ArgumentException) { } - - return Alphaleonis.Win32.Filesystem.File.GetAccessControl(PrefixWithUNC(path)); - } - - private void SetAccessControlFile(string path, FileSecurity rules) - { - if (!IsPathTooLong(path)) - try - { - System.IO.File.SetAccessControl(path, rules); - return; - } - catch (System.IO.PathTooLongException) { } - catch (System.ArgumentException) { } - - Alphaleonis.Win32.Filesystem.File.SetAccessControl(PrefixWithUNC(path), rules, AccessControlSections.All); - } - - private void SetAccessControlDir(string path, DirectorySecurity rules) - { - if (!IsPathTooLong(path)) - try - { - System.IO.Directory.SetAccessControl(path, rules); - return; - } - catch (System.IO.PathTooLongException) { } - catch (System.ArgumentException) { } - - Alphaleonis.Win32.Filesystem.Directory.SetAccessControl(PrefixWithUNC(path), rules, AccessControlSections.All); - } - - public Dictionary GetMetadata(string path, bool isSymlink, bool followSymlink) - { - var isDirTarget = path.EndsWith(DIRSEP, StringComparison.Ordinal); - var targetpath = isDirTarget ? path.Substring(0, path.Length - 1) : path; - var dict = new Dictionary(); - - System.Security.AccessControl.FileSystemSecurity rules; - - if (isDirTarget) - rules = GetAccessControlDir(targetpath); - else - rules = GetAccessControlFile(targetpath); - - var objs = new List(); - foreach(var f in rules.GetAccessRules(true, false, typeof(System.Security.Principal.SecurityIdentifier))) - objs.Add(new FileSystemAccess((FileSystemAccessRule)f)); - - dict["win-ext:accessrules"] = SerializeObject(objs); - - return dict; - } - - public void SetMetadata(string path, Dictionary data, bool restorePermissions) - { - var isDirTarget = path.EndsWith(DIRSEP, StringComparison.Ordinal); - var targetpath = isDirTarget ? path.Substring(0, path.Length - 1) : path; - - System.Security.AccessControl.FileSystemSecurity rules; - - if (isDirTarget) - rules = GetAccessControlDir(targetpath); - else - rules = GetAccessControlFile(targetpath); - - if (restorePermissions && data.ContainsKey("win-ext:accessrules")) - { - var content = DeserializeObject(data["win-ext:accessrules"]); - var c = rules.GetAccessRules(true, false, typeof(System.Security.Principal.SecurityIdentifier)); - for(var i = c.Count - 1; i >= 0; i--) - rules.RemoveAccessRule((System.Security.AccessControl.FileSystemAccessRule)c[i]); - - Exception ex = null; - - foreach (var r in content) - { - // Attempt to apply as many rules as we can - try - { - rules.AddAccessRule((System.Security.AccessControl.FileSystemAccessRule)r.Create(rules)); - } - catch(Exception e) - { - ex = e; - } - } - - if (ex != null) - throw ex; - - if (isDirTarget) - SetAccessControlDir(targetpath, (DirectorySecurity)rules); - else - SetAccessControlFile(targetpath, (FileSecurity)rules); - } - } - - public string GetPathRoot(string path) - { - if (!IsPathTooLong(path)) - { - try { return Path.GetPathRoot(path); } - catch (System.IO.PathTooLongException) { } - catch (System.ArgumentException) { } - } - return AlphaFS.Path.GetPathRoot(path); - } - - public string[] GetDirectories(string path) - { - if (!IsPathTooLong(path)) - { - try { return Directory.GetDirectories(path); } - catch (System.IO.PathTooLongException) { } - catch (System.ArgumentException) { } - } - - return AlphaFS.Directory.GetDirectories(path); - } - - public string[] GetFiles(string path) - { - if (!IsPathTooLong(path)) - { - try { return Directory.GetFiles(path); } - catch (System.IO.PathTooLongException) { } - catch (System.ArgumentException) { } - } - - return AlphaFS.Directory.GetFiles(path); - } - - public string[] GetFiles(string path, string searchPattern) - { - if (!IsPathTooLong(path)) - { - try { return Directory.GetFiles(path, searchPattern); } - catch (System.IO.PathTooLongException) { } - catch (System.ArgumentException) { } - } - - return AlphaFS.Directory.GetFiles(path, searchPattern); - } - - public DateTime GetCreationTimeUtc(string path) - { - if (!IsPathTooLong(path)) - { - try { return Directory.GetCreationTimeUtc(path); } - catch (System.IO.PathTooLongException) { } - catch (System.ArgumentException) { } - } - - return AlphaFS.File.GetCreationTimeUtc(path); - } - - public DateTime GetLastWriteTimeUtc(string path) - { - if (!IsPathTooLong(path)) - { - try { return Directory.GetLastWriteTimeUtc(path); } - catch (System.IO.PathTooLongException) { } - catch (System.ArgumentException) { } - } - - return AlphaFS.File.GetLastWriteTimeUtc(path); - } - - public IEnumerable EnumerateDirectories(string path) - { - if (!IsPathTooLong(path)) - { - try { return Directory.EnumerateDirectories(path); } - catch (System.IO.PathTooLongException) { } - catch (System.ArgumentException) { } - } - - return AlphaFS.Directory.EnumerateDirectories(path); - } - - public void FileCopy(string source, string target, bool overwrite) - { - if (!IsPathTooLong(source) && !IsPathTooLong(target)) - { - try { File.Copy(source, target, overwrite); } - catch (System.IO.PathTooLongException) { } - catch (System.ArgumentException) { } - } - - AlphaFS.File.Copy(source, target, overwrite); - } - - public string PathGetFullPath(string path) - { - if (!IsPathTooLong(path)) - { - try { return System.IO.Path.GetFullPath(path); } - catch (System.IO.PathTooLongException) { } - catch (System.ArgumentException) { } - } - - return AlphaFS.Path.GetFullPath(path); - } - - public IFileEntry DirectoryEntry(string path) - { - if (!IsPathTooLong(path)) - { - try - { - var dInfo = new DirectoryInfo(path); - return new FileEntry(dInfo.Name, 0, dInfo.LastAccessTime, dInfo.LastWriteTime) - { - IsFolder = true - }; - } - catch (System.IO.PathTooLongException) { } - catch (System.ArgumentException) { } - } - - var dInfoAlphaFS = new AlphaFS.DirectoryInfo(path); - return new FileEntry(dInfoAlphaFS.Name, 0, dInfoAlphaFS.LastAccessTime, dInfoAlphaFS.LastWriteTime) - { - IsFolder = true - }; - } - - public IFileEntry FileEntry(string path) - { - if (!IsPathTooLong(path)) - { - try - { - var fileInfo = new FileInfo(path); - return new FileEntry(fileInfo.Name, fileInfo.Length, fileInfo.LastAccessTime, fileInfo.LastWriteTime); - } - catch (System.IO.PathTooLongException) { } - catch (System.ArgumentException) { } - } - - var fInfoAlphaFS = new AlphaFS.FileInfo(path); - return new FileEntry(fInfoAlphaFS.Name, fInfoAlphaFS.Length, fInfoAlphaFS.LastAccessTime, fInfoAlphaFS.LastWriteTime); - } - - #endregion - } -} - diff --git a/Duplicati/Library/IO/Util.cs b/Duplicati/Library/IO/Util.cs deleted file mode 100644 index 52287fcce..000000000 --- a/Duplicati/Library/IO/Util.cs +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (C) 2018, The Duplicati Team -// http://www.duplicati.com, info@duplicati.com -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -using System; -using System.IO; - -namespace Duplicati.Library.IO -{ - public static class Util - { - /// - /// A cached instance of the directory separator as a string - /// - public static readonly string DirectorySeparatorString = Path.DirectorySeparatorChar.ToString(); - - public static readonly string AltDirectorySeparatorString = Path.AltDirectorySeparatorChar.ToString(); - - /// - /// Appends the appropriate directory separator to paths, depending on OS. - /// Does not append the separator if the path already ends with it. - /// - /// The path to append to - /// The path with the directory separator appended - public static string AppendDirSeparator(string path) - { - return AppendDirSeparator(path, DirectorySeparatorString); - } - - /// - /// Appends the specified directory separator to paths. - /// Does not append the separator if the path already ends with it. - /// - /// The path to append to - /// The directory separator to use - /// The path with the directory separator appended - public static string AppendDirSeparator(string path, string separator) - { - return !path.EndsWith(separator, StringComparison.Ordinal) ? path + separator : path; - } - - - /// - /// Guesses the directory separator from the path - /// - /// The path to guess the separator from - /// The guessed directory separator - public static string GuessDirSeparator(string path) - { - return string.IsNullOrWhiteSpace(path) || path.StartsWith("/", StringComparison.Ordinal) ? "/" : "\\"; - } - } -} diff --git a/Duplicati/Library/IO/VssBackupComponents.cs b/Duplicati/Library/IO/VssBackupComponents.cs deleted file mode 100644 index 0368310a9..000000000 --- a/Duplicati/Library/IO/VssBackupComponents.cs +++ /dev/null @@ -1,308 +0,0 @@ -// Copyright (C) 2018, The Duplicati Team -// http://www.duplicati.com, info@duplicati.com -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using Alphaleonis.Win32.Vss; - -namespace Duplicati.Library.IO -{ - public class WriterMetaData - { - public string Name { get; set; } - public string LogicalPath { get; set; } - public Guid Guid { get; set; } - public List Paths { get; set; } - } - - public class VssBackupComponents : IDisposable - { - /// - /// The tag used for logging messages - /// - public static readonly string LOGTAG = Logging.Log.LogTagFromType(); - - - private IVssBackupComponents _vssBackupComponents; - - /// - /// The list of snapshot ids for each volume, key is the path root, eg C:\. - /// The dictionary is case insensitive - /// - private Dictionary _volumes; - - /// - /// The mapping of snapshot sources to their snapshot entries , key is the path root, eg C:\. - /// The dictionary is case insensitive - /// - private Dictionary _volumeMap; - - /// - /// Reverse mapping for speed up. - /// - private Dictionary _volumeReverseMap; - - /// - /// A list of mapped drives - /// - private List _mappedDrives; - - public VssBackupComponents() - { - _vssBackupComponents = VssBackupComponentsHelper.GetVssBackupComponents(); - } - - public void SetupWriters(Guid[] includedWriters, Guid[] excludedWriters) - { - if (includedWriters != null && includedWriters.Length > 0) - _vssBackupComponents.EnableWriterClasses(includedWriters); - - if (excludedWriters != null && excludedWriters.Length > 0) - _vssBackupComponents.DisableWriterClasses(excludedWriters.ToArray()); - - try - { - _vssBackupComponents.GatherWriterMetadata(); - } - finally - { - _vssBackupComponents.FreeWriterMetadata(); - } - - // check if writers got enabled - foreach (var writerGUID in includedWriters) - { - if (!_vssBackupComponents.WriterMetadata.Any(o => o.WriterId.Equals(writerGUID))) - { - throw new Exception(string.Format("Writer with GUID {0} was not added to VSS writer set.", writerGUID.ToString())); - } - } - } - - public void MapDrives() - { - _mappedDrives = new List(); - foreach (var k in new List(_volumeMap.Keys)) - { - try - { - DefineDosDevice d = new DefineDosDevice(_volumeMap[k]); - _mappedDrives.Add(d); - _volumeMap[k] = Util.AppendDirSeparator(d.Drive); - } - catch (Exception ex) - { - Logging.Log.WriteVerboseMessage(LOGTAG, "SubstMappingfailed", ex, "Failed to map VSS path {0} to drive", k); - } - } - } - - public void MapVolumesToSnapShots() - { - _volumeMap = new Dictionary(StringComparer.OrdinalIgnoreCase); - foreach (var kvp in _volumes) - { - _volumeMap.Add(kvp.Key, _vssBackupComponents.GetSnapshotProperties(kvp.Value).SnapshotDeviceObject); - } - - _volumeReverseMap = _volumeMap.ToDictionary(x => x.Value, x => x.Key); - } - - public Dictionary SnapshotDeviceAndVolumes - { - get { - return _volumeReverseMap; - } - - } - - private List GetPathsFromComponent(IVssWMComponent component) - { - var paths = new List(); - - foreach (var file in component.Files) - { - if (file.FileSpecification.Contains("*")) - { - if (Directory.Exists(Util.AppendDirSeparator(file.Path))) - paths.Add(Util.AppendDirSeparator(file.Path)); - } - else - { - var fileWithSpec = SystemIO.IO_WIN.PathCombine(file.Path, file.FileSpecification); - if (File.Exists(fileWithSpec)) - paths.Add(fileWithSpec); - } - } - return paths; - - } - - /// - /// Enumerable to iterate over components of the given writers. - /// Returns an WriterMetaData object containing GUID, component name, logical path and paths of the component. - /// - /// Anonymous object containing GUID, component name, logical path and paths of the component. - /// Writers. - public IEnumerable ParseWriterMetaData(Guid[] writers) - { - // check if writers got enabled - foreach (var writerGUID in writers) - { - var writer = _vssBackupComponents.WriterMetadata.First(o => o.WriterId.Equals(writerGUID)); - foreach (var component in writer.Components) - { - yield return new WriterMetaData{ Guid = writerGUID, - Name = component.ComponentName, - LogicalPath = component.LogicalPath, - Paths = GetPathsFromComponent(component) }; - } - } - } - - - public void InitShadowVolumes(IEnumerable sources) - { - _vssBackupComponents.StartSnapshotSet(); - - CheckSupportedVolumes(sources); - - //Make all writers aware that we are going to do the backup - _vssBackupComponents.PrepareForBackup(); - - //Create the shadow volumes - _vssBackupComponents.DoSnapshotSet(); - } - - public string GetVolumeFromCache(string path) - { - if (!_volumeMap.TryGetValue(path, out var volumePath)) - throw new InvalidOperationException(); - - return volumePath; - } - - - public void CheckSupportedVolumes(IEnumerable sources) - { - //Figure out which volumes are in the set - _volumes = new Dictionary(StringComparer.OrdinalIgnoreCase); - foreach (var s in sources) - { - var drive = SystemIO.IO_WIN.GetPathRoot(s); - if (!_volumes.ContainsKey(drive)) - { - if (!_vssBackupComponents.IsVolumeSupported(drive)) - { - throw new VssVolumeNotSupportedException(drive); - } - - _volumes.Add(drive, _vssBackupComponents.AddToSnapshotSet(drive)); - } - } - } - - public void Dispose() - { - try - { - if (_mappedDrives != null) - { - foreach (var d in _mappedDrives) - { - d.Dispose(); - } - - _mappedDrives = null; - } - } - catch (Exception ex) - { - Logging.Log.WriteVerboseMessage(LOGTAG, "MappedDriveCleanupError", ex, "Failed during VSS mapped drive unmapping"); - } - - try - { - _vssBackupComponents?.BackupComplete(); - } - catch (Exception ex) - { - Logging.Log.WriteVerboseMessage(LOGTAG, "VSSTerminateError", ex, "Failed to signal VSS completion"); - } - - try - { - if (_vssBackupComponents != null) - { - foreach (var g in _volumes.Values) - { - try - { - _vssBackupComponents.DeleteSnapshot(g, false); - } - catch (Exception ex) - { - Logging.Log.WriteVerboseMessage(LOGTAG, "VSSSnapShotDeleteError", ex, "Failed to close VSS snapshot"); - } - } - } - } - catch (Exception ex) - { - Logging.Log.WriteVerboseMessage(LOGTAG, "VSSSnapShotDeleteCleanError", ex, "Failed during VSS esnapshot closing"); - } - - if (_vssBackupComponents != null) - { - _vssBackupComponents.Dispose(); - _vssBackupComponents = null; - } - } - } - - - public static class VssBackupComponentsHelper - { - public static IVssBackupComponents GetVssBackupComponents() - { - //Prepare the backup - IVssBackupComponents m_backup = CreateVssBackupComponents(); - m_backup.InitializeForBackup(null); - m_backup.SetContext(VssSnapshotContext.Backup); - m_backup.SetBackupState(false, true, VssBackupType.Full, false); - - return m_backup; - } - - public static IVssBackupComponents CreateVssBackupComponents() - { - // Substitute for calling VssUtils.LoadImplementation(), as we have the dlls outside the GAC - var assemblyLocation = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); - if (assemblyLocation == null) - throw new InvalidOperationException(); - - //Here we don't need a custom Path.Combine: we need unconditional access to alphaFS - var alphadll = Path.Combine(assemblyLocation, "alphavss", VssUtils.GetPlatformSpecificAssemblyShortName() + ".dll"); - var vss = (IVssImplementation)System.Reflection.Assembly.LoadFile(alphadll).CreateInstance("Alphaleonis.Win32.Vss.VssImplementation"); - if (vss == null) - throw new InvalidOperationException(); - - return vss.CreateVssBackupComponents(); - } - } -} diff --git a/Duplicati/Library/Main/Controller.cs b/Duplicati/Library/Main/Controller.cs index 216a48742..b4fa50e91 100644 --- a/Duplicati/Library/Main/Controller.cs +++ b/Duplicati/Library/Main/Controller.cs @@ -23,7 +23,7 @@ using System.Linq; using System; using System.Collections.Generic; using Duplicati.Library.Utility; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.Library.Main { diff --git a/Duplicati/Library/Main/Database/LocalBugReportDatabase.cs b/Duplicati/Library/Main/Database/LocalBugReportDatabase.cs index fe9fc40c0..15be9fb4e 100644 --- a/Duplicati/Library/Main/Database/LocalBugReportDatabase.cs +++ b/Duplicati/Library/Main/Database/LocalBugReportDatabase.cs @@ -16,7 +16,7 @@ // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA using System; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.Library.Main.Database { diff --git a/Duplicati/Library/Main/Database/LocalListDatabase.cs b/Duplicati/Library/Main/Database/LocalListDatabase.cs index abd2f4a8e..77f7de6ac 100644 --- a/Duplicati/Library/Main/Database/LocalListDatabase.cs +++ b/Duplicati/Library/Main/Database/LocalListDatabase.cs @@ -19,7 +19,7 @@ using System; using System.Linq; using System.Collections.Generic; using System.Text; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.Library.Main.Database { diff --git a/Duplicati/Library/Main/Database/LocalRestoreDatabase.cs b/Duplicati/Library/Main/Database/LocalRestoreDatabase.cs index 3e82f3d93..e36b6f543 100644 --- a/Duplicati/Library/Main/Database/LocalRestoreDatabase.cs +++ b/Duplicati/Library/Main/Database/LocalRestoreDatabase.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; using Duplicati.Library.Main.Volumes; namespace Duplicati.Library.Main.Database diff --git a/Duplicati/Library/Main/Database/PathLookupHelper.cs b/Duplicati/Library/Main/Database/PathLookupHelper.cs index d0d693f2c..ba734cab9 100644 --- a/Duplicati/Library/Main/Database/PathLookupHelper.cs +++ b/Duplicati/Library/Main/Database/PathLookupHelper.cs @@ -19,7 +19,7 @@ using System; using System.IO; using System.Linq; using System.Collections.Generic; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.Library.Main.Database { diff --git a/Duplicati/Library/Main/Duplicati.Library.Main.csproj b/Duplicati/Library/Main/Duplicati.Library.Main.csproj index 23a7ce837..9515d77f8 100644 --- a/Duplicati/Library/Main/Duplicati.Library.Main.csproj +++ b/Duplicati/Library/Main/Duplicati.Library.Main.csproj @@ -187,7 +187,7 @@ {D63E53E4-A458-4C2F-914D-92F715F58ACF} - Duplicati.Library.IO + Duplicati.Library.Common diff --git a/Duplicati/Library/Main/Operation/Backup/FileEnumerationProcess.cs b/Duplicati/Library/Main/Operation/Backup/FileEnumerationProcess.cs index 7294afecb..ec924dbfe 100644 --- a/Duplicati/Library/Main/Operation/Backup/FileEnumerationProcess.cs +++ b/Duplicati/Library/Main/Operation/Backup/FileEnumerationProcess.cs @@ -23,7 +23,7 @@ using System.Linq; using Duplicati.Library.Interface; using Duplicati.Library.Main.Operation.Common; using Duplicati.Library.Snapshots; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.Library.Main.Operation.Backup { @@ -289,7 +289,7 @@ namespace Duplicati.Library.Main.Operation.Backup { foreach (var n in ignorenames) { - var ignorepath = SystemIO.IO_OS(Library.Utility.Utility.IsClientWindows).PathCombine(path, n); + var ignorepath = SystemIO.IO_OS.PathCombine(path, n); if (snapshot.FileExists(ignorepath)) { Logging.Log.WriteVerboseMessage(FILTER_LOGTAG, "ExcludingPathDueToIgnoreFile", "Excluding path because ignore file was found: {0}", ignorepath); diff --git a/Duplicati/Library/Main/Operation/BackupHandler.cs b/Duplicati/Library/Main/Operation/BackupHandler.cs index 679d47510..d83086703 100644 --- a/Duplicati/Library/Main/Operation/BackupHandler.cs +++ b/Duplicati/Library/Main/Operation/BackupHandler.cs @@ -32,7 +32,7 @@ using CoCoL; using System.Threading; using Duplicati.Library.Snapshots; using Duplicati.Library.Utility; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.Library.Main.Operation { diff --git a/Duplicati/Library/Main/Operation/RestoreHandler.cs b/Duplicati/Library/Main/Operation/RestoreHandler.cs index 5ab45830e..b661a061b 100644 --- a/Duplicati/Library/Main/Operation/RestoreHandler.cs +++ b/Duplicati/Library/Main/Operation/RestoreHandler.cs @@ -1,9 +1,8 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; using Duplicati.Library.Interface; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; using Duplicati.Library.Main.Database; using Duplicati.Library.Main.Volumes; @@ -20,7 +19,6 @@ namespace Duplicati.Library.Main.Operation private readonly Options m_options; private byte[] m_blockbuffer; private readonly RestoreResults m_result; - private static readonly ISystemIO m_systemIO = SystemIO.IO_OS(Duplicati.Library.Utility.Utility.IsClientWindows); private static readonly string DIRSEP = Util.DirectorySeparatorString; public RestoreHandler(string backendurl, Options options, RestoreResults result) @@ -88,7 +86,7 @@ namespace Duplicati.Library.Main.Operation // If we have both target paths and a filter, combine into a single filter filter = Library.Utility.JoinedFilterExpression.Join(new Library.Utility.FilterExpression(paths), filter); - if (!m_options.NoLocalDb && m_systemIO.FileExists(m_options.Dbpath)) + if (!m_options.NoLocalDb && SystemIO.IO_OS.FileExists(m_options.Dbpath)) { using(var db = new LocalRestoreDatabase(m_options.Dbpath)) { @@ -162,16 +160,16 @@ namespace Duplicati.Library.Main.Operation try { - var folderpath = m_systemIO.PathGetDirectoryName(targetpath); - if (!options.Dryrun && !m_systemIO.DirectoryExists(folderpath)) + var folderpath = SystemIO.IO_OS.PathGetDirectoryName(targetpath); + if (!options.Dryrun && !SystemIO.IO_OS.DirectoryExists(folderpath)) { Logging.Log.WriteWarningMessage(LOGTAG, "CreateMissingFolder", null, "Creating missing folder {0} for file {1}", folderpath, targetpath); - m_systemIO.DirectoryCreate(folderpath); + SystemIO.IO_OS.DirectoryCreate(folderpath); } // TODO: Much faster if we iterate the volume and checks what blocks are used, // because the compressors usually like sequential reading - using(var file = m_systemIO.FileOpenWrite(targetpath)) + using(var file = SystemIO.IO_OS.FileOpenWrite(targetpath)) foreach(var targetblock in restorelist.Blocks) { file.Position = targetblock.Offset; @@ -270,10 +268,10 @@ namespace Duplicati.Library.Main.Operation try { var folderpath = Duplicati.Library.Utility.Utility.GetParent(targetpath, false); - if (!options.Dryrun && !m_systemIO.DirectoryExists(folderpath)) + if (!options.Dryrun && !SystemIO.IO_OS.DirectoryExists(folderpath)) { Logging.Log.WriteWarningMessage(LOGTAG, "CreateMissingFolder", null, "Creating missing folder {0} for target {1}", folderpath, targetpath); - m_systemIO.DirectoryCreate(folderpath); + SystemIO.IO_OS.DirectoryCreate(folderpath); } ApplyMetadata(targetpath, metainfo.Value, options.RestorePermissions, options.RestoreSymlinkMetadata, options.Dryrun); @@ -398,7 +396,7 @@ namespace Duplicati.Library.Main.Operation // Restore empty files. They might not have any blocks so don't appear in any volume. foreach (var file in database.GetFilesToRestore(true).Where(item => item.Length == 0)) { // Just create the file and close it right away, empty statement is intentional. - using (m_systemIO.FileCreate(file.Path)) + using (SystemIO.IO_OS.FileCreate(file.Path)) { } } @@ -438,7 +436,7 @@ namespace Duplicati.Library.Main.Operation string key; long size; - using(var fs = m_systemIO.FileOpenRead(file.Path)) + using(var fs = SystemIO.IO_OS.FileOpenRead(file.Path)) { size = fs.Length; key = Convert.ToBase64String(filehasher.ComputeHash(fs)); @@ -492,13 +490,13 @@ namespace Duplicati.Library.Main.Operation // Make the symlink first, otherwise we cannot apply metadata to it if (metadata.TryGetValue("CoreSymlinkTarget", out k)) - m_systemIO.CreateSymlink(targetpath, k, isDirTarget); + SystemIO.IO_OS.CreateSymlink(targetpath, k, isDirTarget); // If the target is a folder, make sure we create it first - else if (isDirTarget && !m_systemIO.DirectoryExists(targetpath)) - m_systemIO.DirectoryCreate(targetpath); + else if (isDirTarget && !SystemIO.IO_OS.DirectoryExists(targetpath)) + SystemIO.IO_OS.DirectoryCreate(targetpath); // Avoid setting restoring symlink metadata, as that writes the symlink target, not the symlink itself - if (!restoreSymlinkMetadata && Snapshots.SnapshotUtility.IsSymlink(m_systemIO, targetpath)) + if (!restoreSymlinkMetadata && Snapshots.SnapshotUtility.IsSymlink(SystemIO.IO_OS, targetpath)) { Logging.Log.WriteVerboseMessage(LOGTAG, "no-symlink-metadata-restored", "Not applying metadata to symlink: {0}", targetpath); return; @@ -507,23 +505,23 @@ namespace Duplicati.Library.Main.Operation if (metadata.TryGetValue("CoreLastWritetime", out k) && long.TryParse(k, out t)) { if (isDirTarget) - m_systemIO.DirectorySetLastWriteTimeUtc(targetpath, new DateTime(t, DateTimeKind.Utc)); + SystemIO.IO_OS.DirectorySetLastWriteTimeUtc(targetpath, new DateTime(t, DateTimeKind.Utc)); else - m_systemIO.FileSetLastWriteTimeUtc(targetpath, new DateTime(t, DateTimeKind.Utc)); + SystemIO.IO_OS.FileSetLastWriteTimeUtc(targetpath, new DateTime(t, DateTimeKind.Utc)); } if (metadata.TryGetValue("CoreCreatetime", out k) && long.TryParse(k, out t)) { if (isDirTarget) - m_systemIO.DirectorySetCreationTimeUtc(targetpath, new DateTime(t, DateTimeKind.Utc)); + SystemIO.IO_OS.DirectorySetCreationTimeUtc(targetpath, new DateTime(t, DateTimeKind.Utc)); else - m_systemIO.FileSetCreationTimeUtc(targetpath, new DateTime(t, DateTimeKind.Utc)); + SystemIO.IO_OS.FileSetCreationTimeUtc(targetpath, new DateTime(t, DateTimeKind.Utc)); } if (metadata.TryGetValue("CoreAttributes", out k) && Enum.TryParse(k, true, out fa)) - m_systemIO.SetFileAttributes(targetpath, fa); + SystemIO.IO_OS.SetFileAttributes(targetpath, fa); - m_systemIO.SetMetadata(path, metadata, restorePermissions); + SystemIO.IO_OS.SetMetadata(path, metadata, restorePermissions); } } @@ -542,20 +540,20 @@ namespace Duplicati.Library.Main.Operation try { - if (m_systemIO.FileExists(sourcepath)) + if (SystemIO.IO_OS.FileExists(sourcepath)) { - var folderpath = m_systemIO.PathGetDirectoryName(targetpath); - if (!options.Dryrun && !m_systemIO.DirectoryExists(folderpath)) + var folderpath = SystemIO.IO_OS.PathGetDirectoryName(targetpath); + if (!options.Dryrun && !SystemIO.IO_OS.DirectoryExists(folderpath)) { Logging.Log.WriteWarningMessage(LOGTAG, "CreateMissingFolder", null, "Creating missing folder {0} for file {1}", folderpath, targetpath); - m_systemIO.DirectoryCreate(folderpath); + SystemIO.IO_OS.DirectoryCreate(folderpath); } - using(var targetstream = options.Dryrun ? null : m_systemIO.FileOpenWrite(targetpath)) + using(var targetstream = options.Dryrun ? null : SystemIO.IO_OS.FileOpenWrite(targetpath)) { try { - using(var sourcestream = m_systemIO.FileOpenRead(sourcepath)) + using(var sourcestream = SystemIO.IO_OS.FileOpenRead(sourcepath)) { foreach(var block in entry.Blocks) { @@ -648,14 +646,14 @@ namespace Duplicati.Library.Main.Operation if (result.TaskControlRendevouz() == TaskControlState.Stop) return; - var folderpath = m_systemIO.PathGetDirectoryName(targetpath); - if (!options.Dryrun && !m_systemIO.DirectoryExists(folderpath)) + var folderpath = SystemIO.IO_OS.PathGetDirectoryName(targetpath); + if (!options.Dryrun && !SystemIO.IO_OS.DirectoryExists(folderpath)) { Logging.Log.WriteWarningMessage(LOGTAG, "CreateMissingFolder", null, "Creating missing folder {0} for file {1}", folderpath, targetpath); - m_systemIO.DirectoryCreate(folderpath); + SystemIO.IO_OS.DirectoryCreate(folderpath); } - using (var file = options.Dryrun ? null : m_systemIO.FileOpenWrite(targetpath)) + using (var file = options.Dryrun ? null : SystemIO.IO_OS.FileOpenWrite(targetpath)) foreach (var targetblock in restorelist.Blocks) { foreach (var source in targetblock.Blocksources) @@ -665,7 +663,7 @@ namespace Duplicati.Library.Main.Operation if (result.TaskControlRendevouz() == TaskControlState.Stop) return; - if (m_systemIO.FileExists(source.Path)) + if (SystemIO.IO_OS.FileExists(source.Path)) { if (source.IsMetadata) { @@ -676,7 +674,7 @@ namespace Duplicati.Library.Main.Operation } else { - using (var sourcefile = m_systemIO.FileOpenRead(source.Path)) + using (var sourcefile = SystemIO.IO_OS.FileOpenRead(source.Path)) { sourcefile.Position = source.Offset; int size = Library.Utility.Utility.ForceStreamRead(sourcefile, blockbuffer, blockbuffer.Length); @@ -778,14 +776,14 @@ namespace Duplicati.Library.Main.Operation { // This part is not protected by try/catch as we need the target folder to exist if (!string.IsNullOrEmpty(options.Restorepath)) - if (!m_systemIO.DirectoryExists(options.Restorepath)) + if (!SystemIO.IO_OS.DirectoryExists(options.Restorepath)) { Logging.Log.WriteVerboseMessage(LOGTAG, "CreateFolder", "Creating folder: {0}", options.Restorepath); if (options.Dryrun) Logging.Log.WriteDryrunMessage(LOGTAG, "WouldCreateFolder", "Would create folder: {0}", options.Restorepath); else - m_systemIO.DirectoryCreate(options.Restorepath); + SystemIO.IO_OS.DirectoryCreate(options.Restorepath); } foreach (var folder in database.GetTargetFolders()) @@ -795,7 +793,7 @@ namespace Duplicati.Library.Main.Operation if (result.TaskControlRendevouz() == TaskControlState.Stop) return; - if (!m_systemIO.DirectoryExists(folder)) + if (!SystemIO.IO_OS.DirectoryExists(folder)) { result.FoldersRestored++; @@ -804,7 +802,7 @@ namespace Duplicati.Library.Main.Operation if (options.Dryrun) Logging.Log.WriteDryrunMessage(LOGTAG, "WouldCreateFolder", "Would create folder: {0}", folder); else - m_systemIO.DirectoryCreate(folder); + SystemIO.IO_OS.DirectoryCreate(folder); } } catch (Exception ex) @@ -829,14 +827,14 @@ namespace Duplicati.Library.Main.Operation var targetfileid = restorelist.TargetFileID; var targetfilehash = restorelist.TargetHash; var targetfilelength = restorelist.Length; - if (m_systemIO.FileExists(targetpath)) + if (SystemIO.IO_OS.FileExists(targetpath)) { try { if (result.TaskControlRendevouz() == TaskControlState.Stop) return; - var currentfilelength = m_systemIO.FileLength(targetpath); + var currentfilelength = SystemIO.IO_OS.FileLength(targetpath); var wasTruncated = false; // Adjust file length in overwrite mode if necessary (smaller is ok, will be extended during restore) @@ -844,18 +842,18 @@ namespace Duplicati.Library.Main.Operation // be truncated (i.e. forthwritten log files). if (!rename && currentfilelength > targetfilelength) { - var currentAttr = m_systemIO.GetFileAttributes(targetpath); + var currentAttr = SystemIO.IO_OS.GetFileAttributes(targetpath); if ((currentAttr & System.IO.FileAttributes.ReadOnly) != 0) // clear readonly attribute { if (options.Dryrun) Logging.Log.WriteDryrunMessage(LOGTAG, "WouldResetReadOnlyAttribute", "Would reset read-only attribute on file: {0}", targetpath); - else m_systemIO.SetFileAttributes(targetpath, currentAttr & ~System.IO.FileAttributes.ReadOnly); + else SystemIO.IO_OS.SetFileAttributes(targetpath, currentAttr & ~System.IO.FileAttributes.ReadOnly); } if (options.Dryrun) Logging.Log.WriteDryrunMessage(LOGTAG, "WouldTruncateFile", "Would truncate file '{0}' to length of {1:N0} bytes", targetpath, targetfilelength); else { - using (var file = m_systemIO.FileOpenWrite(targetpath)) + using (var file = SystemIO.IO_OS.FileOpenWrite(targetpath)) file.SetLength(targetfilelength); currentfilelength = targetfilelength; } @@ -873,7 +871,7 @@ namespace Duplicati.Library.Main.Operation bool calcFileHash = (currentfilelength == targetfilelength); if (calcFileHash) filehasher.Initialize(); - using (var file = m_systemIO.FileOpenRead(targetpath)) + using (var file = SystemIO.IO_OS.FileOpenRead(targetpath)) using (var block = new Blockprocessor(file, blockbuffer)) foreach (var targetblock in restorelist.Blocks) { @@ -923,12 +921,12 @@ namespace Duplicati.Library.Main.Operation if (!rename && !fullfilehashmatch && !wasTruncated) // Reset read-only attribute (if set) to overwrite { - var currentAttr = m_systemIO.GetFileAttributes(targetpath); + var currentAttr = SystemIO.IO_OS.GetFileAttributes(targetpath); if ((currentAttr & System.IO.FileAttributes.ReadOnly) != 0) { if (options.Dryrun) Logging.Log.WriteDryrunMessage(LOGTAG, "WouldResetReadOnlyAttribyte", "Would reset read-only attribute on file: {0}", targetpath); - else m_systemIO.SetFileAttributes(targetpath, currentAttr & ~System.IO.FileAttributes.ReadOnly); + else SystemIO.IO_OS.SetFileAttributes(targetpath, currentAttr & ~System.IO.FileAttributes.ReadOnly); } } @@ -972,15 +970,15 @@ namespace Duplicati.Library.Main.Operation if (rename) { //Select a new filename - var ext = m_systemIO.PathGetExtension(targetpath) ?? ""; + var ext = SystemIO.IO_OS.PathGetExtension(targetpath) ?? ""; if (!string.IsNullOrEmpty(ext) && !ext.StartsWith(".", StringComparison.Ordinal)) ext = "." + ext; // First we try with a simple date append, assuming that there are not many conflicts there - var newname = m_systemIO.PathChangeExtension(targetpath, null) + "." + database.RestoreTime.ToLocalTime().ToString("yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture); + var newname = SystemIO.IO_OS.PathChangeExtension(targetpath, null) + "." + database.RestoreTime.ToLocalTime().ToString("yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture); var tr = newname + ext; var c = 0; - while (m_systemIO.FileExists(tr) && c < 1000) + while (SystemIO.IO_OS.FileExists(tr) && c < 1000) { try { @@ -989,7 +987,7 @@ namespace Duplicati.Library.Main.Operation filehasher.Initialize(); string key; - using(var file = m_systemIO.FileOpenRead(tr)) + using(var file = SystemIO.IO_OS.FileOpenRead(tr)) key = Convert.ToBase64String(filehasher.ComputeHash(file)); if (key == targetfilehash) diff --git a/Duplicati/Library/Snapshots/Duplicati.Library.Snapshots.csproj b/Duplicati/Library/Snapshots/Duplicati.Library.Snapshots.csproj index a59162cbe..4e709d6f2 100644 --- a/Duplicati/Library/Snapshots/Duplicati.Library.Snapshots.csproj +++ b/Duplicati/Library/Snapshots/Duplicati.Library.Snapshots.csproj @@ -92,7 +92,7 @@ {D63E53E4-A458-4C2F-914D-92F715F58ACF} - Duplicati.Library.IO + Duplicati.Library.Common diff --git a/Duplicati/Library/Snapshots/HyperVUtility.cs b/Duplicati/Library/Snapshots/HyperVUtility.cs index cdaa8ce84..f4ce0f060 100644 --- a/Duplicati/Library/Snapshots/HyperVUtility.cs +++ b/Duplicati/Library/Snapshots/HyperVUtility.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Management; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.Library.Snapshots { diff --git a/Duplicati/Library/Snapshots/LinuxSnapshot.cs b/Duplicati/Library/Snapshots/LinuxSnapshot.cs index a35fa2447..1e51a5498 100644 --- a/Duplicati/Library/Snapshots/LinuxSnapshot.cs +++ b/Duplicati/Library/Snapshots/LinuxSnapshot.cs @@ -22,7 +22,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Text; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.Library.Snapshots { diff --git a/Duplicati/Library/Snapshots/MSSQLUtility.cs b/Duplicati/Library/Snapshots/MSSQLUtility.cs index 7d92dd590..adcc2bdf5 100644 --- a/Duplicati/Library/Snapshots/MSSQLUtility.cs +++ b/Duplicati/Library/Snapshots/MSSQLUtility.cs @@ -1,4 +1,4 @@ -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; using System; using System.Collections.Generic; using System.Linq; diff --git a/Duplicati/Library/Snapshots/NoSnapshotLinux.cs b/Duplicati/Library/Snapshots/NoSnapshotLinux.cs index 441be3259..3a9e9d253 100644 --- a/Duplicati/Library/Snapshots/NoSnapshotLinux.cs +++ b/Duplicati/Library/Snapshots/NoSnapshotLinux.cs @@ -17,7 +17,7 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA using System.Collections.Generic; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.Library.Snapshots { diff --git a/Duplicati/Library/Snapshots/NoSnapshotWindows.cs b/Duplicati/Library/Snapshots/NoSnapshotWindows.cs index 85c0ab819..33db9c8d6 100644 --- a/Duplicati/Library/Snapshots/NoSnapshotWindows.cs +++ b/Duplicati/Library/Snapshots/NoSnapshotWindows.cs @@ -17,7 +17,7 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA using System; using System.Collections.Generic; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.Library.Snapshots { diff --git a/Duplicati/Library/Snapshots/SnapshotBase.cs b/Duplicati/Library/Snapshots/SnapshotBase.cs index ef831b433..e59118f44 100644 --- a/Duplicati/Library/Snapshots/SnapshotBase.cs +++ b/Duplicati/Library/Snapshots/SnapshotBase.cs @@ -23,7 +23,7 @@ using System.Linq; using System; using System.Collections.Generic; using System.IO; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.Library.Snapshots { diff --git a/Duplicati/Library/Snapshots/SnapshotUtility.cs b/Duplicati/Library/Snapshots/SnapshotUtility.cs index d81dbb44e..bddfd8201 100644 --- a/Duplicati/Library/Snapshots/SnapshotUtility.cs +++ b/Duplicati/Library/Snapshots/SnapshotUtility.cs @@ -20,7 +20,7 @@ using System.Collections.Generic; using System.IO; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.Library.Snapshots { diff --git a/Duplicati/Library/Snapshots/USNJournal.cs b/Duplicati/Library/Snapshots/USNJournal.cs index ce6a1c0ff..138e20d58 100644 --- a/Duplicati/Library/Snapshots/USNJournal.cs +++ b/Duplicati/Library/Snapshots/USNJournal.cs @@ -26,7 +26,7 @@ using System.Diagnostics; using System.Linq; using System.Runtime.InteropServices; using System.Runtime.Serialization; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; using Microsoft.Win32.SafeHandles; namespace Duplicati.Library.Snapshots diff --git a/Duplicati/Library/Snapshots/UsnJournalService.cs b/Duplicati/Library/Snapshots/UsnJournalService.cs index 132dea3fd..657543cc5 100644 --- a/Duplicati/Library/Snapshots/UsnJournalService.cs +++ b/Duplicati/Library/Snapshots/UsnJournalService.cs @@ -25,7 +25,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using Duplicati.Library.Interface; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; using Duplicati.Library.Utility; namespace Duplicati.Library.Snapshots diff --git a/Duplicati/Library/Snapshots/WindowsSnapshot.cs b/Duplicati/Library/Snapshots/WindowsSnapshot.cs index 542935128..826076ffa 100644 --- a/Duplicati/Library/Snapshots/WindowsSnapshot.cs +++ b/Duplicati/Library/Snapshots/WindowsSnapshot.cs @@ -23,7 +23,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.Library.Snapshots { diff --git a/Duplicati/Library/Utility/Duplicati.Library.Utility.csproj b/Duplicati/Library/Utility/Duplicati.Library.Utility.csproj index a146c9445..b2a35870f 100644 --- a/Duplicati/Library/Utility/Duplicati.Library.Utility.csproj +++ b/Duplicati/Library/Utility/Duplicati.Library.Utility.csproj @@ -111,7 +111,7 @@ {D63E53E4-A458-4C2F-914D-92F715F58ACF} - Duplicati.Library.IO + Duplicati.Library.Common diff --git a/Duplicati/Library/Utility/FilterGroups.cs b/Duplicati/Library/Utility/FilterGroups.cs index f3cb428e4..1e5582876 100644 --- a/Duplicati/Library/Utility/FilterGroups.cs +++ b/Duplicati/Library/Utility/FilterGroups.cs @@ -17,7 +17,7 @@ using System; using System.Collections.Generic; using System.Linq; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; using Duplicati.Library.Localization.Short; namespace Duplicati.Library.Utility diff --git a/Duplicati/Library/Utility/TempFile.cs b/Duplicati/Library/Utility/TempFile.cs index 8bb53370d..3f5f7f93c 100644 --- a/Duplicati/Library/Utility/TempFile.cs +++ b/Duplicati/Library/Utility/TempFile.cs @@ -1,4 +1,4 @@ -#region Disclaimer / License +#region Disclaimer / License // Copyright (C) 2015, The Duplicati Team // http://www.duplicati.com, info@duplicati.com // @@ -20,7 +20,7 @@ using System; using System.Collections.Generic; using System.Text; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.Library.Utility { @@ -90,7 +90,7 @@ namespace Duplicati.Library.Utility /// The application temp files. private static IEnumerable GetApplicationTempFiles() { - return SystemIO.IO_OS(Utility.IsClientWindows).GetFiles(TempFolder.SystemTempPath, APPLICATION_PREFIX + "*"); + return SystemIO.IO_OS.GetFiles(TempFolder.SystemTempPath, APPLICATION_PREFIX + "*"); } /// diff --git a/Duplicati/Library/Utility/TempFolder.cs b/Duplicati/Library/Utility/TempFolder.cs index 0a412bf73..8fb510090 100644 --- a/Duplicati/Library/Utility/TempFolder.cs +++ b/Duplicati/Library/Utility/TempFolder.cs @@ -18,7 +18,7 @@ // #endregion using System; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.Library.Utility { diff --git a/Duplicati/Library/Utility/Utility.cs b/Duplicati/Library/Utility/Utility.cs index ccb753c72..65ada56b8 100644 --- a/Duplicati/Library/Utility/Utility.cs +++ b/Duplicati/Library/Utility/Utility.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2015, The Duplicati Team +// Copyright (C) 2015, The Duplicati Team // http://www.duplicati.com, info@duplicati.com // // This library is free software; you can redistribute it and/or @@ -21,7 +21,7 @@ using System.Linq; using System.Threading.Tasks; using System.Text; using System.Text.RegularExpressions; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.Library.Utility { @@ -227,7 +227,7 @@ namespace Duplicati.Library.Utility /// A list of the full filenames public static IEnumerable EnumerateFileSystemEntries(string rootpath, EnumerationFilterDelegate callback) { - return EnumerateFileSystemEntries(rootpath, callback, SystemIO.IO_OS(Utility.IsClientWindows).GetDirectories, Directory.GetFiles); + return EnumerateFileSystemEntries(rootpath, callback, SystemIO.IO_OS.GetDirectories, Directory.GetFiles); } /// diff --git a/Duplicati/License/Duplicati.License.csproj b/Duplicati/License/Duplicati.License.csproj index af6ac8d0c..4ae90ee8e 100644 --- a/Duplicati/License/Duplicati.License.csproj +++ b/Duplicati/License/Duplicati.License.csproj @@ -429,7 +429,7 @@ {D63E53E4-A458-4C2F-914D-92F715F58ACF} - Duplicati.Library.IO + Duplicati.Library.Common {DE3E5D4C-51AB-4E5E-BEE8-E636CEBFBA65} diff --git a/Duplicati/License/LicenseReader.cs b/Duplicati/License/LicenseReader.cs index ebc48fe13..2cfffe7ce 100644 --- a/Duplicati/License/LicenseReader.cs +++ b/Duplicati/License/LicenseReader.cs @@ -1,4 +1,4 @@ -#region Disclaimer / License +#region Disclaimer / License // Copyright (C) 2015, The Duplicati Team // http://www.duplicati.com, info@duplicati.com // @@ -20,7 +20,7 @@ using System; using System.Collections.Generic; using System.Text; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; using Duplicati.Library.Utility; namespace Duplicati.License @@ -52,7 +52,7 @@ namespace Duplicati.License { List res = new List(); - string[] folders = SystemIO.IO_OS(Utility.IsClientWindows).GetDirectories(basefolder); + string[] folders = SystemIO.IO_OS.GetDirectories(basefolder); Array.Sort(folders); foreach (string folder in folders) diff --git a/Duplicati/Server/Duplicati.Server.csproj b/Duplicati/Server/Duplicati.Server.csproj index d34e81084..7cc6703f6 100644 --- a/Duplicati/Server/Duplicati.Server.csproj +++ b/Duplicati/Server/Duplicati.Server.csproj @@ -321,7 +321,7 @@ {D63E53E4-A458-4C2F-914D-92F715F58ACF} - Duplicati.Library.IO + Duplicati.Library.Common diff --git a/Duplicati/Server/Program.cs b/Duplicati/Server/Program.cs index 4dbd8ee54..1fe3844a4 100644 --- a/Duplicati/Server/Program.cs +++ b/Duplicati/Server/Program.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.Server { diff --git a/Duplicati/Server/SingleInstance.cs b/Duplicati/Server/SingleInstance.cs index 8fb16f8fd..aa52d2166 100644 --- a/Duplicati/Server/SingleInstance.cs +++ b/Duplicati/Server/SingleInstance.cs @@ -1,4 +1,4 @@ -#region Disclaimer / License +#region Disclaimer / License // Copyright (C) 2015, The Duplicati Team // http://www.duplicati.com, info@duplicati.com // @@ -20,7 +20,7 @@ using System; using System.Collections.Generic; using System.Text; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; using Duplicati.Library.Utility; namespace Duplicati.Server @@ -171,7 +171,7 @@ namespace Duplicati.Server DateTime startup = System.IO.File.GetLastWriteTime(m_lockfilename); //Clean up any files that were created before the app launched - foreach(string s in SystemIO.IO_OS(Utility.IsClientWindows).GetFiles(m_controldir)) + foreach(string s in SystemIO.IO_OS.GetFiles(m_controldir)) if (s != m_lockfilename && System.IO.File.GetCreationTime(s) < startup) try { System.IO.File.Delete(s); } catch { } diff --git a/Duplicati/Server/SpecialFolders.cs b/Duplicati/Server/SpecialFolders.cs index 268c33910..7c3334aa7 100644 --- a/Duplicati/Server/SpecialFolders.cs +++ b/Duplicati/Server/SpecialFolders.cs @@ -18,7 +18,7 @@ using System; using System.Linq; using System.Collections.Generic; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.Server { @@ -148,8 +148,6 @@ namespace Duplicati.Server internal static Dictionary GetSourceNames(Serialization.Interface.IBackup backup) { - var systemIO = SystemIO.IO_OS(Library.Utility.Utility.IsClientWindows); - if (backup.Sources == null || backup.Sources.Length == 0) return new Dictionary(); @@ -165,7 +163,7 @@ namespace Duplicati.Server var nx = x; if (nx.EndsWith(Util.DirectorySeparatorString, StringComparison.Ordinal)) nx = nx.Substring(0, nx.Length - 1); - var n = systemIO.PathGetFileName(nx); + var n = SystemIO.IO_OS.PathGetFileName(nx); if (!string.IsNullOrWhiteSpace(n)) return new KeyValuePair(x, n); } diff --git a/Duplicati/Server/WebServer/IndexHtmlHandler.cs b/Duplicati/Server/WebServer/IndexHtmlHandler.cs index dd9d78a85..508264719 100644 --- a/Duplicati/Server/WebServer/IndexHtmlHandler.cs +++ b/Duplicati/Server/WebServer/IndexHtmlHandler.cs @@ -20,7 +20,7 @@ using System.Linq; using HttpServer; using HttpServer.HttpModules; using HttpServer.Exceptions; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.Server.WebServer { diff --git a/Duplicati/Server/WebServer/RESTMethods/Acknowledgements.cs b/Duplicati/Server/WebServer/RESTMethods/Acknowledgements.cs index 2183fd4e1..6ca1bd459 100644 --- a/Duplicati/Server/WebServer/RESTMethods/Acknowledgements.cs +++ b/Duplicati/Server/WebServer/RESTMethods/Acknowledgements.cs @@ -16,7 +16,7 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA using System; using System.Collections.Generic; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; using Duplicati.Library.Utility; namespace Duplicati.Server.WebServer.RESTMethods @@ -31,7 +31,7 @@ namespace Duplicati.Server.WebServer.RESTMethods public void GET(string key, RequestInfo info) { - var path = SystemIO.IO_OS(Utility.IsClientWindows).PathCombine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "acknowledgements.txt"); + var path = SystemIO.IO_OS.PathCombine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "acknowledgements.txt"); info.OutputOK(new GetResponse() { Status = "OK", Acknowledgements = System.IO.File.ReadAllText(path) diff --git a/Duplicati/Server/WebServer/RESTMethods/BackupDefaults.cs b/Duplicati/Server/WebServer/RESTMethods/BackupDefaults.cs index 8074b6e39..fc6725cca 100644 --- a/Duplicati/Server/WebServer/RESTMethods/BackupDefaults.cs +++ b/Duplicati/Server/WebServer/RESTMethods/BackupDefaults.cs @@ -16,7 +16,7 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA using System; using System.Linq; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; using Duplicati.Library.Utility; namespace Duplicati.Server.WebServer.RESTMethods @@ -50,7 +50,7 @@ namespace Duplicati.Server.WebServer.RESTMethods try { // Add install defaults/overrides, if present - var path = SystemIO.IO_OS(Utility.IsClientWindows).PathCombine(Library.AutoUpdater.UpdaterManager.InstalledBaseDir, "newbackup.json"); + var path = SystemIO.IO_OS.PathCombine(Library.AutoUpdater.UpdaterManager.InstalledBaseDir, "newbackup.json"); if (System.IO.File.Exists(path)) { Newtonsoft.Json.Linq.JObject n; diff --git a/Duplicati/Server/WebServer/RESTMethods/Filesystem.cs b/Duplicati/Server/WebServer/RESTMethods/Filesystem.cs index f407b641e..8c346c72f 100644 --- a/Duplicati/Server/WebServer/RESTMethods/Filesystem.cs +++ b/Duplicati/Server/WebServer/RESTMethods/Filesystem.cs @@ -19,7 +19,7 @@ using System.Collections.Generic; using System.Linq; using System.IO; using Duplicati.Library.Snapshots; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.Server.WebServer.RESTMethods { @@ -207,15 +207,13 @@ namespace Duplicati.Server.WebServer.RESTMethods return false; }; - var systemIO = SystemIO.IO_OS(Library.Utility.Utility.IsClientWindows); - - foreach (var s in systemIO.EnumerateFileSystemEntries(entrypath)) + foreach (var s in SystemIO.IO_OS.EnumerateFileSystemEntries(entrypath)) { Serializable.TreeNode tn = null; try { - var attr = systemIO.GetFileAttributes(s); - var isSymlink = systemIO.IsSymlink(s, attr); + var attr = SystemIO.IO_OS.GetFileAttributes(s); + var isSymlink = SystemIO.IO_OS.IsSymlink(s, attr); var isFolder = (attr & FileAttributes.Directory) != 0; var isFile = !isFolder; var isHidden = (attr & FileAttributes.Hidden) != 0; @@ -233,7 +231,7 @@ namespace Duplicati.Server.WebServer.RESTMethods tn = new Serializable.TreeNode() { id = rawid, - text = systemIO.PathGetFileName(s), + text = SystemIO.IO_OS.PathGetFileName(s), hidden = isHidden, symlink = isSymlink, iconCls = isFolder ? (accessible ? (isSymlink ? "x-tree-icon-symlink" : "x-tree-icon-parent") : "x-tree-icon-locked") : "x-tree-icon-leaf", diff --git a/Duplicati/Server/WebServer/Server.cs b/Duplicati/Server/WebServer/Server.cs index 7c23994e0..efa46c538 100644 --- a/Duplicati/Server/WebServer/Server.cs +++ b/Duplicati/Server/WebServer/Server.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Linq; using HttpServer.HttpModules; using System.Security.Cryptography.X509Certificates; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.Server.WebServer { diff --git a/Duplicati/UnitTest/Duplicati.UnitTest.csproj b/Duplicati/UnitTest/Duplicati.UnitTest.csproj index 982dfed52..e84486588 100644 --- a/Duplicati/UnitTest/Duplicati.UnitTest.csproj +++ b/Duplicati/UnitTest/Duplicati.UnitTest.csproj @@ -179,7 +179,7 @@ {D63E53E4-A458-4C2F-914D-92F715F58ACF} - Duplicati.Library.IO + Duplicati.Library.Common diff --git a/Duplicati/UnitTest/FilterTest.cs b/Duplicati/UnitTest/FilterTest.cs index 945777094..e8219f662 100644 --- a/Duplicati/UnitTest/FilterTest.cs +++ b/Duplicati/UnitTest/FilterTest.cs @@ -17,7 +17,7 @@ using System; using System.IO; using System.Linq; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; using NUnit.Framework; namespace Duplicati.UnitTest diff --git a/Duplicati/UnitTest/IOTests.cs b/Duplicati/UnitTest/IOTests.cs index 1fa1c4408..a8a6ee02c 100644 --- a/Duplicati/UnitTest/IOTests.cs +++ b/Duplicati/UnitTest/IOTests.cs @@ -18,7 +18,7 @@ using System.Text; using NUnit.Framework; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; using Duplicati.Library.Utility; namespace Duplicati.UnitTest @@ -37,7 +37,7 @@ namespace Duplicati.UnitTest public void TestGetPathRootWithLongPath() { var pathRoot = Utility.IsClientWindows ? "C:\\" : "/"; - var root = SystemIO.IO_OS(Utility.IsClientWindows).GetPathRoot(LongPath(pathRoot)); + var root = SystemIO.IO_OS.GetPathRoot(LongPath(pathRoot)); Assert.AreEqual(pathRoot, root); } @@ -71,13 +71,13 @@ namespace Duplicati.UnitTest var pathRoot = Utility.IsClientWindows ? "C:\\" : "/"; var longPath = LongPath(pathRoot); - if (SystemIO.IO_OS(Utility.IsClientWindows).DirectoryExists(longPath)) + if (SystemIO.IO_OS.DirectoryExists(longPath)) { return; } //In particular don't throw PathTooLongException - Assert.Throws(() => SystemIO.IO_OS(Utility.IsClientWindows).GetFiles(longPath)); + Assert.Throws(() => SystemIO.IO_OS.GetFiles(longPath)); } [Test] @@ -86,13 +86,13 @@ namespace Duplicati.UnitTest var pathRoot = Utility.IsClientWindows ? "C:\\" : "/"; var longPath = LongPath(pathRoot); - if (SystemIO.IO_OS(Utility.IsClientWindows).DirectoryExists(longPath)) + if (SystemIO.IO_OS.DirectoryExists(longPath)) { return; } //In particular don't throw PathTooLongException - Assert.Throws(() => SystemIO.IO_OS(Utility.IsClientWindows).GetDirectories(longPath)); + Assert.Throws(() => SystemIO.IO_OS.GetDirectories(longPath)); } } } diff --git a/Duplicati/UnitTest/PurgeTesting.cs b/Duplicati/UnitTest/PurgeTesting.cs index dd0ade94d..a5e253e36 100644 --- a/Duplicati/UnitTest/PurgeTesting.cs +++ b/Duplicati/UnitTest/PurgeTesting.cs @@ -18,7 +18,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; using Duplicati.Library.Utility; using NUnit.Framework; @@ -184,7 +184,7 @@ namespace Duplicati.UnitTest Assert.AreEqual(res.AddedFiles, round1.Length); } - var dblock_file = SystemIO.IO_OS(Utility.IsClientWindows) + var dblock_file = SystemIO.IO_OS .GetFiles(TARGETFOLDER, "*.dblock.zip.aes") .Select(x => new FileInfo(x)) .OrderBy(x => x.LastWriteTimeUtc) diff --git a/Duplicati/UnitTest/SVNCheckoutsTest.cs b/Duplicati/UnitTest/SVNCheckoutsTest.cs index bf87ce43e..2cfe21745 100644 --- a/Duplicati/UnitTest/SVNCheckoutsTest.cs +++ b/Duplicati/UnitTest/SVNCheckoutsTest.cs @@ -27,7 +27,7 @@ using System.Text; using Duplicati.Library.Logging; using Duplicati.Library.Utility; using System.Linq; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.UnitTest { diff --git a/Duplicati/UnitTest/SizeOmittingBackend.cs b/Duplicati/UnitTest/SizeOmittingBackend.cs index 10480a530..ed8487cf3 100644 --- a/Duplicati/UnitTest/SizeOmittingBackend.cs +++ b/Duplicati/UnitTest/SizeOmittingBackend.cs @@ -19,7 +19,7 @@ using System.Linq; using Duplicati.Library.Interface; using System.Collections.Generic; using System.IO; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.UnitTest { diff --git a/Duplicati/UnitTest/TestUtils.cs b/Duplicati/UnitTest/TestUtils.cs index 93fd67d03..80e301b9b 100644 --- a/Duplicati/UnitTest/TestUtils.cs +++ b/Duplicati/UnitTest/TestUtils.cs @@ -21,7 +21,7 @@ using Duplicati.Library.Utility; using System.Linq; using Duplicati.Library.Logging; using System.Reflection; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; namespace Duplicati.UnitTest { diff --git a/Duplicati/UnitTest/UtilityTests.cs b/Duplicati/UnitTest/UtilityTests.cs index 65b3db4e2..49e9b358a 100644 --- a/Duplicati/UnitTest/UtilityTests.cs +++ b/Duplicati/UnitTest/UtilityTests.cs @@ -15,7 +15,7 @@ // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA using Duplicati.Library.Utility; -using Duplicati.Library.IO; +using Duplicati.Library.Common.IO; using NUnit.Framework; using System; using System.Collections.Generic; -- cgit v1.2.3