From a6acbd1844a47ff89ef48e332909d6dafe08e9bf Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Tue, 27 Jun 2023 15:24:48 +0100 Subject: [PATCH] uptobox: fix Update returning the wrong object Before this patch the Update method had a 50/50 chance of returning the old object rather than the new updated object. This was discovered in the integration tests. This patch fixes the problem by deleting the duplicate object before we look for the new object. --- backend/uptobox/uptobox.go | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/backend/uptobox/uptobox.go b/backend/uptobox/uptobox.go index be2da1569..0f7777cc0 100644 --- a/backend/uptobox/uptobox.go +++ b/backend/uptobox/uptobox.go @@ -482,11 +482,11 @@ func (f *Fs) updateFileInformation(ctx context.Context, update *api.UpdateFileIn return err } -func (f *Fs) putUnchecked(ctx context.Context, in io.Reader, remote string, size int64, options ...fs.OpenOption) (fs.Object, error) { +func (f *Fs) putUnchecked(ctx context.Context, in io.Reader, remote string, size int64, options ...fs.OpenOption) error { if size > int64(200e9) { // max size 200GB - return nil, errors.New("file too big, can't upload") + return errors.New("file too big, can't upload") } else if size == 0 { - return nil, fs.ErrorCantUploadEmptyFiles + return fs.ErrorCantUploadEmptyFiles } // yes it does take 4 requests if we're uploading to root and 6+ if we're uploading to any subdir :( @@ -504,19 +504,19 @@ func (f *Fs) putUnchecked(ctx context.Context, in io.Reader, remote string, size return shouldRetry(ctx, resp, err) }) if err != nil { - return nil, err + return err } if info.StatusCode != 0 { - return nil, fmt.Errorf("putUnchecked api error: %d - %s", info.StatusCode, info.Message) + return fmt.Errorf("putUnchecked api error: %d - %s", info.StatusCode, info.Message) } // we need to have a safe name for the upload to work tmpName := "rcloneTemp" + random.String(8) upload, err := f.uploadFile(ctx, in, size, tmpName, info.Data.UploadLink, options...) if err != nil { - return nil, err + return err } if len(upload.Files) != 1 { - return nil, errors.New("upload unexpected response") + return errors.New("upload unexpected response") } match := f.IDRegexp.FindStringSubmatch(upload.Files[0].URL) @@ -531,12 +531,12 @@ func (f *Fs) putUnchecked(ctx context.Context, in io.Reader, remote string, size // this might need some more error handling. if any of the following requests fail // we'll leave an orphaned temporary file floating around somewhere // they rarely fail though - return nil, err + return err } err = f.move(ctx, fullBase, match[1]) if err != nil { - return nil, err + return err } } @@ -548,11 +548,10 @@ func (f *Fs) putUnchecked(ctx context.Context, in io.Reader, remote string, size Public: f.public, }) if err != nil { - return nil, err + return err } - // finally fetch the file object. - return f.NewObject(ctx, remote) + return nil } // Put in to the remote path with the modTime given of the given size @@ -582,7 +581,11 @@ func (f *Fs) Put(ctx context.Context, in io.Reader, src fs.ObjectInfo, options . // This will create a duplicate if we upload a new file without // checking to see if there is one already - use Put() for that. func (f *Fs) PutUnchecked(ctx context.Context, in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) (fs.Object, error) { - return f.putUnchecked(ctx, in, src.Remote(), src.Size(), options...) + err := f.putUnchecked(ctx, in, src.Remote(), src.Size(), options...) + if err != nil { + return nil, err + } + return f.NewObject(ctx, src.Remote()) } // CreateDir dir creates a directory with the given parent path @@ -1026,7 +1029,7 @@ func (o *Object) Update(ctx context.Context, in io.Reader, src fs.ObjectInfo, op } // upload with new size but old name - info, err := o.fs.putUnchecked(ctx, in, o.Remote(), src.Size(), options...) + err := o.fs.putUnchecked(ctx, in, o.Remote(), src.Size(), options...) if err != nil { return err } @@ -1037,6 +1040,12 @@ func (o *Object) Update(ctx context.Context, in io.Reader, src fs.ObjectInfo, op return fmt.Errorf("failed to remove old version: %w", err) } + // Fetch new object after deleting the duplicate + info, err := o.fs.NewObject(ctx, o.Remote()) + if err != nil { + return err + } + // Replace guts of old object with new one *o = *info.(*Object)