Example #1
0
        public void ExecuteTask(IDuplicityTask task)
        {
            System.Diagnostics.Process p = new System.Diagnostics.Process();
            p.StartInfo = SetupEnv(task);
            p.Start();
            p.WaitForExit();

            string errorstream = p.StandardError.ReadToEnd();
            string outstream = p.StandardOutput.ReadToEnd();

            string logentry = "";
            if (!string.IsNullOrEmpty(errorstream))
            {
                string tmp = errorstream.Replace("gpg: CAST5 encrypted data", "").Replace("gpg: encrypted with 1 passphrase", "").Trim();

                if (tmp.Length > 0)
                    logentry += "** Error stream: \r\n" + errorstream + "\r\n**\r\n";
            }
            logentry += outstream;

            task.RaiseTaskCompleted(logentry);

            if (task.TaskType == DuplicityTaskType.FullBackup || task.TaskType == DuplicityTaskType.IncrementalBackup)
            {
                if (task.Schedule.KeepFull > 0)
                    ExecuteTask(new RemoveAllButNFullTask(task.Schedule, (int)task.Schedule.KeepFull));
                if (!string.IsNullOrEmpty(task.Schedule.KeepTime))
                    ExecuteTask(new RemoveOlderThanTask(task.Schedule, task.Schedule.KeepTime));
            }
        }
Example #2
0
        void ListBackupsTask_TaskCompleted(IDuplicityTask owner, string output, string parsedMessage)
        {
            if (string.IsNullOrEmpty(output))
            {
                return;
            }

            const string DIVIDER = "-------------------------\r\n";
            const string HEADERS = " Type of backup set:                            Time:      Num volumes:";

            List <string> res = new List <string>();

            foreach (string part in output.Split(new string[] { DIVIDER }, StringSplitOptions.RemoveEmptyEntries))
            {
                if (part.IndexOf(HEADERS) >= 0)
                {
                    bool passedHeader = false;
                    foreach (string line in part.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries))
                    {
                        if (line.StartsWith(HEADERS))
                        {
                            passedHeader = true;
                        }
                        else if (passedHeader)
                        {
                            string tmp = line.Trim();
                            if (tmp.StartsWith("Full"))
                            {
                                tmp = tmp.Substring("Full".Length).Trim();
                            }
                            else if (tmp.StartsWith("Incremental"))
                            {
                                tmp = tmp.Substring("Incremental".Length).Trim();
                            }

                            string datetime = tmp.Substring(0, tmp.LastIndexOf(' ')).Trim();

                            /*DateTime dt;
                             * if (DateTime.TryParse(datetime, System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.None, out dt))*/
                            res.Add(datetime);
                        }
                    }
                }
            }


            //System.Text.RegularExpressions.Regex regexp = new System.Text.RegularExpressions.Regex("----------------

            m_backups = res.ToArray();
        }
Example #3
0
        private System.Diagnostics.ProcessStartInfo SetupEnv(IDuplicityTask task)
        {
            task.BeginTime = DateTime.Now;
            List <string> args = new List <string>();

            System.Diagnostics.ProcessStartInfo psi = new System.Diagnostics.ProcessStartInfo();

            StringDictionary env = psi.EnvironmentVariables;

            foreach (string key in m_environment.Keys)
            {
                env[key] = m_environment[key];
            }

            env["PATH"] = System.Environment.ExpandEnvironmentVariables(Program.ApplicationSettings.NcFTPPath) + System.IO.Path.PathSeparator + env["PATH"];
            env["PATH"] = System.Environment.ExpandEnvironmentVariables(Program.ApplicationSettings.PuttyPath) + System.IO.Path.PathSeparator + env["PATH"];
            env["PATH"] = System.Environment.ExpandEnvironmentVariables(Program.ApplicationSettings.PGPPath) + System.IO.Path.PathSeparator + env["PATH"];

            args.Add("\"" + System.Environment.ExpandEnvironmentVariables(Program.ApplicationSettings.DuplicityPath) + "\"");

            task.GetArguments(args);

            if (string.IsNullOrEmpty(task.Task.Encryptionkey))
            {
                args.Add("--no-encryption");
            }
            else
            {
                env["PASSPHRASE"] = task.Task.Encryptionkey;
            }


            task.Task.GetExtraSettings(args, env);

            psi.CreateNoWindow         = true;
            psi.WindowStyle            = System.Diagnostics.ProcessWindowStyle.Hidden;
            psi.FileName               = System.Environment.ExpandEnvironmentVariables(Program.ApplicationSettings.PythonPath);
            psi.RedirectStandardError  = true;
            psi.RedirectStandardOutput = true;
            psi.RedirectStandardInput  = false;
            psi.UseShellExecute        = false;
            psi.WorkingDirectory       = System.IO.Path.GetDirectoryName(psi.FileName);


            psi.Arguments = string.Join(" ", args.ToArray());
            return(psi);
        }
Example #4
0
        public void ExecuteTask(IDuplicityTask task)
        {
            System.Diagnostics.Process p = new System.Diagnostics.Process();
            p.StartInfo = SetupEnv(task);
            p.Start();
            p.WaitForExit();

            string errorstream = p.StandardError.ReadToEnd();
            string outstream   = p.StandardOutput.ReadToEnd();

            string logentry = "";

            if (!string.IsNullOrEmpty(errorstream))
            {
                string tmp = errorstream.Replace("gpg: CAST5 encrypted data", "").Replace("gpg: encrypted with 1 passphrase", "").Trim();

                if (tmp.Length > 0)
                {
                    logentry += "** Error stream: \r\n" + errorstream + "\r\n**\r\n";
                }
            }
            logentry += outstream;

            task.RaiseTaskCompleted(logentry);

            if (task.TaskType == DuplicityTaskType.FullBackup || task.TaskType == DuplicityTaskType.IncrementalBackup)
            {
                if (task.Schedule.KeepFull > 0)
                {
                    ExecuteTask(new RemoveAllButNFullTask(task.Schedule, (int)task.Schedule.KeepFull));
                }
                if (!string.IsNullOrEmpty(task.Schedule.KeepTime))
                {
                    ExecuteTask(new RemoveOlderThanTask(task.Schedule, task.Schedule.KeepTime));
                }
            }
        }
