Skip to content

Cli/stdio/mac metadata#2575

Merged
ChanTsune merged 1 commit into
mainfrom
cli/stdio/mac-metadata
Jan 6, 2026
Merged

Cli/stdio/mac metadata#2575
ChanTsune merged 1 commit into
mainfrom
cli/stdio/mac-metadata

Conversation

@ChanTsune
Copy link
Copy Markdown
Owner

@ChanTsune ChanTsune commented Jan 5, 2026

Summary by CodeRabbit

  • New Features

    • Added CLI flags to control inclusion of macOS AppleDouble metadata and an entry-level mac-metadata accessor; macOS pack/unpack support added.
  • Behavior Changes

    • Preservation is disabled by default; enabling on non-macOS logs a warning; on macOS the flow avoids duplicating metadata.
  • Tests

    • Added stdio CLI tests for flag validation, mutual exclusion, unstable gating, and macOS preservation/extraction.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 5, 2026

📝 Walkthrough

Walkthrough

Adds macOS AppleDouble support: new maMd chunk constant and module, MacMetadataStrategy with CLI flags and option plumbing, macOS-only copyfile pack/unpack helpers, propagation through create/extract/append/update flows, NormalEntry accessor, tests, and a Cargo dependency relocation.

Changes

Cohort / File(s) Summary
Chunk module & export
cli/src/chunk.rs, cli/src/chunk/mac_metadata.rs
New mac_metadata module; re-export its items; defines public maMd: ChunkType constant (pub const maMd: ChunkType = unsafe { ChunkType::from_unchecked(*b"maMd") }).
Core strategy & metadata plumbing
cli/src/command/core.rs
Add MacMetadataStrategy enum (Never, Always) with platform-aware from_flags; add mac_metadata_strategy to KeepOptions; integrate AppleDouble pack/unpack on macOS and warnings on non-macOS; adjust xattr/ACL handling when AppleDouble is used.
CLI integrations
cli/src/command/stdio.rs, cli/src/command/create.rs, cli/src/command/append.rs, cli/src/command/update.rs
New CLI flags --mac-metadata / --no-mac-metadata and ArgGroup; StdioCommand fields; construct MacMetadataStrategy::from_flags(...) and thread into KeepOptions across create/extract/append/update flows.
Extraction & restore flow
cli/src/command/extract.rs
Propagate mac_metadata_strategy into extract/restore; on macOS unpack maMd via copyfile and skip duplicate xattr/ACL handling; non-macOS emits warnings if Always requested.
Entry API extension
cli/src/ext.rs
Add NormalEntryExt::mac_metadata(&self) -> Option<&[u8]> that scans extra_chunks for the maMd chunk and returns its data.
macOS-specific FS helpers
cli/src/utils/os/unix/fs.rs
Add macOS-only copyfile module (cfg(target_os = "macos")) with pack_apple_double(source_path) -> io::Result<Vec<u8>> and unpack_apple_double(apple_double_data, target_path) -> io::Result<()> using libc copyfile, temp-file handling, and cleanup; add TEMP_COUNTER.
Tests
cli/tests/cli/stdio.rs, cli/tests/cli/stdio/option_mac_metadata.rs
Register new stdio test module; add tests covering --mac-metadata/--no-mac-metadata behavior, --unstable gating, mutual exclusion, and macOS-specific xattr preservation (cfg gated).
Manifest
cli/Cargo.toml
Move scopeguard = "1.2.0" from windows-targeted dependency block to top-level [dependencies].

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant User
    participant CLI as "pna CLI"
    participant Core as "command::core"
    participant FS as "copyfile (macOS)"
    participant Archive

    User->>CLI: pna --mac-metadata --unstable create ...
    CLI->>CLI: parse flags → MacMetadataStrategy::Always
    CLI->>Core: CreateOptions { mac_metadata_strategy: Always, ... }
    Core->>Core: collect metadata for entry
    Core->>FS: pack_apple_double(source_path)
    activate FS
    FS->>FS: copyfile(PACK) → write temp file → read bytes
    FS-->>Core: appleDouble bytes
    deactivate FS
    Core->>Archive: append entry + attach `maMd` chunk with metadata bytes
    Core-->>User: archive written
Loading
sequenceDiagram
    autonumber
    participant User
    participant CLI as "pna CLI"
    participant Core as "command::core"
    participant FS as "copyfile (macOS)"
    participant Disk

    User->>CLI: pna --mac-metadata --unstable extract archive
    CLI->>CLI: parse flags → MacMetadataStrategy::Always
    CLI->>Core: OutputOptions { mac_metadata_strategy: Always, ... }
    Core->>Core: extract_entry -> locate `maMd` chunk
    Core->>FS: unpack_apple_double(metadata_bytes, target_path)
    activate FS
    FS->>FS: write temp -> copyfile(UNPACK) -> restore xattr/acl
    FS-->>Core: success / error
    deactivate FS
    Core-->>User: extraction complete (with restored mac metadata)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested labels

break

Poem

🐇 I hopped through bytes and temp-file trails,
I tucked mac chunks in archival bales,
copyfile hummed and metadata stayed,
carrots of code in a tidy cascade,
A tiny rabbit cheers this trade! 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title check ❓ Inconclusive The title is vague and uses non-descriptive path-like phrasing that doesn't convey what the changeset actually implements—adding macOS metadata support with CLI flags and copyfile integration. Consider a more descriptive title such as 'Add macOS metadata (AppleDouble) support with --mac-metadata CLI flag' to clearly indicate the main feature being added.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @ChanTsune, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces robust support for handling macOS-specific metadata, such as extended attributes, ACLs, and resource forks, within archives. It achieves this by implementing a new MacMetadataStrategy that utilizes the AppleDouble format and integrates with the macOS copyfile() API for efficient packing and unpacking. Users can now control the preservation of this metadata via new --mac-metadata and --no-mac-metadata CLI options in the stdio command, ensuring that macOS file fidelity can be maintained when archiving and extracting.

Highlights

  • macOS Metadata Support: Introduced MacMetadataStrategy to control archiving and extraction of macOS-specific metadata (extended attributes, ACLs, resource forks) using the AppleDouble format.
  • New Chunk Type: Added a private maMd chunk type to store AppleDouble data within archives.
  • copyfile() API Integration: Leveraged the macOS copyfile() C API for efficient packing and unpacking of AppleDouble metadata.
  • CLI Options: Added --mac-metadata and --no-mac-metadata (unstable) options to the stdio command for explicit control over macOS metadata handling.
  • Strategy Resolution Logic: Updated XattrStrategy and AclStrategy resolution to consider the new mac_metadata flags, ensuring proper precedence.
  • Core Logic Updates: Modified create_entry, apply_metadata, extract_entry, and restore_metadata functions to incorporate the new MacMetadataStrategy.
  • New Tests: Added comprehensive CLI tests for the new --mac-metadata options, including macOS-specific tests verifying xattr preservation.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces support for archiving and extracting macOS-specific metadata (like extended attributes, ACLs, and resource forks) using the AppleDouble format. This is achieved by leveraging the copyfile() system call on macOS and introducing a new private chunk type maMd. The feature is exposed through new --mac-metadata and --no-mac-metadata flags under the experimental stdio command.

The implementation is comprehensive, including FFI bindings, logic for packing/unpacking metadata, and integration tests. However, I've identified two critical issues where this new functionality leads to redundant storage and restoration of extended attributes and ACLs, as they are handled by both the new AppleDouble mechanism and the existing specific handlers. I've also included a couple of medium-severity suggestions to improve code style and maintainability in the flag resolution logic.

Comment thread cli/src/command/core.rs
Comment thread cli/src/command/extract.rs
Comment thread cli/src/command/stdio.rs Outdated
Comment thread cli/src/command/stdio.rs Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
cli/tests/cli/stdio/option_mac_metadata.rs (2)

268-276: Consider adding error message context on assertion failure.

The assertions at lines 274 and 276 could benefit from descriptive messages to aid debugging if they fail.

🔎 Suggested improvement
-        assert!(output.status.success());
-        let extracted_value = String::from_utf8_lossy(&output.stdout);
-        assert!(extracted_value.trim() == xattr_value);
+        assert!(
+            output.status.success(),
+            "xattr command failed: {}",
+            String::from_utf8_lossy(&output.stderr)
+        );
+        let extracted_value = String::from_utf8_lossy(&output.stdout);
+        assert_eq!(
+            extracted_value.trim(),
+            xattr_value,
+            "xattr value mismatch"
+        );

11-26: Tests lack cleanup of created files.

The tests create files in the current working directory but don't clean them up afterward. Consider using tempfile or adding cleanup in a Drop guard to avoid polluting the test environment.

cli/src/utils/os/unix/fs.rs (1)

125-157: Consider more robust temp file handling.

The current implementation uses a manually constructed temp file path. While functional, this approach has minor edge cases:

  1. The temp directory might not be writable
  2. If the process crashes mid-operation, orphan temp files remain

The current approach is acceptable for this use case, but you might consider using tempfile crate for more robust handling in the future.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6ca40bc and fae5af4.

📒 Files selected for processing (12)
  • cli/src/chunk.rs
  • cli/src/chunk/mac_metadata.rs
  • cli/src/command/append.rs
  • cli/src/command/core.rs
  • cli/src/command/create.rs
  • cli/src/command/extract.rs
  • cli/src/command/stdio.rs
  • cli/src/command/update.rs
  • cli/src/ext.rs
  • cli/src/utils/os/unix/fs.rs
  • cli/tests/cli/stdio.rs
  • cli/tests/cli/stdio/option_mac_metadata.rs
🧰 Additional context used
🧬 Code graph analysis (5)
cli/src/chunk.rs (1)
cli/src/ext.rs (2)
  • mac_metadata (18-18)
  • mac_metadata (65-70)
cli/src/command/append.rs (1)
cli/src/command/core.rs (2)
  • create_entry (636-711)
  • entry_option (713-733)
cli/src/chunk/mac_metadata.rs (1)
lib/src/chunk/types.rs (1)
  • from_unchecked (225-227)
cli/src/command/extract.rs (2)
cli/src/command/core.rs (1)
  • collect_split_archives (581-598)
cli/src/utils/os/unix/fs.rs (2)
  • copyfile (114-120)
  • unpack_apple_double (160-195)
cli/src/command/create.rs (1)
cli/src/command/core.rs (2)
  • create_entry (636-711)
  • entry_option (713-733)
