fix copying for paused versioning buckets (#7548)
* fix copying for paused versioning buckets * copy for non versioned files * add tests * better tests * Update weed/s3api/s3api_object_handlers_copy.go Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * remove etag * update * Update s3api_object_handlers_copy_test.go * Update weed/s3api/s3api_object_handlers_copy_test.go Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * Update weed/s3api/s3api_object_handlers_copy_test.go Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * revert --------- Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
This commit is contained in:
@@ -230,10 +230,11 @@ func (s3a *S3ApiServer) CopyObjectHandler(w http.ResponseWriter, r *http.Request
|
||||
}
|
||||
}
|
||||
|
||||
// Check if destination bucket has versioning configured
|
||||
dstVersioningConfigured, err := s3a.isVersioningConfigured(dstBucket)
|
||||
// Check if destination bucket has versioning enabled
|
||||
// Only create versions if versioning is explicitly "Enabled", not "Suspended" or unconfigured
|
||||
dstVersioningState, err := s3a.getVersioningState(dstBucket)
|
||||
if err != nil {
|
||||
glog.Errorf("Error checking versioning status for destination bucket %s: %v", dstBucket, err)
|
||||
glog.Errorf("Error checking versioning state for destination bucket %s: %v", dstBucket, err)
|
||||
s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
|
||||
return
|
||||
}
|
||||
@@ -241,7 +242,7 @@ func (s3a *S3ApiServer) CopyObjectHandler(w http.ResponseWriter, r *http.Request
|
||||
var dstVersionId string
|
||||
var etag string
|
||||
|
||||
if dstVersioningConfigured {
|
||||
if shouldCreateVersionForCopy(dstVersioningState) {
|
||||
// For versioned destination, create a new version
|
||||
dstVersionId = generateVersionId()
|
||||
glog.V(2).Infof("CopyObjectHandler: creating version %s for destination %s/%s", dstVersionId, dstBucket, dstObject)
|
||||
@@ -294,6 +295,9 @@ func (s3a *S3ApiServer) CopyObjectHandler(w http.ResponseWriter, r *http.Request
|
||||
w.Header().Set("x-amz-version-id", dstVersionId)
|
||||
} else {
|
||||
// For non-versioned destination, use regular copy
|
||||
// Remove any versioning-related metadata from source that shouldn't carry over
|
||||
cleanupVersioningMetadata(dstEntry.Extended)
|
||||
|
||||
dstPath := util.FullPath(fmt.Sprintf("%s/%s%s", s3a.option.BucketsPath, dstBucket, dstObject))
|
||||
dstDir, dstName := dstPath.DirAndName()
|
||||
|
||||
@@ -2327,6 +2331,25 @@ func (ctx *EncryptionHeaderContext) shouldSkipEncryptedToUnencryptedHeader() boo
|
||||
return hasSourceEncryption && !hasDestinationEncryption && isAnyEncryptionHeader
|
||||
}
|
||||
|
||||
// cleanupVersioningMetadata removes versioning-related metadata from Extended attributes
|
||||
// when copying to non-versioned or suspended-versioning buckets.
|
||||
// This prevents objects in non-versioned buckets from carrying invalid versioning metadata.
|
||||
// It also removes the source ETag to prevent metadata inconsistency, as a new ETag will be
|
||||
// calculated for the destination object.
|
||||
func cleanupVersioningMetadata(metadata map[string][]byte) {
|
||||
delete(metadata, s3_constants.ExtVersionIdKey)
|
||||
delete(metadata, s3_constants.ExtDeleteMarkerKey)
|
||||
delete(metadata, s3_constants.ExtIsLatestKey)
|
||||
delete(metadata, s3_constants.ExtETagKey)
|
||||
}
|
||||
|
||||
// shouldCreateVersionForCopy determines whether a version should be created during a copy operation
|
||||
// based on the destination bucket's versioning state.
|
||||
// Returns true only if versioning is explicitly "Enabled", not "Suspended" or unconfigured.
|
||||
func shouldCreateVersionForCopy(versioningState string) bool {
|
||||
return versioningState == s3_constants.VersioningEnabled
|
||||
}
|
||||
|
||||
// shouldSkipEncryptionHeader determines if a header should be skipped when copying extended attributes
|
||||
// based on the source and destination encryption types. This consolidates the repetitive logic for
|
||||
// filtering encryption-related headers during copy operations.
|
||||
|
||||
Reference in New Issue
Block a user