fix(metadata): reject --chmod copy-syntax clauses like upstream#6561
Merged
Conversation
rsync's --chmod grammar does not implement chmod(1)'s copy-from-category form. A category letter (u/g/o) in the permission half of a clause (e.g. g=u, o=g, u+g) is rejected by upstream chmod.c parse_chmod STATE_2ND_HALF (default: -> STATE_ERROR); the caller in options.c emits 'Invalid argument passed to --chmod (%s)' and exits RERR_SYNTAX. oc was silently accepting these via a fabricated ModeCOPY path and exiting 0. Remove the copybits/mode_copy_bits/mode_special_bits copy-from-category machinery and the dead Clause copy fields, restoring upstream's exact rejection. Surface the diagnostic byte-for-byte. Legitimate forms (empty permission half, D/F selectors, X, set-id/sticky, octal) are preserved.
287df80 to
4993879
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.
Summary
rsync's--chmodgrammar does not implement chmod(1)'s copy-from-categoryform. A category letter (
u/g/o) in the permission half of a clause (e.g.g=u,o=g,u+g) is rejected by upstream. oc-rsync was silently accepting it.Empirical divergence (upstream rsync 3.4.4 binary)
rsync -a --chmod=g=u src/ dst/:rsync: Invalid argument passed to --chmod (g=u)then
rsync error: syntax or usage error (code 1)and exits 1.copy-from-category transform.
Root cause
Upstream
chmod.c:parse_chmod()STATE_2ND_HALF(chmod.c:159-185) only acceptsr/w/X/x/s/t; every other byte — includingu/g/o— hitsdefault:andsets
STATE_ERROR, soparse_chmod()returnsNULL. The caller inoptions.c:1762-1766then emitsInvalid argument passed to --chmod (%s)andexit_cleanup(RERR_SYNTAX). Upstream'sstruct chmod_mode_structhas onlyModeAND,ModeOR,flags— there are noModeCOPY_*fields.A prior change added a
copybits/ModeCOPY_*copy-from-category path to theparser and evaluator with fabricated upstream citations. That path over-accepted
specs upstream rejects. This PR removes it and restores upstream's exact
rejection condition.
Changes
crates/metadata/src/chmod/parse.rs:STATE_2ND_HALFnow matches onlyr/w/X/x/s/t;u/g/ofall through to the error path exactly as upstream.Removed the
copybitsaccumulator and themode_special_bits()helper.crates/metadata/src/chmod/spec.rs: dropped the deadcopy_src,copy_dst,copy_and,is_subfields fromClause.crates/metadata/src/chmod/apply.rs: removed the deadmode_copy_bits()helper and the copy distribution in
tweak_mode().crates/cli/.../metadata/compute.rs: the surfaced diagnostic now matchesupstream byte-for-byte:
Invalid argument passed to --chmod (<spec>).Rejected vs still accepted
g=u,o=g,u+g,a=u,g-o,o=u,g=ur,g=us— any category letter in the permission half.750,4755),D/Fselectors (Dg-w,F+x), symbolic perms (u=rwX,a+rX),set-id/sticky (
u+s,g+s,+t), and an empty permission half (g=,o=,Dg=) which clears the class.Reconciliation with the earlier copy-spec change
The earlier work conflated two sub-cases. The empty permission half (
Dg=,o=) is a genuine upstream clause (the operator was seen, so it is not an emptyclause) and is preserved. The copy-from-category form (
g=u) is not a realrsync grammar and is now rejected, matching upstream. The
Xselector,D/Fprefixes, and set-id/sticky handling are untouched.
Dead code removed
Clause::{copy_src, copy_dst, copy_and, is_sub},parse.rs:mode_special_bits(),apply.rs:mode_copy_bits(), and the copy branch intweak_mode().Tests
metadataunit tests updated to assert rejection:parse::tests::copy_from_category_forms_rejected,chmod::tests::who_letter_copy_forms_are_rejected,chmod::comprehensive_tests::...::who_letter_copy_source_in_rhs_rejected.Legitimate forms (
o=,Dg=,u=rwX, set-id) retain passing assertions.run_reports_invalid_chmod_specificationnow assertsexit 1 and the exact
Invalid argument passed to --chmod (<spec>)string fora+q,g=u,o=g,u+g.cargo fmt --allclean,cargo clippy -p metadata -p cli --all-targets --all-features --no-deps -- -D warningsclean,cargo test -p metadata --lib chmod37 passed.