🔇 Additional comments (17)
cli/tests/cli/stdio.rs (1)

6-6: LGTM!

The new test module import aligns with the existing test organization and supports testing of the mac metadata CLI options.

cli/src/chunk.rs (1)

3-3: LGTM!

The module declaration and re-export follow the existing pattern used for acl and fflag modules, properly exposing the macOS metadata chunk type through the public API.

Also applies to: 7-7

cli/src/command/append.rs (2)

10-10: LGTM!

The import of MacMetadataStrategy is correctly added to support the new mac metadata handling infrastructure.


423-423: LGTM!

Initializing mac_metadata_strategy to Never is appropriate for the append command, maintaining consistency with the existing architecture where append operations typically preserve the original archive structure without adding new metadata types by default.

cli/src/command/update.rs (2)

14-14: LGTM!

The import of MacMetadataStrategy correctly integrates the new mac metadata handling into the update command.


432-432: LGTM!

Initializing mac_metadata_strategy to Never is appropriate for the update command, consistent with the append command's behavior and maintaining backward compatibility.

cli/src/chunk/mac_metadata.rs (1)

1-10: LGTM!

The chunk type definition is well-structured:

  • The documentation clearly explains the AppleDouble format purpose and PNA naming convention semantics.
  • The unsafe usage in from_unchecked is justified because the hardcoded byte string b"maMd" is a compile-time constant that adheres to the documented naming convention by construction.
  • The chunk type naming follows the PNA convention correctly: ancillary, private, reserved, safe-to-copy.
cli/src/ext.rs (1)

63-70: LGTM!

The mac_metadata() implementation follows the established pattern used by fflags() and correctly scans extra_chunks for the maMd chunk type. The use of find() with map() is idiomatic and efficient.

cli/src/command/create.rs (1)

554-560: LGTM!

Hardcoding MacMetadataStrategy::Never is appropriate here since the regular create command doesn't expose --mac-metadata flags. The experimental mac metadata feature is only available through the stdio command path.

cli/src/command/extract.rs (2)

945-971: LGTM!

The macOS metadata restoration logic is well-implemented:

  • Uses unpack_apple_double on macOS with appropriate logging
  • Gracefully degrades with a warning on non-macOS platforms when metadata is present
  • Failures are logged as warnings rather than hard errors, allowing extraction to continue

This matches the pattern used for other metadata types (xattrs, ACLs).


449-449: Consistent with create.rs - mac_metadata_strategy hardcoded to Never.

The regular extract command doesn't expose --mac-metadata flags, so hardcoding Never is appropriate. Only the stdio command provides access to this experimental feature.

cli/src/command/stdio.rs (2)

1073-1107: Clear precedence logic for xattr/ACL resolution.

The resolution functions correctly implement a clear precedence:

  1. Explicit --keep-xattr/--no-keep-xattr flags take precedence
  2. On macOS, --mac-metadata/--no-mac-metadata act as defaults
  3. Platform-aware: non-macOS ignores mac_metadata flags

This allows users fine-grained control while --mac-metadata provides a convenient shorthand on macOS.


207-218: LGTM - flags properly gated behind --unstable.

Both --mac-metadata and --no-mac-metadata correctly require --unstable, and the ArgGroup at line 65 ensures mutual exclusivity. The help text clearly describes the feature.

cli/src/command/core.rs (3)

182-212: Well-designed platform-aware enum.

The MacMetadataStrategy enum is well-designed:

  • Uses #[derive(Default)] with Never as the default variant
  • Platform-aware from_flags: on non-macOS, always returns Never regardless of flags, preventing users from enabling a feature that won't work
  • Clear documentation explaining the AppleDouble format purpose

875-908: Robust error handling for mac metadata packing.

The implementation handles errors gracefully:

  • Empty AppleDouble data is skipped (no metadata to pack)
  • NotFound errors are silently ignored (file simply has no mac metadata)
  • Other errors log a warning but don't fail the archive operation
  • Debug logging with byte count aids troubleshooting

This mirrors the pattern used for other metadata types and ensures archive creation succeeds even when some metadata can't be captured.


654-708: mac_metadata_strategy correctly propagated through all entry types.

The strategy is passed to apply_metadata for all StoreAs variants (Hardlink, Symlink, File, Dir), ensuring consistent metadata handling across entry types.

cli/src/utils/os/unix/fs.rs (1)

114-121: Copyfile signature matches macOS SDK.

