mirror of
https://github.com/pgsty/minio.git
synced 2026-11-10 09:35:31 +03:00
fix(batch): let a write refuse to replace a locked version
Add ObjectOptions.RefuseLockedOverwrite. With it set, PutObject (before the rename) and CompleteMultipartUpload check, under the destination's write lock, the stored version the write would replace: the version it addresses, or the null version. DeleteObject checks the stored version that a delete marker it writes names; in a multi-pool deployment that version is resolved across pools. A version under retention or legal hold is refused with ObjectLocked. The check reads the version's own metadata, whatever the bucket configuration, and returns read errors. Nothing sets the option yet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Feng Ruohang <rh@vonng.com>
This commit is contained in:
@@ -1676,6 +1676,15 @@ func (er erasureObjects) putObject(ctx context.Context, bucket string, object st
|
||||
return ObjectInfo{}, toObjectErr(err, bucket, object)
|
||||
}
|
||||
}
|
||||
if opts.RefuseLockedOverwrite {
|
||||
getObjectInfo := er.getObjectInfo
|
||||
if opts.replicaObjectInfo != nil {
|
||||
getObjectInfo = opts.replicaObjectInfo
|
||||
}
|
||||
if err := checkVersionLockedForOverwrite(ctx, bucket, object, fi.VersionID, getObjectInfo, opts.Transition); err != nil {
|
||||
return ObjectInfo{}, toObjectErr(err, bucket, object)
|
||||
}
|
||||
}
|
||||
|
||||
// Rename the successfully written temporary object to final location.
|
||||
onlineDisks, versions, oldDataDir, err := renameData(ctx, onlineDisks, minioMetaTmpBucket, tempObj, partsMetadata, bucket, object, writeQuorum)
|
||||
@@ -2199,6 +2208,13 @@ func (er erasureObjects) DeleteObject(ctx context.Context, bucket, object string
|
||||
}
|
||||
}
|
||||
|
||||
// A delete marker that names a stored version replaces it.
|
||||
if opts.RefuseLockedOverwrite && opts.DeleteMarker && opts.VersionID != "" {
|
||||
if err := refuseLockedMarkerOverwrite(ctx, bucket, object, opts.VersionID, goi, gerr); err != nil {
|
||||
return ObjectInfo{}, err
|
||||
}
|
||||
}
|
||||
|
||||
if opts.Expiration.Expire && !opts.Expiration.CheckedAllPools {
|
||||
if gerr == nil {
|
||||
evt := evalActionFromLifecycle(ctx, *lc, rcfg, replcfg, goi)
|
||||
|
||||
Reference in New Issue
Block a user