/// <summary> /// private helper method to remove list of objects from bucket /// </summary> /// <param name="args">GetObjectArgs Arguments Object encapsulates information like - bucket name, object name etc </param> /// <param name="cancellationToken">Optional cancellation token to cancel the operation</param> private async Task <ObjectStat> getObjectHelper(GetObjectArgs args, CancellationToken cancellationToken = default(CancellationToken)) { // StatObject is called to both verify the existence of the object and return it with GetObject. // NOTE: This avoids writing the error body to the action stream passed (Do not remove). StatObjectArgs statArgs = new StatObjectArgs() .WithBucket(args.BucketName) .WithObject(args.ObjectName) .WithVersionId(args.VersionId) .WithMatchETag(args.MatchETag) .WithNotMatchETag(args.NotMatchETag) .WithModifiedSince(args.ModifiedSince) .WithUnModifiedSince(args.UnModifiedSince) .WithServerSideEncryption(args.SSE); if (args.OffsetLengthSet) { statArgs.WithOffsetAndLength(args.ObjectOffset, args.ObjectLength); } ObjectStat objStat = await this.StatObjectAsync(statArgs, cancellationToken : cancellationToken).ConfigureAwait(false); args.Validate(); if (args.FileName != null) { await this.getObjectFileAsync(args, objStat, cancellationToken); } else { await this.getObjectStreamAsync(args, objStat, args.CallBack, cancellationToken); } return(objStat); }
/// <summary> /// Copy a source object into a new destination object. /// </summary> /// <param name="bucketName"> Bucket name where the object to be copied exists.</param> /// <param name="objectName">Object name source to be copied.</param> /// <param name="destBucketName">Bucket name where the object will be copied to.</param> /// <param name="destObjectName">Object name to be created, if not provided uses source object name as destination object name.</param> /// <param name="copyConditions">optionally can take a key value CopyConditions as well for conditionally attempting copyObject.</param> /// <param name="cancellationToken">Optional cancellation token to cancel the operation</param> /// <returns></returns> public async Task CopyObjectAsync(string bucketName, string objectName, string destBucketName, string destObjectName = null, CopyConditions copyConditions = null, CancellationToken cancellationToken = default(CancellationToken)) { if (bucketName == null) { throw new ArgumentException("Source bucket name cannot be empty"); } if (objectName == null) { throw new ArgumentException("Source object name cannot be empty"); } if (destBucketName == null) { throw new ArgumentException("Destination bucket name cannot be empty"); } // Escape source object path. string sourceObjectPath = bucketName + "/" + utils.UrlEncode(objectName); // Destination object name is optional, if empty default to source object name. if (destObjectName == null) { destObjectName = objectName; } // Get Stats on the source object ObjectStat srcStats = await this.StatObjectAsync(bucketName, objectName, cancellationToken); long srcByteRangeSize = 0L; if (copyConditions != null) { srcByteRangeSize = copyConditions.GetByteRange(); } long copySize = (srcByteRangeSize == 0) ? srcStats.Size : srcByteRangeSize; if ((srcByteRangeSize > srcStats.Size) || ((srcByteRangeSize > 0) && (copyConditions.byteRangeEnd >= srcStats.Size))) { throw new ArgumentException("Specified byte range (" + copyConditions.byteRangeStart.ToString() + "-" + copyConditions.byteRangeEnd.ToString() + ") does not fit within source object (size=" + srcStats.Size.ToString() + ")"); } if ((copySize > Constants.MaxSingleCopyObjectSize) || (srcByteRangeSize > 0 && (srcByteRangeSize != srcStats.Size))) { await MultipartCopyUploadAsync(bucketName, objectName, destBucketName, destObjectName, copyConditions, copySize, cancellationToken); } else { await this.CopyObjectRequestAsync(bucketName, objectName, destBucketName, destObjectName, copyConditions, null, null, cancellationToken, typeof(CopyObjectResult)); } }
/// <summary> /// private helper method return the specified object from the bucket /// </summary> /// <param name="args">GetObjectArgs Arguments Object encapsulates information like - bucket name, object name etc </param> /// <param name="objectStat"> ObjectStat object encapsulates information like - object name, size, etag etc </param> /// <param name="cancellationToken">Optional cancellation token to cancel the operation</param> private Task getObjectFileAsync(GetObjectArgs args, ObjectStat objectStat, CancellationToken cancellationToken = default(CancellationToken)) { long length = objectStat.Size; string etag = objectStat.ETag; long tempFileSize = 0; string tempFileName = $"{args.FileName}.{etag}.part.minio"; if (!string.IsNullOrEmpty(args.VersionId)) { tempFileName = $"{args.FileName}.{etag}.{args.VersionId}.part.minio"; } if (File.Exists(args.FileName)) { File.Delete(args.FileName); } utils.ValidateFile(tempFileName); if (File.Exists(tempFileName)) { File.Delete(tempFileName); } args = args.WithCallbackStream(stream => { using (var fileStream = File.Create(tempFileName)) { stream.CopyTo(fileStream); } FileInfo writtenInfo = new FileInfo(tempFileName); long writtenSize = writtenInfo.Length; if (writtenSize != (length - tempFileSize)) { throw new IOException(tempFileName + ": unexpected data written. expected = " + (length - tempFileSize) + ", written = " + writtenSize); } utils.MoveWithReplace(tempFileName, args.FileName); }); return(getObjectStreamAsync(args, objectStat, null, cancellationToken)); }
/// <summary> /// private helper method return the specified object from the bucket /// </summary> /// <param name="args">GetObjectArgs Arguments Object encapsulates information like - bucket name, object name etc </param> /// <param name="objectStat"> ObjectStat object encapsulates information like - object name, size, etag etc </param> /// <param name="cancellationToken">Optional cancellation token to cancel the operation</param> private Task getObjectFileAsync(GetObjectArgs args, ObjectStat objectStat, CancellationToken cancellationToken = default(CancellationToken)) { long length = objectStat.Size; string etag = objectStat.ETag; string tempFileName = $"{args.FileName}.{etag}.part.minio"; if (!string.IsNullOrEmpty(args.VersionId)) { tempFileName = $"{args.FileName}.{etag}.{args.VersionId}.part.minio"; } if (File.Exists(args.FileName)) { File.Delete(args.FileName); } utils.ValidateFile(tempFileName); if (File.Exists(tempFileName)) { File.Delete(tempFileName); } return(getObjectStreamAsync(args, objectStat, null, cancellationToken)); }
internal StatObjectResponse(HttpStatusCode statusCode, string responseContent, Dictionary <string, string> responseHeaders, StatObjectArgs args) : base(statusCode, responseContent) { // StatObjectResponse object is populated with available stats from the response. this.ObjectInfo = ObjectStat.FromResponseHeaders(args.ObjectName, responseHeaders); }
/// <summary> /// private helper method to remove list of objects from bucket /// </summary> /// <param name="args">GetObjectArgs Arguments Object encapsulates information like - bucket name, object name etc </param> /// <param name="objectStat"> ObjectStat object encapsulates information like - object name, size, etag etc, represents Object Information </param> /// <param name="cb"> Action object of type Stream, callback to send Object contents, if assigned </param> /// <param name="cancellationToken">Optional cancellation token to cancel the operation</param> private async Task getObjectStreamAsync(GetObjectArgs args, ObjectStat objectStat, Action <Stream> cb, CancellationToken cancellationToken = default(CancellationToken)) { RestRequest request = await this.CreateRequest(args).ConfigureAwait(false); await this.ExecuteAsync(this.NoErrorHandlers, request, cancellationToken); }
/// <summary> /// Get an object. The object will be streamed to the callback given by the user. /// </summary> /// <param name="bucketName">Bucket to retrieve object from</param> /// <param name="objectName">Name of object to retrieve</param> /// <param name="fileName">string with file path</param> /// <param name="cancellationToken">Optional cancellation token to cancel the operation</param> /// <returns></returns> public async Task GetObjectAsync(string bucketName, string objectName, string fileName, CancellationToken cancellationToken = default(CancellationToken)) { bool fileExists = File.Exists(fileName); utils.ValidateFile(fileName); ObjectStat objectStat = await StatObjectAsync(bucketName, objectName, cancellationToken); long length = objectStat.Size; string etag = objectStat.ETag; string tempFileName = fileName + "." + etag + ".part.minio"; bool tempFileExists = File.Exists(tempFileName); utils.ValidateFile(tempFileName); FileInfo tempFileInfo = new FileInfo(tempFileName); long tempFileSize = 0; if (tempFileExists) { tempFileSize = tempFileInfo.Length; if (tempFileSize > length) { File.Delete(tempFileName); tempFileExists = false; tempFileSize = 0; } } if (fileExists) { FileInfo fileInfo = new FileInfo(fileName); long fileSize = fileInfo.Length; if (fileSize == length) { // already downloaded. nothing to do return; } else if (fileSize > length) { throw new ArgumentException("'" + fileName + "': object size " + length + " is smaller than file size " + fileSize); } else if (!tempFileExists) { // before resuming the download, copy filename to tempfilename File.Copy(fileName, tempFileName); tempFileSize = fileSize; tempFileExists = true; } } await GetObjectAsync(bucketName, objectName, (stream) => { var fileStream = File.Create(tempFileName); stream.CopyTo(fileStream); fileStream.Dispose(); FileInfo writtenInfo = new FileInfo(tempFileName); long writtenSize = writtenInfo.Length; if (writtenSize != length - tempFileSize) { new IOException(tempFileName + ": unexpected data written. expected = " + (length - tempFileSize) + ", written = " + writtenSize); } utils.MoveWithReplace(tempFileName, fileName); }, cancellationToken); }
/// <summary> /// private helper method to remove list of objects from bucket /// </summary> /// <param name="args">GetObjectArgs Arguments Object encapsulates information like - bucket name, object name etc </param> /// <param name="objectStat"> ObjectStat object encapsulates information like - object name, size, etag etc, represents Object Information </param> /// <param name="cb"> Action object of type Stream, callback to send Object contents, if assigned </param> /// <param name="cancellationToken">Optional cancellation token to cancel the operation</param> private async Task getObjectStreamAsync(GetObjectArgs args, ObjectStat objectStat, Action <Stream> cb, CancellationToken cancellationToken = default(CancellationToken)) { HttpRequestMessageBuilder requestMessageBuilder = await CreateRequest(args).ConfigureAwait(false); await ExecuteTaskAsync(this.NoErrorHandlers, requestMessageBuilder, cancellationToken).ConfigureAwait(false); }