diff options
Diffstat (limited to 'vendor/github.com/minio/minio-go/v7/api-get-object-file.go')
| -rw-r--r-- | vendor/github.com/minio/minio-go/v7/api-get-object-file.go | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/vendor/github.com/minio/minio-go/v7/api-get-object-file.go b/vendor/github.com/minio/minio-go/v7/api-get-object-file.go new file mode 100644 index 0000000..2332dbf --- /dev/null +++ b/vendor/github.com/minio/minio-go/v7/api-get-object-file.go | |||
| @@ -0,0 +1,127 @@ | |||
| 1 | /* | ||
| 2 | * MinIO Go Library for Amazon S3 Compatible Cloud Storage | ||
| 3 | * Copyright 2015-2017 MinIO, Inc. | ||
| 4 | * | ||
| 5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 6 | * you may not use this file except in compliance with the License. | ||
| 7 | * You may obtain a copy of the License at | ||
| 8 | * | ||
| 9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 10 | * | ||
| 11 | * Unless required by applicable law or agreed to in writing, software | ||
| 12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 14 | * See the License for the specific language governing permissions and | ||
| 15 | * limitations under the License. | ||
| 16 | */ | ||
| 17 | |||
| 18 | package minio | ||
| 19 | |||
| 20 | import ( | ||
| 21 | "context" | ||
| 22 | "io" | ||
| 23 | "os" | ||
| 24 | "path/filepath" | ||
| 25 | |||
| 26 | "github.com/minio/minio-go/v7/pkg/s3utils" | ||
| 27 | ) | ||
| 28 | |||
| 29 | // FGetObject - download contents of an object to a local file. | ||
| 30 | // The options can be used to specify the GET request further. | ||
| 31 | func (c *Client) FGetObject(ctx context.Context, bucketName, objectName, filePath string, opts GetObjectOptions) error { | ||
| 32 | // Input validation. | ||
| 33 | if err := s3utils.CheckValidBucketName(bucketName); err != nil { | ||
| 34 | return err | ||
| 35 | } | ||
| 36 | if err := s3utils.CheckValidObjectName(objectName); err != nil { | ||
| 37 | return err | ||
| 38 | } | ||
| 39 | |||
| 40 | // Verify if destination already exists. | ||
| 41 | st, err := os.Stat(filePath) | ||
| 42 | if err == nil { | ||
| 43 | // If the destination exists and is a directory. | ||
| 44 | if st.IsDir() { | ||
| 45 | return errInvalidArgument("fileName is a directory.") | ||
| 46 | } | ||
| 47 | } | ||
| 48 | |||
| 49 | // Proceed if file does not exist. return for all other errors. | ||
| 50 | if err != nil { | ||
| 51 | if !os.IsNotExist(err) { | ||
| 52 | return err | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | // Extract top level directory. | ||
| 57 | objectDir, _ := filepath.Split(filePath) | ||
| 58 | if objectDir != "" { | ||
| 59 | // Create any missing top level directories. | ||
| 60 | if err := os.MkdirAll(objectDir, 0o700); err != nil { | ||
| 61 | return err | ||
| 62 | } | ||
| 63 | } | ||
| 64 | |||
| 65 | // Gather md5sum. | ||
| 66 | objectStat, err := c.StatObject(ctx, bucketName, objectName, StatObjectOptions(opts)) | ||
| 67 | if err != nil { | ||
| 68 | return err | ||
| 69 | } | ||
| 70 | |||
| 71 | // Write to a temporary file "fileName.part.minio" before saving. | ||
| 72 | filePartPath := filePath + objectStat.ETag + ".part.minio" | ||
| 73 | |||
| 74 | // If exists, open in append mode. If not create it as a part file. | ||
| 75 | filePart, err := os.OpenFile(filePartPath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0o600) | ||
| 76 | if err != nil { | ||
| 77 | return err | ||
| 78 | } | ||
| 79 | |||
| 80 | // If we return early with an error, be sure to close and delete | ||
| 81 | // filePart. If we have an error along the way there is a chance | ||
| 82 | // that filePart is somehow damaged, and we should discard it. | ||
| 83 | closeAndRemove := true | ||
| 84 | defer func() { | ||
| 85 | if closeAndRemove { | ||
| 86 | _ = filePart.Close() | ||
| 87 | _ = os.Remove(filePartPath) | ||
| 88 | } | ||
| 89 | }() | ||
| 90 | |||
| 91 | // Issue Stat to get the current offset. | ||
| 92 | st, err = filePart.Stat() | ||
| 93 | if err != nil { | ||
| 94 | return err | ||
| 95 | } | ||
| 96 | |||
| 97 | // Initialize get object request headers to set the | ||
| 98 | // appropriate range offsets to read from. | ||
| 99 | if st.Size() > 0 { | ||
| 100 | opts.SetRange(st.Size(), 0) | ||
| 101 | } | ||
| 102 | |||
| 103 | // Seek to current position for incoming reader. | ||
| 104 | objectReader, objectStat, _, err := c.getObject(ctx, bucketName, objectName, opts) | ||
| 105 | if err != nil { | ||
| 106 | return err | ||
| 107 | } | ||
| 108 | |||
| 109 | // Write to the part file. | ||
| 110 | if _, err = io.CopyN(filePart, objectReader, objectStat.Size); err != nil { | ||
| 111 | return err | ||
| 112 | } | ||
| 113 | |||
| 114 | // Close the file before rename, this is specifically needed for Windows users. | ||
| 115 | closeAndRemove = false | ||
| 116 | if err = filePart.Close(); err != nil { | ||
| 117 | return err | ||
| 118 | } | ||
| 119 | |||
| 120 | // Safely completed. Now commit by renaming to actual filename. | ||
| 121 | if err = os.Rename(filePartPath, filePath); err != nil { | ||
| 122 | return err | ||
| 123 | } | ||
| 124 | |||
| 125 | // Return. | ||
| 126 | return nil | ||
| 127 | } | ||