public override void ExecuteCmdlet() { if (AsJob.IsPresent) { DoBeginProcessing(); } string filePath = this.Source; FileInfo localFile = new FileInfo(filePath); if (!localFile.Exists) { throw new FileNotFoundException(string.Format(CultureInfo.CurrentCulture, Resources.SourceFileNotFound, this.Source)); } long fileSize = localFile.Length; // if FIPS policy is enabled, must use native MD5 for DMlib. if (fipsEnabled) { if (fileSize < sizeTB) { CloudStorageAccount.UseV1MD5 = false; } else // use Track2 SDK { WriteWarning("The uploaded file won't have Content MD5 hash, since caculate MD5 hash fail, most possiblly caused by FIPS is enabled on this machine."); } } bool isDirectory; string[] path = NamingUtil.ValidatePath(this.Path, out isDirectory); var cloudFileToBeUploaded = BuildCloudFileInstanceFromPathAsync(localFile.Name, path, isDirectory).ConfigureAwait(false).GetAwaiter().GetResult(); if (ShouldProcess(cloudFileToBeUploaded.Name, "Set file content")) { // Step 2: Build the CloudFile object which pointed to the // destination cloud file. this.RunTask(async taskId => { var progressRecord = new ProgressRecord( this.OutputStream.GetProgressId(taskId), string.Format(CultureInfo.CurrentCulture, Resources.SendAzureFileActivity, localFile.Name, cloudFileToBeUploaded.GetFullPath(), cloudFileToBeUploaded.Share.Name), Resources.PrepareUploadingFile); if (fileSize <= sizeTB) { await DataMovementTransferHelper.DoTransfer(() => this.TransferManager.UploadAsync( localFile.FullName, cloudFileToBeUploaded, new UploadOptions { PreserveSMBAttributes = context is null ? false : context.PreserveSMBAttribute.IsPresent }, this.GetTransferContext(progressRecord, localFile.Length), this.CmdletCancellationToken), progressRecord, this.OutputStream).ConfigureAwait(false); } else // use Track2 SDK { //Create File ShareFileClient fileClient = AzureStorageFile.GetTrack2FileClient(cloudFileToBeUploaded, Channel.StorageContext); // confirm overwrite if file exist if (!this.Force.IsPresent && fileClient.Exists(this.CmdletCancellationToken) && !await this.OutputStream.ConfirmAsync(string.Format(CultureInfo.CurrentCulture, Resources.OverwriteConfirmation, Util.ConvertToString(cloudFileToBeUploaded)))) { return; } await fileClient.CreateAsync(fileSize, cancellationToken: this.CmdletCancellationToken).ConfigureAwait(false); //Prepare progress Handler IProgress <long> progressHandler = new Progress <long>((finishedBytes) => { if (progressRecord != null) { // Size of the source file might be 0, when it is, directly treat the progress as 100 percent. progressRecord.PercentComplete = 0 == fileSize ? 100 : (int)(finishedBytes * 100 / fileSize); progressRecord.StatusDescription = string.Format(CultureInfo.CurrentCulture, Resources.FileTransmitStatus, progressRecord.PercentComplete); this.OutputStream.WriteProgress(progressRecord); } }); long blockSize = 4 * 1024 * 1024; int maxWorkers = 4; List <Task> runningTasks = new List <Task>(); IncrementalHash hash = null; if (!fipsEnabled) { hash = IncrementalHash.CreateHash(HashAlgorithmName.MD5); } using (FileStream stream = File.OpenRead(localFile.FullName)) { byte[] buffer = null; long lastBlockSize = 0; for (long offset = 0; offset < fileSize; offset += blockSize) { long currentBlockSize = offset + blockSize < fileSize ? blockSize : fileSize - offset; // Only need to create new buffer when chunk size change if (currentBlockSize != lastBlockSize) { buffer = new byte[currentBlockSize]; lastBlockSize = currentBlockSize; } await stream.ReadAsync(buffer: buffer, offset: 0, count: (int)currentBlockSize); if (!fipsEnabled && hash != null) { hash.AppendData(buffer); } Task task = UploadFileRangAsync(fileClient, new HttpRange(offset, currentBlockSize), new MemoryStream(buffer), progressHandler); runningTasks.Add(task); // Check if any of upload range tasks are still busy if (runningTasks.Count >= maxWorkers) { await Task.WhenAny(runningTasks).ConfigureAwait(false); // Clear any completed blocks from the task list for (int i = 0; i < runningTasks.Count; i++) { Task runningTask = runningTasks[i]; if (!runningTask.IsCompleted) { continue; } await runningTask.ConfigureAwait(false); runningTasks.RemoveAt(i); i--; } } } // Wait for all upload range tasks finished await Task.WhenAll(runningTasks).ConfigureAwait(false); } // Need set file properties if ((!fipsEnabled && hash != null) || (context != null && context.PreserveSMBAttribute.IsPresent)) { ShareFileHttpHeaders header = null; if (!fipsEnabled && hash != null) { header = new ShareFileHttpHeaders(); header.ContentHash = hash.GetHashAndReset(); } FileSmbProperties smbProperties = null; if (context != null && context.PreserveSMBAttribute.IsPresent) { FileInfo sourceFileInfo = new FileInfo(localFile.FullName); smbProperties = new FileSmbProperties(); smbProperties.FileCreatedOn = sourceFileInfo.CreationTimeUtc; smbProperties.FileLastWrittenOn = sourceFileInfo.LastWriteTimeUtc; smbProperties.FileAttributes = Util.LocalAttributesToAzureFileNtfsAttributes(File.GetAttributes(localFile.FullName)); } // set file header and attributes to the file fileClient.SetHttpHeaders(httpHeaders: header, smbProperties: smbProperties); } if (this.PassThru) { // fetch latest file properties for output cloudFileToBeUploaded.FetchAttributes(); } } if (this.PassThru) { WriteCloudFileObject(taskId, this.Channel, cloudFileToBeUploaded); } });
/// <summary> /// Write CloudFile to output using specified service channel /// </summary> /// <param name="file">The output CloudFile object</param> /// <param name="channel">IStorageFileManagement channel object</param> internal void WriteCloudFileObject(long taskId, IStorageFileManagement channel, CloudFile file) { AzureStorageFile azureFile = new AzureStorageFile(file, channel.StorageContext); OutputStream.WriteObject(taskId, azureFile); }