Example #5
0
        public void ExecuteTask(IDuplicityTask task)
        {
            Dictionary<string, string> options = new Dictionary<string,string>();

            //Set the log level to be that of the GUI
            options["log-level"] = Duplicati.Library.Logging.Log.LogLevel.ToString();

            string destination = task.GetConfiguration(options);

            string results = "";
            string parsedMessage = "";
            m_isAborted = false;

            try
            {
                //TODO: Its a bit dirty to set the options after creating the instance
                using (Interface i = new Interface(destination, options))
                {
                    lock (m_lock)
                    {
                        m_stopReason = System.Windows.Forms.CloseReason.None;
                        m_currentBackupControlInterface = i;
                    }

                    SetupControlInterface();

                    i.OperationProgress += new OperationProgressEvent(Duplicati_OperationProgress);

                    switch (task.TaskType)
                    {
                        case DuplicityTaskType.FullBackup:
                        case DuplicityTaskType.IncrementalBackup:
                            {
                                //Activate auto-cleanup
                                options["auto-cleanup"] = "";
                                options["force"] = "";
                                if (task.Schedule.Task.KeepFull > 0)
                                    m_extraOperations++;
                                if (!string.IsNullOrEmpty(task.Schedule.Task.KeepTime))
                                    m_extraOperations++;

                                Library.Utility.TempFolder tf = null;
                                try
                                {
                                    if (ProgressEvent != null)
                                        ProgressEvent(DuplicatiOperation.Backup, RunnerState.Started, task.Schedule.Name, "", 0, -1);

                                    if (task.Task.IncludeSetup)
                                    {
                                        //Make a copy of the current database
                                        tf = new Duplicati.Library.Utility.TempFolder();
                                        string filename = System.IO.Path.Combine(tf, System.IO.Path.GetFileName(Program.DatabasePath));

                                        System.IO.File.Copy(Program.DatabasePath, filename, true);
                                        using (System.Data.IDbConnection con = (System.Data.IDbConnection)Activator.CreateInstance(SQLiteLoader.SQLiteConnectionType))
                                        {
                                            con.ConnectionString = "Data Source=" + filename;

                                            //Open the database, handle any encryption issues automatically
                                            Program.OpenDatabase(con);

                                            using (System.Data.IDbCommand cmd = con.CreateCommand())
                                            {
                                                //Remove all log data to minimize the size of the database
                                                cmd.CommandText = "DELETE FROM CommandQueue;";
                                                cmd.ExecuteNonQuery();
                                                cmd.CommandText = "DELETE FROM Log;";
                                                cmd.ExecuteNonQuery();
                                                cmd.CommandText = "DELETE FROM LogBlob;";
                                                cmd.ExecuteNonQuery();

                                                //Free up unused space
                                                cmd.CommandText = "VACUUM;";
                                                cmd.ExecuteNonQuery();
                                            }
                                        }

                                        options["signature-control-files"] = filename;
                                    }

                                    options["full-if-sourcefolder-changed"] = "";

                                    List<KeyValuePair<bool, string>> filters = new List<KeyValuePair<bool, string>>();
                                    string[] sourceFolders = DynamicSetupHelper.GetSourceFolders(task.Task, new ApplicationSettings(task.Task.DataParent), filters);

                                    if (options.ContainsKey("filter"))
                                        filters.AddRange(Library.Utility.FilenameFilter.DecodeFilter(options["filter"]));

                                    options["filter"] = Library.Utility.FilenameFilter.EncodeAsFilter(filters);

                                    //At this point we register the backup as being in progress
                                    ((FullOrIncrementalTask)task).WriteBackupInProgress(Strings.DuplicatiRunner.ShutdownWhileBackupInprogress);

                                    results = i.Backup(sourceFolders);
                                }
                                finally
                                {
                                    if (tf != null)
                                        tf.Dispose();

                                    if (ProgressEvent != null)
                                        ProgressEvent(DuplicatiOperation.Backup, RunnerState.Stopped, task.Schedule.Name, "", 100, -1);
                                }
                                break;
                            }
                        case DuplicityTaskType.ListBackups:

                            List<string> res = new List<string>();
                            foreach (ManifestEntry be in i.GetBackupSets())
                            {
                                res.Add(be.Time.ToString());
                                foreach (ManifestEntry bei in be.Incrementals)
                                    res.Add(bei.Time.ToString());
                            }

                            (task as ListBackupsTask).Backups = res.ToArray();
                            break;
                        case DuplicityTaskType.ListBackupEntries:
                            (task as ListBackupEntriesTask).Backups = i.GetBackupSets();
                            break;
                        case DuplicityTaskType.ListFiles:
                            (task as ListFilesTask).Files = i.ListCurrentFiles();
                            break;
                        case DuplicityTaskType.ListSourceFolders:
                            (task as ListSourceFoldersTask).Files = new List<string>(i.ListSourceFolders() ?? new string[0]);
                            break;
                        case DuplicityTaskType.ListActualFiles:
                            (task as ListActualFilesTask).Files = i.ListActualSignatureFiles();
                            break;
                        case DuplicityTaskType.RemoveAllButNFull:
                            results = i.DeleteAllButNFull();
                            break;
                        case DuplicityTaskType.RemoveOlderThan:
                            results = i.DeleteOlderThan();
                            break;
                        case DuplicityTaskType.Restore:
                            options["file-to-restore"] = ((RestoreTask)task).SourceFiles;
                            if (options.ContainsKey("filter"))
                                options.Remove("filter");

                            try
                            {
                                if (ProgressEvent != null)
                                    ProgressEvent(DuplicatiOperation.Restore, RunnerState.Started, task.Schedule.Name, "", 0, -1);
                                results = i.Restore(task.LocalPath.Split(System.IO.Path.PathSeparator));
                            }
                            finally
                            {
                                if (ProgressEvent != null)
                                    ProgressEvent(DuplicatiOperation.Restore, RunnerState.Stopped, task.Schedule.Name, "", 100, -1);
                            }
                            break;

                        case DuplicityTaskType.RestoreSetup:
                            i.RestoreControlFiles(task.LocalPath);
                            break;
                        default:
                            return;
                    }
                }
            }
            catch (Exception ex)
            {
                while (ex is System.Reflection.TargetInvocationException && ex.InnerException != null)
                    ex = ex.InnerException;

                if (ex is System.Threading.ThreadAbortException)
                {
                    m_isAborted = true;
                    System.Threading.Thread.ResetAbort();
                }
                else if (ex is Library.Main.LiveControl.ExecutionStoppedException)
                    m_isAborted = true;

                if (m_isAborted && m_stopReason != System.Windows.Forms.CloseReason.None)
                {
                    //If the user has stopped the backup for some reason, write a nicer message
                    switch (m_stopReason)
                    {
                        case System.Windows.Forms.CloseReason.ApplicationExitCall:
                            parsedMessage = Strings.DuplicatiRunner.ApplicationExitLogMesssage;
                            break;
                        case System.Windows.Forms.CloseReason.TaskManagerClosing:
                            parsedMessage = Strings.DuplicatiRunner.TaskManagerCloseMessage;
                            break;
                        case System.Windows.Forms.CloseReason.UserClosing:
                            parsedMessage = Strings.DuplicatiRunner.UserClosingMessage;
                            break;
                        case System.Windows.Forms.CloseReason.WindowsShutDown:
                            parsedMessage = Strings.DuplicatiRunner.WindowsShutdownMessage;
                            break;
                        default:
                            parsedMessage = string.Format(Strings.DuplicatiRunner.OtherAbortMessage, m_stopReason);
                            break;
                    }

                    if (task.Schedule != null)
                    {
                        //If the application is going down, the backup should resume on next launch
                        switch (m_stopReason)
                        {
                            case System.Windows.Forms.CloseReason.ApplicationExitCall:
                            case System.Windows.Forms.CloseReason.TaskManagerClosing:
                            case System.Windows.Forms.CloseReason.WindowsShutDown:
                                task.Schedule.ScheduledRunFailed();
                                break;
                        }
                    }
                }
                else
                    parsedMessage = string.Format(Strings.DuplicatiRunner.ErrorMessage, ex.Message);

                results = "Error: " + ex.ToString(); //Don't localize

                while (ex.InnerException != null)
                {
                    ex = ex.InnerException;
                    results += Environment.NewLine + "InnerError: " + ex.ToString(); //Don't localize
                }

            }
            finally
            {
                lock (m_lock)
                    m_currentBackupControlInterface = null;
            }

            try
            {
                if (!m_isAborted && (task.TaskType == DuplicityTaskType.FullBackup || task.TaskType == DuplicityTaskType.IncrementalBackup))
                {
                    if (task.Schedule.Task.KeepFull > 0)
                    {
                        m_lastPGProgress = 100;
                        m_lastPGmessage = Strings.DuplicatiRunner.CleaningUpMessage;
                        m_lastPGSubmessage = "";
                        m_lastPGSubprogress = -1;

                        ReinvokeLastProgressEvent();
                        m_extraOperations--;

                        RemoveAllButNFullTask tmpTask = new RemoveAllButNFullTask(task.Schedule, (int)task.Schedule.Task.KeepFull);
                        ExecuteTask(tmpTask);
                        results += Environment.NewLine + Strings.DuplicatiRunner.CleanupLogdataHeader + Environment.NewLine + tmpTask.Result;
                    }

                    if (!string.IsNullOrEmpty(task.Schedule.Task.KeepTime))
                    {
                        m_lastPGProgress = 100;
                        m_lastPGmessage = Strings.DuplicatiRunner.CleaningUpMessage;
                        m_lastPGSubmessage = "";
                        m_lastPGSubprogress = -1;

                        ReinvokeLastProgressEvent();
                        m_extraOperations--;

                        RemoveOlderThanTask tmpTask = new RemoveOlderThanTask(task.Schedule, task.Schedule.Task.KeepTime);
                        ExecuteTask(tmpTask);
                        results += Environment.NewLine + Strings.DuplicatiRunner.CleanupLogdataHeader + Environment.NewLine + tmpTask.Result;
                    }

                    if (task.Schedule.Task.KeepFull > 0 || !string.IsNullOrEmpty(task.Schedule.Task.KeepTime))
                        ReinvokeLastProgressEvent();

                    if (ProgressEvent != null)
                        ProgressEvent(DuplicatiOperation.Backup, RunnerState.Stopped, task.Schedule.Name, "", 100, -1);
                }
            }
            catch (Exception ex)
            {
                results += Environment.NewLine + string.Format(Strings.DuplicatiRunner.CleanupError, ex.Message);
            }

            task.IsAborted = m_isAborted;
            task.Result = results;
            task.RaiseTaskCompleted(results, parsedMessage);

            if (ResultEvent != null && task is FullBackupTask || task is IncrementalBackupTask)
            {
                Log[] logs = Program.DataConnection.GetObjects<Log>("TaskID = ? AND SubAction LIKE ? ORDER BY EndTime DESC", task.Task.ID, "Primary");
                if (logs != null && logs.Length > 0)
                {
                    Datamodel.Log l = logs[0];
                    RunnerResult r = RunnerResult.Error;
                    if (l.ParsedStatus == DuplicatiOutputParser.ErrorStatus)
                        r = RunnerResult.Error;
                    else if (l.ParsedStatus == DuplicatiOutputParser.OKStatus || l.ParsedStatus == DuplicatiOutputParser.NoChangedFiles)
                        r = RunnerResult.OK;
                    else if (l.ParsedStatus == DuplicatiOutputParser.PartialStatus)
                        r = RunnerResult.Partial;
                    else if (l.ParsedStatus == DuplicatiOutputParser.WarningStatus)
                        r = RunnerResult.Warning;

                    ResultEvent(r, parsedMessage, results);
                }
            }

            if (task.Schedule != null && !m_isAborted)
                task.Schedule.ScheduledRunCompleted(); //Register as completed if not aborted
        }
