Skip to content

tar: add -C/--directory flag#314

Draft
nnosal wants to merge 5 commits into
uutils:mainfrom
nnosal:feat/directory
Draft

tar: add -C/--directory flag#314
nnosal wants to merge 5 commits into
uutils:mainfrom
nnosal:feat/directory

Conversation

@nnosal

@nnosal nnosal commented Jun 30, 2026

Copy link
Copy Markdown

Add -C DIR / --directory=DIR to change the working directory before
performing any operation.

The archive file given by -f is opened in the original working
directory so that relative paths resolve correctly. set_current_dir
is called afterwards, just before the operation begins, so extraction
and creation happen relative to DIR.

A private apply_directory helper avoids repeating the same
set_current_dir call and error mapping at each of the four operation
call sites. A new TarError::CannotChangeDirectory variant carries the
target path and the underlying io::Error for a precise error message.

Integration tests cover basic extraction into a destination directory,
combined use with --strip-components, and rejection of a non-existent
directory with exit code 2.

Closes #169.

Note: stacked on top of #313 (--wildcards and --strip-components).
Please merge that one first, then this PR's diff will reduce to only
the -C changes.

Implements two GNU tar compatibility flags for extract and list modes:

- --wildcards: treat positional file arguments as glob patterns when
  filtering archive entries (* matches any string, ? matches any char)
- --strip-components=N: strip N leading path components from entry
  paths; entries that become empty after stripping are silently skipped

Shared helpers are added in operations/mod.rs:
  strip_leading_components(), wildcard_match(), entry_matches()

Closes uutils#186, closes uutils#195
@codecov

codecov Bot commented Jun 30, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.80137% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 98.12%. Comparing base (791ae26) to head (9643717).
⚠️ Report is 11 commits behind head on main.

Files with missing lines Patch % Lines
src/uu/tar/src/operations/extract.rs 80.55% 7 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #314      +/-   ##
==========================================
+ Coverage   96.84%   98.12%   +1.27%     
==========================================
  Files          11       15       +4     
  Lines        1492     2290     +798     
  Branches       29       51      +22     
==========================================
+ Hits         1445     2247     +802     
+ Misses         46       42       -4     
  Partials        1        1              
Flag Coverage Δ
macos_latest 98.12% <98.80%> (+1.27%) ⬆️
ubuntu_latest 98.12% <98.80%> (+1.27%) ⬆️
windows_latest 0.00% <0.00%> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

…natures

list_archive and extract_archive now take three additional arguments
(file_patterns, wildcards, strip_components). Pass neutral defaults
(&[], false, 0) at the benchmark call sites so the benchmarks compile
and measure the same workload as before.
@codspeed-hq

codspeed-hq Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will degrade performance by 26.01%

❌ 1 regressed benchmark
✅ 6 untouched benchmarks

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Benchmark BASE HEAD Efficiency
build_cli_command 44.3 µs 59.9 µs -26.01%

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing nnosal:feat/directory (9643717) with main (9aa518b)

Open in CodSpeed

…sal safety

Cover the three uncovered code paths in extract_archive:
- verbose output when strip_components > 0 (lines 76-78)
- create_dir_all for non-empty parent after stripping (line 82)
- path-traversal rejection for entries with ".." after strip (lines 68-74)
nnosal added 2 commits June 30, 2026 13:27
- Reformat two long list_archive calls in bench_tar.rs to satisfy rustfmt
- Replace make_plain_tar (which the tar crate rejects for paths with "..") with
  make_raw_traversal_tar that writes POSIX tar bytes directly, enabling tests
  for malicious archives with path-traversal components
Implements `-C DIR` / `--directory=DIR` (issue uutils#169).  The archive file
is opened in the original working directory so that relative `-f` paths
resolve correctly; `set_current_dir` is then called before the operation
begins so that extraction, creation, and listing all happen relative to
DIR.

A private `apply_directory` helper avoids repeating the same
`set_current_dir` + error-mapping block at each of the four call sites.
A new `TarError::CannotChangeDirectory` variant carries the target path
and underlying `io::Error` for a precise error message.

Three integration tests cover the flag: basic extraction into a
destination directory, combined use with `--strip-components`, and a
check that a non-existent directory is rejected with exit code 2.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

GNU tar compatibility: Add -C / --directory=DIR (global)

1 participant