1
0
mirror of https://github.com/minio/mc.git synced 2025-07-30 07:23:03 +03:00

Allow copying file onto itself (#2617)

This allows encrypting an unencrypted file
using server side CopyObject API.
This commit is contained in:
Harshavardhana
2018-12-06 10:18:16 -08:00
committed by kannappanr
parent f3eaa54a32
commit 2073642656
4 changed files with 8 additions and 58 deletions

View File

@ -365,58 +365,19 @@ func readFile(fpath string) (io.ReadCloser, error) {
return fileData, nil return fileData, nil
} }
// createFile creates an empty file at the provided filepath
// if one does not exist already.
func createFile(fpath string) (io.WriteCloser, error) {
if e := os.MkdirAll(filepath.Dir(fpath), 0777); e != nil {
return nil, e
}
file, e := os.Create(fpath)
if e != nil {
return nil, e
}
return file, nil
}
// Copy - copy data from source to destination // Copy - copy data from source to destination
func (f *fsClient) Copy(source string, size int64, progress io.Reader, srcSSEKey, tgtSSEKey string) *probe.Error { func (f *fsClient) Copy(source string, size int64, progress io.Reader, srcSSEKey, tgtSSEKey string) *probe.Error {
// Don't use f.Get() f.Put() directly. Instead use readFile and createFile
destination := f.PathURL.Path destination := f.PathURL.Path
if destination == source { // Cannot copy file into itself
return probe.NewError(SameFile{
Source: source,
Destination: destination,
})
}
rc, e := readFile(source) rc, e := readFile(source)
if e != nil { if e != nil {
err := f.toClientError(e, destination) err := f.toClientError(e, destination)
return err.Trace(destination) return err.Trace(destination)
} }
defer rc.Close() defer rc.Close()
wc, e := createFile(destination)
if e != nil { _, err := f.put(rc, size, map[string][]string{}, progress)
err := f.toClientError(e, destination) if err != nil {
return err.Trace(destination) return err.Trace(destination, source)
}
defer wc.Close()
reader := hookreader.NewHook(rc, progress)
// Perform copy
n, _ := io.CopyN(wc, reader, size) // e == nil only if n != size
// Only check size related errors if size is positive
if size > 0 {
if n < size { // Unexpected early EOF
return probe.NewError(UnexpectedEOF{
TotalSize: size,
TotalWritten: n,
})
}
if n > size { // Unexpected ExcessRead
return probe.NewError(UnexpectedExcessRead{
TotalSize: size,
TotalWritten: n,
})
}
} }
return nil return nil
} }

View File

@ -594,7 +594,7 @@ func (c *s3Client) Get(sseKey string) (io.ReadCloser, *probe.Error) {
Bucket: bucket, Bucket: bucket,
}) })
} }
if errResponse.Code == "NoSuchKey" || errResponse.Code == "InvalidArgument" { if errResponse.Code == "NoSuchKey" {
return nil, probe.NewError(ObjectMissing{}) return nil, probe.NewError(ObjectMissing{})
} }
return nil, probe.NewError(e) return nil, probe.NewError(e)
@ -646,7 +646,7 @@ func (c *s3Client) Copy(source string, size int64, progress io.Reader, srcSSEKey
Bucket: dstBucket, Bucket: dstBucket,
}) })
} }
if errResponse.Code == "NoSuchKey" || errResponse.Code == "InvalidArgument" { if errResponse.Code == "NoSuchKey" {
return probe.NewError(ObjectMissing{}) return probe.NewError(ObjectMissing{})
} }
return probe.NewError(e) return probe.NewError(e)
@ -742,7 +742,7 @@ func (c *s3Client) Put(ctx context.Context, reader io.Reader, size int64, metada
Bucket: bucket, Bucket: bucket,
}) })
} }
if errResponse.Code == "NoSuchKey" || errResponse.Code == "InvalidArgument" { if errResponse.Code == "NoSuchKey" {
return n, probe.NewError(ObjectMissing{}) return n, probe.NewError(ObjectMissing{})
} }
return n, probe.NewError(e) return n, probe.NewError(e)
@ -1116,7 +1116,7 @@ func (c *s3Client) getObjectStat(bucket, object string, opts minio.StatObjectOpt
Bucket: bucket, Bucket: bucket,
}) })
} }
if errResponse.Code == "NoSuchKey" || errResponse.Code == "InvalidArgument" { if errResponse.Code == "NoSuchKey" {
return nil, probe.NewError(ObjectMissing{}) return nil, probe.NewError(ObjectMissing{})
} }
return nil, probe.NewError(e) return nil, probe.NewError(e)

View File

@ -97,10 +97,6 @@ func prepareCopyURLsTypeA(sourceURL string, targetURL string, encKeyDB map[strin
// Source is not a regular file // Source is not a regular file
return URLs{Error: errInvalidSource(sourceURL).Trace(sourceURL)} return URLs{Error: errInvalidSource(sourceURL).Trace(sourceURL)}
} }
if sourceContent.URL.String() == targetURL {
// source and target can not be same
return URLs{Error: errSourceTargetSame(sourceURL).Trace(sourceURL)}
}
// All OK.. We can proceed. Type A // All OK.. We can proceed. Type A
return makeCopyContentTypeA(sourceAlias, sourceContent, targetAlias, targetURL, encKeyDB) return makeCopyContentTypeA(sourceAlias, sourceContent, targetAlias, targetURL, encKeyDB)

View File

@ -111,10 +111,3 @@ var errSourceIsDir = func(URL string) *probe.Error {
msg := "Source `" + URL + "` is a folder." msg := "Source `" + URL + "` is a folder."
return probe.NewError(sourceIsDirErr(errors.New(msg))).Untrace() return probe.NewError(sourceIsDirErr(errors.New(msg))).Untrace()
} }
type sourceTargetSameErr error
var errSourceTargetSame = func(URL string) *probe.Error {
msg := "Source and target URL can not be same : " + URL
return probe.NewError(sourceTargetSameErr(errors.New(msg))).Untrace()
}