Example #6
0
 void DoneEvent(IDuplicityTask owner, string output, string parsedMessage)
 {
     WriteLogMessage("Backup", "Cleanup", output, parsedMessage, false, null);
 }
Example #7
0
        void ListBackupsTask_TaskCompleted(IDuplicityTask owner, string output, string parsedMessage)
        {
            if (string.IsNullOrEmpty(output))
                return;

            const string DIVIDER = "-------------------------\r\n";
            const string HEADERS = " Type of backup set:                            Time:      Num volumes:";

            List<string> res = new List<string>();

            foreach (string part in output.Split(new string[] { DIVIDER }, StringSplitOptions.RemoveEmptyEntries))
                if (part.IndexOf(HEADERS) >= 0)
                {
                    bool passedHeader = false;
                    foreach (string line in part.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries))
                    {
                        if (line.StartsWith(HEADERS))
                            passedHeader = true;
                        else if (passedHeader)
                        {
                            string tmp = line.Trim();
                            if (tmp.StartsWith("Full"))
                                tmp = tmp.Substring("Full".Length).Trim();
                            else if (tmp.StartsWith("Incremental"))
                                tmp = tmp.Substring("Incremental".Length).Trim();

                            string datetime = tmp.Substring(0, tmp.LastIndexOf(' ')).Trim();
                            /*DateTime dt;
                            if (DateTime.TryParse(datetime, System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.None, out dt))*/
                            res.Add(datetime);
                        }
                    }
                }

            //System.Text.RegularExpressions.Regex regexp = new System.Text.RegularExpressions.Regex("----------------

            m_backups = res.ToArray();
        }
