diff --git a/Duplicati/CommandLine/Commands.cs b/Duplicati/CommandLine/Commands.cs index edd7866b7..a47365a90 100644 --- a/Duplicati/CommandLine/Commands.cs +++ b/Duplicati/CommandLine/Commands.cs @@ -19,7 +19,8 @@ using System; using System.Linq; using System.Collections.Generic; using System.IO; - +using Duplicati.Library.IO; + namespace Duplicati.CommandLine { public static class Commands @@ -33,7 +34,7 @@ namespace Duplicati.CommandLine private readonly ConsoleOutput m_output; private System.Threading.Thread m_thread; private readonly TimeSpan m_updateFrequency; - + public PeriodicOutput(ConsoleOutput messageSink, TimeSpan updateFrequency) { m_output = messageSink; @@ -45,27 +46,27 @@ namespace Duplicati.CommandLine m_thread.Name = "Periodic console writer"; m_thread.Start(); } - + public void SetReady() { m_readyEvent.Set(); } public void SetFinished() { m_finishEvent.Set(); } - + public bool Join(TimeSpan wait) { if (m_thread != null) return m_thread.Join(wait); - + return true; } - + private void ThreadMain() { m_readyEvent.WaitOne(); if (m_finishEvent.WaitOne(TimeSpan.FromMilliseconds(10), true)) return; - + var last_count = -1L; var finished = false; - + while (true) { Duplicati.Library.Main.OperationPhase phase; @@ -76,10 +77,10 @@ namespace Duplicati.CommandLine long filesize; bool counting; m_output.OperationProgress.UpdateOverall(out phase, out progress, out filesprocessed, out filesizeprocessed, out filecount, out filesize, out counting); - + var files = Math.Max(0, filecount - filesprocessed); var size = Math.Max(0, filesize - filesizeprocessed); - + if (finished) { files = 0; @@ -87,21 +88,21 @@ namespace Duplicati.CommandLine } else if (size > 0) files = Math.Max(1, files); - + if (last_count < 0 || files != last_count) if (WriteOutput != null) WriteOutput(progress, files, size, counting); - + if (!counting) last_count = files; - + if (finished) return; - - finished = m_finishEvent.WaitOne(m_updateFrequency, true); + + finished = m_finishEvent.WaitOne(m_updateFrequency, true); } } - + public void Dispose() { if (m_thread != null) @@ -110,7 +111,7 @@ namespace Duplicati.CommandLine { m_finishEvent.Set(); m_readyEvent.Set(); - + if (m_thread != null && m_thread.IsAlive) { m_thread.Abort(); @@ -130,7 +131,7 @@ namespace Duplicati.CommandLine Duplicati.CommandLine.Help.PrintUsage(outwriter, "example", options); return 0; } - + public static int Help(TextWriter outwriter, Action setup, List args, Dictionary options, Library.Utility.IFilter filter) { Duplicati.CommandLine.Help.PrintUsage(outwriter, args.Count > 1? args[1] : "help", options); @@ -172,8 +173,8 @@ namespace Duplicati.CommandLine using(var i = new Library.Main.Controller(backend, options, console)) { setup(i); - i.ListAffected(args, res => - { + i.ListAffected(args, res => + { if (res.Filesets != null && res.Filesets.Any()) { outwriter.WriteLine("The following filesets are affected:"); @@ -233,6 +234,15 @@ namespace Duplicati.CommandLine return 0; } } + + public static List PrefixArgsWithAsterisk(IList argList) + { + // Prefix all filenames with "*/" so we search all folders + var specialArgChars = new[] { '*', '?', Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }; + return argList.Select(arg => arg.IndexOfAny(specialArgChars) < 0 + && !arg.StartsWith("[", StringComparison.Ordinal) ? "*" + Util.DirectorySeparatorString + arg : arg).ToList(); + } + public static int List(TextWriter outwriter, Action setup, List args, Dictionary options, Library.Utility.IFilter filter) { filter = filter ?? new Duplicati.Library.Utility.FilterExpression(); @@ -245,7 +255,7 @@ namespace Duplicati.CommandLine setup(i); var backend = args[0]; args.RemoveAt(0); - + if (args.Count == 1) { long v; @@ -272,12 +282,9 @@ namespace Duplicati.CommandLine } } } - - // Prefix all filenames with "*/" so we search all folders - for(var ix = 0; ix < args.Count; ix++) - if (args[ix].IndexOfAny(new char[] { '*', '?', System.IO.Path.DirectorySeparatorChar, System.IO.Path.AltDirectorySeparatorChar }) < 0 && !args[ix].StartsWith("[", StringComparison.Ordinal)) - args[ix] = "*" + System.IO.Path.DirectorySeparatorChar.ToString() + args[ix]; - + + args = PrefixArgsWithAsterisk(args); + // Support for not adding the --auth-username if possible string dbpath; options.TryGetValue("dbpath", out dbpath); @@ -304,20 +311,20 @@ namespace Duplicati.CommandLine } } - + bool controlFiles = Library.Utility.Utility.ParseBoolOption(options, "control-files"); options.Remove("control-files"); - + var res = controlFiles ? i.ListControlFiles(args, filter) : i.List(args, filter); - //If there are no files matching, and we are looking for one or more files, + //If there are no files matching, and we are looking for one or more files, // try again with all-versions set var compareFilter = Library.Utility.JoinedFilterExpression.Join(new Library.Utility.FilterExpression(args), filter); - var isRequestForFiles = - !controlFiles && res.Filesets.Any() && - (res.Files == null || !res.Files.Any()) && + var isRequestForFiles = + !controlFiles && res.Filesets.Any() && + (res.Files == null || !res.Files.Any()) && !compareFilter.Empty; - + if (isRequestForFiles && !Library.Utility.Utility.ParseBoolOption(options, "all-versions")) { outwriter.WriteLine("No files matching, looking in all versions"); @@ -330,7 +337,7 @@ namespace Duplicati.CommandLine if (res.Filesets.Any() && (res.Files == null || !res.Files.Any()) && compareFilter.Empty) { outwriter.WriteLine("Listing filesets:"); - + foreach(var e in res.Filesets) { if (e.FileCount >= 0) @@ -357,8 +364,8 @@ namespace Duplicati.CommandLine { var f = res.Filesets.First(); outwriter.WriteLine("Listing contents {0} ({1}):", f.Version, f.Time); - foreach(var e in res.Files) - outwriter.WriteLine("{0} {1}", e.Path, e.Path.EndsWith(System.IO.Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal) ? "" : "(" + Library.Utility.Utility.FormatSizeString(e.Sizes.First()) + ")"); + foreach (var e in res.Files) + outwriter.WriteLine("{0} {1}", e.Path, e.Path.EndsWith(Util.DirectorySeparatorString, StringComparison.Ordinal) ? "" : "(" + Library.Utility.Utility.FormatSizeString(e.Sizes.First()) + ")"); } else { @@ -368,34 +375,34 @@ namespace Duplicati.CommandLine outwriter.WriteLine(e.Path); foreach(var nx in res.Filesets.Zip(e.Sizes, (a, b) => new { Index = a.Version, Time = a.Time, Size = b } )) outwriter.WriteLine("{0}\t: {1} {2}", nx.Index, nx.Time, nx.Size < 0 ? " - " : Library.Utility.Utility.FormatSizeString(nx.Size)); - + outwriter.WriteLine(); } - + } } } - + return 0; } - + public static int Delete(TextWriter outwriter, Action setup, List args, Dictionary options, Library.Utility.IFilter filter) { var requiredOptions = new string[] { "keep-time", "keep-versions", "version" }; - + if (!options.Keys.Any(x => requiredOptions.Contains(x, StringComparer.OrdinalIgnoreCase))) { - outwriter.WriteLine(Strings.Program.DeleteCommandNeedsOptions("delete", requiredOptions)); + outwriter.WriteLine(Strings.Program.DeleteCommandNeedsOptions("delete", requiredOptions)); return 200; } - + using (var console = new ConsoleOutput(outwriter, options)) using(var i = new Library.Main.Controller(args[0], options, console)) { setup(i); args.RemoveAt(0); var res = i.Delete(); - + if (!res.DeletedSets.Any()) { outwriter.WriteLine(Strings.Program.NoFilesetsMatching); @@ -406,14 +413,14 @@ namespace Duplicati.CommandLine outwriter.WriteLine(Strings.Program.WouldDeleteBackups); else outwriter.WriteLine(Strings.Program.DeletedBackups); - + foreach(var f in res.DeletedSets) outwriter.WriteLine(string.Format("{0}: {1}", f.Item1, f.Item2)); } } - + return 0; - + } public static int Repair(TextWriter outwriter, Action setup, List args, Dictionary options, Library.Utility.IFilter filter) @@ -435,23 +442,20 @@ namespace Duplicati.CommandLine { if (args.Count < 1) return PrintWrongNumberOfArguments(outwriter, args, 1); - + string backend = args[0]; args.RemoveAt(0); - + bool controlFiles = Library.Utility.Utility.ParseBoolOption(options, "control-files"); options.Remove("control-files"); - // Prefix all filenames with "*/" so we search all folders - for (var ix = 0; ix < args.Count; ix++) - if (args[ix].IndexOfAny(new char[] { '*', '?', System.IO.Path.DirectorySeparatorChar, System.IO.Path.AltDirectorySeparatorChar }) < 0 && !args[ix].StartsWith("[", StringComparison.Ordinal)) - args[ix] = "*" + System.IO.Path.DirectorySeparatorChar.ToString() + args[ix]; + args = PrefixArgsWithAsterisk(args); // suffix all folders with "*" so we restore all contents in the folder for (var ix = 0; ix < args.Count; ix++) - if (args[ix].IndexOfAny(new char[] { '*', '?' }) < 0 && !args[ix].StartsWith("[", StringComparison.Ordinal) && args[ix].EndsWith(System.IO.Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)) + if (args[ix].IndexOfAny(new char[] { '*', '?' }) < 0 && !args[ix].StartsWith("[", StringComparison.Ordinal) && args[ix].EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)) args[ix] += "*"; - + using(var output = new ConsoleOutput(outwriter, options)) using (var i = new Library.Main.Controller(backend, options, output)) { @@ -524,7 +528,7 @@ namespace Duplicati.CommandLine } } } - + return 0; } @@ -532,7 +536,7 @@ namespace Duplicati.CommandLine { if (args.Count < 2) return PrintWrongNumberOfArguments(outwriter, args, 2); - + var backend = args[0]; args.RemoveAt(0); var dirs = args.ToArray(); @@ -647,7 +651,7 @@ namespace Duplicati.CommandLine return 0; } } - + public static int Compact(TextWriter outwriter, Action setup, List args, Dictionary options, Library.Utility.IFilter filter) { if (args.Count != 1) @@ -668,7 +672,7 @@ namespace Duplicati.CommandLine var fullResults = Duplicati.Library.Utility.Utility.ParseBoolOption(options, "full-result"); if (args.Count != 1 && args.Count != 2) return PrintWrongNumberOfArguments(outwriter, args, 1); - + var tests = 1L; if (args.Count == 2) { @@ -677,7 +681,7 @@ namespace Duplicati.CommandLine else tests = Convert.ToInt64(args[1]); } - + Library.Interface.ITestResults result; using (var console = new ConsoleOutput(outwriter, options)) using (var i = new Library.Main.Controller(args[0], options, console)) @@ -685,7 +689,7 @@ namespace Duplicati.CommandLine setup(i); result = i.Test(tests); } - + var totalFiles = result.Verifications.Count(); if (totalFiles == 0) { @@ -733,7 +737,7 @@ namespace Duplicati.CommandLine } } } - + private static int PrintWrongNumberOfArguments(TextWriter outwriter, List args, int expected) { outwriter.WriteLine(Strings.Program.WrongNumberOfCommandsError_v2(args.Count, expected, args.Select(n => "\"" + n + "\"").ToArray())); @@ -755,7 +759,7 @@ namespace Duplicati.CommandLine { if (args.Count > 0) dbpath = Library.Main.DatabaseLocator.GetDatabasePath(args[0], new Duplicati.Library.Main.Options(options), false, true); - + if (dbpath == null) { outwriter.WriteLine("No local database found, please add --{0}", "dbpath"); @@ -763,9 +767,9 @@ namespace Duplicati.CommandLine } else options["dbpath"] = dbpath; - + } - + if (args.Count == 0) args = new List(new string[] { "file://unused", "report" }); else if (args.Count == 1) @@ -787,14 +791,14 @@ namespace Duplicati.CommandLine return 0; } - + public static int ListChanges(TextWriter outwriter, Action setup, List args, Dictionary options, Library.Utility.IFilter filter) { var fullresult = Duplicati.Library.Utility.Utility.ParseBoolOption(options, "full-result"); if (args.Count < 1) return PrintWrongNumberOfArguments(outwriter, args, 1); - + // Support for not adding the --auth-username if possible string dbpath; options.TryGetValue("dbpath", out dbpath); @@ -804,7 +808,7 @@ namespace Duplicati.CommandLine if (dbpath != null) options["dbpath"] = dbpath; } - + // Don't ask for passphrase if we have a local db if (!string.IsNullOrEmpty(dbpath) && System.IO.File.Exists(dbpath) && !options.ContainsKey("no-encryption") && !Duplicati.Library.Utility.Utility.ParseBoolOption(options, "no-local-db")) { @@ -814,9 +818,9 @@ namespace Duplicati.CommandLine options["no-encryption"] = "true"; } - Action>> handler = - (result, items) => - { + Action>> handler = + (result, items) => + { outwriter.WriteLine("Listing changes"); outwriter.WriteLine(" {0}: {1}", result.BaseVersionIndex, result.BaseVersionTimestamp); outwriter.WriteLine(" {0}: {1}", result.CompareVersionIndex, result.CompareVersionTimestamp); @@ -912,9 +916,9 @@ namespace Duplicati.CommandLine result.DeletedFolders + result.DeletedSymlinks + result.DeletedFiles == 0) outwriter.WriteLine(" No changes found"); - outwriter.WriteLine("Size of backup {0}: {1}", result.CompareVersionIndex, Library.Utility.Utility.FormatSizeString(result.CurrentSize)); + outwriter.WriteLine("Size of backup {0}: {1}", result.CompareVersionIndex, Library.Utility.Utility.FormatSizeString(result.CurrentSize)); }; - + using (var console = new ConsoleOutput(outwriter, options)) using (var i = new Library.Main.Controller(args[0], options, console)) { @@ -927,7 +931,7 @@ namespace Duplicati.CommandLine return 0; } - + public static int TestFilters(TextWriter outwriter, Action setup, List args, Dictionary options, Library.Utility.IFilter filter) { if (args == null || args.Count < 1) @@ -935,16 +939,16 @@ namespace Duplicati.CommandLine outwriter.WriteLine("No source paths given"); return 200; } - + using (var console = new ConsoleOutput(outwriter, options)) using(var i = new Library.Main.Controller("dummy://", options, console)) { setup(i); var result = i.TestFilter(args.ToArray(), filter); - + outwriter.WriteLine("Matched {0} files ({1})", result.FileCount, Duplicati.Library.Utility.Utility.FormatSizeString(result.FileSize)); } - + return 0; } @@ -1001,7 +1005,7 @@ namespace Duplicati.CommandLine setup(i); i.PurgeFiles(filter); } - + return 0; } @@ -1078,9 +1082,9 @@ namespace Duplicati.CommandLine } public static int Vacuum( - TextWriter outwriter, + TextWriter outwriter, Action setup, - List args, Dictionary options, + List args, Dictionary options, Library.Utility.IFilter filter) { if (args.Count != 1) diff --git a/Duplicati/CommandLine/Duplicati.CommandLine.csproj b/Duplicati/CommandLine/Duplicati.CommandLine.csproj index 3845a3bb2..8c3f35112 100644 --- a/Duplicati/CommandLine/Duplicati.CommandLine.csproj +++ b/Duplicati/CommandLine/Duplicati.CommandLine.csproj @@ -208,6 +208,10 @@ {0797AA22-C5DD-4950-BB60-34765AB8C6DD} Duplicati.Tools + + {D63E53E4-A458-4C2F-914D-92F715F58ACF} + Duplicati.Library.IO + diff --git a/Duplicati/Library/AutoUpdater/UpdaterManager.cs b/Duplicati/Library/AutoUpdater/UpdaterManager.cs index 0d21499fb..852eff04c 100644 --- a/Duplicati/Library/AutoUpdater/UpdaterManager.cs +++ b/Duplicati/Library/AutoUpdater/UpdaterManager.cs @@ -524,7 +524,7 @@ namespace Duplicati.Library.AutoUpdater continue; var fullpath = System.IO.Path.Combine(targetfolder, relpath); - if (relpath.EndsWith(System.IO.Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)) + if (relpath.EndsWith(Util.DirectorySeparatorString, StringComparison.Ordinal)) System.IO.Directory.CreateDirectory(fullpath); else System.IO.File.Copy(e, fullpath); @@ -721,7 +721,7 @@ namespace Duplicati.Library.AutoUpdater inputfolder = Util.AppendDirSeparator(inputfolder); var baselen = inputfolder.Length; - var dirsep = System.IO.Path.DirectorySeparatorChar.ToString(); + var dirsep = Util.DirectorySeparatorString; ignoreMap.Add(UPDATE_MANIFEST_FILENAME, ""); diff --git a/Duplicati/Library/IO/Duplicati.Library.IO.csproj b/Duplicati/Library/IO/Duplicati.Library.IO.csproj index 744b538f3..a784ae16c 100644 --- a/Duplicati/Library/IO/Duplicati.Library.IO.csproj +++ b/Duplicati/Library/IO/Duplicati.Library.IO.csproj @@ -66,7 +66,6 @@ - diff --git a/Duplicati/Library/IO/SystemIOWindows.cs b/Duplicati/Library/IO/SystemIOWindows.cs index 17dae205f..8fd7ee28c 100644 --- a/Duplicati/Library/IO/SystemIOWindows.cs +++ b/Duplicati/Library/IO/SystemIOWindows.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2015, The Duplicati Team +// Copyright (C) 2015, The Duplicati Team // http://www.duplicati.com, info@duplicati.com // @@ -31,7 +31,7 @@ namespace Duplicati.Library.IO private const string UNCPREFIX = @"\\?\"; private const string UNCPREFIX_SERVER = @"\\?\UNC\"; private const string PATHPREFIX_SERVER = @"\\"; - private static readonly string DIRSEP = System.IO.Path.DirectorySeparatorChar.ToString(); + private static readonly string DIRSEP = Util.DirectorySeparatorString; private static bool IsPathTooLong(string path) { diff --git a/Duplicati/Library/IO/Util.cs b/Duplicati/Library/IO/Util.cs index f66977cbb..52287fcce 100644 --- a/Duplicati/Library/IO/Util.cs +++ b/Duplicati/Library/IO/Util.cs @@ -26,6 +26,7 @@ namespace Duplicati.Library.IO /// 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. diff --git a/Duplicati/Library/IO/WinNativeMethods.cs b/Duplicati/Library/IO/WinNativeMethods.cs deleted file mode 100644 index eac0b450a..000000000 --- a/Duplicati/Library/IO/WinNativeMethods.cs +++ /dev/null @@ -1,306 +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 -//// -//using System.Security.AccessControl; - - -//#endregion -//using System; -//using System.Text; -//using System.Runtime.InteropServices; -//using System.ComponentModel; -//using Microsoft.Win32.SafeHandles; - -//namespace Duplicati.Library.IO -//{ -// /// -// /// This class contains various Windows system calls related to reading locked files. -// /// Some PInvoke signatures are from http://www.pinvoke.net -// /// -// public static class WinNativeMethods -// { -// [Flags] -// private enum FileAccess : uint -// { -// GenericNone = 0x00000000, -// GenericRead = 0x80000000, -// GenericWrite = 0x40000000, -// GenericExecute = 0x20000000, -// GenericAll = 0x10000000, -// ReadControl = 0x00020000 -// } - -// [Flags] -// private enum FileShare : uint -// { -// None = 0x00000000, -// Read = 0x00000001, -// Write = 0x00000002, -// ReadWrite = 0x00000003, -// Delete = 0x00000004 -// } - -// private enum CreationDisposition : uint -// { -// New = 1, -// CreateAlways = 2, -// OpenExisting = 3, -// OpenAlways = 4, -// TruncateExisting = 5 -// } - -// [Flags] -// private enum FileAttributes : uint -// { -// Readonly = 0x00000001, -// Hidden = 0x00000002, -// System = 0x00000004, -// Directory = 0x00000010, -// Archive = 0x00000020, -// Device = 0x00000040, -// Normal = 0x00000080, -// Temporary = 0x00000100, -// SparseFile = 0x00000200, -// ReparsePoint = 0x00000400, -// Compressed = 0x00000800, -// Offline = 0x00001000, -// NotContentIndexed = 0x00002000, -// Encrypted = 0x00004000, -// Write_Through = 0x80000000, -// Overlapped = 0x40000000, -// NoBuffering = 0x20000000, -// RandomAccess = 0x10000000, -// SequentialScan = 0x08000000, -// DeleteOnClose = 0x04000000, -// BackupSemantics = 0x02000000, -// PosixSemantics = 0x01000000, -// OpenReparsePoint = 0x00200000, -// OpenNoRecall = 0x00100000, -// FirstPipeInstance = 0x00080000 -// } - -// private const int TOKEN_ADJUST_PRIVILEGES = 0x00000020; -// private const int TOKEN_QUERY = 0x00000008; -// private const int SE_PRIVILEGE_ENABLED = 0x00000002; -// private const string SE_BACKUP_NAME = "SeBackupPrivilege"; -// private const string SE_RESTORE_NAME = "SeRestorePrivilege"; -// private const int TOKEN_INFORMATION_CLASS_PRIVILEGES = 0x3; -// private const int ATTRIBUTE_FIXED_SIZE = 200; - -// [StructLayout(LayoutKind.Sequential)] -// private struct LUID -// { -// public UInt32 LowPart; -// public Int32 HighPart; -// } - -// [StructLayout(LayoutKind.Sequential)] -// private struct LUID_AND_ATTRIBUTES -// { -// public LUID Luid; -// public UInt32 Attributes; -// } - -// [StructLayout(LayoutKind.Sequential)] -// private struct TOKEN_PRIVILEGES -// { -// public UInt32 PrivilegeCount; -// [MarshalAs(UnmanagedType.ByValArray, SizeConst = ATTRIBUTE_FIXED_SIZE)] //We make sure there is enough room -// public LUID_AND_ATTRIBUTES[] Privileges; -// } - - -// [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] -// private static extern int OpenProcessToken(int ProcessHandle, int DesiredAccess, ref int tokenhandle); - -// [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] -// private static extern int GetCurrentProcess(); - -// [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] -// private static extern int GetTokenInformation(int tokenhandle, int tokeninformationclass, [MarshalAs(UnmanagedType.Struct)]ref TOKEN_PRIVILEGES state, int bufferlength, ref int actualsize); - -// [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] -// private static extern int LookupPrivilegeValue(string lpsystemname, string lpname, [MarshalAs(UnmanagedType.Struct)] ref LUID lpLuid); - -// [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] -// private static extern int AdjustTokenPrivileges(int tokenhandle, bool disableprivs, [MarshalAs(UnmanagedType.Struct)]ref TOKEN_PRIVILEGES newState, int bufferlength, [MarshalAs(UnmanagedType.Struct)]ref TOKEN_PRIVILEGES previousState, ref int actualsize); - -// [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] -// private static extern int LookupPrivilegeName(string lpSystemName, [MarshalAs(UnmanagedType.Struct)] ref LUID lpLuid, System.Text.StringBuilder lpName, ref int cchName); - -// [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] -// private static extern SafeFileHandle CreateFile( -// string lpFileName, -// FileAccess dwDesiredAccess, -// FileShare dwShareMode, -// IntPtr lpSecurityAttributes, -// CreationDisposition dwCreationDisposition, -// FileAttributes dwFlagsAndAttributes, -// IntPtr hTemplateFile -// ); - -// /// -// /// Opens a file with backup semantics, only works if the caller has the SeBackupPrivilege -// /// -// /// The file to open -// /// The opened backup filestream -// public static System.IO.Stream OpenAsBackupFile(string filename) -// { -// var hFile = CreateFile(filename, FileAccess.ReadControl, FileShare.None, IntPtr.Zero, CreationDisposition.OpenExisting, FileAttributes.BackupSemantics | FileAttributes.SequentialScan, IntPtr.Zero); - -// if (hFile.IsInvalid) -// throw new Win32Exception(Marshal.GetLastWin32Error()); - -// //TODO: We need to be able to seek to pos 0 -// return new Alphaleonis.Win32.Filesystem.BackupFileStream(hFile, FileSystemRights.Read); -// } - -// /// -// /// Internal helper function that returns two values relating to the SeBackupPrivilege -// /// -// /// True if the calling proccess has the SeBackupPrivilege, false otherwise -// /// True if the SeBackupPrivilege is enabled, false otherwise -// private static void GetBackupPrivilege(out bool hasPrivilege, out bool isEnabled) -// { -// int token = 0; -// int outsize = 0; - -// TOKEN_PRIVILEGES TP = new TOKEN_PRIVILEGES(); -// LUID backupLuid = new LUID(); - -// if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref token) == 0) -// throw new Win32Exception(Marshal.GetLastWin32Error()); - -// if (LookupPrivilegeValue(null, SE_BACKUP_NAME, ref backupLuid) == 0) -// throw new Win32Exception(Marshal.GetLastWin32Error()); - -// if (GetTokenInformation(token, TOKEN_INFORMATION_CLASS_PRIVILEGES, ref TP, Marshal.SizeOf(typeof(TOKEN_PRIVILEGES)), ref outsize) == 0) -// throw new Win32Exception(Marshal.GetLastWin32Error()); - -//#if DEBUG -// Console.WriteLine("Read token information:"); -// PrintTokenInformation(TP); -//#endif - -// for (int i = 0; i < TP.PrivilegeCount; i++) -// if (TP.Privileges[i].Luid.LowPart == backupLuid.LowPart && TP.Privileges[i].Luid.HighPart == backupLuid.HighPart) -// { -// isEnabled = (TP.Privileges[i].Attributes & SE_PRIVILEGE_ENABLED) == SE_PRIVILEGE_ENABLED; -// hasPrivilege = true; -// return; -// } - -// hasPrivilege = false; -// isEnabled = false; -// } - -// /// -// /// Gets a value indicating if the current process can set the SeBackupPrivilege value -// /// -// public static bool CanEnableBackupPrivilege -// { -// get -// { -// bool hasPrivilege, isEnabled; -// GetBackupPrivilege(out hasPrivilege, out isEnabled); - -// return hasPrivilege; -// } -// } - -// /// -// /// Gets or sets a value indicating if the current process has the backup privilege (SE_BACKUP_NAME) -// /// -// public static bool BackupPrivilege -// { -// get -// { -// bool hasPrivilege, isEnabled; -// GetBackupPrivilege(out hasPrivilege, out isEnabled); - -// //if (!hasPrivilege) -// //throw new Duplicati.Library.Interface.UserInformationException(Strings.WinNativeMethod.MissingBackupPrivilegeError, "MissingBackupPrivilege"); - -// return isEnabled; -// } -// set -// { -// //if (!CanEnableBackupPrivilege) -// //throw new Duplicati.Library.Interface.UserInformationException(Strings.WinNativeMethod.MissingBackupPrivilegeError, "MissingBackupPrivilege"); - -// int token = 0; -// int outsize = 0; - -// TOKEN_PRIVILEGES TP = new TOKEN_PRIVILEGES(); -// LUID backupLuid = new LUID(); -// LUID restoreLuid = new LUID(); - -// if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref token) == 0) -// throw new Win32Exception(Marshal.GetLastWin32Error()); - -// if (LookupPrivilegeValue(null, SE_BACKUP_NAME, ref backupLuid) == 0) -// throw new Win32Exception(Marshal.GetLastWin32Error()); - -// if (LookupPrivilegeValue(null, SE_RESTORE_NAME, ref restoreLuid) == 0) -// throw new Win32Exception(Marshal.GetLastWin32Error()); - -// TP.PrivilegeCount = 1; -// TP.Privileges = new LUID_AND_ATTRIBUTES[ATTRIBUTE_FIXED_SIZE]; -// TP.Privileges[0].Attributes = value ? SE_PRIVILEGE_ENABLED : 0u; -// TP.Privileges[0].Luid = backupLuid; -// TP.Privileges[1].Attributes = value ? SE_PRIVILEGE_ENABLED : 0u; -// TP.Privileges[1].Luid = restoreLuid; - -// TOKEN_PRIVILEGES TPOut = new TOKEN_PRIVILEGES(); - - -// if (AdjustTokenPrivileges(token, false, ref TP, Marshal.SizeOf(typeof(TOKEN_PRIVILEGES)), ref TPOut, ref outsize) == 0) -// throw new Win32Exception(Marshal.GetLastWin32Error()); - -//#if DEBUG -// Console.WriteLine("Modified token information:"); -// PrintTokenInformation(TPOut); -//#endif - -// if (Marshal.GetLastWin32Error() != 0) -// throw new Win32Exception(Marshal.GetLastWin32Error()); -// } -// } - -//#if DEBUG -// private static void PrintTokenInformation(TOKEN_PRIVILEGES tp) -// { -// int outsize; -// StringBuilder sbname = new StringBuilder(1024 * 4); - -// for (int i = 0; i < tp.PrivilegeCount; i++) -// { -// LUID id = tp.Privileges[i].Luid; - -// outsize = sbname.Capacity; -// if (LookupPrivilegeName(null, ref id, sbname, ref outsize) == 0) -// Console.WriteLine("Invalid LUID {0}:{1}: {2}", id.HighPart, id.LowPart, new Win32Exception(Marshal.GetLastWin32Error()).Message); -// else -// Console.WriteLine("{0}, status {1}", sbname, tp.Privileges[i].Attributes); -// } - -// } -//#endif - -// } -//} diff --git a/Duplicati/Library/Main/Controller.cs b/Duplicati/Library/Main/Controller.cs index 9cdf33337..216a48742 100644 --- a/Duplicati/Library/Main/Controller.cs +++ b/Duplicati/Library/Main/Controller.cs @@ -942,7 +942,7 @@ namespace Duplicati.Library.Main //Sanity check for multiple inclusions of the same folder for (int i = 0; i < sources.Count; i++) for (int j = 0; j < sources.Count; j++) - if (i != j && sources[i].StartsWith(sources[j], Library.Utility.Utility.ClientFilenameStringComparison) && sources[i].EndsWith(System.IO.Path.DirectorySeparatorChar.ToString(), Library.Utility.Utility.ClientFilenameStringComparison)) + if (i != j && sources[i].StartsWith(sources[j], Library.Utility.Utility.ClientFilenameStringComparison) && sources[i].EndsWith(Util.DirectorySeparatorString, Library.Utility.Utility.ClientFilenameStringComparison)) { if (filter != null) { diff --git a/Duplicati/Library/Main/Operation/BackupHandler.cs b/Duplicati/Library/Main/Operation/BackupHandler.cs index 0850c5504..679d47510 100644 --- a/Duplicati/Library/Main/Operation/BackupHandler.cs +++ b/Duplicati/Library/Main/Operation/BackupHandler.cs @@ -377,7 +377,7 @@ namespace Duplicati.Library.Main.Operation Utility.VerifyParameters(m_database, m_options); var probe_path = m_database.GetFirstPath(); - if (probe_path != null && Util.GuessDirSeparator(probe_path) != System.IO.Path.DirectorySeparatorChar.ToString()) + if (probe_path != null && Util.GuessDirSeparator(probe_path) != Util.DirectorySeparatorString) throw new UserInformationException(string.Format("The backup contains files that belong to another operating system. Proceeding with a backup would cause the database to contain paths from two different operation systems, which is not supported. To proceed without losing remote data, delete all filesets and make sure the --{0} option is set, then run the backup again to re-use the existing data on the remote store.", "no-auto-compact"), "CrossOsDatabaseReuseNotSupported"); if (m_database.PartiallyRecreated) diff --git a/Duplicati/Library/Main/Operation/RestoreHandler.cs b/Duplicati/Library/Main/Operation/RestoreHandler.cs index e49ecdbb7..5ab45830e 100644 --- a/Duplicati/Library/Main/Operation/RestoreHandler.cs +++ b/Duplicati/Library/Main/Operation/RestoreHandler.cs @@ -21,7 +21,7 @@ namespace Duplicati.Library.Main.Operation 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 = System.IO.Path.DirectorySeparatorChar.ToString(); + private static readonly string DIRSEP = Util.DirectorySeparatorString; public RestoreHandler(string backendurl, Options options, RestoreResults result) { diff --git a/Duplicati/Library/Utility/FilterGroups.cs b/Duplicati/Library/Utility/FilterGroups.cs index db9757403..f3cb428e4 100644 --- a/Duplicati/Library/Utility/FilterGroups.cs +++ b/Duplicati/Library/Utility/FilterGroups.cs @@ -111,12 +111,12 @@ namespace Duplicati.Library.Utility /// /// Regex escaped string for the AltDirectorySeparatorChar /// - private static readonly string RegexEscapedAltDirectorySeparatorChar = System.Text.RegularExpressions.Regex.Escape(System.IO.Path.AltDirectorySeparatorChar.ToString()); + private static readonly string RegexEscapedAltDirectorySeparatorChar = System.Text.RegularExpressions.Regex.Escape(Util.AltDirectorySeparatorString); /// /// Regex escaped string for the DirectorySeparatorChar /// - private static readonly string RegexEscapedDirectorySeparatorChar = System.Text.RegularExpressions.Regex.Escape(System.IO.Path.DirectorySeparatorChar.ToString()); + private static readonly string RegexEscapedDirectorySeparatorChar = System.Text.RegularExpressions.Regex.Escape(Util.DirectorySeparatorString); /// /// Gets the list of alternate aliases which can refer to this group. @@ -269,7 +269,7 @@ namespace Duplicati.Library.Utility if (n.Length > 2 && char.IsLetter(n[0]) && n[1] == ':' && wildcardRootWindowsPaths.Contains(n.Substring(2))) continue; - else if (prev != null && prev.EndsWith(System.IO.Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal) && n.StartsWith(prev, Utility.ClientFilenameStringComparison)) + else if (prev != null && prev.EndsWith(Util.DirectorySeparatorString, StringComparison.Ordinal) && n.StartsWith(prev, Utility.ClientFilenameStringComparison)) continue; else yield return prev = n; diff --git a/Duplicati/Server/SpecialFolders.cs b/Duplicati/Server/SpecialFolders.cs index 661fada4c..268c33910 100644 --- a/Duplicati/Server/SpecialFolders.cs +++ b/Duplicati/Server/SpecialFolders.cs @@ -163,7 +163,7 @@ namespace Duplicati.Server try { var nx = x; - if (nx.EndsWith(System.IO.Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)) + if (nx.EndsWith(Util.DirectorySeparatorString, StringComparison.Ordinal)) nx = nx.Substring(0, nx.Length - 1); var n = systemIO.PathGetFileName(nx); if (!string.IsNullOrWhiteSpace(n)) @@ -173,7 +173,7 @@ namespace Duplicati.Server { } - if (x.EndsWith(System.IO.Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal) && x.Length > 1) + if (x.EndsWith(Util.DirectorySeparatorString, StringComparison.Ordinal) && x.Length > 1) return new KeyValuePair(x, x.Substring(0, x.Length - 1).Substring(x.Substring(0, x.Length - 1).LastIndexOf("/", StringComparison.Ordinal) + 1)); else return new KeyValuePair(x, x); diff --git a/Duplicati/Server/WebServer/IndexHtmlHandler.cs b/Duplicati/Server/WebServer/IndexHtmlHandler.cs index b5680e432..dd9d78a85 100644 --- a/Duplicati/Server/WebServer/IndexHtmlHandler.cs +++ b/Duplicati/Server/WebServer/IndexHtmlHandler.cs @@ -20,7 +20,8 @@ using System.Linq; using HttpServer; using HttpServer.HttpModules; using HttpServer.Exceptions; - +using Duplicati.Library.IO; + namespace Duplicati.Server.WebServer { internal class IndexHtmlHandler : HttpModule @@ -28,7 +29,7 @@ namespace Duplicati.Server.WebServer private readonly string m_webroot; private static readonly string[] ForbiddenChars = new string[] {"\\", "..", ":"}.Union(from n in System.IO.Path.GetInvalidPathChars() select n.ToString()).Distinct().ToArray(); - private static readonly string DirSep = System.IO.Path.DirectorySeparatorChar.ToString(); + private static readonly string DirSep = Util.DirectorySeparatorString; public IndexHtmlHandler(string webroot) { m_webroot = webroot; } diff --git a/Duplicati/UnitTest/FilterTest.cs b/Duplicati/UnitTest/FilterTest.cs index 9c0e95285..945777094 100644 --- a/Duplicati/UnitTest/FilterTest.cs +++ b/Duplicati/UnitTest/FilterTest.cs @@ -17,6 +17,7 @@ using System; using System.IO; using System.Linq; +using Duplicati.Library.IO; using NUnit.Framework; namespace Duplicati.UnitTest @@ -71,8 +72,8 @@ namespace Duplicati.UnitTest using (var c = new Library.Main.Controller("file://" + TARGETFOLDER, testopts.Expand(new { version = 0 }), null)) { var r = c.List("*"); - var folders = r.Files.Count(x => x.Path.EndsWith(System.IO.Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)); - var files = r.Files.Count(x => !x.Path.EndsWith(System.IO.Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)); + var folders = r.Files.Count(x => x.Path.EndsWith(Util.DirectorySeparatorString, StringComparison.Ordinal)); + var files = r.Files.Count(x => !x.Path.EndsWith(Util.DirectorySeparatorString, StringComparison.Ordinal)); if (folders != 7) throw new Exception($"Initial condition not satisfied, found {folders} folders, but expected 7"); @@ -90,8 +91,8 @@ namespace Duplicati.UnitTest using (var c = new Library.Main.Controller("file://" + TARGETFOLDER, testopts.Expand(new { version = 0 }), null)) { var r = c.List("*"); - var folders = r.Files.Count(x => x.Path.EndsWith(System.IO.Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)); - var files = r.Files.Count(x => !x.Path.EndsWith(System.IO.Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)); + var folders = r.Files.Count(x => x.Path.EndsWith(Util.DirectorySeparatorString, StringComparison.Ordinal)); + var files = r.Files.Count(x => !x.Path.EndsWith(Util.DirectorySeparatorString, StringComparison.Ordinal)); if (folders != 6) throw new Exception($"Initial condition not satisfied, found {folders} folders, but expected 6"); @@ -109,8 +110,8 @@ namespace Duplicati.UnitTest using (var c = new Library.Main.Controller("file://" + TARGETFOLDER, testopts.Expand(new { version = 0 }), null)) { var r = c.List("*"); - var folders = r.Files.Count(x => x.Path.EndsWith(System.IO.Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)); - var files = r.Files.Count(x => !x.Path.EndsWith(System.IO.Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)); + var folders = r.Files.Count(x => x.Path.EndsWith(Util.DirectorySeparatorString, StringComparison.Ordinal)); + var files = r.Files.Count(x => !x.Path.EndsWith(Util.DirectorySeparatorString, StringComparison.Ordinal)); if (folders != 4) throw new Exception($"Empty not satisfied, found {folders} folders, but expected 4"); @@ -128,8 +129,8 @@ namespace Duplicati.UnitTest using (var c = new Library.Main.Controller("file://" + TARGETFOLDER, testopts.Expand(new { version = 0 }), null)) { var r = c.List("*"); - var folders = r.Files.Count(x => x.Path.EndsWith(System.IO.Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)); - var files = r.Files.Count(x => !x.Path.EndsWith(System.IO.Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)); + var folders = r.Files.Count(x => x.Path.EndsWith(Util.DirectorySeparatorString, StringComparison.Ordinal)); + var files = r.Files.Count(x => !x.Path.EndsWith(Util.DirectorySeparatorString, StringComparison.Ordinal)); if (folders != 3) throw new Exception($"Empty not satisfied, found {folders} folders, but expected 3"); @@ -147,8 +148,8 @@ namespace Duplicati.UnitTest using (var c = new Library.Main.Controller("file://" + TARGETFOLDER, testopts.Expand(new { version = 0 }), null)) { var r = c.List("*"); - var folders = r.Files.Count(x => x.Path.EndsWith(System.IO.Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)); - var files = r.Files.Count(x => !x.Path.EndsWith(System.IO.Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)); + var folders = r.Files.Count(x => x.Path.EndsWith(Util.DirectorySeparatorString, StringComparison.Ordinal)); + var files = r.Files.Count(x => !x.Path.EndsWith(Util.DirectorySeparatorString, StringComparison.Ordinal)); if (folders != 1) throw new Exception($"Empty not satisfied, found {folders} folders, but expected 1");