2013-02-12 21:43:14 +00:00
#region Disclaimer / License
// Copyright (C) 2011, Kenneth Skovhede
// http://www.hexad.dk, opensource@hexad.dk
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
#endregion
using System ;
using System.Collections.Generic ;
using System.Text ;
using Duplicati.Library.Utility ;
namespace Duplicati.Library.Main
{
/// <summary>
/// The operations that Duplicati can report
/// </summary>
public enum DuplicatiOperation
{
/// <summary>
/// Indicates that the operations is a full or incremental backup
/// </summary>
Backup ,
/// <summary>
/// Indicates that the operation is a restore type operation
/// </summary>
Restore ,
/// <summary>
/// Indicates that the operation is a list type operation
/// </summary>
List ,
/// <summary>
/// Indicates that the operation is a delete type operation
/// </summary>
Remove
}
/// <summary>
/// The actual operation that Duplicati supports
/// </summary>
public enum DuplicatiOperationMode
{
/// <summary>
/// A backup operation, either full or incremental
/// </summary>
Backup ,
/// <summary>
/// A full backup
/// </summary>
BackupFull ,
/// <summary>
/// An incremental backup
/// </summary>
BackupIncremental ,
/// <summary>
/// A restore operation
/// </summary>
Restore ,
/// <summary>
/// A restore operation for control files
/// </summary>
RestoreControlfiles ,
/// <summary>
2013-05-05 18:14:27 +02:00
/// A backup file listing
2013-02-12 21:43:14 +00:00
/// </summary>
List ,
/// <summary>
/// A list of backup chains found on the backend
/// </summary>
GetBackupSets ,
/// <summary>
/// A list of the source folders found in a specific backup set
/// </summary>
ListSourceFolders ,
/// <summary>
/// A list of files found in a specific backup set, only shows content from the single backup set and not the entire chain
/// </summary>
ListActualSignatureFiles ,
/// <summary>
/// A delete operation performed by looking at the number of existing full backups
/// </summary>
DeleteAllButNFull ,
/// <summary>
/// A delete operation performed by looking at the number of existing backups
/// </summary>
DeleteAllButN ,
/// <summary>
/// A delete operation performed by looking at the age of existing backups
/// </summary>
DeleteOlderThan ,
/// <summary>
/// A cleanup operation that removes orphan files
/// </summary>
CleanUp ,
/// <summary>
/// A request to create the underlying folder
/// </summary>
CreateFolder ,
/// <summary>
/// A search for files in signature files
/// </summary>
FindLastFileVersion ,
/// <summary>
/// Verifies the hashes and backup chain
/// </summary>
2013-04-22 21:20:14 +02:00
Verify ,
/// <summary>
/// Creates a log of the database suitable for attaching to a bug report
/// </summary>
CreateLogDb
2013-02-12 21:43:14 +00:00
}
/// <summary>
/// An enum that describes the level of verification done by the verify command
/// </summary>
public enum VerificationLevel
{
/// <summary>
/// Just verify the manifest chain
/// </summary>
Manifest ,
/// <summary>
/// Verify the manifest chain and all signature files
/// </summary>
Signature ,
/// <summary>
/// Verify everything, including the content files, requires download of all files
/// </summary>
Full ,
}
/// <summary>
/// A delegate for reporting progress from within the Duplicati module
/// </summary>
/// <param name="caller">The instance that is running</param>
/// <param name="operation">The overall operation type</param>
/// <param name="specificoperation">A more specific type of operation</param>
/// <param name="progress">The current overall progress of the operation</param>
/// <param name="subprogress">The progress of a transfer</param>
/// <param name="message">A message describing the current operation</param>
/// <param name="submessage">A message describing the current transfer operation</param>
public delegate void OperationProgressEvent ( Interface caller , DuplicatiOperation operation , DuplicatiOperationMode specificoperation , int progress , int subprogress , string message , string submessage );
/// <summary>
/// A delegate used to report metadata about the current backup, obtained while running a normal operation
/// </summary>
/// <param name="metadata">A table with various metadata informations</param>
public delegate void MetadataReportDelegate ( IDictionary < string , string > metadata );
2013-05-05 17:54:59 +02:00
public class Interface : IDisposable
2013-02-12 21:43:14 +00:00
{
/// <summary>
/// The amount of progressbar allocated for reading incremental data
/// </summary>
private const double INCREMENAL_COST = 0.10 ;
/// <summary>
/// The amount of progressbar allocated for uploading async volumes
/// </summary>
private const double ASYNC_RESERVED = 0.10 ;
/// <summary>
/// The backend url
/// </summary>
private string m_backend ;
/// <summary>
/// The parsed type-safe version of the commandline options
/// </summary>
private Options m_options ;
/// <summary>
/// The restult of an operation, used to report via IGenericCallbackModule
/// </summary>
private object m_result ;
/// <summary>
/// The amount of progressbar allocated for reading incremental data
/// </summary>
private double m_incrementalFraction = INCREMENAL_COST ;
/// <summary>
/// The amount of progressbar allocated for uploading the remaining volumes in asynchronous mode
/// </summary>
private double m_asyncReserved = 0.0 ;
/// <summary>
/// The current overall progress without taking the reserved amounts into account
/// </summary>
private double m_progress = 0.0 ;
/// <summary>
/// The number of restore patches
/// </summary>
private int m_restorePatches = 0 ;
/// <summary>
/// Cache of the last progress message
/// </summary>
private string m_lastProgressMessage = "" ;
/// <summary>
/// A flag indicating if logging has been set, used to dispose the logging
/// </summary>
private bool m_hasSetLogging = false ;
/// <summary>
/// A flag toggling if the upload progress is reported,
/// used to prevent showing the progress bar when performing
/// ansynchronous uploads
/// </summary>
private bool m_allowUploadProgress = true ;
/// <summary>
/// When allowing the upload progress to be reported,
/// there can be a flicker because the upload progresses,
/// before the flag is disabled again. This value
/// is set to DateTime.Now.AddSeconds(1) before
/// entering a potentially blocking operation, which
/// allows the progress to be reported if the call blocks,
/// but prevents flicker from non-blocking calls.
/// </summary>
private DateTime m_allowUploadProgressAfter = DateTime . Now ;
public event OperationProgressEvent OperationStarted ;
public event OperationProgressEvent OperationCompleted ;
public event OperationProgressEvent OperationProgress ;
public event OperationProgressEvent OperationError ;
public event MetadataReportDelegate MetadataReport ;
/// <summary>
/// This gets called whenever execution of an operation is started or stopped; it currently handles the AllowSleep option
/// </summary>
/// <param name="isRunning">Flag indicating execution state</param>
private void OperationRunning ( bool isRunning )
{
if ( m_options != null && ! m_options . AllowSleep && ! Duplicati . Library . Utility . Utility . IsClientLinux )
try
{
Win32 . SetThreadExecutionState ( Win32 . EXECUTION_STATE . ES_CONTINUOUS | ( isRunning ? Win32 . EXECUTION_STATE . ES_SYSTEM_REQUIRED : 0 ));
}
catch { } //TODO: Report this somehow
}
/// <summary>
/// Returns the current overall operation mode based on the actual operation mode
/// </summary>
/// <returns>The overall operation type</returns>
private DuplicatiOperation GetOperationType ()
{
switch ( m_options . MainAction )
{
case DuplicatiOperationMode . Backup :
case DuplicatiOperationMode . BackupFull :
case DuplicatiOperationMode . BackupIncremental :
return DuplicatiOperation . Backup ;
case DuplicatiOperationMode . Restore :
case DuplicatiOperationMode . RestoreControlfiles :
return DuplicatiOperation . Restore ;
case DuplicatiOperationMode . List :
case DuplicatiOperationMode . GetBackupSets :
case DuplicatiOperationMode . ListSourceFolders :
case DuplicatiOperationMode . ListActualSignatureFiles :
case DuplicatiOperationMode . FindLastFileVersion :
case DuplicatiOperationMode . Verify :
return DuplicatiOperation . List ;
case DuplicatiOperationMode . DeleteAllButNFull :
case DuplicatiOperationMode . DeleteOlderThan :
case DuplicatiOperationMode . CleanUp :
return DuplicatiOperation . Remove ;
default :
throw new Exception ( string . Format ( Strings . Interface . UnexpectedOperationTypeError , m_options . MainAction ));
}
}
/// <summary>
/// Constructs a new interface for performing backup and restore operations
/// </summary>
/// <param name="backend">The url for the backend to use</param>
/// <param name="options">All required options</param>
public Interface ( string backend , Dictionary < string , string > options )
{
m_backend = backend ;
m_options = new Options ( options );
OperationProgress += new OperationProgressEvent ( Interface_OperationProgress );
}
/// <summary>
/// Event handler for the OperationProgres, used to store the last status message
/// </summary>
private void Interface_OperationProgress ( Interface caller , DuplicatiOperation operation , DuplicatiOperationMode specificoperation , int progress , int subprogress , string message , string submessage )
{
m_lastProgressMessage = message ;
}
2013-05-05 17:54:59 +02:00
public string Backup ( string [] sources )
2013-02-12 21:43:14 +00:00
{
BackupStatistics bs = new BackupStatistics ( DuplicatiOperationMode . Backup );
SetupCommonOptions ( bs , ref sources );
using ( new Logging . Timer ( "Backup from " + string . Join ( ";" , sources ) + " to " + m_backend ))
{
var fhopts = new ForestHash . FhOptions ( m_options . RawOptions );
if ( string . IsNullOrEmpty ( fhopts . Fhdbpath ))
throw new Exception ( string . Format ( Strings . Interface . MissingDatabasepathError , "fh-dbpath" ));
if ( sources == null || sources . Length == 0 )
throw new Exception ( Strings . Interface . NoSourceFoldersError );
//Make sure they all have the same format and exist
for ( int i = 0 ; i < sources . Length ; i ++)
{
sources [ i ] = Utility . Utility . AppendDirSeparator ( System . IO . Path . GetFullPath ( sources [ i ]));
if (! System . IO . Directory . Exists ( sources [ i ]))
throw new System . IO . IOException ( String . Format ( Strings . Interface . SourceFolderIsMissingError , sources [ i ]));
}
//Sanity check for duplicate folders and multiple inclusions of the same folder
for ( int i = 0 ; i < sources . Length - 1 ; i ++)
{
for ( int j = i + 1 ; j < sources . Length ; j ++)
if ( sources [ i ]. Equals ( sources [ j ], Utility . Utility . IsFSCaseSensitive ? StringComparison . CurrentCulture : StringComparison . CurrentCultureIgnoreCase ))
throw new Exception ( string . Format ( Strings . Interface . SourceDirIsIncludedMultipleTimesError , sources [ i ]));
else if ( sources [ i ]. StartsWith ( sources [ j ], Utility . Utility . IsFSCaseSensitive ? StringComparison . CurrentCulture : StringComparison . CurrentCultureIgnoreCase ))
throw new Exception ( string . Format ( Strings . Interface . SourceDirsAreRelatedError , sources [ i ], sources [ j ]));
}
ForestHash . ForestHash . Backup ( m_backend , fhopts , bs , sources );
return bs . ToString ();
}
}
2013-05-05 17:54:59 +02:00
public string Restore ( string [] target )
2013-02-12 21:43:14 +00:00
{
if ( target == null || target . Length != 1 )
throw new Exception ( "Cannot specify more than a single target folder" );
var rs = new RestoreStatistics ( DuplicatiOperationMode . Restore );
SetupCommonOptions ( rs , ref target );
var fhopts = new ForestHash . FhOptions ( m_options . RawOptions );
ForestHash . ForestHash . Restore ( m_backend , fhopts , rs , target [ 0 ]);
return rs . ToString ();
}
2013-05-05 17:54:59 +02:00
public string RestoreControlFiles ( string target )
2013-02-12 21:43:14 +00:00
{
2013-05-05 17:54:59 +02:00
var rs = new RestoreStatistics ( DuplicatiOperationMode . RestoreControlfiles );
SetupCommonOptions ( rs );
2013-04-05 10:22:00 +02:00
2013-05-05 17:54:59 +02:00
var fhopts = new ForestHash . FhOptions ( m_options . RawOptions );
2013-02-12 21:43:14 +00:00
2013-05-05 17:54:59 +02:00
using ( var handler = new ForestHash . Operation . RestoreControlFilesHandler ( m_backend , fhopts , rs , target ))
handler . Run ();
2013-02-12 21:43:14 +00:00
2013-05-05 17:54:59 +02:00
return rs . ToString ();
2013-02-12 21:43:14 +00:00
}
2013-05-05 17:54:59 +02:00
public string DeleteAllButN ()
2013-02-12 21:43:14 +00:00
{
2013-05-05 17:54:59 +02:00
var rs = new RestoreStatistics ( DuplicatiOperationMode . DeleteAllButN );
SetupCommonOptions ( rs );
2013-02-12 21:43:14 +00:00
2013-05-05 17:54:59 +02:00
var fhopts = new ForestHash . FhOptions ( m_options . RawOptions );
2013-02-12 21:43:14 +00:00
2013-05-05 17:54:59 +02:00
using ( var handler = new ForestHash . Operation . DeleteHandler ( m_backend , fhopts , rs ))
handler . Run ();
2013-02-12 21:43:14 +00:00
2013-05-05 17:54:59 +02:00
return rs . ToString ();
2013-02-12 21:43:14 +00:00
}
2013-05-05 17:54:59 +02:00
public string Repair ()
2013-02-12 21:43:14 +00:00
{
2013-05-05 17:54:59 +02:00
var rs = new RestoreStatistics ( DuplicatiOperationMode . CleanUp );
SetupCommonOptions ( rs );
2013-02-12 21:43:14 +00:00
2013-05-05 17:54:59 +02:00
var fhopts = new ForestHash . FhOptions ( m_options . RawOptions );
2013-02-12 21:43:14 +00:00
2013-05-05 17:54:59 +02:00
using ( var handler = new ForestHash . Operation . RepairHandler ( m_backend , fhopts , rs ))
handler . Run ();
2013-02-12 21:43:14 +00:00
2013-05-05 17:54:59 +02:00
return rs . ToString ();
2013-02-12 21:43:14 +00:00
}
2013-05-05 17:54:59 +02:00
2013-05-05 18:14:27 +02:00
public List < string > List ()
2013-02-12 21:43:14 +00:00
{
2013-05-05 18:14:27 +02:00
var rs = new RestoreStatistics ( DuplicatiOperationMode . List );
2013-05-05 17:54:59 +02:00
SetupCommonOptions ( rs );
2013-02-12 21:43:14 +00:00
2013-05-05 17:54:59 +02:00
var fhopts = new ForestHash . FhOptions ( m_options . RawOptions );
2013-02-12 21:43:14 +00:00
2013-05-05 17:54:59 +02:00
using ( var handler = new ForestHash . Operation . ListFilesHandler ( m_backend , fhopts , rs ))
return handler . Run ();
2013-02-12 21:43:14 +00:00
}
private void SetupCommonOptions ( CommunicationStatistics stats )
{
string [] tmp = null ;
SetupCommonOptions ( stats , ref tmp );
}
private void SetupCommonOptions ( CommunicationStatistics stats , ref string [] paths )
{
m_options . MainAction = stats . OperationMode ;
switch ( m_options . MainAction )
{
case DuplicatiOperationMode . Backup :
case DuplicatiOperationMode . BackupFull :
case DuplicatiOperationMode . BackupIncremental :
break ;
default :
//It only makes sense to enable auto-creation if we are writing files.
if (! m_options . RawOptions . ContainsKey ( "disable-autocreate-folder" ))
m_options . RawOptions [ "disable-autocreate-folder" ] = "true" ;
break ;
}
//Load all generic modules
m_options . LoadedModules . Clear ();
foreach ( Library . Interface . IGenericModule m in DynamicLoader . GenericLoader . Modules )
m_options . LoadedModules . Add ( new KeyValuePair < bool , Library . Interface . IGenericModule >( Array . IndexOf < string >( m_options . DisableModules , m . Key . ToLower ()) < 0 && ( m . LoadAsDefault || Array . IndexOf < string >( m_options . EnableModules , m . Key . ToLower ()) >= 0 ), m ));
foreach ( KeyValuePair < bool , Library . Interface . IGenericModule > mx in m_options . LoadedModules )
if ( mx . Key )
{
mx . Value . Configure ( m_options . RawOptions );
if ( mx . Value is Library . Interface . IGenericCallbackModule )
(( Library . Interface . IGenericCallbackModule ) mx . Value ). OnStart ( stats . OperationMode . ToString (), ref m_backend , ref paths );
}
OperationRunning ( true );
Library . Logging . Log . LogLevel = m_options . Loglevel ;
if (! string . IsNullOrEmpty ( m_options . Logfile ))
{
m_hasSetLogging = true ;
2013-03-08 23:04:19 +01:00
var path = System . IO . Path . GetDirectoryName ( System . IO . Path . GetFullPath ( m_options . Logfile ));
if (! System . IO . Directory . Exists ( path ))
System . IO . Directory . CreateDirectory ( path );
2013-02-12 21:43:14 +00:00
Library . Logging . Log . CurrentLog = new Library . Logging . StreamLog ( m_options . Logfile );
}
if ( stats != null )
{
stats . VerboseErrors = m_options . DebugOutput ;
stats . VerboseRetryErrors = m_options . VerboseRetryErrors ;
2013-03-27 16:06:45 +01:00
stats . QuietConsole = m_options . QuietConsole ;
2013-02-12 21:43:14 +00:00
}
2013-03-08 12:25:35 +01:00
if ( m_options . HasTempDir )
2013-02-12 21:43:14 +00:00
Utility . TempFolder . SystemTempPath = m_options . TempDir ;
if (! string . IsNullOrEmpty ( m_options . ThreadPriority ))
System . Threading . Thread . CurrentThread . Priority = Utility . Utility . ParsePriority ( m_options . ThreadPriority );
ValidateOptions ( stats );
Library . Logging . Log . WriteMessage ( string . Format ( Strings . Interface . StartingOperationMessage , m_options . MainAction ), Logging . LogMessageType . Information );
}
2013-05-05 17:54:59 +02:00
public List < KeyValuePair < string , DateTime >> FindLastFileVersion ()
2013-02-12 21:43:14 +00:00
{
var rs = new RestoreStatistics ( DuplicatiOperationMode . FindLastFileVersion );
SetupCommonOptions ( rs );
var fhopts = new ForestHash . FhOptions ( m_options . RawOptions );
using ( var handler = new ForestHash . Operation . FindLastFileVersionHandler ( m_backend , fhopts , rs ))
return handler . Run ();
}
/// <summary>
/// This function will examine all options passed on the commandline, and test for unsupported or deprecated values.
/// Any errors will be logged into the statistics module.
/// </summary>
/// <param name="options">The commandline options given</param>
/// <param name="backend">The backend url</param>
/// <param name="stats">The statistics into which warnings are written</param>
private void ValidateOptions ( CommunicationStatistics stats )
{
//No point in going through with this if we can't report
if ( stats == null )
return ;
//Keep a list of all supplied options
2013-05-05 13:09:55 +02:00
Dictionary < string , string > ropts = new Dictionary < string , string >( m_options . RawOptions );
2013-02-12 21:43:14 +00:00
//Keep a list of all supported options
Dictionary < string , Library . Interface . ICommandLineArgument > supportedOptions = new Dictionary < string , Library . Interface . ICommandLineArgument >();
//There are a few internal options that are not accessible from outside, and thus not listed
foreach ( string s in Options . InternalOptions )
supportedOptions [ s ] = null ;
//Figure out what module options are supported in the current setup
List < Library . Interface . ICommandLineArgument > moduleOptions = new List < Duplicati . Library . Interface . ICommandLineArgument >();
Dictionary < string , string > disabledModuleOptions = new Dictionary < string , string >();
foreach ( KeyValuePair < bool , Library . Interface . IGenericModule > m in m_options . LoadedModules )
if ( m . Value . SupportedCommands != null )
if ( m . Key )
moduleOptions . AddRange ( m . Value . SupportedCommands );
else
{
foreach ( Library . Interface . ICommandLineArgument c in m . Value . SupportedCommands )
{
disabledModuleOptions [ c . Name ] = m . Value . DisplayName + " (" + m . Value . Key + ")" ;
if ( c . Aliases != null )
foreach ( string s in c . Aliases )
disabledModuleOptions [ s ] = disabledModuleOptions [ c . Name ];
}
}
2013-05-05 13:09:55 +02:00
// Throw url-encoded options into the mix
//TODO: This can hide values if both commandline and url-parameters supply the same key
2013-05-05 23:46:00 +02:00
var ext = new Utility . Uri ( m_backend ). QueryParameters ;
foreach ( var k in ext . AllKeys )
ropts [ k ] = ext [ k ];
2013-02-12 21:43:14 +00:00
//Now run through all supported options, and look for deprecated options
foreach ( IList < Library . Interface . ICommandLineArgument > l in new IList < Library . Interface . ICommandLineArgument >[] {
m_options . SupportedCommands ,
DynamicLoader . BackendLoader . GetSupportedCommands ( m_backend ),
m_options . NoEncryption ? null : DynamicLoader . EncryptionLoader . GetSupportedCommands ( m_options . EncryptionModule ),
moduleOptions ,
DynamicLoader . CompressionLoader . GetSupportedCommands ( m_options . CompressionModule ) })
{
if ( l != null )
foreach ( Library . Interface . ICommandLineArgument a in l )
{
if ( supportedOptions . ContainsKey ( a . Name ) && Array . IndexOf ( Options . KnownDuplicates , a . Name . ToLower ()) < 0 )
stats . LogWarning ( string . Format ( Strings . Interface . DuplicateOptionNameWarning , a . Name ), null );
supportedOptions [ a . Name ] = a ;
if ( a . Aliases != null )
foreach ( string s in a . Aliases )
{
if ( supportedOptions . ContainsKey ( s ) && Array . IndexOf ( Options . KnownDuplicates , s . ToLower ()) < 0 )
stats . LogWarning ( string . Format ( Strings . Interface . DuplicateOptionNameWarning , s ), null );
supportedOptions [ s ] = a ;
}
if ( a . Deprecated )
{
List < string > aliases = new List < string >();
aliases . Add ( a . Name );
if ( a . Aliases != null )
aliases . AddRange ( a . Aliases );
foreach ( string s in aliases )
if ( ropts . ContainsKey ( s ))
{
string optname = a . Name ;
if ( a . Name != s )
optname += " (" + s + ")" ;
stats . LogWarning ( string . Format ( Strings . Interface . DeprecatedOptionUsedWarning , optname , a . DeprecationMessage ), null );
}
}
}
}
//Now look for options that were supplied but not supported
foreach ( string s in ropts . Keys )
if (! supportedOptions . ContainsKey ( s ))
if ( disabledModuleOptions . ContainsKey ( s ))
stats . LogWarning ( string . Format ( Strings . Interface . UnsupportedOptionDisabledModuleWarning , s , disabledModuleOptions [ s ]), null );
else
stats . LogWarning ( string . Format ( Strings . Interface . UnsupportedOptionWarning , s ), null );
//Look at the value supplied for each argument and see if is valid according to its type
foreach ( string s in ropts . Keys )
{
Library . Interface . ICommandLineArgument arg ;
if ( supportedOptions . TryGetValue ( s , out arg ) && arg != null )
{
string validationMessage = ValidateOptionValue ( arg , s , ropts [ s ]);
if ( validationMessage != null )
stats . LogWarning ( validationMessage , null );
}
}
//TODO: Based on the action, see if all options are relevant
}
#region Static interface
/// <summary>
/// Checks if the value passed to an option is actually valid.
/// </summary>
/// <param name="arg">The argument being validated</param>
/// <param name="optionname">The name of the option to validate</param>
/// <param name="value">The value to check</param>
/// <returns>Null if no errors are found, an error message otherwise</returns>
public static string ValidateOptionValue ( Library . Interface . ICommandLineArgument arg , string optionname , string value )
{
if ( arg . Type == Duplicati . Library . Interface . CommandLineArgument . ArgumentType . Enumeration )
{
bool found = false ;
foreach ( string v in arg . ValidValues ?? new string [ 0 ])
if ( string . Equals ( v , value , StringComparison . CurrentCultureIgnoreCase ))
{
found = true ;
break ;
}
if (! found )
return string . Format ( Strings . Interface . UnsupportedEnumerationValue , optionname , value , string . Join ( ", " , arg . ValidValues ?? new string [ 0 ]));
}
else if ( arg . Type == Duplicati . Library . Interface . CommandLineArgument . ArgumentType . Boolean )
{
if (! string . IsNullOrEmpty ( value ) && Utility . Utility . ParseBool ( value , true ) != Utility . Utility . ParseBool ( value , false ))
return string . Format ( Strings . Interface . UnsupportedBooleanValue , optionname , value );
}
else if ( arg . Type == Duplicati . Library . Interface . CommandLineArgument . ArgumentType . Integer )
{
long l ;
if (! long . TryParse ( value , out l ))
return string . Format ( Strings . Interface . UnsupportedIntegerValue , optionname , value );
}
else if ( arg . Type == Duplicati . Library . Interface . CommandLineArgument . ArgumentType . Path )
{
foreach ( string p in value . Split ( System . IO . Path . DirectorySeparatorChar ))
if ( p . IndexOfAny ( System . IO . Path . GetInvalidPathChars ()) >= 0 )
return string . Format ( Strings . Interface . UnsupportedPathValue , optionname , p );
}
else if ( arg . Type == Duplicati . Library . Interface . CommandLineArgument . ArgumentType . Size )
{
try
{
Utility . Sizeparser . ParseSize ( value );
}
catch
{
return string . Format ( Strings . Interface . UnsupportedSizeValue , optionname , value );
}
}
else if ( arg . Type == Duplicati . Library . Interface . CommandLineArgument . ArgumentType . Timespan )
{
try
{
Utility . Timeparser . ParseTimeSpan ( value );
}
catch
{
return string . Format ( Strings . Interface . UnsupportedTimeValue , optionname , value );
}
}
return null ;
}
public static string Backup ( string [] source , string target , Dictionary < string , string > options )
{
using ( Interface i = new Interface ( target , options ))
return i . Backup ( source );
}
public static string Restore ( string source , string [] target , Dictionary < string , string > options )
{
using ( Interface i = new Interface ( source , options ))
return i . Restore ( target );
}
2013-05-05 18:14:27 +02:00
public static IList < string > List ( string target , Dictionary < string , string > options )
2013-02-12 21:43:14 +00:00
{
using ( Interface i = new Interface ( target , options ))
2013-05-05 18:14:27 +02:00
return i . List ();
2013-02-12 21:43:14 +00:00
}
2013-05-05 17:54:59 +02:00
2013-02-12 21:43:14 +00:00
public static string DeleteAllButN ( string target , Dictionary < string , string > options )
{
using ( Interface i = new Interface ( target , options ))
return i . DeleteAllButN ();
}
public static string DeleteOlderThan ( string target , Dictionary < string , string > options )
{
using ( Interface i = new Interface ( target , options ))
2013-05-05 17:54:59 +02:00
return i . DeleteAllButN ();
2013-02-12 21:43:14 +00:00
}
2013-05-05 17:54:59 +02:00
public static string Repair ( string target , Dictionary < string , string > options )
2013-02-12 21:43:14 +00:00
{
using ( Interface i = new Interface ( target , options ))
2013-05-05 17:54:59 +02:00
return i . Repair ();
2013-02-12 21:43:14 +00:00
}
public static string RestoreControlFiles ( string source , string target , Dictionary < string , string > options )
{
using ( Interface i = new Interface ( source , options ))
return i . RestoreControlFiles ( target );
}
public static List < KeyValuePair < string , DateTime >> FindLastFileVersion ( string target , Dictionary < string , string > options )
{
using ( Interface i = new Interface ( target , options ))
return i . FindLastFileVersion ();
}
#endregion
#region IDisposable Members
public void Dispose ()
{
if ( m_options != null && m_options . LoadedModules != null )
{
foreach ( KeyValuePair < bool , Library . Interface . IGenericModule > mx in m_options . LoadedModules )
if ( mx . Key && mx . Value is Duplicati . Library . Interface . IGenericCallbackModule )
try { (( Duplicati . Library . Interface . IGenericCallbackModule ) mx . Value ). OnFinish ( m_result ); }
catch ( Exception ex ) { Logging . Log . WriteMessage ( string . Format ( "OnFinish callback {0} failed: {1}" , mx . Key , ex . Message ), Duplicati . Library . Logging . LogMessageType . Warning , ex ); }
foreach ( KeyValuePair < bool , Library . Interface . IGenericModule > mx in m_options . LoadedModules )
if ( mx . Key && mx . Value is IDisposable )
try { (( IDisposable ) mx . Value ). Dispose (); }
catch ( Exception ex ) { Logging . Log . WriteMessage ( string . Format ( "Dispose for {0} failed: {1}" , mx . Key , ex . Message ), Duplicati . Library . Logging . LogMessageType . Warning , ex ); }
m_options . LoadedModules . Clear ();
OperationRunning ( false );
}
if ( m_hasSetLogging && Logging . Log . CurrentLog is Logging . StreamLog )
{
Logging . StreamLog sl = ( Logging . StreamLog ) Logging . Log . CurrentLog ;
Logging . Log . CurrentLog = null ;
sl . Dispose ();
m_hasSetLogging = false ;
}
}
#endregion
2013-03-08 22:24:54 +01:00
public static IEnumerable < ForestHash . Volumes . IParsedVolume > ParseFhFileList ( string target , Dictionary < string , string > options , CommunicationStatistics stat )
2013-02-12 21:43:14 +00:00
{
2013-03-08 22:24:54 +01:00
stat = stat ?? new CommunicationStatistics ( DuplicatiOperationMode . List );
2013-03-27 16:06:45 +01:00
using ( var i = new Interface ( target , options ))
{
i . SetupCommonOptions ( stat );
return ForestHash . ForestHash . ParseFileList ( target , options , stat );
}
2013-02-12 21:43:14 +00:00
}
2013-03-27 16:06:45 +01:00
public static string CompactBlocks ( string target , Dictionary < string , string > options , CommunicationStatistics stat )
2013-02-12 21:43:14 +00:00
{
2013-03-27 16:06:45 +01:00
stat = stat ?? new CommunicationStatistics ( DuplicatiOperationMode . CleanUp );
using ( var i = new Interface ( target , options ))
{
i . SetupCommonOptions ( stat );
return ForestHash . ForestHash . CompactBlocks ( target , options , stat );
}
}
public static string RecreateDatabase ( string target , Dictionary < string , string > options , CommunicationStatistics stat )
{
stat = stat ?? new CommunicationStatistics ( DuplicatiOperationMode . CleanUp );
using ( var i = new Interface ( target , options ))
{
i . SetupCommonOptions ( stat );
return ForestHash . ForestHash . RecreateDatabase ( target , options , stat );
}
2013-02-12 21:43:14 +00:00
}
2013-03-31 19:33:34 +02:00
public static string DeleteFilesets ( string target , string filesets , Dictionary < string , string > options , CommunicationStatistics stat )
{
stat = stat ?? new CommunicationStatistics ( DuplicatiOperationMode . DeleteAllButN );
using ( var i = new Interface ( target , options ))
{
i . SetupCommonOptions ( stat );
return ForestHash . ForestHash . DeleteFilesets ( target , filesets , options , stat );
}
}
2013-04-22 21:20:14 +02:00
public static string CreateLogDatabase ( string target , Dictionary < string , string > options , CommunicationStatistics stat )
{
stat = stat ?? new CommunicationStatistics ( DuplicatiOperationMode . CreateLogDb );
using ( var i = new Interface ( target , options ))
{
i . SetupCommonOptions ( stat );
return ForestHash . ForestHash . CreateLogDatabase ( target , options , stat );
}
}
2013-02-12 21:43:14 +00:00
}
}