b2: fix multipart upload: corrupted on transfer: sizes differ XXX vs 0

Before this change the b2 backend wasn't writing the metadata to the
object properly after a multipart upload.

The symptom of this was that sometimes it would give the error:

    corrupted on transfer: sizes differ XXX vs 0

This was fixed by returning the metadata in the chunk writer and setting it in Update.

See: https://forum.rclone.org/t/multipart-upload-to-b2-sometimes-failing-with-corrupted-on-transfer-sizes-differ/41829
This commit is contained in:
Nick Craig-Wood 2023-09-18 20:41:31 +01:00
parent 9277ca1e54
commit 6072d314e1
2 changed files with 9 additions and 3 deletions

View File

@ -1930,11 +1930,15 @@ func (o *Object) Update(ctx context.Context, in io.Reader, src fs.ObjectInfo, op
return err return err
} }
} else if size > int64(o.fs.opt.UploadCutoff) { } else if size > int64(o.fs.opt.UploadCutoff) {
_, err := multipart.UploadMultipart(ctx, src, in, multipart.UploadMultipartOptions{ chunkWriter, err := multipart.UploadMultipart(ctx, src, in, multipart.UploadMultipartOptions{
Open: o.fs, Open: o.fs,
OpenOptions: options, OpenOptions: options,
}) })
return err if err != nil {
return err
}
up := chunkWriter.(*largeUpload)
return o.decodeMetaDataFileInfo(up.info)
} }
modTime := src.ModTime(ctx) modTime := src.ModTime(ctx)

View File

@ -85,6 +85,7 @@ type largeUpload struct {
uploads []*api.GetUploadPartURLResponse // result of get upload URL calls uploads []*api.GetUploadPartURLResponse // result of get upload URL calls
chunkSize int64 // chunk size to use chunkSize int64 // chunk size to use
src *Object // if copying, object we are reading from src *Object // if copying, object we are reading from
info *api.FileInfo // final response with info about the object
} }
// newLargeUpload starts an upload of object o from in with metadata in src // newLargeUpload starts an upload of object o from in with metadata in src
@ -352,7 +353,8 @@ func (up *largeUpload) Close(ctx context.Context) error {
if err != nil { if err != nil {
return err return err
} }
return up.o.decodeMetaDataFileInfo(&response) up.info = &response
return nil
} }
// Abort aborts the large upload // Abort aborts the large upload