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:
kenneth.skovhede@gmail.com
2009-02-15 23:27:14 +00:00
parent 2fa5facdf5
commit fd422ef4b4
29 changed files with 902 additions and 361 deletions
+46 -4
View File
@@ -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;
}
}
+28
View File
@@ -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)
{
}
}
}
+3
View File
@@ -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; }
}
}
}
+88 -88
View File
@@ -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
}
}
+10
View File
@@ -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
+10
View File
@@ -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>
+8 -9
View File
@@ -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>
+41
View File
@@ -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";
}
}
}
}
+1 -1
View File
@@ -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;
}
@@ -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
View File
@@ -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)
+4 -1
View File
@@ -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; } }
+1 -1
View File
@@ -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
View File
@@ -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
}
}
+13
View File
@@ -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
{
}
}
-111
View File
@@ -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;
}
}
}
+1
View File
@@ -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";
+1 -1
View File
@@ -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;