2013-02-12 21:43:14 +00:00
#region Disclaimer / License
2015-01-20 21:44:52 +01:00
// Copyright (C) 2015, The Duplicati Team
// http://www.duplicati.com, info@duplicati.com
2016-04-09 11:45:15 +02:00
//
2013-02-12 21:43:14 +00:00
// 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.
2016-04-09 11:45:15 +02:00
//
2013-02-12 21:43:14 +00:00
// 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.
2016-04-09 11:45:15 +02:00
//
2013-02-12 21:43:14 +00:00
// 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
2016-04-09 11:45:15 +02:00
//
2015-09-04 15:04:04 +02:00
using System.Linq ;
2013-02-12 21:43:14 +00:00
#endregion
using System ;
using System.Collections.Generic ;
using System.Text ;
using Duplicati.Library.Utility ;
namespace Duplicati.Library.Main
{
2013-05-08 21:29:59 +02:00
public class Controller : IDisposable
2013-02-12 21:43:14 +00:00
{
/// <summary>
/// The backend url
/// </summary>
private string m_backend ;
/// <summary>
/// The parsed type-safe version of the commandline options
/// </summary>
private Options m_options ;
2013-08-18 23:16:58 +02:00
/// <summary>
/// The destination for all output messages during execution
/// </summary>
private IMessageSink m_messageSink ;
2013-02-12 21:43:14 +00:00
/// <summary>
2017-01-09 23:27:56 +01:00
/// The stream log, if any
2013-02-12 21:43:14 +00:00
/// </summary>
2017-01-09 23:27:56 +01:00
private Logging . StreamLog m_logfile = null ;
/// <summary>
/// The logging filescope
/// </summary>
private IDisposable m_logfilescope = null ;
2016-04-09 11:45:15 +02:00
2014-05-15 12:47:16 +02:00
/// <summary>
/// The current executing task
/// </summary>
private ITaskControl m_currentTask = null ;
2016-04-09 11:45:15 +02:00
2014-05-15 12:47:16 +02:00
/// <summary>
/// The thread running the current task
/// </summary>
private System . Threading . Thread m_currentTaskThread = null ;
2013-02-12 21:43:14 +00:00
2015-09-04 15:04:04 +02:00
/// <summary>
/// Holds various keys that need to be reset after running the task
/// </summary>
private Dictionary < string , string > m_resetKeys = new Dictionary < string , string >();
/// <summary>
/// The thread priority to reset to
/// </summary>
private System . Threading . ThreadPriority ? m_resetPriority ;
2015-09-11 11:21:57 +02:00
/// <summary>
/// The localization culture to reset to
/// </summary>
private System . Globalization . CultureInfo m_resetLocale ;
/// <summary>
/// The localization UI culture to reset to
/// </summary>
private System . Globalization . CultureInfo m_resetLocaleUI ;
/// <summary>
/// True if the locale should be reset
/// </summary>
private bool m_doResetLocale ;
2016-10-04 11:53:51 +02:00
/// <summary>
/// The caffeinate process runner
/// </summary>
private System . Diagnostics . Process m_caffeinate ;
2013-02-12 21:43:14 +00:00
/// <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 )
2016-04-09 11:45:15 +02:00
{
2016-10-04 11:53:51 +02:00
if ( m_options != null && ! m_options . AllowSleep )
2016-09-28 09:55:04 +02:00
{
2016-10-04 11:53:51 +02:00
if ( Duplicati . Library . Utility . Utility . IsClientWindows )
2013-02-12 21:43:14 +00:00
{
2016-10-04 11:53:51 +02:00
try
{
Win32 . SetThreadExecutionState ( Win32 . EXECUTION_STATE . ES_CONTINUOUS | ( isRunning ? Win32 . EXECUTION_STATE . ES_SYSTEM_REQUIRED : 0 ));
}
catch ( Exception ex )
{
Logging . Log . WriteMessage ( "Failed to set sleep prevention" , Logging . LogMessageType . Warning , ex );
}
2013-02-12 21:43:14 +00:00
}
2016-10-04 11:53:51 +02:00
else if ( Duplicati . Library . Utility . Utility . IsClientOSX )
2016-09-28 09:55:04 +02:00
{
2016-10-04 11:53:51 +02:00
if ( isRunning )
{
try
{
if ( m_caffeinate == null )
{
// -s prevents sleep on AC, -i prevents sleep generally
var psi = new System . Diagnostics . ProcessStartInfo ( "caffeinate" , "-s" );
psi . RedirectStandardInput = true ;
psi . UseShellExecute = false ;
m_caffeinate = System . Diagnostics . Process . Start ( psi );
}
}
catch ( Exception ex )
{
Logging . Log . WriteMessage ( "Failed to set sleep prevention" , Logging . LogMessageType . Warning , ex );
}
}
else
{
try
{
if ( m_caffeinate != null && ! m_caffeinate . HasExited )
{
// Send CTRL+C
m_caffeinate . StandardInput . Write ( "\x3" );
m_caffeinate . StandardInput . Flush ();
m_caffeinate . WaitForExit ( 500 );
if (! m_caffeinate . HasExited )
{
m_caffeinate . Kill ();
m_caffeinate . WaitForExit ( 500 );
if (! m_caffeinate . HasExited )
throw new Exception ( "Failed to kill the caffeinate process" );
}
}
}
catch ( Exception ex )
{
Logging . Log . WriteMessage ( "Failed to unset sleep prevention" , Logging . LogMessageType . Warning , ex );
}
}
2016-09-28 09:55:04 +02:00
}
}
2013-02-12 21:43:14 +00:00
}
/// <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>
2013-08-18 23:16:58 +02:00
public Controller ( string backend , Dictionary < string , string > options , IMessageSink messageSink )
2013-02-12 21:43:14 +00:00
{
m_backend = backend ;
m_options = new Options ( options );
2013-08-18 23:16:58 +02:00
m_messageSink = messageSink ;
2013-02-12 21:43:14 +00:00
}
2017-04-06 10:10:22 +02:00
/// <summary>
/// Appends another message sink to the controller
/// </summary>
/// <param name="sink">The sink to use.</param>
public void AppendSink ( IMessageSink sink )
{
if ( m_messageSink is MultiMessageSink )
(( MultiMessageSink ) m_messageSink ). Append ( sink );
else
m_messageSink = new MultiMessageSink ( m_messageSink , sink );
}
2013-06-29 12:17:52 +02:00
public Duplicati . Library . Interface . IBackupResults Backup ( string [] inputsources , IFilter filter = null )
2016-09-15 11:39:27 +02:00
{
2015-12-22 00:35:00 +01:00
Library . UsageReporter . Reporter . Report ( "USE_BACKEND" , new Library . Utility . Uri ( m_backend ). Scheme );
Library . UsageReporter . Reporter . Report ( "USE_COMPRESSION" , m_options . CompressionModule );
Library . UsageReporter . Reporter . Report ( "USE_ENCRYPTION" , m_options . EncryptionModule );
2016-10-15 23:55:50 +02:00
2015-12-27 00:16:45 +01:00
return RunAction ( new BackupResults (), ref inputsources , ref filter , ( result ) => {
2016-04-09 11:45:15 +02:00
2016-10-22 23:08:27 +02:00
if ( inputsources == null || inputsources . Length == 0 )
2017-01-09 11:35:38 +01:00
throw new Duplicati . Library . Interface . UserInformationException ( Strings . Controller . NoSourceFoldersError );
2013-05-25 16:40:15 +02:00
2013-06-29 12:17:52 +02:00
var sources = new List < string >( inputsources );
2016-09-15 11:39:27 +02:00
//Make sure they all have the same format and exist
for ( int i = 0 ; i < sources . Count ; i ++)
{
try
{
sources [ i ] = System . IO . Path . GetFullPath ( sources [ i ]);
}
catch ( Exception ex )
{
2017-01-09 11:35:38 +01:00
throw new Duplicati . Library . Interface . UserInformationException ( Strings . Controller . InvalidPathError ( sources [ i ], ex . Message ), ex );
2016-09-15 11:39:27 +02:00
}
2016-04-09 11:45:15 +02:00
2013-06-29 12:17:52 +02:00
var fi = new System . IO . FileInfo ( sources [ i ]);
var di = new System . IO . DirectoryInfo ( sources [ i ]);
if (!( fi . Exists || di . Exists ) && ! m_options . AllowMissingSource )
2015-01-20 21:07:24 +01:00
throw new System . IO . IOException ( Strings . Controller . SourceIsMissingError ( sources [ i ]));
2016-04-09 11:45:15 +02:00
2013-06-29 12:17:52 +02:00
if (! fi . Exists )
2016-09-15 11:39:27 +02:00
sources [ i ] = Library . Utility . Utility . AppendDirSeparator ( sources [ i ]);
}
2016-10-09 11:47:36 +02:00
//Sanity check for duplicate files/folders
var pathDuplicates = sources . GroupBy ( x => x , Library . Utility . Utility . ClientFilenameStringComparer )
. Where ( g => g . Count () > 1 ). Select ( y => y . Key ). ToList ();
2015-11-17 10:08:16 +01:00
2016-10-09 11:47:36 +02:00
foreach ( var pathDuplicate in pathDuplicates )
result . AddVerboseMessage ( string . Format ( "Removing duplicate source: {0}" , pathDuplicate ));
2015-11-17 10:08:16 +01:00
2016-10-09 11:47:36 +02:00
sources = sources . Distinct ( Library . Utility . Utility . ClientFilenameStringComparer ). OrderBy ( a => a ). ToList ();
//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 . ClientFilenameStringComparision ))
{
if ( filter != null )
2015-11-17 10:08:16 +01:00
{
2016-10-09 11:47:36 +02:00
bool includes ;
bool excludes ;
FilterExpression . AnalyzeFilters ( filter , out includes , out excludes );
// If there are no excludes, there is no need to keep the folder as a filter
if ( excludes )
{
result . AddVerboseMessage ( "Removing source \"{0}\" because it is a subfolder of \"{1}\", and using it as an include filter" , sources [ i ], sources [ j ]);
filter = Library . Utility . JoinedFilterExpression . Join ( new FilterExpression ( sources [ i ]), filter );
}
else
result . AddVerboseMessage ( "Removing source \"{0}\" because it is a subfolder or subfile of \"{1}\"" , sources [ i ], sources [ j ]);
2015-11-17 10:08:16 +01:00
}
else
2016-10-09 11:47:36 +02:00
result . AddVerboseMessage ( "Removing source \"{0}\" because it is a subfolder or subfile of \"{1}\"" , sources [ i ], sources [ j ]);
2015-11-17 10:08:16 +01:00
2013-06-29 12:17:52 +02:00
sources . RemoveAt ( i );
i --;
break ;
}
2013-05-25 16:40:15 +02:00
2016-10-09 11:47:36 +02:00
using ( var h = new Operation . BackupHandler ( m_backend , m_options , result ))
2013-06-29 12:17:52 +02:00
h . Run ( sources . ToArray (), filter );
2015-12-22 02:22:56 +01:00
Library . UsageReporter . Reporter . Report ( "BACKUP_FILECOUNT" , result . ExaminedFiles );
Library . UsageReporter . Reporter . Report ( "BACKUP_FILESIZE" , result . SizeOfExaminedFiles );
Library . UsageReporter . Reporter . Report ( "BACKUP_DURATION" , ( long ) result . Duration . TotalSeconds );
2013-05-25 16:40:15 +02:00
});
2013-02-12 21:43:14 +00:00
}
2013-05-25 16:40:15 +02:00
public Library . Interface . IRestoreResults Restore ( string [] paths , Library . Utility . IFilter filter = null )
2016-09-15 11:39:27 +02:00
{
2015-12-27 00:16:45 +01:00
return RunAction ( new RestoreResults (), ref paths , ref filter , ( result ) => {
2016-09-15 11:39:27 +02:00
new Operation . RestoreHandler ( m_backend , m_options , result ). Run ( paths , filter );
2015-12-27 22:34:05 +01:00
Library . UsageReporter . Reporter . Report ( "RESTORE_FILECOUNT" , result . FilesRestored );
Library . UsageReporter . Reporter . Report ( "RESTORE_FILESIZE" , result . SizeOfRestoredFiles );
Library . UsageReporter . Reporter . Report ( "RESTORE_DURATION" , ( long ) result . Duration . TotalSeconds );
2013-05-25 16:40:15 +02:00
});
2013-02-12 21:43:14 +00:00
}
2013-05-30 23:00:09 +02:00
public Duplicati . Library . Interface . IRestoreControlFilesResults RestoreControlFiles ( IEnumerable < string > files = null , Library . Utility . IFilter filter = null )
2013-02-12 21:43:14 +00:00
{
2015-12-27 00:16:45 +01:00
return RunAction ( new RestoreControlFilesResults (), ref filter , ( result ) => {
2013-05-30 23:00:09 +02:00
new Operation . RestoreControlFilesHandler ( m_backend , m_options , result ). Run ( files , filter );
2013-05-25 16:40:15 +02:00
});
2013-02-12 21:43:14 +00:00
}
2013-05-25 16:40:15 +02:00
public Duplicati . Library . Interface . IDeleteResults Delete ()
2016-09-15 11:39:27 +02:00
{
2013-05-25 16:40:15 +02:00
return RunAction ( new DeleteResults (), ( result ) => {
2016-09-15 11:39:27 +02:00
new Operation . DeleteHandler ( m_backend , m_options , result ). Run ();
2013-05-25 16:40:15 +02:00
});
2013-02-12 21:43:14 +00:00
}
2015-04-08 20:19:46 +02:00
public Duplicati . Library . Interface . IRepairResults Repair ( Library . Utility . IFilter filter = null )
2013-02-12 21:43:14 +00:00
{
2015-12-27 00:16:45 +01:00
return RunAction ( new RepairResults (), ref filter , ( result ) => {
2015-04-08 20:19:46 +02:00
new Operation . RepairHandler ( m_backend , m_options , result ). Run ( filter );
2013-05-25 16:40:15 +02:00
});
2013-02-12 21:43:14 +00:00
}
2016-04-09 11:45:15 +02:00
2013-05-30 21:54:43 +02:00
public Duplicati . Library . Interface . IListResults List ( Library . Utility . IFilter filter = null )
{
return List (( IEnumerable < string >) null , filter );
}
2013-05-05 17:54:59 +02:00
2013-05-30 21:54:43 +02:00
public Duplicati . Library . Interface . IListResults List ( string filterstring , Library . Utility . IFilter filter = null )
2013-05-11 13:04:01 +02:00
{
2013-05-30 21:54:43 +02:00
return List ( filterstring == null ? null : new string [] { filterstring }, null );
2013-05-11 13:04:01 +02:00
}
2016-04-09 11:45:15 +02:00
2013-05-30 21:54:43 +02:00
public Duplicati . Library . Interface . IListResults List ( IEnumerable < string > filterstrings , Library . Utility . IFilter filter = null )
2016-09-15 11:39:27 +02:00
{
2015-12-27 00:16:45 +01:00
return RunAction ( new ListResults (), ref filter , ( result ) => {
2016-09-15 11:39:27 +02:00
new Operation . ListFilesHandler ( m_backend , m_options , result ). Run ( filterstrings , filter );
2013-05-30 21:54:43 +02:00
});
}
2016-04-09 11:45:15 +02:00
2013-05-30 21:54:43 +02:00
public Duplicati . Library . Interface . IListResults ListControlFiles ( IEnumerable < string > filterstrings = null , Library . Utility . IFilter filter = null )
{
2015-12-27 00:16:45 +01:00
return RunAction ( new ListResults (), ref filter , ( result ) => {
2013-05-30 21:54:43 +02:00
new Operation . ListControlFilesHandler ( m_backend , m_options , result ). Run ( filterstrings , filter );
2013-05-25 16:40:15 +02:00
});
}
2016-04-09 11:45:15 +02:00
2016-10-13 21:45:31 +02:00
public Duplicati . Library . Interface . IListRemoteResults ListRemote ()
{
return RunAction ( new ListRemoteResults (), ( result ) =>
{
using ( var tf = System . IO . File . Exists ( m_options . Dbpath ) ? null : new Library . Utility . TempFile ())
using ( var db = new Database . LocalDatabase ((( string ) tf ) ?? m_options . Dbpath , "list-remote" , true ))
using ( var bk = new BackendManager ( m_backend , m_options , result . BackendWriter , null ))
result . SetResult ( bk . List ());
});
}
public Duplicati . Library . Interface . IListRemoteResults DeleteAllRemoteFiles ()
{
return RunAction ( new ListRemoteResults (), ( result ) =>
{
result . OperationProgressUpdater . UpdatePhase ( OperationPhase . Delete_Listing );
using ( var tf = System . IO . File . Exists ( m_options . Dbpath ) ? null : new Library . Utility . TempFile ())
using ( var db = new Database . LocalDatabase ((( string ) tf ) ?? m_options . Dbpath , "list-remote" , true ))
using ( var bk = new BackendManager ( m_backend , m_options , result . BackendWriter , null ))
{
var list = bk . List ();
result . OperationProgressUpdater . UpdatePhase ( OperationPhase . Delete_Deleting );
result . OperationProgressUpdater . UpdateProgress ( 0 );
for ( var i = 0 ; i < list . Count ; i ++)
{
try
{
bk . Delete ( list [ i ]. Name , list [ i ]. Size , true );
}
catch ( Exception ex )
{
result . AddWarning ( string . Format ( "Failed to delete remote file: {0}" , list [ i ]. Name ), ex );
}
result . OperationProgressUpdater . UpdateProgress (( float ) i / list . Count );
}
result . OperationProgressUpdater . UpdateProgress ( 1 );
}
});
}
2013-05-25 16:40:15 +02:00
public Duplicati . Library . Interface . ICompactResults Compact ()
2013-02-12 21:43:14 +00:00
{
2013-05-25 16:40:15 +02:00
return RunAction ( new CompactResults (), ( result ) => {
new Operation . CompactHandler ( m_backend , m_options , result ). Run ();
});
}
2016-04-09 11:45:15 +02:00
2015-04-08 20:19:46 +02:00
public Duplicati . Library . Interface . IRecreateDatabaseResults RecreateDatabase ( string targetpath , Library . Utility . IFilter filter = null )
2013-05-25 16:40:15 +02:00
{
var t = new string [] { string . IsNullOrEmpty ( targetpath ) ? m_options . Dbpath : targetpath };
2015-04-08 20:19:46 +02:00
var filelistfilter = Operation . RestoreHandler . FilterNumberedFilelist ( m_options . Time , m_options . Version );
2015-12-27 00:16:45 +01:00
return RunAction ( new RecreateDatabaseResults (), ref t , ref filter , ( result ) => {
2013-05-25 16:40:15 +02:00
using ( var h = new Operation . RecreateDatabaseHandler ( m_backend , m_options , result ))
2015-04-08 20:19:46 +02:00
h . Run ( t [ 0 ], filter , filelistfilter );
});
}
2015-04-08 21:01:36 +02:00
public Duplicati . Library . Interface . IRecreateDatabaseResults UpdateDatabaseWithVersions ( Library . Utility . IFilter filter = null )
{
var filelistfilter = Operation . RestoreHandler . FilterNumberedFilelist ( m_options . Time , m_options . Version , singleTimeMatch : true );
2015-12-27 00:16:45 +01:00
return RunAction ( new RecreateDatabaseResults (), ref filter , ( result ) => {
2015-04-08 21:01:36 +02:00
using ( var h = new Operation . RecreateDatabaseHandler ( m_backend , m_options , result ))
h . RunUpdate ( filter , filelistfilter );
2013-05-25 16:40:15 +02:00
});
2013-02-12 21:43:14 +00:00
}
2013-05-25 16:40:15 +02:00
public Duplicati . Library . Interface . ICreateLogDatabaseResults CreateLogDatabase ( string targetpath )
2013-02-12 21:43:14 +00:00
{
2013-05-25 16:40:15 +02:00
var t = new string [] { targetpath };
2016-04-09 11:45:15 +02:00
2013-05-25 16:40:15 +02:00
return RunAction ( new CreateLogDatabaseResults (), ref t , ( result ) => {
new Operation . CreateBugReportHandler ( t [ 0 ], m_options , result ). Run ();
});
2013-02-12 21:43:14 +00:00
}
2013-06-20 20:17:10 +02:00
2017-04-04 23:53:36 +02:00
public Duplicati . Library . Interface . IListChangesResults ListChanges ( string baseVersion , string targetVersion , IEnumerable < string > filterstrings = null , Library . Utility . IFilter filter = null , Action < Duplicati . Library . Interface . IListChangesResults , IEnumerable < Tuple < Library . Interface . ListChangesChangeType , Library . Interface . ListChangesElementType , string >>> callback = null )
2013-06-20 20:17:10 +02:00
{
var t = new string [] { baseVersion , targetVersion };
2016-04-09 11:45:15 +02:00
2015-12-27 00:16:45 +01:00
return RunAction ( new ListChangesResults (), ref t , ref filter , ( result ) => {
2017-04-04 23:53:36 +02:00
new Operation . ListChangesHandler ( m_backend , m_options , result ). Run ( t [ 0 ], t [ 1 ], filterstrings , filter , callback );
2013-06-20 20:17:10 +02:00
});
}
2013-06-26 21:59:01 +02:00
2017-04-04 23:53:36 +02:00
public Duplicati . Library . Interface . IListAffectedResults ListAffected ( List < string > args , Action < Duplicati . Library . Interface . IListAffectedResults > callback = null )
2014-08-19 20:27:14 +02:00
{
return RunAction ( new ListAffectedResults (), ( result ) => {
2017-04-04 23:53:36 +02:00
new Operation . ListAffected ( m_options , result ). Run ( args , callback );
2014-08-19 20:27:14 +02:00
});
}
2013-06-26 21:59:01 +02:00
public Duplicati . Library . Interface . ITestResults Test ( long samples = 1 )
2016-04-09 11:45:15 +02:00
{
2017-03-03 20:52:04 +01:00
if (! m_options . RawOptions . ContainsKey ( "full-remote-verification" ))
m_options . RawOptions [ "full-remote-verification" ] = "true" ;
2013-06-26 21:59:01 +02:00
return RunAction ( new TestResults (), ( result ) => {
new Operation . TestHandler ( m_backend , m_options , result ). Run ( samples );
});
}
2016-04-09 11:45:15 +02:00
2013-12-07 15:22:51 +01:00
public Library . Interface . ITestFilterResults TestFilter ( string [] paths , Library . Utility . IFilter filter = null )
{
m_options . RawOptions [ "verbose" ] = "true" ;
m_options . RawOptions [ "dry-run" ] = "true" ;
m_options . RawOptions [ "dbpath" ] = "INVALID!" ;
2016-04-09 11:45:15 +02:00
2015-12-27 00:16:45 +01:00
return RunAction ( new TestFilterResults (), ref paths , ref filter , ( result ) => {
2013-12-07 15:22:51 +01:00
new Operation . TestFilterHandler ( m_options , result ). Run ( paths , filter );
});
}
2015-09-11 10:57:31 +02:00
public Library . Interface . ISystemInfoResults SystemInfo ()
{
return RunAction ( new SystemInfoResults (), result => {
Operation . SystemInfoHandler . Run ( result );
});
}
2016-04-09 11:45:15 +02:00
2016-12-29 22:41:13 +01:00
public Library . Interface . IPurgeFilesResults PurgeFiles ( Library . Utility . IFilter filter )
{
return RunAction ( new PurgeFilesResults (), result =>
{
new Operation . PurgeFilesHandler ( m_backend , m_options , result ). Run ( filter );
});
}
2017-01-05 16:46:01 +01:00
public Library . Interface . IListBrokenFilesResults ListBrokenFiles ( Library . Utility . IFilter filter , Func < long , DateTime , long , string , long , bool > callbackhandler = null )
{
return RunAction ( new ListBrokenFilesResults (), result =>
{
new Operation . ListBrokenFilesHandler ( m_backend , m_options , result ). Run ( filter , callbackhandler );
});
}
public Library . Interface . IPurgeBrokenFilesResults PurgeBrokenFiles ( Library . Utility . IFilter filter )
{
return RunAction ( new PurgeBrokenFilesResults (), result =>
{
new Operation . PurgeBrokenFilesHandler ( m_backend , m_options , result ). Run ( filter );
});
}
2017-01-09 23:21:00 +01:00
public Library . Interface . ISendMailResults SendMail ()
{
m_options . RawOptions [ "send-mail-level" ] = "all" ;
m_options . RawOptions [ "send-mail-any-operation" ] = "true" ;
string targetmail ;
m_options . RawOptions . TryGetValue ( "send-mail-to" , out targetmail );
if ( string . IsNullOrWhiteSpace ( targetmail ))
throw new Exception ( string . Format ( "No email specified, please use --{0}" , "send-mail-to" ));
if ( m_options . Loglevel == Logging . LogMessageType . Error )
m_options . RawOptions [ "log-level" ] = Logging . LogMessageType . Warning . ToString ();
m_options . RawOptions [ "disable-module" ] = string . Join (
"," ,
DynamicLoader . GenericLoader . Modules
. Where ( m =>
!( m is Library . Interface . IConnectionModule ) && m . GetType (). FullName != "Duplicati.Library.Modules.Builtin.SendMail"
)
. Select ( x => x . Key )
);
return RunAction ( new SendMailResults (), result =>
{
result . Lines = new string [ 0 ];
System . Threading . Thread . Sleep ( 5 );
});
}
2013-05-25 16:40:15 +02:00
private T RunAction < T >( T result , Action < T > method )
2017-01-09 23:27:56 +01:00
where T : ISetCommonOptions , ITaskControl , Logging . ILog
2013-05-25 16:40:15 +02:00
{
var tmp = new string [ 0 ];
2015-12-27 00:16:45 +01:00
IFilter tempfilter = null ;
return RunAction < T >( result , ref tmp , ref tempfilter , method );
2013-05-25 16:40:15 +02:00
}
2015-12-27 00:16:45 +01:00
2013-05-25 16:40:15 +02:00
private T RunAction < T >( T result , ref string [] paths , Action < T > method )
2017-01-09 23:27:56 +01:00
where T : ISetCommonOptions , ITaskControl , Logging . ILog
2015-12-27 00:16:45 +01:00
{
IFilter tempfilter = null ;
return RunAction < T >( result , ref paths , ref tempfilter , method );
}
private T RunAction < T >( T result , ref IFilter filter , Action < T > method )
2017-01-09 23:27:56 +01:00
where T : ISetCommonOptions , ITaskControl , Logging . ILog
2015-12-27 00:16:45 +01:00
{
var tmp = new string [ 0 ];
return RunAction < T >( result , ref tmp , ref filter , method );
}
private T RunAction < T >( T result , ref string [] paths , ref IFilter filter , Action < T > method )
2017-01-09 23:27:56 +01:00
where T : ISetCommonOptions , ITaskControl , Logging . ILog
2014-05-15 12:47:16 +02:00
{
2017-01-11 23:35:42 +01:00
using ( Logging . Log . StartScope ( result ))
2014-05-15 12:47:16 +02:00
{
2017-01-11 23:35:42 +01:00
try
2013-05-25 16:40:15 +02:00
{
2017-01-11 23:35:42 +01:00
m_currentTask = result ;
m_currentTaskThread = System . Threading . Thread . CurrentThread ;
2015-12-27 00:16:45 +01:00
SetupCommonOptions ( result , ref paths , ref filter );
2016-04-09 11:45:15 +02:00
2017-01-11 23:35:42 +01:00
result . WriteLogMessageDirect ( Strings . Controller . StartingOperationMessage ( m_options . MainAction ), Logging . LogMessageType . Information , null );
using ( new Logging . Timer ( string . Format ( "Running {0}" , result . MainOperation )))
method ( result );
2016-04-09 11:45:15 +02:00
2016-12-01 23:59:54 +01:00
if ( result . EndTime . Ticks == 0 )
result . EndTime = DateTime . UtcNow ;
2013-05-25 16:40:15 +02:00
result . SetDatabase ( null );
2016-04-09 11:45:15 +02:00
2014-05-15 12:47:16 +02:00
OnOperationComplete ( result );
2016-09-28 09:55:04 +02:00
2017-01-11 23:35:42 +01:00
result . WriteLogMessageDirect ( Strings . Controller . CompletedOperationMessage ( m_options . MainAction ), Logging . LogMessageType . Information , null );
2016-09-28 09:55:04 +02:00
2014-05-15 12:47:16 +02:00
return result ;
2013-05-25 16:40:15 +02:00
}
2017-01-11 23:35:42 +01:00
catch ( Exception ex )
{
result . EndTime = DateTime . UtcNow ;
2016-04-09 11:45:15 +02:00
2017-01-11 23:35:42 +01:00
try { ( result as BasicResults ). OperationProgressUpdater . UpdatePhase ( OperationPhase . Error ); }
catch { }
2016-04-09 11:45:15 +02:00
2017-01-09 23:27:56 +01:00
OnOperationComplete ( ex );
2016-09-28 09:55:04 +02:00
2017-01-11 23:35:42 +01:00
result . WriteLogMessageDirect ( Strings . Controller . FailedOperationMessage ( m_options . MainAction , ex . Message ), Logging . LogMessageType . Error , ex );
throw ;
}
finally
{
m_currentTask = null ;
2014-05-15 12:47:16 +02:00
m_currentTaskThread = null ;
2017-01-11 23:35:42 +01:00
}
2014-05-15 12:47:16 +02:00
}
2016-09-15 11:39:27 +02:00
}
2016-03-10 21:53:28 +01:00
2016-03-26 11:03:06 +01:00
/// <summary>
/// Attempts to get the locale, but delays linking to the calls as they are missing in some environments
/// </summary>
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
private static void DoGetLocale ( out System . Globalization . CultureInfo locale , out System . Globalization . CultureInfo uiLocale )
{
locale = System . Globalization . CultureInfo . DefaultThreadCurrentCulture ;
uiLocale = System . Globalization . CultureInfo . DefaultThreadCurrentUICulture ;
}
2016-04-09 11:45:15 +02:00
2016-03-10 21:53:28 +01:00
/// <summary>
/// Attempts to set the locale, but delays linking to the calls as they are missing in some environments
/// </summary>
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
private static void DoSetLocale ( System . Globalization . CultureInfo locale , System . Globalization . CultureInfo uiLocale )
{
System . Globalization . CultureInfo . DefaultThreadCurrentCulture = locale ;
System . Globalization . CultureInfo . DefaultThreadCurrentUICulture = uiLocale ;
}
2016-04-09 11:45:15 +02:00
2016-09-15 11:39:27 +02:00
private void OnOperationComplete ( object result )
{
2013-05-25 16:40:15 +02:00
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 ( result ); }
catch ( Exception ex ) { Logging . Log . WriteMessage ( string . Format ( "OnFinish callback {0} failed: {1}" , mx . Key , ex . Message ), Duplicati . Library . Logging . LogMessageType . Warning , ex ); }
2013-02-12 21:43:14 +00:00
2013-05-25 16:40:15 +02:00
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 );
}
2015-09-04 15:04:04 +02:00
if ( m_resetPriority != null )
{
System . Threading . Thread . CurrentThread . Priority = m_resetPriority . Value ;
m_resetPriority = null ;
}
2015-09-11 11:21:57 +02:00
if ( m_doResetLocale )
{
2016-03-10 21:53:28 +01:00
// Wrap the call to avoid loading issues for the setLocale method
DoSetLocale ( m_resetLocale , m_resetLocaleUI );
2015-09-11 11:21:57 +02:00
m_doResetLocale = false ;
m_resetLocale = null ;
2016-03-10 21:53:28 +01:00
m_resetLocaleUI = null ;
2015-09-11 11:21:57 +02:00
}
2015-09-04 15:04:04 +02:00
if ( m_resetKeys != null )
{
var keys = m_resetKeys . Keys . ToArray ();
foreach ( var k in keys )
{
try
{
Environment . SetEnvironmentVariable ( k , m_resetKeys [ k ]);
2016-04-09 11:45:15 +02:00
}
2015-09-04 15:04:04 +02:00
catch { }
2016-04-09 11:45:15 +02:00
2015-09-04 15:04:04 +02:00
m_resetKeys . Remove ( k );
}
}
2017-01-09 23:27:56 +01:00
if ( m_logfilescope != null )
2013-05-25 16:40:15 +02:00
{
2017-01-09 23:27:56 +01:00
m_logfilescope . Dispose ();
m_logfilescope = null ;
2016-04-09 11:45:15 +02:00
}
2017-01-09 23:27:56 +01:00
if ( m_logfile != null )
{
m_logfile . Dispose ();
m_logfile = null ;
}
2016-09-15 11:39:27 +02:00
}
2013-05-25 16:40:15 +02:00
2015-12-27 00:16:45 +01:00
private void SetupCommonOptions ( ISetCommonOptions result , ref string [] paths , ref IFilter filter )
2013-02-12 21:43:14 +00:00
{
2013-05-25 16:40:15 +02:00
m_options . MainAction = result . MainOperation ;
2013-08-18 23:16:58 +02:00
result . MessageSink = m_messageSink ;
2016-04-09 11:45:15 +02:00
2013-02-12 21:43:14 +00:00
switch ( m_options . MainAction )
{
2013-05-08 21:29:59 +02:00
case OperationMode . Backup :
2013-02-12 21:43:14 +00:00
break ;
2016-04-09 11:45:15 +02:00
2013-02-12 21:43:14 +00:00
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 ));
2016-04-09 11:45:15 +02:00
2014-07-25 16:36:26 +02:00
var conopts = new Dictionary < string , string >( m_options . RawOptions );
var qp = new Library . Utility . Uri ( m_backend ). QueryParameters ;
foreach ( var k in qp . Keys )
conopts [( string ) k ] = qp [( string ) k ];
2013-02-12 21:43:14 +00:00
2015-12-27 00:16:45 +01:00
// Make the filter read-n-write able in the generic modules
var pristinefilter = conopts [ "filter" ] = string . Join ( System . IO . Path . PathSeparator . ToString (), FilterExpression . Serialize ( filter ));
2016-10-15 23:55:50 +02:00
foreach ( var mx in m_options . LoadedModules )
2013-02-12 21:43:14 +00:00
if ( mx . Key )
{
2014-07-25 16:36:26 +02:00
if ( mx . Value is Library . Interface . IConnectionModule )
mx . Value . Configure ( conopts );
else
mx . Value . Configure ( m_options . RawOptions );
2016-04-09 11:45:15 +02:00
2016-10-15 16:18:26 +02:00
if ( mx . Value is Library . Interface . IGenericSourceModule )
2016-10-15 23:55:50 +02:00
{
2016-11-02 00:17:49 +01:00
var sourcemodule = ( Library . Interface . IGenericSourceModule ) mx . Value ;
2016-10-15 23:55:50 +02:00
2016-11-02 00:17:49 +01:00
if ( sourcemodule . ContainFilesForBackup ( paths ))
{
var sourceoptions = sourcemodule . ParseSourcePaths ( ref paths , ref pristinefilter , m_options . RawOptions );
foreach ( var sourceoption in sourceoptions )
m_options . RawOptions [ sourceoption . Key ] = sourceoption . Value ;
}
2016-10-15 23:55:50 +02:00
}
2016-10-15 16:18:26 +02:00
2013-02-12 21:43:14 +00:00
if ( mx . Value is Library . Interface . IGenericCallbackModule )
2013-05-25 16:40:15 +02:00
(( Library . Interface . IGenericCallbackModule ) mx . Value ). OnStart ( result . MainOperation . ToString (), ref m_backend , ref paths );
2013-02-12 21:43:14 +00:00
}
2015-12-27 00:16:45 +01:00
// If the filters were changed, read them back in
if ( pristinefilter != conopts [ "filter" ])
2016-10-15 23:55:50 +02:00
filter = FilterExpression . Deserialize ( pristinefilter . Split ( new string [] { System . IO . Path . PathSeparator . ToString ()}, StringSplitOptions . RemoveEmptyEntries ));
2015-12-27 00:16:45 +01:00
2013-02-12 21:43:14 +00:00
OperationRunning ( true );
2014-08-12 11:02:03 +02:00
if ( m_options . HasLoglevel )
Library . Logging . Log . LogLevel = m_options . Loglevel ;
2013-02-12 21:43:14 +00:00
if (! string . IsNullOrEmpty ( m_options . Logfile ))
{
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 );
2017-01-09 23:27:56 +01:00
2017-01-19 13:12:17 +01:00
m_logfilescope = Logging . Log . StartScope ( m_logfile = new Library . Logging . StreamLog ( m_options . Logfile ));
2013-02-12 21:43:14 +00:00
}
2013-05-29 22:15:13 +02:00
result . VerboseErrors = m_options . DebugOutput ;
result . VerboseOutput = m_options . Verbose ;
2013-02-12 21:43:14 +00:00
2013-03-08 12:25:35 +01:00
if ( m_options . HasTempDir )
2015-09-04 15:04:04 +02:00
{
2013-05-08 21:29:59 +02:00
Library . Utility . TempFolder . SystemTempPath = m_options . TempDir ;
2015-09-04 15:04:04 +02:00
if ( Library . Utility . Utility . IsClientLinux )
{
m_resetKeys [ "TMPDIR" ] = Environment . GetEnvironmentVariable ( "TMPDIR" );
Environment . SetEnvironmentVariable ( "TMPDIR" , m_options . TempDir );
}
else
{
m_resetKeys [ "TMP" ] = Environment . GetEnvironmentVariable ( "TMP" );
m_resetKeys [ "TEMP" ] = Environment . GetEnvironmentVariable ( "TEMP" );
Environment . SetEnvironmentVariable ( "TMP" , m_options . TempDir );
Environment . SetEnvironmentVariable ( "TEMP" , m_options . TempDir );
}
}
2013-02-12 21:43:14 +00:00
2015-09-11 11:21:57 +02:00
if ( m_options . HasForcedLocale )
{
2016-03-26 11:34:37 +01:00
try
{
var locale = m_options . ForcedLocale ;
DoGetLocale ( out m_resetLocale , out m_resetLocaleUI );
m_doResetLocale = true ;
// Wrap the call to avoid loading issues for the setLocale method
DoSetLocale ( locale , locale );
}
catch ( Exception ex ) // or only: MissingMethodException
{
Library . Logging . Log . WriteMessage ( Strings . Controller . FailedForceLocaleError ( ex . Message ), Logging . LogMessageType . Warning );
m_doResetLocale = false ;
m_resetLocale = m_resetLocaleUI = null ;
}
2015-09-11 11:21:57 +02:00
}
2013-02-12 21:43:14 +00:00
if (! string . IsNullOrEmpty ( m_options . ThreadPriority ))
2015-09-04 15:04:04 +02:00
{
m_resetPriority = System . Threading . Thread . CurrentThread . Priority ;
2013-05-08 21:29:59 +02:00
System . Threading . Thread . CurrentThread . Priority = Library . Utility . Utility . ParsePriority ( m_options . ThreadPriority );
2015-09-04 15:04:04 +02:00
}
2013-02-12 21:43:14 +00:00
2013-05-08 19:57:13 +02:00
if ( string . IsNullOrEmpty ( m_options . Dbpath ))
2013-05-08 20:17:07 +02:00
m_options . Dbpath = DatabaseLocator . GetDatabasePath ( m_backend , m_options );
2013-05-06 09:58:19 +02:00
2013-05-25 16:40:15 +02:00
ValidateOptions ( result );
2013-02-12 21:43:14 +00:00
}
/// <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>
2017-02-27 09:09:52 +01:00
/// <param name="log">The log instance</param>
2013-05-25 16:40:15 +02:00
private void ValidateOptions ( ILogWriter log )
2013-02-12 21:43:14 +00:00
{
2016-09-15 11:39:27 +02:00
if ( m_options . KeepTime . Ticks > 0 && m_options . KeepVersions > 0 )
2017-02-27 09:09:52 +01:00
throw new Interface . UserInformationException ( string . Format ( "Setting both --{0} and --{1} is not permitted" , "keep-versions" , "keep-time" ));
2016-05-19 00:14:09 +02:00
2017-02-27 09:09:02 +01:00
if (! string . IsNullOrWhiteSpace ( m_options . Prefix ) && m_options . Prefix . Contains ( "-" ))
throw new Interface . UserInformationException ( "The prefix cannot contain hyphens (-)" );
2013-02-12 21:43:14 +00:00
//No point in going through with this if we can't report
2013-05-25 16:40:15 +02:00
if ( log == null )
2013-02-12 21:43:14 +00:00
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 );
2016-04-09 11:45:15 +02:00
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 )
2016-10-22 23:08:27 +02:00
if ( m . Value . SupportedCommands != null )
if ( m . Key )
2013-02-12 21:43:14 +00:00
moduleOptions . AddRange ( m . Value . SupportedCommands );
2016-10-22 23:08:27 +02:00
else
2013-02-12 21:43:14 +00:00
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 ];
}
2016-04-09 11:45:15 +02:00
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-08 21:29:59 +02:00
var ext = new Library . Utility . Uri ( m_backend ). QueryParameters ;
2013-05-05 23:46:00 +02:00
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
2016-04-09 11:45:15 +02:00
foreach ( IList < Library . Interface . ICommandLineArgument > l in new IList < Library . Interface . ICommandLineArgument >[] {
m_options . SupportedCommands ,
DynamicLoader . BackendLoader . GetSupportedCommands ( m_backend ),
2013-02-12 21:43:14 +00:00
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 )
2015-01-20 21:07:24 +01:00
log . AddWarning ( Strings . Controller . DuplicateOptionNameWarning ( a . Name ), null );
2013-02-12 21:43:14 +00:00
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 )
2015-01-20 21:07:24 +01:00
log . AddWarning ( Strings . Controller . DuplicateOptionNameWarning ( s ), null );
2013-02-12 21:43:14 +00:00
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 + ")" ;
2015-01-20 21:07:24 +01:00
log . AddWarning ( Strings . Controller . DeprecatedOptionUsedWarning ( optname , a . DeprecationMessage ), null );
2013-02-12 21:43:14 +00:00
}
}
}
}
//Now look for options that were supplied but not supported
foreach ( string s in ropts . Keys )
if (! supportedOptions . ContainsKey ( s ))
if ( disabledModuleOptions . ContainsKey ( s ))
2015-01-20 21:07:24 +01:00
log . AddWarning ( Strings . Controller . UnsupportedOptionDisabledModuleWarning ( s , disabledModuleOptions [ s ]), null );
2013-02-12 21:43:14 +00:00
else
2015-01-20 21:07:24 +01:00
log . AddWarning ( Strings . Controller . UnsupportedOptionWarning ( s ), null );
2013-02-12 21:43:14 +00:00
//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 )
2013-05-25 16:40:15 +02:00
log . AddWarning ( validationMessage , null );
2013-02-12 21:43:14 +00:00
}
}
//TODO: Based on the action, see if all options are relevant
}
/// <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 )
2016-09-15 11:39:27 +02:00
{
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 Strings . Controller . UnsupportedEnumerationValue ( optionname , value , arg . ValidValues ?? new string [ 0 ]);
}
else if ( arg . Type == Duplicati . Library . Interface . CommandLineArgument . ArgumentType . Flags )
{
bool validatedAllFlags = false ;
var flags = ( value ?? string . Empty ). ToLowerInvariant (). Split ( new [] { "," }, StringSplitOptions . None ). Select ( flag => flag . Trim ()). Distinct ();
var validFlags = arg . ValidValues ?? new string [ 0 ];
foreach ( var flag in flags )
{
if (! validFlags . Any ( validFlag => string . Equals ( validFlag , flag , StringComparison . CurrentCultureIgnoreCase )))
{
validatedAllFlags = false ;
break ;
}
validatedAllFlags = true ;
}
if (! validatedAllFlags )
{
return Strings . Controller . UnsupportedFlagsValue ( optionname , value , validFlags );
}
}
else if ( arg . Type == Duplicati . Library . Interface . CommandLineArgument . ArgumentType . Boolean )
2013-02-12 21:43:14 +00:00
{
2013-05-08 21:29:59 +02:00
if (! string . IsNullOrEmpty ( value ) && Library . Utility . Utility . ParseBool ( value , true ) != Library . Utility . Utility . ParseBool ( value , false ))
2015-01-20 21:07:24 +01:00
return Strings . Controller . UnsupportedBooleanValue ( optionname , value );
2013-02-12 21:43:14 +00:00
}
else if ( arg . Type == Duplicati . Library . Interface . CommandLineArgument . ArgumentType . Integer )
{
long l ;
if (! long . TryParse ( value , out l ))
2015-01-20 21:07:24 +01:00
return Strings . Controller . UnsupportedIntegerValue ( optionname , value );
2013-02-12 21:43:14 +00:00
}
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 )
2015-01-20 21:07:24 +01:00
return Strings . Controller . UnsupportedPathValue ( optionname , p );
2013-02-12 21:43:14 +00:00
}
else if ( arg . Type == Duplicati . Library . Interface . CommandLineArgument . ArgumentType . Size )
{
try
{
2013-05-08 21:29:59 +02:00
Library . Utility . Sizeparser . ParseSize ( value );
2013-02-12 21:43:14 +00:00
}
catch
{
2015-01-20 21:07:24 +01:00
return Strings . Controller . UnsupportedSizeValue ( optionname , value );
2013-02-12 21:43:14 +00:00
}
}
else if ( arg . Type == Duplicati . Library . Interface . CommandLineArgument . ArgumentType . Timespan )
{
try
{
2013-05-08 21:29:59 +02:00
Library . Utility . Timeparser . ParseTimeSpan ( value );
2013-02-12 21:43:14 +00:00
}
catch
{
2015-01-20 21:07:24 +01:00
return Strings . Controller . UnsupportedTimeValue ( optionname , value );
2013-02-12 21:43:14 +00:00
}
}
return null ;
}
2016-04-09 11:45:15 +02:00
2014-05-15 12:47:16 +02:00
public void Pause ()
{
var ct = m_currentTask ;
if ( ct != null )
ct . Pause ();
}
public void Resume ()
{
var ct = m_currentTask ;
if ( ct != null )
ct . Resume ();
}
public void Stop ()
{
var ct = m_currentTask ;
if ( ct != null )
ct . Stop ();
}
public void Abort ()
{
var ct = m_currentTask ;
if ( ct != null )
ct . Abort ();
2016-04-09 11:45:15 +02:00
2014-05-15 12:47:16 +02:00
var t = m_currentTaskThread ;
if ( t != null )
t . Abort ();
}
2013-02-12 21:43:14 +00:00
#region IDisposable Members
public void Dispose ()
{
}
#endregion
}
}