# Pre11 Batch C: ACL Parsing Responsibilities ## Scope This batch mechanically separates POSIX ACL wire-format parsing from the FreeBSD vnode and xattr acquisition path. Modified files: - `src/xattr.c` - `docs/pre11-batch-c.md` No xattr body loading, header-only xattr behavior, namespace handling, public VOP interface, build configuration, or test infrastructure was changed. ## Responsibility Split `erofs_get_acl()` continues to own: - mount option and ACL type validation; - the default-ACL directory restriction; - no-ACL filter handling and mode fallback; - xattr namespace and name selection; - both `erofs_getxattr()` stages; - FreeBSD `uio` and `iovec` setup; - `ENOATTR` fallback and the stack input buffer. The new `erofs_posix_acl_from_xattr()` receives an already-read buffer and owns only wire-format validation and ACL population. It borrows both the input buffer and output ACL and performs no allocation, release, lookup, or vnode operation. `erofs_acl_from_mode()` now receives the inode mode directly. This preserves the original fallback writes while preventing the parser from depending on an `erofs_node`. ## Moved-Code Mapping The parsing block formerly at the end of `erofs_get_acl()` was moved in the same statement order into `erofs_posix_acl_from_xattr()`: 1. Header length and entry-size remainder validation. 2. Header copy and version validation. 3. Entry count calculation and maximum check. 4. Zero-entry mode fallback. 5. `acl_cnt` assignment and phase initialization. 6. Permission validation before tag-phase validation. 7. Tag phase transitions and `UINT32_MAX` rules. 8. Duplicate named user and group ID checks. 9. ACL entry writes and undefined-ID mapping. 10. The short-circuit `phase != 6 || acl_posix1e_check(aclp) != 0` check. No ACL zeroing or additional field initialization was added. Partial ACL mutation on malformed input remains possible exactly as before. ## Branch Matrix | Input or state | Preserved result | | --- | --- | | POSIX ACL mount option disabled | `EOPNOTSUPP` in caller | | Unsupported ACL type | `EINVAL` in caller | | Default ACL requested for non-directory | `EINVAL` in caller | | No-ACL filter match | Mode-derived ACL in caller | | ACL xattr absent | Mode-derived ACL in caller | | Xattr lookup/read failure | Original error from caller | | Oversized xattr or nonzero UIO residual | `EINTEGRITY` in caller | | Short or misaligned wire value | `EINTEGRITY` in parser | | Unsupported wire version | `EINTEGRITY` in parser | | Entry count above limit | `EINTEGRITY` in parser | | Zero entries | Mode-derived ACL in parser | | Invalid permission, phase, tag, or ID | `EINTEGRITY` in parser | | Duplicate named user/group ID | `EINTEGRITY` in parser | | Missing required mask or incomplete phase | `EINTEGRITY` in parser | | Valid ACL | Identical ACL entry population and success | ## Resource And Error Audit - The input buffer remains stack-owned by `erofs_get_acl()`. - The parser does not allocate, free, or retain pointers. - There are no new cleanup paths. - Xattr errors, UIO residual errors, wire errors, and ACL validation errors retain their previous ordering. - `erofs_xattr_load_body()` and its release paths were not modified. - The optional header validation helper was intentionally omitted to avoid touching the known header-only behavior. ## Static Verification The batch is validated with: - a strict two-file path whitelist; - unique definitions of `erofs_get_acl()`, `erofs_acl_from_mode()`, and `erofs_posix_acl_from_xattr()`; - pre/post comparison of parser returns, phase transitions, ACL writes, and duplicate-ID checks; - `git diff --check`; - confirmation that `erofs_xattr_load_body()` is absent from the source diff. No build, QEMU smoke test, or feature test was run for this mechanical split.