The declaration is correct: flags: u32 properly maps to copyfile_flags_t (typedef'd as uint32_t in the SDK). All parameters match the official macOS copyfile signature: from and to are *const libc::c_char (const char*), and the return type is libc::c_int (int).

@github-actions github-actions Bot added the cli This issue is about cli application label Jan 5, 2026
Comment thread cli/src/command/core.rs Dismissed
Comment thread cli/src/command/core.rs Dismissed
Comment thread cli/src/command/core.rs Dismissed
Comment thread cli/src/command/core.rs Dismissed
Comment thread cli/src/command/extract.rs Fixed
Comment thread cli/src/command/extract.rs Fixed
@ChanTsune ChanTsune force-pushed the cli/stdio/mac-metadata branch from fae5af4 to 21ac20a Compare January 5, 2026 08:56
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Fix all issues with AI Agents 🤖
In @cli/src/utils/os/unix/fs.rs:
- Around line 174-175: The temp file can be left on disk if CString::new for
c_target fails after c_temp succeeded; ensure the temp file is always removed on
all early-return paths by either constructing both CStrings (CString::new for
temp_file and target_path) before creating/writing the temp_file, or wrap the
temp file lifecycle in a scope guard/cleanup that calls
std::fs::remove_file(temp_file) on error; adjust the code around temp_file,
CString::new, c_temp and c_target to guarantee removal of the temp_file when any
subsequent step (including creating c_target) returns Err.
- Around line 159-195: The temp file created in unpack_apple_double is not
removed if writing fails; ensure temp_file is cleaned up on any early return by
creating the temp file, writing, and the subsequent copy in a closure or block
that returns io::Result and then always calling fs::remove_file(&temp_file) in a
finally-like place (e.g., use a match/if let on the closure's result or a
scopeguard/Drop helper) so that failures from file.write_all or any other error
still trigger removal of temp_file; refer to unpack_apple_double, temp_file,
file.write_all, and the existing fs::remove_file call to implement this
guaranteed cleanup.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
cli/src/command/stdio.rs (1)

681-691: Critical: Mac metadata strategy not propagated in create flow.

The run_create_archive function constructs CreationContext but does not include mac_metadata_strategy. When create_archive_file is called (line 693 or 699), it hardcodes mac_metadata_strategy: MacMetadataStrategy::Never (see cli/src/command/create.rs line 559). This means the --mac-metadata and --no-mac-metadata flags parsed at lines 207-218 are ignored during archive creation via the stdio interface.

In contrast, the extract (line 784-787), append (line 947-950), and update (line 1086-1089) paths correctly propagate the strategy using MacMetadataStrategy::from_flags(args.mac_metadata, args.no_mac_metadata).

Fix: Either add mac_metadata_strategy to the CreationContext struct and pass it through, or construct CreateOptions directly in run_create_archive with the resolved strategy before calling create_archive_file.

♻️ Duplicate comments (3)
cli/src/command/core.rs (1)

875-908: Critical: Duplicate metadata when using MacMetadataStrategy::Always on macOS.

The past review comment is still valid. When mac_metadata_strategy is Always on macOS, pack_apple_double includes extended attributes and ACLs in the maMd chunk. However, the existing xattr handling (lines 837-853) and ACL handling (lines 805-835) also run independently, resulting in duplicate data in the archive.

To fix this, skip the separate xattr and ACL handling on macOS when mac_metadata_strategy is Always:

🔎 Proposed fix

For xattrs (around line 837):

 #[cfg(unix)]
 if let XattrStrategy::Always = keep_options.xattr_strategy {
+    #[cfg(target_os = "macos")]
+    if mac_metadata_strategy == MacMetadataStrategy::Always {
+        // Skip: xattrs are already packed in maMd chunk
+    } else {
+        match utils::os::unix::fs::xattrs::get_xattrs(path) {
+            // ... existing xattr logic ...
+        }
+    }
+    #[cfg(not(target_os = "macos"))]
     match utils::os::unix::fs::xattrs::get_xattrs(path) {
-        Ok(xattrs) => {
-            for attr in xattrs {
-                entry.add_xattr(attr);
-            }
-        }
-        Err(e) if e.kind() == std::io::ErrorKind::Unsupported => {
-            log::warn!(
-                "Extended attributes are not supported on filesystem for '{}': {}",
-                path.display(),
-                e
-            );
-        }
-        Err(e) => return Err(e),
+        // ... existing xattr logic ...
     }
 }

Similar changes needed for ACLs (around line 813).

cli/src/command/extract.rs (2)

906-918: Address potential conflict with macOS AppleDouble restoration.

When mac_metadata_strategy is Always on macOS (lines 945-971), unpack_apple_double uses copyfile() with COPYFILE_XATTR and COPYFILE_ACL flags, which restores extended attributes and ACLs from the AppleDouble format. However, this block (lines 906-918) unconditionally applies xattrs when XattrStrategy::Always, and line 924 unconditionally restores ACLs when enabled.

This can lead to:

  1. Redundant operations (AppleDouble already restored them)
  2. Conflicts if the individually-stored xattrs/ACLs differ from those in the AppleDouble blob
  3. Potential overwrites where the later restoration replaces the earlier one

Recommendation: Skip individual xattr restoration on macOS when mac_metadata_strategy is Always:

Proposed fix
 #[cfg(unix)]
 if let XattrStrategy::Always = keep_options.xattr_strategy {
+    #[cfg(target_os = "macos")]
+    let should_skip = matches!(mac_metadata_strategy, MacMetadataStrategy::Always);
+    #[cfg(not(target_os = "macos"))]
+    let should_skip = false;
+    
+    if !should_skip {
         match utils::os::unix::fs::xattrs::set_xattrs(path, item.xattrs()) {
             Ok(()) => {}
             Err(e) if e.kind() == io::ErrorKind::Unsupported => {
                 log::warn!(
                     "Extended attributes are not supported on filesystem for '{}': {}",
                     path.display(),
                     e
                 );
             }
             Err(e) => return Err(e),
         }
+    }
 }

Apply similar logic for ACL restoration at line 924.

Based on past review comments from gemini-code-assist[bot].


964-971: Optional: Simplify nested cfg blocks.

The nested #[cfg(not(target_os = "macos"))] and conditional check could potentially be collapsed for readability, though the current structure is clear.

Alternative structure
-#[cfg(not(target_os = "macos"))]
-if let MacMetadataStrategy::Always = mac_metadata_strategy {
-    if item.mac_metadata().is_some() {
-        log::warn!(
-            "macOS metadata present but cannot be restored on this platform: '{}'",
-            path.display()
-        );
-    }
-}
+#[cfg(not(target_os = "macos"))]
+if matches!(mac_metadata_strategy, MacMetadataStrategy::Always) && item.mac_metadata().is_some() {
+    log::warn!(
+        "macOS metadata present but cannot be restored on this platform: '{}'",
+        path.display()
+    );
+}

Related to static analysis hints from github-advanced-security[bot].

🧹 Nitpick comments (1)
cli/src/utils/os/unix/fs.rs (1)

125-157: Consider handling potential temp file collisions.

While the combination of process ID and atomic counter makes collisions unlikely, there's no explicit check or retry mechanism if the temp file already exists. If this function is called concurrently across multiple processes with the same PID (e.g., after a PID wrap), collisions could occur.

Consider either:

  1. Using O_EXCL semantics via OpenOptions::new().create_new(true) to fail fast on collision
  2. Adding a retry loop with a different counter value

That said, this is a minor edge case and the current implementation is acceptable for typical usage.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fae5af4 and 21ac20a.

📒 Files selected for processing (12)
  • cli/src/chunk.rs
  • cli/src/chunk/mac_metadata.rs
  • cli/src/command/append.rs
  • cli/src/command/core.rs
  • cli/src/command/create.rs
  • cli/src/command/extract.rs
  • cli/src/command/stdio.rs
  • cli/src/command/update.rs
  • cli/src/ext.rs
  • cli/src/utils/os/unix/fs.rs
  • cli/tests/cli/stdio.rs
  • cli/tests/cli/stdio/option_mac_metadata.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • cli/tests/cli/stdio/option_mac_metadata.rs
  • cli/src/command/append.rs
🧰 Additional context used
🧬 Code graph analysis (6)
cli/src/chunk.rs (1)
cli/src/ext.rs (2)
  • mac_metadata (18-18)
  • mac_metadata (65-70)
cli/src/command/create.rs (1)
cli/src/command/core.rs (1)
  • create_entry (636-711)
cli/src/command/core.rs (2)
cli/src/ext.rs (2)
  • mac_metadata (18-18)
  • mac_metadata (65-70)
cli/src/utils/os/unix/fs.rs (2)
  • copyfile (114-120)
  • pack_apple_double (125-157)
cli/src/command/stdio.rs (1)
cli/src/command/core.rs (6)
  • from_flags (117-125)
  • from_flags (135-143)
  • from_flags (153-161)
  • from_flags (171-179)
  • from_flags (198-206)
  • from_flags (209-211)
cli/src/command/extract.rs (1)
cli/src/utils/os/unix/fs.rs (2)
  • copyfile (114-120)
  • unpack_apple_double (160-195)
cli/src/chunk/mac_metadata.rs (1)
lib/src/chunk/types.rs (1)
  • from_unchecked (225-227)
🔇 Additional comments (13)
cli/src/chunk/mac_metadata.rs (1)

1-10: LGTM! Chunk type definition follows PNA conventions.

The unsafe usage with from_unchecked is appropriate here since the byte pattern *b"maMd" is statically defined and follows the documented PNA chunk naming convention. The documentation clearly explains the semantic meaning of each character's case, which aligns with the ancillary, private chunk specification.

cli/src/utils/os/unix/fs.rs (1)

89-121: LGTM! FFI setup is correct.

The copyfile FFI declaration and flag constants match the macOS copyfile API. Using AtomicU64 with Relaxed ordering for the counter is appropriate since we only need uniqueness, not ordering guarantees.

cli/src/command/core.rs (3)

312-312: LGTM! Field addition is correct.

The mac_metadata_strategy field is properly added to CreateOptions and will be propagated through entry creation.


636-710: LGTM! Consistent propagation of mac_metadata_strategy.

All StoreAs variants (Hardlink, Symlink, File, Dir) correctly pass mac_metadata_strategy to apply_metadata. The implementation is consistent across all paths.


182-212: CLI flags are properly wired and the Always variant is reachable.

The search results confirm that MacMetadataStrategy::from_flags() is called in cli/src/command/stdio.rs (lines 784, 947, 1086) to properly instantiate the strategy based on CLI arguments. The test suite in cli/tests/cli/stdio/option_mac_metadata.rs includes comprehensive test coverage exercising both --mac-metadata and --no-mac-metadata flags across create, extract, append, and update modes.

The Always variant is actively used in the codebase at cli/src/command/core.rs:877 and cli/src/command/extract.rs:947 (within #[cfg(target_os = "macos")] gates). Static analysis tools may report the variant as unreachable due to not fully understanding platform-specific conditional compilation or test execution paths. On macOS, the tests stdio_mac_metadata_preserves_xattrs() and stdio_no_mac_metadata_excludes_xattrs() exercise the actual metadata handling.

Note: Other command modules (create.rs, append.rs, update.rs, extract.rs) currently hardcode MacMetadataStrategy::Never, which means the flag functionality is only available via the stdio command. This is the current design, not an oversight in the reviewed code.

cli/tests/cli/stdio.rs (1)

6-6: LGTM! Test module declaration added.

The new test module for mac_metadata options is properly declared alongside existing test modules.

cli/src/chunk.rs (1)

3-7: LGTM! Module wiring follows established pattern.

The mac_metadata module is properly declared and re-exported, following the same pattern as the existing acl and fflag modules.

cli/src/ext.rs (1)

64-70: LGTM!

The implementation follows the same pattern as acl() and fflags() methods, correctly scanning extra chunks for the maMd chunk type and returning its data.

cli/src/command/create.rs (1)

559-559: Hardcoded to Never in create command.

The create command hardcodes mac_metadata_strategy to Never, while the stdio interface supports --mac-metadata flags. This appears intentional for this PR, limiting Mac metadata support to the stdio (tar-style) interface initially.

cli/src/command/update.rs (1)

432-432: Consistent with create command pattern.

Like the create command, the standalone update command hardcodes mac_metadata_strategy to Never, while stdio interface support is provided separately.

cli/src/command/extract.rs (2)

449-449: Consistent with standalone command pattern.

The standalone extract command hardcodes mac_metadata_strategy to Never, matching the pattern used in create and update commands. Mac metadata support is provided through the stdio interface, which correctly uses MacMetadataStrategy::from_flags() (see cli/src/command/stdio.rs lines 784-787).


886-888: Updated documentation reflects new functionality.

The docstring accurately describes the metadata restoration behavior including the new macOS AppleDouble support.

cli/src/command/stdio.rs (1)

207-218: Flags work consistently across platforms as designed.

The MacMetadataStrategy::from_flags implementation correctly handles platform differences: on macOS, it processes the flags and can return Always or Never; on non-macOS platforms, it ignores the flag values and always returns Never (lines 197-211 in cli/src/command/core.rs). Both flags properly require the unstable feature across all platforms, and the runtime handling in apply_metadata (lines ~265-271 in cli/src/command/core.rs) logs a warning if someone attempts to use --mac-metadata on non-macOS systems. The behavior is intentional and appropriate.

Comment thread cli/src/utils/os/unix/fs.rs
Comment thread cli/src/utils/os/unix/fs.rs Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
cli/tests/cli/stdio/option_mac_metadata.rs (1)

273-275: Consider using assert_eq! for clearer test failure messages.

The current assertion works correctly, but assert_eq! would provide more informative output if the test fails by showing both the expected and actual values.

🔎 Proposed refactor
-        assert!(output.status.success());
-        let extracted_value = String::from_utf8_lossy(&output.stdout);
-        assert!(extracted_value.trim() == "test_value");
+        assert!(output.status.success());
+        let extracted_value = String::from_utf8_lossy(&output.stdout);
+        assert_eq!(extracted_value.trim(), "test_value");
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 21ac20a and 9de410e.

📒 Files selected for processing (1)
  • cli/tests/cli/stdio/option_mac_metadata.rs
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (16)
  • GitHub Check: Run cargo fuzz (split_archive)
  • GitHub Check: Run cargo fuzz (aes_cbc)
  • GitHub Check: tier1 (windows-latest, beta)
  • GitHub Check: tier1 (macos-latest, stable)
  • GitHub Check: Analyze (rust)
  • GitHub Check: Run rust-clippy analyzing
  • GitHub Check: tier1 (windows-latest, beta)
  • GitHub Check: Test WebAssembly (nightly-2025-12-09, wasm32-unknown-emscripten)
  • GitHub Check: Test WebAssembly (beta, wasm32-unknown-unknown)
  • GitHub Check: Test WebAssembly (nightly-2025-12-09, wasm32-wasip2)
  • GitHub Check: Test WebAssembly (stable, wasm32-wasip2)
  • GitHub Check: Test WebAssembly (stable, wasm32-wasip1)
  • GitHub Check: Test WebAssembly (stable, wasm32-unknown-unknown)
  • GitHub Check: Test WebAssembly (beta, wasm32-unknown-emscripten)
  • GitHub Check: Test WebAssembly (stable, wasm32-unknown-emscripten)
  • GitHub Check: tier3_cross (redoxos/redoxer, x86_64-unknown-redox)
🔇 Additional comments (2)
cli/tests/cli/stdio/option_mac_metadata.rs (2)

12-202: LGTM!

The test coverage for CLI flag acceptance and validation is thorough and well-structured. The tests appropriately verify:

  • Flag acceptance for create, extract, append, and update modes
  • The requirement that --mac-metadata needs --unstable
  • Mutual exclusivity of --mac-metadata and --no-mac-metadata

The test isolation is good with unique file/directory names for each test case.


282-343: LGTM!

This test correctly verifies that --no-mac-metadata excludes extended attributes from the archive. The approach of creating without metadata but attempting to extract with --mac-metadata is a good way to confirm nothing was stored.

@ChanTsune ChanTsune force-pushed the cli/stdio/mac-metadata branch from 9de410e to d5b1ee9 Compare January 5, 2026 13:26
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (2)
cli/src/command/extract.rs (1)

945-971: Consider skipping individual xattr/ACL restoration when AppleDouble is used.

When MacMetadataStrategy::Always is active on macOS, the unpack_apple_double call restores xattrs and ACLs via copyfile(). However, the individual xattr restoration (lines 906-918) and ACL restoration (line 924) still run before this, resulting in redundant operations that get overwritten.

While not incorrect, this could be optimized by skipping the individual restorations when AppleDouble handling is enabled on macOS.

cli/src/command/core.rs (1)

875-908: Critical: Data duplication when Mac metadata is enabled.

When mac_metadata_strategy is Always on macOS, this logic packs extended attributes and ACLs into the maMd chunk via copyfile() with COPYFILE_XATTR | COPYFILE_ACL flags. However, if --mac-metadata also enables --keep-xattr and --keep-acl by default (as mentioned in past comments), the existing xattr logic (lines 837-853) and ACL logic (lines 805-835) will also execute, resulting in duplicate storage of xattrs and ACLs—once in their specific chunks (xAtT, faCl, faCe) and again within the maMd chunk.

To prevent duplication, skip the xattr and ACL handling blocks on macOS when mac_metadata_strategy is Always.

🔎 Proposed fix to prevent duplication

For xattrs (lines 837-853):

 #[cfg(unix)]
 if let XattrStrategy::Always = keep_options.xattr_strategy {
+    #[cfg(target_os = "macos")]
+    let skip_due_to_mac_metadata = mac_metadata_strategy == MacMetadataStrategy::Always;
+    #[cfg(not(target_os = "macos"))]
+    let skip_due_to_mac_metadata = false;
+    
+    if !skip_due_to_mac_metadata {
         match utils::os::unix::fs::xattrs::get_xattrs(path) {
             Ok(xattrs) => {
                 for attr in xattrs {
                     entry.add_xattr(attr);
                 }
             }
             Err(e) if e.kind() == std::io::ErrorKind::Unsupported => {
                 log::warn!(
                     "Extended attributes are not supported on filesystem for '{}': {}",
                     path.display(),
                     e
                 );
             }
             Err(e) => return Err(e),
         }
+    }
 }

For ACLs (lines 805-835), apply a similar guard:

 #[cfg(feature = "acl")]
 {
     #[cfg(any(
         target_os = "linux",
         target_os = "freebsd",
         target_os = "macos",
         windows
     ))]
     if let AclStrategy::Always = keep_options.acl_strategy {
+        #[cfg(target_os = "macos")]
+        let skip_due_to_mac_metadata = mac_metadata_strategy == MacMetadataStrategy::Always;
+        #[cfg(not(target_os = "macos"))]
+        let skip_due_to_mac_metadata = false;
+        
+        if !skip_due_to_mac_metadata {
             use crate::chunk;
             use pna::RawChunk;
             let acl = utils::acl::get_facl(path)?;
             entry.add_extra_chunk(RawChunk::from_data(chunk::faCl, acl.platform.to_bytes()));
             for ace in acl.entries {
                 entry.add_extra_chunk(RawChunk::from_data(chunk::faCe, ace.to_bytes()));
             }
+        }
     }
     // ... rest of the block
 }
