/// <summary> /// Returns the next valid date, given the start and the interval /// </summary> /// <param name="basetime">The base time</param> /// <param name="firstdata">The first allowed date</param> /// <param name="repetition">The repetition interval</param> /// <param name="allowedDays">The days the backup is allowed to run</param> /// <returns>The next valid date, or throws an exception if no such date can be found</returns> public static DateTime GetNextValidTime(DateTime basetime, DateTime firstdate, string repetition, DayOfWeek[] allowedDays) { DateTime res = basetime; int i = 50000; while ((!IsDateAllowed(res, allowedDays) || res < firstdate) && i-- > 0) { res = Timeparser.ParseTimeInterval(repetition, res); } if (!IsDateAllowed(res, allowedDays) || res < firstdate) { StringBuilder sb = new StringBuilder(); if (allowedDays != null) { foreach (DayOfWeek w in allowedDays) { if (sb.Length != 0) { sb.Append(", "); } sb.Append(w.ToString()); } } throw new Exception(Strings.Scheduler.InvalidTimeSetupError(basetime, repetition, sb.ToString())); } return(res); }
void IncrementalSettings_PageLeave(object sender, PageChangedArgs args) { if (args.Direction == PageChangedDirection.Back) { return; } if (EnableCleanupDuration.Checked) { try { if (Timeparser.ParseTimeSpan(CleanupDuration.Value).TotalDays < 1) { MessageBox.Show(this, Strings.CleanupSettings.TooShortCleanupDurationDay, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error); args.Cancel = true; return; } } catch (Exception ex) { MessageBox.Show(this, string.Format(GUI.Strings.Common.InvalidDuration, ex.Message), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error); args.Cancel = true; return; } } if (!m_wrapper.CleanupSettingsUI.HasWarnedClean && !(EnableCleanupDuration.Checked || EnableFullBackupClean.Checked)) { if (MessageBox.Show(this, Strings.CleanupSettings.DisabledCleanupWarning, Application.ProductName, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Warning) != DialogResult.Yes) { args.Cancel = true; return; } m_wrapper.CleanupSettingsUI.HasWarnedClean = true; } m_wrapper.MaxFullBackups = EnableFullBackupClean.Checked ? (int)CleanFullBackupCount.Value : 0; m_wrapper.BackupExpireInterval = EnableCleanupDuration.Checked ? CleanupDuration.Value : ""; m_wrapper.IgnoreFileTimestamps = IgnoreTimestamps.Checked; //Don't set args.NextPage, it runs on a list }
public SharePointBackend(string url, Dictionary <string, string> options) { m_deleteToRecycler = Utility.Utility.ParseBoolOption(options, "delete-to-recycler"); m_useBinaryDirectMode = Utility.Utility.ParseBoolOption(options, "binary-direct-mode"); try { string strSpan; if (options.TryGetValue("web-timeout", out strSpan)) { TimeSpan ts = Timeparser.ParseTimeSpan(strSpan); if (ts.TotalMilliseconds > 30000 && ts.TotalMilliseconds < int.MaxValue) { this.m_useContextTimeoutMs = (int)ts.TotalMilliseconds; } } } catch { } try { string strChunkSize; if (options.TryGetValue("chunk-size", out strChunkSize)) { long pSize = Utility.Sizeparser.ParseSize(strChunkSize, "MB"); if (pSize >= (1 << 14) && pSize <= (1 << 30)) // [16kb .. 1GB] { this.m_fileChunkSize = (int)pSize; } } } catch { } var u = new Utility.Uri(url); u.RequireHost(); // Create sanitized plain https-URI (note: still has double slashes for processing web) m_orgUrl = new Utility.Uri("https", u.Host, u.Path, null, null, null, u.Port); // Actual path to Web will be searched for on first use. Ctor should not throw. m_spWebUrl = null; m_serverRelPath = u.Path; if (!m_serverRelPath.StartsWith("/", StringComparison.Ordinal)) { m_serverRelPath = "/" + m_serverRelPath; } if (!m_serverRelPath.EndsWith("/", StringComparison.Ordinal)) { m_serverRelPath += "/"; } // remove marker for SP-Web m_serverRelPath = m_serverRelPath.Replace("//", "/"); // Authentication settings processing: // Default: try integrated auth (will normally not work for Office365, but maybe with on-prem SharePoint...). // Otherwise: Use settings from URL(precedence) or from command line options. bool useIntegratedAuthentication = Utility.Utility.ParseBoolOption(options, "integrated-authentication"); string useUsername = null; string usePassword = null; if (!useIntegratedAuthentication) { if (!string.IsNullOrEmpty(u.Username)) { useUsername = u.Username; if (!string.IsNullOrEmpty(u.Password)) { usePassword = u.Password; } else if (options.ContainsKey("auth-password")) { usePassword = options["auth-password"]; } } else { if (options.ContainsKey("auth-username")) { useUsername = options["auth-username"]; if (options.ContainsKey("auth-password")) { usePassword = options["auth-password"]; } } } } if (useIntegratedAuthentication || (useUsername == null || usePassword == null)) { // This might or might not work for on-premises SP. Maybe support if someone complains... m_userInfo = System.Net.CredentialCache.DefaultNetworkCredentials; } else { System.Security.SecureString securePwd = new System.Security.SecureString(); usePassword.ToList().ForEach(c => securePwd.AppendChar(c)); m_userInfo = new Microsoft.SharePoint.Client.SharePointOnlineCredentials(useUsername, securePwd); // Other options (also ADAL, see class remarks) might be supported on request. // Maybe go in deep then and also look at: // - Microsoft.SharePoint.Client.AppPrincipalCredential.CreateFromKeyGroup() // - ctx.AuthenticationMode = SP.ClientAuthenticationMode.FormsAuthentication; // - ctx.FormsAuthenticationLoginInfo = new SP.FormsAuthenticationLoginInfo(user, pwd); } }
/// <summary> /// Returns the next valid date, given the start and the interval /// </summary> /// <param name="basetime">The base time</param> /// <param name="firstdate">The first allowed date</param> /// <param name="repetition">The repetition interval</param> /// <param name="allowedDays">The days the backup is allowed to run</param> /// <returns>The next valid date, or throws an exception if no such date can be found</returns> public static DateTime GetNextValidTime(DateTime basetime, DateTime firstdate, string repetition, DayOfWeek[] allowedDays) { var res = basetime; var i = 50000; while (res < firstdate && i-- > 0) { res = Timeparser.ParseTimeInterval(repetition, res); } // If we arived somewhere after the first allowed date if (res >= firstdate) { var ts = Timeparser.ParseTimeSpan(repetition); if (ts.TotalDays >= 1) { // We jump in days, so we pick the first valid day after firstdate for (var n = 0; n < 8; n++) { if (IsDateAllowed(res, allowedDays)) { break; } else { res = res.AddDays(1); } } } else { // We jump less than a day, so we keep adding the repetition until // we hit a valid day i = 50000; while (!IsDateAllowed(res, allowedDays) && i-- > 0) { res = Timeparser.ParseTimeInterval(repetition, res); } } } if (!IsDateAllowed(res, allowedDays) || res < firstdate) { StringBuilder sb = new StringBuilder(); if (allowedDays != null) { foreach (DayOfWeek w in allowedDays) { if (sb.Length != 0) { sb.Append(", "); } sb.Append(w.ToString()); } } throw new Exception(Strings.Scheduler.InvalidTimeSetupError(basetime, repetition, sb.ToString())); } return(res); }
private void BuildRecent() { Log[] logs; lock (Program.MainLock) logs = Program.DataConnection.GetObjects <Log>("EndTime > ? AND SubAction LIKE ? ORDER BY EndTime DESC", Timeparser.ParseTimeInterval(new Datamodel.ApplicationSettings(Program.DataConnection).RecentBackupDuration, DateTime.Now, true), "Primary"); try { recentBackups.BeginUpdate(); recentBackups.Items.Clear(); foreach (Log l in logs) { ListViewItem lvi = new ListViewItem(new string[] { l.EndTime.ToString("g"), l.OwnerTask == null || l.OwnerTask.Schedule == null ? "" : l.OwnerTask.Schedule.Name, l.Transfersize > 0 ? l.TransferSizeString : "" }); lvi.Tag = l; lvi.ImageIndex = imageList.Images.ContainsKey(l.ParsedStatus) ? imageList.Images.IndexOfKey(l.ParsedStatus) : imageList.Images.IndexOfKey("Warning"); recentBackups.Items.Add(lvi); if (!string.IsNullOrEmpty(l.ParsedMessage)) { lvi.ToolTipText = l.ParsedMessage; } else { switch (l.ParsedStatus) { case DuplicatiOutputParser.OKStatus: lvi.ToolTipText = Strings.ServiceStatus.BackupStatusOK; break; case DuplicatiOutputParser.ErrorStatus: lvi.ToolTipText = Strings.ServiceStatus.BackupStatusError; break; case DuplicatiOutputParser.WarningStatus: lvi.ToolTipText = Strings.ServiceStatus.BackupStatusWarning; break; case DuplicatiOutputParser.PartialStatus: lvi.ToolTipText = Strings.ServiceStatus.BackupStatusPartial; break; } } } } finally { recentBackups.EndUpdate(); } }
/// <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); } }
void SelectWhen_PageLeave(object sender, PageChangedArgs args) { if (args.Direction == PageChangedDirection.Back) { return; } if (!m_wrapper.SelectWhenUI.HasWarnedNoSchedule && NoScheduleRadio.Checked) { if (MessageBox.Show(this, Strings.SelectWhen.NoScheduleWarning, Application.ProductName, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button3) != DialogResult.Yes) { args.Cancel = true; return; } m_wrapper.SelectWhenUI.HasWarnedNoSchedule = true; } if (!m_wrapper.SelectWhenUI.HasWarnedNoIncrementals && !IncrementalPeriodRadio.Checked) { string s = NeverFullRadio.Checked ? Strings.SelectWhen.OnlyIncrementalBackupsWarning : Strings.SelectWhen.OnlyFullBackupsWarning; if (MessageBox.Show(this, s, Application.ProductName, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button3) != DialogResult.Yes) { args.Cancel = true; return; } m_wrapper.SelectWhenUI.HasWarnedNoIncrementals = true; } DateTime scheduledTime = OffsetDate.Value.Date.Add(OffsetTime.Value.TimeOfDay); TimeSpan scheduleInterval = new TimeSpan(0); if (ScheduleRadio.Checked) { try { scheduleInterval = Timeparser.ParseTimeSpan(RepeatInterval.Value); if (scheduleInterval.TotalMinutes < 5) { MessageBox.Show(this, string.Format(Strings.SelectWhen.TooShortScheduleDurationError, 5), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error); args.Cancel = true; return; } } catch (Exception ex) { MessageBox.Show(this, string.Format(Duplicati.GUI.Strings.Common.InvalidDuration, ex.Message), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error); args.Cancel = true; return; } } TimeSpan fullDuration = new TimeSpan(0); if (IncrementalPeriodRadio.Checked) { try { fullDuration = Timeparser.ParseTimeSpan(FullDuration.Value); if (fullDuration.TotalMinutes < 10) { MessageBox.Show(this, string.Format(Strings.SelectWhen.TooShortFullDurationError, 10), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error); args.Cancel = true; return; } } catch (Exception ex) { MessageBox.Show(this, string.Format(Duplicati.GUI.Strings.Common.InvalidDuration, ex.Message), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error); args.Cancel = true; return; } } if (ScheduleRadio.Checked && IncrementalPeriodRadio.Checked) { if (fullDuration < scheduleInterval) { MessageBox.Show(this, Strings.SelectWhen.FullDurationShorterThanScheduleDurationError, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error); args.Cancel = true; return; } if (!m_wrapper.SelectWhenUI.HasWarnedTooManyIncremental && fullDuration.Ticks / scheduleInterval.Ticks > 100) { if (MessageBox.Show(this, string.Format(Strings.SelectWhen.TooManyIncrementalsWarning, fullDuration.Ticks / scheduleInterval.Ticks), Application.ProductName, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Warning) != DialogResult.Yes) { args.Cancel = true; return; } m_wrapper.SelectWhenUI.HasWarnedTooManyIncremental = true; } } m_wrapper.BackupTimeOffset = scheduledTime; if (ScheduleRadio.Checked) { m_wrapper.RepeatInterval = RepeatInterval.Value; List <DayOfWeek> w = new List <DayOfWeek>(); CheckBox[] chks = new CheckBox[] { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday }; for (int i = 0; i < chks.Length; i++) { if (chks[i].Checked) { w.Add((DayOfWeek)i); } } m_wrapper.AllowedWeekdays = w.ToArray(); try { Scheduler.GetNextValidTime(m_wrapper.BackupTimeOffset, m_wrapper.RepeatInterval, m_wrapper.AllowedWeekdays); } catch (Exception ex) { MessageBox.Show(this, string.Format(Duplicati.GUI.Strings.Common.InvalidDuration, ex.Message), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error); args.Cancel = true; return; } } else { m_wrapper.RepeatInterval = ""; m_wrapper.AllowedWeekdays = null; } if (IncrementalPeriodRadio.Checked) { m_wrapper.FullBackupInterval = FullDuration.Value; } else if (NeverFullRadio.Checked) { m_wrapper.FullBackupInterval = ""; } else if (AlwaysFullRadio.Checked) { m_wrapper.FullBackupInterval = "1s"; //TODO: Is this a good way to specify this? } //Don't set args.NextPage, it runs on a list }