Added option to set the temp folder.
Added code to restore the setup from a backup. Removed the unused RDiffWrapper. Added events to the main interface. The beta for 1.0 is now completed, but the installer is missing. git-svn-id: https://duplicati.googlecode.com/svn/trunk@89 59da171f-624f-0410-aa54-27559c288bec
This commit is contained in:
+46
-4
@@ -47,6 +47,10 @@ namespace Duplicati.GUI
|
||||
this.BrowseGPGDialog = new System.Windows.Forms.OpenFileDialog();
|
||||
this.BrowseSFTPDialog = new System.Windows.Forms.OpenFileDialog();
|
||||
this.BrowseSCPDialog = new System.Windows.Forms.OpenFileDialog();
|
||||
this.TempPathBrowse = new System.Windows.Forms.Button();
|
||||
this.TempPath = new System.Windows.Forms.TextBox();
|
||||
this.label4 = new System.Windows.Forms.Label();
|
||||
this.BrowseTempPath = new System.Windows.Forms.FolderBrowserDialog();
|
||||
this.groupBox1.SuspendLayout();
|
||||
this.groupBox2.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
@@ -105,6 +109,9 @@ namespace Duplicati.GUI
|
||||
//
|
||||
this.groupBox2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.groupBox2.Controls.Add(this.TempPathBrowse);
|
||||
this.groupBox2.Controls.Add(this.TempPath);
|
||||
this.groupBox2.Controls.Add(this.label4);
|
||||
this.groupBox2.Controls.Add(this.BrowseSCP);
|
||||
this.groupBox2.Controls.Add(this.SCPPath);
|
||||
this.groupBox2.Controls.Add(this.label3);
|
||||
@@ -116,7 +123,7 @@ namespace Duplicati.GUI
|
||||
this.groupBox2.Controls.Add(this.label2);
|
||||
this.groupBox2.Location = new System.Drawing.Point(8, 72);
|
||||
this.groupBox2.Name = "groupBox2";
|
||||
this.groupBox2.Size = new System.Drawing.Size(437, 104);
|
||||
this.groupBox2.Size = new System.Drawing.Size(437, 128);
|
||||
this.groupBox2.TabIndex = 5;
|
||||
this.groupBox2.TabStop = false;
|
||||
this.groupBox2.Text = "Path settings (Advanced)";
|
||||
@@ -195,7 +202,7 @@ namespace Duplicati.GUI
|
||||
// OKBtn
|
||||
//
|
||||
this.OKBtn.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
|
||||
this.OKBtn.Location = new System.Drawing.Point(135, 186);
|
||||
this.OKBtn.Location = new System.Drawing.Point(135, 207);
|
||||
this.OKBtn.Name = "OKBtn";
|
||||
this.OKBtn.Size = new System.Drawing.Size(80, 24);
|
||||
this.OKBtn.TabIndex = 6;
|
||||
@@ -207,7 +214,7 @@ namespace Duplicati.GUI
|
||||
//
|
||||
this.CancelBtn.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
|
||||
this.CancelBtn.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
this.CancelBtn.Location = new System.Drawing.Point(231, 186);
|
||||
this.CancelBtn.Location = new System.Drawing.Point(231, 207);
|
||||
this.CancelBtn.Name = "CancelBtn";
|
||||
this.CancelBtn.Size = new System.Drawing.Size(72, 24);
|
||||
this.CancelBtn.TabIndex = 7;
|
||||
@@ -235,12 +242,42 @@ namespace Duplicati.GUI
|
||||
this.BrowseSCPDialog.Filter = "Executables (*.exe)|*.exe|All files (*.*)|*.*";
|
||||
this.BrowseSCPDialog.Title = "Select the SCP executable";
|
||||
//
|
||||
// TempPathBrowse
|
||||
//
|
||||
this.TempPathBrowse.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.TempPathBrowse.Location = new System.Drawing.Point(400, 96);
|
||||
this.TempPathBrowse.Name = "TempPathBrowse";
|
||||
this.TempPathBrowse.Size = new System.Drawing.Size(24, 20);
|
||||
this.TempPathBrowse.TabIndex = 22;
|
||||
this.TempPathBrowse.Text = "...";
|
||||
this.TempPathBrowse.UseVisualStyleBackColor = true;
|
||||
this.TempPathBrowse.Click += new System.EventHandler(this.TempPathBrowse_Click);
|
||||
//
|
||||
// TempPath
|
||||
//
|
||||
this.TempPath.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.TempPath.Location = new System.Drawing.Point(128, 96);
|
||||
this.TempPath.Name = "TempPath";
|
||||
this.TempPath.Size = new System.Drawing.Size(272, 20);
|
||||
this.TempPath.TabIndex = 21;
|
||||
this.TempPath.TextChanged += new System.EventHandler(this.TempPath_TextChanged);
|
||||
//
|
||||
// label4
|
||||
//
|
||||
this.label4.AutoSize = true;
|
||||
this.label4.Location = new System.Drawing.Point(8, 96);
|
||||
this.label4.Name = "label4";
|
||||
this.label4.Size = new System.Drawing.Size(86, 13);
|
||||
this.label4.TabIndex = 20;
|
||||
this.label4.Text = "Temporary folder";
|
||||
//
|
||||
// ApplicationSetup
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.CancelButton = this.CancelBtn;
|
||||
this.ClientSize = new System.Drawing.Size(453, 224);
|
||||
this.ClientSize = new System.Drawing.Size(453, 245);
|
||||
this.Controls.Add(this.CancelBtn);
|
||||
this.Controls.Add(this.OKBtn);
|
||||
this.Controls.Add(this.groupBox2);
|
||||
@@ -252,6 +289,7 @@ namespace Duplicati.GUI
|
||||
this.Name = "ApplicationSetup";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||
this.Text = "Duplicati setup";
|
||||
this.Load += new System.EventHandler(this.ApplicationSetup_Load);
|
||||
this.groupBox1.ResumeLayout(false);
|
||||
this.groupBox1.PerformLayout();
|
||||
this.groupBox2.ResumeLayout(false);
|
||||
@@ -280,5 +318,9 @@ namespace Duplicati.GUI
|
||||
private System.Windows.Forms.OpenFileDialog BrowseGPGDialog;
|
||||
private System.Windows.Forms.OpenFileDialog BrowseSFTPDialog;
|
||||
private System.Windows.Forms.OpenFileDialog BrowseSCPDialog;
|
||||
private System.Windows.Forms.Button TempPathBrowse;
|
||||
private System.Windows.Forms.TextBox TempPath;
|
||||
private System.Windows.Forms.Label label4;
|
||||
private System.Windows.Forms.FolderBrowserDialog BrowseTempPath;
|
||||
}
|
||||
}
|
||||
@@ -41,6 +41,15 @@ namespace Duplicati.GUI
|
||||
m_connection = new DataFetcherNested(Program.DataConnection);
|
||||
m_settings = new ApplicationSettings(m_connection);
|
||||
|
||||
RecentDuration.SetIntervals(new List<KeyValuePair<string, string>>(
|
||||
new KeyValuePair<string, string>[]
|
||||
{
|
||||
new KeyValuePair<string, string>("One week", "1W"),
|
||||
new KeyValuePair<string, string>("Two weeks", "2W"),
|
||||
new KeyValuePair<string, string>("One month", "1M"),
|
||||
new KeyValuePair<string, string>("Three months", "3M"),
|
||||
}));
|
||||
|
||||
try
|
||||
{
|
||||
m_isUpdating = true;
|
||||
@@ -48,6 +57,7 @@ namespace Duplicati.GUI
|
||||
GPGPath.Text = m_settings.GPGPath;
|
||||
SFTPPath.Text = m_settings.SFtpPath;
|
||||
SCPPath.Text = m_settings.ScpPath;
|
||||
TempPath.Text = m_settings.TempPath;
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -133,5 +143,23 @@ namespace Duplicati.GUI
|
||||
RecentDuration_TextChanged(sender, e);
|
||||
}
|
||||
|
||||
private void TempPathBrowse_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (BrowseTempPath.ShowDialog(this) == DialogResult.OK)
|
||||
TempPath.Text = BrowseTempPath.SelectedPath;
|
||||
}
|
||||
|
||||
private void TempPath_TextChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (m_isUpdating)
|
||||
return;
|
||||
m_settings.TempPath = TempPath.Text;
|
||||
}
|
||||
|
||||
private void ApplicationSetup_Load(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -126,6 +126,9 @@
|
||||
<metadata name="BrowseSCPDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>277, 17</value>
|
||||
</metadata>
|
||||
<metadata name="BrowseTempPath.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>415, 17</value>
|
||||
</metadata>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
|
||||
@@ -32,6 +32,7 @@ namespace Duplicati.Datamodel
|
||||
private const string PGP_PATH = "PGP path";
|
||||
private const string SFTP_PATH = "SFTP Path";
|
||||
private const string SCP_PATH = "SCP Path";
|
||||
private const string TEMP_PATH = "Temp Path";
|
||||
|
||||
//TODO: Deal with this on Linux
|
||||
public const string PROGRAM_FILES = "%PROGRAMFILES%";
|
||||
@@ -108,5 +109,25 @@ namespace Duplicati.Datamodel
|
||||
}
|
||||
set { m_appset[SCP_PATH] = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the path to store temporary files. May contain environment variables
|
||||
/// </summary>
|
||||
public string TempPath
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrEmpty(m_appset[TEMP_PATH]))
|
||||
{
|
||||
if (System.Environment.OSVersion.Platform == PlatformID.Unix || System.Environment.OSVersion.Platform == PlatformID.MacOSX)
|
||||
return "";
|
||||
else
|
||||
return "%temp%";
|
||||
}
|
||||
return m_appset[TEMP_PATH];
|
||||
}
|
||||
set { m_appset[TEMP_PATH] = value; }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,92 +17,92 @@
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
#endregion
|
||||
/// <metadata>
|
||||
/// <creator>This class was created by DataClassFileBuilder (LightDatamodel)</creator>
|
||||
/// <provider name="System.Data.LightDatamodel.SQLiteDataProvider" connectionstring="Version=3;Data Source=D:\Dokumenter\duplicati\Duplicati\GUI\Datamodel\Duplicati.sqlite;" />
|
||||
/// <type>Table</type>
|
||||
/// <namespace>Duplicati.Datamodel</namespace>
|
||||
/// <name>Schedule</name>
|
||||
/// <sql></sql>
|
||||
/// </metadata>
|
||||
|
||||
using System.Data.LightDatamodel;
|
||||
using System.Data.LightDatamodel.DataClassAttributes;
|
||||
|
||||
namespace Duplicati.Datamodel
|
||||
{
|
||||
|
||||
[DatabaseTable("Schedule")]
|
||||
public partial class Schedule : DataClassBase
|
||||
{
|
||||
|
||||
#region " private members "
|
||||
|
||||
[AutoIncrement, PrimaryKey, Relation("TaskSchedule", typeof(Task), "ScheduleID", false), DatabaseField("ID")]
|
||||
private System.Int64 m_ID = long.MinValue;
|
||||
[DatabaseField("Name")]
|
||||
private System.String m_Name = "";
|
||||
[DatabaseField("Path")]
|
||||
private System.String m_Path = "";
|
||||
[DatabaseField("When")]
|
||||
private System.DateTime m_When = new System.DateTime(1, 1, 1);
|
||||
[DatabaseField("Repeat")]
|
||||
private System.String m_Repeat = "";
|
||||
[DatabaseField("Weekdays")]
|
||||
private System.String m_Weekdays = "";
|
||||
#endregion
|
||||
|
||||
#region " properties "
|
||||
|
||||
public System.Int64 ID
|
||||
{
|
||||
get{return m_ID;}
|
||||
set{object oldvalue = m_ID;OnBeforeDataChange(this, "ID", oldvalue, value);m_ID = value;OnAfterDataChange(this, "ID", oldvalue, value);}
|
||||
}
|
||||
|
||||
public System.String Name
|
||||
{
|
||||
get{return m_Name;}
|
||||
set{object oldvalue = m_Name;OnBeforeDataChange(this, "Name", oldvalue, value);m_Name = value;OnAfterDataChange(this, "Name", oldvalue, value);}
|
||||
}
|
||||
|
||||
public System.String Path
|
||||
{
|
||||
get{return m_Path;}
|
||||
set{object oldvalue = m_Path;OnBeforeDataChange(this, "Path", oldvalue, value);m_Path = value;OnAfterDataChange(this, "Path", oldvalue, value);}
|
||||
}
|
||||
|
||||
public System.DateTime When
|
||||
{
|
||||
get{return m_When;}
|
||||
set{object oldvalue = m_When;OnBeforeDataChange(this, "When", oldvalue, value);m_When = value;OnAfterDataChange(this, "When", oldvalue, value);}
|
||||
}
|
||||
|
||||
public System.String Repeat
|
||||
{
|
||||
get{return m_Repeat;}
|
||||
set{object oldvalue = m_Repeat;OnBeforeDataChange(this, "Repeat", oldvalue, value);m_Repeat = value;OnAfterDataChange(this, "Repeat", oldvalue, value);}
|
||||
}
|
||||
|
||||
public System.String Weekdays
|
||||
{
|
||||
get{return m_Weekdays;}
|
||||
set{object oldvalue = m_Weekdays;OnBeforeDataChange(this, "Weekdays", oldvalue, value);m_Weekdays = value;OnAfterDataChange(this, "Weekdays", oldvalue, value);}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region " referenced properties "
|
||||
|
||||
[Affects(typeof(Task))]
|
||||
public Task Task
|
||||
{
|
||||
get{ return ((DataFetcherWithRelations)m_dataparent).GetRelatedObject<Task>("TaskSchedule", this); }
|
||||
set{ ((DataFetcherWithRelations)m_dataparent).SetRelatedObject("TaskSchedule", this, value); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
/// <metadata>
|
||||
/// <creator>This class was created by DataClassFileBuilder (LightDatamodel)</creator>
|
||||
/// <provider name="System.Data.LightDatamodel.SQLiteDataProvider" connectionstring="Version=3;Data Source=D:\Dokumenter\duplicati\Duplicati\GUI\Datamodel\Duplicati.sqlite;" />
|
||||
/// <type>Table</type>
|
||||
/// <namespace>Duplicati.Datamodel</namespace>
|
||||
/// <name>Schedule</name>
|
||||
/// <sql></sql>
|
||||
/// </metadata>
|
||||
|
||||
using System.Data.LightDatamodel;
|
||||
using System.Data.LightDatamodel.DataClassAttributes;
|
||||
|
||||
namespace Duplicati.Datamodel
|
||||
{
|
||||
|
||||
[DatabaseTable("Schedule")]
|
||||
public partial class Schedule : DataClassBase
|
||||
{
|
||||
|
||||
#region " private members "
|
||||
|
||||
[AutoIncrement, PrimaryKey, Relation("TaskSchedule", typeof(Task), "ScheduleID", false), DatabaseField("ID")]
|
||||
private System.Int64 m_ID = long.MinValue;
|
||||
[DatabaseField("Name")]
|
||||
private System.String m_Name = "";
|
||||
[DatabaseField("Path")]
|
||||
private System.String m_Path = "";
|
||||
[DatabaseField("When")]
|
||||
private System.DateTime m_When = new System.DateTime(1, 1, 1);
|
||||
[DatabaseField("Repeat")]
|
||||
private System.String m_Repeat = "";
|
||||
[DatabaseField("Weekdays")]
|
||||
private System.String m_Weekdays = "";
|
||||
#endregion
|
||||
|
||||
#region " properties "
|
||||
|
||||
public System.Int64 ID
|
||||
{
|
||||
get{return m_ID;}
|
||||
set{object oldvalue = m_ID;OnBeforeDataChange(this, "ID", oldvalue, value);m_ID = value;OnAfterDataChange(this, "ID", oldvalue, value);}
|
||||
}
|
||||
|
||||
public System.String Name
|
||||
{
|
||||
get{return m_Name;}
|
||||
set{object oldvalue = m_Name;OnBeforeDataChange(this, "Name", oldvalue, value);m_Name = value;OnAfterDataChange(this, "Name", oldvalue, value);}
|
||||
}
|
||||
|
||||
public System.String Path
|
||||
{
|
||||
get{return m_Path;}
|
||||
set{object oldvalue = m_Path;OnBeforeDataChange(this, "Path", oldvalue, value);m_Path = value;OnAfterDataChange(this, "Path", oldvalue, value);}
|
||||
}
|
||||
|
||||
public System.DateTime When
|
||||
{
|
||||
get{return m_When;}
|
||||
set{object oldvalue = m_When;OnBeforeDataChange(this, "When", oldvalue, value);m_When = value;OnAfterDataChange(this, "When", oldvalue, value);}
|
||||
}
|
||||
|
||||
public System.String Repeat
|
||||
{
|
||||
get{return m_Repeat;}
|
||||
set{object oldvalue = m_Repeat;OnBeforeDataChange(this, "Repeat", oldvalue, value);m_Repeat = value;OnAfterDataChange(this, "Repeat", oldvalue, value);}
|
||||
}
|
||||
|
||||
public System.String Weekdays
|
||||
{
|
||||
get{return m_Weekdays;}
|
||||
set{object oldvalue = m_Weekdays;OnBeforeDataChange(this, "Weekdays", oldvalue, value);m_Weekdays = value;OnAfterDataChange(this, "Weekdays", oldvalue, value);}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region " referenced properties "
|
||||
|
||||
[Affects(typeof(Task))]
|
||||
public Task Task
|
||||
{
|
||||
get{ return ((DataFetcherWithRelations)m_dataparent).GetRelatedObject<Task>("TaskSchedule", this); }
|
||||
set{ ((DataFetcherWithRelations)m_dataparent).SetRelatedObject("TaskSchedule", this, value); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -89,6 +89,16 @@ namespace Duplicati.Datamodel
|
||||
options["gpg-encryption"] = "";
|
||||
options["gpg-program-path"] = new ApplicationSettings(this.DataParent).GPGPath;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(this.Encryptionkey))
|
||||
options.Add("no-encryption", "");
|
||||
else
|
||||
options.Add("passphrase", this.Encryptionkey);
|
||||
|
||||
ApplicationSettings set = new ApplicationSettings(this.DataParent);
|
||||
if (!string.IsNullOrEmpty(set.TempPath))
|
||||
options["tempdir"] = System.Environment.ExpandEnvironmentVariables(set.TempPath);
|
||||
|
||||
}
|
||||
|
||||
public string EncodedFilter
|
||||
|
||||
@@ -85,6 +85,12 @@
|
||||
<Compile Include="HelperControls\FilterEditor.Designer.cs">
|
||||
<DependentUpon>FilterEditor.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="HelperControls\WaitForOperation.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="HelperControls\WaitForOperation.Designer.cs">
|
||||
<DependentUpon>WaitForOperation.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="LogViewer.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
@@ -386,6 +392,10 @@
|
||||
<SubType>Designer</SubType>
|
||||
<DependentUpon>FilterEditor.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="HelperControls\WaitForOperation.resx">
|
||||
<SubType>Designer</SubType>
|
||||
<DependentUpon>WaitForOperation.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="LogViewer.resx">
|
||||
<SubType>Designer</SubType>
|
||||
<DependentUpon>LogViewer.cs</DependentUpon>
|
||||
|
||||
@@ -33,11 +33,6 @@ namespace Duplicati.GUI
|
||||
public void ExecuteTask(IDuplicityTask task)
|
||||
{
|
||||
Dictionary<string, string> options = new Dictionary<string,string>();
|
||||
if (string.IsNullOrEmpty(task.Task.Encryptionkey))
|
||||
options.Add("no-encryption", "");
|
||||
else
|
||||
options.Add("passphrase", task.Task.Encryptionkey);
|
||||
|
||||
task.GetOptions(options);
|
||||
string results = "";
|
||||
|
||||
@@ -103,20 +98,24 @@ namespace Duplicati.GUI
|
||||
break;
|
||||
case DuplicityTaskType.ListFiles:
|
||||
(task as ListFilesTask).Files = Interface.ListContent(task.SourcePath, options);
|
||||
return;
|
||||
break;
|
||||
|
||||
case DuplicityTaskType.RemoveAllButNFull:
|
||||
results = Interface.RemoveAllButNFull(task.SourcePath, options);
|
||||
return;
|
||||
break;
|
||||
case DuplicityTaskType.RemoveOlderThan:
|
||||
results = Interface.RemoveOlderThan(task.SourcePath, options);
|
||||
return;
|
||||
break;
|
||||
case DuplicityTaskType.Restore:
|
||||
options["file-to-restore"] = ((RestoreTask)task).SourceFiles;
|
||||
if (options.ContainsKey("filter"))
|
||||
options.Remove("filter");
|
||||
results = Interface.Restore(task.SourcePath, task.TargetPath, options);
|
||||
return;
|
||||
break;
|
||||
|
||||
case DuplicityTaskType.RestoreSetup:
|
||||
Interface.RestoreControlFiles(task.SourcePath, task.TargetPath, options);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -46,8 +46,8 @@ namespace Duplicati.GUI.HelperControls
|
||||
{
|
||||
EasyDuration.Items.Clear();
|
||||
|
||||
if (values[values.Count - 1].Key != "")
|
||||
values.Add(new KeyValuePair<string, string>("", ""));
|
||||
if (values[values.Count - 1].Value != "")
|
||||
values.Add(new KeyValuePair<string, string>("Custom...", ""));
|
||||
|
||||
m_values = new string[values.Count];
|
||||
for (int i = 0; i < values.Count; i++)
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
namespace Duplicati.GUI.HelperControls
|
||||
{
|
||||
partial class WaitForOperation
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.progressBar1 = new System.Windows.Forms.ProgressBar();
|
||||
this.backgroundWorker1 = new System.ComponentModel.BackgroundWorker();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// progressBar1
|
||||
//
|
||||
this.progressBar1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.progressBar1.Location = new System.Drawing.Point(16, 8);
|
||||
this.progressBar1.Name = "progressBar1";
|
||||
this.progressBar1.Size = new System.Drawing.Size(274, 23);
|
||||
this.progressBar1.Style = System.Windows.Forms.ProgressBarStyle.Marquee;
|
||||
this.progressBar1.TabIndex = 0;
|
||||
//
|
||||
// backgroundWorker1
|
||||
//
|
||||
this.backgroundWorker1.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker1_RunWorkerCompleted);
|
||||
//
|
||||
// WaitForOperation
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(307, 41);
|
||||
this.Controls.Add(this.progressBar1);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
|
||||
this.MaximizeBox = false;
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "WaitForOperation";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "WaitForOperation";
|
||||
this.Load += new System.EventHandler(this.WaitForOperation_Load);
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.ProgressBar progressBar1;
|
||||
private System.ComponentModel.BackgroundWorker backgroundWorker1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Duplicati.GUI.HelperControls
|
||||
{
|
||||
public partial class WaitForOperation : Form
|
||||
{
|
||||
private Exception m_exception;
|
||||
|
||||
public WaitForOperation()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public void Setup(DoWorkEventHandler callback, string title)
|
||||
{
|
||||
backgroundWorker1.DoWork += callback;
|
||||
this.Text = title;
|
||||
}
|
||||
|
||||
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
|
||||
{
|
||||
m_exception = e.Error;
|
||||
if (e.Cancelled || e.Error != null)
|
||||
this.DialogResult = DialogResult.Cancel;
|
||||
else
|
||||
this.DialogResult = DialogResult.OK;
|
||||
|
||||
this.Close();
|
||||
}
|
||||
|
||||
private void WaitForOperation_Load(object sender, EventArgs e)
|
||||
{
|
||||
backgroundWorker1.RunWorkerAsync();
|
||||
}
|
||||
|
||||
public Exception Error { get { return m_exception; } }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="backgroundWorker1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
</root>
|
||||
@@ -33,6 +33,7 @@ namespace Duplicati.GUI
|
||||
Restore,
|
||||
ListBackups,
|
||||
ListFiles,
|
||||
RestoreSetup
|
||||
}
|
||||
|
||||
public delegate void TaskCompletedHandler(IDuplicityTask owner, string output);
|
||||
@@ -340,6 +341,46 @@ namespace Duplicati.GUI
|
||||
}
|
||||
}
|
||||
|
||||
public class RestoreSetupTask : BackupTask
|
||||
{
|
||||
protected string m_targetdir = null;
|
||||
|
||||
public RestoreSetupTask(Schedule schedule, string targetdir)
|
||||
: base(schedule)
|
||||
{
|
||||
m_targetdir = targetdir;
|
||||
}
|
||||
|
||||
public override string SourcePath
|
||||
{
|
||||
get { return System.Environment.ExpandEnvironmentVariables(this.Task.GetDestinationPath()); }
|
||||
}
|
||||
|
||||
public override string TargetPath
|
||||
{
|
||||
get { return System.Environment.ExpandEnvironmentVariables(this.TargetDir); }
|
||||
}
|
||||
|
||||
public string TargetDir { get { return m_targetdir; } }
|
||||
|
||||
public override void GetArguments(List<string> args)
|
||||
{
|
||||
throw new Exception("The method or operation is not implemented.");
|
||||
}
|
||||
|
||||
public override void GetOptions(Dictionary<string, string> options)
|
||||
{
|
||||
base.GetOptions(options);
|
||||
if (options.ContainsKey("filter"))
|
||||
options.Remove("filter");
|
||||
}
|
||||
|
||||
public override DuplicityTaskType TaskType
|
||||
{
|
||||
get { return DuplicityTaskType.RestoreSetup; }
|
||||
}
|
||||
}
|
||||
|
||||
public class RestoreTask : BackupTask
|
||||
{
|
||||
protected DateTime m_when;
|
||||
|
||||
@@ -108,5 +108,27 @@ namespace Duplicati.GUI.Wizard_pages.Add_backup
|
||||
|
||||
args.TreatAsLast = true;
|
||||
}
|
||||
|
||||
public override string HelpText
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_wrapper.PrimayAction == WizardSettingsWrapper.MainAction.Add)
|
||||
return base.HelpText;
|
||||
else
|
||||
return "The backup modifications are now ready to be saved.";
|
||||
}
|
||||
}
|
||||
|
||||
public override string Title
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_wrapper.PrimayAction == WizardSettingsWrapper.MainAction.Add)
|
||||
return base.Title;
|
||||
else
|
||||
return "Ready to save modifications";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ namespace Duplicati.GUI.Wizard_pages.Add_backup
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_warnedNoPassword && !EnablePassword.Checked)
|
||||
if (!m_warnedNoPassword && !EnablePassword.Checked && m_wrapper.PrimayAction != WizardSettingsWrapper.MainAction.RestoreSetup)
|
||||
{
|
||||
if (MessageBox.Show(this, "If the backup is stored on machine or device that is not under your direct control,\nit is possible that others may view the files you have stored in the backups.\nIt is highly recomended that you enable encryption.\nDo you want to continue without encryption?", Application.ProductName, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Warning) != DialogResult.Yes)
|
||||
{
|
||||
@@ -118,7 +118,7 @@ namespace Duplicati.GUI.Wizard_pages.Add_backup
|
||||
|
||||
if (!m_valuesAutoLoaded)
|
||||
{
|
||||
EnablePassword.Checked = !string.IsNullOrEmpty(m_wrapper.BackupPassword) || m_wrapper.PrimayAction == WizardSettingsWrapper.MainAction.Add;
|
||||
EnablePassword.Checked = !string.IsNullOrEmpty(m_wrapper.BackupPassword) || (m_wrapper.PrimayAction == WizardSettingsWrapper.MainAction.Add || m_wrapper.PrimayAction == WizardSettingsWrapper.MainAction.RestoreSetup);
|
||||
Password.Text = m_wrapper.BackupPassword;
|
||||
UseGPG.Checked = m_wrapper.GPGEncryption;
|
||||
m_settingsChanged = false;
|
||||
@@ -132,6 +132,14 @@ namespace Duplicati.GUI.Wizard_pages.Add_backup
|
||||
m_warnedChanged = (bool)m_settings["Password:WarnedChanged"];
|
||||
if (m_settings.ContainsKey("Password:SettingsChanged"))
|
||||
m_settingsChanged = (bool)m_settings["Password:SettingsChanged"];
|
||||
|
||||
if (m_wrapper.PrimayAction == WizardSettingsWrapper.MainAction.RestoreSetup)
|
||||
{
|
||||
PasswordHelptext.Visible =
|
||||
PasswordGeneratorSettings.Visible = false;
|
||||
|
||||
EnablePassword.Text = "Backup is protected with password";
|
||||
}
|
||||
}
|
||||
|
||||
private void GeneratePassword_Click(object sender, EventArgs e)
|
||||
@@ -158,5 +166,16 @@ namespace Duplicati.GUI.Wizard_pages.Add_backup
|
||||
m_warnedNoGPG = false;
|
||||
}
|
||||
|
||||
public override string HelpText
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_wrapper.PrimayAction != WizardSettingsWrapper.MainAction.RestoreSetup)
|
||||
return base.HelpText;
|
||||
else
|
||||
return "Enter the encryption settings that were used to create the backup originally";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ namespace Duplicati.GUI.Wizard_pages
|
||||
}
|
||||
else
|
||||
{
|
||||
args.NextPage = new SelectBackend();
|
||||
args.NextPage = new Add_backup.PasswordSettings();
|
||||
wrapper.PrimayAction = WizardSettingsWrapper.MainAction.RestoreSetup;
|
||||
}
|
||||
|
||||
|
||||
+14
-1
@@ -30,6 +30,7 @@ namespace Duplicati.GUI.Wizard_pages.Restore
|
||||
{
|
||||
this.Summary = new System.Windows.Forms.TextBox();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.RunInBackground = new System.Windows.Forms.CheckBox();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// Summary
|
||||
@@ -40,7 +41,7 @@ namespace Duplicati.GUI.Wizard_pages.Restore
|
||||
this.Summary.Name = "Summary";
|
||||
this.Summary.ReadOnly = true;
|
||||
this.Summary.ScrollBars = System.Windows.Forms.ScrollBars.Both;
|
||||
this.Summary.Size = new System.Drawing.Size(456, 152);
|
||||
this.Summary.Size = new System.Drawing.Size(456, 144);
|
||||
this.Summary.TabIndex = 3;
|
||||
//
|
||||
// label1
|
||||
@@ -52,10 +53,21 @@ namespace Duplicati.GUI.Wizard_pages.Restore
|
||||
this.label1.TabIndex = 2;
|
||||
this.label1.Text = "Summary";
|
||||
//
|
||||
// RunInBackground
|
||||
//
|
||||
this.RunInBackground.AutoSize = true;
|
||||
this.RunInBackground.Location = new System.Drawing.Point(24, 200);
|
||||
this.RunInBackground.Name = "RunInBackground";
|
||||
this.RunInBackground.Size = new System.Drawing.Size(228, 17);
|
||||
this.RunInBackground.TabIndex = 4;
|
||||
this.RunInBackground.Text = "Run restore operation as a background job";
|
||||
this.RunInBackground.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// FinishedRestore
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.Controls.Add(this.RunInBackground);
|
||||
this.Controls.Add(this.Summary);
|
||||
this.Controls.Add(this.label1);
|
||||
this.Name = "FinishedRestore";
|
||||
@@ -69,5 +81,6 @@ namespace Duplicati.GUI.Wizard_pages.Restore
|
||||
|
||||
public System.Windows.Forms.TextBox Summary;
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.CheckBox RunInBackground;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ namespace Duplicati.GUI.Wizard_pages.Restore
|
||||
public partial class FinishedRestore : WizardControl
|
||||
{
|
||||
private WizardSettingsWrapper m_wrapper;
|
||||
private HelperControls.WaitForOperation m_waitdlg;
|
||||
|
||||
public FinishedRestore()
|
||||
: base("Ready to restore files", "Duplicati is now ready to restore your files.")
|
||||
@@ -39,6 +40,24 @@ namespace Duplicati.GUI.Wizard_pages.Restore
|
||||
InitializeComponent();
|
||||
|
||||
base.PageEnter += new PageChangeHandler(FinishedRestore_PageEnter);
|
||||
base.PageLeave += new PageChangeHandler(FinishedRestore_PageLeave);
|
||||
}
|
||||
|
||||
void FinishedRestore_PageLeave(object sender, PageChangedArgs args)
|
||||
{
|
||||
if (args.Direction == PageChangedDirection.Back)
|
||||
return;
|
||||
|
||||
if (!RunInBackground.Checked)
|
||||
{
|
||||
m_waitdlg = new Duplicati.GUI.HelperControls.WaitForOperation();
|
||||
m_waitdlg.Setup(new DoWorkEventHandler(Restore), "Restoring files, please wait...");
|
||||
m_waitdlg.ShowDialog();
|
||||
m_owner.CancelButton.PerformClick();
|
||||
m_waitdlg = null;
|
||||
args.Cancel = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void FinishedRestore_PageEnter(object sender, PageChangedArgs args)
|
||||
@@ -54,5 +73,30 @@ namespace Duplicati.GUI.Wizard_pages.Restore
|
||||
args.TreatAsLast = true;
|
||||
}
|
||||
|
||||
private void Restore(object sender, DoWorkEventArgs args)
|
||||
{
|
||||
Schedule s = Program.DataConnection.GetObjectById<Schedule>(m_wrapper.ScheduleID);
|
||||
|
||||
RestoreTask task = new RestoreTask(s, m_wrapper.RestorePath, m_wrapper.RestoreFilter, m_wrapper.RestoreTime);
|
||||
Dictionary<string, string> options = new Dictionary<string, string>();
|
||||
task.GetOptions(options);
|
||||
if (options.ContainsKey("filter"))
|
||||
options.Remove("filter");
|
||||
using (Library.Main.Interface i = new Duplicati.Library.Main.Interface(task.SourcePath, options))
|
||||
{
|
||||
i.OperationProgress += new Duplicati.Library.Main.OperationProgressEvent(i_OperationProgress);
|
||||
i.Restore(task.TargetPath);
|
||||
}
|
||||
}
|
||||
|
||||
void i_OperationProgress(Duplicati.Library.Main.Interface caller, Duplicati.Library.Main.DuplicatiOperation operation, int progress, string message)
|
||||
{
|
||||
if (m_waitdlg.InvokeRequired)
|
||||
m_waitdlg.Invoke(new Duplicati.Library.Main.OperationProgressEvent(i_OperationProgress), caller, operation, progress, message);
|
||||
else
|
||||
m_waitdlg.Text = message;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,16 @@ namespace Duplicati.GUI.Wizard_pages.RestoreSetup
|
||||
if (args.Direction == PageChangedDirection.Back)
|
||||
return;
|
||||
|
||||
//TODO: Perform the restore
|
||||
HelperControls.WaitForOperation dlg = new Duplicati.GUI.HelperControls.WaitForOperation();
|
||||
dlg.Setup(new DoWorkEventHandler(Restore), "Restoring setup, please wait...");
|
||||
if (dlg.ShowDialog() != DialogResult.OK)
|
||||
{
|
||||
if (dlg.Error != null)
|
||||
MessageBox.Show(this, "Failed to restore setup files, the error message was:\n" + dlg.Error.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
|
||||
args.Cancel = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void FinishedRestoreSetup_PageEnter(object sender, PageChangedArgs args)
|
||||
@@ -96,5 +105,30 @@ namespace Duplicati.GUI.Wizard_pages.RestoreSetup
|
||||
|
||||
args.TreatAsLast = true;
|
||||
}
|
||||
|
||||
private void Restore(object sender, DoWorkEventArgs args)
|
||||
{
|
||||
System.Data.LightDatamodel.DataFetcherNested con = new System.Data.LightDatamodel.DataFetcherNested(Program.DataConnection);
|
||||
Schedule s = con.Add<Schedule>();
|
||||
s.Task = con.Add<Task>();
|
||||
m_wrapper.UpdateSchedule(s);
|
||||
|
||||
using (Library.Core.TempFolder tf = new Duplicati.Library.Core.TempFolder())
|
||||
{
|
||||
RestoreSetupTask task = new RestoreSetupTask(s, tf);
|
||||
Dictionary<string, string> options = new Dictionary<string, string>();
|
||||
task.GetOptions(options);
|
||||
Library.Main.Interface.RestoreControlFiles(task.SourcePath, task.TargetPath, options);
|
||||
|
||||
string filename = System.IO.Path.Combine(tf, System.IO.Path.GetFileName(Program.DatabasePath));
|
||||
if (System.IO.File.Exists(filename))
|
||||
System.IO.File.Copy(filename, Program.DatabasePath, true);
|
||||
else
|
||||
throw new Exception("Unable to restore setup file from backup");
|
||||
|
||||
Program.DataConnection.ClearCache();
|
||||
Program.Scheduler.Reschedule();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+10
-10
@@ -33,7 +33,7 @@ namespace Duplicati.GUI.Wizard_pages
|
||||
this.SSH = new System.Windows.Forms.RadioButton();
|
||||
this.WebDAV = new System.Windows.Forms.RadioButton();
|
||||
this.S3 = new System.Windows.Forms.RadioButton();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.Question = new System.Windows.Forms.Label();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// File
|
||||
@@ -96,20 +96,20 @@ namespace Duplicati.GUI.Wizard_pages
|
||||
this.S3.UseVisualStyleBackColor = true;
|
||||
this.S3.CheckedChanged += new System.EventHandler(this.Item_CheckChanged);
|
||||
//
|
||||
// label1
|
||||
// Question
|
||||
//
|
||||
this.label1.AutoSize = true;
|
||||
this.label1.Location = new System.Drawing.Point(40, 16);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(206, 13);
|
||||
this.label1.TabIndex = 5;
|
||||
this.label1.Text = "Where do you want to store the backups?";
|
||||
this.Question.AutoSize = true;
|
||||
this.Question.Location = new System.Drawing.Point(40, 16);
|
||||
this.Question.Name = "Question";
|
||||
this.Question.Size = new System.Drawing.Size(206, 13);
|
||||
this.Question.TabIndex = 5;
|
||||
this.Question.Text = "Where do you want to store the backups?";
|
||||
//
|
||||
// SelectBackend
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.Controls.Add(this.label1);
|
||||
this.Controls.Add(this.Question);
|
||||
this.Controls.Add(this.S3);
|
||||
this.Controls.Add(this.WebDAV);
|
||||
this.Controls.Add(this.SSH);
|
||||
@@ -129,6 +129,6 @@ namespace Duplicati.GUI.Wizard_pages
|
||||
private System.Windows.Forms.RadioButton SSH;
|
||||
private System.Windows.Forms.RadioButton WebDAV;
|
||||
private System.Windows.Forms.RadioButton S3;
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.Label Question;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,6 +130,9 @@ namespace Duplicati.GUI.Wizard_pages
|
||||
Item_CheckChanged(null, null);
|
||||
|
||||
|
||||
if (m_wrapper.PrimayAction == WizardSettingsWrapper.MainAction.RestoreSetup)
|
||||
Question.Text = "Where is the backup stored?";
|
||||
|
||||
}
|
||||
|
||||
private void Item_CheckChanged(object sender, EventArgs e)
|
||||
|
||||
@@ -84,7 +84,6 @@ namespace Duplicati.GUI
|
||||
Schedule schedule = Program.DataConnection.GetObjectById<Schedule>(wrapper.ScheduleID);
|
||||
DateTime when = wrapper.RestoreTime;
|
||||
string target = wrapper.RestorePath;
|
||||
//TODO: Use this
|
||||
string restoreFilter = wrapper.RestoreFilter;
|
||||
|
||||
if (when.Ticks == 0)
|
||||
@@ -114,6 +113,10 @@ namespace Duplicati.GUI
|
||||
Program.DataConnection.DeleteObject(o);
|
||||
Program.DataConnection.Commit(items.ToArray());
|
||||
}
|
||||
else if (m_form.CurrentPage is Wizard_pages.RestoreSetup.FinishedRestoreSetup)
|
||||
{
|
||||
MessageBox.Show(m_form as Form, "The previous Duplicati setup is now restored!", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Visible { get { return m_form.Dialog.Visible; } }
|
||||
|
||||
@@ -23,7 +23,7 @@ using System.Text;
|
||||
|
||||
namespace Duplicati.Library.Main
|
||||
{
|
||||
public class BackupStatistics : CommunicationStatistics
|
||||
internal class BackupStatistics : CommunicationStatistics
|
||||
{
|
||||
private DateTime m_beginTime;
|
||||
private DateTime m_endTime;
|
||||
|
||||
@@ -40,8 +40,8 @@
|
||||
<Compile Include="CommunicationStatistics.cs" />
|
||||
<Compile Include="FilenameStrategy.cs" />
|
||||
<Compile Include="Interface.cs" />
|
||||
<Compile Include="ProgressEvents.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="RDiffWrapper.cs" />
|
||||
<Compile Include="RestoreStatistics.cs" />
|
||||
<Compile Include="RSyncDir.cs" />
|
||||
<Compile Include="BackupStatistics.cs" />
|
||||
|
||||
+235
-128
@@ -23,46 +23,73 @@ using System.Text;
|
||||
|
||||
namespace Duplicati.Library.Main
|
||||
{
|
||||
public static class Interface
|
||||
public enum DuplicatiOperation
|
||||
{
|
||||
public static string Backup(string source, string target, Dictionary<string, string> options)
|
||||
Backup,
|
||||
Restore,
|
||||
List,
|
||||
Remove
|
||||
};
|
||||
|
||||
public delegate void OperationProgressEvent(Interface caller, DuplicatiOperation operation, int progress, string message);
|
||||
|
||||
public class Interface : IDisposable
|
||||
{
|
||||
private string m_backend;
|
||||
private Dictionary<string, string> m_options;
|
||||
|
||||
public event OperationProgressEvent OperationStarted;
|
||||
public event OperationProgressEvent OperationCompleted;
|
||||
public event OperationProgressEvent OperationProgress;
|
||||
public event OperationProgressEvent OperationError;
|
||||
|
||||
public Interface(string backend, Dictionary<string, string> options)
|
||||
{
|
||||
m_backend = backend;
|
||||
m_options = options;
|
||||
}
|
||||
|
||||
public string Backup(string source)
|
||||
{
|
||||
BackupStatistics bs = new BackupStatistics();
|
||||
|
||||
SetupCommonOptions(options);
|
||||
SetupCommonOptions(m_options);
|
||||
Backend.IBackend backend = null;
|
||||
|
||||
using (new Logging.Timer("Backup from " + source + " to " + target))
|
||||
using (new Logging.Timer("Backup from " + source + " to " + m_backend))
|
||||
{
|
||||
try
|
||||
{
|
||||
FilenameStrategy fns = new FilenameStrategy(options);
|
||||
Core.FilenameFilter filter = new Duplicati.Library.Core.FilenameFilter(options);
|
||||
bool full = options.ContainsKey("full");
|
||||
if (OperationStarted != null)
|
||||
OperationStarted(this, DuplicatiOperation.Backup, 0, "Started");
|
||||
|
||||
int volumesize = (int)Core.Sizeparser.ParseSize(options.ContainsKey("volsize") ? options["volsize"] : "5", "mb");
|
||||
FilenameStrategy fns = new FilenameStrategy(m_options);
|
||||
Core.FilenameFilter filter = new Duplicati.Library.Core.FilenameFilter(m_options);
|
||||
bool full = m_options.ContainsKey("full");
|
||||
|
||||
int volumesize = (int)Core.Sizeparser.ParseSize(m_options.ContainsKey("volsize") ? m_options["volsize"] : "5", "mb");
|
||||
volumesize = Math.Max(1024 * 1024, volumesize);
|
||||
|
||||
long totalmax = options.ContainsKey("totalsize") ? Core.Sizeparser.ParseSize(options["totalsize"], "mb") : long.MaxValue;
|
||||
long totalmax = m_options.ContainsKey("totalsize") ? Core.Sizeparser.ParseSize(m_options["totalsize"], "mb") : long.MaxValue;
|
||||
totalmax = Math.Max(volumesize, totalmax);
|
||||
|
||||
backend = Backend.BackendLoader.GetBackend(target, options);
|
||||
backend = Backend.BackendLoader.GetBackend(m_backend, m_options);
|
||||
if (backend == null)
|
||||
throw new Exception("Unable to find backend for target: " + target);
|
||||
backend = new BackendWrapper(bs, backend, options);
|
||||
backend = Encryption.EncryptedBackendWrapper.WrapWithEncryption(backend, options);
|
||||
throw new Exception("Unable to find backend for m_backend: " + m_backend);
|
||||
backend = new BackendWrapper(bs, backend, m_options);
|
||||
backend = Encryption.EncryptedBackendWrapper.WrapWithEncryption(backend, m_options);
|
||||
|
||||
List<BackupEntry> prev = ParseFileList(backend, options);
|
||||
List<BackupEntry> prev = ParseFileList(backend);
|
||||
|
||||
if (prev.Count == 0)
|
||||
full = true;
|
||||
|
||||
if (!full && options.ContainsKey("full-if-older-than"))
|
||||
full = DateTime.Now > Core.Timeparser.ParseTimeInterval(options["full-if-older-than"], prev[prev.Count - 1].Time);
|
||||
if (!full && m_options.ContainsKey("full-if-older-than"))
|
||||
full = DateTime.Now > Core.Timeparser.ParseTimeInterval(m_options["full-if-older-than"], prev[prev.Count - 1].Time);
|
||||
|
||||
List<string> controlfiles = new List<string>();
|
||||
if (options.ContainsKey("signature-control-files"))
|
||||
controlfiles.AddRange(options["signature-control-files"].Split(System.IO.Path.PathSeparator));
|
||||
if (m_options.ContainsKey("signature-control-files"))
|
||||
controlfiles.AddRange(m_options["signature-control-files"].Split(System.IO.Path.PathSeparator));
|
||||
|
||||
using (Core.TempFolder tempfolder = new Duplicati.Library.Core.TempFolder())
|
||||
{
|
||||
@@ -71,6 +98,9 @@ namespace Duplicati.Library.Main
|
||||
{
|
||||
using (new Logging.Timer("Reading incremental data"))
|
||||
{
|
||||
if (OperationProgress != null)
|
||||
OperationProgress(this, DuplicatiOperation.Backup, 0, "Reading incremental data");
|
||||
|
||||
List<BackupEntry> entries = new List<BackupEntry>();
|
||||
entries.Add(prev[prev.Count - 1]);
|
||||
entries.AddRange(prev[prev.Count - 1].Incrementals);
|
||||
@@ -78,6 +108,9 @@ namespace Duplicati.Library.Main
|
||||
foreach (BackupEntry be in entries)
|
||||
foreach (BackupEntry bes in be.SignatureFile)
|
||||
{
|
||||
if (OperationProgress != null)
|
||||
OperationProgress(this, DuplicatiOperation.Backup, 0, "Reading incremental file: " + bes.Filename);
|
||||
|
||||
string filename = System.IO.Path.Combine(tempfolder, "patch-" + patches.Count.ToString() + ".zip");
|
||||
using (new Logging.Timer("Get " + bes.Filename))
|
||||
backend.Get(bes.Filename, filename);
|
||||
@@ -103,6 +136,9 @@ namespace Duplicati.Library.Main
|
||||
{
|
||||
using (new Logging.Timer("Multipass " + (vol + 1).ToString()))
|
||||
{
|
||||
if (OperationProgress != null)
|
||||
OperationProgress(this, DuplicatiOperation.Backup, 0, "Creating volume " + (vol + 1).ToString());
|
||||
|
||||
//The backendwrapper will remove these
|
||||
Core.TempFile signaturefile = new Duplicati.Library.Core.TempFile();
|
||||
Core.TempFile contentfile = new Duplicati.Library.Core.TempFile();
|
||||
@@ -116,7 +152,7 @@ namespace Duplicati.Library.Main
|
||||
//Add signature files to archive
|
||||
foreach (string s in controlfiles)
|
||||
if (!string.IsNullOrEmpty(s))
|
||||
using (System.IO.Stream cs = signaturearchive.CreateFile(System.IO.Path.GetFileName(s)))
|
||||
using (System.IO.Stream cs = signaturearchive.CreateFile(System.IO.Path.Combine(RSync.RSyncDir.CONTROL_ROOT, System.IO.Path.GetFileName(s))))
|
||||
using (System.IO.FileStream fs = System.IO.File.OpenRead(s))
|
||||
Core.Utility.CopyStream(fs, cs);
|
||||
|
||||
@@ -178,6 +214,9 @@ namespace Duplicati.Library.Main
|
||||
{
|
||||
if (backend != null)
|
||||
backend.Dispose();
|
||||
|
||||
if (OperationCompleted != null)
|
||||
OperationCompleted(this, DuplicatiOperation.Backup, 100, "Completed");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,23 +224,26 @@ namespace Duplicati.Library.Main
|
||||
return bs.ToString();
|
||||
}
|
||||
|
||||
public static string Restore(string source, string target, Dictionary<string, string> options)
|
||||
public string Restore(string target)
|
||||
{
|
||||
SetupCommonOptions(options);
|
||||
SetupCommonOptions(m_options);
|
||||
RestoreStatistics rs = new RestoreStatistics();
|
||||
|
||||
Backend.IBackend backend = null;
|
||||
|
||||
using (new Logging.Timer("Restore from " + source + " to " + target))
|
||||
using (new Logging.Timer("Restore from " + m_backend + " to " + target))
|
||||
{
|
||||
try
|
||||
{
|
||||
string specificfile = options.ContainsKey("file-to-restore") ? options["file-to-restore"] : "";
|
||||
string specifictime = options.ContainsKey("restore-time") ? options["restore-time"] : "now";
|
||||
Core.FilenameFilter filter = new Duplicati.Library.Core.FilenameFilter(options);
|
||||
if (OperationStarted != null)
|
||||
OperationStarted(this, DuplicatiOperation.Restore, 0, "Started");
|
||||
|
||||
string specificfile = m_options.ContainsKey("file-to-restore") ? m_options["file-to-restore"] : "";
|
||||
string specifictime = m_options.ContainsKey("restore-time") ? m_options["restore-time"] : "now";
|
||||
Core.FilenameFilter filter = new Duplicati.Library.Core.FilenameFilter(m_options);
|
||||
|
||||
//Filter is prefered, if both file and filter is specified
|
||||
if (!options.ContainsKey("filter") && !string.IsNullOrEmpty(specificfile))
|
||||
if (!m_options.ContainsKey("filter") && !string.IsNullOrEmpty(specificfile))
|
||||
{
|
||||
List<Core.IFilenameFilter> list = new List<Duplicati.Library.Core.IFilenameFilter>();
|
||||
list.Add(new Core.FilelistFilter(true, specificfile.Split(System.IO.Path.PathSeparator)));
|
||||
@@ -210,14 +252,14 @@ namespace Duplicati.Library.Main
|
||||
filter = new Duplicati.Library.Core.FilenameFilter(list);
|
||||
}
|
||||
|
||||
backend = Backend.BackendLoader.GetBackend(source, options);
|
||||
backend = Backend.BackendLoader.GetBackend(m_backend, m_options);
|
||||
if (backend == null)
|
||||
throw new Exception("Unable to find backend for target: " + source);
|
||||
backend = new BackendWrapper(rs, backend, options);
|
||||
throw new Exception("Unable to find backend for target: " + m_backend);
|
||||
backend = new BackendWrapper(rs, backend, m_options);
|
||||
|
||||
BackupEntry bestFit = FindBestMatch(ParseFileList(backend, options), specifictime);
|
||||
BackupEntry bestFit = FindBestMatch(ParseFileList(backend), specifictime);
|
||||
if (bestFit.EncryptionMode != null)
|
||||
backend = Encryption.EncryptedBackendWrapper.WrapWithEncryption(backend, bestFit.EncryptionMode, options);
|
||||
backend = Encryption.EncryptedBackendWrapper.WrapWithEncryption(backend, bestFit.EncryptionMode, m_options);
|
||||
|
||||
List<BackupEntry> entries = new List<BackupEntry>();
|
||||
entries.Add(bestFit);
|
||||
@@ -234,6 +276,10 @@ namespace Duplicati.Library.Main
|
||||
|
||||
using (Core.TempFile patchzip = new Duplicati.Library.Core.TempFile())
|
||||
{
|
||||
//TODO: Set better text messages
|
||||
if (OperationProgress != null)
|
||||
OperationProgress(this, DuplicatiOperation.Backup, 0, "Patching restore with #" + (patchno + 1).ToString());
|
||||
|
||||
using (new Logging.Timer("Get " + vol.Filename))
|
||||
backend.Get(vol.Filename, patchzip);
|
||||
|
||||
@@ -248,6 +294,9 @@ namespace Duplicati.Library.Main
|
||||
{
|
||||
if (backend != null)
|
||||
backend.Dispose();
|
||||
|
||||
if (OperationCompleted != null)
|
||||
OperationCompleted(this, DuplicatiOperation.Restore, 100, "Completed");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,58 +311,28 @@ namespace Duplicati.Library.Main
|
||||
/// <summary>
|
||||
/// Restores control files added to a backup.
|
||||
/// </summary>
|
||||
/// <param name="source">The backend to retrieve the control files from</param>
|
||||
/// <param name="target">The folder into which to restore the files</param>
|
||||
/// <param name="options">Options that affect how the call is performed</param>
|
||||
/// <returns>A restore report</returns>
|
||||
public static string RestoreControlFiles(string source, string target, Dictionary<string, string> options)
|
||||
public string RestoreControlFiles(string target)
|
||||
{
|
||||
SetupCommonOptions(options);
|
||||
SetupCommonOptions(m_options);
|
||||
RestoreStatistics rs = new RestoreStatistics();
|
||||
|
||||
Backend.IBackend backend = null;
|
||||
|
||||
using (new Logging.Timer("Restore control files from " + source + " to " + target))
|
||||
using (new Logging.Timer("Restore control files from " + m_backend + " to " + target))
|
||||
{
|
||||
try
|
||||
{
|
||||
backend = Backend.BackendLoader.GetBackend(source, options);
|
||||
if (OperationStarted != null)
|
||||
OperationStarted(this, DuplicatiOperation.Restore, 0, "Started");
|
||||
|
||||
backend = Backend.BackendLoader.GetBackend(m_backend, m_options);
|
||||
if (backend == null)
|
||||
throw new Exception("Unable to find backend for target: " + source);
|
||||
backend = new BackendWrapper(rs, backend, options);
|
||||
|
||||
List<BackupEntry> attempts = ParseFileList(backend, options);
|
||||
|
||||
Core.FilenameFilter filter;
|
||||
|
||||
if (!options.ContainsKey("file-to-restore"))
|
||||
{
|
||||
filter = new Duplicati.Library.Core.FilenameFilter(
|
||||
new List<Core.IFilenameFilter>(new Core.IFilenameFilter[] {
|
||||
//Exclude everything with a path
|
||||
new Duplicati.Library.Core.RegularExpressionFilter(false, "*." + System.IO.Path.DirectorySeparatorChar.ToString() + "*."),
|
||||
//Exclude known files
|
||||
new Duplicati.Library.Core.FilelistFilter(false, new string[] {
|
||||
RSync.RSyncDir.ADDED_FOLDERS,
|
||||
RSync.RSyncDir.DELETED_FILES,
|
||||
RSync.RSyncDir.DELETED_FOLDERS
|
||||
})
|
||||
})
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
filter = new Duplicati.Library.Core.FilenameFilter(
|
||||
new List<Core.IFilenameFilter>(new Core.IFilenameFilter[] {
|
||||
//Include requested items
|
||||
new Duplicati.Library.Core.FilelistFilter(true, options["file-to-restore"].Split(System.IO.Path.PathSeparator)),
|
||||
//Exclude everything else
|
||||
new Duplicati.Library.Core.RegularExpressionFilter(false, "*.")
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
throw new Exception("Unable to find backend for target: " + m_backend);
|
||||
backend = new BackendWrapper(rs, backend, m_options);
|
||||
|
||||
List<BackupEntry> attempts = ParseFileList(backend);
|
||||
|
||||
List<BackupEntry> flatlist = new List<BackupEntry>();
|
||||
foreach (BackupEntry be in attempts)
|
||||
@@ -323,26 +342,32 @@ namespace Duplicati.Library.Main
|
||||
}
|
||||
|
||||
flatlist.Reverse();
|
||||
|
||||
string prefix = Core.Utility.AppendDirSeperator(RSync.RSyncDir.CONTROL_ROOT);
|
||||
|
||||
foreach (BackupEntry be in flatlist)
|
||||
{
|
||||
Backend.IBackend realbackend = backend;
|
||||
if (be.EncryptionMode != null)
|
||||
realbackend = Encryption.EncryptedBackendWrapper.WrapWithEncryption(backend, be.EncryptionMode, options);
|
||||
realbackend = Encryption.EncryptedBackendWrapper.WrapWithEncryption(backend, be.EncryptionMode, m_options);
|
||||
|
||||
if (be.SignatureFile.Count > 0)
|
||||
using(Core.TempFile z = new Duplicati.Library.Core.TempFile())
|
||||
{
|
||||
if (OperationProgress != null)
|
||||
OperationProgress(this, DuplicatiOperation.Backup, 0, "Reading incremental data from " + be.SignatureFile[0].Filename);
|
||||
|
||||
using (new Logging.Timer("Get " + be.SignatureFile[0].Filename))
|
||||
realbackend.Get(be.SignatureFile[0].Filename, z);
|
||||
|
||||
using(Compression.FileArchiveZip fz = new Duplicati.Library.Compression.FileArchiveZip(z))
|
||||
{
|
||||
bool any = false;
|
||||
foreach (string f in filter.FilterList("", fz.ListFiles(null)))
|
||||
foreach (string f in fz.ListFiles(prefix))
|
||||
{
|
||||
any = true;
|
||||
using (System.IO.Stream s1 = fz.OpenRead(f))
|
||||
using (System.IO.Stream s2 = System.IO.File.Create(System.IO.Path.Combine(target, f)))
|
||||
using (System.IO.Stream s2 = System.IO.File.Create(System.IO.Path.Combine(target, f.Substring(prefix.Length))))
|
||||
Core.Utility.CopyStream(s1, s2);
|
||||
}
|
||||
|
||||
@@ -359,6 +384,9 @@ namespace Duplicati.Library.Main
|
||||
{
|
||||
if (backend != null)
|
||||
backend.Dispose();
|
||||
|
||||
if (OperationCompleted != null)
|
||||
OperationCompleted(this, DuplicatiOperation.Restore, 100, "Completed");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -370,21 +398,24 @@ namespace Duplicati.Library.Main
|
||||
return rs.ToString();
|
||||
}
|
||||
|
||||
public static string RemoveAllButNFull(string source, Dictionary<string, string> options)
|
||||
public string RemoveAllButNFull()
|
||||
{
|
||||
if (!options.ContainsKey("remove-all-but-n-full"))
|
||||
if (!m_options.ContainsKey("remove-all-but-n-full"))
|
||||
throw new Exception("No count given for \"Remove All But N Full\"");
|
||||
|
||||
int x = int.Parse(options["remove-all-but-n-full"]);
|
||||
int x = int.Parse(m_options["remove-all-but-n-full"]);
|
||||
if (x < 0)
|
||||
throw new Exception("Invalid count for remove-all-but-n-full");
|
||||
Backend.IBackend backend = Backend.BackendLoader.GetBackend(source, options);
|
||||
Backend.IBackend backend = Backend.BackendLoader.GetBackend(m_backend, m_options);
|
||||
if (backend == null)
|
||||
throw new Exception("Unable to find backend for target: " + source);
|
||||
throw new Exception("Unable to find backend for target: " + m_backend);
|
||||
|
||||
try
|
||||
{
|
||||
List<BackupEntry> entries = ParseFileList(backend, options);
|
||||
if (OperationStarted != null)
|
||||
OperationStarted(this, DuplicatiOperation.Remove, 0, "Started");
|
||||
|
||||
List<BackupEntry> entries = ParseFileList(backend);
|
||||
|
||||
|
||||
List<BackupEntry> toremove = new List<BackupEntry>();
|
||||
@@ -399,30 +430,35 @@ namespace Duplicati.Library.Main
|
||||
toremove.Add(be);
|
||||
}
|
||||
|
||||
return RemoveBackupSets(backend, options, toremove);
|
||||
return RemoveBackupSets(backend, toremove);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (backend != null)
|
||||
backend.Dispose();
|
||||
if (OperationCompleted != null)
|
||||
OperationCompleted(this, DuplicatiOperation.Remove, 100, "Completed");
|
||||
}
|
||||
}
|
||||
|
||||
public static string RemoveOlderThan(string source, Dictionary<string, string> options)
|
||||
public string RemoveOlderThan()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
if (!options.ContainsKey("remove-older-than"))
|
||||
if (!m_options.ContainsKey("remove-older-than"))
|
||||
throw new Exception("No count given for \"Remove Older Than\"");
|
||||
|
||||
Backend.IBackend backend = Backend.BackendLoader.GetBackend(source, options);
|
||||
Backend.IBackend backend = Backend.BackendLoader.GetBackend(m_backend, m_options);
|
||||
if (backend == null)
|
||||
throw new Exception("Unable to find backend for target: " + source);
|
||||
throw new Exception("Unable to find backend for target: " + m_backend);
|
||||
|
||||
try
|
||||
{
|
||||
string duration = options["remove-older-than"];
|
||||
List<BackupEntry> entries = ParseFileList(backend, options);
|
||||
if (OperationStarted != null)
|
||||
OperationStarted(this, DuplicatiOperation.Remove, 0, "Started");
|
||||
|
||||
string duration = m_options["remove-older-than"];
|
||||
List<BackupEntry> entries = ParseFileList(backend);
|
||||
|
||||
DateTime expires = Core.Timeparser.ParseTimeInterval(duration, DateTime.Now, true);
|
||||
|
||||
@@ -461,18 +497,20 @@ namespace Duplicati.Library.Main
|
||||
}
|
||||
|
||||
|
||||
sb.Append(RemoveBackupSets(backend, options, toremove));
|
||||
sb.Append(RemoveBackupSets(backend, toremove));
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (backend != null)
|
||||
backend.Dispose();
|
||||
if (OperationCompleted != null)
|
||||
OperationCompleted(this, DuplicatiOperation.Remove, 100, "Completed");
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private static string RemoveBackupSets(Backend.IBackend backend, Dictionary<string, string> options, List<BackupEntry> entries)
|
||||
private string RemoveBackupSets(Backend.IBackend backend, List<BackupEntry> entries)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
@@ -480,7 +518,7 @@ namespace Duplicati.Library.Main
|
||||
{
|
||||
sb.AppendLine("Deleting backup at " + be.Time.ToString(System.Globalization.CultureInfo.InvariantCulture));
|
||||
|
||||
if (options.ContainsKey("force"))
|
||||
if (m_options.ContainsKey("force"))
|
||||
{
|
||||
//Delete manifest
|
||||
backend.Delete(be.Filename);
|
||||
@@ -493,46 +531,62 @@ namespace Duplicati.Library.Main
|
||||
}
|
||||
}
|
||||
|
||||
if (!options.ContainsKey("force") && entries.Count > 0)
|
||||
if (!m_options.ContainsKey("force") && entries.Count > 0)
|
||||
sb.AppendLine("Files are not deleted, use the --force command to actually remove files");
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
|
||||
public static string[] List(string source, Dictionary<string, string> options)
|
||||
public string[] List()
|
||||
{
|
||||
SetupCommonOptions(options);
|
||||
SetupCommonOptions(m_options);
|
||||
|
||||
List<string> res = new List<string>();
|
||||
Duplicati.Library.Backend.IBackend i = new Duplicati.Library.Backend.BackendLoader(source, options);
|
||||
Duplicati.Library.Backend.IBackend i = new Duplicati.Library.Backend.BackendLoader(m_backend, m_options);
|
||||
|
||||
if (i == null)
|
||||
throw new Exception("Unable to find backend for target: " + source);
|
||||
throw new Exception("Unable to find backend for target: " + m_backend);
|
||||
|
||||
if (OperationStarted != null)
|
||||
OperationStarted(this, DuplicatiOperation.List, 0, "Started");
|
||||
|
||||
using(i)
|
||||
foreach (Duplicati.Library.Backend.FileEntry fe in i.List())
|
||||
res.Add(fe.Name);
|
||||
|
||||
if (OperationCompleted != null)
|
||||
OperationCompleted(this, DuplicatiOperation.List, 100, "Completed");
|
||||
|
||||
return res.ToArray();
|
||||
}
|
||||
|
||||
public static List<BackupEntry> ParseFileList(string backend, Dictionary<string, string> options)
|
||||
public List<BackupEntry> ParseFileList()
|
||||
{
|
||||
Backend.IBackend obackend = Backend.BackendLoader.GetBackend(backend, options);
|
||||
if (OperationStarted != null)
|
||||
OperationStarted(this, DuplicatiOperation.List, 0, "Started");
|
||||
|
||||
Backend.IBackend obackend = Backend.BackendLoader.GetBackend(m_backend, m_options);
|
||||
if (obackend == null)
|
||||
throw new Exception("Unable to find backend for target: " + backend);
|
||||
using(obackend)
|
||||
return ParseFileList(obackend, options);
|
||||
throw new Exception("Unable to find backend for target: " + m_backend);
|
||||
using (obackend)
|
||||
{
|
||||
List<BackupEntry> data = ParseFileList(obackend);
|
||||
|
||||
if (OperationCompleted != null)
|
||||
OperationCompleted(this, DuplicatiOperation.List, 100, "Completed");
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
public static List<BackupEntry> ParseFileList(Duplicati.Library.Backend.IBackend backend, Dictionary<string, string> options)
|
||||
private List<BackupEntry> ParseFileList(Duplicati.Library.Backend.IBackend backend)
|
||||
{
|
||||
SetupCommonOptions(options);
|
||||
SetupCommonOptions(m_options);
|
||||
|
||||
using (new Logging.Timer("Getting and sorting filelist from " + backend.DisplayName))
|
||||
{
|
||||
FilenameStrategy fns = new FilenameStrategy(options);
|
||||
FilenameStrategy fns = new FilenameStrategy(m_options);
|
||||
|
||||
List<BackupEntry> incrementals = new List<BackupEntry>();
|
||||
List<BackupEntry> fulls = new List<BackupEntry>();
|
||||
@@ -610,22 +664,25 @@ namespace Duplicati.Library.Main
|
||||
}
|
||||
}
|
||||
|
||||
public static IList<string> ListContent(string source, Dictionary<string, string> options)
|
||||
public IList<string> ListContent()
|
||||
{
|
||||
SetupCommonOptions(options);
|
||||
SetupCommonOptions(m_options);
|
||||
RestoreStatistics rs = new RestoreStatistics();
|
||||
|
||||
SortedList<string, string> res = new SortedList<string, string>();
|
||||
Duplicati.Library.Backend.IBackend backend = new Duplicati.Library.Backend.BackendLoader(source, options);
|
||||
Duplicati.Library.Backend.IBackend backend = new Duplicati.Library.Backend.BackendLoader(m_backend, m_options);
|
||||
|
||||
if (backend == null)
|
||||
throw new Exception("Unable to find backend for target: " + source);
|
||||
backend = new BackendWrapper(rs, backend, options);
|
||||
throw new Exception("Unable to find backend for target: " + m_backend);
|
||||
backend = new BackendWrapper(rs, backend, m_options);
|
||||
|
||||
string specifictime = options.ContainsKey("restore-time") ? options["restore-time"] : "now";
|
||||
BackupEntry bestFit = FindBestMatch(ParseFileList(backend, options), specifictime);
|
||||
if (OperationStarted != null)
|
||||
OperationStarted(this, DuplicatiOperation.List, 0, "Started");
|
||||
|
||||
string specifictime = m_options.ContainsKey("restore-time") ? m_options["restore-time"] : "now";
|
||||
BackupEntry bestFit = FindBestMatch(ParseFileList(backend), specifictime);
|
||||
if (bestFit.EncryptionMode != null)
|
||||
backend = Encryption.EncryptedBackendWrapper.WrapWithEncryption(backend, bestFit.EncryptionMode, options);
|
||||
backend = Encryption.EncryptedBackendWrapper.WrapWithEncryption(backend, bestFit.EncryptionMode, m_options);
|
||||
|
||||
using (backend)
|
||||
using (Core.TempFolder basefolder = new Duplicati.Library.Core.TempFolder())
|
||||
@@ -647,6 +704,9 @@ namespace Duplicati.Library.Main
|
||||
if (be.CompressionMode != "zip")
|
||||
throw new Exception("Unexpected compression mode");
|
||||
|
||||
if (OperationProgress != null)
|
||||
OperationProgress(this, DuplicatiOperation.Backup, 0, "Reading incremental data: " + be.Filename);
|
||||
|
||||
using (new Logging.Timer("Get " + be.Filename))
|
||||
backend.Get(be.Filename, patchzip);
|
||||
|
||||
@@ -673,25 +733,13 @@ namespace Duplicati.Library.Main
|
||||
}
|
||||
}
|
||||
|
||||
if (OperationCompleted != null)
|
||||
OperationCompleted(this, DuplicatiOperation.List, 100, "Completed");
|
||||
|
||||
return res.Keys;
|
||||
}
|
||||
|
||||
private static string NormalizeZipFileName(string name)
|
||||
{
|
||||
if (System.IO.Path.DirectorySeparatorChar != '/')
|
||||
name = name.Replace(System.IO.Path.DirectorySeparatorChar, '/');
|
||||
return name;
|
||||
}
|
||||
|
||||
private static string NormalizeZipDirName(string name)
|
||||
{
|
||||
name = NormalizeZipFileName(name);
|
||||
if (!name.EndsWith("/"))
|
||||
name += "/";
|
||||
return name;
|
||||
}
|
||||
|
||||
private static BackupEntry FindBestMatch(List<BackupEntry> backups, string specifictime)
|
||||
private BackupEntry FindBestMatch(List<BackupEntry> backups, string specifictime)
|
||||
{
|
||||
if (string.IsNullOrEmpty(specifictime))
|
||||
specifictime = "now";
|
||||
@@ -720,12 +768,71 @@ namespace Duplicati.Library.Main
|
||||
return bestFit;
|
||||
}
|
||||
|
||||
private static void SetupCommonOptions(Dictionary<string, string> options)
|
||||
private void SetupCommonOptions(Dictionary<string, string> options)
|
||||
{
|
||||
if (options.ContainsKey("tempdir"))
|
||||
Core.TempFolder.SystemTempPath = options["tempdir"];
|
||||
if (options.ContainsKey("thread-priority"))
|
||||
System.Threading.Thread.CurrentThread.Priority = Core.Utility.ParsePriority(options["thread-priority"]);
|
||||
}
|
||||
|
||||
//Static helpers
|
||||
|
||||
public static string[] List(string target, Dictionary<string, string> options)
|
||||
{
|
||||
using (Interface i = new Interface(target, options))
|
||||
return i.List();
|
||||
}
|
||||
|
||||
public static string Backup(string source, string target, Dictionary<string, string> options)
|
||||
{
|
||||
using (Interface i = new Interface(target, options))
|
||||
return i.Backup(source);
|
||||
}
|
||||
|
||||
public static string Restore(string source, string target, Dictionary<string, string> options)
|
||||
{
|
||||
using (Interface i = new Interface(source, options))
|
||||
return i.Restore(target);
|
||||
}
|
||||
|
||||
public static List<BackupEntry> ParseFileList(string target, Dictionary<string, string> options)
|
||||
{
|
||||
using (Interface i = new Interface(target, options))
|
||||
return i.ParseFileList();
|
||||
}
|
||||
|
||||
public static IList<string> ListContent(string target, Dictionary<string, string> options)
|
||||
{
|
||||
using (Interface i = new Interface(target, options))
|
||||
return i.ListContent();
|
||||
}
|
||||
|
||||
public static string RemoveAllButNFull(string target, Dictionary<string, string> options)
|
||||
{
|
||||
using (Interface i = new Interface(target, options))
|
||||
return i.RemoveAllButNFull();
|
||||
}
|
||||
|
||||
public static string RemoveOlderThan(string target, Dictionary<string, string> options)
|
||||
{
|
||||
using (Interface i = new Interface(target, options))
|
||||
return i.RemoveOlderThan();
|
||||
}
|
||||
|
||||
public static string RestoreControlFiles(string source, string target, Dictionary<string, string> options)
|
||||
{
|
||||
using (Interface i = new Interface(source, options))
|
||||
return i.RestoreControlFiles(target);
|
||||
}
|
||||
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Duplicati.Library.Main
|
||||
{
|
||||
/// <summary>
|
||||
/// A wrapper for holding multiple events
|
||||
/// </summary>
|
||||
public class ProgressEvents
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
#region Disclaimer / License
|
||||
// Copyright (C) 2009, Kenneth Skovhede
|
||||
// http://www.hexad.dk, opensource@hexad.dk
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
#endregion
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Duplicati.Library.Main.RSync
|
||||
{
|
||||
/// <summary>
|
||||
/// This class wraps the usage of RDiff.exe so the use of RDiff looks like native calls
|
||||
/// </summary>
|
||||
public class RDiffWrapper
|
||||
{
|
||||
/// <summary>
|
||||
/// The name of the RDiff program to call
|
||||
/// </summary>
|
||||
public static string RDIFF_PROGRAM = "rdiff";
|
||||
|
||||
/// <summary>
|
||||
/// Generates a signature file
|
||||
/// </summary>
|
||||
/// <param name="filename">The file to create the signature for</param>
|
||||
/// <param name="outputfile">The file write the signature to</param>
|
||||
public static void GenerateSignature(string filename, string outputfile)
|
||||
{
|
||||
if (System.IO.File.Exists(outputfile))
|
||||
System.IO.File.Delete(outputfile);
|
||||
//System.IO.File.Create(outputfile);
|
||||
ReadProgramOutput("signature \"" + filename + "\" \"" + outputfile + "\"", null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a delta file
|
||||
/// </summary>
|
||||
/// <param name="signaturefile">The signature for the file</param>
|
||||
/// <param name="filename">The file to create the delta for</param>
|
||||
/// <param name="deltafile">The delta output file</param>
|
||||
public static void GenerateDelta(string signaturefile, string filename, string deltafile)
|
||||
{
|
||||
if (System.IO.File.Exists(deltafile))
|
||||
System.IO.File.Delete(deltafile);
|
||||
ReadProgramOutput("delta \"" + signaturefile + "\" \"" + filename + "\" \"" + deltafile + "\"", null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Patches a file
|
||||
/// </summary>
|
||||
/// <param name="basefile">The most recent full copy of the file</param>
|
||||
/// <param name="deltafile">The delta file</param>
|
||||
/// <param name="outputfile">The restored file</param>
|
||||
public static void PatchFile(string basefile, string deltafile, string outputfile)
|
||||
{
|
||||
if (System.IO.File.Exists(outputfile))
|
||||
System.IO.File.Delete(outputfile);
|
||||
ReadProgramOutput("patch \"" + basefile + "\" \"" + deltafile + "\" \"" + outputfile + "\"", null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Internal helper function that wraps the usage of rdiff
|
||||
/// </summary>
|
||||
/// <param name="args">The command line arguments</param>
|
||||
/// <param name="output">An optional stream to write output to</param>
|
||||
/// <returns>The data from stdout</returns>
|
||||
private static byte[] ReadProgramOutput(string args, System.IO.Stream output)
|
||||
{
|
||||
System.Diagnostics.ProcessStartInfo pi = new System.Diagnostics.ProcessStartInfo(RDIFF_PROGRAM);
|
||||
pi.Arguments = args;
|
||||
pi.CreateNoWindow = true;
|
||||
pi.RedirectStandardOutput = true;
|
||||
pi.RedirectStandardError = true;
|
||||
pi.UseShellExecute = false;
|
||||
pi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
|
||||
|
||||
System.Diagnostics.Process p = System.Diagnostics.Process.Start(pi);
|
||||
System.IO.Stream outstream = output;
|
||||
if (outstream == null)
|
||||
outstream = new System.IO.MemoryStream();
|
||||
|
||||
byte[] buf = new byte[1024];
|
||||
int a;
|
||||
while ((a = p.StandardOutput.BaseStream.Read(buf, 0, buf.Length)) != 0)
|
||||
outstream.Write(buf, 0, a);
|
||||
p.WaitForExit();
|
||||
|
||||
if (p.ExitCode != 0)
|
||||
throw new Exception(p.StandardError.ReadToEnd());
|
||||
else if (output == null)
|
||||
return (outstream as System.IO.MemoryStream).ToArray();
|
||||
else
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,7 @@ namespace Duplicati.Library.Main.RSync
|
||||
internal static readonly string CONTENT_ROOT = "snapshot";
|
||||
internal static readonly string DELTA_ROOT = "diff";
|
||||
//private static readonly string DACL_ROOT = "dacl";
|
||||
internal static readonly string CONTROL_ROOT = "controlfiles";
|
||||
|
||||
internal static readonly string DELETED_FILES = "deleted_files.txt";
|
||||
internal static readonly string DELETED_FOLDERS = "deleted_folders.txt";
|
||||
|
||||
@@ -23,7 +23,7 @@ using System.Text;
|
||||
|
||||
namespace Duplicati.Library.Main
|
||||
{
|
||||
public class RestoreStatistics : CommunicationStatistics
|
||||
internal class RestoreStatistics : CommunicationStatistics
|
||||
{
|
||||
private DateTime m_beginTime;
|
||||
private DateTime m_endTime;
|
||||
|
||||
Reference in New Issue
Block a user