Skip to content

feat(xattr): generic unknown-section passthrough on RevisionXAttr - #244

Open
major0 wants to merge 2 commits into
ProtonMail:masterfrom
major0:feat/xattr-mode-field
Open

feat(xattr): generic unknown-section passthrough on RevisionXAttr#244
major0 wants to merge 2 commits into
ProtonMail:masterfrom
major0:feat/xattr-mode-field

Conversation

@major0

@major0 major0 commented Jul 29, 2026

Copy link
Copy Markdown

feat(xattr): generic unknown-section passthrough on RevisionXAttr

Add a forward-compatible passthrough for arbitrary top-level XAttr
sections so unmodeled data (Media, Camera, Location, POSIX, ...)
survives a decode/encode cycle byte-equivalently.

  • Add Extra map[string]json.RawMessage (json:"-") to RevisionXAttr
    with custom MarshalJSON/UnmarshalJSON via the alias-type technique:
    the typed Common section is handled through revisionXAttrAlias while
    every other top-level section is captured into / spliced from Extra
    verbatim. Top-level keys are emitted in sorted order for deterministic
    output. Typed Common wins over any stray Extra["Common"]; a blob
    with no Common yields a zero Common plus all sections in Extra; an
    empty object leaves Extra nil.
  • Add Mode field t POSIX namesapce for storing Unix permission bits.
    Zero means unset; existing revisions without Mode decode cleanly.
  • Switch helper signatures to carry the full *RevisionXAttr:
    SetEncXAttrString marshals Common + Extra together, and both
    GetDecXAttrString methods (on RevisionMetadata and Revision) return
    *RevisionXAttr (nil when no XAttr is present).
  • Add rapid property tests plus lossless unit tests covering round-trip
    byte-equivalence, marshal determinism, and the stray-Common, no-Common,
    and empty-object cases.

Depends-on: #237 (feat/file_extended_attributes)

@major0
major0 force-pushed the feat/xattr-mode-field branch from b6f7ea5 to 49503d2 Compare July 29, 2026 22:19
@major0 major0 changed the title feat(xattr): add Mode field to RevisionXAttrCommon feat(xattr): generic unknown-section passthrough on RevisionXAttr Jul 29, 2026
@major0
major0 force-pushed the feat/xattr-mode-field branch 3 times, most recently from e4889bb to b57516a Compare July 31, 2026 13:45
@major0
major0 force-pushed the feat/xattr-mode-field branch from b57516a to 3ed4ee5 Compare August 11, 2026 15:17
major0 added 2 commits August 22, 2026 07:15
Expose the extended-attribute types (RevisionXAttrCommon,
RevisionXAttr) and SetEncXAttrString on UpdateRevisionReq. Add the
XAttr field to Link, RevisionMetadata, and Revision, plus
GetDecXAttrString helpers on RevisionMetadata and Revision that
decrypt the XAttr blob into a RevisionXAttrCommon.
Add a forward-compatible passthrough for arbitrary top-level XAttr
sections so unmodeled data (Media, Camera, Location, POSIX, ...)
survives a decode/encode cycle byte-equivalently.

- Add `Extra map[string]json.RawMessage` (json:"-") to RevisionXAttr
  with custom MarshalJSON/UnmarshalJSON via the alias-type technique:
  the typed `Common` section is handled through revisionXAttrAlias while
  every other top-level section is captured into / spliced from `Extra`
  verbatim. Top-level keys are emitted in sorted order for deterministic
  output. Typed `Common` wins over any stray `Extra["Common"]`; a blob
  with no `Common` yields a zero Common plus all sections in `Extra`; an
  empty object leaves `Extra` nil.
- Add `Mode` field t `POSIX` namesapce for storing Unix permission bits.
  Zero means unset; existing revisions without Mode decode cleanly.
- Switch helper signatures to carry the full *RevisionXAttr:
  SetEncXAttrString marshals Common + Extra together, and both
  GetDecXAttrString methods (on RevisionMetadata and Revision) return
  *RevisionXAttr (nil when no XAttr is present).
- Add rapid property tests plus lossless unit tests covering round-trip
  byte-equivalence, marshal determinism, and the stray-Common, no-Common,
  and empty-object cases.

This also closes a latent data-loss bug: the previous typed-only encoding
emitted only Common, so re-encoding an XAttr silently dropped any sibling
section written by other Proton clients (Media, Camera, Location). Any
read-modify-write of a revision's XAttr would clobber those sections.
The Extra passthrough makes "change one section, preserve the rest" hold.
@major0
major0 force-pushed the feat/xattr-mode-field branch from 3ed4ee5 to 3fe3a03 Compare August 22, 2026 14:17
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.

1 participant