Replaced DirectorySeparatorChar.ToString() calls.
This commit is contained in:
@@ -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<Duplicati.Library.Main.Controller> setup, List<string> args, Dictionary<string, string> 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<string> PrefixArgsWithAsterisk(IList<string> 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<Duplicati.Library.Main.Controller> setup, List<string> args, Dictionary<string, string> 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<Duplicati.Library.Main.Controller> setup, List<string> args, Dictionary<string, string> 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<Duplicati.Library.Main.Controller> setup, List<string> args, Dictionary<string, string> 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<Duplicati.Library.Main.Controller> setup, List<string> args, Dictionary<string, string> 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<string> 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<string>(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<Duplicati.Library.Main.Controller> setup, List<string> args, Dictionary<string, string> 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<Duplicati.Library.Interface.IListChangesResults, IEnumerable<Tuple<Library.Interface.ListChangesChangeType, Library.Interface.ListChangesElementType, string>>> handler =
|
||||
(result, items) =>
|
||||
{
|
||||
Action<Duplicati.Library.Interface.IListChangesResults, IEnumerable<Tuple<Library.Interface.ListChangesChangeType, Library.Interface.ListChangesElementType, string>>> 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<Duplicati.Library.Main.Controller> setup, List<string> args, Dictionary<string, string> 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<Duplicati.Library.Main.Controller> setup,
|
||||
List<string> args, Dictionary<string, string> options,
|
||||
List<string> args, Dictionary<string, string> options,
|
||||
Library.Utility.IFilter filter)
|
||||
{
|
||||
if (args.Count != 1)
|
||||
|
||||
@@ -208,6 +208,10 @@
|
||||
<Project>{0797AA22-C5DD-4950-BB60-34765AB8C6DD}</Project>
|
||||
<Name>Duplicati.Tools</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Library\IO\Duplicati.Library.IO.csproj">
|
||||
<Project>{D63E53E4-A458-4C2F-914D-92F715F58ACF}</Project>
|
||||
<Name>Duplicati.Library.IO</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="app.manifest">
|
||||
|
||||
@@ -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, "");
|
||||
|
||||
|
||||
@@ -66,7 +66,6 @@
|
||||
<Compile Include="VssBackupComponents.cs" />
|
||||
<Compile Include="Util.cs" />
|
||||
<Compile Include="DefineDosDevice.cs" />
|
||||
<Compile Include="WinNativeMethods.cs" />
|
||||
<Compile Include="FileEntry.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace Duplicati.Library.IO
|
||||
/// </summary>
|
||||
public static readonly string DirectorySeparatorString = Path.DirectorySeparatorChar.ToString();
|
||||
|
||||
public static readonly string AltDirectorySeparatorString = Path.AltDirectorySeparatorChar.ToString();
|
||||
|
||||
/// <summary>
|
||||
/// Appends the appropriate directory separator to paths, depending on OS.
|
||||
|
||||
@@ -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
|
||||
//{
|
||||
// /// <summary>
|
||||
// /// This class contains various Windows system calls related to reading locked files.
|
||||
// /// Some PInvoke signatures are from http://www.pinvoke.net
|
||||
// /// </summary>
|
||||
// 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
|
||||
// );
|
||||
|
||||
// /// <summary>
|
||||
// /// Opens a file with backup semantics, only works if the caller has the SeBackupPrivilege
|
||||
// /// </summary>
|
||||
// /// <param name="filename">The file to open</param>
|
||||
// /// <returns>The opened backup filestream</returns>
|
||||
// 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);
|
||||
// }
|
||||
|
||||
// /// <summary>
|
||||
// /// Internal helper function that returns two values relating to the SeBackupPrivilege
|
||||
// /// </summary>
|
||||
// /// <param name="hasPrivilege">True if the calling proccess has the SeBackupPrivilege, false otherwise</param>
|
||||
// /// <param name="isEnabled">True if the SeBackupPrivilege is enabled, false otherwise</param>
|
||||
// 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;
|
||||
// }
|
||||
|
||||
// /// <summary>
|
||||
// /// Gets a value indicating if the current process can set the SeBackupPrivilege value
|
||||
// /// </summary>
|
||||
// public static bool CanEnableBackupPrivilege
|
||||
// {
|
||||
// get
|
||||
// {
|
||||
// bool hasPrivilege, isEnabled;
|
||||
// GetBackupPrivilege(out hasPrivilege, out isEnabled);
|
||||
|
||||
// return hasPrivilege;
|
||||
// }
|
||||
// }
|
||||
|
||||
// /// <summary>
|
||||
// /// Gets or sets a value indicating if the current process has the backup privilege (SE_BACKUP_NAME)
|
||||
// /// </summary>
|
||||
// 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
|
||||
|
||||
// }
|
||||
//}
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -111,12 +111,12 @@ namespace Duplicati.Library.Utility
|
||||
/// <summary>
|
||||
/// Regex escaped string for the AltDirectorySeparatorChar
|
||||
/// </summary>
|
||||
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);
|
||||
|
||||
/// <summary>
|
||||
/// Regex escaped string for the DirectorySeparatorChar
|
||||
/// </summary>
|
||||
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);
|
||||
|
||||
/// <summary>
|
||||
/// 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;
|
||||
|
||||
@@ -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<string, string>(x, x.Substring(0, x.Length - 1).Substring(x.Substring(0, x.Length - 1).LastIndexOf("/", StringComparison.Ordinal) + 1));
|
||||
else
|
||||
return new KeyValuePair<string, string>(x, x);
|
||||
|
||||
@@ -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; }
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user