Updated to allow files as input arguments to backup

This commit is contained in:
Kenneth Skovhede
2013-06-29 12:17:52 +02:00
parent 2bf912a0af
commit a9ca999962
13 changed files with 164 additions and 168 deletions
+30 -19
View File
@@ -65,48 +65,59 @@ namespace Duplicati.Library.Main
m_options = new Options(options);
}
public Duplicati.Library.Interface.IBackupResults Backup(string[] sources, IFilter filter = null)
public Duplicati.Library.Interface.IBackupResults Backup(string[] inputsources, IFilter filter = null)
{
return RunAction(new BackupResults(), ref sources, (result) => {
return RunAction(new BackupResults(), ref inputsources, (result) => {
if (sources == null || sources.Length == 0)
if (inputsources == null || inputsources.Length == 0)
throw new Exception(Strings.Controller.NoSourceFoldersError);
var sources = new List<string>(inputsources);
//Make sure they all have the same format and exist
for(int i = 0; i < sources.Length; i++)
for(int i = 0; i < sources.Count; i++)
{
string fp;
try
{
fp = System.IO.Path.GetFullPath(sources[i]);
sources[i] = System.IO.Path.GetFullPath(sources[i]);
}
catch (Exception ex)
{
throw new ArgumentException(string.Format(Strings.Controller.InvalidPathError, sources[i], ex.Message), ex);
}
sources[i] = Library.Utility.Utility.AppendDirSeparator(fp);
if (!System.IO.Directory.Exists(sources[i]) && !m_options.AllowMissingSourceFolders)
throw new System.IO.IOException(String.Format(Strings.Controller.SourceFolderIsMissingError, sources[i]));
var fi = new System.IO.FileInfo(sources[i]);
var di = new System.IO.DirectoryInfo(sources[i]);
if (!(fi.Exists || di.Exists) && !m_options.AllowMissingSource)
throw new System.IO.IOException(String.Format(Strings.Controller.SourceIsMissingError, sources[i]));
if (!fi.Exists)
sources[i] = Library.Utility.Utility.AppendDirSeparator(sources[i]);
}
//Sanity check for duplicate folders and multiple inclusions of the same folder
//We could automatically fix this by excluding multiple copies of the same folder
// and remove the longest path of matching subfolders,
// but really the user should clean up the input
for(int i = 0; i < sources.Length - 1; i++)
for(int i = 0; i < sources.Count - 1; i++)
{
for(int j = i + 1; j < sources.Length; j++)
for(int j = i + 1; j < sources.Count; j++)
if (sources[i].Equals(sources[j], Library.Utility.Utility.IsFSCaseSensitive ? StringComparison.CurrentCulture : StringComparison.CurrentCultureIgnoreCase))
throw new Exception(string.Format(Strings.Controller.SourceDirIsIncludedMultipleTimesError, sources[i]));
{
result.AddVerboseMessage("Removing duplicate source: {0}", sources[j]);
sources.RemoveAt(j);
j--;
}
else if (sources[i].StartsWith(sources[j], Library.Utility.Utility.IsFSCaseSensitive ? StringComparison.CurrentCulture : StringComparison.CurrentCultureIgnoreCase))
throw new Exception(string.Format(Strings.Controller.SourceDirsAreRelatedError, sources[i], sources[j]));
{
result.AddVerboseMessage("Removing source \"{0}\" because it is a subfolder of \"{1}\"", sources[i], sources[j]);
filter = Library.Utility.JoinedFilterExpression.Join(new FilterExpression(sources[i]), filter);
sources.RemoveAt(i);
i--;
break;
}
}
using(var h = new Operation.BackupHandler(m_backend, m_options, result))
h.Run(sources, filter);
h.Run(sources.ToArray(), filter);
});
}
@@ -65,12 +65,12 @@ namespace Duplicati.Library.Main.Operation
throw new Exception(string.Format(Strings.Foresthash.InvalidCryptoSystem, m_options.FileHashAlgorithm));
}
private static Snapshots.ISnapshotService GetSnapshot(string[] sourcefolders, Options options, ILogWriter log)
private static Snapshots.ISnapshotService GetSnapshot(string[] sources, Options options, ILogWriter log)
{
try
{
if (options.SnapShotStrategy != Options.OptimizationStrategy.Off)
return Duplicati.Library.Snapshots.SnapshotUtility.CreateSnapshot(sourcefolders, options.RawOptions);
return Duplicati.Library.Snapshots.SnapshotUtility.CreateSnapshot(sources, options.RawOptions);
}
catch (Exception ex)
{
@@ -83,9 +83,9 @@ namespace Duplicati.Library.Main.Operation
}
return Library.Utility.Utility.IsClientLinux ?
(Library.Snapshots.ISnapshotService)new Duplicati.Library.Snapshots.NoSnapshotLinux(sourcefolders, options.RawOptions)
(Library.Snapshots.ISnapshotService)new Duplicati.Library.Snapshots.NoSnapshotLinux(sources, options.RawOptions)
:
(Library.Snapshots.ISnapshotService)new Duplicati.Library.Snapshots.NoSnapshotWindows(sourcefolders, options.RawOptions);
(Library.Snapshots.ISnapshotService)new Duplicati.Library.Snapshots.NoSnapshotWindows(sources, options.RawOptions);
}
+4 -4
View File
@@ -187,7 +187,7 @@ namespace Duplicati.Library.Main
"disable-autocreate-folder",
"disable-filetime-check",
"disable-time-tolerance",
"allow-missing-source-folders",
"allow-missing-source",
"skip-files-larger-than",
"upload-unchanged-backups",
"list-verify-uploads",
@@ -348,7 +348,7 @@ namespace Duplicati.Library.Main
new CommandLineArgument("version", CommandLineArgument.ArgumentType.String, Strings.Options.VersionShort, Strings.Options.VersionLong, ""),
new CommandLineArgument("all-versions", CommandLineArgument.ArgumentType.Boolean, Strings.Options.AllversionsShort, Strings.Options.AllversionsLong, "false"),
new CommandLineArgument("disable-autocreate-folder", CommandLineArgument.ArgumentType.Boolean, Strings.Options.DisableautocreatefolderShort, Strings.Options.DisableautocreatefolderLong, "false"),
new CommandLineArgument("allow-missing-source-folders", CommandLineArgument.ArgumentType.Boolean, Strings.Options.AllowmissingsourcefoldersShort, Strings.Options.AllowmissingsourcefoldersLong, "false"),
new CommandLineArgument("allow-missing-source", CommandLineArgument.ArgumentType.Boolean, Strings.Options.AllowmissingsourceShort, Strings.Options.AllowmissingsourceLong, "false"),
new CommandLineArgument("disable-filetime-check", CommandLineArgument.ArgumentType.Boolean, Strings.Options.DisablefiletimecheckShort, Strings.Options.DisablefiletimecheckLong, "false"),
//new CommandLineArgument("disable-usn-diff-check", CommandLineArgument.ArgumentType.Boolean, Strings.Options.DisableusndiffcheckShort, Strings.Options.DisableusndiffcheckLong, "false"),
@@ -1385,9 +1385,9 @@ namespace Duplicati.Library.Main
/// <summary>
/// Gets a flag indicating if compacting should not be done automatically
/// </summary>
public bool AllowMissingSourceFolders
public bool AllowMissingSource
{
get { return Library.Utility.Utility.ParseBoolOption(m_options, "allow-missing-source-folders"); }
get { return Library.Utility.Utility.ParseBoolOption(m_options, "allow-missing-source"); }
}
/// <summary>
+2 -29
View File
@@ -555,39 +555,12 @@ namespace Duplicati.Library.Main.Strings {
}
}
/// <summary>
/// Looks up a localized string similar to The folder {0} is included multiple times.
/// </summary>
internal static string SourceDirIsIncludedMultipleTimesError {
get {
return ResourceManager.GetString("SourceDirIsIncludedMultipleTimesError", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The folder {1} is a subfolder of {0}. It is not allowed to specify the same folder multiple times..
/// </summary>
internal static string SourceDirsAreRelatedError {
get {
return ResourceManager.GetString("SourceDirsAreRelatedError", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The source folder {0} does not exist, aborting backup.
/// </summary>
internal static string SourceFolderIsMissingError {
internal static string SourceIsMissingError {
get {
return ResourceManager.GetString("SourceFolderIsMissingError", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The folder {0} is no longer in the source folder set. It is not allowed to change source folders for a backup..
/// </summary>
internal static string SourceFoldersHasChangedError {
get {
return ResourceManager.GetString("SourceFoldersHasChangedError", resourceCulture);
return ResourceManager.GetString("SourceIsMissingError", resourceCulture);
}
}
+1 -10
View File
@@ -195,18 +195,9 @@
<data name="SkippedUnlistedSignatureFileWarning" xml:space="preserve">
<value>The signature file {0} was skipped because the signature file was not found in the manifest</value>
</data>
<data name="SourceDirIsIncludedMultipleTimesError" xml:space="preserve">
<value>The folder {0} is included multiple times</value>
</data>
<data name="SourceDirsAreRelatedError" xml:space="preserve">
<value>The folder {1} is a subfolder of {0}. It is not allowed to specify the same folder multiple times.</value>
</data>
<data name="SourceFolderIsMissingError" xml:space="preserve">
<data name="SourceIsMissingError" xml:space="preserve">
<value>The source folder {0} does not exist, aborting backup</value>
</data>
<data name="SourceFoldersHasChangedError" xml:space="preserve">
<value>The folder {0} is no longer in the source folder set. It is not allowed to change source folders for a backup.</value>
</data>
<data name="StatusBuildingFilelist" xml:space="preserve">
<value>Building filelist ...</value>
</data>
+6 -6
View File
@@ -61,20 +61,20 @@ namespace Duplicati.Library.Main.Strings {
}
/// <summary>
/// Looks up a localized string similar to Use this option to set the timespan in which backups are kept..
/// Looks up a localized string similar to Use this option to continue even if some source entries are missing..
/// </summary>
internal static string AllowmissingsourcefoldersLong {
internal static string AllowmissingsourceLong {
get {
return ResourceManager.GetString("AllowmissingsourcefoldersLong", resourceCulture);
return ResourceManager.GetString("AllowmissingsourceLong", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Keep all versions within a timespan.
/// Looks up a localized string similar to Ignore missing source elements.
/// </summary>
internal static string AllowmissingsourcefoldersShort {
internal static string AllowmissingsourceShort {
get {
return ResourceManager.GetString("AllowmissingsourcefoldersShort", resourceCulture);
return ResourceManager.GetString("AllowmissingsourceShort", resourceCulture);
}
}
+4 -4
View File
@@ -540,11 +540,11 @@
<data name="KeeptimeLong" xml:space="preserve">
<value>Use this option to set the timespan in which backups are kept.</value>
</data>
<data name="AllowmissingsourcefoldersShort" xml:space="preserve">
<value>Keep all versions within a timespan</value>
<data name="AllowmissingsourceShort" xml:space="preserve">
<value>Ignore missing source elements</value>
</data>
<data name="AllowmissingsourcefoldersLong" xml:space="preserve">
<value>Use this option to set the timespan in which backups are kept.</value>
<data name="AllowmissingsourceLong" xml:space="preserve">
<value>Use this option to continue even if some source entries are missing.</value>
</data>
<data name="DownloadedFileSizeError" xml:space="preserve">
<value>The file {0} was downloaded and had size {1} but the size was expected to be {2}</value>
@@ -48,6 +48,8 @@
<Reference Include="UnixSupport">
<HintPath>..\..\..\thirdparty\UnixSupport\UnixSupport.dll</HintPath>
</Reference>
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
</ItemGroup>
<ItemGroup>
<Compile Include="DefineDosDevice.cs" />
+3 -3
View File
@@ -68,7 +68,7 @@ namespace Duplicati.Library.Snapshots
public SnapShot(string path)
{
m_name = string.Format("duplicati-{0}", Guid.NewGuid().ToString());
m_realDir = Utility.Utility.AppendDirSeparator(path);
m_realDir = System.IO.Directory.Exists(path) ? Utility.Utility.AppendDirSeparator(path) : path;
GetVolumeName(m_realDir);
}
@@ -261,7 +261,7 @@ namespace Duplicati.Library.Snapshots
/// </summary>
/// <param name="folders">The list of folders to create snapshots for</param>
/// <param name="options">A set of commandline options</param>
public LinuxSnapshot(string[] folders, Dictionary<string, string> options)
public LinuxSnapshot(string[] sources, Dictionary<string, string> options)
{
try
{
@@ -269,7 +269,7 @@ namespace Duplicati.Library.Snapshots
//Make sure we do not create more snapshots than we have to
Dictionary<string, SnapShot> snaps = new Dictionary<string, SnapShot>();
foreach (string s in folders)
foreach (string s in sources)
{
SnapShot sn = new SnapShot(s);
if (!snaps.ContainsKey(sn.DeviceName))
+8 -8
View File
@@ -35,7 +35,7 @@ namespace Duplicati.Library.Snapshots
/// <summary>
/// The list of all folders in the snapshot
/// </summary>
protected string[] m_sourcefolders;
protected string[] m_sources;
/// <summary>
/// A frequently used char-as-string
@@ -46,8 +46,8 @@ namespace Duplicati.Library.Snapshots
/// Constructs a new backup snapshot, using all the required disks
/// </summary>
/// <param name="sourcepaths">The folders that are about to be backed up</param>
public NoSnapshot(string[] folders)
: this(folders, new Dictionary<string, string>())
public NoSnapshot(string[] sources)
: this(sources, new Dictionary<string, string>())
{
}
@@ -56,11 +56,11 @@ namespace Duplicati.Library.Snapshots
/// </summary>
/// <param name="folders">The folders that are about to be backed up</param>
/// <param name="options">A set of system options</param>
public NoSnapshot(string[] folders, Dictionary<string, string> options)
public NoSnapshot(string[] sources, Dictionary<string, string> options)
{
m_sourcefolders = new string[folders.Length];
for (int i = 0; i < m_sourcefolders.Length; i++)
m_sourcefolders[i] = Utility.Utility.AppendDirSeparator(folders[i]);
m_sources = new string[sources.Length];
for (int i = 0; i < m_sources.Length; i++)
m_sources[i] = System.IO.Directory.Exists(sources[i]) ? Utility.Utility.AppendDirSeparator(sources[i]) : sources[i];
}
#region Private Methods
@@ -101,7 +101,7 @@ namespace Duplicati.Library.Snapshots
/// <param name="callback">The callback to invoke with each found path</param>
public IEnumerable<string> EnumerateFilesAndFolders(Duplicati.Library.Utility.Utility.EnumerationFilterDelegate callback)
{
return m_sourcefolders.SelectMany(
return m_sources.SelectMany(
s => Utility.Utility.EnumerateFileSystemEntries(s, callback, this.ListFolders, this.ListFiles, this.GetAttributes)
);
}
@@ -29,13 +29,13 @@ namespace Duplicati.Library.Snapshots
{
private SystemIOWindows m_sysIO = new SystemIOWindows();
public NoSnapshotWindows(string[] sourcefolders)
: base(sourcefolders)
public NoSnapshotWindows(string[] sources)
: base(sources)
{
}
public NoSnapshotWindows(string[] sourcefolders, Dictionary<string, string> options)
: base(sourcefolders, options)
public NoSnapshotWindows(string[] sources, Dictionary<string, string> options)
: base(sources, options)
{
}
@@ -105,7 +105,7 @@ namespace Duplicati.Library.Snapshots
m_sourcepaths = new string[sourcepaths.Length];
for(int i = 0; i < m_sourcepaths.Length; i++)
m_sourcepaths[i] = Utility.Utility.AppendDirSeparator(sourcepaths[i]);
m_sourcepaths[i] = System.IO.Directory.Exists(sourcepaths[i]) ? Utility.Utility.AppendDirSeparator(sourcepaths[i]) : sourcepaths[i];
try
{
+95 -76
View File
@@ -215,7 +215,7 @@ namespace Duplicati.Library.Utility
/// </summary>
/// <param name="path">The path to return data from</param>
/// <returns>Attributes for the file or folder</returns>
public delegate System.IO.FileAttributes ExtractFileAttributes(string path);
public delegate System.IO.FileAttributes ExtractFileAttributes(string path);
/// <summary>
/// Returns a list of all files found in the given folder.
/// The search is recursive.
@@ -224,10 +224,10 @@ namespace Duplicati.Library.Utility
/// <param name="filter">An optional filter to apply to the filenames</param>
/// <param name="callback">The function to call with the filenames</param>
/// <returns>A list of the full filenames</returns>
public static IEnumerable<string> EnumerateFileSystemEntries(string rootpath, EnumerationFilterDelegate callback)
{
return EnumerateFileSystemEntries(rootpath, callback, new FileSystemInteraction(System.IO.Directory.GetDirectories), new FileSystemInteraction(System.IO.Directory.GetFiles));
}
public static IEnumerable<string> EnumerateFileSystemEntries(string rootpath, EnumerationFilterDelegate callback)
{
return EnumerateFileSystemEntries(rootpath, callback, new FileSystemInteraction(System.IO.Directory.GetDirectories), new FileSystemInteraction(System.IO.Directory.GetFiles));
}
/// <summary>
/// Returns a list of all files found in the given folder.
/// The search is recursive.
@@ -237,10 +237,10 @@ namespace Duplicati.Library.Utility
/// <param name="folderList">A function to call that lists all folders in the supplied folder</param>
/// <param name="fileList">A function to call that lists all files in the supplied folder</param>
/// <returns>A list of the full filenames</returns>
public static IEnumerable<string> EnumerateFileSystemEntries(string rootpath, EnumerationFilterDelegate callback, FileSystemInteraction folderList, FileSystemInteraction fileList)
{
return EnumerateFileSystemEntries(rootpath, callback, folderList, fileList, null);
}
public static IEnumerable<string> EnumerateFileSystemEntries(string rootpath, EnumerationFilterDelegate callback, FileSystemInteraction folderList, FileSystemInteraction fileList)
{
return EnumerateFileSystemEntries(rootpath, callback, folderList, fileList, null);
}
/// <summary>
/// Returns a list of all files found in the given folder.
/// The search is recursive.
@@ -251,77 +251,96 @@ namespace Duplicati.Library.Utility
/// <param name="fileList">A function to call that lists all files in the supplied folder</param>
/// <param name="attributeReader">A function to call that obtains the attributes for an element, set to null to avoid reading attributes</param>
/// <returns>A list of the full filenames</returns>
public static IEnumerable<string> EnumerateFileSystemEntries(string rootpath, EnumerationFilterDelegate callback, FileSystemInteraction folderList, FileSystemInteraction fileList, ExtractFileAttributes attributeReader)
{
if (System.IO.Directory.Exists(rootpath))
{
Queue<string> lst = new Queue<string>();
lst.Enqueue(rootpath);
public static IEnumerable<string> EnumerateFileSystemEntries(string rootpath, EnumerationFilterDelegate callback, FileSystemInteraction folderList, FileSystemInteraction fileList, ExtractFileAttributes attributeReader)
{
if (System.IO.Directory.Exists(rootpath))
{
Queue<string> lst = new Queue<string>();
lst.Enqueue(rootpath);
while (lst.Count > 0)
{
string f = AppendDirSeparator(lst.Dequeue());
string fv = null;
try
{
System.IO.FileAttributes attr = attributeReader == null ? System.IO.FileAttributes.Directory : attributeReader(f);
if (!callback(rootpath, f, attr))
continue;
while (lst.Count > 0)
{
string f = AppendDirSeparator(lst.Dequeue());
string fv = null;
try
{
System.IO.FileAttributes attr = attributeReader == null ? System.IO.FileAttributes.Directory : attributeReader(f);
if (!callback(rootpath, f, attr))
continue;
fv = f;
foreach(string s in folderList(f))
lst.Enqueue(s);
}
catch (System.Threading.ThreadAbortException)
{
throw;
}
catch (Exception)
{
callback(rootpath, f, ATTRIBUTE_ERROR | System.IO.FileAttributes.Directory);
}
fv = f;
if (fv != null)
yield return fv;
foreach(string s in folderList(f))
lst.Enqueue(s);
}
catch (System.Threading.ThreadAbortException)
{
throw;
}
catch (Exception)
{
callback(rootpath, f, ATTRIBUTE_ERROR | System.IO.FileAttributes.Directory);
}
if (fv != null)
yield return fv;
string[] files = null;
if (fileList != null)
try
{
files = fileList(f);
}
catch (System.Threading.ThreadAbortException)
{
throw;
}
catch (Exception)
{
callback(rootpath, f, ATTRIBUTE_ERROR);
}
string[] files = null;
if (fileList != null)
try
{
files = fileList(f);
}
catch (System.Threading.ThreadAbortException)
{
throw;
}
catch (Exception)
{
callback(rootpath, f, ATTRIBUTE_ERROR);
}
if (files != null)
foreach(var s in files)
{
try
{
System.IO.FileAttributes attr = attributeReader == null ? System.IO.FileAttributes.Normal : attributeReader(s);
if (!callback(rootpath, s, attr))
continue;
}
catch (System.Threading.ThreadAbortException)
{
throw;
}
catch (Exception)
{
callback(rootpath, s, ATTRIBUTE_ERROR);
continue;
}
yield return s;
}
}
}
if (files != null)
foreach(var s in files)
{
try
{
System.IO.FileAttributes attr = attributeReader == null ? System.IO.FileAttributes.Normal : attributeReader(s);
if (!callback(rootpath, s, attr))
continue;
}
catch (System.Threading.ThreadAbortException)
{
throw;
}
catch (Exception)
{
callback(rootpath, s, ATTRIBUTE_ERROR);
continue;
}
yield return s;
}
}
}
else if (System.IO.File.Exists(rootpath))
{
try
{
System.IO.FileAttributes attr = attributeReader == null ? System.IO.FileAttributes.Normal : attributeReader(rootpath);
if (!callback(rootpath, rootpath, attr))
yield break;
}
catch (System.Threading.ThreadAbortException)
{
throw;
}
catch (Exception)
{
callback(rootpath, rootpath, ATTRIBUTE_ERROR);
yield break;
}
yield return rootpath;
}
}
/// <summary>
/// Calculates the size of files in a given folder