Example #8
0
 protected void DoneEvent(IDuplicityTask task, string output, string parsedMessage)
 {
     WriteLogMessage("Backup", "Primary", output, parsedMessage, true, m_log);
     m_log = null;
 }
Example #9
0
 void DoneEvent(IDuplicityTask owner, string output, string parsedMessage)
 {
     WriteLogMessage("Restore", "Primary", output, parsedMessage, true, null);
 }
Example #10
0
 void DoneEvent(IDuplicityTask owner, string output, string parsedMessage)
 {
     WriteLogMessage("Backup", "Cleanup", output, parsedMessage, false, null);
 }
Example #11
0
 void DoneEvent(IDuplicityTask owner, string output, string parsedMessage)
 {
     WriteLogMessage("Restore", "Primary", output, parsedMessage, true, null);
 }
Example #12
0
 protected void DoneEvent(IDuplicityTask task, string output, string parsedMessage)
 {
     WriteLogMessage("Backup", "Primary", output, parsedMessage, true, m_log);
     m_log = null;
 }
Example #13
0
        /// <summary>
        /// The actual scheduling procedure
        /// </summary>
        private void Runner()
        {
            while (!m_terminate)
            {
                List <Schedule> reps = new List <Schedule>();
                List <Schedule> tmp;
                lock (m_datalock)
                    tmp = new List <Schedule>(m_connection.GetObjects <Schedule>());

                //Determine schedule list
                foreach (Schedule sc in tmp)
                {
                    if (!string.IsNullOrEmpty(sc.Repeat))
                    {
                        DateTime start = sc.NextScheduledTime;

                        try { start = GetNextValidTime(sc.NextScheduledTime, sc.Repeat, sc.AllowedWeekdays); }
                        catch { } //TODO: Report this somehow

                        //If time is exceeded, run it now
                        if (start <= DateTime.Now)
                        {
                            //See if it is already queued
                            List <IDuplicityTask> tmplst   = m_worker.CurrentTasks;
                            IDuplicityTask        tastTemp = m_worker.CurrentTask;
                            if (tastTemp != null)
                            {
                                tmplst.Add(tastTemp);
                            }

                            bool found = false;
                            foreach (IDuplicityTask t in tmplst)
                            {
                                if (t != null && t is IncrementalBackupTask && ((IncrementalBackupTask)t).Schedule.ID == sc.ID)
                                {
                                    found = true;
                                    break;
                                }
                            }

                            //If it is not already in queue, put it there
                            if (!found)
                            {
                                m_worker.AddTask(new IncrementalBackupTask(sc));
                            }

                            //Caluclate next time, by adding the interval to the start until we have
                            // passed the current date and time
                            //TODO: Make this more efficient
                            int i = 50000;
                            while (start <= DateTime.Now && i-- > 0)
                            {
                                try { start = GetNextValidTime(Timeparser.ParseTimeInterval(sc.Repeat, start), sc.Repeat, sc.AllowedWeekdays); }
                                catch
                                {
                                    //TODO: Report this somehow
                                    continue;
                                }
                            }

                            if (start < DateTime.Now)
                            {
                                continue;
                            }
                        }

                        //Add to schedule list at the new time
                        reps.Add(sc);
                        sc.NextScheduledTime = start;
                    }
                }

                System.Data.LightDatamodel.QueryModel.OperationOrParameter op = System.Data.LightDatamodel.QueryModel.Parser.ParseQuery("ORDER BY When ASC");

                //Sort them, lock as we assign the m_schedule variable
                lock (m_lock)
                    m_schedule = op.EvaluateList <Schedule>(reps).ToArray();

                //Raise event if needed
                if (NewSchedule != null)
                {
                    NewSchedule(this, null);
                }

                int waittime = 0;

                //Figure out a sensible amount of time to sleep the thread
                if (m_schedule.Length > 0)
                {
                    //When is the next run scheduled?
                    TimeSpan nextrun = m_schedule[0].NextScheduledTime - DateTime.Now;
                    if (nextrun.TotalMilliseconds < 0)
                    {
                        continue;
                    }

                    //Don't sleep for more than 5 minutes
                    waittime = (int)Math.Min(nextrun.TotalMilliseconds, 60 * 1000 * 5);
                }
                else
                {
                    //No tasks, check back later
                    waittime = 60 * 1000;
                }

                //Waiting on the event, enables a wakeup call from termination
                // never use waittime = 0
                m_event.WaitOne(Math.Max(100, waittime), false);
            }
        }
