diff --git a/BreakingChanges.txt b/BreakingChanges.txt
index 80fe1d1a..61661bba 100644
--- a/BreakingChanges.txt
+++ b/BreakingChanges.txt
@@ -1,3 +1,9 @@
+Tracking Breaking Changes since 1.0.0
+ - Added a parameter in SetAttributesCallbackAsync to represent source instance, changed the delegate definition from:
+ public delegate Task SetAttributesCallbackAsync(object)
+ to
+ public delegate Task SetAttributesCallbackAsync(object, object)
+
Tracking Breaking Changes since 0.12.0
- Changed parameter isServiceCopy of bool value to copyMethod which is an enumeration value in interfaces of CopyAsync and CopyDirectoryAsync.
diff --git a/DMLibTest_NetStandard.sln b/DMLibTest_NetStandard.sln
new file mode 100644
index 00000000..4795393f
--- /dev/null
+++ b/DMLibTest_NetStandard.sln
@@ -0,0 +1,49 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29613.14
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DMLibTest", "test\DMLibTest_NetStandard\DMLibTest.csproj", "{2A4656A4-F744-4653-A9D6-15112E9AB352}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Azure.Storage.DataMovement", "netcore\Microsoft.Azure.Storage.DataMovement\Microsoft.Azure.Storage.DataMovement.csproj", "{D52B1401-CF85-441F-9A19-D8A90010306A}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DMLibTestCodeGen", "test\DMLibTestCodeGen\DMLibTestCodeGen.csproj", "{7018EE4E-D389-424E-A8DD-F9B4FFDA5194}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DMTestLib", "test\DMTestLib\DMTestLib.csproj", "{2C79E154-EFD2-4FFD-8A73-5A62A61BC6E5}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MsTestLib", "test\MsTestLib\MsTestLib.csproj", "{AC39B50F-DC27-4411-9ED4-A4A137190ACB}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {2A4656A4-F744-4653-A9D6-15112E9AB352}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2A4656A4-F744-4653-A9D6-15112E9AB352}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2A4656A4-F744-4653-A9D6-15112E9AB352}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2A4656A4-F744-4653-A9D6-15112E9AB352}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D52B1401-CF85-441F-9A19-D8A90010306A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D52B1401-CF85-441F-9A19-D8A90010306A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D52B1401-CF85-441F-9A19-D8A90010306A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D52B1401-CF85-441F-9A19-D8A90010306A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7018EE4E-D389-424E-A8DD-F9B4FFDA5194}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7018EE4E-D389-424E-A8DD-F9B4FFDA5194}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7018EE4E-D389-424E-A8DD-F9B4FFDA5194}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7018EE4E-D389-424E-A8DD-F9B4FFDA5194}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2C79E154-EFD2-4FFD-8A73-5A62A61BC6E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2C79E154-EFD2-4FFD-8A73-5A62A61BC6E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2C79E154-EFD2-4FFD-8A73-5A62A61BC6E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2C79E154-EFD2-4FFD-8A73-5A62A61BC6E5}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AC39B50F-DC27-4411-9ED4-A4A137190ACB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AC39B50F-DC27-4411-9ED4-A4A137190ACB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AC39B50F-DC27-4411-9ED4-A4A137190ACB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AC39B50F-DC27-4411-9ED4-A4A137190ACB}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {1AA31E1E-29C8-467B-B6FE-48F50C90FFCF}
+ EndGlobalSection
+EndGlobal
diff --git a/README.md b/README.md
index c8db4220..060b0c43 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# Microsoft Azure Storage Data Movement Library (1.3.0)
+# Microsoft Azure Storage Data Movement Library (2.0.0)
The Microsoft Azure Storage Data Movement Library designed for high-performance uploading, downloading and copying Azure Storage Blob and File. This library is based on the core data movement framework that powers [AzCopy](https://azure.microsoft.com/documentation/articles/storage-use-azcopy/).
diff --git a/changelog.txt b/changelog.txt
index 4a0a8033..19a495ac 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,3 +1,15 @@
+2020.08.31 Version 2.0.0
+ * All Service on both .Net Framework and .Net Core
+ - Upgraded Microsoft.Azure.Storage.Blob from 11.1.2 to 11.2.2
+ - Upgraded Microsoft.Azure.Storage.File from 11.1.2 to 11.2.2
+ - Added a parameter in SetAttributesCallbackAsync to represent source instance.
+ * Blob Service on both .Net Framework and .Net Core
+ - Added support to set encryption scope when destination is Azure Blob Service.
+ * File Service on both .Net Framework and .Net Core
+ - Added support to preserve preserve file permissions and SMB attributes when copying between Azure File Services.
+ * All Service on .Net Core
+ - Fix an issue of throwing out "illegal character" in some environment without UNC path support.
+
2020.02.26 Version 1.3.0
* All Service on both .Net Framework and .Net Core
- Upgraded Microsoft.Azure.Storage.Blob from 11.1.1 to 11.1.2
diff --git a/lib/DataMovement.csproj b/lib/DataMovement.csproj
index c7f6d3d7..7ee84cae 100644
--- a/lib/DataMovement.csproj
+++ b/lib/DataMovement.csproj
@@ -54,14 +54,14 @@
..\packages\Microsoft.Azure.KeyVault.Core.1.0.0\lib\net40\Microsoft.Azure.KeyVault.Core.dll
-
- ..\packages\Microsoft.Azure.Storage.Blob.11.1.2\lib\net452\Microsoft.Azure.Storage.Blob.dll
+
+ ..\packages\Microsoft.Azure.Storage.Blob.11.2.2\lib\net452\Microsoft.Azure.Storage.Blob.dll
-
- ..\packages\Microsoft.Azure.Storage.Common.11.1.2\lib\net452\Microsoft.Azure.Storage.Common.dll
+
+ ..\packages\Microsoft.Azure.Storage.Common.11.2.2\lib\net452\Microsoft.Azure.Storage.Common.dll
-
- ..\packages\Microsoft.Azure.Storage.File.11.1.2\lib\net452\Microsoft.Azure.Storage.File.dll
+
+ ..\packages\Microsoft.Azure.Storage.File.11.2.2\lib\net452\Microsoft.Azure.Storage.File.dll
..\packages\Microsoft.WindowsAzure.ConfigurationManager.1.8.0.0\lib\net35-full\Microsoft.WindowsAzure.Configuration.dll
diff --git a/lib/Extensions/StorageExtensions.cs b/lib/Extensions/StorageExtensions.cs
index fd2e3fad..e05f666f 100644
--- a/lib/Extensions/StorageExtensions.cs
+++ b/lib/Extensions/StorageExtensions.cs
@@ -41,14 +41,15 @@ internal static bool Equals(
}
internal static CloudFile GenerateCopySourceFile(
- this CloudFile file)
+ this CloudFile file,
+ bool preservePermission)
{
if (null == file)
{
throw new ArgumentNullException("file");
}
- string sasToken = GetFileSASToken(file);
+ string sasToken = GetFileSASToken(file, preservePermission);
if (string.IsNullOrEmpty(sasToken))
{
@@ -58,13 +59,13 @@ internal static CloudFile GenerateCopySourceFile(
return new CloudFile(file.SnapshotQualifiedUri, new StorageCredentials(sasToken));
}
- internal static Uri GenerateCopySourceUri(this CloudFile file)
+ internal static Uri GenerateCopySourceUri(this CloudFile file, bool preservePermission = false)
{
- CloudFile fileForCopy = file.GenerateCopySourceFile();
+ CloudFile fileForCopy = file.GenerateCopySourceFile(preservePermission);
return fileForCopy.ServiceClient.Credentials.TransformUri(fileForCopy.SnapshotQualifiedUri);
}
- private static string GetFileSASToken(CloudFile file)
+ private static string GetFileSASToken(CloudFile file, bool preservePermission)
{
if (null == file.ServiceClient.Credentials
|| file.ServiceClient.Credentials.IsAnonymous)
@@ -85,7 +86,7 @@ private static string GetFileSASToken(CloudFile file)
Permissions = SharedAccessFilePermissions.Read,
};
- return file.GetSharedAccessSignature(policy);
+ return preservePermission ? file.Share.GetSharedAccessSignature(policy) : file.GetSharedAccessSignature(policy);
}
///
diff --git a/lib/FileSecurityOperations.cs b/lib/FileSecurityOperations.cs
index 98238669..d18eb768 100644
--- a/lib/FileSecurityOperations.cs
+++ b/lib/FileSecurityOperations.cs
@@ -320,9 +320,6 @@ public static void SetFileSecurity(string filePath, string portableSDDL, Preserv
return;
}
#endif
-
- filePath = LongPath.ToUncPath(filePath);
-
if (PreserveSMBPermissions.None == preserveSMBPermissions) return;
if (string.IsNullOrEmpty(portableSDDL)) return;
@@ -621,8 +618,6 @@ private static string GetFileSDDL(
string filePath,
NativeMethods.SECURITY_INFORMATION securityInfo)
{
- filePath = LongPath.ToUncPath(filePath);
-
// Note: to get the SACL, special permissions are needed. Refer https://docs.microsoft.com/en-us/windows/win32/api/aclapi/nf-aclapi-getsecurityinfo
IntPtr pZero = IntPtr.Zero;
IntPtr pSid = pZero;
diff --git a/lib/LongPathFile.cs b/lib/LongPathFile.cs
index 779a5127..b3f5db74 100644
--- a/lib/LongPathFile.cs
+++ b/lib/LongPathFile.cs
@@ -15,12 +15,7 @@ internal static partial class LongPathFile
public static bool Exists(string path)
{
#if DOTNET5_4
- string longFilePath = path;
- if (Interop.CrossPlatformHelpers.IsWindows)
- {
- longFilePath = LongPath.ToUncPath(longFilePath);
- }
- return File.Exists(longFilePath);
+ return File.Exists(path);
#else
try
{
@@ -28,7 +23,6 @@ public static bool Exists(string path)
{
return false;
}
- path = LongPath.ToUncPath(path);
bool success = NativeMethods.PathFileExistsW(path);
if (!success)
{
diff --git a/lib/LongPathFileStream.cs b/lib/LongPathFileStream.cs
index 47464062..d3a0cdde 100644
--- a/lib/LongPathFileStream.cs
+++ b/lib/LongPathFileStream.cs
@@ -313,7 +313,6 @@ public static bool Exists(string path)
if (String.IsNullOrEmpty(path))
return false;
- path = LongPath.ToUncPath(path);
bool success = NativeMethods.PathFileExistsW(path);
if (!success)
{
@@ -358,8 +357,6 @@ public static void CreateDirectory(string path)
LongPathDirectory.CreateDirectory(dir);
}
- path = LongPath.ToUncPath(path);
-
if (!NativeMethods.CreateDirectoryW(path, IntPtr.Zero))
NativeMethods.ThrowExceptionForLastWin32ErrorIfExists(new int[] {
NativeMethods.ERROR_SUCCESS,
@@ -512,7 +509,6 @@ public static FileStream Open(string filePath, FileMode mode, FileAccess access,
#if DOTNET5_4
return new FileStream(filePath, mode, access, share);
#else
- filePath = LongPath.ToUncPath(filePath);
SafeFileHandle fileHandle = GetFileHandle(filePath, mode, access, share);
return new FileStream(fileHandle, access);
#endif
@@ -573,7 +569,6 @@ public static void SetAttributes(string path, FileAttributes fileAttributes)
#if DOTNET5_4
File.SetAttributes(path, fileAttributes);
#else
- path = LongPath.ToUncPath(path);
if (!NativeMethods.SetFileAttributesW(path, (uint)(fileAttributes)))
{
NativeMethods.ThrowExceptionForLastWin32ErrorIfExists();
@@ -609,8 +604,6 @@ public static void GetFileProperties(string path, out DateTimeOffset? creationTi
)
{
#if !DOTNET5_4
- path = LongPath.ToUncPath(path);
-
if (path.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal))
{
path = path.Substring(0, path.Length - 1);
@@ -666,7 +659,6 @@ public static void GetFileProperties(string path, out DateTimeOffset? creationTi
public static void SetFileTime(string path, DateTimeOffset creationTimeUtc, DateTimeOffset lastWriteTimeUtc, bool isDirectory = false)
{
#if !DOTNET5_4
- path = LongPath.ToUncPath(path);
SafeFileHandle fileHandle = GetFileHandle(path, FileMode.Open, FileAccess.Write, FileShare.None, isDirectory);
try
diff --git a/lib/TransferCallbacks.cs b/lib/TransferCallbacks.cs
index 6d4a5d85..9e21bc3e 100644
--- a/lib/TransferCallbacks.cs
+++ b/lib/TransferCallbacks.cs
@@ -32,6 +32,7 @@ public delegate Task ShouldTransferCallbackAsync(
/// Callback invoked to set destination's attributes in memory.
/// The attributes set in this callback will be sent to azure storage service.
///
+ /// Source instance in the transfer.
/// Instance of destination to be overwritten.
- public delegate Task SetAttributesCallbackAsync(object destination);
+ public delegate Task SetAttributesCallbackAsync(object source, object destination);
}
diff --git a/lib/TransferConfigurations.cs b/lib/TransferConfigurations.cs
index 02f0f838..05b5804e 100644
--- a/lib/TransferConfigurations.cs
+++ b/lib/TransferConfigurations.cs
@@ -7,6 +7,7 @@ namespace Microsoft.Azure.Storage.DataMovement
{
using System;
using System.Globalization;
+ using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using ClientLibraryConstants = Microsoft.Azure.Storage.Shared.Protocol.Constants;
@@ -46,6 +47,7 @@ public class TransferConfigurations
/// Initializes a new instance of the
/// class.
///
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
public TransferConfigurations()
{
// setup default values.
@@ -54,6 +56,19 @@ public TransferConfigurations()
this.MemoryChunkSize = Constants.DefaultMemoryChunkSize;
this.UpdateMaximumCacheSize(this.blockSize);
+ this.SupportUncPath = false;
+
+ if (Interop.CrossPlatformHelpers.IsWindows)
+ {
+ try
+ {
+ LongPath.GetFullPath("\\\\?\\F:");
+ this.SupportUncPath = true;
+ }
+ catch (Exception)
+ {
+ }
+ }
}
///
@@ -83,6 +98,12 @@ public int ParallelOperations
}
}
+ ///
+ /// Gets or sets a value indicating how many listing works to process concurrently.
+ /// When source is an Azure File directory or local file directory, DataMovement Library would list the directory in parallel.
+ /// This value is to indicate the maximum number of listing works to process in parallel.
+ ///
+ /// How many listing works to process concurrently.
public int? MaxListingConcurrency
{
get
@@ -192,6 +213,16 @@ internal long MaximumCacheSize
}
}
+ ///
+ /// To indicate whether the process environment supports UNC path.
+ ///
+ /// On Windows, it requires to use UNC path to access files/directories with long path.
+ /// In some environment, the .Net Framework only supports legacy path without UNC path support.
+ /// DataMovement Library will detect whether .Net Framework supports UNC path in the process environment
+ /// to determine whether to use UNC path in the following transfers.
+ ///
+ internal bool SupportUncPath { get; private set; }
+
///
/// The size of memory chunk of memory pool
///
diff --git a/lib/TransferControllers/AsyncCopyControllers/BlobAsyncCopyController.cs b/lib/TransferControllers/AsyncCopyControllers/BlobAsyncCopyController.cs
index 04f5d646..5a91ff70 100644
--- a/lib/TransferControllers/AsyncCopyControllers/BlobAsyncCopyController.cs
+++ b/lib/TransferControllers/AsyncCopyControllers/BlobAsyncCopyController.cs
@@ -205,7 +205,7 @@ protected override async Task SetAttributesAsync(SetAttributesCallbackAsync setC
var originalAttributes = Utils.GenerateAttributes(this.destBlob);
var originalMetadata = new Dictionary(this.destBlob.Metadata);
- await setCustomAttributes(this.destBlob);
+ await setCustomAttributes(this.TransferJob.Source.Instance, this.destBlob);
if (!Utils.CompareProperties(originalAttributes, Utils.GenerateAttributes(this.destBlob)))
{
diff --git a/lib/TransferControllers/AsyncCopyControllers/FileAsyncCopyController.cs b/lib/TransferControllers/AsyncCopyControllers/FileAsyncCopyController.cs
index f75f99a1..de8532a3 100644
--- a/lib/TransferControllers/AsyncCopyControllers/FileAsyncCopyController.cs
+++ b/lib/TransferControllers/AsyncCopyControllers/FileAsyncCopyController.cs
@@ -89,6 +89,7 @@ await this.destFile.StartCopyAsync(
this.SourceUri,
null,
null,
+ default(FileCopyOptions),
Utils.GenerateFileRequestOptions(this.destLocation.FileRequestOptions),
operationContext,
this.CancellationToken);
@@ -101,6 +102,7 @@ await this.destFile.StartCopyAsync(
this.SourceBlob.GenerateCopySourceUri(),
null,
null,
+ default(FileCopyOptions),
Utils.GenerateFileRequestOptions(this.destLocation.FileRequestOptions),
operationContext,
this.CancellationToken);
@@ -116,10 +118,24 @@ await this.destFile.StartCopyAsync(
}
else
{
+ var transfer = this.TransferJob.Transfer;
+ FileCopyOptions fileCopyOptions = new FileCopyOptions();
+
+ if (transfer.PreserveSMBAttributes)
+ {
+ fileCopyOptions.PreserveCreationTime = transfer.PreserveSMBAttributes;
+ fileCopyOptions.PreserveLastWriteTime = transfer.PreserveSMBAttributes;
+ fileCopyOptions.PreserveNtfsAttributes = transfer.PreserveSMBAttributes;
+ fileCopyOptions.SetArchive = false;
+ }
+
+ fileCopyOptions.PreservePermissions = (transfer.PreserveSMBPermissions != PreserveSMBPermissions.None);
+
await this.destFile.StartCopyAsync(
- this.SourceFile.GenerateCopySourceUri(),
+ this.SourceFile.GenerateCopySourceUri(fileCopyOptions.PreservePermissions),
null,
null,
+ fileCopyOptions,
Utils.GenerateFileRequestOptions(this.destLocation.FileRequestOptions),
operationContext,
this.CancellationToken);
@@ -155,7 +171,7 @@ protected override async Task SetAttributesAsync(SetAttributesCallbackAsync setC
var originalAttributes = Utils.GenerateAttributes(this.destFile, true);
var originalMetadata = new Dictionary(this.destFile.Metadata);
- await setCustomAttributes(this.destFile);
+ await setCustomAttributes(this.TransferJob.Source.Instance, this.destFile);
if (!Utils.CompareProperties(originalAttributes, Utils.GenerateAttributes(this.destFile, true)))
{
diff --git a/lib/TransferControllers/DummyTransferController.cs b/lib/TransferControllers/DummyTransferController.cs
index bb000a82..10fb89bd 100644
--- a/lib/TransferControllers/DummyTransferController.cs
+++ b/lib/TransferControllers/DummyTransferController.cs
@@ -70,7 +70,8 @@ await Task.Run(
&& this.TransferJob.Destination.Type == TransferLocationType.FilePath)
{
// Dummy transfer for downloading dummy blobs.
- var filePath = (this.TransferJob.Destination as FileLocation).FilePath;
+ var filePath = (this.TransferJob.Destination as FileLocation).FilePath.ToLongPath();
+
if (LongPathFile.Exists(filePath))
{
string exceptionMessage = string.Format(
diff --git a/lib/TransferControllers/ServiceSideSyncCopyControllers/BlockBlobServiceSideSyncCopyController.cs b/lib/TransferControllers/ServiceSideSyncCopyControllers/BlockBlobServiceSideSyncCopyController.cs
index e9c9b9f7..6ed6637a 100644
--- a/lib/TransferControllers/ServiceSideSyncCopyControllers/BlockBlobServiceSideSyncCopyController.cs
+++ b/lib/TransferControllers/ServiceSideSyncCopyControllers/BlockBlobServiceSideSyncCopyController.cs
@@ -256,7 +256,7 @@ protected override async Task CommitAsync()
OverWriteAll = true
});
- await this.SetCustomAttributesAsync(this.destBlockBlob);
+ await this.SetCustomAttributesAsync(this.TransferJob.Source.Instance, this.destBlockBlob);
BlobRequestOptions blobRequestOptions = Utils.GenerateBlobRequestOptions(this.destLocation.BlobRequestOptions);
OperationContext operationContext = Utils.GenerateOperationContext(this.TransferContext);
diff --git a/lib/TransferControllers/ServiceSideSyncCopyControllers/ServiceSideSyncCopyDest/BlobDestHandler.cs b/lib/TransferControllers/ServiceSideSyncCopyControllers/ServiceSideSyncCopyDest/BlobDestHandler.cs
index 1e3fd8e3..e1b21cf2 100644
--- a/lib/TransferControllers/ServiceSideSyncCopyControllers/ServiceSideSyncCopyDest/BlobDestHandler.cs
+++ b/lib/TransferControllers/ServiceSideSyncCopyControllers/ServiceSideSyncCopyDest/BlobDestHandler.cs
@@ -60,37 +60,43 @@ public async Task CheckAndCreateDestinationAsync(
{
bool needCreateDestination = true;
bool gotDestAttributes = false;
- if (!isForceOverwrite)
+
+ // Check access condition here no matter whether force overwrite is true.
+ if (!this.destLocation.CheckedAccessCondition && null != this.destLocation.AccessCondition)
{
- if (this.transferJob.Overwrite.HasValue)
- {
- await checkOverwrite(true);
- }
- else if (!this.destLocation.CheckedAccessCondition && null != this.destLocation.AccessCondition)
+ try
{
- try
+ await this.destBlob.FetchAttributesAsync(
+ Utils.GenerateConditionWithCustomerCondition(this.destLocation.AccessCondition, false),
+ Utils.GenerateBlobRequestOptions(this.destLocation.BlobRequestOptions),
+ Utils.GenerateOperationContext(this.transferContext),
+ cancellationToken);
+
+ // Only try to send the blob creating request, when blob length is not as expected. Otherwise, only need to clear all pages.
+ needCreateDestination = true;
+ this.destLocation.CheckedAccessCondition = true;
+ gotDestAttributes = true;
+
+ if (!isForceOverwrite)
{
- await this.destBlob.FetchAttributesAsync(
- Utils.GenerateConditionWithCustomerCondition(this.destLocation.AccessCondition, false),
- Utils.GenerateBlobRequestOptions(this.destLocation.BlobRequestOptions),
- Utils.GenerateOperationContext(this.transferContext),
- cancellationToken);
-
- // Only try to send the blob creating request, when blob length is not as expected. Otherwise, only need to clear all pages.
- needCreateDestination = (this.destBlob.Properties.Length != totalLength);
- this.destLocation.CheckedAccessCondition = true;
- gotDestAttributes = true;
-
await checkOverwrite(true);
}
- catch (StorageException se)
+ }
+ catch (StorageException se)
+ {
+ if ((null == se.RequestInformation) || ((int)HttpStatusCode.NotFound != se.RequestInformation.HttpStatusCode))
{
- if ((null == se.RequestInformation) || ((int)HttpStatusCode.NotFound != se.RequestInformation.HttpStatusCode))
- {
- throw;
- }
+ throw;
}
}
+ }
+
+ if (!isForceOverwrite)
+ {
+ if (this.transferJob.Overwrite.HasValue)
+ {
+ await checkOverwrite(true);
+ }
else
{
AccessCondition accessCondition = AccessCondition.GenerateIfNoneMatchCondition("*");
@@ -128,14 +134,13 @@ await this.destBlob.FetchAttributesAsync(
if (needCreateDestination)
{
- await this.CreateDestinationAsync(
- totalLength,
- Utils.GenerateConditionWithCustomerCondition(this.destLocation.AccessCondition, this.destLocation.CheckedAccessCondition),
- cancellationToken);
-
this.transferJob.Overwrite = true;
- this.destLocation.CheckedAccessCondition = true;
this.transferJob.Transfer.UpdateJournal();
+
+ await this.CreateDestinationAsync(
+ totalLength,
+ Utils.GenerateConditionWithCustomerCondition(this.destLocation.AccessCondition, true),
+ CancellationToken.None);
}
return gotDestAttributes;
@@ -144,7 +149,7 @@ await this.CreateDestinationAsync(
public virtual async Task CommitAsync(
bool gotDestAttributes,
Attributes sourceAttributes,
- Func