🧹 Nitpick comments (4)
cli/tests/cli/stdio/option_mac_metadata.rs (1)

273-276: Consider using assert_eq! for better failure diagnostics.

Using assert_eq! instead of assert! with equality comparison provides more informative error messages when tests fail.

🔎 Proposed fix
-        assert!(output.status.success());
-        let extracted_value = String::from_utf8_lossy(&output.stdout);
-        assert!(extracted_value.trim() == "test_value");
+        assert!(output.status.success());
+        let extracted_value = String::from_utf8_lossy(&output.stdout);
+        assert_eq!(extracted_value.trim(), "test_value");
cli/src/utils/os/unix/fs.rs (2)

129-131: Unused variable in scopeguard closure.

The closure parameter f is unused. Consider using _ to silence the warning or removing the parameter name.

🔎 Proposed fix
-        let clean = scopeguard::guard(&temp_file, |f| {
+        let clean = scopeguard::guard(&temp_file, |_| {
             let _ = fs::remove_file(&temp_file);
         });

153-155: Same unused variable issue in the second scopeguard closure.

🔎 Proposed fix
-        let clean = scopeguard::guard(&temp_file, |f| {
+        let clean = scopeguard::guard(&temp_file, |_| {
             let _ = fs::remove_file(&temp_file);
         });
cli/src/command/extract.rs (1)

964-971: Collapsible if statement.

Per static analysis, these nested if statements can be collapsed.

🔎 Proposed fix
     #[cfg(not(target_os = "macos"))]
-    if let MacMetadataStrategy::Always = mac_metadata_strategy {
-        if item.mac_metadata().is_some() {
-            log::warn!(
-                "macOS metadata present but cannot be restored on this platform: '{}'",
-                path.display()
-            );
-        }
+    if matches!(mac_metadata_strategy, MacMetadataStrategy::Always) && item.mac_metadata().is_some() {
+        log::warn!(
+            "macOS metadata present but cannot be restored on this platform: '{}'",
+            path.display()
+        );
     }
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9de410e and d5b1ee9.

📒 Files selected for processing (13)
  • cli/Cargo.toml
  • cli/src/chunk.rs
  • cli/src/chunk/mac_metadata.rs
  • cli/src/command/append.rs
  • cli/src/command/core.rs
  • cli/src/command/create.rs
  • cli/src/command/extract.rs
  • cli/src/command/stdio.rs
  • cli/src/command/update.rs
  • cli/src/ext.rs
  • cli/src/utils/os/unix/fs.rs
  • cli/tests/cli/stdio.rs
  • cli/tests/cli/stdio/option_mac_metadata.rs
🚧 Files skipped from review as they are similar to previous changes (4)
  • cli/src/chunk.rs
  • cli/src/command/create.rs
  • cli/src/command/update.rs
  • cli/tests/cli/stdio.rs
🧰 Additional context used
🧬 Code graph analysis (4)
cli/src/command/stdio.rs (1)
cli/src/command/core.rs (6)
  • from_flags (117-125)
  • from_flags (135-143)
  • from_flags (153-161)
  • from_flags (171-179)
  • from_flags (198-206)
  • from_flags (209-211)
cli/src/command/extract.rs (2)
cli/src/command/core.rs (1)
  • collect_split_archives (581-598)
cli/src/utils/os/unix/fs.rs (2)
  • copyfile (107-120)
  • unpack_apple_double (148-170)
cli/src/chunk/mac_metadata.rs (1)
lib/src/chunk/types.rs (1)
  • from_unchecked (225-227)
cli/src/command/core.rs (2)
cli/src/ext.rs (2)
  • mac_metadata (18-18)
  • mac_metadata (65-70)
cli/src/utils/os/unix/fs.rs (2)
  • copyfile (107-120)
  • pack_apple_double (124-145)
🔇 Additional comments (14)
cli/Cargo.toml (1)

43-43: Version 1.2.0 is current and secure.

The scopeguard dependency at version 1.2.0 is the latest stable version available. No security advisories or CVEs are reported for this version. The change is safe to proceed.

cli/src/ext.rs (1)

17-18: LGTM!

The new mac_metadata() trait method and implementation follow the existing patterns in the file (similar to fflags()). The use of find() with map() is appropriate for returning the first matching chunk's data.

Also applies to: 64-70

cli/src/chunk/mac_metadata.rs (1)

1-10: LGTM!

The chunk type definition is well-documented with clear explanation of the PNA naming convention. Using from_unchecked with a compile-time constant byte array is safe since the validity of the chunk type is verified at compile time.

cli/src/command/append.rs (1)

10-12: LGTM!

The append command correctly hardcodes MacMetadataStrategy::Never since it doesn't expose the --mac-metadata CLI flags. This is consistent with the design where only the stdio path exposes this unstable feature.

Also applies to: 423-423

cli/tests/cli/stdio/option_mac_metadata.rs (1)

1-7: Good test coverage for the new feature.

The tests comprehensively cover the --mac-metadata option behavior including flag acceptance, --unstable requirement, mutual exclusivity with --no-mac-metadata, and various command modes. The macOS-specific tests properly validate xattr preservation.

cli/src/utils/os/unix/fs.rs (1)

89-171: Good use of scopeguard for resource cleanup.

The implementation properly addresses previous concerns about temp file leaks by using scopeguard::guard(). This ensures cleanup occurs on all exit paths including early returns and panics.

cli/src/command/extract.rs (1)

449-449: Extract command defaults to MacMetadataStrategy::Never.

The extract command hardcodes Never since it doesn't expose the --mac-metadata CLI flags (only the stdio path does). This is consistent with the append command.

cli/src/command/stdio.rs (5)

65-65: LGTM!

The new --mac-metadata and --no-mac-metadata CLI flags are properly:

  • Gated behind --unstable requirement
  • Made mutually exclusive via the mac-metadata-flag ArgGroup
  • Have clear help text explaining their purpose

Also applies to: 207-218


784-788: MacMetadataStrategy properly wired for extract mode.

The strategy is correctly derived from CLI flags using MacMetadataStrategy::from_flags().


947-951: MacMetadataStrategy properly wired for append mode.

Consistent with the extract path.


1086-1090: MacMetadataStrategy properly wired for update mode.

Consistent with the other paths.


681-700: Verify: Create path doesn't use MacMetadataStrategy.

The run_create_archive function uses CreationContext which doesn't include mac_metadata_strategy, while run_append and run_update use CreateOptions which does. This means --mac-metadata won't have any effect in create mode (-c), even though the flags are accepted.

Is this intentional? If so, consider emitting a warning when --mac-metadata is used with -c mode.

#!/bin/bash
# Check if CreationContext has mac_metadata_strategy field
rg -n "struct CreationContext" -A 20 cli/src/command/create.rs

# Check if CreateOptions has mac_metadata_strategy field  
rg -n "struct CreateOptions" -A 20 cli/src/command/core.rs
cli/src/command/core.rs (2)

636-711: LGTM! Strategy correctly propagated across all entry types.

The mac_metadata_strategy is consistently passed through all StoreAs variants (Hardlink, Symlink, File, Dir) to apply_metadata.


182-212: Enum definition and flag wiring are correct with comprehensive test coverage.

The MacMetadataStrategy enum and platform-specific from_flags implementations are well-structured and properly integrated. The CLI flags are correctly wired in cli/src/command/stdio.rs (lines 784-787, 947-950, 1086-1089), with comprehensive test coverage in cli/tests/cli/stdio/option_mac_metadata.rs, including macOS-specific tests that verify the Always variant preserves extended attributes. The static analysis warning about the Always variant is a false positive caused by platform-specific compilation on non-macOS CI environments—the variant is properly tested on macOS.

@github-actions github-actions Bot added the dependencies Pull requests that update a dependency file label Jan 5, 2026
@ChanTsune ChanTsune force-pushed the cli/stdio/mac-metadata branch from d5b1ee9 to 0b5bdba Compare January 5, 2026 23:41
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
cli/src/command/extract.rs (2)

945-971: Potential redundant metadata restoration when combining flags.

A past review noted that when mac_metadata_strategy is Always, unpack_apple_double restores xattrs and ACLs via copyfile(). However, the code above (lines 906-918 for xattrs, line 924 for ACLs) may also restore these if their respective strategies are Always.

On macOS, if a user passes --mac-metadata --keep-xattr --keep-acl, metadata could be applied twice:

  1. First via chunk-based restoration (xattrs chunk, ACL chunks)
  2. Then via unpack_apple_double (which sets xattrs/ACLs from AppleDouble)

This isn't incorrect (the AppleDouble data would overwrite), but it's inefficient. Consider either:

  • Documenting that --mac-metadata supersedes --keep-xattr/--keep-acl on macOS
  • Skipping individual xattr/ACL restoration when mac_metadata_strategy == Always on macOS

Since this is marked unstable and the behavior is safe (just potentially redundant), this can be deferred.


963-971: Consider collapsing nested if statements.

Static analysis flagged this nested structure. The two conditions can be combined:

🔎 Proposed fix
 #[cfg(not(target_os = "macos"))]
-if let MacMetadataStrategy::Always = mac_metadata_strategy {
-    if item.mac_metadata().is_some() {
-        log::warn!(
-            "macOS metadata present but cannot be restored on this platform: '{}'",
-            path.display()
-        );
-    }
+if let MacMetadataStrategy::Always = mac_metadata_strategy && item.mac_metadata().is_some() {
+    log::warn!(
+        "macOS metadata present but cannot be restored on this platform: '{}'",
+        path.display()
+    );
 }
cli/src/command/core.rs (1)

875-908: Potential duplicate metadata when combining --mac-metadata with --keep-xattr/--keep-acl.

Similar to the extraction path, when packing entries with mac_metadata_strategy == Always, the AppleDouble blob includes xattrs and ACLs. If keep_options.xattr_strategy or keep_options.acl_strategy is also Always, the same data may be stored twice:

  1. In dedicated xattr/ACL chunks (lines 837-853, 805-821)
  2. In the maMd AppleDouble chunk (lines 875-903)

This increases archive size without benefit. A past review suggested skipping individual xattr/ACL storage when mac_metadata_strategy == Always on macOS. Since this is an unstable feature, this optimization can be deferred, but consider documenting the interaction.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d5b1ee9 and 0b5bdba.

📒 Files selected for processing (13)
  • cli/Cargo.toml
  • cli/src/chunk.rs
  • cli/src/chunk/mac_metadata.rs
  • cli/src/command/append.rs
  • cli/src/command/core.rs
  • cli/src/command/create.rs
  • cli/src/command/extract.rs
  • cli/src/command/stdio.rs
  • cli/src/command/update.rs
  • cli/src/ext.rs
  • cli/src/utils/os/unix/fs.rs
  • cli/tests/cli/stdio.rs
  • cli/tests/cli/stdio/option_mac_metadata.rs
🚧 Files skipped from review as they are similar to previous changes (6)
  • cli/Cargo.toml
  • cli/src/chunk/mac_metadata.rs
  • cli/src/command/append.rs
  • cli/src/chunk.rs
  • cli/tests/cli/stdio.rs
  • cli/tests/cli/stdio/option_mac_metadata.rs
🧰 Additional context used
🧬 Code graph analysis (3)
cli/src/command/create.rs (1)
cli/src/command/core.rs (1)
  • create_entry (636-711)
cli/src/command/extract.rs (1)
cli/src/utils/os/unix/fs.rs (2)
  • copyfile (107-120)
  • unpack_apple_double (148-170)
cli/src/command/stdio.rs (1)
cli/src/command/core.rs (6)
  • from_flags (117-125)
  • from_flags (135-143)
  • from_flags (153-161)
  • from_flags (171-179)
  • from_flags (198-206)
  • from_flags (209-211)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (19)
  • GitHub Check: Test WebAssembly (nightly-2025-12-09, wasm32-wasip1)
  • GitHub Check: tier1 (ubuntu-22.04-arm, nightly)
  • GitHub Check: tier1 (windows-11-arm, beta)
  • GitHub Check: tier1 (ubuntu-22.04-arm, stable)
  • GitHub Check: Test WebAssembly (beta, wasm32-wasip2)
  • GitHub Check: Test WebAssembly (nightly-2025-12-09, wasm32-wasip2)
  • GitHub Check: Test WebAssembly (nightly-2025-12-09, wasm32-wasip1)
  • GitHub Check: Test WebAssembly (stable, wasm32-wasip2)
  • GitHub Check: tier1 (macos-latest, stable)
  • GitHub Check: tier1 (macos-latest, beta)
  • GitHub Check: tier1 (ubuntu-22.04-arm, stable)
  • GitHub Check: tier1 (ubuntu-22.04-arm, beta)
  • GitHub Check: tier1 (windows-11-arm, stable)
  • GitHub Check: tier1 (ubuntu-latest, nightly)
  • GitHub Check: tier1 (ubuntu-22.04-arm, nightly)
  • GitHub Check: tier1 (windows-11-arm, nightly)
  • GitHub Check: tier1 (ubuntu-latest, beta)
  • GitHub Check: msrv (ubuntu-latest, portable-network-archive)
  • GitHub Check: msrv (ubuntu-latest, libpna)
🔇 Additional comments (12)
cli/src/utils/os/unix/fs.rs (1)

89-171: LGTM! AppleDouble handling with proper cleanup.

The scopeguard usage correctly addresses the previous resource leak concerns. The temp file is now cleaned up on all exit paths, including early returns from copyfile and fs::read failures.

Minor observation: The pack_apple_double function reads the entire AppleDouble data into memory. For very large resource forks, this could be memory-intensive, but this is acceptable for typical use cases.

cli/src/ext.rs (1)

64-70: LGTM! Clean implementation following existing patterns.

The mac_metadata() accessor correctly scans extra_chunks for the maMd chunk type, consistent with the existing fflags() and acl() implementations.

cli/src/command/update.rs (1)

432-432: Verify: --mac-metadata flag not exposed in UpdateCommand.

The mac_metadata_strategy is hardcoded to Never here, while the stdio path uses MacMetadataStrategy::from_flags() to respect CLI arguments. This means the regular pna update subcommand won't support Mac metadata preservation.

If this is intentional (e.g., feature is stdio-only for now), consider adding a comment. Otherwise, the UpdateCommand struct should gain mac_metadata and no_mac_metadata flags similar to StdioCommand.

cli/src/command/create.rs (2)

502-502: Consistent with update.rs: --mac-metadata not exposed in CreateCommand.

Same as the update command, mac_metadata_strategy is hardcoded to Never. The stdio interface supports the flags, but the standalone pna create subcommand does not. If this is a phased rollout, consider tracking this as a follow-up task.


535-563: LGTM! Proper threading of mac_metadata_strategy through creation paths.

The mac_metadata_strategy is correctly destructured from CreationContext and passed into CreateOptions, ensuring consistent propagation through both file-based and split archive creation flows.

cli/src/command/stdio.rs (5)

207-218: LGTM! Well-designed CLI flags with appropriate gating.

The --mac-metadata and --no-mac-metadata flags are properly:

  • Grouped to prevent conflicting usage
  • Gated behind --unstable for experimental features
  • Documented with clear help text describing the scope (extended attributes and ACLs)

691-694: LGTM! Correct propagation in create path.

MacMetadataStrategy::from_flags() is used correctly, respecting the platform-specific behavior defined in core.rs.


788-791: LGTM! Correct propagation in extract path.

The extract flow properly receives the mac_metadata_strategy via OutputOption.


951-954: LGTM! Correct propagation in append path.


1090-1093: LGTM! Correct propagation in update path.

cli/src/command/core.rs (2)

182-212: LGTM! Well-designed platform-aware strategy enum.

The MacMetadataStrategy enum correctly uses conditional compilation to:

  • On macOS: Allow Always when --mac-metadata is passed
  • On non-macOS: Always return Never regardless of flags

The static analysis warnings about "variant Always is never constructed" are expected on non-macOS builds and can be safely ignored—the variant is used on macOS.


654-708: LGTM! Consistent propagation through all StoreAs variants.

The mac_metadata_strategy is correctly passed to apply_metadata for all entry types (Hardlink, Symlink, File, Dir), ensuring consistent behavior.

@ChanTsune ChanTsune force-pushed the cli/stdio/mac-metadata branch from 0b5bdba to 9aec838 Compare January 6, 2026 00:06
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Fix all issues with AI Agents 🤖
In @cli/src/command/core.rs:
- Around line 841-874: When keep_options.mac_metadata_strategy is
MacMetadataStrategy::Always on macOS, avoid duplicating metadata by skipping the
separate xattr and ACL collection paths; detect this case (check
keep_options.mac_metadata_strategy == MacMetadataStrategy::Always) before
executing the xattr and ACL handling blocks and short-circuit them so only
utils::os::unix::fs::copyfile::pack_apple_double(...) is used to produce the
maMd chunk (crate::chunk::maMd) added via entry.add_extra_chunk(...). Ensure the
conditional gating surrounds the existing xattr collection logic and the ACL
handling logic so they do not run when pack_apple_double is used.

In @cli/src/command/stdio.rs:
- Around line 792-795: The OutputOption construction duplicates
mac_metadata_strategy: remove the top-level mac_metadata_strategy initialization
and rely on the one inside keep_options; update the OutputOption builder to keep
only the mac_metadata_strategy set via KeepOptions (using
MacMetadataStrategy::from_flags(args.mac_metadata, args.no_mac_metadata)) and
delete the duplicate mac_metadata_strategy field at the top level so there is a
single source of truth for mac_metadata_strategy within KeepOptions.

In @cli/tests/cli/stdio/option_mac_metadata.rs:
- Around line 289-297: The test currently calls
Command::new("xattr").args(...).status().expect("Failed to set xattr") but does
not verify the process exit code; change it to capture the returned Status from
.status() and assert that status.success() (or call .expect_err/unwrap with a
message that includes the Status) so the test fails if xattr returns a non-zero
exit code; look for the Command::new("xattr") invocation in
option_mac_metadata.rs and replace the direct .expect on .status() with a check
against status.success().
- Around line 221-229: The test calls Command::new("xattr").status().expect(...)
which only ensures the process ran but not that it succeeded; capture the
returned Status (e.g., let status = Command::new("xattr")...
.status().expect(...)) and assert status.success(), failing the test with a
message that includes status.code() or the full Status so a non-zero exit is
detected and reported.
🧹 Nitpick comments (2)
cli/Cargo.toml (1)

43-43: Consider removing duplicate scopeguard from [dev-dependencies].

scopeguard is now declared in both [dependencies] (line 43) and [dev-dependencies] (line 74). Since it's a production dependency, the entry in [dev-dependencies] is redundant—Cargo will use the one from [dependencies] for both production and test builds.

🔎 Proposed fix
 [dev-dependencies]
 maplit = "1.0.2"
 path-slash = "0.2.1"
 rust-embed = { version = "8.9.0", features = ["debug-embed"] }
 same-file = "1.0.6"
-scopeguard = "1.2.0"
 walkdir = "2.5.0"

Also applies to: 74-74

cli/tests/cli/stdio/option_mac_metadata.rs (1)

273-276: Use assert_eq! for clearer test failure messages.

Using assert_eq! instead of assert!(...== ...) provides better diagnostic output when tests fail.

🔎 Proposed fix
-        assert!(output.status.success());
-        let extracted_value = String::from_utf8_lossy(&output.stdout);
-        assert!(extracted_value.trim() == "test_value");
+        assert!(output.status.success(), "xattr read command failed");
+        let extracted_value = String::from_utf8_lossy(&output.stdout);
+        assert_eq!(extracted_value.trim(), "test_value");
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0b5bdba and 9aec838.

📒 Files selected for processing (13)
  • cli/Cargo.toml
  • cli/src/chunk.rs
  • cli/src/chunk/mac_metadata.rs
  • cli/src/command/append.rs
  • cli/src/command/core.rs
  • cli/src/command/create.rs
  • cli/src/command/extract.rs
  • cli/src/command/stdio.rs
  • cli/src/command/update.rs
  • cli/src/ext.rs
  • cli/src/utils/os/unix/fs.rs
  • cli/tests/cli/stdio.rs
  • cli/tests/cli/stdio/option_mac_metadata.rs
🚧 Files skipped from review as they are similar to previous changes (3)
  • cli/src/chunk.rs
  • cli/src/command/append.rs
  • cli/src/command/create.rs
🧰 Additional context used
🧬 Code graph analysis (4)
cli/src/chunk/mac_metadata.rs (1)
lib/src/chunk/types.rs (1)
  • from_unchecked (225-227)
cli/src/command/stdio.rs (1)
cli/src/command/core.rs (6)
  • from_flags (117-125)
  • from_flags (135-143)
  • from_flags (153-161)
  • from_flags (171-179)
  • from_flags (198-206)
  • from_flags (209-211)
cli/src/command/extract.rs (2)
cli/src/command/core.rs (1)
  • collect_split_archives (581-598)
cli/src/utils/os/unix/fs.rs (2)
  • copyfile (107-120)
  • unpack_apple_double (148-170)
cli/src/command/core.rs (2)
cli/src/ext.rs (2)
  • mac_metadata (18-18)
  • mac_metadata (65-70)
cli/src/utils/os/unix/fs.rs (2)
  • copyfile (107-120)
  • pack_apple_double (124-145)
🔇 Additional comments (6)
cli/src/chunk/mac_metadata.rs (1)

1-10: LGTM!

The maMd chunk type constant is well-documented with clear explanation of the PNA chunk naming semantics. The use of unsafe { ChunkType::from_unchecked(*b"maMd") } is appropriate here since the 4-byte literal is a compile-time constant.

cli/src/ext.rs (1)

17-18: LGTM!

The mac_metadata trait method and implementation follow the established pattern of other methods like acl and fflags. The implementation correctly scans extra_chunks for the maMd chunk type and returns the raw data if present.

Also applies to: 64-70

cli/src/utils/os/unix/fs.rs (1)

89-171: Well-implemented macOS AppleDouble handling with proper resource cleanup.

The scopeguard usage correctly ensures temporary files are cleaned up on all exit paths, addressing the previous review concerns. The implementation properly wraps the macOS copyfile() API.

Minor note: The explicit drop(clean) calls at lines 143 and 168 are technically unnecessary since the guard would be dropped at scope end anyway, but they do make the cleanup point explicit.

cli/tests/cli/stdio.rs (1)

6-6: LGTM!

Module declaration properly added in alphabetical order within the test suite.

cli/src/command/update.rs (1)

404-404: Verify: mac_metadata_strategy is hardcoded to Never for the update command.

Unlike other commands (create, extract, append) that appear to have CLI flags for --mac-metadata, the update command hardcodes MacMetadataStrategy::Never.

Is this an intentional scope limitation for this PR, or should --mac-metadata / --no-mac-metadata flags be added to UpdateCommand for consistency?

cli/src/command/core.rs (1)

182-212: LGTM! Clean platform-aware strategy implementation.

The MacMetadataStrategy enum is well-designed with:

  • Clear documentation explaining AppleDouble behavior
  • Platform-aware from_flags constructors using cfg(target_os = "macos")
  • Proper default (Never) for non-macOS platforms

Comment thread cli/src/command/core.rs
Comment thread cli/src/command/extract.rs
Comment thread cli/src/command/stdio.rs Outdated
Comment thread cli/tests/cli/stdio/option_mac_metadata.rs Outdated
Comment thread cli/tests/cli/stdio/option_mac_metadata.rs Outdated
@ChanTsune ChanTsune force-pushed the cli/stdio/mac-metadata branch from 9aec838 to 9b4198d Compare January 6, 2026 00:16
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
cli/Cargo.toml (1)

43-43: Redundant scopeguard in [dev-dependencies].

scopeguard is now listed in both [dependencies] (line 43) and [dev-dependencies] (line 74). Since runtime dependencies are automatically available to tests, the [dev-dependencies] entry is redundant and can be removed.

🔎 Proposed fix

Remove line 74:

 [dev-dependencies]
 maplit = "1.0.2"
 path-slash = "0.2.1"
 rust-embed = { version = "8.9.0", features = ["debug-embed"] }
 same-file = "1.0.6"
-scopeguard = "1.2.0"
 walkdir = "2.5.0"

Also applies to: 74-74

cli/src/command/extract.rs (1)

977-985: Minor: Collapsible if statements.

The static analysis flagged that the nested if at lines 978-985 can be collapsed. This is a minor style improvement.

🔎 Proposed fix
     #[cfg(not(target_os = "macos"))]
-    if let MacMetadataStrategy::Always = mac_metadata_strategy {
-        if item.mac_metadata().is_some() {
-            log::warn!(
-                "macOS metadata present but cannot be restored on this platform: '{}'",
-                path.display()
-            );
-        }
+    if matches!(mac_metadata_strategy, MacMetadataStrategy::Always) && item.mac_metadata().is_some() {
+        log::warn!(
+            "macOS metadata present but cannot be restored on this platform: '{}'",
+            path.display()
+        );
     }
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9aec838 and 9b4198d.

📒 Files selected for processing (13)
  • cli/Cargo.toml
  • cli/src/chunk.rs
  • cli/src/chunk/mac_metadata.rs
  • cli/src/command/append.rs
  • cli/src/command/core.rs
  • cli/src/command/create.rs
  • cli/src/command/extract.rs
  • cli/src/command/stdio.rs
  • cli/src/command/update.rs
  • cli/src/ext.rs
  • cli/src/utils/os/unix/fs.rs
  • cli/tests/cli/stdio.rs
  • cli/tests/cli/stdio/option_mac_metadata.rs
🚧 Files skipped from review as they are similar to previous changes (6)
  • cli/src/chunk/mac_metadata.rs
  • cli/src/chunk.rs
  • cli/src/command/update.rs
  • cli/src/ext.rs
  • cli/tests/cli/stdio.rs
  • cli/src/command/stdio.rs
🔇 Additional comments (16)
cli/tests/cli/stdio/option_mac_metadata.rs (2)

1-46: Good test coverage for CLI flag acceptance.

The tests properly verify that --mac-metadata and --no-mac-metadata are accepted with --unstable, and that --mac-metadata fails without --unstable. The mutual exclusivity test at lines 71-88 correctly validates that both flags cannot be used together.


204-276: macOS xattr preservation test looks well-structured.

The test flow (set xattr → create archive with --mac-metadata → extract → verify xattr) correctly validates the AppleDouble roundtrip. The verification at line 273-275 properly checks both the command success and the extracted value.

cli/src/command/create.rs (2)

9-12: Import addition looks correct.

The MacMetadataStrategy is properly imported alongside other strategy types from the core module.


461-482: mac_metadata_strategy: MacMetadataStrategy::Never is appropriate here.

For the standard create command, defaulting to Never is correct since the --mac-metadata flag isn't exposed in this command's argument struct. The stdio command path handles the flag separately.

cli/src/command/append.rs (2)

9-12: Import correctly added.

MacMetadataStrategy is properly imported from the core module.


375-396: Consistent initialization of mac_metadata_strategy to Never.

This follows the same pattern as create.rs, correctly defaulting to Never for the standard append command.

cli/src/utils/os/unix/fs.rs (3)

89-120: Well-designed copyfile wrapper with proper error handling.

The copyfile function correctly uses nix::NixPath for safe path handling and properly propagates errors via nix::errno::Errno::result. The module is correctly gated behind #[cfg(target_os = "macos")].


122-145: pack_apple_double correctly uses scopeguard for cleanup.

The scopeguard::guard at line 129 ensures the temp file is removed regardless of how the function exits, addressing the resource leak concerns from past reviews. The implementation correctly:

  • Creates a unique temp file
  • Packs metadata via copyfile
  • Reads the result
  • Cleans up via scopeguard drop

147-171: unpack_apple_double properly handles temp file lifecycle.

Same scopeguard pattern ensures cleanup on all exit paths. The explicit drop(clean) at line 168 is slightly redundant (would happen anyway at function end) but doesn't cause issues.

cli/src/command/core.rs (3)

182-212: MacMetadataStrategy enum is well-designed.

The platform-specific from_flags implementations correctly ensure that Always is only returned on macOS, while non-macOS platforms always return Never. The #[derive(Default)] with #[default] on Never is appropriate.

Note: The static analysis warnings about "Always is never constructed" are false positives in cross-platform builds since Always is only constructed via the macOS-specific from_flags.


771-831: Duplicate metadata archival issue properly addressed.

The skip_xattr_acl flag (lines 771-779) correctly prevents duplicate xattr and ACL archival when mac_metadata_strategy is Always on macOS, since AppleDouble packing already captures this data. This addresses the critical issue flagged in past reviews.

The conditional guards at lines 782 and 813 properly skip the individual xattr/ACL handling when AppleDouble is being used.


853-886: AppleDouble packing implementation looks correct.

The macOS-specific packing logic:

  • Gracefully ignores NotFound errors (file has no Mac metadata)
  • Logs warnings for other failures without failing the operation
  • Uses the maMd chunk type for the AppleDouble data
  • Non-macOS platforms correctly emit a warning
cli/src/command/extract.rs (4)

11-14: Imports correctly added.

MacMetadataStrategy is properly imported alongside other strategy types.


404-451: Consistent initialization of mac_metadata_strategy to Never.

Both KeepOptions (line 424) and OutputOption (line 450) correctly default to Never for the standard extract command.


906-938: Redundant metadata restoration issue properly addressed.

The skip_xattr_acl logic (lines 906-913) correctly prevents duplicate xattr and ACL restoration when:

  1. mac_metadata_strategy is Always AND
  2. The entry actually has mac_metadata

This is more precise than the archival side, which is correct because during extraction we need to check if the entry has AppleDouble data before skipping individual restoration.


959-985: AppleDouble restoration implementation looks correct.

The macOS-specific restoration logic:

  • Only processes entries that have mac_metadata
  • Logs debug message on success
  • Logs warnings on failure without failing the operation
  • Non-macOS platforms correctly warn when mac_metadata is present but cannot be restored

@ChanTsune ChanTsune force-pushed the cli/stdio/mac-metadata branch from 9b4198d to 3647698 Compare January 6, 2026 00:38
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
cli/src/chunk/mac_metadata.rs (1)

10-10: Add SAFETY comment to justify the unsafe block.

The use of ChunkType::from_unchecked requires a SAFETY comment explaining why the byte pattern *b"maMd" satisfies the function's safety requirements. While the doc comment above describes the naming convention, a direct SAFETY comment above the unsafe block would clarify that this specific pattern is valid.

🔎 Proposed addition
 #[allow(non_upper_case_globals)]
-pub const maMd: ChunkType = unsafe { ChunkType::from_unchecked(*b"maMd") };
+// SAFETY: The byte pattern "maMd" follows the PNA chunk naming convention:
+// ancillary, private, reserved, safe-to-copy as documented above.
+pub const maMd: ChunkType = unsafe { ChunkType::from_unchecked(*b"maMd") };
cli/tests/cli/stdio/option_mac_metadata.rs (1)

12-202: Consider test cleanup for better isolation.

While the tests use unique file/directory names per test (e.g., stdio_mac_metadata_option_accepted.txt), they don't appear to explicitly clean up created artifacts. Consider adding cleanup code or using temporary directories to prevent potential test pollution across runs.

Example approach using tempfile or explicit cleanup

You could either:

  1. Use the tempfile crate to create temporary directories that auto-cleanup
  2. Add explicit cleanup in test teardown or at test start

Example pattern:

#[test]
fn my_test() {
    setup();
    let temp_dir = tempfile::tempdir().unwrap();
    let file = temp_dir.path().join("test.txt");
    // ... test code using file ...
    // temp_dir automatically cleaned up when dropped
}

Or add cleanup at the start of each test:

let file = "stdio_test.txt";
let _ = fs::remove_file(file); // Clean up if exists from previous run
fs::write(file, "content").unwrap();
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9b4198d and 3647698.

📒 Files selected for processing (13)
  • cli/Cargo.toml
  • cli/src/chunk.rs
  • cli/src/chunk/mac_metadata.rs
  • cli/src/command/append.rs
  • cli/src/command/core.rs
  • cli/src/command/create.rs
  • cli/src/command/extract.rs
  • cli/src/command/stdio.rs
  • cli/src/command/update.rs
  • cli/src/ext.rs
  • cli/src/utils/os/unix/fs.rs
  • cli/tests/cli/stdio.rs
  • cli/tests/cli/stdio/option_mac_metadata.rs
🚧 Files skipped from review as they are similar to previous changes (5)
  • cli/src/command/update.rs
  • cli/Cargo.toml
  • cli/src/ext.rs
  • cli/src/chunk.rs
  • cli/src/command/stdio.rs
🧰 Additional context used
🧬 Code graph analysis (3)
cli/src/chunk/mac_metadata.rs (1)
lib/src/chunk/types.rs (1)
  • from_unchecked (225-227)
cli/src/command/core.rs (3)
cli/src/ext.rs (2)
  • mac_metadata (18-18)
  • mac_metadata (65-70)
cli/src/utils/os/unix/fs/xattrs.rs (1)
  • get_xattrs (5-20)
cli/src/utils/os/unix/fs.rs (2)
  • copyfile (107-120)
  • pack_apple_double (124-145)
cli/src/command/extract.rs (2)
cli/src/utils/os/unix/fs/xattrs.rs (1)
  • set_xattrs (22-35)
cli/src/utils/os/unix/fs.rs (2)
  • copyfile (107-120)
  • unpack_apple_double (148-170)
🔇 Additional comments (21)
cli/tests/cli/stdio.rs (1)

6-6: LGTM!

The module declaration correctly integrates the new macOS metadata tests into the stdio test suite.

cli/src/command/create.rs (2)

10-12: LGTM!

The import addition correctly brings MacMetadataStrategy into scope for use in KeepOptions initialization.


481-481: LGTM!

Initializing mac_metadata_strategy to Never is correct here since CreateCommand doesn't expose --mac-metadata CLI flags. The macOS metadata functionality is available through the stdio command path (as evidenced by the test file).

cli/src/command/append.rs (2)

10-12: LGTM!

The import correctly adds MacMetadataStrategy to the append command's dependencies.


395-395: LGTM!

Consistent with create.rs, initializing mac_metadata_strategy to Never is appropriate since AppendCommand doesn't define CLI flags for macOS metadata handling.

cli/tests/cli/stdio/option_mac_metadata.rs (6)

12-26: LGTM!

These tests correctly verify that the CLI accepts --mac-metadata and --no-mac-metadata options when paired with --unstable. The tests are appropriately scoped to option parsing validation.

Also applies to: 32-46


52-66: LGTM!

These validation tests correctly verify that:

  1. --mac-metadata requires the --unstable flag
  2. --mac-metadata and --no-mac-metadata are mutually exclusive

The use of stderr predicates ensures proper error messaging.

Also applies to: 72-88


94-126: LGTM!

These tests provide comprehensive coverage of --mac-metadata across all stdio modes (extract, append, update). The test structure is consistent and correctly validates that the option is recognized in each operational context.

Also applies to: 132-163, 169-202


221-234: LGTM!

The xattr command status checking has been correctly implemented. Both tests now:

  1. Capture the returned Status from .status()
  2. Assert that status.success() is true
  3. Provide informative error messages with the exit code

This addresses the previous review feedback.

Also applies to: 294-307


214-281: LGTM!

This test correctly verifies the end-to-end preservation of macOS extended attributes when using --mac-metadata. The test flow is sound:

  1. Creates a file with xattr
  2. Archives it with --mac-metadata
  3. Extracts with --mac-metadata
  4. Verifies the xattr is restored

287-353: LGTM!

This test correctly verifies that xattrs are NOT preserved when using --no-mac-metadata. The assertion at line 352 correctly expects the xattr read command to fail (because the attribute doesn't exist in the extracted file).

cli/src/utils/os/unix/fs.rs (4)

89-106: LGTM! Well-structured module with proper documentation.

The module is correctly gated with #[cfg(target_os = "macos")] and includes helpful documentation referencing the Apple man page. The TEMP_COUNTER with process ID combination provides unique temporary file names across concurrent operations.


107-120: LGTM! Clean wrapper around libc::copyfile.

The function properly uses nix::NixPath for safe path-to-CString conversions and correctly checks the return value via Errno::result.


122-145: LGTM! Proper resource management with scopeguard.

The implementation correctly uses scopeguard to ensure the temporary file is cleaned up on all code paths (success or error). The order of operations (read data, then cleanup) is correct.


147-170: LGTM! Resource leak concerns from past reviews properly addressed.

The scopeguard pattern ensures the temporary file is cleaned up on all paths, including early returns from write_all or copyfile failures. The inner block ensures the file handle is dropped before calling copyfile.

cli/src/command/core.rs (3)

182-212: LGTM! Well-designed strategy enum with proper platform gating.

The MacMetadataStrategy enum follows the established pattern of other strategy enums in this file. The platform-specific from_flags implementations correctly ensure that Always is only returned on macOS, preventing misuse on other platforms.


771-831: LGTM! Correctly prevents duplicate metadata when using AppleDouble.

The skip_xattr_acl flag properly gates the individual xattr and ACL handling when mac_metadata_strategy is Always on macOS. This addresses the previous review concerns about data duplication.


853-886: LGTM! Appropriate error handling for metadata packing.

The implementation correctly:

  • Silently skips files without Mac metadata (NotFound)
  • Logs warnings for other failures without failing the archive operation
  • Only adds the chunk when data is non-empty
  • Provides a clear warning on non-macOS platforms
cli/src/command/extract.rs (3)

11-14: LGTM! Properly imports and initializes MacMetadataStrategy.

The import is correctly added and mac_metadata_strategy is initialized to Never in extract_archive, which is the expected default behavior for the extract command.

Also applies to: 424-424


895-929: LGTM! Correctly guards xattr/ACL restoration based on AppleDouble presence.

The skip_xattr_acl condition appropriately checks both mac_metadata_strategy == Always AND item.mac_metadata().is_some(). This ensures that entries without AppleDouble data still get their individual xattrs/ACLs restored, which is the correct behavior for archives containing a mix of entries.


950-976: LGTM! Consistent error handling for metadata restoration.

The implementation:

  • Logs success at debug level
  • Logs failures as warnings without failing extraction (consistent with create flow)
  • On non-macOS, only warns when metadata is actually present in the entry

The lenient error handling is appropriate for metadata operations that shouldn't block file extraction.

Comment thread cli/src/command/extract.rs Dismissed
Comment thread cli/src/command/extract.rs Dismissed
Add --mac-metadata and --no-mac-metadata flags to preserve macOS extended
attributes, ACLs, and resource forks using the AppleDouble format via copyfile().

- Introduce MacMetadataStrategy enum with Always/Never variants
- Integrate with KeepOptions for consistent metadata handling
- Add maMd chunk type for storing packed AppleDouble data
- Support all stdio modes: create (-c), extract (-x), append (-r), update (-u)
- Require --unstable flag as feature is experimental
@ChanTsune ChanTsune force-pushed the cli/stdio/mac-metadata branch from e5a59c1 to b4b2533 Compare January 6, 2026 09:24
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
cli/tests/cli/stdio/option_mac_metadata.rs (2)

52-66: Consider adding a corresponding test for --no-mac-metadata requiring --unstable.

The test stdio_mac_metadata_requires_unstable verifies that --mac-metadata fails without --unstable, but there's no equivalent test verifying that --no-mac-metadata also requires --unstable. This creates an asymmetry in test coverage.

🔎 Suggested test to add
/// Precondition: A file exists in the filesystem.
/// Action: Attempt to use --no-mac-metadata without --unstable flag.
/// Expectation: Command fails because --no-mac-metadata requires --unstable.
#[test]
fn stdio_no_mac_metadata_requires_unstable() {
    setup();
    let file = "stdio_no_mac_metadata_requires_unstable.txt";
    fs::write(file, "test content").unwrap();

    let mut cmd = cargo_bin_cmd!("pna");
    cmd.arg("experimental")
        .arg("stdio")
        .arg("-c")
        .arg("--no-mac-metadata")
        .arg(file)
        .assert()
        .failure()
        .stderr(predicate::str::contains("--unstable"));
}

94-126: Extract/append/update tests only cover --mac-metadata, not --no-mac-metadata.

The tests for extract (lines 94-126), append (lines 132-163), and update (lines 169-202) verify that --mac-metadata is accepted in these modes, but there are no corresponding tests for --no-mac-metadata. While not critical, this creates incomplete coverage of the flag matrix across different stdio operations.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e5a59c1 and b4b2533.

📒 Files selected for processing (13)
  • cli/Cargo.toml
  • cli/src/chunk.rs
  • cli/src/chunk/mac_metadata.rs
  • cli/src/command/append.rs
  • cli/src/command/core.rs
  • cli/src/command/create.rs
  • cli/src/command/extract.rs
  • cli/src/command/stdio.rs
  • cli/src/command/update.rs
  • cli/src/ext.rs
  • cli/src/utils/os/unix/fs.rs
  • cli/tests/cli/stdio.rs
  • cli/tests/cli/stdio/option_mac_metadata.rs
🚧 Files skipped from review as they are similar to previous changes (5)
  • cli/Cargo.toml
  • cli/src/ext.rs
  • cli/src/command/append.rs
  • cli/tests/cli/stdio.rs
  • cli/src/utils/os/unix/fs.rs
🧰 Additional context used
🧬 Code graph analysis (7)
cli/src/chunk.rs (1)
cli/src/ext.rs (2)
  • mac_metadata (18-18)
  • mac_metadata (65-70)
cli/tests/cli/stdio/option_mac_metadata.rs (2)
cli/src/command/core.rs (1)
  • new (283-304)
cli/src/ext.rs (1)
  • new (98-104)
cli/src/command/core.rs (4)
cli/src/ext.rs (2)
  • mac_metadata (18-18)
  • mac_metadata (65-70)
cli/src/utils/os/unix/fs/xattrs.rs (1)
  • get_xattrs (5-20)
cli/src/utils/os/unix/fs.rs (2)
  • copyfile (107-120)
  • pack_apple_double (124-145)
lib/src/chunk.rs (1)
  • from_data (288-300)
cli/src/chunk/mac_metadata.rs (1)
lib/src/chunk/types.rs (1)
  • from_unchecked (225-227)
cli/src/command/create.rs (1)
cli/src/command/core.rs (3)
  • collect_items_from_paths (392-406)
  • create_entry (636-678)
  • entry_option (680-700)
cli/src/command/extract.rs (3)
lib/src/entry.rs (1)
  • xattrs (888-890)
cli/src/utils/os/unix/fs/xattrs.rs (1)
  • set_xattrs (22-35)
cli/src/utils/os/unix/fs.rs (2)
  • copyfile (107-120)
  • unpack_apple_double (148-170)
cli/src/command/stdio.rs (1)
cli/src/command/core.rs (6)
  • from_flags (117-125)
  • from_flags (135-143)
  • from_flags (153-161)
  • from_flags (171-179)
  • from_flags (198-206)
  • from_flags (209-211)
🔇 Additional comments (14)
cli/src/command/core.rs (3)

182-212: LGTM: Well-designed platform-aware strategy pattern.

The MacMetadataStrategy enum with platform-conditional from_flags implementations cleanly handles the macOS-only nature of AppleDouble metadata. The default of Never is appropriate, and the non-macOS variant correctly ignores the flags to prevent runtime errors on unsupported platforms.


771-779: LGTM: Correct deduplication logic for macOS metadata.

The skip_xattr_acl flag properly prevents duplicate metadata when MacMetadataStrategy::Always is active on macOS, since pack_apple_double already captures xattrs and ACLs via copyfile(). This addresses the previously identified critical issue about data duplication.


853-886: LGTM: Robust AppleDouble packing with appropriate error handling.

The implementation correctly:

  • Skips empty AppleDouble data
  • Treats NotFound as a non-error (file has no Mac metadata)
  • Logs warnings for other errors without failing the entire operation
  • Emits a platform warning on non-macOS when Always is configured
cli/src/command/update.rs (1)

404-404: Verify: Update command lacks --mac-metadata CLI flag support.

The mac_metadata_strategy is hardcoded to Never, but the UpdateCommand struct doesn't include --mac-metadata/--no-mac-metadata flags like StdioCommand does. If this is intentional (deferring feature parity), consider adding a TODO comment. Otherwise, the flags should be added for consistency with other archive operations.

cli/src/command/create.rs (1)

481-481: Verify: Create command lacks --mac-metadata CLI flag support.

Similar to the update command, mac_metadata_strategy is hardcoded to Never. The StdioCommand supports --mac-metadata, but the standalone CreateCommand does not. If this is intentional (e.g., only supporting via stdio for bsdtar compatibility), consider documenting this design decision. Otherwise, add the flags for feature parity.

cli/src/command/stdio.rs (3)

65-65: LGTM: Proper argument group for mutual exclusion.

The mac-metadata-flag group correctly ensures --mac-metadata and --no-mac-metadata are mutually exclusive.


207-218: LGTM: Clear help text and appropriate unstable gating.

The CLI flags are well-documented with descriptive help text. Requiring --unstable is appropriate for this new feature.


671-674: LGTM: Consistent propagation across all stdio operations.

The MacMetadataStrategy::from_flags is correctly and consistently used in all four operations (create, extract, append, update), ensuring uniform behavior across the stdio interface.

Also applies to: 769-772, 932-935, 1073-1076

cli/src/command/extract.rs (3)

895-904: LGTM: Correct deduplication logic for extraction.

The skip_xattr_acl flag correctly checks both MacMetadataStrategy::Always AND the presence of mac_metadata before skipping separate xattr/ACL restoration. This is more precise than the creation side (which only checks strategy) because during extraction, the entry might not have mac_metadata even if the strategy is Always.


950-976: LGTM: Robust AppleDouble unpacking with appropriate fallback.

The implementation correctly:

  • Only unpacks when both strategy is Always AND mac_metadata is present
  • Logs debug on success for troubleshooting
  • Logs warnings for failures without stopping extraction
  • Provides informative warning on non-macOS platforms when metadata cannot be restored

424-424: Verify: Extract command lacks --mac-metadata CLI flag support.

Similar to create and update commands, mac_metadata_strategy is hardcoded to Never in the standalone ExtractCommand. The stdio interface supports the flags, but standalone commands do not. Consider adding flags for consistency or documenting this as intentional.

cli/src/chunk.rs (1)

3-3: LGTM: Consistent module structure.

The new mac_metadata module follows the existing pattern established by acl and fflag modules, with proper declaration and public re-export.

Also applies to: 7-7

cli/src/chunk/mac_metadata.rs (1)

1-10: LGTM: Well-documented chunk type with correct naming semantics.

The maMd chunk type follows PNA conventions appropriately:

  • Ancillary (lowercase first letter) - archive is still usable without it
  • Private (lowercase second letter) - not part of the public PNA specification
  • Reserved (uppercase third letter) - follows convention
  • Safe to copy (lowercase fourth letter) - can be copied when modifying the archive

The use of unsafe { ChunkType::from_unchecked(...) } is acceptable here since *b"maMd" is a compile-time constant valid 4-byte ASCII sequence.

cli/tests/cli/stdio/option_mac_metadata.rs (1)

206-356: Well-structured macOS xattr tests.

The macOS-specific tests properly verify:

  • Extended attributes are preserved when using --mac-metadata during both creation and extraction
  • Extended attributes are excluded when using --no-mac-metadata during creation, even if extraction attempts to restore them
  • Exit status checks for the xattr command are correctly implemented (addressing previous review feedback)

The test logic correctly uses assert!(!output.status.success()) at line 354 to verify that the xattr command fails when the attribute doesn't exist, which is the expected behavior when --no-mac-metadata was used during archive creation.

@ChanTsune ChanTsune merged commit 8918538 into main Jan 6, 2026
120 of 121 checks passed
@ChanTsune ChanTsune deleted the cli/stdio/mac-metadata branch January 6, 2026 13:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cli This issue is about cli application dependencies Pull requests that update a dependency file

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants