Skip to content

[stable-34.0] Detect upload conflicts with an If-Match precondition#10394

Merged
mgallien merged 1 commit into
stable-34.0from
backport/10393/stable-34.0
Jul 17, 2026
Merged

[stable-34.0] Detect upload conflicts with an If-Match precondition#10394
mgallien merged 1 commit into
stable-34.0from
backport/10393/stable-34.0

Conversation

@backportbot

@backportbot backportbot Bot commented Jul 17, 2026

Copy link
Copy Markdown

Backport of PR #10393

…tion

Content uploads on the modify path were unconditional PUTs: the extension
never told the server "only accept this if your copy is still the version I
edited." When the server copy changed since the last sync — another device or
user, or an app such as Adobe InDesign/Illustrator issuing rapid multi-step
re-saves — the client silently overwrote it (last-writer-wins, data loss).

Send the base version's etag as an `If-Match` precondition so the server
rejects a conflicting write with 412 Precondition Failed instead of clobbering.
`modifyContents` now takes `baseVersion` + `options` (threaded from the
`modify` call site) and derives the base etag from `baseVersion.contentVersion`
(falling back to the stored metadata etag).

Behaviour is tiered by OS, because Apple's real conflict-resolution contract —
`NSFileProviderModifyItemFailOnConflict` and the
`.localVersionConflictingWithServer` error — is macOS 26.0+ only, while the
extension deploys back to macOS 13:

  * macOS 26+ with the system's `.failOnConflict` option: on 412 return
    `.localVersionConflictingWithServer` so the system creates a conflict copy
    and both versions survive. Advertised via
    `NSExtensionFileProviderSupportsFailingUploadOnConflict` in Info.plist.
  * macOS 13–25 (best-effort heuristic): always send `If-Match`; on 412 clear
    any lock token, signal a working-set re-enumeration, and return a transient
    NSCocoaError so the system re-fetches the server version before re-driving
    the edit — turning a silent overwrite into a visible sync round-trip.
  * macOS 26+ without `.failOnConflict`: unchanged (no `If-Match` sent).

A `sentIfMatch` guard (we only send `If-Match` when a base etag exists) gates
the new 412-as-conflict branch, so a lock-only 412 keeps its previous
stale-lock meaning.

Scope: the single-PUT modify path. Chunked (large-file) uploads need an
upstream NextcloudKit change (an `If-Match` scoped to the assembly MOVE only,
so it does not ride on the chunk PUTs) and are a deferred follow-up.

Tests: added coverage for the precondition being sent, the macOS 26+ conflict
return, and the macOS < 26 transient-retry path; updated the existing 412
lock-token test for the new OS-dependent behaviour; added a
`lastUploadIfMatchHeader` capture knob to the mock remote interface.

Signed-off-by: Iva Horn <iva.horn@nextcloud.com>
@backportbot
backportbot Bot requested review from camilasan and i2h3 as code owners July 17, 2026 14:07
@backportbot
backportbot Bot requested a review from i2h3 July 17, 2026 14:07
@backportbot backportbot Bot added bug os: 🍎 macOS Apple macOS, formerly also known as OS X 3. to review feature: 📁 file provider macOS File Provider Extension, more general also known as virtual file system. labels Jul 17, 2026
@backportbot backportbot Bot added this to the 34.0.0 milestone Jul 17, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Artifact containing the AppImage: nextcloud-appimage-pr-10394.zip

Digest: sha256:e0ff7e411af49aa03da9e72caa68455f5764dbbdac85e08357078240972de138

To test this change/fix you can download the above artifact file, unzip it, and run it.

Please make sure to quit your existing Nextcloud app and backup your data.

@sonarqubecloud

Copy link
Copy Markdown

@mgallien
mgallien merged commit 65ef09c into stable-34.0 Jul 17, 2026
21 checks passed
@mgallien
mgallien deleted the backport/10393/stable-34.0 branch July 17, 2026 15:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

3. to review bug feature: 📁 file provider macOS File Provider Extension, more general also known as virtual file system. os: 🍎 macOS Apple macOS, formerly also known as OS X

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants