aboutsummaryrefslogtreecommitdiff
path: root/weed/s3api/s3api_object_handlers_delete.go
diff options
context:
space:
mode:
Diffstat (limited to 'weed/s3api/s3api_object_handlers_delete.go')
-rw-r--r--weed/s3api/s3api_object_handlers_delete.go71
1 files changed, 57 insertions, 14 deletions
diff --git a/weed/s3api/s3api_object_handlers_delete.go b/weed/s3api/s3api_object_handlers_delete.go
index d7457fabe..35c842e6c 100644
--- a/weed/s3api/s3api_object_handlers_delete.go
+++ b/weed/s3api/s3api_object_handlers_delete.go
@@ -49,6 +49,16 @@ func (s3a *S3ApiServer) DeleteObjectHandler(w http.ResponseWriter, r *http.Reque
auditLog = s3err.GetAccessLog(r, http.StatusNoContent, s3err.ErrNone)
}
+ // Check object lock permissions before deletion (only for versioned buckets)
+ if versioningEnabled {
+ bypassGovernance := r.Header.Get("x-amz-bypass-governance-retention") == "true"
+ if err := s3a.checkObjectLockPermissions(bucket, object, versionId, bypassGovernance); err != nil {
+ glog.V(2).Infof("DeleteObjectHandler: object lock check failed for %s/%s: %v", bucket, object, err)
+ s3err.WriteErrorResponse(w, r, s3err.ErrAccessDenied)
+ return
+ }
+ }
+
if versioningEnabled {
// Handle versioned delete
if versionId != "" {
@@ -117,9 +127,10 @@ func (s3a *S3ApiServer) DeleteObjectHandler(w http.ResponseWriter, r *http.Reque
w.WriteHeader(http.StatusNoContent)
}
-// / ObjectIdentifier carries key name for the object to delete.
+// ObjectIdentifier represents an object to be deleted with its key name and optional version ID.
type ObjectIdentifier struct {
- ObjectName string `xml:"Key"`
+ Key string `xml:"Key"`
+ VersionId string `xml:"VersionId,omitempty"`
}
// DeleteObjectsRequest - xml carrying the object key names which needs to be deleted.
@@ -132,9 +143,10 @@ type DeleteObjectsRequest struct {
// DeleteError structure.
type DeleteError struct {
- Code string
- Message string
- Key string
+ Code string `xml:"Code"`
+ Message string `xml:"Message"`
+ Key string `xml:"Key"`
+ VersionId string `xml:"VersionId,omitempty"`
}
// DeleteObjectsResponse container for multiple object deletes.
@@ -180,18 +192,48 @@ func (s3a *S3ApiServer) DeleteMultipleObjectsHandler(w http.ResponseWriter, r *h
if s3err.Logger != nil {
auditLog = s3err.GetAccessLog(r, http.StatusNoContent, s3err.ErrNone)
}
+
+ // Check for bypass governance retention header
+ bypassGovernance := r.Header.Get("x-amz-bypass-governance-retention") == "true"
+
+ // Check if versioning is enabled for the bucket (needed for object lock checks)
+ versioningEnabled, err := s3a.isVersioningEnabled(bucket)
+ if err != nil {
+ if err == filer_pb.ErrNotFound {
+ s3err.WriteErrorResponse(w, r, s3err.ErrNoSuchBucket)
+ return
+ }
+ glog.Errorf("Error checking versioning status for bucket %s: %v", bucket, err)
+ s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
+ return
+ }
+
s3a.WithFilerClient(false, func(client filer_pb.SeaweedFilerClient) error {
// delete file entries
for _, object := range deleteObjects.Objects {
- if object.ObjectName == "" {
+ if object.Key == "" {
continue
}
- lastSeparator := strings.LastIndex(object.ObjectName, "/")
- parentDirectoryPath, entryName, isDeleteData, isRecursive := "", object.ObjectName, true, false
- if lastSeparator > 0 && lastSeparator+1 < len(object.ObjectName) {
- entryName = object.ObjectName[lastSeparator+1:]
- parentDirectoryPath = "/" + object.ObjectName[:lastSeparator]
+
+ // Check object lock permissions before deletion (only for versioned buckets)
+ if versioningEnabled {
+ if err := s3a.checkObjectLockPermissions(bucket, object.Key, object.VersionId, bypassGovernance); err != nil {
+ glog.V(2).Infof("DeleteMultipleObjectsHandler: object lock check failed for %s/%s (version: %s): %v", bucket, object.Key, object.VersionId, err)
+ deleteErrors = append(deleteErrors, DeleteError{
+ Code: s3err.GetAPIError(s3err.ErrAccessDenied).Code,
+ Message: s3err.GetAPIError(s3err.ErrAccessDenied).Description,
+ Key: object.Key,
+ VersionId: object.VersionId,
+ })
+ continue
+ }
+ }
+ lastSeparator := strings.LastIndex(object.Key, "/")
+ parentDirectoryPath, entryName, isDeleteData, isRecursive := "", object.Key, true, false
+ if lastSeparator > 0 && lastSeparator+1 < len(object.Key) {
+ entryName = object.Key[lastSeparator+1:]
+ parentDirectoryPath = "/" + object.Key[:lastSeparator]
}
parentDirectoryPath = fmt.Sprintf("%s/%s%s", s3a.option.BucketsPath, bucket, parentDirectoryPath)
@@ -204,9 +246,10 @@ func (s3a *S3ApiServer) DeleteMultipleObjectsHandler(w http.ResponseWriter, r *h
} else {
delete(directoriesWithDeletion, parentDirectoryPath)
deleteErrors = append(deleteErrors, DeleteError{
- Code: "",
- Message: err.Error(),
- Key: object.ObjectName,
+ Code: "",
+ Message: err.Error(),
+ Key: object.Key,
+ VersionId: object.VersionId,
})
}
if auditLog != nil {