Example #14
0
        private System.Diagnostics.ProcessStartInfo SetupEnv(IDuplicityTask task)
        {
            task.BeginTime = DateTime.Now;
            List<string> args = new List<string>();
            System.Diagnostics.ProcessStartInfo psi = new System.Diagnostics.ProcessStartInfo();

            StringDictionary env = psi.EnvironmentVariables;

            foreach (string key in m_environment.Keys)
                env[key] = m_environment[key];

            env["PATH"] = System.Environment.ExpandEnvironmentVariables(Program.ApplicationSettings.NcFTPPath) + System.IO.Path.PathSeparator + env["PATH"];
            env["PATH"] = System.Environment.ExpandEnvironmentVariables(Program.ApplicationSettings.PuttyPath) + System.IO.Path.PathSeparator + env["PATH"];
            env["PATH"] = System.Environment.ExpandEnvironmentVariables(Program.ApplicationSettings.PGPPath) + System.IO.Path.PathSeparator + env["PATH"];

            args.Add("\"" + System.Environment.ExpandEnvironmentVariables(Program.ApplicationSettings.DuplicityPath) + "\"");

            task.GetArguments(args);

            if (string.IsNullOrEmpty(task.Task.Encryptionkey))
                args.Add("--no-encryption");
            else
                env["PASSPHRASE"] = task.Task.Encryptionkey;

            task.Task.GetExtraSettings(args, env);

            psi.CreateNoWindow = true;
            psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
            psi.FileName = System.Environment.ExpandEnvironmentVariables(Program.ApplicationSettings.PythonPath);
            psi.RedirectStandardError = true;
            psi.RedirectStandardOutput = true;
            psi.RedirectStandardInput = false;
            psi.UseShellExecute = false;
            psi.WorkingDirectory = System.IO.Path.GetDirectoryName(psi.FileName);

            psi.Arguments = string.Join(" ", args.ToArray());
            return psi;
        }
