diff --git a/cmd/bucket-handlers.go b/cmd/bucket-handlers.go index bd851ad9d..ab46893d8 100644 --- a/cmd/bucket-handlers.go +++ b/cmd/bucket-handlers.go @@ -467,13 +467,6 @@ func (api objectAPIHandlers) DeleteMultipleObjectsHandler(w http.ResponseWriter, // Ignore errors here to preserve the S3 error behavior of GetBucketInfo() checkRequestAuthType(ctx, r, policy.DeleteObjectAction, bucket, "") - // Before proceeding validate if bucket exists. - _, err := objectAPI.GetBucketInfo(ctx, bucket, BucketOptions{}) - if err != nil { - writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL) - return - } - deleteObjectsFn := objectAPI.DeleteObjects // Return Malformed XML as S3 spec if the number of objects is empty @@ -611,6 +604,12 @@ func (api objectAPIHandlers) DeleteMultipleObjectsHandler(w http.ResponseWriter, VersionSuspended: vc.Suspended(), }) + // Are all objects saying bucket not found? + if isAllBucketsNotFound(errs) { + writeErrorResponse(ctx, w, toAPIError(ctx, errs[0]), r.URL) + return + } + for i := range errs { // DeleteMarkerVersionID is not used specifically to avoid // lookup errors, since DeleteMarkerVersionID is only @@ -618,7 +617,7 @@ func (api objectAPIHandlers) DeleteMultipleObjectsHandler(w http.ResponseWriter, // specify a versionID. objToDel := ObjectToDelete{ ObjectV: ObjectV{ - ObjectName: dObjects[i].ObjectName, + ObjectName: decodeDirObject(dObjects[i].ObjectName), VersionID: dObjects[i].VersionID, }, VersionPurgeStatus: dObjects[i].VersionPurgeStatus(), diff --git a/cmd/bucket-handlers_test.go b/cmd/bucket-handlers_test.go index ee6f59243..70a816e25 100644 --- a/cmd/bucket-handlers_test.go +++ b/cmd/bucket-handlers_test.go @@ -880,6 +880,15 @@ func testAPIDeleteMultipleObjectsHandler(obj ObjectLayer, instanceType, bucketNa expectedContent: encodedAnonResponseWithPartialPublicAccess, expectedRespStatus: http.StatusOK, }, + // Test case - 7. + // Bucket does not exist. + 7: { + bucket: "unknown-bucket-name", + objects: successRequest0, + accessKey: credentials.AccessKey, + secretKey: credentials.SecretKey, + expectedRespStatus: http.StatusNotFound, + }, } for i, testCase := range testCases { @@ -888,13 +897,12 @@ func testAPIDeleteMultipleObjectsHandler(obj ObjectLayer, instanceType, bucketNa // Generate a signed or anonymous request based on the testCase if testCase.accessKey != "" { - req, err = newTestSignedRequestV4(http.MethodPost, getDeleteMultipleObjectsURL("", bucketName), + req, err = newTestSignedRequestV4(http.MethodPost, getDeleteMultipleObjectsURL("", testCase.bucket), int64(len(testCase.objects)), bytes.NewReader(testCase.objects), testCase.accessKey, testCase.secretKey, nil) } else { - req, err = newTestRequest(http.MethodPost, getDeleteMultipleObjectsURL("", bucketName), + req, err = newTestRequest(http.MethodPost, getDeleteMultipleObjectsURL("", testCase.bucket), int64(len(testCase.objects)), bytes.NewReader(testCase.objects)) } - if err != nil { t.Fatalf("Failed to create HTTP request for DeleteMultipleObjects: %v", err) } diff --git a/cmd/erasure-healing.go b/cmd/erasure-healing.go index 334075ac0..dbb1b4099 100644 --- a/cmd/erasure-healing.go +++ b/cmd/erasure-healing.go @@ -861,8 +861,12 @@ func isAllBucketsNotFound(errs []error) bool { } notFoundCount := 0 for _, err := range errs { - if err != nil && errors.Is(err, errVolumeNotFound) { - notFoundCount++ + if err != nil { + if errors.Is(err, errVolumeNotFound) { + notFoundCount++ + } else if isErrBucketNotFound(err) { + notFoundCount++ + } } } return len(errs) == notFoundCount diff --git a/cmd/xl-storage.go b/cmd/xl-storage.go index 7bfa7dfa0..170767a30 100644 --- a/cmd/xl-storage.go +++ b/cmd/xl-storage.go @@ -1085,6 +1085,11 @@ func (s *xlStorage) deleteVersions(ctx context.Context, volume, path string, fis } if len(buf) == 0 { + if errors.Is(err, errFileNotFound) && !skipAccessChecks(volume) { + if aerr := Access(volumeDir); aerr != nil && osIsNotExist(aerr) { + return errVolumeNotFound + } + } return errFileNotFound }