Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/duplicati/duplicati.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'Duplicati/Library')
-rw-r--r--Duplicati/Library/Backend/AlternativeFTP/AlternativeFTPBackend.cs8
-rw-r--r--Duplicati/Library/Backend/AzureBlob/AzureBlobBackend.cs4
-rw-r--r--Duplicati/Library/Backend/Backblaze/B2.cs20
-rw-r--r--Duplicati/Library/Backend/Box/BoxBackend.cs4
-rw-r--r--Duplicati/Library/Backend/CloudFiles/CloudFiles.cs4
-rw-r--r--Duplicati/Library/Backend/Dropbox/Dropbox.cs4
-rw-r--r--Duplicati/Library/Backend/FTP/FTPBackend.cs4
-rw-r--r--Duplicati/Library/Backend/GoogleServices/GoogleCloudStorage.cs4
-rw-r--r--Duplicati/Library/Backend/GoogleServices/GoogleDrive.cs4
-rw-r--r--Duplicati/Library/Backend/Jottacloud/Jottacloud.cs4
-rw-r--r--Duplicati/Library/Backend/Mega/Duplicati.Library.Backend.Mega.csproj7
-rw-r--r--Duplicati/Library/Backend/Mega/MegaBackend.cs17
-rw-r--r--Duplicati/Library/Backend/Mega/Strings.cs4
-rw-r--r--Duplicati/Library/Backend/Mega/packages.config5
-rw-r--r--Duplicati/Library/Backend/OpenStack/OpenStackStorage.cs4
-rw-r--r--Duplicati/Library/Backend/S3/S3Backend.cs4
-rw-r--r--Duplicati/Library/Backend/SSHv2/SSHv2Backend.cs4
-rw-r--r--Duplicati/Library/Backend/SharePoint/SharePointBackend.cs4
-rw-r--r--Duplicati/Library/Backend/Storj/Duplicati.Library.Backend.Storj.csproj128
-rw-r--r--Duplicati/Library/Backend/Storj/Properties/AssemblyInfo.cs37
-rw-r--r--Duplicati/Library/Backend/Storj/StorjBackend.cs368
-rw-r--r--Duplicati/Library/Backend/Storj/StorjConfig.cs (renamed from Duplicati/Library/Backend/Tardigrade/TardigradeConfig.cs)18
-rw-r--r--Duplicati/Library/Backend/Storj/StorjFile.cs (renamed from Duplicati/Library/Backend/Tardigrade/TardigradeFile.cs)18
-rw-r--r--Duplicati/Library/Backend/Storj/Strings.cs30
-rw-r--r--Duplicati/Library/Backend/Storj/libstorj_uplink.dylib (renamed from Duplicati/Library/Backend/Tardigrade/libstorj_uplink.dylib)bin16654056 -> 15742632 bytes
-rw-r--r--Duplicati/Library/Backend/Storj/libstorj_uplink.so (renamed from Duplicati/Library/Backend/Tardigrade/libstorj_uplink.so)bin17074528 -> 15696192 bytes
-rw-r--r--Duplicati/Library/Backend/Storj/packages.config13
-rw-r--r--Duplicati/Library/Backend/Storj/win-x64/storj_uplink.dll (renamed from Duplicati/Library/Backend/Tardigrade/win-x64/storj_uplink.dll)bin10642432 -> 9741824 bytes
-rw-r--r--Duplicati/Library/Backend/Storj/win-x86/storj_uplink.dll (renamed from Duplicati/Library/Backend/Tardigrade/win-x86/storj_uplink.dll)bin9273344 -> 8320000 bytes
-rw-r--r--Duplicati/Library/Backend/TahoeLAFS/TahoeBackend.cs4
-rw-r--r--Duplicati/Library/Backend/Tardigrade/Duplicati.Library.Backend.Tardigrade.csproj59
-rw-r--r--Duplicati/Library/Backend/Tardigrade/Properties/AssemblyInfo.cs2
-rw-r--r--Duplicati/Library/Backend/Tardigrade/Strings.cs19
-rw-r--r--Duplicati/Library/Backend/Tardigrade/TardigradeBackend.cs327
-rw-r--r--Duplicati/Library/Backend/Tardigrade/packages.config11
-rw-r--r--Duplicati/Library/Backend/TencentCOS/COSBackend.cs4
-rw-r--r--Duplicati/Library/Backend/WEBDAV/WEBDAV.cs4
-rw-r--r--Duplicati/Library/Interface/CustomExceptions.cs16
-rw-r--r--Duplicati/Library/Main/Controller.cs8
-rw-r--r--Duplicati/Library/Main/Operation/BackupHandler.cs2
-rw-r--r--Duplicati/Library/Main/Operation/FilelistProcessor.cs8
-rw-r--r--Duplicati/Library/Modules/Builtin/Duplicati.Library.Modules.Builtin.csproj3
-rw-r--r--Duplicati/Library/Modules/Builtin/packages.config1
-rw-r--r--Duplicati/Library/Utility/FilterExpression.cs5
44 files changed, 767 insertions, 427 deletions
diff --git a/Duplicati/Library/Backend/AlternativeFTP/AlternativeFTPBackend.cs b/Duplicati/Library/Backend/AlternativeFTP/AlternativeFTPBackend.cs
index 23d3a3f6c..3c99e48ac 100644
--- a/Duplicati/Library/Backend/AlternativeFTP/AlternativeFTPBackend.cs
+++ b/Duplicati/Library/Backend/AlternativeFTP/AlternativeFTPBackend.cs
@@ -30,8 +30,8 @@ using System.Security.Authentication;
using System.Threading;
using System.Threading.Tasks;
using CoreUtility = Duplicati.Library.Utility.Utility;
-using Uri = System.Uri;
-
+using Uri = System.Uri;
+
namespace Duplicati.Library.Backend.AlternativeFTP
{
// ReSharper disable once RedundantExtendsListEntry
@@ -370,11 +370,11 @@ namespace Duplicati.Library.Backend.AlternativeFTP
}
}
- public Task PutAsync(string remotename, string localname, CancellationToken cancelToken)
+ public async Task PutAsync(string remotename, string localname, CancellationToken cancelToken)
{
using (FileStream fs = File.Open(localname, FileMode.Open, FileAccess.Read, FileShare.Read))
{
- return PutAsync(remotename, fs, cancelToken);
+ await PutAsync(remotename, fs, cancelToken);
}
}
diff --git a/Duplicati/Library/Backend/AzureBlob/AzureBlobBackend.cs b/Duplicati/Library/Backend/AzureBlob/AzureBlobBackend.cs
index 18ab0cc92..becf985c9 100644
--- a/Duplicati/Library/Backend/AzureBlob/AzureBlobBackend.cs
+++ b/Duplicati/Library/Backend/AzureBlob/AzureBlobBackend.cs
@@ -101,12 +101,12 @@ namespace Duplicati.Library.Backend.AzureBlob
return _azureBlob.ListContainerEntries();
}
- public Task PutAsync(string remotename, string localname, CancellationToken cancelToken)
+ public async Task PutAsync(string remotename, string localname, CancellationToken cancelToken)
{
using (var fs = File.Open(localname,
FileMode.Open, FileAccess.Read, FileShare.Read))
{
- return PutAsync(remotename, fs, cancelToken);
+ await PutAsync(remotename, fs, cancelToken);
}
}
diff --git a/Duplicati/Library/Backend/Backblaze/B2.cs b/Duplicati/Library/Backend/Backblaze/B2.cs
index d1e811d92..241cd7821 100644
--- a/Duplicati/Library/Backend/Backblaze/B2.cs
+++ b/Duplicati/Library/Backend/Backblaze/B2.cs
@@ -30,10 +30,10 @@ namespace Duplicati.Library.Backend.Backblaze
public class B2 : IBackend, IStreamingBackend
{
private const string B2_ID_OPTION = "b2-accountid";
- private const string B2_KEY_OPTION = "b2-applicationkey";
- private const string B2_PAGESIZE_OPTION = "b2-page-size";
+ private const string B2_KEY_OPTION = "b2-applicationkey";
+ private const string B2_PAGESIZE_OPTION = "b2-page-size";
private const string B2_DOWNLOAD_URL_OPTION = "b2-download-url";
-
+
private const string B2_CREATE_BUCKET_TYPE_OPTION = "b2-create-bucket-type";
private const string DEFAULT_BUCKET_TYPE = "allPrivate";
@@ -95,9 +95,9 @@ namespace Duplicati.Library.Backend.Backblaze
if (string.IsNullOrEmpty(accountKey))
throw new UserInformationException(Strings.B2.NoB2KeyError, "B2MissingKey");
- m_helper = new B2AuthHelper(accountId, accountKey);
-
- m_pagesize = DEFAULT_PAGE_SIZE;
+ m_helper = new B2AuthHelper(accountId, accountKey);
+
+ m_pagesize = DEFAULT_PAGE_SIZE;
if (options.ContainsKey(B2_PAGESIZE_OPTION))
{
int.TryParse(options[B2_PAGESIZE_OPTION], out m_pagesize);
@@ -182,8 +182,8 @@ namespace Duplicati.Library.Backend.Backblaze
new CommandLineArgument(B2_KEY_OPTION, CommandLineArgument.ArgumentType.Password, Strings.B2.B2applicationkeyDescriptionShort, Strings.B2.B2applicationkeyDescriptionLong, null, new string[] {"auth-username"}, null),
new CommandLineArgument("auth-password", CommandLineArgument.ArgumentType.Password, Strings.B2.AuthPasswordDescriptionShort, Strings.B2.AuthPasswordDescriptionLong),
new CommandLineArgument("auth-username", CommandLineArgument.ArgumentType.String, Strings.B2.AuthUsernameDescriptionShort, Strings.B2.AuthUsernameDescriptionLong),
- new CommandLineArgument(B2_CREATE_BUCKET_TYPE_OPTION, CommandLineArgument.ArgumentType.String, Strings.B2.B2createbuckettypeDescriptionShort, Strings.B2.B2createbuckettypeDescriptionLong, DEFAULT_BUCKET_TYPE),
- new CommandLineArgument(B2_PAGESIZE_OPTION, CommandLineArgument.ArgumentType.Integer, Strings.B2.B2pagesizeDescriptionShort, Strings.B2.B2pagesizeDescriptionLong, DEFAULT_PAGE_SIZE.ToString()),
+ new CommandLineArgument(B2_CREATE_BUCKET_TYPE_OPTION, CommandLineArgument.ArgumentType.String, Strings.B2.B2createbuckettypeDescriptionShort, Strings.B2.B2createbuckettypeDescriptionLong, DEFAULT_BUCKET_TYPE),
+ new CommandLineArgument(B2_PAGESIZE_OPTION, CommandLineArgument.ArgumentType.Integer, Strings.B2.B2pagesizeDescriptionShort, Strings.B2.B2pagesizeDescriptionLong, DEFAULT_PAGE_SIZE.ToString()),
new CommandLineArgument(B2_DOWNLOAD_URL_OPTION, CommandLineArgument.ArgumentType.String, Strings.B2.B2downloadurlDescriptionShort, Strings.B2.B2downloadurlDescriptionLong),
});
@@ -362,10 +362,10 @@ namespace Duplicati.Library.Backend.Backblaze
).ToList();
}
- public Task PutAsync(string remotename, string filename, CancellationToken cancelToken)
+ public async Task PutAsync(string remotename, string filename, CancellationToken cancelToken)
{
using (System.IO.FileStream fs = System.IO.File.OpenRead(filename))
- return PutAsync(remotename, fs, cancelToken);
+ await PutAsync(remotename, fs, cancelToken);
}
public void Get(string remotename, string filename)
diff --git a/Duplicati/Library/Backend/Box/BoxBackend.cs b/Duplicati/Library/Backend/Box/BoxBackend.cs
index 03d6f6bb0..acc725d20 100644
--- a/Duplicati/Library/Backend/Box/BoxBackend.cs
+++ b/Duplicati/Library/Backend/Box/BoxBackend.cs
@@ -260,10 +260,10 @@ namespace Duplicati.Library.Backend.Box
select (IFileEntry)new FileEntry(n.Name, n.Size, n.ModifiedAt, n.ModifiedAt) { IsFolder = n.Type == "folder" };
}
- public Task PutAsync(string remotename, string filename, CancellationToken cancelToken)
+ public async Task PutAsync(string remotename, string filename, CancellationToken cancelToken)
{
using (System.IO.FileStream fs = System.IO.File.OpenRead(filename))
- return PutAsync(remotename, fs, cancelToken);
+ await PutAsync(remotename, fs, cancelToken);
}
public void Get(string remotename, string filename)
diff --git a/Duplicati/Library/Backend/CloudFiles/CloudFiles.cs b/Duplicati/Library/Backend/CloudFiles/CloudFiles.cs
index ece4510e7..f53c40e78 100644
--- a/Duplicati/Library/Backend/CloudFiles/CloudFiles.cs
+++ b/Duplicati/Library/Backend/CloudFiles/CloudFiles.cs
@@ -194,10 +194,10 @@ namespace Duplicati.Library.Backend
} while (repeat);
}
- public Task PutAsync(string remotename, string filename, CancellationToken cancelToken)
+ public async Task PutAsync(string remotename, string filename, CancellationToken cancelToken)
{
using (System.IO.FileStream fs = System.IO.File.OpenRead(filename))
- return PutAsync(remotename, fs, cancelToken);
+ await PutAsync(remotename, fs, cancelToken);
}
public void Get(string remotename, string filename)
diff --git a/Duplicati/Library/Backend/Dropbox/Dropbox.cs b/Duplicati/Library/Backend/Dropbox/Dropbox.cs
index 835deb38b..89ea8b863 100644
--- a/Duplicati/Library/Backend/Dropbox/Dropbox.cs
+++ b/Duplicati/Library/Backend/Dropbox/Dropbox.cs
@@ -107,10 +107,10 @@ namespace Duplicati.Library.Backend
}
}
- public Task PutAsync(string remotename, string filename, CancellationToken cancelToken)
+ public async Task PutAsync(string remotename, string filename, CancellationToken cancelToken)
{
using(FileStream fs = File.OpenRead(filename))
- return PutAsync(remotename, fs, cancelToken);
+ await PutAsync(remotename, fs, cancelToken);
}
public void Get(string remotename, string filename)
diff --git a/Duplicati/Library/Backend/FTP/FTPBackend.cs b/Duplicati/Library/Backend/FTP/FTPBackend.cs
index e5c2bbc2e..cabffc9dc 100644
--- a/Duplicati/Library/Backend/FTP/FTPBackend.cs
+++ b/Duplicati/Library/Backend/FTP/FTPBackend.cs
@@ -296,10 +296,10 @@ namespace Duplicati.Library.Backend
}
}
- public Task PutAsync(string remotename, string localname, CancellationToken cancelToken)
+ public async Task PutAsync(string remotename, string localname, CancellationToken cancelToken)
{
using (System.IO.FileStream fs = System.IO.File.Open(localname, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read))
- return PutAsync(remotename, fs, cancelToken);
+ await PutAsync(remotename, fs, cancelToken);
}
public void Get(string remotename, System.IO.Stream output)
diff --git a/Duplicati/Library/Backend/GoogleServices/GoogleCloudStorage.cs b/Duplicati/Library/Backend/GoogleServices/GoogleCloudStorage.cs
index 1c63f0e06..65f744969 100644
--- a/Duplicati/Library/Backend/GoogleServices/GoogleCloudStorage.cs
+++ b/Duplicati/Library/Backend/GoogleServices/GoogleCloudStorage.cs
@@ -139,10 +139,10 @@ namespace Duplicati.Library.Backend.GoogleCloudStorage
}
}
- public Task PutAsync(string remotename, string filename, CancellationToken cancelToken)
+ public async Task PutAsync(string remotename, string filename, CancellationToken cancelToken)
{
using (System.IO.FileStream fs = System.IO.File.OpenRead(filename))
- return PutAsync(remotename, fs, cancelToken);
+ await PutAsync(remotename, fs, cancelToken);
}
public void Get(string remotename, string filename)
diff --git a/Duplicati/Library/Backend/GoogleServices/GoogleDrive.cs b/Duplicati/Library/Backend/GoogleServices/GoogleDrive.cs
index 29e179e50..bee4df367 100644
--- a/Duplicati/Library/Backend/GoogleServices/GoogleDrive.cs
+++ b/Duplicati/Library/Backend/GoogleServices/GoogleDrive.cs
@@ -253,10 +253,10 @@ namespace Duplicati.Library.Backend.GoogleDrive
}
}
- public Task PutAsync(string remotename, string filename, CancellationToken cancelToken)
+ public async Task PutAsync(string remotename, string filename, CancellationToken cancelToken)
{
using (System.IO.FileStream fs = System.IO.File.OpenRead(filename))
- return PutAsync(remotename, fs, cancelToken);
+ await PutAsync(remotename, fs, cancelToken);
}
public void Get(string remotename, string filename)
diff --git a/Duplicati/Library/Backend/Jottacloud/Jottacloud.cs b/Duplicati/Library/Backend/Jottacloud/Jottacloud.cs
index 95dc2762f..9f297abf2 100644
--- a/Duplicati/Library/Backend/Jottacloud/Jottacloud.cs
+++ b/Duplicati/Library/Backend/Jottacloud/Jottacloud.cs
@@ -304,10 +304,10 @@ namespace Duplicati.Library.Backend
return ToFileEntry(xFile);
}
- public Task PutAsync(string remotename, string filename, CancellationToken cancelToken)
+ public async Task PutAsync(string remotename, string filename, CancellationToken cancelToken)
{
using (System.IO.FileStream fs = System.IO.File.OpenRead(filename))
- return PutAsync(remotename, fs, cancelToken);
+ await PutAsync(remotename, fs, cancelToken);
}
public void Get(string remotename, string filename)
diff --git a/Duplicati/Library/Backend/Mega/Duplicati.Library.Backend.Mega.csproj b/Duplicati/Library/Backend/Mega/Duplicati.Library.Backend.Mega.csproj
index c8871b0e0..27a9e9cd4 100644
--- a/Duplicati/Library/Backend/Mega/Duplicati.Library.Backend.Mega.csproj
+++ b/Duplicati/Library/Backend/Mega/Duplicati.Library.Backend.Mega.csproj
@@ -31,12 +31,15 @@
<ConsolePause>false</ConsolePause>
</PropertyGroup>
<ItemGroup>
- <Reference Include="MegaApiClient, Version=1.7.1.495, Culture=neutral, PublicKeyToken=0480d311efbeb4e2, processorArchitecture=MSIL">
- <HintPath>..\..\..\..\packages\MegaApiClient.1.7.1\lib\net46\MegaApiClient.dll</HintPath>
+ <Reference Include="MegaApiClient, Version=1.9.0.0, Culture=neutral, PublicKeyToken=0480d311efbeb4e2">
+ <HintPath>..\..\..\..\packages\MegaApiClient.1.9.0\lib\net46\MegaApiClient.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\..\..\..\packages\Newtonsoft.Json.12.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
+ <Reference Include="Otp.NET, Version=1.2.2.0, Culture=neutral, PublicKeyToken=38a48df817e173a6">
+ <HintPath>..\..\..\..\packages\Otp.NET.1.2.2\lib\net45\Otp.NET.dll</HintPath>
+ </Reference>
<Reference Include="System" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Web" />
diff --git a/Duplicati/Library/Backend/Mega/MegaBackend.cs b/Duplicati/Library/Backend/Mega/MegaBackend.cs
index 184a63769..8f73cf2a4 100644
--- a/Duplicati/Library/Backend/Mega/MegaBackend.cs
+++ b/Duplicati/Library/Backend/Mega/MegaBackend.cs
@@ -22,6 +22,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using OtpNet;
namespace Duplicati.Library.Backend.Mega
{
@@ -31,6 +32,7 @@ namespace Duplicati.Library.Backend.Mega
{
private readonly string m_username = null;
private readonly string m_password = null;
+ private readonly string m_twoFactorKey = null;
private Dictionary<string, List<INode>> m_filecache;
private INode m_currentFolder = null;
private readonly string m_prefix = null;
@@ -48,7 +50,13 @@ namespace Duplicati.Library.Backend.Mega
if (m_client == null)
{
var cl = new MegaApiClient();
- cl.Login(m_username, m_password);
+ if (m_twoFactorKey == null)
+ cl.Login(m_username, m_password);
+ else
+ {
+ var totp = new Totp(Base32Encoding.ToBytes(m_twoFactorKey)).ComputeTotp();
+ cl.Login(m_username, m_password, totp);
+ }
m_client = cl;
}
@@ -64,6 +72,8 @@ namespace Duplicati.Library.Backend.Mega
m_username = options["auth-username"];
if (options.ContainsKey("auth-password"))
m_password = options["auth-password"];
+ if (options.ContainsKey("auth-two-factor-key"))
+ m_twoFactorKey = options["auth-two-factor-key"];
if (!string.IsNullOrEmpty(uri.Username))
m_username = uri.Username;
@@ -186,10 +196,10 @@ namespace Duplicati.Library.Backend.Mega
select new FileEntry(item.Name, item.Size, item.ModificationDate ?? new DateTime(0), item.ModificationDate ?? new DateTime(0));
}
- public Task PutAsync(string remotename, string filename, CancellationToken cancelToken)
+ public async Task PutAsync(string remotename, string filename, CancellationToken cancelToken)
{
using (System.IO.FileStream fs = System.IO.File.OpenRead(filename))
- return PutAsync(remotename, fs, cancelToken);
+ await PutAsync(remotename, fs, cancelToken);
}
public void Get(string remotename, string filename)
@@ -253,6 +263,7 @@ namespace Duplicati.Library.Backend.Mega
return new List<ICommandLineArgument>(new ICommandLineArgument[] {
new CommandLineArgument("auth-password", CommandLineArgument.ArgumentType.Password, Strings.MegaBackend.AuthPasswordDescriptionShort, Strings.MegaBackend.AuthPasswordDescriptionLong),
new CommandLineArgument("auth-username", CommandLineArgument.ArgumentType.String, Strings.MegaBackend.AuthUsernameDescriptionShort, Strings.MegaBackend.AuthUsernameDescriptionLong),
+ new CommandLineArgument("auth-two-factor-key", CommandLineArgument.ArgumentType.Password, Strings.MegaBackend.AuthTwoFactorKeyDescriptionShort, Strings.MegaBackend.AuthTwoFactorKeyDescriptionLong),
});
}
}
diff --git a/Duplicati/Library/Backend/Mega/Strings.cs b/Duplicati/Library/Backend/Mega/Strings.cs
index d52089191..3009798e1 100644
--- a/Duplicati/Library/Backend/Mega/Strings.cs
+++ b/Duplicati/Library/Backend/Mega/Strings.cs
@@ -6,8 +6,10 @@ namespace Duplicati.Library.Backend.Strings {
public static string AuthPasswordDescriptionShort { get { return LC.L(@"Supplies the password used to connect to the server"); } }
public static string AuthUsernameDescriptionLong { get { return LC.L(@"The username used to connect to the server. This may also be supplied as the environment variable ""AUTH_USERNAME""."); } }
public static string AuthUsernameDescriptionShort { get { return LC.L(@"Supplies the username used to connect to the server"); } }
+ public static string AuthTwoFactorKeyDescriptionShort { get { return LC.L(@"The shared secret used to generate two-factor TOTP codes."); } }
+ public static string AuthTwoFactorKeyDescriptionLong { get { return LC.L(@"For accounts with two-factor authentication enabled, this is the shared secret used to generate the two-factor TOTP codes."); } }
public static string NoPasswordError { get { return LC.L(@"No password given"); } }
public static string NoUsernameError { get { return LC.L(@"No username given"); } }
public static string Description { get { return LC.L(@"This backend can read and write data to Mega.co.nz. Allowed formats are: ""mega://folder/subfolder"""); } }
}
-}
+} \ No newline at end of file
diff --git a/Duplicati/Library/Backend/Mega/packages.config b/Duplicati/Library/Backend/Mega/packages.config
index 06ff32662..c90fbddd1 100644
--- a/Duplicati/Library/Backend/Mega/packages.config
+++ b/Duplicati/Library/Backend/Mega/packages.config
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
- <package id="MegaApiClient" version="1.7.1" targetFramework="net471" />
+ <package id="MegaApiClient" version="1.9.0" targetFramework="net471" />
<package id="Newtonsoft.Json" version="12.0.2" targetFramework="net471" />
-</packages>
+ <package id="Otp.NET" version="1.2.2" targetFramework="net471" />
+</packages> \ No newline at end of file
diff --git a/Duplicati/Library/Backend/OpenStack/OpenStackStorage.cs b/Duplicati/Library/Backend/OpenStack/OpenStackStorage.cs
index 306aa9087..935645c3b 100644
--- a/Duplicati/Library/Backend/OpenStack/OpenStackStorage.cs
+++ b/Duplicati/Library/Backend/OpenStack/OpenStackStorage.cs
@@ -565,10 +565,10 @@ namespace Duplicati.Library.Backend.OpenStack
}
}
- public Task PutAsync(string remotename, string filename, CancellationToken cancelToken)
+ public async Task PutAsync(string remotename, string filename, CancellationToken cancelToken)
{
using (FileStream fs = File.OpenRead(filename))
- return PutAsync(remotename, fs, cancelToken);
+ await PutAsync(remotename, fs, cancelToken);
}
public void Get(string remotename, string filename)
diff --git a/Duplicati/Library/Backend/S3/S3Backend.cs b/Duplicati/Library/Backend/S3/S3Backend.cs
index 6b14eabbf..cde4dbf23 100644
--- a/Duplicati/Library/Backend/S3/S3Backend.cs
+++ b/Duplicati/Library/Backend/S3/S3Backend.cs
@@ -341,10 +341,10 @@ namespace Duplicati.Library.Backend
}
}
- public Task PutAsync(string remotename, string localname, CancellationToken cancelToken)
+ public async Task PutAsync(string remotename, string localname, CancellationToken cancelToken)
{
using (FileStream fs = File.Open(localname, FileMode.Open, FileAccess.Read, FileShare.Read))
- return PutAsync(remotename, fs, cancelToken);
+ await PutAsync(remotename, fs, cancelToken);
}
public async Task PutAsync(string remotename, Stream input, CancellationToken cancelToken)
diff --git a/Duplicati/Library/Backend/SSHv2/SSHv2Backend.cs b/Duplicati/Library/Backend/SSHv2/SSHv2Backend.cs
index 14bb5264a..5e79a6db9 100644
--- a/Duplicati/Library/Backend/SSHv2/SSHv2Backend.cs
+++ b/Duplicati/Library/Backend/SSHv2/SSHv2Backend.cs
@@ -167,11 +167,11 @@ namespace Duplicati.Library.Backend
public string ProtocolKey => "ssh";
- public Task PutAsync(string remotename, string filename, CancellationToken cancelToken)
+ public async Task PutAsync(string remotename, string filename, CancellationToken cancelToken)
{
using (System.IO.FileStream fs = System.IO.File.Open(filename, System.IO.FileMode.Open,
System.IO.FileAccess.Read, System.IO.FileShare.Read))
- return PutAsync(remotename, fs, cancelToken);
+ await PutAsync(remotename, fs, cancelToken);
}
public void Get(string remotename, string filename)
diff --git a/Duplicati/Library/Backend/SharePoint/SharePointBackend.cs b/Duplicati/Library/Backend/SharePoint/SharePointBackend.cs
index c0af18060..646471669 100644
--- a/Duplicati/Library/Backend/SharePoint/SharePointBackend.cs
+++ b/Duplicati/Library/Backend/SharePoint/SharePointBackend.cs
@@ -518,10 +518,10 @@ namespace Duplicati.Library.Backend
Utility.Utility.CopyStream(s, stream, true, copybuffer);
}
- public Task PutAsync(string remotename, string filename, CancellationToken cancelToken)
+ public async Task PutAsync(string remotename, string filename, CancellationToken cancelToken)
{
using (FileStream fs = System.IO.File.OpenRead(filename))
- return PutAsync(remotename, fs, cancelToken);
+ await PutAsync(remotename, fs, cancelToken);
}
public Task PutAsync(string remotename, Stream stream, CancellationToken cancelToken) { return doPut(remotename, stream, false, cancelToken); }
diff --git a/Duplicati/Library/Backend/Storj/Duplicati.Library.Backend.Storj.csproj b/Duplicati/Library/Backend/Storj/Duplicati.Library.Backend.Storj.csproj
new file mode 100644
index 000000000..4f6179435
--- /dev/null
+++ b/Duplicati/Library/Backend/Storj/Duplicati.Library.Backend.Storj.csproj
@@ -0,0 +1,128 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{AE035E01-C917-4F13-A35E-78F21C1A2F17}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Duplicati.Library.Backend.Storj</RootNamespace>
+ <AssemblyName>Duplicati.Library.Backend.Storj</AssemblyName>
+ <TargetFrameworkVersion>v4.7.1</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <Deterministic>true</Deterministic>
+ <NuGetPackageImportStamp>
+ </NuGetPackageImportStamp>
+ <TargetFrameworkProfile />
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <PlatformTarget>x64</PlatformTarget>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="SQLite-net, Version=1.7.335.0, Culture=neutral, processorArchitecture=MSIL">
+ <HintPath>..\..\..\..\packages\sqlite-net-pcl.1.7.335\lib\netstandard2.0\SQLite-net.dll</HintPath>
+ </Reference>
+ <Reference Include="SQLitePCLRaw.batteries_v2, Version=2.0.3.851, Culture=neutral, PublicKeyToken=8226ea5df37bcae9, processorArchitecture=MSIL">
+ <HintPath>..\..\..\..\packages\SQLitePCLRaw.bundle_green.2.0.3\lib\net461\SQLitePCLRaw.batteries_v2.dll</HintPath>
+ </Reference>
+ <Reference Include="SQLitePCLRaw.core, Version=2.0.3.851, Culture=neutral, PublicKeyToken=1488e028ca7ab535, processorArchitecture=MSIL">
+ <HintPath>..\..\..\..\packages\SQLitePCLRaw.core.2.0.3\lib\netstandard2.0\SQLitePCLRaw.core.dll</HintPath>
+ </Reference>
+ <Reference Include="SQLitePCLRaw.nativelibrary, Version=2.0.3.851, Culture=neutral, PublicKeyToken=502ed628492ab262, processorArchitecture=MSIL">
+ <HintPath>..\..\..\..\packages\SQLitePCLRaw.bundle_green.2.0.3\lib\net461\SQLitePCLRaw.nativelibrary.dll</HintPath>
+ </Reference>
+ <Reference Include="SQLitePCLRaw.provider.dynamic_cdecl, Version=2.0.3.851, Culture=neutral, PublicKeyToken=b68184102cba0b3b, processorArchitecture=MSIL">
+ <HintPath>..\..\..\..\packages\SQLitePCLRaw.provider.dynamic_cdecl.2.0.3\lib\netstandard2.0\SQLitePCLRaw.provider.dynamic_cdecl.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.Buffers, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
+ <HintPath>..\..\..\..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Core" />
+ <Reference Include="System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
+ <HintPath>..\..\..\..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Numerics" />
+ <Reference Include="System.Numerics.Vectors, Version=4.1.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <HintPath>..\..\..\..\packages\System.Numerics.Vectors.4.4.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.4.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <HintPath>..\..\..\..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Net.Http" />
+ <Reference Include="System.Xml" />
+ <Reference Include="uplink.NET, Version=2.7.0.0, Culture=neutral, processorArchitecture=MSIL">
+ <HintPath>..\..\..\..\packages\uplink.NET.2.7.1604\lib\netstandard2.0\uplink.NET.dll</HintPath>
+ </Reference>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="StorjFile.cs" />
+ <Compile Include="Strings.cs" />
+ <Compile Include="StorjBackend.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="StorjConfig.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\Common\Duplicati.Library.Common.csproj">
+ <Project>{d63e53e4-a458-4c2f-914d-92f715f58acf}</Project>
+ <Name>Duplicati.Library.Common</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\Interface\Duplicati.Library.Interface.csproj">
+ <Project>{c5899f45-b0ff-483c-9d38-24a9fcaab237}</Project>
+ <Name>Duplicati.Library.Interface</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\Localization\Duplicati.Library.Localization.csproj">
+ <Project>{b68f2214-951f-4f78-8488-66e1ed3f50bf}</Project>
+ <Name>Duplicati.Library.Localization</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\Utility\Duplicati.Library.Utility.csproj">
+ <Project>{de3e5d4c-51ab-4e5e-bee8-e636cebfba65}</Project>
+ <Name>Duplicati.Library.Utility</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="libstorj_uplink.dylib">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </None>
+ <None Include="libstorj_uplink.so">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </None>
+ <None Include="packages.config" />
+ </ItemGroup>
+ <ItemGroup>
+ <Content Include="win-x64\storj_uplink.dll">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="win-x86\storj_uplink.dll">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+ <PropertyGroup>
+ <ErrorText>Dieses Projekt verweist auf mindestens ein NuGet-Paket, das auf diesem Computer fehlt. Verwenden Sie die Wiederherstellung von NuGet-Paketen, um die fehlenden Dateien herunterzuladen. Weitere Informationen finden Sie unter "http://go.microsoft.com/fwlink/?LinkID=322105". Die fehlende Datei ist "{0}".</ErrorText>
+ </PropertyGroup>
+ <Error Condition="!Exists('..\..\..\..\packages\SQLitePCLRaw.lib.e_sqlite3.2.0.3\build\net461\SQLitePCLRaw.lib.e_sqlite3.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\SQLitePCLRaw.lib.e_sqlite3.2.0.3\build\net461\SQLitePCLRaw.lib.e_sqlite3.targets'))" />
+ </Target>
+ <Import Project="..\..\..\..\packages\SQLitePCLRaw.lib.e_sqlite3.2.0.3\build\net461\SQLitePCLRaw.lib.e_sqlite3.targets" Condition="Exists('..\..\..\..\packages\SQLitePCLRaw.lib.e_sqlite3.2.0.3\build\net461\SQLitePCLRaw.lib.e_sqlite3.targets')" />
+</Project> \ No newline at end of file
diff --git a/Duplicati/Library/Backend/Storj/Properties/AssemblyInfo.cs b/Duplicati/Library/Backend/Storj/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..27b1092b7
--- /dev/null
+++ b/Duplicati/Library/Backend/Storj/Properties/AssemblyInfo.cs
@@ -0,0 +1,37 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// Allgemeine Informationen über eine Assembly werden über die folgenden
+// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
+// die einer Assembly zugeordnet sind.
+[assembly: AssemblyTitle("Duplicati.Library.Backend.Tardigrade")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Duplicati.Library.Backend.Tardigrade")]
+[assembly: AssemblyCopyright("Copyright © 2020")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Durch Festlegen von ComVisible auf FALSE werden die Typen in dieser Assembly
+// für COM-Komponenten unsichtbar. Wenn Sie auf einen Typ in dieser Assembly von
+// COM aus zugreifen müssen, sollten Sie das ComVisible-Attribut für diesen Typ auf "True" festlegen.
+[assembly: ComVisible(false)]
+
+// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird
+[assembly: Guid("ae035e01-c917-4f13-a35e-78f21c1a2f17")]
+
+// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
+//
+// Hauptversion
+// Nebenversion
+// Buildnummer
+// Revision
+//
+// Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden,
+// indem Sie "*" wie unten gezeigt eingeben:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
+[assembly:InternalsVisibleTo("Duplicati.Library.Backend.Tardigrade")]
diff --git a/Duplicati/Library/Backend/Storj/StorjBackend.cs b/Duplicati/Library/Backend/Storj/StorjBackend.cs
new file mode 100644
index 000000000..43b4f42a9
--- /dev/null
+++ b/Duplicati/Library/Backend/Storj/StorjBackend.cs
@@ -0,0 +1,368 @@
+using Duplicati.Library.Interface;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Linq.Expressions;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using uplink.NET.Interfaces;
+using uplink.NET.Models;
+using uplink.NET.Services;
+
+namespace Duplicati.Library.Backend.Storj
+{
+ public class Storj : IStreamingBackend
+ {
+ private const string STORJ_AUTH_METHOD = "storj-auth-method";
+ private const string STORJ_SATELLITE = "storj-satellite";
+ private const string STORJ_API_KEY = "storj-api-key";
+ private const string STORJ_SECRET = "storj-secret";
+ private const string STORJ_SHARED_ACCESS = "storj-shared-access";
+ private const string STORJ_BUCKET = "storj-bucket";
+ private const string STORJ_FOLDER = "storj-folder";
+
+ private const string PROTOCOL_KEY = "storj";
+ private const string STORJ_PARTNER_ID = "duplicati";
+
+ private readonly string _satellite;
+ private readonly string _api_key;
+ private readonly string _secret;
+ private readonly string _bucket;
+ private readonly string _folder;
+ private Access _access;
+ private IBucketService _bucketService;
+ private IObjectService _objectService;
+
+ public static readonly Dictionary<string, string> KNOWN_STORJ_SATELLITES = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase){
+ { "US Central", "us1.storj.io:7777" },
+ { "Asia East", "ap1.storj.io:7777" },
+ { "Europe", "eu1.storj.io:7777" },
+ };
+
+ public static readonly Dictionary<string, string> KNOWN_AUTHENTICATION_METHODS = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase){
+ { "API key", "API key" },
+ { "Access grant", "Access grant" },
+ };
+
+ [DllImport("kernel32.dll")]
+ protected static extern IntPtr LoadLibrary(string filename);
+
+ private static bool _libraryLoaded = false;
+ private static void InitStorjLibrary()
+ {
+ if (_libraryLoaded)
+ return;
+
+ if (Duplicati.Library.Common.Platform.IsClientWindows) //We need to init only on Windows to distinguish between x64 and x86
+ {
+ if (System.Environment.Is64BitProcess)
+ {
+ var res = LoadLibrary("win-x64/storj_uplink.dll");
+ }
+ else
+ {
+ var res = LoadLibrary("win-x86/storj_uplink.dll");
+ }
+ }
+ Access.SetTempDirectory(Library.Utility.TempFolder.SystemTempPath);
+ _libraryLoaded = true;
+ }
+
+ // ReSharper disable once UnusedMember.Global
+ // This constructor is needed by the BackendLoader.
+ public Storj()
+ {
+ }
+
+ // ReSharper disable once UnusedMember.Global
+ // This constructor is needed by the BackendLoader.
+ public Storj(string url, Dictionary<string, string> options)
+ {
+ InitStorjLibrary();
+
+ foreach(var option in options.ToList())
+ {
+ if(option.Key.ToLower().Contains("tardigrade"))
+ {
+ options.Add(option.Key.ToLower().Replace("tardigrade", "storj"), option.Value);
+ }
+ }
+
+ var auth_method = options[STORJ_AUTH_METHOD];
+ if (auth_method == "Access grant")
+ {
+ //Create an access from the access grant
+ var shared_access = options[STORJ_SHARED_ACCESS];
+ _access = new Access(shared_access, new Config() { UserAgent = STORJ_PARTNER_ID });
+ }
+ else
+ {
+ //Create an access for a satellite, API key and encryption passphrase
+ _satellite = options[STORJ_SATELLITE];
+
+ if (options.ContainsKey(STORJ_API_KEY))
+ {
+ _api_key = options[STORJ_API_KEY];
+ }
+ if (options.ContainsKey(STORJ_SECRET))
+ {
+ _secret = options[STORJ_SECRET];
+ }
+
+ _access = new Access(_satellite, _api_key, _secret, new Config() { UserAgent = STORJ_PARTNER_ID });
+ }
+
+ _bucketService = new BucketService(_access);
+ _objectService = new ObjectService(_access);
+
+ //If no bucket was provided use the default "duplicati"-bucket
+ if (options.ContainsKey(STORJ_BUCKET))
+ {
+ _bucket = options[STORJ_BUCKET];
+ }
+ else
+ {
+ _bucket = "duplicati";
+ }
+
+ if (options.ContainsKey(STORJ_FOLDER))
+ {
+ _folder = options[STORJ_FOLDER];
+ }
+ }
+
+ public string DisplayName
+ {
+ get { return Strings.Storj.DisplayName; }
+ }
+
+ public string ProtocolKey => PROTOCOL_KEY;
+
+ public IList<ICommandLineArgument> SupportedCommands
+ {
+ get
+ {
+ return new List<ICommandLineArgument>(new ICommandLineArgument[] {
+ new CommandLineArgument(STORJ_AUTH_METHOD, CommandLineArgument.ArgumentType.String, Strings.Storj.StorjAuthMethodDescriptionShort, Strings.Storj.StorjAuthMethodDescriptionLong, "API key"),
+ new CommandLineArgument(STORJ_SATELLITE, CommandLineArgument.ArgumentType.String, Strings.Storj.StorjSatelliteDescriptionShort, Strings.Storj.StorjSatelliteDescriptionLong, "us1.storj.io:7777"),
+ new CommandLineArgument(STORJ_API_KEY, CommandLineArgument.ArgumentType.String, Strings.Storj.StorjAPIKeyDescriptionShort, Strings.Storj.StorjAPIKeyDescriptionLong),
+ new CommandLineArgument(STORJ_SECRET, CommandLineArgument.ArgumentType.Password, Strings.Storj.StorjSecretDescriptionShort, Strings.Storj.StorjSecretDescriptionLong),
+ new CommandLineArgument(STORJ_SHARED_ACCESS, CommandLineArgument.ArgumentType.String, Strings.Storj.StorjSharedAccessDescriptionShort, Strings.Storj.StorjSharedAccessDescriptionLong),
+ new CommandLineArgument(STORJ_BUCKET, CommandLineArgument.ArgumentType.String, Strings.Storj.StorjBucketDescriptionShort, Strings.Storj.StorjBucketDescriptionLong),
+ new CommandLineArgument(STORJ_FOLDER, CommandLineArgument.ArgumentType.String, Strings.Storj.StorjFolderDescriptionShort, Strings.Storj.StorjFolderDescriptionLong),
+ });
+ }
+ }
+
+ public string Description
+ {
+ get
+ {
+ return Strings.Storj.Description;
+ }
+ }
+
+ public string[] DNSName
+ {
+ get
+ {
+ return new string[0];
+ }
+ }
+
+ public void CreateFolder()
+ {
+ //Storj DCS has no folders
+ }
+
+ public void Delete(string remotename)
+ {
+ var deleteTask = DeleteAsync(remotename);
+ deleteTask.Wait();
+ }
+
+ public async Task DeleteAsync(string remotename)
+ {
+ try
+ {
+ var bucket = await _bucketService.EnsureBucketAsync(_bucket);
+ await _objectService.DeleteObjectAsync(bucket, GetBasePath() + remotename);
+ }
+ catch (Exception root)
+ {
+ throw new FileMissingException(root);
+ }
+ }
+
+ public void Dispose()
+ {
+ if (_objectService != null)
+ {
+ _objectService = null;
+ }
+ if (_bucketService != null)
+ {
+ _bucketService = null;
+ }
+ if (_access != null)
+ {
+ _access.Dispose();
+ _access = null;
+ }
+ }
+
+ public void Get(string remotename, string filename)
+ {
+ var getTask = GetAsync(remotename, filename);
+ getTask.Wait();
+ }
+
+ public async Task GetAsync(string remotename, string filename)
+ {
+ var bucket = await _bucketService.EnsureBucketAsync(_bucket);
+ var download = await _objectService.DownloadObjectAsync(bucket, GetBasePath() + remotename, new DownloadOptions(), false);
+ await download.StartDownloadAsync();
+
+ if (download.Completed)
+ {
+ using (FileStream file = new FileStream(filename, FileMode.Create))
+ {
+ await file.WriteAsync(download.DownloadedBytes, 0, (int)download.BytesReceived);
+ await file.FlushAsync().ConfigureAwait(false);
+ }
+ }
+ }
+
+ public void Get(string remotename, Stream stream)
+ {
+ var getTask = GetAsync(remotename, stream);
+ getTask.Wait();
+ }
+
+ public async Task GetAsync(string remotename, Stream stream)
+ {
+ int index = 0;
+ var bucket = await _bucketService.EnsureBucketAsync(_bucket);
+ var download = await _objectService.DownloadObjectAsync(bucket, GetBasePath() + remotename, new DownloadOptions(), false);
+ download.DownloadOperationProgressChanged += (op) =>
+ {
+ int newPartLength = (int)op.BytesReceived - index;
+ byte[] newPart = new byte[newPartLength];
+ Array.Copy(op.DownloadedBytes, index, newPart, 0, newPartLength);
+ stream.Write(newPart, 0, newPartLength);
+ index = index + newPartLength;
+ };
+ await download.StartDownloadAsync();
+ }
+
+ public IEnumerable<IFileEntry> List()
+ {
+ var listTask = ListAsync();
+ listTask.Wait();
+ return listTask.Result;
+ }
+
+ private async Task<IEnumerable<IFileEntry>> ListAsync()
+ {
+ List<StorjFile> files = new List<StorjFile>();
+ var bucket = await _bucketService.EnsureBucketAsync(_bucket);
+ var prefix = GetBasePath();
+ var objects = await _objectService.ListObjectsAsync(bucket, new ListObjectsOptions { Recursive = true, System = true, Custom = true, Prefix = prefix });
+
+ foreach (var obj in objects.Items)
+ {
+ StorjFile file = new StorjFile(obj);
+ if (prefix != "")
+ {
+ file.Name = file.Name.Replace(prefix, "");
+ }
+ files.Add(file);
+ }
+
+ return files;
+ }
+
+ public async Task PutAsync(string remotename, string filename, CancellationToken cancelToken)
+ {
+ using (FileStream fs = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
+ await PutAsync(remotename, fs, cancelToken);
+ }
+
+ public async Task PutAsync(string remotename, Stream stream, CancellationToken cancelToken)
+ {
+ var bucket = await _bucketService.EnsureBucketAsync(_bucket);
+ CustomMetadata custom = new CustomMetadata();
+ custom.Entries.Add(new CustomMetadataEntry { Key = StorjFile.STORJ_LAST_ACCESS, Value = DateTime.Now.ToUniversalTime().ToString("O") });
+ custom.Entries.Add(new CustomMetadataEntry { Key = StorjFile.STORJ_LAST_MODIFICATION, Value = DateTime.Now.ToUniversalTime().ToString("O") });
+ var upload = await _objectService.UploadObjectAsync(bucket, GetBasePath() + remotename, new UploadOptions(), stream, custom, false);
+ await upload.StartUploadAsync();
+ }
+
+ public void Test()
+ {
+ var testTask = TestAsync();
+ testTask.Wait(10000);
+ if (!testTask.Result)
+ {
+ throw new Exception(Strings.Storj.TestConnectionFailed);
+ }
+ }
+
+ /// <summary>
+ /// Test the connection by:
+ /// - creating the bucket (if it not already exists)
+ /// - uploading 256 random bytes to a test-file
+ /// - downloading the file back and expecting 256 bytes
+ /// </summary>
+ /// <returns>true, if the test was successfull or and exception</returns>
+ private async Task<bool> TestAsync()
+ {
+ string testFileName = GetBasePath() + "duplicati_test.dat";
+
+ var bucket = await _bucketService.EnsureBucketAsync(_bucket);
+ var upload = await _objectService.UploadObjectAsync(bucket, testFileName, new UploadOptions(), GetRandomBytes(256), false);
+ await upload.StartUploadAsync();
+
+ var download = await _objectService.DownloadObjectAsync(bucket, testFileName, new DownloadOptions(), false);
+ await download.StartDownloadAsync();
+
+ await _objectService.DeleteObjectAsync(bucket, testFileName);
+
+ if (download.Failed || download.BytesReceived != 256)
+ {
+ throw new Exception(download.ErrorMessage);
+ }
+
+ return true;
+ }
+
+ /// <summary>
+ /// Gets the base path - depending on there is a folder set or not
+ /// </summary>
+ /// <returns>The base path within a bucket where the backup shall be placed</returns>
+ private string GetBasePath()
+ {
+ if (!string.IsNullOrEmpty(_folder))
+ return _folder + "/";
+ else
+ return "";
+ }
+
+ /// <summary>
+ /// Creates some random bytes with the given length - just for testing the connection
+ /// </summary>
+ /// <param name="length">The length of the bytes to create</param>
+ /// <returns>A byte-array with the given length</returns>
+ private static byte[] GetRandomBytes(long length)
+ {
+ byte[] bytes = new byte[length];
+ Random rand = new Random();
+ rand.NextBytes(bytes);
+
+ return bytes;
+ }
+ }
+}
diff --git a/Duplicati/Library/Backend/Tardigrade/TardigradeConfig.cs b/Duplicati/Library/Backend/Storj/StorjConfig.cs
index 1464fe17f..7b449645f 100644
--- a/Duplicati/Library/Backend/Tardigrade/TardigradeConfig.cs
+++ b/Duplicati/Library/Backend/Storj/StorjConfig.cs
@@ -5,12 +5,12 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
-namespace Duplicati.Library.Backend.Tardigrade
+namespace Duplicati.Library.Backend.Storj
{
- public class TardigradeConfig : IWebModule
+ public class StorjConfig : IWebModule
{
private const ConfigType DEFAULT_CONFIG_TYPE = ConfigType.Satellites;
- private const string KEY_CONFIGTYPE = "tardigrade-config";
+ private const string KEY_CONFIGTYPE = "storj-config";
private static readonly string DEFAULT_CONFIG_TYPE_STR = Enum.GetName(typeof(ConfigType), DEFAULT_CONFIG_TYPE);
public enum ConfigType
@@ -21,11 +21,11 @@ namespace Duplicati.Library.Backend.Tardigrade
#region IWebModule implementation
- public string Key { get { return "tardigrade-getconfig"; } }
+ public string Key { get { return "storj-getconfig"; } }
- public string DisplayName { get { return "Tardigrade configuration module"; } }
+ public string DisplayName { get { return "Storj DCS configuration module"; } }
- public string Description { get { return "Exposes Tardigrade configuration as a web module"; } }
+ public string Description { get { return "Exposes Storj DCS configuration as a web module"; } }
public IList<ICommandLineArgument> SupportedCommands
{
@@ -56,11 +56,11 @@ namespace Duplicati.Library.Backend.Tardigrade
switch (ct)
{
case ConfigType.Satellites:
- return Tardigrade.KNOWN_TARDIGRADE_SATELLITES;
+ return Storj.KNOWN_STORJ_SATELLITES;
case ConfigType.AuthenticationMethods:
- return Tardigrade.KNOWN_AUTHENTICATION_METHODS;
+ return Storj.KNOWN_AUTHENTICATION_METHODS;
default:
- return Tardigrade.KNOWN_TARDIGRADE_SATELLITES;
+ return Storj.KNOWN_STORJ_SATELLITES;
}
}
#endregion
diff --git a/Duplicati/Library/Backend/Tardigrade/TardigradeFile.cs b/Duplicati/Library/Backend/Storj/StorjFile.cs
index 794e427e0..fa83c3907 100644
--- a/Duplicati/Library/Backend/Tardigrade/TardigradeFile.cs
+++ b/Duplicati/Library/Backend/Storj/StorjFile.cs
@@ -5,12 +5,12 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
-namespace Duplicati.Library.Backend.Tardigrade
+namespace Duplicati.Library.Backend.Storj
{
- public class TardigradeFile : IFileEntry
+ public class StorjFile : IFileEntry
{
- public static readonly string TARDIGRADE_LAST_ACCESS = "DUPLICATI:LAST-ACCESS";
- public static readonly string TARDIGRADE_LAST_MODIFICATION = "DUPLICATI:LAST-MODIFICATION";
+ public static readonly string STORJ_LAST_ACCESS = "DUPLICATI:LAST-ACCESS";
+ public static readonly string STORJ_LAST_MODIFICATION = "DUPLICATI:LAST-MODIFICATION";
public bool IsFolder { get; set; }
public DateTime LastAccess { get; set; }
@@ -21,15 +21,15 @@ namespace Duplicati.Library.Backend.Tardigrade
public long Size { get; set; }
- public TardigradeFile()
+ public StorjFile()
{
}
- public TardigradeFile(uplink.NET.Models.Object tardigradeObject)
+ public StorjFile(uplink.NET.Models.Object tardigradeObject)
{
IsFolder = tardigradeObject.IsPrefix;
- var lastAccess = tardigradeObject.CustomMetaData.Entries.Where(e => e.Key == TARDIGRADE_LAST_ACCESS).FirstOrDefault();
+ var lastAccess = tardigradeObject.CustomMetadata.Entries.Where(e => e.Key == STORJ_LAST_ACCESS).FirstOrDefault();
if (lastAccess != null && !string.IsNullOrEmpty(lastAccess.Value))
{
LastAccess = DateTime.Parse(lastAccess.Value);
@@ -39,7 +39,7 @@ namespace Duplicati.Library.Backend.Tardigrade
LastAccess = DateTime.MinValue;
}
- var lastMod = tardigradeObject.CustomMetaData.Entries.Where(e => e.Key == TARDIGRADE_LAST_MODIFICATION).FirstOrDefault();
+ var lastMod = tardigradeObject.CustomMetadata.Entries.Where(e => e.Key == STORJ_LAST_MODIFICATION).FirstOrDefault();
if (lastMod != null && !string.IsNullOrEmpty(lastMod.Value))
{
LastModification = DateTime.Parse(lastMod.Value);
@@ -50,7 +50,7 @@ namespace Duplicati.Library.Backend.Tardigrade
}
Name = tardigradeObject.Key;
- Size = tardigradeObject.SystemMetaData.ContentLength;
+ Size = tardigradeObject.SystemMetadata.ContentLength;
}
}
}
diff --git a/Duplicati/Library/Backend/Storj/Strings.cs b/Duplicati/Library/Backend/Storj/Strings.cs
new file mode 100644
index 000000000..c1de9425f
--- /dev/null
+++ b/Duplicati/Library/Backend/Storj/Strings.cs
@@ -0,0 +1,30 @@
+using Duplicati.Library.Localization.Short;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Duplicati.Library.Backend.Strings
+{
+ internal static class Storj
+ {
+ public static string DisplayName { get { return LC.L(@"Storj DCS (Decentralized Cloud Storage)"); } }
+ public static string Description { get { return LC.L(@"This backend can read and write data to the Storj DCS."); } }
+ public static string TestConnectionFailed { get { return LC.L(@"The connection-test failed."); } }
+ public static string StorjAuthMethodDescriptionShort { get { return LC.L(@"The authentication method"); } }
+ public static string StorjAuthMethodDescriptionLong { get { return LC.L(@"The authentication method describes which way to use to connect to the network - either via API key or via an access grant."); } }
+ public static string StorjSatelliteDescriptionShort { get { return LC.L(@"The satellite"); } }
+ public static string StorjSatelliteDescriptionLong { get { return LC.L(@"The satellite that keeps track of all metadata. Use a Storj DCS server for high-performance SLA-backed connectivity or use a community server. Or even host your own."); } }
+ public static string StorjAPIKeyDescriptionShort { get { return LC.L(@"The API key"); } }
+ public static string StorjAPIKeyDescriptionLong { get { return LC.L(@"The API key grants access to a specific project on your chosen satellite. Head over to the dashboard of your satellite to create one if you do not already have an API key."); } }
+ public static string StorjSecretDescriptionShort { get { return LC.L(@"The encryption passphrase"); } }
+ public static string StorjSecretDescriptionLong { get { return LC.L(@"The encryption passphrase is used to encrypt your data before sending it to the Storj network. This passphrase can be the only secret to provide - for Storj you do not necessary need any additional encryption (from Duplicati) in place."); } }
+ public static string StorjSharedAccessDescriptionShort { get { return LC.L(@"The access grant"); } }
+ public static string StorjSharedAccessDescriptionLong { get { return LC.L(@"An access grant contains all information in one encrypted string. You may use it instead of a satellite, API key and secret."); } }
+ public static string StorjBucketDescriptionShort { get { return LC.L(@"The bucket"); } }
+ public static string StorjBucketDescriptionLong { get { return LC.L(@"The bucket where the backup will reside in."); } }
+ public static string StorjFolderDescriptionShort { get { return LC.L(@"The folder"); } }
+ public static string StorjFolderDescriptionLong { get { return LC.L(@"The folder within the bucket where the backup will reside in."); } }
+ }
+}
diff --git a/Duplicati/Library/Backend/Tardigrade/libstorj_uplink.dylib b/Duplicati/Library/Backend/Storj/libstorj_uplink.dylib
index 4f0190dea..4f8ea2938 100644
--- a/Duplicati/Library/Backend/Tardigrade/libstorj_uplink.dylib
+++ b/Duplicati/Library/Backend/Storj/libstorj_uplink.dylib
Binary files differ
diff --git a/Duplicati/Library/Backend/Tardigrade/libstorj_uplink.so b/Duplicati/Library/Backend/Storj/libstorj_uplink.so
index 7c307a134..f4f495271 100644
--- a/Duplicati/Library/Backend/Tardigrade/libstorj_uplink.so
+++ b/Duplicati/Library/Backend/Storj/libstorj_uplink.so
Binary files differ
diff --git a/Duplicati/Library/Backend/Storj/packages.config b/Duplicati/Library/Backend/Storj/packages.config
new file mode 100644
index 000000000..983b0e7cc
--- /dev/null
+++ b/Duplicati/Library/Backend/Storj/packages.config
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="sqlite-net-pcl" version="1.7.335" targetFramework="net471" />
+ <package id="SQLitePCLRaw.bundle_green" version="2.0.3" targetFramework="net471" />
+ <package id="SQLitePCLRaw.core" version="2.0.3" targetFramework="net471" />
+ <package id="SQLitePCLRaw.lib.e_sqlite3" version="2.0.3" targetFramework="net471" />
+ <package id="SQLitePCLRaw.provider.dynamic_cdecl" version="2.0.3" targetFramework="net471" />
+ <package id="System.Buffers" version="4.4.0" targetFramework="net471" />
+ <package id="System.Memory" version="4.5.3" targetFramework="net471" />
+ <package id="System.Numerics.Vectors" version="4.4.0" targetFramework="net471" />
+ <package id="System.Runtime.CompilerServices.Unsafe" version="4.5.2" targetFramework="net471" />
+ <package id="uplink.NET" version="2.7.1604" targetFramework="net471" />
+</packages> \ No newline at end of file
diff --git a/Duplicati/Library/Backend/Tardigrade/win-x64/storj_uplink.dll b/Duplicati/Library/Backend/Storj/win-x64/storj_uplink.dll
index 29863308c..dbbca788d 100644
--- a/Duplicati/Library/Backend/Tardigrade/win-x64/storj_uplink.dll
+++ b/Duplicati/Library/Backend/Storj/win-x64/storj_uplink.dll
Binary files differ
diff --git a/Duplicati/Library/Backend/Tardigrade/win-x86/storj_uplink.dll b/Duplicati/Library/Backend/Storj/win-x86/storj_uplink.dll
index 6f1cc9e95..bbc697695 100644
--- a/Duplicati/Library/Backend/Tardigrade/win-x86/storj_uplink.dll
+++ b/Duplicati/Library/Backend/Storj/win-x86/storj_uplink.dll
Binary files differ
diff --git a/Duplicati/Library/Backend/TahoeLAFS/TahoeBackend.cs b/Duplicati/Library/Backend/TahoeLAFS/TahoeBackend.cs
index e36e03ce9..b35ad4585 100644
--- a/Duplicati/Library/Backend/TahoeLAFS/TahoeBackend.cs
+++ b/Duplicati/Library/Backend/TahoeLAFS/TahoeBackend.cs
@@ -209,10 +209,10 @@ namespace Duplicati.Library.Backend
}
}
- public Task PutAsync(string remotename, string filename, CancellationToken cancelToken)
+ public async Task PutAsync(string remotename, string filename, CancellationToken cancelToken)
{
using (System.IO.FileStream fs = System.IO.File.OpenRead(filename))
- return PutAsync(remotename, fs, cancelToken);
+ await PutAsync(remotename, fs, cancelToken);
}
public void Get(string remotename, string filename)
diff --git a/Duplicati/Library/Backend/Tardigrade/Duplicati.Library.Backend.Tardigrade.csproj b/Duplicati/Library/Backend/Tardigrade/Duplicati.Library.Backend.Tardigrade.csproj
index 0383b960b..5f7ba3ef7 100644
--- a/Duplicati/Library/Backend/Tardigrade/Duplicati.Library.Backend.Tardigrade.csproj
+++ b/Duplicati/Library/Backend/Tardigrade/Duplicati.Library.Backend.Tardigrade.csproj
@@ -4,7 +4,7 @@
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
- <ProjectGuid>{AE035E01-C917-4F13-A35E-78F21C1A2F17}</ProjectGuid>
+ <ProjectGuid>{9A04CB37-DA72-4008-9703-3AC5191974E9}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Duplicati.Library.Backend.Tardigrade</RootNamespace>
@@ -35,24 +35,50 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
+ <Reference Include="SQLite-net, Version=1.7.335.0, Culture=neutral, processorArchitecture=MSIL">
+ <HintPath>..\..\..\..\packages\sqlite-net-pcl.1.7.335\lib\netstandard2.0\SQLite-net.dll</HintPath>
+ </Reference>
+ <Reference Include="SQLitePCLRaw.batteries_v2, Version=2.0.3.851, Culture=neutral, PublicKeyToken=8226ea5df37bcae9, processorArchitecture=MSIL">
+ <HintPath>..\..\..\..\packages\SQLitePCLRaw.bundle_green.2.0.3\lib\net461\SQLitePCLRaw.batteries_v2.dll</HintPath>
+ </Reference>
+ <Reference Include="SQLitePCLRaw.core, Version=2.0.3.851, Culture=neutral, PublicKeyToken=1488e028ca7ab535, processorArchitecture=MSIL">
+ <HintPath>..\..\..\..\packages\SQLitePCLRaw.core.2.0.3\lib\netstandard2.0\SQLitePCLRaw.core.dll</HintPath>
+ </Reference>
+ <Reference Include="SQLitePCLRaw.nativelibrary, Version=2.0.3.851, Culture=neutral, PublicKeyToken=502ed628492ab262, processorArchitecture=MSIL">
+ <HintPath>..\..\..\..\packages\SQLitePCLRaw.bundle_green.2.0.3\lib\net461\SQLitePCLRaw.nativelibrary.dll</HintPath>
+ </Reference>
+ <Reference Include="SQLitePCLRaw.provider.dynamic_cdecl, Version=2.0.3.851, Culture=neutral, PublicKeyToken=b68184102cba0b3b, processorArchitecture=MSIL">
+ <HintPath>..\..\..\..\packages\SQLitePCLRaw.provider.dynamic_cdecl.2.0.3\lib\netstandard2.0\SQLitePCLRaw.provider.dynamic_cdecl.dll</HintPath>
+ </Reference>
<Reference Include="System" />
+ <Reference Include="System.Buffers, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
+ <HintPath>..\..\..\..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll</HintPath>
+ </Reference>
<Reference Include="System.Core" />
+ <Reference Include="System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
+ <HintPath>..\..\..\..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Numerics" />
+ <Reference Include="System.Numerics.Vectors, Version=4.1.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <HintPath>..\..\..\..\packages\System.Numerics.Vectors.4.4.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.4.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <HintPath>..\..\..\..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
+ </Reference>
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
- <Reference Include="uplink.NET, Version=2.3.4.0, Culture=neutral, processorArchitecture=MSIL">
- <HintPath>..\..\..\..\packages\uplink.NET.2.3.4\lib\netstandard2.0\uplink.NET.dll</HintPath>
+ <Reference Include="uplink.NET, Version=2.7.0.0, Culture=neutral, processorArchitecture=MSIL">
+ <HintPath>..\..\..\..\packages\uplink.NET.2.7.1604\lib\netstandard2.0\uplink.NET.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
- <Compile Include="TardigradeFile.cs" />
<Compile Include="Strings.cs" />
<Compile Include="TardigradeBackend.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
- <Compile Include="TardigradeConfig.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Common\Duplicati.Library.Common.csproj">
@@ -71,29 +97,20 @@
<Project>{de3e5d4c-51ab-4e5e-bee8-e636cebfba65}</Project>
<Name>Duplicati.Library.Utility</Name>
</ProjectReference>
+ <ProjectReference Include="..\Storj\Duplicati.Library.Backend.Storj.csproj">
+ <Project>{ae035e01-c917-4f13-a35e-78f21c1a2f17}</Project>
+ <Name>Duplicati.Library.Backend.Storj</Name>
+ </ProjectReference>
</ItemGroup>
<ItemGroup>
- <None Include="libstorj_uplink.dylib">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </None>
- <None Include="libstorj_uplink.so">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </None>
<None Include="packages.config" />
</ItemGroup>
- <ItemGroup>
- <Content Include="win-x64\storj_uplink.dll">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="win-x86\storj_uplink.dll">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>Dieses Projekt verweist auf mindestens ein NuGet-Paket, das auf diesem Computer fehlt. Verwenden Sie die Wiederherstellung von NuGet-Paketen, um die fehlenden Dateien herunterzuladen. Weitere Informationen finden Sie unter "http://go.microsoft.com/fwlink/?LinkID=322105". Die fehlende Datei ist "{0}".</ErrorText>
</PropertyGroup>
- <Error Condition="!Exists('..\..\..\..\packages\uplink.NET.2.3.4\build\net40\uplink.NET.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\uplink.NET.2.3.4\build\net40\uplink.NET.targets'))" />
+ <Error Condition="!Exists('..\..\..\..\packages\SQLitePCLRaw.lib.e_sqlite3.2.0.3\build\net461\SQLitePCLRaw.lib.e_sqlite3.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\SQLitePCLRaw.lib.e_sqlite3.2.0.3\build\net461\SQLitePCLRaw.lib.e_sqlite3.targets'))" />
</Target>
-</Project>
+ <Import Project="..\..\..\..\packages\SQLitePCLRaw.lib.e_sqlite3.2.0.3\build\net461\SQLitePCLRaw.lib.e_sqlite3.targets" Condition="Exists('..\..\..\..\packages\SQLitePCLRaw.lib.e_sqlite3.2.0.3\build\net461\SQLitePCLRaw.lib.e_sqlite3.targets')" />
+</Project> \ No newline at end of file
diff --git a/Duplicati/Library/Backend/Tardigrade/Properties/AssemblyInfo.cs b/Duplicati/Library/Backend/Tardigrade/Properties/AssemblyInfo.cs
index 5f3cc907e..762e1e0c9 100644
--- a/Duplicati/Library/Backend/Tardigrade/Properties/AssemblyInfo.cs
+++ b/Duplicati/Library/Backend/Tardigrade/Properties/AssemblyInfo.cs
@@ -20,7 +20,7 @@ using System.Runtime.InteropServices;
[assembly: ComVisible(false)]
// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird
-[assembly: Guid("ae035e01-c917-4f13-a35e-78f21c1a2f17")]
+[assembly: Guid("9A04CB37-DA72-4008-9703-3AC5191974E9")]
// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
//
diff --git a/Duplicati/Library/Backend/Tardigrade/Strings.cs b/Duplicati/Library/Backend/Tardigrade/Strings.cs
index 7540c2859..3703872f2 100644
--- a/Duplicati/Library/Backend/Tardigrade/Strings.cs
+++ b/Duplicati/Library/Backend/Tardigrade/Strings.cs
@@ -9,22 +9,7 @@ namespace Duplicati.Library.Backend.Strings
{
internal static class Tardigrade
{
- public static string DisplayName { get { return LC.L(@"Tardigrade Decentralized Cloud Storage"); } }
- public static string Description { get { return LC.L(@"This backend can read and write data to the Tardigrade Decentralized Cloud Storage."); } }
- public static string TestConnectionFailed { get { return LC.L(@"The connection-test failed."); } }
- public static string TardigradeAuthMethodDescriptionShort { get { return LC.L(@"The authentication method"); } }
- public static string TardigradeAuthMethodDescriptionLong { get { return LC.L(@"The authentication method describes which way to use to connect to the network - either via API key or via an access grant."); } }
- public static string TardigradeSatelliteDescriptionShort { get { return LC.L(@"The satellite"); } }
- public static string TardigradeSatelliteDescriptionLong { get { return LC.L(@"The satellite that keeps track of all metadata. Use a Tardigrade-grade server for high-performance SLA-backed connectivity or use a community server. Or even host your own."); } }
- public static string TardigradeAPIKeyDescriptionShort { get { return LC.L(@"The API key"); } }
- public static string TardigradeAPIKeyDescriptionLong { get { return LC.L(@"The API key grants access to a specific project on your chosen satellite. Head over to the dashboard of your satellite to create one if you do not already have an API key."); } }
- public static string TardigradeSecretDescriptionShort { get { return LC.L(@"The encryption passphrase"); } }
- public static string TardigradeSecretDescriptionLong { get { return LC.L(@"The encryption passphrase is used to encrypt your data before sending it to the tardigrade network. This passphrase can be the only secret to provide - for Tardigrade you do not necessary need any additional encryption (from Duplicati) in place."); } }
- public static string TardigradeSharedAccessDescriptionShort { get { return LC.L(@"The access grant"); } }
- public static string TardigradeSharedAccessDescriptionLong { get { return LC.L(@"An access grant contains all information in one encrypted string. You may use it instead of a satellite, API key and secret."); } }
- public static string TardigradeBucketDescriptionShort { get { return LC.L(@"The bucket"); } }
- public static string TardigradeBucketDescriptionLong { get { return LC.L(@"The bucket where the backup will reside in."); } }
- public static string TardigradeFolderDescriptionShort { get { return LC.L(@"The folder"); } }
- public static string TardigradeFolderDescriptionLong { get { return LC.L(@"The folder within the bucket where the backup will reside in."); } }
+ public static string DisplayName { get { return LC.L(@"Tardigrade Decentralised Cloud Storage (Deprecated)"); } }
+ public static string Description { get { return LC.L(@"This backend can read and write data to the Tardigrade Decentralized Cloud Storage. It is deprecated - please move over to the new Storj DCS. (Deprecated)"); } }
}
}
diff --git a/Duplicati/Library/Backend/Tardigrade/TardigradeBackend.cs b/Duplicati/Library/Backend/Tardigrade/TardigradeBackend.cs
index 0bf808105..255830500 100644
--- a/Duplicati/Library/Backend/Tardigrade/TardigradeBackend.cs
+++ b/Duplicati/Library/Backend/Tardigrade/TardigradeBackend.cs
@@ -14,7 +14,15 @@ using uplink.NET.Services;
namespace Duplicati.Library.Backend.Tardigrade
{
- public class Tardigrade : IStreamingBackend
+
+ /// <summary>
+ /// This backend is deprecated! It will be removed in the future.
+ /// Tardigrade renamed to Storj DCS in Spring 2021 - but existing Tardigrade-Configurations could not be easily renamed.
+ /// So we decided to "copy" Tardigrade over to the new name Storj DCS. In order to reduce duplicate code, the old
+ /// Tardigrade-Backend hands it's logic over to Storj DCS. Only the UI-specific part, the config-parameters and
+ /// the protocol-key stay here named for Tardigrade.
+ /// </summary>
+ public class Tardigrade : Duplicati.Library.Backend.Storj.Storj, IStreamingBackend
{
private const string TARDIGRADE_AUTH_METHOD = "tardigrade-auth-method";
private const string TARDIGRADE_SATELLITE = "tardigrade-satellite";
@@ -23,339 +31,50 @@ namespace Duplicati.Library.Backend.Tardigrade
private const string TARDIGRADE_SHARED_ACCESS = "tardigrade-shared-access";
private const string TARDIGRADE_BUCKET = "tardigrade-bucket";
private const string TARDIGRADE_FOLDER = "tardigrade-folder";
- private const string PROTOCOL_KEY = "tardigrade";
- private const string TARDIGRADE_PARTNER_ID = "duplicati";
-
- private readonly string _satellite;
- private readonly string _api_key;
- private readonly string _secret;
- private readonly string _bucket;
- private readonly string _folder;
- private Access _access;
- private IBucketService _bucketService;
- private IObjectService _objectService;
-
- public static readonly Dictionary<string, string> KNOWN_TARDIGRADE_SATELLITES = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase){
- { "US Central 1", "us-central-1.tardigrade.io:7777" },
- { "Asia East 1", "asia-east-1.tardigrade.io:7777" },
- { "Saltlake", "saltlake.tardigrade.io:7777" },
- { "Europe West 1", "europe-west-1.tardigrade.io:7777" },
- { "Europe North 1", "europe-north-1.tardigrade.io:7777" },
- };
-
- public static readonly Dictionary<string, string> KNOWN_AUTHENTICATION_METHODS = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase){
- { "API key", "API key" },
- { "Access grant", "Access grant" },
- };
-
- [DllImport("kernel32.dll")]
- protected static extern IntPtr LoadLibrary(string filename);
-
- private static bool _libraryLoaded = false;
- private static void InitStorjLibrary()
- {
- if (_libraryLoaded)
- return;
- if (Duplicati.Library.Common.Platform.IsClientWindows) //We need to init only on Windows to distinguish between x64 and x86
- {
- if (System.Environment.Is64BitProcess)
- {
- var res = LoadLibrary("win-x64/storj_uplink.dll");
- }
- else
- {
- var res = LoadLibrary("win-x86/storj_uplink.dll");
- }
- }
- Access.SetTempDirectory(Library.Utility.TempFolder.SystemTempPath);
- _libraryLoaded = true;
- }
+ private const string PROTOCOL_KEY = "tardigrade";
// ReSharper disable once UnusedMember.Global
// This constructor is needed by the BackendLoader.
- public Tardigrade()
+ public Tardigrade():base()
{
}
// ReSharper disable once UnusedMember.Global
// This constructor is needed by the BackendLoader.
- public Tardigrade(string url, Dictionary<string, string> options)
+ public Tardigrade(string url, Dictionary<string, string> options) :base(url, options)
{
- InitStorjLibrary();
-
- var auth_method = options[TARDIGRADE_AUTH_METHOD];
- if (auth_method == "Access grant")
- {
- //Create an access from the access grant
- var shared_access = options[TARDIGRADE_SHARED_ACCESS];
- _access = new Access(shared_access, new Config() { UserAgent = TARDIGRADE_PARTNER_ID });
- }
- else
- {
- //Create an access for a satellite, API key and encryption passphrase
- _satellite = options[TARDIGRADE_SATELLITE];
-
- if (options.ContainsKey(TARDIGRADE_API_KEY))
- {
- _api_key = options[TARDIGRADE_API_KEY];
- }
- if (options.ContainsKey(TARDIGRADE_SECRET))
- {
- _secret = options[TARDIGRADE_SECRET];
- }
-
- _access = new Access(_satellite, _api_key, _secret, new Config() { UserAgent = TARDIGRADE_PARTNER_ID });
- }
-
- _bucketService = new BucketService(_access);
- _objectService = new ObjectService(_access);
-
- //If no bucket was provided use the default "duplicati"-bucket
- if (options.ContainsKey(TARDIGRADE_BUCKET))
- {
- _bucket = options[TARDIGRADE_BUCKET];
- }
- else
- {
- _bucket = "duplicati";
- }
-
- if (options.ContainsKey(TARDIGRADE_FOLDER))
- {
- _folder = options[TARDIGRADE_FOLDER];
- }
}
- public string DisplayName
+ public new string DisplayName
{
get { return Strings.Tardigrade.DisplayName; }
}
- public string ProtocolKey => PROTOCOL_KEY;
+ public new string ProtocolKey => PROTOCOL_KEY;
- public IList<ICommandLineArgument> SupportedCommands
+ public new IList<ICommandLineArgument> SupportedCommands
{
get
{
return new List<ICommandLineArgument>(new ICommandLineArgument[] {
- new CommandLineArgument(TARDIGRADE_AUTH_METHOD, CommandLineArgument.ArgumentType.String, Strings.Tardigrade.TardigradeAuthMethodDescriptionShort, Strings.Tardigrade.TardigradeAuthMethodDescriptionLong, "API key"),
- new CommandLineArgument(TARDIGRADE_SATELLITE, CommandLineArgument.ArgumentType.String, Strings.Tardigrade.TardigradeSatelliteDescriptionShort, Strings.Tardigrade.TardigradeSatelliteDescriptionLong, "us-central-1.tardigrade.io:7777"),
- new CommandLineArgument(TARDIGRADE_API_KEY, CommandLineArgument.ArgumentType.String, Strings.Tardigrade.TardigradeAPIKeyDescriptionShort, Strings.Tardigrade.TardigradeAPIKeyDescriptionLong),
- new CommandLineArgument(TARDIGRADE_SECRET, CommandLineArgument.ArgumentType.Password, Strings.Tardigrade.TardigradeSecretDescriptionShort, Strings.Tardigrade.TardigradeSecretDescriptionLong),
- new CommandLineArgument(TARDIGRADE_SHARED_ACCESS, CommandLineArgument.ArgumentType.String, Strings.Tardigrade.TardigradeSharedAccessDescriptionShort, Strings.Tardigrade.TardigradeSharedAccessDescriptionLong),
- new CommandLineArgument(TARDIGRADE_BUCKET, CommandLineArgument.ArgumentType.String, Strings.Tardigrade.TardigradeBucketDescriptionShort, Strings.Tardigrade.TardigradeBucketDescriptionLong),
- new CommandLineArgument(TARDIGRADE_FOLDER, CommandLineArgument.ArgumentType.String, Strings.Tardigrade.TardigradeFolderDescriptionShort, Strings.Tardigrade.TardigradeFolderDescriptionLong),
+ new CommandLineArgument(TARDIGRADE_AUTH_METHOD, CommandLineArgument.ArgumentType.String, Strings.Storj.StorjAuthMethodDescriptionShort, Strings.Storj.StorjAuthMethodDescriptionLong, "API key", null, null),
+ new CommandLineArgument(TARDIGRADE_SATELLITE, CommandLineArgument.ArgumentType.String, Strings.Storj.StorjSatelliteDescriptionShort, Strings.Storj.StorjSatelliteDescriptionLong, "us1.storj.io:7777", null, null),
+ new CommandLineArgument(TARDIGRADE_API_KEY, CommandLineArgument.ArgumentType.String, Strings.Storj.StorjAPIKeyDescriptionShort, Strings.Storj.StorjAPIKeyDescriptionLong, null, null, null),
+ new CommandLineArgument(TARDIGRADE_SECRET, CommandLineArgument.ArgumentType.Password, Strings.Storj.StorjSecretDescriptionShort, Strings.Storj.StorjSecretDescriptionLong, null, null, null),
+ new CommandLineArgument(TARDIGRADE_SHARED_ACCESS, CommandLineArgument.ArgumentType.String, Strings.Storj.StorjSharedAccessDescriptionShort, Strings.Storj.StorjSharedAccessDescriptionLong, null, null, null),
+ new CommandLineArgument(TARDIGRADE_BUCKET, CommandLineArgument.ArgumentType.String, Strings.Storj.StorjBucketDescriptionShort, Strings.Storj.StorjBucketDescriptionLong, null, null, null),
+ new CommandLineArgument(TARDIGRADE_FOLDER, CommandLineArgument.ArgumentType.String, Strings.Storj.StorjFolderDescriptionShort, Strings.Storj.StorjFolderDescriptionLong, null, null, null),
});
}
}
- public string Description
+ public new string Description
{
get
{
return Strings.Tardigrade.Description;
}
}
-
- public string[] DNSName
- {
- get
- {
- return new string[0];
- }
- }
-
- public void CreateFolder()
- {
- //Tardigrade has no folders
- }
-
- public void Delete(string remotename)
- {
- var deleteTask = DeleteAsync(remotename);
- deleteTask.Wait();
- }
-
- public async Task DeleteAsync(string remotename)
- {
- try
- {
- var bucket = await _bucketService.EnsureBucketAsync(_bucket);
- await _objectService.DeleteObjectAsync(bucket, GetBasePath() + remotename);
- }
- catch (Exception root)
- {
- throw new FileMissingException(root);
- }
- }
-
- public void Dispose()
- {
- if (_objectService != null)
- {
- _objectService = null;
- }
- if (_bucketService != null)
- {
- _bucketService = null;
- }
- if (_access != null)
- {
- _access.Dispose();
- _access = null;
- }
- }
-
- public void Get(string remotename, string filename)
- {
- var getTask = GetAsync(remotename, filename);
- getTask.Wait();
- }
-
- public async Task GetAsync(string remotename, string filename)
- {
- var bucket = await _bucketService.EnsureBucketAsync(_bucket);
- var download = await _objectService.DownloadObjectAsync(bucket, GetBasePath() + remotename, new DownloadOptions(), false);
- await download.StartDownloadAsync();
-
- if (download.Completed)
- {
- using (FileStream file = new FileStream(filename, FileMode.Create))
- {
- await file.WriteAsync(download.DownloadedBytes, 0, (int)download.BytesReceived);
- await file.FlushAsync().ConfigureAwait(false);
- }
- }
- }
-
- public void Get(string remotename, Stream stream)
- {
- var getTask = GetAsync(remotename, stream);
- getTask.Wait();
- }
-
- public async Task GetAsync(string remotename, Stream stream)
- {
- int index = 0;
- var bucket = await _bucketService.EnsureBucketAsync(_bucket);
- var download = await _objectService.DownloadObjectAsync(bucket, GetBasePath() + remotename, new DownloadOptions(), false);
- download.DownloadOperationProgressChanged += (op) =>
- {
- int newPartLength = (int)op.BytesReceived - index;
- byte[] newPart = new byte[newPartLength];
- Array.Copy(op.DownloadedBytes, index, newPart, 0, newPartLength);
- stream.Write(newPart, 0, newPartLength);
- index = index + newPartLength;
- };
- await download.StartDownloadAsync();
- }
-
- public IEnumerable<IFileEntry> List()
- {
- var listTask = ListAsync();
- listTask.Wait();
- return listTask.Result;
- }
-
- private async Task<IEnumerable<IFileEntry>> ListAsync()
- {
- List<TardigradeFile> files = new List<TardigradeFile>();
- var bucket = await _bucketService.EnsureBucketAsync(_bucket);
- var prefix = GetBasePath();
- var objects = await _objectService.ListObjectsAsync(bucket, new ListObjectsOptions { Recursive = true, System = true, Custom = true, Prefix = prefix });
-
- foreach (var obj in objects.Items)
- {
- TardigradeFile file = new TardigradeFile(obj);
- if (prefix != "")
- {
- file.Name = file.Name.Replace(prefix, "");
- }
- files.Add(file);
- }
-
- return files;
- }
-
- public async Task PutAsync(string remotename, string filename, CancellationToken cancelToken)
- {
- using (FileStream fs = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
- await PutAsync(remotename, fs, cancelToken);
- }
-
- public async Task PutAsync(string remotename, Stream stream, CancellationToken cancelToken)
- {
- var bucket = await _bucketService.EnsureBucketAsync(_bucket);
- CustomMetadata custom = new CustomMetadata();
- custom.Entries.Add(new CustomMetadataEntry { Key = TardigradeFile.TARDIGRADE_LAST_ACCESS, Value = DateTime.Now.ToUniversalTime().ToString("O") });
- custom.Entries.Add(new CustomMetadataEntry { Key = TardigradeFile.TARDIGRADE_LAST_MODIFICATION, Value = DateTime.Now.ToUniversalTime().ToString("O") });
- var upload = await _objectService.UploadObjectAsync(bucket, GetBasePath() + remotename, new UploadOptions(), stream, custom, false);
- await upload.StartUploadAsync();
- }
-
- public void Test()
- {
- var testTask = TestAsync();
- testTask.Wait(10000);
- if (!testTask.Result)
- {
- throw new Exception(Strings.Tardigrade.TestConnectionFailed);
- }
- }
-
- /// <summary>
- /// Test the connection by:
- /// - creating the bucket (if it not already exists)
- /// - uploading 256 random bytes to a test-file
- /// - downloading the file back and expecting 256 bytes
- /// </summary>
- /// <returns>true, if the test was successfull or and exception</returns>
- private async Task<bool> TestAsync()
- {
- string testFileName = GetBasePath() + "duplicati_test.dat";
-
- var bucket = await _bucketService.EnsureBucketAsync(_bucket);
- var upload = await _objectService.UploadObjectAsync(bucket, testFileName, new UploadOptions(), GetRandomBytes(256), false);
- await upload.StartUploadAsync();
-
- var download = await _objectService.DownloadObjectAsync(bucket, testFileName, new DownloadOptions(), false);
- await download.StartDownloadAsync();
-
- await _objectService.DeleteObjectAsync(bucket, testFileName);
-
- if (download.Failed || download.BytesReceived != 256)
- {
- throw new Exception(download.ErrorMessage);
- }
-
- return true;
- }
-
- /// <summary>
- /// Gets the base path - depending on there is a folder set or not
- /// </summary>
- /// <returns>The base path within a bucket where the backup shall be placed</returns>
- private string GetBasePath()
- {
- if (!string.IsNullOrEmpty(_folder))
- return _folder + "/";
- else
- return "";
- }
-
- /// <summary>
- /// Creates some random bytes with the given length - just for testing the connection
- /// </summary>
- /// <param name="length">The length of the bytes to create</param>
- /// <returns>A byte-array with the given length</returns>
- private static byte[] GetRandomBytes(long length)
- {
- byte[] bytes = new byte[length];
- Random rand = new Random();
- rand.NextBytes(bytes);
-
- return bytes;
- }
}
}
diff --git a/Duplicati/Library/Backend/Tardigrade/packages.config b/Duplicati/Library/Backend/Tardigrade/packages.config
index 51d5eec31..983b0e7cc 100644
--- a/Duplicati/Library/Backend/Tardigrade/packages.config
+++ b/Duplicati/Library/Backend/Tardigrade/packages.config
@@ -1,4 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
- <package id="uplink.NET" version="2.3.4" targetFramework="net471" />
+ <package id="sqlite-net-pcl" version="1.7.335" targetFramework="net471" />
+ <package id="SQLitePCLRaw.bundle_green" version="2.0.3" targetFramework="net471" />
+ <package id="SQLitePCLRaw.core" version="2.0.3" targetFramework="net471" />
+ <package id="SQLitePCLRaw.lib.e_sqlite3" version="2.0.3" targetFramework="net471" />
+ <package id="SQLitePCLRaw.provider.dynamic_cdecl" version="2.0.3" targetFramework="net471" />
+ <package id="System.Buffers" version="4.4.0" targetFramework="net471" />
+ <package id="System.Memory" version="4.5.3" targetFramework="net471" />
+ <package id="System.Numerics.Vectors" version="4.4.0" targetFramework="net471" />
+ <package id="System.Runtime.CompilerServices.Unsafe" version="4.5.2" targetFramework="net471" />
+ <package id="uplink.NET" version="2.7.1604" targetFramework="net471" />
</packages> \ No newline at end of file
diff --git a/Duplicati/Library/Backend/TencentCOS/COSBackend.cs b/Duplicati/Library/Backend/TencentCOS/COSBackend.cs
index 59d5a719b..5951c50b3 100644
--- a/Duplicati/Library/Backend/TencentCOS/COSBackend.cs
+++ b/Duplicati/Library/Backend/TencentCOS/COSBackend.cs
@@ -196,10 +196,10 @@ namespace Duplicati.Library.Backend.TencentCOS
}
}
- public Task PutAsync(string remotename, string filename, CancellationToken cancelToken)
+ public async Task PutAsync(string remotename, string filename, CancellationToken cancelToken)
{
using (FileStream fs = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
- return PutAsync(remotename, fs, cancelToken);
+ await PutAsync(remotename, fs, cancelToken);
}
public void Get(string remotename, string filename)
diff --git a/Duplicati/Library/Backend/WEBDAV/WEBDAV.cs b/Duplicati/Library/Backend/WEBDAV/WEBDAV.cs
index 5e1f0b205..1f40b8f00 100644
--- a/Duplicati/Library/Backend/WEBDAV/WEBDAV.cs
+++ b/Duplicati/Library/Backend/WEBDAV/WEBDAV.cs
@@ -256,10 +256,10 @@ namespace Duplicati.Library.Backend
return files;
}
- public Task PutAsync(string remotename, string filename, CancellationToken cancelToken)
+ public async Task PutAsync(string remotename, string filename, CancellationToken cancelToken)
{
using (System.IO.FileStream fs = System.IO.File.OpenRead(filename))
- return PutAsync(remotename, fs, cancelToken);
+ await PutAsync(remotename, fs, cancelToken);
}
public void Get(string remotename, string filename)
diff --git a/Duplicati/Library/Interface/CustomExceptions.cs b/Duplicati/Library/Interface/CustomExceptions.cs
index 2e0c90262..1dbc0ff63 100644
--- a/Duplicati/Library/Interface/CustomExceptions.cs
+++ b/Duplicati/Library/Interface/CustomExceptions.cs
@@ -183,4 +183,20 @@ namespace Duplicati.Library.Interface
AbortReason = reason;
}
}
+
+ /// <summary>
+ /// An exception indicating that verification of uploaded volumes has failed
+ /// due to extra, missing, or duplicate files.
+ /// </summary>
+ [Serializable]
+ public class RemoteListVerificationException : UserInformationException
+ {
+ public RemoteListVerificationException(string message, string helpId)
+ : base(message, helpId)
+ {}
+
+ public RemoteListVerificationException(string message, string helpId, Exception innerException)
+ : base(message, helpId, innerException)
+ {}
+ }
}
diff --git a/Duplicati/Library/Main/Controller.cs b/Duplicati/Library/Main/Controller.cs
index 18669a994..5b319fab3 100644
--- a/Duplicati/Library/Main/Controller.cs
+++ b/Duplicati/Library/Main/Controller.cs
@@ -816,8 +816,12 @@ namespace Duplicati.Library.Main
if (string.Equals(m_options.CompressionModule, "7z", StringComparison.OrdinalIgnoreCase))
Logging.Log.WriteWarningMessage(LOGTAG, "7zModuleHasIssues", null, "The 7z compression module has known issues and should only be used for experimental purposes");
- //TODO: Based on the action, see if all options are relevant
- }
+ //Inform the user about the deprecated Tardigrade-Backend. They should switch to Storj DCS instead.
+ if (string.Equals(new Library.Utility.Uri(m_backend).Scheme, "tardigrade", StringComparison.OrdinalIgnoreCase))
+ Logging.Log.WriteWarningMessage(LOGTAG, "TardigradeRename", null, "The Tardigrade-backend got renamed to Storj DCS - please migrate your backups to the new configuration by changing the destination storage type to Storj DCS.");
+
+ //TODO: Based on the action, see if all options are relevant
+ }
/// <summary>
/// Helper method that expands the users chosen source input paths,
diff --git a/Duplicati/Library/Main/Operation/BackupHandler.cs b/Duplicati/Library/Main/Operation/BackupHandler.cs
index f78246cdd..ef12b94e8 100644
--- a/Duplicati/Library/Main/Operation/BackupHandler.cs
+++ b/Duplicati/Library/Main/Operation/BackupHandler.cs
@@ -156,7 +156,7 @@ namespace Duplicati.Library.Main.Operation
else
FilelistProcessor.VerifyRemoteList(backend, m_options, m_database, m_result.BackendWriter, new string[] { protectedfile });
}
- catch (Exception ex)
+ catch (RemoteListVerificationException ex)
{
if (m_options.AutoCleanup)
{
diff --git a/Duplicati/Library/Main/Operation/FilelistProcessor.cs b/Duplicati/Library/Main/Operation/FilelistProcessor.cs
index 643c0110f..0652020d8 100644
--- a/Duplicati/Library/Main/Operation/FilelistProcessor.cs
+++ b/Duplicati/Library/Main/Operation/FilelistProcessor.cs
@@ -113,7 +113,7 @@ namespace Duplicati.Library.Main.Operation
{
var s = string.Format("Found {0} remote files that are not recorded in local storage, please run repair", extraCount);
Logging.Log.WriteErrorMessage(LOGTAG, "ExtraRemoteFiles", null, s);
- throw new Duplicati.Library.Interface.UserInformationException(s, "ExtraRemoteFiles");
+ throw new RemoteListVerificationException(s, "ExtraRemoteFiles");
}
ISet<string> doubles;
@@ -123,7 +123,7 @@ namespace Duplicati.Library.Main.Operation
{
var s = string.Format("Found remote files reported as duplicates, either the backend module is broken or you need to manually remove the extra copies.\nThe following files were found multiple times: {0}", string.Join(", ", doubles));
Logging.Log.WriteErrorMessage(LOGTAG, "DuplicateRemoteFiles", null, s);
- throw new Duplicati.Library.Interface.UserInformationException(s, "DuplicateRemoteFiles");
+ throw new RemoteListVerificationException(s, "DuplicateRemoteFiles");
}
if (missingCount > 0)
@@ -135,7 +135,7 @@ namespace Duplicati.Library.Main.Operation
s = string.Format("Found {0} files that are missing from the remote storage, please run repair", missingCount);
Logging.Log.WriteErrorMessage(LOGTAG, "MissingRemoteFiles", null, s);
- throw new Duplicati.Library.Interface.UserInformationException(s, "MissingRemoteFiles");
+ throw new RemoteListVerificationException(s, "MissingRemoteFiles");
}
}
@@ -279,7 +279,7 @@ namespace Duplicati.Library.Main.Operation
if (e.Value == RemoteVolumeState.Uploading || e.Value == RemoteVolumeState.Temporary)
database.UnlinkRemoteVolume(e.Key, e.Value);
else
- throw new Exception(string.Format("The remote volume {0} appears in the database with state {1} and a deleted state, cannot continue", e.Key, e.Value.ToString()));
+ throw new RemoteListVerificationException(string.Format("The remote volume {0} appears in the database with state {1} and a deleted state, cannot continue", e.Key, e.Value.ToString()), "AmbiguousStateRemoteFiles");
}
var locallist = database.GetRemoteVolumes();
diff --git a/Duplicati/Library/Modules/Builtin/Duplicati.Library.Modules.Builtin.csproj b/Duplicati/Library/Modules/Builtin/Duplicati.Library.Modules.Builtin.csproj
index e6c962ce9..559c21c80 100644
--- a/Duplicati/Library/Modules/Builtin/Duplicati.Library.Modules.Builtin.csproj
+++ b/Duplicati/Library/Modules/Builtin/Duplicati.Library.Modules.Builtin.csproj
@@ -38,9 +38,6 @@
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
- <Reference Include="BouncyCastle.Crypto, Version=1.8.5.0, Culture=neutral, PublicKeyToken=0e99375e54769942">
- <HintPath>..\..\..\..\packages\BouncyCastle.1.8.5\lib\BouncyCastle.Crypto.dll</HintPath>
- </Reference>
<Reference Include="MailKit, Version=2.3.0.0, Culture=neutral, PublicKeyToken=4e064fe7c44a8f1b, processorArchitecture=MSIL">
<HintPath>..\..\..\..\packages\MailKit.2.3.1.6\lib\net46\MailKit.dll</HintPath>
</Reference>
diff --git a/Duplicati/Library/Modules/Builtin/packages.config b/Duplicati/Library/Modules/Builtin/packages.config
index 5733784ee..743c5b29d 100644
--- a/Duplicati/Library/Modules/Builtin/packages.config
+++ b/Duplicati/Library/Modules/Builtin/packages.config
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
- <package id="BouncyCastle" version="1.8.5" targetFramework="net471" />
<package id="MailKit" version="2.3.1.6" targetFramework="net471" />
<package id="MimeKit" version="2.3.1" targetFramework="net471" />
<package id="Newtonsoft.Json" version="12.0.2" targetFramework="net471" />
diff --git a/Duplicati/Library/Utility/FilterExpression.cs b/Duplicati/Library/Utility/FilterExpression.cs
index fc4eb1745..60ca22588 100644
--- a/Duplicati/Library/Utility/FilterExpression.cs
+++ b/Duplicati/Library/Utility/FilterExpression.cs
@@ -81,14 +81,15 @@ namespace Duplicati.Library.Utility
/// The multiple wildcard character (DOS style)
/// </summary>
private const char MULTIPLE_WILDCARD = '*';
-
+
/// <summary>
/// The regular expression flags
/// </summary>
private static readonly RegexOptions REGEXP_OPTIONS =
RegexOptions.Compiled |
RegexOptions.ExplicitCapture |
- (Utility.IsFSCaseSensitive ? RegexOptions.None : RegexOptions.IgnoreCase);
+ (Utility.IsFSCaseSensitive ? RegexOptions.None : RegexOptions.IgnoreCase) |
+ RegexOptions.Singleline;
// Since we might need to get the regex for a particular filter group multiple times
// (e.g., when combining multiple FilterExpressions together, which discards the existing FilterEntries and recreates them from the Filter representations),