Example #15
0
        public void ExecuteTask(IDuplicityTask task)
        {
            Dictionary <string, string> options = new Dictionary <string, string>();

            //Set the log level to be that of the GUI
            options["log-level"] = Duplicati.Library.Logging.Log.LogLevel.ToString();

            string destination = task.GetConfiguration(options);

            string results       = "";
            string parsedMessage = "";

            m_isAborted = false;

            try
            {
                //TODO: Its a bit dirty to set the options after creating the instance
                using (Interface i = new Interface(destination, options))
                {
                    lock (m_lock)
                    {
                        m_stopReason = System.Windows.Forms.CloseReason.None;
                        m_currentBackupControlInterface = i;
                    }

                    SetupControlInterface();

                    i.OperationProgress += new OperationProgressEvent(Duplicati_OperationProgress);

                    switch (task.TaskType)
                    {
                    case DuplicityTaskType.FullBackup:
                    case DuplicityTaskType.IncrementalBackup:
                    {
                        //Activate auto-cleanup
                        options["auto-cleanup"] = "";
                        options["force"]        = "";
                        if (task.Schedule.Task.KeepFull > 0)
                        {
                            m_extraOperations++;
                        }
                        if (!string.IsNullOrEmpty(task.Schedule.Task.KeepTime))
                        {
                            m_extraOperations++;
                        }

                        Library.Utility.TempFolder tf = null;
                        try
                        {
                            if (ProgressEvent != null)
                            {
                                ProgressEvent(DuplicatiOperation.Backup, RunnerState.Started, task.Schedule.Name, "", 0, -1);
                            }

                            if (task.Task.IncludeSetup)
                            {
                                //Make a copy of the current database
                                tf = new Duplicati.Library.Utility.TempFolder();
                                string filename = System.IO.Path.Combine(tf, System.IO.Path.GetFileName(Program.DatabasePath));

                                System.IO.File.Copy(Program.DatabasePath, filename, true);
                                using (System.Data.IDbConnection con = (System.Data.IDbConnection)Activator.CreateInstance(SQLiteLoader.SQLiteConnectionType))
                                {
                                    con.ConnectionString = "Data Source=" + filename;

                                    //Open the database, handle any encryption issues automatically
                                    Program.OpenDatabase(con);

                                    using (System.Data.IDbCommand cmd = con.CreateCommand())
                                    {
                                        //Remove all log data to minimize the size of the database
                                        cmd.CommandText = "DELETE FROM CommandQueue;";
                                        cmd.ExecuteNonQuery();
                                        cmd.CommandText = "DELETE FROM Log;";
                                        cmd.ExecuteNonQuery();
                                        cmd.CommandText = "DELETE FROM LogBlob;";
                                        cmd.ExecuteNonQuery();

                                        //Free up unused space
                                        cmd.CommandText = "VACUUM;";
                                        cmd.ExecuteNonQuery();
                                    }
                                }

                                options["signature-control-files"] = filename;
                            }

                            options["full-if-sourcefolder-changed"] = "";

                            List <KeyValuePair <bool, string> > filters = new List <KeyValuePair <bool, string> >();
                            string[] sourceFolders = DynamicSetupHelper.GetSourceFolders(task.Task, new ApplicationSettings(task.Task.DataParent), filters);

                            if (options.ContainsKey("filter"))
                            {
                                filters.AddRange(Library.Utility.FilenameFilter.DecodeFilter(options["filter"]));
                            }

                            options["filter"] = Library.Utility.FilenameFilter.EncodeAsFilter(filters);

                            //At this point we register the backup as being in progress
                            ((FullOrIncrementalTask)task).WriteBackupInProgress(Strings.DuplicatiRunner.ShutdownWhileBackupInprogress);

                            results = i.Backup(sourceFolders);
                        }
                        finally
                        {
                            if (tf != null)
                            {
                                tf.Dispose();
                            }

                            if (ProgressEvent != null)
                            {
                                ProgressEvent(DuplicatiOperation.Backup, RunnerState.Stopped, task.Schedule.Name, "", 100, -1);
                            }
                        }
                        break;
                    }

                    case DuplicityTaskType.ListBackups:

                        List <string> res = new List <string>();
                        foreach (ManifestEntry be in i.GetBackupSets())
                        {
                            res.Add(be.Time.ToString());
                            foreach (ManifestEntry bei in be.Incrementals)
                            {
                                res.Add(bei.Time.ToString());
                            }
                        }

                        (task as ListBackupsTask).Backups = res.ToArray();
                        break;

                    case DuplicityTaskType.ListBackupEntries:
                        (task as ListBackupEntriesTask).Backups = i.GetBackupSets();
                        break;

                    case DuplicityTaskType.ListFiles:
                        (task as ListFilesTask).Files = i.ListCurrentFiles();
                        break;

                    case DuplicityTaskType.ListSourceFolders:
                        (task as ListSourceFoldersTask).Files = new List <string>(i.ListSourceFolders() ?? new string[0]);
                        break;

                    case DuplicityTaskType.ListActualFiles:
                        (task as ListActualFilesTask).Files = i.ListActualSignatureFiles();
                        break;

                    case DuplicityTaskType.RemoveAllButNFull:
                        results = i.DeleteAllButNFull();
                        break;

                    case DuplicityTaskType.RemoveOlderThan:
                        results = i.DeleteOlderThan();
                        break;

                    case DuplicityTaskType.Restore:
                        options["file-to-restore"] = ((RestoreTask)task).SourceFiles;
                        if (options.ContainsKey("filter"))
                        {
                            options.Remove("filter");
                        }

                        try
                        {
                            if (ProgressEvent != null)
                            {
                                ProgressEvent(DuplicatiOperation.Restore, RunnerState.Started, task.Schedule.Name, "", 0, -1);
                            }
                            results = i.Restore(task.LocalPath.Split(System.IO.Path.PathSeparator));
                        }
                        finally
                        {
                            if (ProgressEvent != null)
                            {
                                ProgressEvent(DuplicatiOperation.Restore, RunnerState.Stopped, task.Schedule.Name, "", 100, -1);
                            }
                        }
                        break;

                    case DuplicityTaskType.RestoreSetup:
                        i.RestoreControlFiles(task.LocalPath);
                        break;

                    default:
                        return;
                    }
                }
            }
            catch (Exception ex)
            {
                while (ex is System.Reflection.TargetInvocationException && ex.InnerException != null)
                {
                    ex = ex.InnerException;
                }

                if (ex is System.Threading.ThreadAbortException)
                {
                    m_isAborted = true;
                    System.Threading.Thread.ResetAbort();
                }
                else if (ex is Library.Main.LiveControl.ExecutionStoppedException)
                {
                    m_isAborted = true;
                }

                if (m_isAborted && m_stopReason != System.Windows.Forms.CloseReason.None)
                {
                    //If the user has stopped the backup for some reason, write a nicer message
                    switch (m_stopReason)
                    {
                    case System.Windows.Forms.CloseReason.ApplicationExitCall:
                        parsedMessage = Strings.DuplicatiRunner.ApplicationExitLogMesssage;
                        break;

                    case System.Windows.Forms.CloseReason.TaskManagerClosing:
                        parsedMessage = Strings.DuplicatiRunner.TaskManagerCloseMessage;
                        break;

                    case System.Windows.Forms.CloseReason.UserClosing:
                        parsedMessage = Strings.DuplicatiRunner.UserClosingMessage;
                        break;

                    case System.Windows.Forms.CloseReason.WindowsShutDown:
                        parsedMessage = Strings.DuplicatiRunner.WindowsShutdownMessage;
                        break;

                    default:
                        parsedMessage = string.Format(Strings.DuplicatiRunner.OtherAbortMessage, m_stopReason);
                        break;
                    }

                    if (task.Schedule != null)
                    {
                        //If the application is going down, the backup should resume on next launch
                        switch (m_stopReason)
                        {
                        case System.Windows.Forms.CloseReason.ApplicationExitCall:
                        case System.Windows.Forms.CloseReason.TaskManagerClosing:
                        case System.Windows.Forms.CloseReason.WindowsShutDown:
                            task.Schedule.ScheduledRunFailed();
                            break;
                        }
                    }
                }
                else
                {
                    parsedMessage = string.Format(Strings.DuplicatiRunner.ErrorMessage, ex.Message);
                }

                results = "Error: " + ex.ToString(); //Don't localize

                while (ex.InnerException != null)
                {
                    ex       = ex.InnerException;
                    results += Environment.NewLine + "InnerError: " + ex.ToString(); //Don't localize
                }
            }
            finally
            {
                lock (m_lock)
                    m_currentBackupControlInterface = null;
            }

            try
            {
                if (!m_isAborted && (task.TaskType == DuplicityTaskType.FullBackup || task.TaskType == DuplicityTaskType.IncrementalBackup))
                {
                    if (task.Schedule.Task.KeepFull > 0)
                    {
                        m_lastPGProgress    = 100;
                        m_lastPGmessage     = Strings.DuplicatiRunner.CleaningUpMessage;
                        m_lastPGSubmessage  = "";
                        m_lastPGSubprogress = -1;

                        ReinvokeLastProgressEvent();
                        m_extraOperations--;

                        RemoveAllButNFullTask tmpTask = new RemoveAllButNFullTask(task.Schedule, (int)task.Schedule.Task.KeepFull);
                        ExecuteTask(tmpTask);
                        results += Environment.NewLine + Strings.DuplicatiRunner.CleanupLogdataHeader + Environment.NewLine + tmpTask.Result;
                    }

                    if (!string.IsNullOrEmpty(task.Schedule.Task.KeepTime))
                    {
                        m_lastPGProgress    = 100;
                        m_lastPGmessage     = Strings.DuplicatiRunner.CleaningUpMessage;
                        m_lastPGSubmessage  = "";
                        m_lastPGSubprogress = -1;

                        ReinvokeLastProgressEvent();
                        m_extraOperations--;

                        RemoveOlderThanTask tmpTask = new RemoveOlderThanTask(task.Schedule, task.Schedule.Task.KeepTime);
                        ExecuteTask(tmpTask);
                        results += Environment.NewLine + Strings.DuplicatiRunner.CleanupLogdataHeader + Environment.NewLine + tmpTask.Result;
                    }

                    if (task.Schedule.Task.KeepFull > 0 || !string.IsNullOrEmpty(task.Schedule.Task.KeepTime))
                    {
                        ReinvokeLastProgressEvent();
                    }

                    if (ProgressEvent != null)
                    {
                        ProgressEvent(DuplicatiOperation.Backup, RunnerState.Stopped, task.Schedule.Name, "", 100, -1);
                    }
                }
            }
            catch (Exception ex)
            {
                results += Environment.NewLine + string.Format(Strings.DuplicatiRunner.CleanupError, ex.Message);
            }

            task.IsAborted = m_isAborted;
            task.Result    = results;
            task.RaiseTaskCompleted(results, parsedMessage);

            if (ResultEvent != null && task is FullBackupTask || task is IncrementalBackupTask)
            {
                Log[] logs = Program.DataConnection.GetObjects <Log>("TaskID = ? AND SubAction LIKE ? ORDER BY EndTime DESC", task.Task.ID, "Primary");
                if (logs != null && logs.Length > 0)
                {
                    Datamodel.Log l = logs[0];
                    RunnerResult  r = RunnerResult.Error;
                    if (l.ParsedStatus == DuplicatiOutputParser.ErrorStatus)
                    {
                        r = RunnerResult.Error;
                    }
                    else if (l.ParsedStatus == DuplicatiOutputParser.OKStatus || l.ParsedStatus == DuplicatiOutputParser.NoChangedFiles)
                    {
                        r = RunnerResult.OK;
                    }
                    else if (l.ParsedStatus == DuplicatiOutputParser.PartialStatus)
                    {
                        r = RunnerResult.Partial;
                    }
                    else if (l.ParsedStatus == DuplicatiOutputParser.WarningStatus)
                    {
                        r = RunnerResult.Warning;
                    }

                    ResultEvent(r, parsedMessage, results);
                }
            }

            if (task.Schedule != null && !m_isAborted)
            {
                task.Schedule.ScheduledRunCompleted(); //Register as completed if not aborted
            }
        }
