feat(xattr): generic unknown-section passthrough on RevisionXAttr - #244
Open
major0 wants to merge 2 commits into
Open
feat(xattr): generic unknown-section passthrough on RevisionXAttr#244major0 wants to merge 2 commits into
major0 wants to merge 2 commits into
Conversation
major0
force-pushed
the
feat/xattr-mode-field
branch
from
July 29, 2026 22:19
b6f7ea5 to
49503d2
Compare
major0
force-pushed
the
feat/xattr-mode-field
branch
3 times, most recently
from
July 31, 2026 13:45
e4889bb to
b57516a
Compare
major0
force-pushed
the
feat/xattr-mode-field
branch
from
August 11, 2026 15:17
b57516a to
3ed4ee5
Compare
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
force-pushed
the
feat/xattr-mode-field
branch
from
August 22, 2026 14:17
3ed4ee5 to
3fe3a03
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.
Extra map[string]json.RawMessage(json:"-") to RevisionXAttrwith custom MarshalJSON/UnmarshalJSON via the alias-type technique:
the typed
Commonsection is handled through revisionXAttrAlias whileevery other top-level section is captured into / spliced from
Extraverbatim. Top-level keys are emitted in sorted order for deterministic
output. Typed
Commonwins over any strayExtra["Common"]; a blobwith no
Commonyields a zero Common plus all sections inExtra; anempty object leaves
Extranil.Modefield tPOSIXnamesapce for storing Unix permission bits.Zero means unset; existing revisions without Mode decode cleanly.
SetEncXAttrString marshals Common + Extra together, and both
GetDecXAttrString methods (on RevisionMetadata and Revision) return
*RevisionXAttr (nil when no XAttr is present).
byte-equivalence, marshal determinism, and the stray-Common, no-Common,
and empty-object cases.
Depends-on: #237 (feat/file_extended_attributes)