diff --git a/cmd/fs-v1-helpers.go b/cmd/fs-v1-helpers.go index 673b0354e..31b229eea 100644 --- a/cmd/fs-v1-helpers.go +++ b/cmd/fs-v1-helpers.go @@ -309,6 +309,7 @@ func fsRemoveUploadIDPath(basePath, uploadIDPath string) error { } } + fsRemoveDir(uploadIDPath) return nil } diff --git a/cmd/fs-v1-multipart.go b/cmd/fs-v1-multipart.go index 4f961996f..0a635cc3f 100644 --- a/cmd/fs-v1-multipart.go +++ b/cmd/fs-v1-multipart.go @@ -62,11 +62,11 @@ func (fs fsObjects) deleteUploadsJSON(bucket, object, uploadID string) error { // Removes the uploadID, called either by CompleteMultipart of AbortMultipart. If the resuling uploads // slice is empty then we remove/purge the file. -func (fs fsObjects) removeUploadID(bucket, object, uploadID string, rwlk *lock.LockedFile) error { +func (fs fsObjects) removeUploadID(bucket, object, uploadID string, rwlk *lock.LockedFile) (bool, error) { uploadIDs := uploadsV1{} _, err := uploadIDs.ReadFrom(rwlk) if err != nil { - return err + return false, err } // Removes upload id from the uploads list. @@ -75,12 +75,12 @@ func (fs fsObjects) removeUploadID(bucket, object, uploadID string, rwlk *lock.L // Check this is the last entry. if uploadIDs.IsEmpty() { // No more uploads left, so we delete `uploads.json` file. - return fs.deleteUploadsJSON(bucket, object, uploadID) + return true, fs.deleteUploadsJSON(bucket, object, uploadID) } // else not empty // Write update `uploads.json`. _, err = uploadIDs.WriteTo(rwlk) - return err + return false, err } // Adds a new uploadID if no previous `uploads.json` is @@ -656,6 +656,7 @@ func (fs fsObjects) CompleteMultipartUpload(bucket string, object string, upload } uploadIDPath := pathJoin(bucket, object, uploadID) + var removeObjectDir bool // Hold the lock so that two parallel complete-multipart-uploads // do not leave a stale uploads.json behind. @@ -663,7 +664,15 @@ func (fs fsObjects) CompleteMultipartUpload(bucket string, object string, upload if err = objectMPartPathLock.GetLock(globalOperationTimeout); err != nil { return oi, err } - defer objectMPartPathLock.Unlock() + + defer func() { + if removeObjectDir { + basePath := pathJoin(fs.fsPath, minioMetaMultipartBucket, bucket) + derr := fsDeleteFile(basePath, pathJoin(basePath, object)) + errorIf(derr, "unable to remove %s in %s", pathJoin(basePath, object), basePath) + } + objectMPartPathLock.Unlock() + }() fsMetaPathMultipart := pathJoin(fs.fsPath, minioMetaMultipartBucket, uploadIDPath, fsMetaJSONFile) rlk, err := fs.rwPool.Open(fsMetaPathMultipart) @@ -830,7 +839,8 @@ func (fs fsObjects) CompleteMultipartUpload(bucket string, object string, upload } // Remove entry from `uploads.json`. - if err = fs.removeUploadID(bucket, object, uploadID, rwlk); err != nil { + removeObjectDir, err = fs.removeUploadID(bucket, object, uploadID, rwlk) + if err != nil { return oi, toObjectErr(err, minioMetaMultipartBucket, pathutil.Join(bucket, object)) } @@ -865,6 +875,7 @@ func (fs fsObjects) AbortMultipartUpload(bucket, object, uploadID string) error } uploadIDPath := pathJoin(bucket, object, uploadID) + var removeObjectDir bool // Hold the lock so that two parallel complete-multipart-uploads // do not leave a stale uploads.json behind. @@ -873,7 +884,15 @@ func (fs fsObjects) AbortMultipartUpload(bucket, object, uploadID string) error if err := objectMPartPathLock.GetLock(globalOperationTimeout); err != nil { return err } - defer objectMPartPathLock.Unlock() + + defer func() { + if removeObjectDir { + basePath := pathJoin(fs.fsPath, minioMetaMultipartBucket, bucket) + derr := fsDeleteFile(basePath, pathJoin(basePath, object)) + errorIf(derr, "unable to remove %s in %s", pathJoin(basePath, object), basePath) + } + objectMPartPathLock.Unlock() + }() fsMetaPath := pathJoin(fs.fsPath, minioMetaMultipartBucket, uploadIDPath, fsMetaJSONFile) if _, err := fs.rwPool.Open(fsMetaPath); err != nil { @@ -910,7 +929,8 @@ func (fs fsObjects) AbortMultipartUpload(bucket, object, uploadID string) error } // Remove entry from `uploads.json`. - if err = fs.removeUploadID(bucket, object, uploadID, rwlk); err != nil { + removeObjectDir, err = fs.removeUploadID(bucket, object, uploadID, rwlk) + if err != nil { return toObjectErr(err, bucket, object) }