Example #16
0
        void m_form_Finished(object sender, System.ComponentModel.CancelEventArgs e)
        {
            Wizard_pages.WizardSettingsWrapper wrapper = new Duplicati.GUI.Wizard_pages.WizardSettingsWrapper(m_form.Settings);

            if (wrapper.PrimayAction == Duplicati.GUI.Wizard_pages.WizardSettingsWrapper.MainAction.Add || wrapper.PrimayAction == Duplicati.GUI.Wizard_pages.WizardSettingsWrapper.MainAction.Edit)
            {
                bool scheduleRun   = wrapper.RunImmediately;
                bool autoScheduled = (wrapper.BackupTimeOffset < DateTime.Now) && !string.IsNullOrEmpty(wrapper.RepeatInterval);

                //Resume Duplicati if the backup is supposed to run
                if (scheduleRun || autoScheduled)
                {
                    if (!AskToResumeIfPaused())
                    {
                        e.Cancel = true;
                        return;
                    }
                }

                Schedule schedule;
                IDataFetcherWithRelations con = new DataFetcherNested(Program.DataConnection);

                if (wrapper.PrimayAction == Duplicati.GUI.Wizard_pages.WizardSettingsWrapper.MainAction.Add)
                {
                    schedule = con.Add <Schedule>();
                }
                else
                {
                    schedule = con.GetObjectById <Schedule>(wrapper.ScheduleID);
                }

                wrapper.UpdateSchedule(schedule);

                lock (Program.MainLock)
                    con.CommitAllRecursive();
                schedule = Program.DataConnection.GetObjectById <Schedule>(schedule.ID);

                if (wrapper.UseEncryptionAsDefault)
                {
                    ApplicationSettings appset = new ApplicationSettings(Program.DataConnection);
                    appset.UseCommonPassword = true;
                    appset.CommonPassword    = wrapper.BackupPassword;
                    appset.CommonPasswordEncryptionModule = wrapper.EncryptionModule;
                    Program.DataConnection.Commit(Program.DataConnection.GetObjects <ApplicationSetting>());
                }

                //If the user has selected that the backup should run now
                // and it is not run automatically, start it now
                if (scheduleRun && !autoScheduled)
                {
                    Program.WorkThread.AddTask(new IncrementalBackupTask(schedule));
                }
            }
            else if (m_form.CurrentPage is Wizard_pages.Restore.FinishedRestore)
            {
                if (!AskToResumeIfPaused())
                {
                    e.Cancel = true;
                    return;
                }

                Schedule schedule = wrapper.DataConnection.GetObjectById <Schedule>(wrapper.ScheduleID);

                DateTime when          = wrapper.RestoreTime;
                string   target        = wrapper.FullRestorePath;
                string   restoreFilter = wrapper.RestoreFilter;

                if (when.Ticks == 0)
                {
                    Program.WorkThread.AddTask(new RestoreTask(schedule, target, restoreFilter));
                }
                else
                {
                    Program.WorkThread.AddTask(new RestoreTask(schedule, target, restoreFilter, when));
                }

                Program.DisplayHelper.ShowStatus();
            }
            else if (m_form.CurrentPage is Wizard_pages.RunNow.RunNowFinished)
            {
                if (!AskToResumeIfPaused())
                {
                    e.Cancel = true;
                    return;
                }

                Schedule schedule = wrapper.DataConnection.GetObjectById <Schedule>(wrapper.ScheduleID);
                if (wrapper.ForceFull)
                {
                    Program.WorkThread.AddTask(new FullBackupTask(schedule));
                }
                else
                {
                    Program.WorkThread.AddTask(new IncrementalBackupTask(schedule));
                }
            }
            else if (m_form.CurrentPage is Wizard_pages.Delete_backup.DeleteFinished)
            {
                Schedule schedule = wrapper.DataConnection.GetObjectById <Schedule>(wrapper.ScheduleID);

                if (Program.WorkThread.Active)
                {
                    try
                    {
                        //TODO: It's not safe to access the values like this,
                        //because the runner thread might interfere
                        if (Program.WorkThread.CurrentTask.Schedule.ID == schedule.ID)
                        {
                            bool paused = Program.LiveControl.State == LiveControls.LiveControlState.Paused;
                            Program.LiveControl.Pause();
                            if (MessageBox.Show(m_form.Dialog, Strings.WizardHandler.StopRunningBackupQuestion, Application.ProductName, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question) != DialogResult.Yes)
                            {
                                e.Cancel = true;
                                if (!paused)
                                {
                                    Program.LiveControl.Resume();
                                }
                                return;
                            }

                            bool repaused = Program.LiveControl.State == LiveControls.LiveControlState.Paused;
                            Program.LiveControl.Pause();
                            if (Program.WorkThread.CurrentTask.Schedule.ID == schedule.ID)
                            {
                                Program.Runner.Terminate();
                            }

                            Cursor prevCursor = m_form.Dialog.Cursor;

                            try
                            {
                                m_form.Dialog.Cursor = Cursors.WaitCursor;
                                for (int i = 0; i < 10; i++)
                                {
                                    if (Program.WorkThread.Active)
                                    {
                                        IDuplicityTask t = Program.WorkThread.CurrentTask;
                                        if (t != null && t.Schedule.ID == schedule.ID)
                                        {
                                            System.Threading.Thread.Sleep(1000);
                                        }
                                        else
                                        {
                                            break;
                                        }
                                    }
                                    else
                                    {
                                        break;
                                    }
                                }
                            }
                            finally
                            {
                                try { m_form.Dialog.Cursor = prevCursor; }
                                catch { }
                            }

                            if (Program.WorkThread.Active)
                            {
                                IDuplicityTask t = Program.WorkThread.CurrentTask;
                                if (t == null && t.Schedule.ID == schedule.ID)
                                {
                                    MessageBox.Show(m_form.Dialog, Strings.WizardHandler.UnableToStopBackupError, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                                    e.Cancel = true;
                                    return;
                                }
                            }

                            if (!paused || !repaused)
                            {
                                Program.LiveControl.Resume();
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(m_form.Dialog, string.Format(Strings.WizardHandler.StopBackupError, ex.Message), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                        e.Cancel = true;
                        return;
                    }
                }

                //Prior to deleting we need to make sure all relations are loaded
                Queue <object> unvisited            = new Queue <object>();
                Dictionary <object, object> visited = new Dictionary <object, object>();

                //Set up a transaction we can safely work on
                System.Data.LightDatamodel.DataFetcherNested con = new DataFetcherNested(Program.DataConnection);

                //Load the schedule in the transaction context
                object entryItem = con.GetObjectById <Schedule>(schedule.ID);
                unvisited.Enqueue(entryItem);
                visited[entryItem] = null;

                //Traverse the object relations
                while (unvisited.Count > 0)
                {
                    object x = unvisited.Dequeue();
                    foreach (System.Reflection.PropertyInfo pi in x.GetType().GetProperties())
                    {
                        if (pi.PropertyType != typeof(string) && (typeof(System.Data.LightDatamodel.IDataClass).IsAssignableFrom(pi.PropertyType) || typeof(System.Collections.IEnumerable).IsAssignableFrom(pi.PropertyType)))
                        {
                            try
                            {
                                object tmp = pi.GetValue(x, null);
                                foreach (object i in tmp as System.Collections.IEnumerable ?? new object[] { tmp })
                                {
                                    if (i as IDataClass != null && !visited.ContainsKey(i))
                                    {
                                        visited[i] = null;
                                        unvisited.Enqueue(i);
                                    }
                                }
                            }
                            catch
                            {
                                //TODO: Perhaps log this?
                            }
                        }
                    }
                }

                //Remove all entries visited
                foreach (IDataClass o in visited.Keys)
                {
                    con.DeleteObject(o);
                }

                //TODO: The worker may schedule the task while we attempt to de-schedule it
                foreach (IDuplicityTask t in Program.WorkThread.CurrentTasks)
                {
                    if (t != null && t is IncrementalBackupTask && ((IncrementalBackupTask)t).Schedule.ID == schedule.ID)
                    {
                        Program.WorkThread.RemoveTask(t);
                    }
                }

                //Persist to database
                con.CommitAllRecursive();

                //We have fiddled with the schedules
                Program.Scheduler.Reschedule();
            }
            else if (m_form.CurrentPage is Wizard_pages.RestoreSetup.FinishedRestoreSetup)
            {
                MessageBox.Show(m_form as Form, Strings.WizardHandler.SetupRestoreSuccess, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }