public override async Task Execute()
        {
            if (File.Exists(this.target))
            {
                if (File.GetLastWriteTimeUtc(this.source) == File.GetLastWriteTimeUtc(this.target))
                {
                    return;
                }
            }
            else
            {
                Directory.CreateDirectory(Path.GetDirectoryName(this.target) ?? "");
            }

            using (var sourceStream = new FileStream(this.source, FileMode.Open, FileAccess.Read, FileShare.ReadWrite,
                                                     Consts.BufferSize, FileOptions.Asynchronous))

                using (var targetStream = new FileStream(this.target, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite,
                                                         Consts.BufferSize, FileOptions.Asynchronous))

                    using (var encryptor = new CipherStreamEncryptor(sourceStream))
                    {
                        Directory.CreateDirectory(Path.GetDirectoryName(this.target) ?? "");
                        var contentInfo = encryptor.Init(this.credentials.RecepientId, this.credentials.PublicKey, Consts.BufferSize);
                        await targetStream.WriteAsync(contentInfo);

                        while (encryptor.HasMore())
                        {
                            await targetStream.WriteAsync(await encryptor.GetChunk());
                        }
                    }

            File.SetLastWriteTimeUtc(this.target, File.GetLastWriteTimeUtc(this.source));
        }
        private async Task ExecuteInternal(CancellationToken cancellationToken)
        {
            var targetPath = this.target.Value;
            var sourcePath = this.source.Value;

            if (File.Exists(targetPath))
            {
                if (File.GetLastWriteTimeUtc(sourcePath) == File.GetLastWriteTimeUtc(targetPath))
                {
                    return;
                }
            }
            else
            {
                Directory.CreateDirectory(Path.GetDirectoryName(targetPath) ?? "");
            }

            using (var sourceStream = new FileStream(sourcePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite,
                                                     Consts.BufferSize, FileOptions.Asynchronous))

                using (var targetStream = new FileStream(targetPath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite,
                                                         Consts.BufferSize, FileOptions.Asynchronous))

                    using (var encryptor = new CipherStreamEncryptor(sourceStream))
                    {
                        Directory.CreateDirectory(Path.GetDirectoryName(targetPath) ?? "");
                        var contentInfo = encryptor.Init(this.recipientCard.GetRecepientId(), this.recipientCard.PublicKey.Data, Consts.BufferSize);
                        await targetStream.WriteAsync(contentInfo);

                        while (encryptor.HasMore())
                        {
                            await targetStream.WriteAsync(await encryptor.GetChunk());
                        }
                    }

            File.SetLastWriteTimeUtc(targetPath, File.GetLastWriteTimeUtc(sourcePath));
        }
        public async Task UploadFile(LocalPath localPath, CancellationToken token, IProgress <double> progress = null)
        {
            using (OperationExecutionContext.Instance.IgnoreChangesTo(localPath))
            {
                token.ThrowIfCancellationRequested();

                var serverPath = localPath.ToServerPath();

                var fileInfo            = new FileInfo(localPath.Value);
                var lastWriteTimeLocal  = fileInfo.LastWriteTimeUtc;
                var fileMetadata        = (await this.GetFileMetadata(serverPath, token));
                var lastWriteTimeServer = fileMetadata?.ClientModified;
                if (lastWriteTimeLocal.AlmostEquals(lastWriteTimeServer))
                {
                    progress?.Report(100);
                    return;
                }

                using (var fileStream = new FileStream(localPath.Value,
                                                       FileMode.Open, FileAccess.Read, FileShare.ReadWrite, BufferSize,
                                                       FileOptions.Asynchronous | FileOptions.SequentialScan))
                {
                    using (var encryptor = new CipherStreamEncryptor(fileStream))
                    {
                        encryptor.AddEncryptedValue(OriginalFileNameKey, localPath.ToUniversalPath().Value,
                                                    this.credentials.GetRecepientId(), this.credentials.PublicKey);

                        var contentInfo = encryptor.Init(
                            this.credentials.GetRecepientId(),
                            this.credentials.PublicKey,
                            BufferSize);

                        var result = await this.client.Files.UploadSessionStartAsync(false, new MemoryStream(contentInfo));

                        var   sessionId = result.SessionId;
                        ulong written   = (ulong)contentInfo.Length;

                        while (encryptor.HasMore())
                        {
                            token.ThrowIfCancellationRequested();

                            var chunk = await encryptor.GetChunk();

                            var cursor = new UploadSessionCursor(sessionId, written);

                            if (encryptor.HasMore())
                            {
                                await this.client.Files.UploadSessionAppendV2Async(cursor, false, new MemoryStream(chunk));

                                written += (ulong)chunk.Length;
                                progress?.Report(100.0 * written / fileStream.Length);
                            }
                            else
                            {
                                await this.client.Files.UploadSessionFinishAsync(
                                    cursor,
                                    new CommitInfo(serverPath.Value,
                                                   mode : WriteMode.Overwrite.Instance,
                                                   clientModified : lastWriteTimeLocal.Truncate()),
                                    new MemoryStream(chunk));

                                progress?.Report(100);
                            }
                        }
                    }
                }
            }
        }