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:
authorMuhammad Abrar <abrar1984@gmail.com>2022-05-27 13:50:55 +0300
committerMuhammad Abrar <abrar1984@gmail.com>2022-05-27 13:50:55 +0300
commit068eba8538f9cc798ebb6a7baf4b34a6de8930ad (patch)
tree0dbec6b5f355f486337962b2f60197744061e06c
parent93a4e2cb6e60c85357cfad9f1288c9833919a054 (diff)
Added support for new backend IDrivee2(https://www.idrivee2.com)
-rw-r--r--Duplicati.sln10
-rw-r--r--Duplicati/GUI/Duplicati.GUI.TrayIcon/app.config30
-rw-r--r--Duplicati/Library/Backend/Backblaze/Strings.cs6
-rw-r--r--Duplicati/Library/Backend/Dropbox/WebApi.cs2
-rw-r--r--Duplicati/Library/Backend/Idrivee2/Duplicati.Library.Backend.Idrivee2.csproj111
-rw-r--r--Duplicati/Library/Backend/Idrivee2/Duplicati.snkbin0 -> 596 bytes
-rw-r--r--Duplicati/Library/Backend/Idrivee2/Idrivee2Backend.cs249
-rw-r--r--Duplicati/Library/Backend/Idrivee2/Properties/AssemblyInfo.cs54
-rw-r--r--Duplicati/Library/Backend/Idrivee2/Strings.cs17
-rw-r--r--Duplicati/Library/Backend/Idrivee2/app.config6
-rw-r--r--Duplicati/Library/Backend/Idrivee2/packages.config9
-rw-r--r--Duplicati/Server/Duplicati.Server.csproj4
-rw-r--r--Duplicati/Server/WebServer/RESTMethods/ServerSettings.cs6
-rw-r--r--Duplicati/Server/app.config30
-rw-r--r--Duplicati/Server/webroot/ngax/scripts/services/EditUriBuiltins.js74
-rw-r--r--Duplicati/Server/webroot/ngax/scripts/services/SystemInfo.js1
-rw-r--r--Duplicati/Server/webroot/ngax/templates/backends/e2.html18
-rw-r--r--Duplicati/Service/Runner.cs12
-rw-r--r--Duplicati/Service/app.config30
-rwxr-xr-xDuplicati/UnitTest/BackendToolTests.cs114
-rw-r--r--Installer/Docker/README.md2
-rw-r--r--README.md2
22 files changed, 677 insertions, 110 deletions
diff --git a/Duplicati.sln b/Duplicati.sln
index 5f90df87f..d36769dc3 100644
--- a/Duplicati.sln
+++ b/Duplicati.sln
@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 16
-VisualStudioVersion = 16.0.29102.190
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.31919.166
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Library.Utility", "Duplicati\Library\Utility\Duplicati.Library.Utility.csproj", "{DE3E5D4C-51AB-4E5E-BEE8-E636CEBFBA65}"
EndProject
@@ -107,6 +107,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Library.Backend.T
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Library.Backend.Tardigrade", "Duplicati\Library\Backend\Tardigrade\Duplicati.Library.Backend.Tardigrade.csproj", "{9A04CB37-DA72-4008-9703-3AC5191974E9}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Library.Backend.Idrivee2", "Duplicati\Library\Backend\Idrivee2\Duplicati.Library.Backend.Idrivee2.csproj", "{6B594D23-B629-465C-B799-70EE9E56C218}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -321,6 +323,10 @@ Global
{9A04CB37-DA72-4008-9703-3AC5191974E9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9A04CB37-DA72-4008-9703-3AC5191974E9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9A04CB37-DA72-4008-9703-3AC5191974E9}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6B594D23-B629-465C-B799-70EE9E56C218}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6B594D23-B629-465C-B799-70EE9E56C218}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6B594D23-B629-465C-B799-70EE9E56C218}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6B594D23-B629-465C-B799-70EE9E56C218}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/Duplicati/GUI/Duplicati.GUI.TrayIcon/app.config b/Duplicati/GUI/Duplicati.GUI.TrayIcon/app.config
index 9eaab5dd7..f6b2cb0d0 100644
--- a/Duplicati/GUI/Duplicati.GUI.TrayIcon/app.config
+++ b/Duplicati/GUI/Duplicati.GUI.TrayIcon/app.config
@@ -3,19 +3,25 @@
<startup useLegacyV2RuntimeActivationPolicy="true"><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.1" /></startup>
<runtime>
<AppContextSwitchOverrides value="Switch.System.IO.UseLegacyPathHandling=false" />
+
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
- <dependentAssembly>
- <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
- <bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0" />
- </dependentAssembly>
- <dependentAssembly>
- <assemblyIdentity name="Microsoft.Azure.KeyVault.Core" publicKeyToken="31bf3856ad364e35" culture="neutral" />
- <bindingRedirect oldVersion="0.0.0.0-3.0.4.0" newVersion="3.0.4.0" />
- </dependentAssembly>
- <dependentAssembly>
- <assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
- <bindingRedirect oldVersion="0.0.0.0-4.1.1.3" newVersion="4.2.0.0" />
- </dependentAssembly>
+
+ <dependentAssembly>
+
+ <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
+
+ <bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0" />
+
+ </dependentAssembly>
+
+ <dependentAssembly>
+
+ <assemblyIdentity name="Microsoft.Azure.KeyVault.Core" publicKeyToken="31bf3856ad364e35" culture="neutral" />
+
+ <bindingRedirect oldVersion="0.0.0.0-3.0.4.0" newVersion="3.0.4.0" />
+
+ </dependentAssembly>
+
</assemblyBinding>
</runtime>
</configuration>
diff --git a/Duplicati/Library/Backend/Backblaze/Strings.cs b/Duplicati/Library/Backend/Backblaze/Strings.cs
index 168553757..b4d0b2429 100644
--- a/Duplicati/Library/Backend/Backblaze/Strings.cs
+++ b/Duplicati/Library/Backend/Backblaze/Strings.cs
@@ -14,9 +14,9 @@ namespace Duplicati.Library.Backend.Strings {
public static string NoB2UserIDError { get { return LC.L(@"No ""B2 Cloud Storage Account ID"" given"); } }
public static string Description { get { return LC.L(@"This backend can read and write data to the Backblaze B2 Cloud Storage. Allowed formats are: ""b2://bucketname/prefix"""); } }
public static string B2createbuckettypeDescriptionLong { get { return LC.L(@"By default, a private bucket is created. Use this option to set the bucket type. Refer to the B2 documentation for allowed types "); } }
- public static string B2createbuckettypeDescriptionShort { get { return LC.L(@"The bucket type used when creating a bucket"); } }
- public static string B2pagesizeDescriptionLong { get { return LC.L(@"Use this option to set the page size for listing contents of B2 buckets. A lower number means less data, but can increase the number of Class C transaction on B2. Suggested values are between 100 and 1000"); } }
- public static string B2pagesizeDescriptionShort { get { return LC.L(@"The size of file-listing pages"); } }
+ public static string B2createbuckettypeDescriptionShort { get { return LC.L(@"The bucket type used when creating a bucket"); } }
+ public static string B2pagesizeDescriptionLong { get { return LC.L(@"Use this option to set the page size for listing contents of B2 buckets. A lower number means less data, but can increase the number of Class C transaction on B2. Suggested values are between 100 and 1000"); } }
+ public static string B2pagesizeDescriptionShort { get { return LC.L(@"The size of file-listing pages"); } }
public static string B2downloadurlDescriptionLong { get { return LC.L(@"Change this if you want to use your custom domain to download files, and uploading will not be affected. The default download url depends on your account and looks like ""https://f00X.backblazeb2.com"""); } }
public static string B2downloadurlDescriptionShort { get { return LC.L(@"The base URL to use for downloading files"); } }
public static string InvalidPageSizeError(string argname, string value) { return LC.L(@"The setting ""{0}"" is invalid for ""{1}"", it must be an integer larger than zero", value, argname); }
diff --git a/Duplicati/Library/Backend/Dropbox/WebApi.cs b/Duplicati/Library/Backend/Dropbox/WebApi.cs
index 1d0f2af86..376dd4ec9 100644
--- a/Duplicati/Library/Backend/Dropbox/WebApi.cs
+++ b/Duplicati/Library/Backend/Dropbox/WebApi.cs
@@ -41,7 +41,7 @@ namespace Duplicati.Library.Backend.WebApi
return Uri.UriBuilder(Url.API, Path.DeleteFolder);
}
- public static string UploadSessionStartUrl()
+ public static string UploadSessionStartUrl()
{
return Uri.UriBuilder(Url.CONTENT_API_URL, Path.UploadSessionStart);
}
diff --git a/Duplicati/Library/Backend/Idrivee2/Duplicati.Library.Backend.Idrivee2.csproj b/Duplicati/Library/Backend/Idrivee2/Duplicati.Library.Backend.Idrivee2.csproj
new file mode 100644
index 000000000..1447efbf7
--- /dev/null
+++ b/Duplicati/Library/Backend/Idrivee2/Duplicati.Library.Backend.Idrivee2.csproj
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="15.0">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{6B594D23-B629-465C-B799-70EE9E56C218}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Duplicati.Library.Backend</RootNamespace>
+ <AssemblyName>Duplicati.Library.Backend.idrivee2</AssemblyName>
+ <AssemblyOriginatorKeyFile>Duplicati.snk</AssemblyOriginatorKeyFile>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <TargetFrameworkVersion>v4.7.1</TargetFrameworkVersion>
+ <TargetFrameworkProfile />
+ <OldToolsVersion>3.5</OldToolsVersion>
+ <UpgradeBackupLocation>
+ </UpgradeBackupLocation>
+ <UseMSBuildEngine>false</UseMSBuildEngine>
+ </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>
+ </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>
+ <PropertyGroup>
+ <SignAssembly>false</SignAssembly>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="AWSSDK.Core, Version=3.3.0.0, Culture=neutral, PublicKeyToken=885c28607f98e604, processorArchitecture=MSIL">
+ <HintPath>..\..\..\..\packages\AWSSDK.Core.3.3.103.37\lib\net45\AWSSDK.Core.dll</HintPath>
+ </Reference>
+ <Reference Include="AWSSDK.S3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=885c28607f98e604, processorArchitecture=MSIL">
+ <HintPath>..\..\..\..\packages\AWSSDK.S3.3.3.104.25\lib\net45\AWSSDK.S3.dll</HintPath>
+ </Reference>
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="RestSharp, Version=106.3.1.0, Culture=neutral, PublicKeyToken=598062e77f915f75">
+ <HintPath>..\..\..\..\packages\RestSharp.106.3.1\lib\net452\RestSharp.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.Reactive, Version=4.0.0.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263">
+ <HintPath>..\..\..\..\packages\System.Reactive.4.0.0\lib\net46\System.Reactive.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="System.Reactive.Linq, Version=3.0.3000.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263">
+ <HintPath>..\..\..\..\packages\System.Reactive.Linq.4.0.0\lib\net46\System.Reactive.Linq.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="System.Web" />
+ <Reference Include="System.Windows" />
+ <Reference Include="System.Windows.Forms" />
+ <Reference Include="WindowsBase" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Idrivee2Backend.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="Strings.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\Utility\Duplicati.Library.Utility.csproj">
+ <Project>{DE3E5D4C-51AB-4E5E-BEE8-E636CEBFBA65}</Project>
+ <Name>Duplicati.Library.Utility</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="..\..\Logging\Duplicati.Library.Logging.csproj">
+ <Project>{D10A5FC0-11B4-4E70-86AA-8AEA52BD9798}</Project>
+ <Name>Duplicati.Library.Logging</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\Common\Duplicati.Library.Common.csproj">
+ <Project>{D63E53E4-A458-4C2F-914D-92F715F58ACF}</Project>
+ <Name>Duplicati.Library.Common</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\S3\Duplicati.Library.Backend.S3.csproj">
+ <Project>{C03F6DFD-805A-4BE0-9338-64870ADDB4A2}</Project>
+ <Name>Duplicati.Library.Backend.S3</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="app.config" />
+ <None Include="Duplicati.snk" />
+ <None Include="packages.config" />
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project> \ No newline at end of file
diff --git a/Duplicati/Library/Backend/Idrivee2/Duplicati.snk b/Duplicati/Library/Backend/Idrivee2/Duplicati.snk
new file mode 100644
index 000000000..e0c1e2dd8
--- /dev/null
+++ b/Duplicati/Library/Backend/Idrivee2/Duplicati.snk
Binary files differ
diff --git a/Duplicati/Library/Backend/Idrivee2/Idrivee2Backend.cs b/Duplicati/Library/Backend/Idrivee2/Idrivee2Backend.cs
new file mode 100644
index 000000000..aef41259b
--- /dev/null
+++ b/Duplicati/Library/Backend/Idrivee2/Idrivee2Backend.cs
@@ -0,0 +1,249 @@
+#region Disclaimer / License
+// Copyright (C) 2015, The Duplicati Team
+// http://www.duplicati.com, info@duplicati.com
+//
+// 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 Duplicati.Library.Common.IO;
+using Duplicati.Library.Interface;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Duplicati.Library.Backend
+{
+ public class Idrivee2Backend : IBackend, IStreamingBackend
+ {
+ private static readonly string LOGTAG = Logging.Log.LogTagFromType<Idrivee2Backend>();
+
+ static Idrivee2Backend()
+ {
+
+ }
+
+ private readonly string m_prefix;
+ private readonly string m_bucket;
+
+ private IS3Client m_s3Client;
+
+ public Idrivee2Backend()
+ {
+ }
+
+ public Idrivee2Backend(string url, Dictionary<string, string> options)
+ {
+ var uri = new Utility.Uri(url);
+ m_bucket = uri.Host;
+ m_prefix = uri.Path;
+ m_prefix = m_prefix.Trim();
+ if (m_prefix.Length != 0)
+ {
+ m_prefix = Util.AppendDirSeparator(m_prefix, "/");
+ }
+ string accessKeyId = null;
+ string accessKeySecret = null;
+
+ if (options.ContainsKey("auth-username"))
+ accessKeyId = options["auth-username"];
+ if (options.ContainsKey("auth-password"))
+ accessKeySecret = options["auth-password"];
+
+ if (options.ContainsKey("access_key_id"))
+ accessKeyId = options["access_key_id"];
+ if (options.ContainsKey("secret_access_key"))
+ accessKeySecret = options["secret_access_key"];
+
+ if (string.IsNullOrEmpty(accessKeyId))
+ throw new UserInformationException(Strings.Idrivee2Backend.NoKeyIdError, "Idrivee2NoKeyId");
+ if (string.IsNullOrEmpty(accessKeySecret))
+ throw new UserInformationException(Strings.Idrivee2Backend.NoKeySecretError, "Idrivee2NoKeySecret");
+ string host= GetRegionEndpoint("https://api.idrivee2.com/api/service/get_region_end_point/" + accessKeyId);
+
+
+ m_s3Client = new S3AwsClient(accessKeyId, accessKeySecret, null, host, null, true, options);
+
+ }
+
+ public string GetRegionEndpoint(string url)
+ {
+ try
+ {
+ System.Net.HttpWebRequest req = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(url);
+ req.Method = System.Net.WebRequestMethods.Http.Get;
+
+ Utility.AsyncHttpRequest areq = new Utility.AsyncHttpRequest(req);
+
+ using (System.Net.HttpWebResponse resp = (System.Net.HttpWebResponse)areq.GetResponse())
+ {
+ int code = (int)resp.StatusCode;
+ if (code < 200 || code >= 300) //For some reason Mono does not throw this automatically
+ throw new Exception("Failed to fetch region endpoint");
+ using (var s = areq.GetResponseStream())
+ {
+ using (var reader = new StreamReader(s))
+ {
+ string endpoint = reader.ReadToEnd();
+ return endpoint;
+ }
+ }
+ }
+ }
+ catch (System.Net.WebException wex)
+ {
+ //Convert to better exception
+ throw new Exception("Failed to fetch region endpoint");
+ }
+ }
+
+ #region IBackend Members
+
+ public string DisplayName
+ {
+ get { return Strings.Idrivee2Backend.DisplayName; }
+ }
+
+ public string ProtocolKey => "e2";
+
+ public bool SupportsStreaming => true;
+
+
+ public IEnumerable<IFileEntry> List()
+ {
+ foreach (IFileEntry file in Connection.ListBucket(m_bucket, m_prefix))
+ {
+ ((FileEntry)file).Name = file.Name.Substring(m_prefix.Length);
+ if (file.Name.StartsWith("/", StringComparison.Ordinal) && !m_prefix.StartsWith("/", StringComparison.Ordinal))
+ ((FileEntry)file).Name = file.Name.Substring(1);
+
+ yield return file;
+ }
+ }
+
+ public async Task PutAsync(string remotename, string localname, CancellationToken cancelToken)
+ {
+ using (FileStream fs = File.Open(localname, FileMode.Open, FileAccess.Read, FileShare.Read))
+ await PutAsync(remotename, fs, cancelToken);
+ }
+
+ public async Task PutAsync(string remotename, Stream input, CancellationToken cancelToken)
+ {
+ await Connection.AddFileStreamAsync(m_bucket, GetFullKey(remotename), input, cancelToken);
+ }
+
+ public void Get(string remotename, string localname)
+ {
+ using (var fs = File.Open(localname, FileMode.Create, FileAccess.Write, FileShare.None))
+ Get(remotename, fs);
+ }
+
+ public void Get(string remotename, Stream output)
+ {
+ Connection.GetFileStream(m_bucket, GetFullKey(remotename), output);
+ }
+
+ public void Delete(string remotename)
+ {
+ Connection.DeleteObject(m_bucket, GetFullKey(remotename));
+ }
+
+ public IList<ICommandLineArgument> SupportedCommands
+ {
+ get
+ {
+
+ var defaults = new Amazon.S3.AmazonS3Config();
+
+ var exts =
+ typeof(Amazon.S3.AmazonS3Config).GetProperties().Where(x => x.CanRead && x.CanWrite && (x.PropertyType == typeof(string) || x.PropertyType == typeof(bool) || x.PropertyType == typeof(int) || x.PropertyType == typeof(long) || x.PropertyType.IsEnum))
+ .Select(x => (ICommandLineArgument)new CommandLineArgument(
+ "s3-ext-" + x.Name.ToLowerInvariant(),
+ x.PropertyType == typeof(bool) ? CommandLineArgument.ArgumentType.Boolean : x.PropertyType.IsEnum ? CommandLineArgument.ArgumentType.Enumeration : CommandLineArgument.ArgumentType.String,
+ x.Name,
+ string.Format("Extended option {0}", x.Name),
+ string.Format("{0}", x.GetValue(defaults)),
+ null,
+ x.PropertyType.IsEnum ? Enum.GetNames(x.PropertyType) : null));
+
+
+ var normal = new ICommandLineArgument[] {
+
+ new CommandLineArgument("access_key_secret", CommandLineArgument.ArgumentType.Password, Strings.Idrivee2Backend.KeySecretDescriptionShort, Strings.Idrivee2Backend.KeySecretDescriptionLong, null, new[]{"auth-password"}, null),
+ new CommandLineArgument("access_key_id", CommandLineArgument.ArgumentType.String, Strings.Idrivee2Backend.KeyIDDescriptionShort, Strings.Idrivee2Backend.KeyIDDescriptionLong,null, new[]{"auth-username"}, null)
+
+ };
+
+ return normal.Union(exts).ToList();
+
+ }
+ }
+
+ public string Description
+ {
+ get
+ {
+ return Strings.Idrivee2Backend.Description;
+ }
+ }
+
+ public void Test()
+ {
+ this.TestList();
+ }
+
+ public void CreateFolder()
+ {
+ //S3 does not complain if the bucket already exists
+ Connection.AddBucket(m_bucket);
+ }
+
+ #endregion
+
+ #region IRenameEnabledBackend Members
+
+ public void Rename(string source, string target)
+ {
+ Connection.RenameFile(m_bucket, GetFullKey(source), GetFullKey(target));
+ }
+
+ #endregion
+
+ #region IDisposable Members
+
+ public void Dispose()
+ {
+ m_s3Client?.Dispose();
+ m_s3Client = null;
+ }
+
+ #endregion
+
+ private IS3Client Connection => m_s3Client;
+
+ public string[] DNSName
+ {
+ get { return new[] { m_s3Client.GetDnsHost() }; }
+ }
+
+ private string GetFullKey(string name)
+ {
+ //AWS SDK encodes the filenames correctly
+ return m_prefix + name;
+ }
+ }
+}
diff --git a/Duplicati/Library/Backend/Idrivee2/Properties/AssemblyInfo.cs b/Duplicati/Library/Backend/Idrivee2/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..e169e70d0
--- /dev/null
+++ b/Duplicati/Library/Backend/Idrivee2/Properties/AssemblyInfo.cs
@@ -0,0 +1,54 @@
+#region Disclaimer / License
+// Copyright (C) 2015, The Duplicati Team
+// http://www.duplicati.com, info@duplicati.com
+//
+// 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.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("S3")]
+[assembly: AssemblyDescription("An S3-compatible backend for Duplicati")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Duplicati Team")]
+[assembly: AssemblyProduct("Duplicati.Backend.S3")]
+[assembly: AssemblyCopyright("LGPL, Copyright © Duplicati Team 2015")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("afa68988-4d82-490e-8044-acbc7d52ef4f")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
+[assembly: AssemblyVersion("2.0.0.7")]
+[assembly: AssemblyFileVersion("2.0.0.7")]
diff --git a/Duplicati/Library/Backend/Idrivee2/Strings.cs b/Duplicati/Library/Backend/Idrivee2/Strings.cs
new file mode 100644
index 000000000..f80a5f159
--- /dev/null
+++ b/Duplicati/Library/Backend/Idrivee2/Strings.cs
@@ -0,0 +1,17 @@
+using Duplicati.Library.Localization.Short;
+namespace Duplicati.Library.Backend.Strings {
+ internal static class Idrivee2Backend {
+ public static string KeySecretDescriptionLong { get { return LC.L(@"The ""Access Key Secret "" can be obtained after logging into your IDrive e2 account, this can also be supplied through the ""auth-password"" property."); } }
+ public static string KeySecretDescriptionShort { get { return LC.L(@"The ""Access Key Secret"""); } }
+ public static string KeyIDDescriptionLong { get { return LC.L(@"The ""Access Key ID"" can be obtained after logging into your IDrive e2 account., this can also be supplied through the ""auth-username"" property."); } }
+ public static string KeyIDDescriptionShort { get { return LC.L(@"The ""Access Key ID"""); } }
+
+ public static string BucketNameOrPathDescriptionLong { get { return LC.L(@"The ""Bucket Name or Complete Path"" is name of target bucket or complete of a folder inside the bucket."); } }
+ public static string BucketNameOrPathDescriptionShort { get { return LC.L(@"The ""Bucket Name or Complete Path"""); } }
+
+ public static string DisplayName { get { return LC.L(@"IDrive e2"); } }
+ public static string NoKeySecretError { get { return LC.L(@"No Access key secret given"); } }
+ public static string NoKeyIdError { get { return LC.L(@"No Access key Id given"); } }
+ public static string Description { get; set; }
+ }
+}
diff --git a/Duplicati/Library/Backend/Idrivee2/app.config b/Duplicati/Library/Backend/Idrivee2/app.config
new file mode 100644
index 000000000..ba98fc967
--- /dev/null
+++ b/Duplicati/Library/Backend/Idrivee2/app.config
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+ <startup>
+ <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.1"/>
+ </startup>
+</configuration>
diff --git a/Duplicati/Library/Backend/Idrivee2/packages.config b/Duplicati/Library/Backend/Idrivee2/packages.config
new file mode 100644
index 000000000..52f490cda
--- /dev/null
+++ b/Duplicati/Library/Backend/Idrivee2/packages.config
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="AWSSDK.Core" version="3.3.103.37" targetFramework="net471" />
+ <package id="AWSSDK.S3" version="3.3.104.25" targetFramework="net471" />
+ <package id="Minio" version="3.1.7" targetFramework="net471" />
+ <package id="RestSharp" version="106.3.1" targetFramework="net471" />
+ <package id="System.Reactive" version="4.0.0" targetFramework="net471" />
+ <package id="System.Reactive.Linq" version="4.0.0" targetFramework="net471" />
+</packages> \ No newline at end of file
diff --git a/Duplicati/Server/Duplicati.Server.csproj b/Duplicati/Server/Duplicati.Server.csproj
index c0697798d..f661556c9 100644
--- a/Duplicati/Server/Duplicati.Server.csproj
+++ b/Duplicati/Server/Duplicati.Server.csproj
@@ -168,6 +168,10 @@
<Project>{F61679A9-E5DE-468A-B5A4-05F92D0143D2}</Project>
<Name>Duplicati.Library.Backend.FTP</Name>
</ProjectReference>
+ <ProjectReference Include="..\Library\Backend\Idrivee2\Duplicati.Library.Backend.Idrivee2.csproj">
+ <Project>{6b594d23-b629-465c-b799-70ee9e56c218}</Project>
+ <Name>Duplicati.Library.Backend.Idrivee2</Name>
+ </ProjectReference>
<ProjectReference Include="..\Library\Backend\Jottacloud\Duplicati.Library.Backend.Jottacloud.csproj">
<Project>{2cd5dbc3-3da6-432d-ba97-f0b8d24501c2}</Project>
<Name>Duplicati.Library.Backend.Jottacloud</Name>
diff --git a/Duplicati/Server/WebServer/RESTMethods/ServerSettings.cs b/Duplicati/Server/WebServer/RESTMethods/ServerSettings.cs
index 1df9d13cf..cb09037d8 100644
--- a/Duplicati/Server/WebServer/RESTMethods/ServerSettings.cs
+++ b/Duplicati/Server/WebServer/RESTMethods/ServerSettings.cs
@@ -75,10 +75,10 @@ namespace Duplicati.Server.WebServer.RESTMethods
var serversettings = data.Where(x => !string.IsNullOrWhiteSpace(x.Key)).ToDictionary(x => x.Key, x => x.Key.StartsWith("--", StringComparison.Ordinal) ? null : x.Value);
var globalsettings = data.Where(x => !string.IsNullOrWhiteSpace(x.Key) && x.Key.StartsWith("--", StringComparison.Ordinal));
- serversettings.Remove("server-ssl-certificate");
- serversettings.Remove("ServerSSLCertificate");
+ serversettings.Remove("server-ssl-certificate");
+ serversettings.Remove("ServerSSLCertificate");
- if (serversettings.Any())
+ if (serversettings.Any())
Program.DataConnection.ApplicationSettings.UpdateSettings(serversettings, false);
if (globalsettings.Any())
diff --git a/Duplicati/Server/app.config b/Duplicati/Server/app.config
index 9eaab5dd7..de0fd923e 100644
--- a/Duplicati/Server/app.config
+++ b/Duplicati/Server/app.config
@@ -3,19 +3,25 @@
<startup useLegacyV2RuntimeActivationPolicy="true"><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.1" /></startup>
<runtime>
<AppContextSwitchOverrides value="Switch.System.IO.UseLegacyPathHandling=false" />
+
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
- <dependentAssembly>
- <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
- <bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0" />
- </dependentAssembly>
- <dependentAssembly>
- <assemblyIdentity name="Microsoft.Azure.KeyVault.Core" publicKeyToken="31bf3856ad364e35" culture="neutral" />
- <bindingRedirect oldVersion="0.0.0.0-3.0.4.0" newVersion="3.0.4.0" />
- </dependentAssembly>
- <dependentAssembly>
- <assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
- <bindingRedirect oldVersion="0.0.0.0-4.1.1.3" newVersion="4.2.0.0" />
- </dependentAssembly>
+
+ <dependentAssembly>
+
+ <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
+
+ <bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0" />
+
+ </dependentAssembly>
+
+ <dependentAssembly>
+
+ <assemblyIdentity name="Microsoft.Azure.KeyVault.Core" publicKeyToken="31bf3856ad364e35" culture="neutral" />
+
+ <bindingRedirect oldVersion="0.0.0.0-3.0.4.0" newVersion="3.0.4.0" />
+
+ </dependentAssembly>
+
</assemblyBinding>
</runtime>
</configuration>
diff --git a/Duplicati/Server/webroot/ngax/scripts/services/EditUriBuiltins.js b/Duplicati/Server/webroot/ngax/scripts/services/EditUriBuiltins.js
index 63a94b64d..e8e90ffda 100644
--- a/Duplicati/Server/webroot/ngax/scripts/services/EditUriBuiltins.js
+++ b/Duplicati/Server/webroot/ngax/scripts/services/EditUriBuiltins.js
@@ -33,6 +33,7 @@ backupApp.service('EditUriBuiltins', function (AppService, AppUtils, SystemInfo,
EditUriBackendConfig.templates['tardigrade'] = 'templates/backends/tardigrade.html';
EditUriBackendConfig.templates['rclone'] = 'templates/backends/rclone.html';
EditUriBackendConfig.templates['cos'] = 'templates/backends/cos.html';
+ EditUriBackendConfig.templates['e2'] = 'templates/backends/e2.html';
EditUriBackendConfig.testers['s3'] = function(scope, callback) {
@@ -478,6 +479,17 @@ backupApp.service('EditUriBuiltins', function (AppService, AppUtils, SystemInfo,
delete options[nukeopts[x]];
};
+ EditUriBackendConfig.parsers['e2'] = function (scope, module, server, port, path, options) {
+ if (options['--access-key-id'])
+ scope.Username = options['--access-key-id'];
+ if (options['--access-key-secret'])
+ scope.Password = options['--access-key-secret'];
+
+ var nukeopts = ['--access-key-id', '--access-key-secret'];
+ for (var x in nukeopts)
+ delete options[nukeopts[x]];
+ };
+
EditUriBackendConfig.parsers['mega'] = function (scope, module, server, port, path, options) {
EditUriBackendConfig.mergeServerAndPath(scope);
};
@@ -759,6 +771,24 @@ backupApp.service('EditUriBuiltins', function (AppService, AppUtils, SystemInfo,
return url;
};
+ EditUriBackendConfig.builders['e2'] = function (scope) {
+ var opts = {};
+
+ EditUriBackendConfig.merge_in_advanced_options(scope, opts);
+
+ // Slightly better error message
+ scope.Folder = scope.Server;
+
+ var url = AppUtils.format('{0}://{1}/{2}{3}',
+ scope.Backend.Key,
+ scope.Server || '',
+ scope.Path || '',
+ AppUtils.encodeDictAsUrl(opts)
+ );
+
+ return url;
+ };
+
EditUriBackendConfig.builders['mega'] = function (scope) {
var opts = {};
@@ -1272,4 +1302,48 @@ backupApp.service('EditUriBuiltins', function (AppService, AppUtils, SystemInfo,
if (res)
continuation();
};
+
+ EditUriBackendConfig.validaters['e2'] = function (scope, continuation) {
+ var res =
+ EditUriBackendConfig.require_field(scope, 'Username', gettextCatalog.getString('Idrivee2 Access Key Id')) &&
+ EditUriBackendConfig.require_field(scope, 'Password', gettextCatalog.getString('Idrivee2 Access Key Secret')) &&
+ EditUriBackendConfig.require_field(scope, 'Server', gettextCatalog.getString('Bucket Name'));
+
+ if (res) {
+ var re = new RegExp('[^A-Za-z0-9-]');
+ var bucketname = scope['Server'] || '';
+ var ix = bucketname.search(/[^A-Za-z0-9-]/g);
+
+ if (ix >= 0) {
+ EditUriBackendConfig.show_error_dialog(gettextCatalog.getString('The \'{{fieldname}}\' field contains an invalid character: {{character}} (value: {{value}}, index: {{pos}})', {
+ value: bucketname[ix].charCodeAt(),
+ pos: ix,
+ character: bucketname[ix],
+ fieldname: gettextCatalog.getString('Bucket Name')
+ }));
+ res = false;
+ }
+ }
+
+ if (res) {
+ var pathname = scope['Path'] || '';
+ for (var i = pathname.length - 1; i >= 0; i--) {
+ var char = pathname.charCodeAt(i);
+
+ if (char == '\\'.charCodeAt(0) || char == 127 || char < 32) {
+ EditUriBackendConfig.show_error_dialog(gettextCatalog.getString('The \'{{fieldname}}\' field contains an invalid character: {{character}} (value: {{value}}, index: {{pos}})', {
+ value: char,
+ pos: i,
+ character: pathname[i],
+ fieldname: gettextCatalog.getString('Path')
+ }));
+ res = false;
+ break;
+ }
+ }
+ }
+
+ if (res)
+ continuation();
+ };
});
diff --git a/Duplicati/Server/webroot/ngax/scripts/services/SystemInfo.js b/Duplicati/Server/webroot/ngax/scripts/services/SystemInfo.js
index b6b4e4e52..7569b5eab 100644
--- a/Duplicati/Server/webroot/ngax/scripts/services/SystemInfo.js
+++ b/Duplicati/Server/webroot/ngax/scripts/services/SystemInfo.js
@@ -53,6 +53,7 @@ backupApp.service('SystemInfo', function($rootScope, $timeout, $cookies, AppServ
},
local: {'file': null},
prop: {
+ 'e2':null,
's3': null,
'azure': null,
'googledrive': null,
diff --git a/Duplicati/Server/webroot/ngax/templates/backends/e2.html b/Duplicati/Server/webroot/ngax/templates/backends/e2.html
new file mode 100644
index 000000000..86af8a762
--- /dev/null
+++ b/Duplicati/Server/webroot/ngax/templates/backends/e2.html
@@ -0,0 +1,18 @@
+<div class="input text">
+ <label for="e2_access_key" translate>Access Key Id</label>
+ <input type="text" name="e2_access_key" id="e2_access_key" ng-model="$parent.Username" placeholder="{{'Idrivee2 Access Id' | translate}}" />
+</div>
+<div class="input password">
+ <label for="e2_access_secret" translate>Access Key Secret</label>
+ <input autocomplete="new-password" type="password" name="e2_access_secret" id="e2_access_secret" ng-model="$parent.Password" placeholder="{{'Idrivee2 Access Secret' | translate}}" />
+</div>
+
+<div class="input text">
+ <label for="e2_bucket" translate>Bucket name</label>
+ <input type="text" id="b2_bucket" ng-model="$parent.Server" placeholder="{{'Bucket name' | translate}}" />
+</div>
+
+<div class="input text">
+ <label for="e2_path" translate>Folder path</label>
+ <input type="text" name="e2_path" id="e2_path" ng-model="$parent.Path" placeholder="{{'Path or subfolder in the bucket' | translate}}" />
+</div>
diff --git a/Duplicati/Service/Runner.cs b/Duplicati/Service/Runner.cs
index 4f2ae0f76..3922f7910 100644
--- a/Duplicati/Service/Runner.cs
+++ b/Duplicati/Service/Runner.cs
@@ -79,13 +79,13 @@ namespace Duplicati.Service
m_reportMessage(string.Format("Starting process {0} with cmd args {1}", exec, cmdargs), false);
- var pr = new System.Diagnostics.ProcessStartInfo(exec, cmdargs)
- {
- UseShellExecute = false,
- RedirectStandardInput = true,
+ var pr = new System.Diagnostics.ProcessStartInfo(exec, cmdargs)
+ {
+ UseShellExecute = false,
+ RedirectStandardInput = true,
RedirectStandardOutput = true,
- RedirectStandardError = false,
- WorkingDirectory = path
+ RedirectStandardError = false,
+ WorkingDirectory = path
};
if (!m_terminate)
diff --git a/Duplicati/Service/app.config b/Duplicati/Service/app.config
index f8e90b9d2..157aa09a9 100644
--- a/Duplicati/Service/app.config
+++ b/Duplicati/Service/app.config
@@ -5,19 +5,25 @@
</startup>
<runtime>
<AppContextSwitchOverrides value="Switch.System.IO.UseLegacyPathHandling=false" />
+
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
- <dependentAssembly>
- <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
- <bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0" />
- </dependentAssembly>
- <dependentAssembly>
- <assemblyIdentity name="Microsoft.Azure.KeyVault.Core" publicKeyToken="31bf3856ad364e35" culture="neutral" />
- <bindingRedirect oldVersion="0.0.0.0-3.0.4.0" newVersion="3.0.4.0" />
- </dependentAssembly>
- <dependentAssembly>
- <assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
- <bindingRedirect oldVersion="0.0.0.0-4.1.1.3" newVersion="4.2.0.0" />
- </dependentAssembly>
+
+ <dependentAssembly>
+
+ <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
+
+ <bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0" />
+
+ </dependentAssembly>
+
+ <dependentAssembly>
+
+ <assemblyIdentity name="Microsoft.Azure.KeyVault.Core" publicKeyToken="31bf3856ad364e35" culture="neutral" />
+
+ <bindingRedirect oldVersion="0.0.0.0-3.0.4.0" newVersion="3.0.4.0" />
+
+ </dependentAssembly>
+
</assemblyBinding>
</runtime>
</configuration>
diff --git a/Duplicati/UnitTest/BackendToolTests.cs b/Duplicati/UnitTest/BackendToolTests.cs
index 6c4b17122..420166cdb 100755
--- a/Duplicati/UnitTest/BackendToolTests.cs
+++ b/Duplicati/UnitTest/BackendToolTests.cs
@@ -1,58 +1,58 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using Duplicati.Library.Interface;
-using Duplicati.Library.Main;
-using NUnit.Framework;
-
-namespace Duplicati.UnitTest
-{
- [TestFixture]
- public class BackendToolTests : BasicSetupHelper
- {
- [Test]
- [Category("BackendTool")]
- public void Get()
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using Duplicati.Library.Interface;
+using Duplicati.Library.Main;
+using NUnit.Framework;
+
+namespace Duplicati.UnitTest
+{
+ [TestFixture]
+ public class BackendToolTests : BasicSetupHelper
+ {
+ [Test]
+ [Category("BackendTool")]
+ public void Get()
{
- // Files to create in MB.
- int[] fileSizes = {10, 20, 30};
- foreach (int size in fileSizes)
- {
- var data = new byte[size * 1024 * 1024];
- var rng = new Random();
- rng.NextBytes(data);
- File.WriteAllBytes(Path.Combine(DATAFOLDER, size + "MB"), data);
- }
-
- // Run a backup.
- var options = new Dictionary<string, string>(TestOptions);
- var backendURL = "file://" + this.TARGETFOLDER;
- using (Controller c = new Controller(backendURL, options, null))
- {
- var backupResults = c.Backup(new[] {DATAFOLDER});
- Assert.AreEqual(0, backupResults.Errors.Count());
- Assert.AreEqual(0, backupResults.Warnings.Count());
- }
-
- // Get the backend files using absolute paths
- var absoluteDownloadFolder = Path.Combine(RESTOREFOLDER, "target-files-absolute");
- Directory.CreateDirectory(absoluteDownloadFolder);
- foreach (var targetFile in Directory.GetFiles(TARGETFOLDER))
- {
- // Absolute path
+ // Files to create in MB.
+ int[] fileSizes = {10, 20, 30};
+ foreach (int size in fileSizes)
+ {
+ var data = new byte[size * 1024 * 1024];
+ var rng = new Random();
+ rng.NextBytes(data);
+ File.WriteAllBytes(Path.Combine(DATAFOLDER, size + "MB"), data);
+ }
+
+ // Run a backup.
+ var options = new Dictionary<string, string>(TestOptions);
+ var backendURL = "file://" + this.TARGETFOLDER;
+ using (Controller c = new Controller(backendURL, options, null))
+ {
+ var backupResults = c.Backup(new[] {DATAFOLDER});
+ Assert.AreEqual(0, backupResults.Errors.Count());
+ Assert.AreEqual(0, backupResults.Warnings.Count());
+ }
+
+ // Get the backend files using absolute paths
+ var absoluteDownloadFolder = Path.Combine(RESTOREFOLDER, "target-files-absolute");
+ Directory.CreateDirectory(absoluteDownloadFolder);
+ foreach (var targetFile in Directory.GetFiles(TARGETFOLDER))
+ {
+ // Absolute path
var downloadFileName = Path.Combine(absoluteDownloadFolder, Path.GetFileName(targetFile));
var status = CommandLine.BackendTool.Program.RealMain(new[] { "GET", $"{backendURL}", $"{downloadFileName}" });
- Assert.AreEqual(0, status);
- Assert.IsTrue(File.Exists(downloadFileName));
- TestUtils.AssertFilesAreEqual(targetFile, downloadFileName, false, downloadFileName);
- }
-
- // Get the backend files using relative paths
- var relativeDownloadFolder = Path.Combine(RESTOREFOLDER, "target-files-relative");
- Directory.CreateDirectory(relativeDownloadFolder);
- var originalCurrentDirectory = Directory.GetCurrentDirectory();
- Directory.SetCurrentDirectory(relativeDownloadFolder);
+ Assert.AreEqual(0, status);
+ Assert.IsTrue(File.Exists(downloadFileName));
+ TestUtils.AssertFilesAreEqual(targetFile, downloadFileName, false, downloadFileName);
+ }
+
+ // Get the backend files using relative paths
+ var relativeDownloadFolder = Path.Combine(RESTOREFOLDER, "target-files-relative");
+ Directory.CreateDirectory(relativeDownloadFolder);
+ var originalCurrentDirectory = Directory.GetCurrentDirectory();
+ Directory.SetCurrentDirectory(relativeDownloadFolder);
try
{
foreach (var targetFile in Directory.GetFiles(TARGETFOLDER))
@@ -63,12 +63,12 @@ namespace Duplicati.UnitTest
Assert.AreEqual(0, status);
Assert.IsTrue(File.Exists(downloadFileName));
TestUtils.AssertFilesAreEqual(targetFile, downloadFileName, false, downloadFileName);
- }
- }
- finally
+ }
+ }
+ finally
{
- Directory.SetCurrentDirectory(originalCurrentDirectory);
- }
+ Directory.SetCurrentDirectory(originalCurrentDirectory);
+ }
}
}
} \ No newline at end of file
diff --git a/Installer/Docker/README.md b/Installer/Docker/README.md
index 3928c17d5..e905ed620 100644
--- a/Installer/Docker/README.md
+++ b/Installer/Docker/README.md
@@ -1,7 +1,7 @@
# [Duplicati](https://www.duplicati.com)
Duplicati is a free, open source, backup client that securely stores encrypted, incremental, compressed backups on cloud storage services and remote file servers. It works with:
-*Amazon S3, OneDrive, Google Drive, Rackspace Cloud Files, HubiC, Backblaze (B2), Swift / OpenStack, WebDAV, SSH (SFTP), FTP, and more!*
+*Amazon S3, IDrive e2, OneDrive, Google Drive, Rackspace Cloud Files, HubiC, Backblaze (B2), Swift / OpenStack, WebDAV, SSH (SFTP), FTP, and more!*
Duplicati is licensed under LGPL and available for Windows, OSX and Linux (.NET 4.7.1+ or Mono 4.8.0+ required).
diff --git a/README.md b/README.md
index 4200e63b8..a0eec245a 100644
--- a/README.md
+++ b/README.md
@@ -21,7 +21,7 @@ Removed Gitter
Duplicati is a free, open source, backup client that securely stores encrypted, incremental, compressed backups on cloud storage services and remote file servers. It works with:
-&nbsp;&nbsp; *Amazon S3, [Backblaze (B2)](https://www.backblaze.com/blog/duplicati-backups-cloud-storage/ "Duplicati with Backblaze B2 Cloud Storage"), Box, Dropbox, FTP, Google Cloud and Drive, HubiC, MEGA, Microsoft Azure and OneDrive, Rackspace Cloud Files, OpenStack Storage (Swift), Sia, Storj DCS, SSH (SFTP), WebDAV, Tencent Cloud Object Storage (COS), [and more!](https://duplicati.readthedocs.io/en/latest/01-introduction/#supported-backends)*
+&nbsp;&nbsp; *Amazon S3, [IDrive e2](https://www.idrive.com/e2/duplicati "Using Duplicati with IDrive e2"), [Backblaze (B2)](https://www.backblaze.com/blog/duplicati-backups-cloud-storage/ "Duplicati with Backblaze B2 Cloud Storage"), Box, Dropbox, FTP, Google Cloud and Drive, HubiC, MEGA, Microsoft Azure and OneDrive, Rackspace Cloud Files, OpenStack Storage (Swift), Sia, Storj DCS, SSH (SFTP), WebDAV, Tencent Cloud Object Storage (COS), [and more!](https://duplicati.readthedocs.io/en/latest/01-introduction/#supported-backends)*
Duplicati is licensed under LGPL and available for Windows, OSX and Linux (.NET 4.7.1+ or Mono 5.10.0+ required).