Skip to content

fix(document-provider): wait for pending uploads before rename, move and copy - #17989

Open
kilrau wants to merge 2 commits into
nextcloud:masterfrom
kilrau:fix/saf-rename-waits-for-pending-upload
Open

kilrau wants to merge 2 commits into
nextcloud:masterfrom
kilrau:fix/saf-rename-waits-for-pending-upload

Conversation

@kilrau

@kilrau kilrau commented Nov 7, 2026 •

Copy link
Copy Markdown

Fixes #7846

Description

I encountered the pain of Signal's local backup to a Nextcloud folder leaving me with 0-byte files and Nextcloud in a retry loop until my phone battery was drained. Very frustrating situation as it takes a while to realize what's happening and search for a workaround (let Signal write to local Android folder and add this folder manually to Nextcloud Auto Upload) - see linked issue. As one can see from the issue as well, not only Signal but all apps that rename, move or copy right after writing a file are affected.

Out of scope: delete-after-write, read-after-write, an older write undoing a rename and potentially others

This is a first attempt to fix the underlying issue, split into two commits:

  1. fix(document-provider): wait for pending uploads before rename, move and copy: before renaming, moving or copying a file, the provider waits until its upload has been queued and finished.
  2. fix(document-provider): also wait for pending uploads inside renamed, moved or copied folders: does the same for folders.

Open questions for maintainers

  1. Blocking a binder thread. The wait blocks the caller's binder thread inside renameDocument/moveDocument/copyDocument, with no overall limit, so that large uploads (several GB) on a slow connection still complete. It gives up only after 10 minutes without progress. Is blocking acceptable here, or
    would you prefer an overall cap, or failing fast and leaving the retry to the calling app?
  2. Idle timeout during server-side chunk assembly. Progress is measured in bytes transferred. After the last chunk, the server assembles the file, and no bytes move during that time. For very large files the assembly may take longer than 10 minutes, and the wait would then fail even though the upload succeeds. Should the timeout be longer, or is there a better way to handle this?

🖼️ Screenshots (Didn't take any)

🏚️ Before 🏡 After
0 byte files Files arrive complete

🏁 Checklist

  • ⛑️ Tests (unit tests, DAO and provider instrumented tests, and an emulator run against a real server with files up to 50 MB)
  • 🔙 Backport requests are created or not needed: /backport to stable-xx.x
  • 📅 Milestone is set
  • 🌸 PR title is meaningful (if it should be in the changelog: is it meaningful to users?)

🤖 AI (if applicable)

  • The content of this PR was partly or fully generated using AI (Claude Opus 5.5: code, tests. Reviewed and tested with a sample app writing signal-style backups by me)

@kilrau
kilrau marked this pull request as ready for review November 8, 2026 11:01
…and copy

Content written through the documents provider is uploaded asynchronously
after the file descriptor is closed, and the queued upload is bound to the
remote path at that moment. A rename, move or copy issued right after the
write ran on the server against the empty placeholder created by
createDocument, and the upload was left pointing at a path that no longer
existed. Apps that write to a temporary name and rename it when done (e.g.
Signal's local backups) ended up with 0 byte files on the server.

- Track every write in openForWrite before the file descriptor is handed
  out, as OPEN and then CLOSED_UPLOAD_NOT_QUEUED once the close is reported.
  The mark ends when the upload job is enqueued: startFilesUploadJob now
  returns its Job, which completes once WorkManager accepted the chain or
  enqueueing failed.
- Rename, move and copy wait while a write is CLOSED_UPLOAD_NOT_QUEUED or the
  scheduled upload job still has to process the document: its upload row is
  in progress, or failed with a result the job retries. Rows are matched by
  account and exact path. An OPEN write is waited for only for a short
  grace period, since the close is reported asynchronously; a document that
  stays open is not blocked on.
- The wait gives up only when no upload bytes of the account have been
  transferred for 10 minutes, so uploads that take hours are not cut short.

Refs nextcloud#7846

Assisted-by: ClaudeCode:claude-opus-5-5
Signed-off-by: Kilian <19181985+kilrau@users.noreply.github.com>
… moved or copied folders

Renaming, moving or copying a folder right after writing a file inside it
has the same problem as doing it to the file itself: the server-side
operation runs against the empty placeholder and the queued upload targets
the old path. Signal's current local backups write each snapshot into a
signal-backup-<timestamp>-tmp folder and rename the folder when done, so
they still end up with 0 byte files without this.

Wait for writes and unfinished uploads of every file below the folder as
well, matched by account and remote path prefix.

Refs nextcloud#7846

Assisted-by: ClaudeCode:claude-opus-5-5
Signed-off-by: Kilian <19181985+kilrau@users.noreply.github.com>
@kilrau
kilrau force-pushed the fix/saf-rename-waits-for-pending-upload branch from c5c8ba3 to 06c2a63 Compare November 10, 2026 13:02

This branch has not been deployed

No deployments
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.

Some apps (Signal, SMS Backup&Restore) can't upload backups via SAF

1 participant