diff --git a/cmd/fs-v1-multipart.go b/cmd/fs-v1-multipart.go index b05ba35c1..d583f579f 100644 --- a/cmd/fs-v1-multipart.go +++ b/cmd/fs-v1-multipart.go @@ -462,11 +462,14 @@ func (fs fsObjects) PutObjectPart(bucket, object, uploadID string, partID int, s return "", traceError(IncompleteBody{}) } + // Delete temporary part in case of failure. If + // PutObjectPart succeeds then there would be nothing to + // delete. + defer fs.storage.DeleteFile(minioMetaBucket, tmpPartPath) + newMD5Hex := hex.EncodeToString(md5Writer.Sum(nil)) if md5Hex != "" { if newMD5Hex != md5Hex { - // MD5 mismatch, delete the temporary object. - fs.storage.DeleteFile(minioMetaBucket, tmpPartPath) return "", traceError(BadDigest{md5Hex, newMD5Hex}) } } @@ -474,8 +477,6 @@ func (fs fsObjects) PutObjectPart(bucket, object, uploadID string, partID int, s if sha256sum != "" { newSHA256sum := hex.EncodeToString(sha256Writer.Sum(nil)) if newSHA256sum != sha256sum { - // SHA256 mismatch, delete the temporary object. - fs.storage.DeleteFile(minioMetaBucket, tmpPartPath) return "", traceError(SHA256Mismatch{}) } } @@ -504,9 +505,6 @@ func (fs fsObjects) PutObjectPart(bucket, object, uploadID string, partID int, s partPath := path.Join(mpartMetaPrefix, bucket, object, uploadID, partSuffix) err = fs.storage.RenameFile(minioMetaBucket, tmpPartPath, minioMetaBucket, partPath) if err != nil { - if dErr := fs.storage.DeleteFile(minioMetaBucket, tmpPartPath); dErr != nil { - return "", toObjectErr(traceError(dErr), minioMetaBucket, tmpPartPath) - } return "", toObjectErr(traceError(err), minioMetaBucket, partPath) } uploadIDPath = path.Join(mpartMetaPrefix, bucket, object, uploadID) diff --git a/cmd/fs-v1.go b/cmd/fs-v1.go index b1a753454..b43abceda 100644 --- a/cmd/fs-v1.go +++ b/cmd/fs-v1.go @@ -384,6 +384,7 @@ func (fs fsObjects) PutObject(bucket string, object string, size int64, data io. // For size 0 we write a 0byte file. err = fs.storage.AppendFile(minioMetaBucket, tempObj, []byte("")) if err != nil { + fs.storage.DeleteFile(minioMetaBucket, tempObj) return ObjectInfo{}, toObjectErr(traceError(err), bucket, object) } } else { @@ -397,8 +398,8 @@ func (fs fsObjects) PutObject(bucket string, object string, size int64, data io. var bytesWritten int64 bytesWritten, err = fsCreateFile(fs.storage, teeReader, buf, minioMetaBucket, tempObj) if err != nil { - errorIf(err, "Failed to create object %s/%s", bucket, object) fs.storage.DeleteFile(minioMetaBucket, tempObj) + errorIf(err, "Failed to create object %s/%s", bucket, object) return ObjectInfo{}, toObjectErr(err, bucket, object) } @@ -409,6 +410,10 @@ func (fs fsObjects) PutObject(bucket string, object string, size int64, data io. return ObjectInfo{}, traceError(IncompleteBody{}) } } + // Delete the temporary object in the case of a + // failure. If PutObject succeeds, then there would be + // nothing to delete. + defer fs.storage.DeleteFile(minioMetaBucket, tempObj) newMD5Hex := hex.EncodeToString(md5Writer.Sum(nil)) // Update the md5sum if not set with the newly calculated one. @@ -420,8 +425,6 @@ func (fs fsObjects) PutObject(bucket string, object string, size int64, data io. md5Hex := metadata["md5Sum"] if md5Hex != "" { if newMD5Hex != md5Hex { - // MD5 mismatch, delete the temporary object. - fs.storage.DeleteFile(minioMetaBucket, tempObj) // Returns md5 mismatch. return ObjectInfo{}, traceError(BadDigest{md5Hex, newMD5Hex}) } @@ -430,8 +433,6 @@ func (fs fsObjects) PutObject(bucket string, object string, size int64, data io. if sha256sum != "" { newSHA256sum := hex.EncodeToString(sha256Writer.Sum(nil)) if newSHA256sum != sha256sum { - // SHA256 mismatch, delete the temporary object. - fs.storage.DeleteFile(minioMetaBucket, tempObj) return ObjectInfo{}, traceError(SHA256Mismatch{}) } } diff --git a/cmd/xl-v1-multipart.go b/cmd/xl-v1-multipart.go index d645d56f2..955138506 100644 --- a/cmd/xl-v1-multipart.go +++ b/cmd/xl-v1-multipart.go @@ -413,11 +413,15 @@ func (xl xlObjects) PutObjectPart(bucket, object, uploadID string, partID int, s // Construct a tee reader for md5sum. teeReader := io.TeeReader(lreader, mw) + // Delete the temporary object part. If PutObjectPart succeeds there would be nothing to delete. + defer xl.deleteObject(minioMetaBucket, tmpPartPath) + // Erasure code data and write across all disks. sizeWritten, checkSums, err := erasureCreateFile(onlineDisks, minioMetaBucket, tmpPartPath, teeReader, xlMeta.Erasure.BlockSize, xl.dataBlocks, xl.parityBlocks, bitRotAlgo, xl.writeQuorum) if err != nil { return "", toObjectErr(err, bucket, object) } + // Should return IncompleteBody{} error when reader has fewer bytes // than specified in request header. if sizeWritten < size { @@ -434,8 +438,6 @@ func (xl xlObjects) PutObjectPart(bucket, object, uploadID string, partID int, s newMD5Hex := hex.EncodeToString(md5Writer.Sum(nil)) if md5Hex != "" { if newMD5Hex != md5Hex { - // MD5 mismatch, delete the temporary object. - xl.deleteObject(minioMetaBucket, tmpPartPath) // Returns md5 mismatch. return "", traceError(BadDigest{md5Hex, newMD5Hex}) } @@ -444,8 +446,6 @@ func (xl xlObjects) PutObjectPart(bucket, object, uploadID string, partID int, s if sha256sum != "" { newSHA256sum := hex.EncodeToString(sha256Writer.Sum(nil)) if newSHA256sum != sha256sum { - // SHA256 mismatch, delete the temporary object. - xl.deleteObject(minioMetaBucket, tmpPartPath) return "", traceError(SHA256Mismatch{}) } } diff --git a/cmd/xl-v1-object.go b/cmd/xl-v1-object.go index 49e3069d7..450a5bc28 100644 --- a/cmd/xl-v1-object.go +++ b/cmd/xl-v1-object.go @@ -443,18 +443,19 @@ func (xl xlObjects) PutObject(bucket string, object string, size int64, data io. onlineDisks := getOrderedDisks(xlMeta.Erasure.Distribution, xl.storageDisks) + // Delete temporary object in the event of failure. If + // PutObject succeeded there would be no temporary object to + // delete. + defer xl.deleteObject(minioMetaTmpBucket, tempObj) + // Erasure code data and write across all disks. sizeWritten, checkSums, err := erasureCreateFile(onlineDisks, minioMetaBucket, tempErasureObj, teeReader, xlMeta.Erasure.BlockSize, xlMeta.Erasure.DataBlocks, xlMeta.Erasure.ParityBlocks, bitRotAlgo, xl.writeQuorum) if err != nil { - // Create file failed, delete temporary object. - xl.deleteObject(minioMetaTmpBucket, tempObj) return ObjectInfo{}, toObjectErr(err, minioMetaBucket, tempErasureObj) } // Should return IncompleteBody{} error when reader has fewer bytes // than specified in request header. if sizeWritten < size { - // Short write, delete temporary object. - xl.deleteObject(minioMetaTmpBucket, tempObj) return ObjectInfo{}, traceError(IncompleteBody{}) } @@ -486,8 +487,6 @@ func (xl xlObjects) PutObject(bucket string, object string, size int64, data io. md5Hex := metadata["md5Sum"] if md5Hex != "" { if newMD5Hex != md5Hex { - // MD5 mismatch, delete the temporary object. - xl.deleteObject(minioMetaTmpBucket, tempObj) // Returns md5 mismatch. return ObjectInfo{}, traceError(BadDigest{md5Hex, newMD5Hex}) } @@ -496,8 +495,6 @@ func (xl xlObjects) PutObject(bucket string, object string, size int64, data io. if sha256sum != "" { newSHA256sum := hex.EncodeToString(sha256Writer.Sum(nil)) if newSHA256sum != sha256sum { - // SHA256 mismatch, delete the temporary object. - xl.deleteObject(minioMetaBucket, tempObj) return ObjectInfo{}, traceError(SHA256Mismatch{}) } } @@ -514,14 +511,15 @@ func (xl xlObjects) PutObject(bucket string, object string, size int64, data io. // Check if an object is present as one of the parent dir. // -- FIXME. (needs a new kind of lock). if xl.parentDirIsObject(bucket, path.Dir(object)) { - // Parent (in the namespace) is an object, delete temporary object. - xl.deleteObject(minioMetaTmpBucket, tempObj) return ObjectInfo{}, toObjectErr(traceError(errFileAccessDenied), bucket, object) } // Rename if an object already exists to temporary location. newUniqueID := getUUID() if xl.isObject(bucket, object) { + // Delete the temporary copy of the object that existed before this PutObject request. + defer xl.deleteObject(minioMetaTmpBucket, newUniqueID) + // NOTE: Do not use online disks slice here. // The reason is that existing object should be purged // regardless of `xl.json` status and rolled back in case of errors. @@ -561,9 +559,6 @@ func (xl xlObjects) PutObject(bucket string, object string, size int64, data io. return ObjectInfo{}, toObjectErr(err, bucket, object) } - // Delete the temporary object. - xl.deleteObject(minioMetaTmpBucket, newUniqueID) - // Once we have successfully renamed the object, Close the buffer which would // save the object on cache. if size > 0 && xl.objCacheEnabled && newBuffer != nil {