Stop Writer.Resume from finishing an unfinished large file whose parts do not match the new content

Aperta
#177 1 commento 0 reazioni 1 assegnatario Vedi su GitHub

I maintainer di solito rispondono entro 1 giorno

@ffumero2003 ci sta già lavorando.

Dal 28/10/2026.

Valutazione

Questa issue non è ancora stata valutata.

Descrizione

bug

Context

With Writer.Resume = true, the writer picks an unfinished large file by name alone and finishes it with every part B2 already holds. It compares SHA-1s only for parts the new stream reaches. Parts beyond the end of the new content are never checked and stay in the part list sent to b2_finish_large_file, so the stored object is the earlier, longer content while Close returns nil. When several unfinished uploads share the name, the last one listed wins. When a mismatch is detected, there is no way to cancel and restart other than by hand.

Stale content type and file info on resume are tracked in Backblaze/blazer#156 and are not part of this issue.

Current behavior

At a5e0d13:

  • b2/writer.go:419-428: selection by exact name; last match wins. The listing is not prefix-scoped on the server: base/base.go:1595-1600 (ListUnfinishedLargeFiles) sends no prefix, so every unfinished file in the bucket is paged through.
  • b2/writer.go:443-467: every listed part goes into seen; base/base.go:1456-1468 (CompileParts) and :1563-1592 (FinishLargeFile) send all of seen as partSha1Array.
  • b2/writer.go:201-212: the only content check, per chunk the new stream produces.
  • b2/writer.go:436-441: checkResumedLock and checkResumedEncryption compare Object Lock and encryption settings (including the SSE-C key ID added in merged Backblaze/blazer#153), not the part count or size.
  • b2/writer.go:201-204: the mismatch path returns without cnk.buf.Close(), leaving a temp file in FileBufferDir with UseFileBuffer.

Reproduced locally with a recording test server: an unfinished file with five 4-byte parts (aaaa to eeee), resumed with ChunkSize = 4 and 12 bytes aaaabbbbcccc. Close returned nil, no part was uploaded, and the finish request carried five part hashes. With two unfinished files of the same name listed, the writer finished the last one.

Expected behavior

Resume either finishes exactly the new content, or returns an error.

Acceptance criteria

  • R1. Resuming with content shorter than the unfinished upload returns an error (or restarts in the opt-in mode) and never finishes with extra parts.
  • R2. Two unfinished uploads with the same name give a deterministic, documented outcome.
  • R3. The mismatch path removes the file-buffer temp file.

In scope

Proposed change

In getLargeFile (b2/writer.go):

  1. List with the name as server-side prefix and, when more than one unfinished file matches, refuse or choose deterministically (newest first) and document it.
  2. At Close, refuse to finish unless the part list is exactly 1..n for the new content.
  3. Add an opt-in mode that cancels a mismatched unfinished file and starts a new one.
  4. Close the chunk buffer on the mismatch path.

Behavior without Resume does not change.

Out of scope

  • Stale content type and file info on resume, tracked in #156.
  • Changes to behavior without Resume.

Verification

Run the repository regression checks with live credentials unset:

unset B2_APPLICATION_KEY_ID B2_APPLICATION_KEY B2_ACCOUNT_ID B2_ACCOUNT_KEY
go build ./...
go vet ./...
go test -race -count=1 ./b2/... ./base
  • Reproduce the supplied five-part unfinished upload resumed with only three parts, and the multiple unfinished-file selection case.
  • Assert no finish publishes extra parts, the selected outcome is deterministic/documented, and the mismatch path removes the file-buffer temp file; show match controls still pass.
  • Expected result: the checks above succeed and the observable outcomes in Acceptance criteria are demonstrated. If a check cannot run, report Could not run because: ...; if it starts but fails, report Could not complete because: .... A skipped check is not a pass.

Links

Backblaze/blazer#156 (stale content type or file info on resume). Merged Backblaze/blazer#153 added SSE-C checks to the same resume path. Backblaze/blazer#157 (resume in the sync engine) would rely on this path.

Lingua principale
Go
Stelle
66
Fork
18
Merge medio
1g 10h
PR unite (30g)
132

Preparare l'ambiente

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di Backblaze/blazer

Tutte le issue di Backblaze/blazer

Issue simili

Altre issue su Go

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.