From 6ef934f1b5251e0c9d276ec871e133768926c28b Mon Sep 17 00:00:00 2001 From: MadDogOwner Date: Sat, 29 Aug 2026 15:54:05 +0800 Subject: [PATCH] fix(server/s3): ensure resource close safely Signed-off-by: MadDogOwner --- server/s3/multipart.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/server/s3/multipart.go b/server/s3/multipart.go index 806986470..7261ea361 100644 --- a/server/s3/multipart.go +++ b/server/s3/multipart.go @@ -39,9 +39,12 @@ type multipartPart struct { // multipartState tracks one in-progress multipart upload. // -// gofakes3 does not serialize multipart operations for a given UploadID, so -// the parts map is guarded by mu. Each part is written to its own file inside -// dir, so concurrent UploadPart calls for different part numbers are safe. +// Concurrency: gofakes3 does not serialize operations for the same uploadID, +// so concurrent UploadPart/Complete/Abort calls may overlap. The parts map is +// protected by mu. Each part is written to its own file inside dir, so +// concurrent UploadPart calls for different part numbers are safe without +// additional locking. lastActivity is updated under mu on create and on each +// part upload so the reaper can make a consistent expiry decision. type multipartState struct { bucket string object string @@ -229,8 +232,9 @@ func (b *s3Backend) CompleteMultipartUpload(ctx context.Context, bucket, object return firstErr }) + defer combined.Close() + err := b.putStream(ctx, bucket, object, state.meta, combined, total) - _ = combined.Close() if err != nil { // Leave the upload in place so the client may retry completion, per // the gofakes3 MultipartBackend contract.