FileShareTransferCommand
using Polly;
using Relativity.Transfer.Enumeration.Native;
using Relativity.Transfer.Exceptions;
using Relativity.Transfer.Extensions;
using Relativity.Transfer.FileShare.Issues;
using Relativity.Transfer.FileShare.Resources;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Threading;
namespace Relativity.Transfer.FileShare
{
internal class FileShareTransferCommand : TransferPathCommandBase
{
private readonly FileShareClientConfiguration ;
private bool? ;
private bool? ;
private bool? ;
private readonly FileshareTransferIssueBuilderFactory ;
private bool {
get {
if (!copyDirectories.HasValue)
copyDirectories = configuration.CopyDirectories;
return copyDirectories.Value;
}
}
private bool {
get {
if (!copySubDirectories.HasValue)
copySubDirectories = configuration.CopySubDirectories;
return copySubDirectories.Value;
}
}
private bool {
get {
if (!overWriteFiles.HasValue)
overWriteFiles = configuration.OverwriteFiles;
return overWriteFiles.Value;
}
}
public FileShareTransferCommand(ITransferLog log, ITransferRequest request, ITransferJobService jobService, IFileSystemService fileSystemService, FileShareClientConfiguration configuration)
: base(log, request, jobService, fileSystemService, configuration)
{
if (log == null)
throw new ArgumentNullException("log");
if (request == null)
throw new ArgumentNullException("request");
if (configuration == null)
throw new ArgumentNullException("configuration");
this.configuration = configuration;
copySubDirectories = configuration.CopySubDirectories;
overWriteFiles = configuration.OverwriteFiles;
issueBuilderFactory = new FileshareTransferIssueBuilderFactory(this.configuration);
}
protected override void (CancellationToken token)
{
if (!token.IsCancellationRequested) {
if (string.IsNullOrWhiteSpace(configuration.FileShareUncPath))
throw new TransferException(FileShareStrings.WorkspaceFileShareEmptyExceptionMessage);
IRetryStrategy retryStrategy = RetryStrategies.CreateFixedTimeStrategy(1);
int retryCount = 0;
RetrySyntax.WaitAndRetry(Policy.Handle<Exception>(), 3, retryStrategy.Calculation, (Action<Exception, TimeSpan, Context>)delegate(Exception exception, TimeSpan timespan, Context context) {
base.Log.LogTransferWarning(exception, base.Request, "Retry - {Timespan} - File Share pre-execute failed.", timespan);
base.Log.LogError(FileShareStrings.WorkspaceFileShareValidationMessage, configuration.FileShareUncPath, LogRedaction.OnPositions(default(int)));
ITransferIssue issue = issueBuilderFactory.Create().CreateFromErrorMessage("The workspace UNC path validation check failed - check logs for more details.").WithAttributes(IssueAttributes.Warning)
.WithMaxRetryAttempts(base.Configuration.MaxJobRetryAttempts)
.WithRetryAttempt(retryCount)
.Build();
RegisterIssue(issue);
retryCount++;
}).Execute((Action)delegate {
if (base.FileSystemService.DirectoryExists(configuration.FileShareUncPath))
return;
base.Log.LogError(FileShareStrings.WorkspaceFileShareInvalidExceptionMessage, configuration.FileShareUncPath, LogRedaction.OnPositions(default(int)));
throw new TransferException("Workspace file share is not accessible - check logs for more details.", true);
});
}
}
protected override TransferPathResult (TransferPath path, CancellationToken token)
{
if (path == (TransferPath)null)
throw new ArgumentNullException("path");
TransferPathResult transferPathResult = new TransferPathResult {
Path = path,
Status = TransferPathStatus.Started
};
if (!token.IsCancellationRequested)
try {
if (!base.FileSystemService.DirectoryExists(path.TargetPath))
base.FileSystemService.CreateDirectory(path.TargetPath);
string destination = (!string.IsNullOrEmpty(path.TargetFileName)) ? base.FileSystemService.Combine(path.TargetPath, path.TargetFileName) : base.FileSystemService.Combine(path.TargetPath, base.FileSystemService.GetFileName(path.SourcePath));
LargeFileProgress progress = (base.LargeFileProgressProvider != null) ? new LargeFileProgress(OnLargeFileProgress, base.LargeFileProgressRateSeconds) : null;
Transfer(path, path.SourcePath, destination, transferPathResult, token, progress);
return transferPathResult;
} catch (PotentialMalwareException e) {
IssueAttributes attributes = IssueAttributes.File | IssueAttributes.Warning | IssueAttributes.Malware;
PublishTransferIssue(attributes, path, e);
return new TransferPathResult {
Completed = true,
Path = path,
Status = TransferPathStatus.FileBlocked
};
} catch (OperationCanceledException) {
HandleCancel(transferPathResult);
return transferPathResult;
} catch (UnauthorizedAccessException ex2) {
IssueAttributes attributes2 = IssueAttributes.File | IssueAttributes.ReadWritePermissions | (base.FilePermissionErrorsRetry ? GetWarningErrorAttribute() : IssueAttributes.Error);
PublishTransferIssue(attributes2, path, ex2);
return HandleUnauthorizedAccessException(path, ex2, transferPathResult, configuration.MaxJobRetryAttempts);
} catch (ArgumentException ex3) {
LogError(ex3.Message, true, ex3);
IssueAttributes attributes3 = IssueAttributes.Error | IssueAttributes.File | IssueAttributes.InvalidCharacters;
PublishTransferIssue(attributes3, path, ex3);
throw new TransferException(ex3.Message, ex3, true);
} catch (PathTooLongException ex4) {
LogError(ex4.Message, true, ex4);
IssueAttributes attributes4 = IssueAttributes.Error | IssueAttributes.File | IssueAttributes.LongPath;
PublishTransferIssue(attributes4, path, ex4);
throw new TransferException(ex4.Message, ex4, true);
} catch (DirectoryNotFoundException ex5) {
string errorMessage = FileshareErrorHelper.GetErrorMessage(path, ex5);
LogError(errorMessage, false, ex5);
IssueAttributes attributes5 = IssueAttributes.DirectoryNotFound | IssueAttributes.Io | GetWarningErrorAttribute();
PublishTransferIssue(attributes5, path, ex5);
transferPathResult.Status = TransferPathStatus.Failed;
transferPathResult.EndTime = DateTime.Now;
return transferPathResult;
} catch (FileNotFoundException ex6) {
string errorMessage2 = FileshareErrorHelper.GetErrorMessage(path, ex6);
if (base.FileNotFoundErrorsDisabled)
LogWarning(errorMessage2, false, ex6);
else
LogError(errorMessage2, false, ex6);
IssueAttributes attributes6 = IssueAttributes.File | IssueAttributes.FileNotFound | IssueAttributes.Io | (base.FileNotFoundErrorsDisabled ? IssueAttributes.Warning : GetWarningErrorAttribute());
PublishTransferIssue(attributes6, path, ex6);
transferPathResult.Status = TransferPathStatus.FileNotFound;
transferPathResult.EndTime = DateTime.Now;
return transferPathResult;
} catch (IOException ex7) {
LogError(ex7.Message, true, ex7);
if (FileshareErrorHelper.IsDiskFull(ex7)) {
IssueAttributes attributes7 = IssueAttributes.Error | IssueAttributes.Io | IssueAttributes.StorageOutOfSpace;
PublishTransferIssue(attributes7, path, ex7);
throw new TransferException(ex7.Message, ex7, true);
}
IssueAttributes attributes8 = IssueAttributes.File | IssueAttributes.Io | IssueAttributes.Overwrite | IssueAttributes.StorageReadWrite | GetWarningErrorAttribute();
PublishTransferIssue(attributes8, path, ex7);
throw new TransferException(ex7.Message, ex7, false);
} catch (NotSupportedException ex8) {
LogError(ex8.Message, true, ex8);
IssueAttributes attributes9 = IssueAttributes.Error | IssueAttributes.File | IssueAttributes.InvalidPath;
PublishTransferIssue(attributes9, path, ex8);
throw new TransferException(ex8.Message, ex8, true);
} catch (Exception ex9) {
LogError(ex9.Message, true, ex9);
IssueAttributes attributes10 = IssueAttributes.Error;
PublishTransferIssue(attributes10, path, ex9);
throw new TransferException(ex9.Message, ex9, true);
}
HandleCancel(transferPathResult);
return transferPathResult;
}
private void (IssueAttributes attributes, TransferPath path, Exception e)
{
ITransferIssue issue = issueBuilderFactory.Create().CreateFromException(path, e).WithAttributes(attributes)
.WithMaxRetryAttempts(base.MaxJobRetryAttempts)
.WithRetryAttempt(base.JobService.Statistics.RetryAttempt)
.Build();
RegisterIssue(issue);
}
private void (TransferPath path, string source, string destination, TransferPathResult result, CancellationToken token, IProgress<LargeFileProgressEventArgs> progress)
{
if (string.IsNullOrEmpty(source))
throw new ArgumentNullException("source");
if (string.IsNullOrEmpty(destination))
throw new ArgumentNullException("source");
if (token.IsCancellationRequested)
HandleCancel(result);
else {
result.StartTime = DateTime.Now;
if (base.FileSystemService.FileExists(source))
CopyFile(path, source, destination, result, token, progress);
else {
if (!base.FileSystemService.DirectoryExists(source)) {
base.Log.LogError(FileShareStrings.TransferCommandUnableToFindFile, source, LogRedaction.OnPositions(default(int)));
throw new FileNotFoundException(FileShareStrings.TransferCommandFileNotFoundCheckLogs);
}
if (!CopyDirectories)
throw new ArgumentException(FileShareStrings.TransferCommandNotConfiguredToTransferDirectoriesErrorMessage);
CopyDirectory(path, source, destination, result, token);
}
}
}
private void (TransferPath path, string sourcePath, string destinationPath, TransferPathResult result, CancellationToken token)
{
if (string.IsNullOrEmpty(sourcePath))
throw new ArgumentNullException("sourcePath");
if (string.IsNullOrEmpty(destinationPath))
throw new ArgumentNullException("destinationPath");
if (token.IsCancellationRequested)
HandleCancel(result);
else {
if (base.FileSystemService.DirectoryExists(destinationPath)) {
if (!OverWriteFilesAtDestination)
throw new IOException(FileShareStrings.TargetDirectoryAlreadyExistsExceptionMessage);
base.FileSystemService.DeleteDirectory(destinationPath, true);
}
base.FileSystemService.CreateDirectory(destinationPath);
string[] files = base.FileSystemService.GetFiles(sourcePath);
foreach (string text in files) {
if (token.IsCancellationRequested) {
HandleCancel(result);
return;
}
CopyFile(path, text, base.FileSystemService.Combine(destinationPath, base.FileSystemService.GetFileName(text)), result, token, null);
}
if (CopySubDirectories) {
foreach (FolderItem item in base.FileSystemService.EnumerateDirectories(sourcePath)) {
if (token.IsCancellationRequested) {
HandleCancel(result);
return;
}
CopyDirectory(path, item.FullName, base.FileSystemService.Combine(destinationPath, item.Name), result, token);
}
}
result.EndTime = DateTime.Now;
result.Status = (token.IsCancellationRequested ? TransferPathStatus.Canceled : TransferPathStatus.Successful);
}
}
private void (TransferPath path, string sourcePath, string destinationPath, TransferPathResult result, CancellationToken token, IProgress<LargeFileProgressEventArgs> progress)
{
DateTime? sourceCreationTime = null;
DateTime? sourceLastAccessTime = null;
DateTime? sourceLastWriteTime = null;
long num = 0;
if (string.IsNullOrEmpty(sourcePath))
throw new ArgumentNullException("sourcePath");
if (string.IsNullOrEmpty(destinationPath))
throw new ArgumentNullException("destinationPath");
if (token.IsCancellationRequested)
HandleCancel(result);
else {
if (base.PreserveDates) {
sourceCreationTime = base.FileSystemService.GetFileCreationTime(sourcePath);
sourceLastAccessTime = base.FileSystemService.GetFileLastAccessTime(sourcePath);
sourceLastWriteTime = base.FileSystemService.GetFileLastWriteTime(sourcePath);
}
using (FileStream fileStream = CreateFileStreamForSource(sourcePath))
using (FileStream fileStream2 = CreateFileStreamForDestination(destinationPath)) {
byte[] buffer = new byte[base.FileSystemChunkSize];
int num2 = 0;
long length = fileStream.Length;
int totalChunks = TransferHelper.CalculateTotalChunks(length, base.FileSystemChunkSize);
int num3;
while ((num3 = fileStream.Read(buffer, 0, base.FileSystemChunkSize)) != 0) {
num2++;
if (token.IsCancellationRequested) {
HandleCancel(result);
return;
}
fileStream2.Write(buffer, 0, num3);
num += num3;
progress?.Report(new LargeFileProgressEventArgs(path, num, length, num2, totalChunks));
}
result.EndTime = DateTime.Now;
result.Status = (token.IsCancellationRequested ? TransferPathStatus.Canceled : TransferPathStatus.Successful);
result.BytesTransferred += num;
result.Checksum = string.Empty;
}
SaveSourceCreationTime(destinationPath, sourceCreationTime);
SaveSourceLastAccessTime(destinationPath, sourceLastAccessTime);
SaveSourceLastWriteTime(destinationPath, sourceLastWriteTime);
if (result.Status == TransferPathStatus.Successful || result.Status == TransferPathStatus.Skipped)
base.JobService.Statistics.TotalTransferredFiles++;
base.JobService.Statistics.TotalTransferredBytes += num;
PublishTransferStatistics(false);
}
}
private FileStream (string sourcePath)
{
try {
return new FileStream(PathHelper.CheckAddLongPathPrefix(sourcePath), FileMode.Open, FileAccess.Read, System.IO.FileShare.ReadWrite);
} catch (Exception ex) {
LogError(ex, "source");
if (ex.ContainsAntiMalwareEvent())
throw new PotentialMalwareException(ex);
throw;
}
}
private void (Exception ex, string streamType)
{
int lastError = NativeMethods.GetLastError();
string message = new Win32Exception(lastError).Message;
base.Log.LogError(ex, "An exception of type {ExceptionType} with message '{ExceptionMessage}' was thrown while a {StreamType} file stream was created. Possible error code was {ErrorCode} and error message was '{ErrorMessage}'.", ex.GetType().FullName, ex.Message, streamType, lastError, message);
}
private FileStream (string destinationPath)
{
FileMode mode = (!OverWriteFilesAtDestination) ? FileMode.CreateNew : FileMode.Create;
try {
return new FileStream(PathHelper.CheckAddLongPathPrefix(destinationPath), mode);
} catch (Exception ex) {
LogError(ex, "destination");
throw;
}
}
private void (string destinationPath, DateTime? sourceLastWriteTime)
{
if (sourceLastWriteTime.HasValue)
try {
base.FileSystemService.SetFileLastWriteTime(destinationPath, sourceLastWriteTime.Value);
} catch (Exception exception) {
base.Log.LogError(exception, "Failed to preserve the {Path} last write time.", destinationPath, LogRedaction.OnPositions(default(int)));
if (ExceptionHelper.IsFatalException(exception))
throw;
}
}
private void (string destinationPath, DateTime? sourceLastAccessTime)
{
if (sourceLastAccessTime.HasValue)
try {
base.FileSystemService.SetFileLastAccessTime(destinationPath, sourceLastAccessTime.Value);
} catch (Exception exception) {
base.Log.LogError(exception, "Failed to preserve the {Path} last access time.", destinationPath, LogRedaction.OnPositions(default(int)));
if (ExceptionHelper.IsFatalException(exception))
throw;
}
}
private void (string destinationPath, DateTime? sourceCreationTime)
{
if (sourceCreationTime.HasValue)
try {
base.FileSystemService.SetFileCreationTime(destinationPath, sourceCreationTime.Value);
} catch (Exception exception) {
base.Log.LogError(exception, "Failed to preserve the {Path} creation time.", destinationPath, LogRedaction.OnPositions(default(int)));
if (ExceptionHelper.IsFatalException(exception))
throw;
}
}
private long (string path)
{
long num = base.FileSystemService.GetFiles(path).Sum((string file) => base.FileSystemService.GetFileLength(file));
if (!CopySubDirectories)
return num;
IEnumerable<FolderItem> source = base.FileSystemService.EnumerateDirectories(path);
return num + source.Sum((FolderItem dir) => GetDirectorySize(dir.FullName));
}
private void (string message, bool useRedaction, Exception exception = null)
{
if (useRedaction)
base.Log.LogTransferError(exception, base.Request, "FileShare Transfer Command - {0}", message, LogRedaction.OnPositions(default(int)));
else
base.Log.LogTransferError(exception, base.Request, "FileShare Transfer Command - {0}", message);
}
private void (string message, bool useRedaction, Exception exception = null)
{
if (useRedaction)
base.Log.LogTransferWarning(exception, base.Request, "FileShare Transfer Command - {0}", message, LogRedaction.OnPositions(default(int)));
else
base.Log.LogTransferWarning(exception, base.Request, "FileShare Transfer Command - {0}", message);
}
}
}