Thanks to visit codestin.com
Credit goes to github.com

Skip to content

box: fix truncated files being uploaded successfully when the source ends early - #9785

Merged
ncw merged 1 commit into
rclone:masterfrom
r0h1tb:fix/box-truncated-upload
Aug 21, 2026
Merged

ncw merged 1 commit into
rclone:masterfrom
r0h1tb:fix/box-truncated-upload

Conversation

@r0h1tb

@r0h1tb r0h1tb commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Continues the "source ends early" sweep (5d05754 sia, a2baa97 pikpak, e1bf940 filelu,
7357fb8 internetarchive, 884b28c azurefiles, 18fa445 compress).

Problem

(*Object).upload — the single-shot path taken when the size is at or below
upload_cutoff (50 MiB by default) — passes the source straight to Box as the multipart
body:

opts := rest.Opts{
    Method:               "POST",
    Body:                 in,
    MultipartContentName: "contents",
    ...
}

No ContentLength is set, so the request is chunked and a source that stops short simply
produces a shorter body. Box accepts it, returns one entry, and the upload is reported as a
success with a truncated file stored.

uploadMultipart is not affected: it fills each chunk with io.ReadFull, which returns
io.ErrUnexpectedEOF when the source ends early.

Fix

Wrap the body in readers.NewCountingReader and compare the bytes actually read against the
declared size, matching the sia fix. size is already computed in Update and passed to
uploadMultipart; it is now passed to upload as well.

Verification

go build ./..., go test ./backend/box/... and golangci-lint run ./backend/box/...
(0 issues) all pass. RCLONE_CONFIG=/notfound go test ./... is unchanged from master:
cmd/gitannex and cmd/serve/s3 fail identically before and after this commit on my
machine (no git-annex or minio binary locally). No Box remote here, so the backend
integration tests have not been run against a real remote.

Possibly the same, not yet checked

While looking for this I noticed four more backends that stream the source with no
ContentLength and no byte-count check, so they may have the same problem — flagging rather
than claiming, as I have not confirmed any of them:

yandex (yandex.go:1135), gofile (gofile.go:1450), filefabric
(filefabric.go:1276), googlephotos (googlephotos.go:1198).

Happy to follow up on those if useful.

…ends early

The single-shot upload path sent the source straight to Box as a multipart
body with no Content-Length, so a source that supplied fewer bytes than its
declared size produced a short request that Box accepted and stored, and the
upload was reported as a success.

Count the bytes actually read and fail the upload if they do not match the
declared size. The multipart path already reads each chunk with io.ReadFull
and so already fails in this case.

@ncw ncw left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, nice fix.

I checked the integration tests

=== RUN TestIntegration/FsMkdir/FsPutShortEOF/Simple
fstests.go:2596: Put returned an error (acceptable): expected 10240 bytes in input, but got 5120: unexpected EOF

👍

@ncw
ncw merged commit 64ab1ac into rclone:master Aug 21, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants