Repository navigation
fix: do not fail on sole directory inputs beyond MAX_PATH on Windows - #411
Conversation
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
The fallback changes descendant ignore-pattern matching because the expanded root is not propagated to traversal callers.
Review effort: Balanced
Findings: 1
Open (1)
What changed in this PR
Adds a Windows long-path fallback for sole-directory inputs.
Changes:
- Expands directories into absolute child paths when changing directory fails.
- Preserves the expanded root for interactive mode.
- Adds a Windows regression test.
| File | Description |
|---|---|
src/main.rs |
Implements fallback path expansion and testing. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| let cwd_device = device_id(&cwd).ok(); | ||
| // With an expanded root, the working directory is unchanged, so its entries are | ||
| // resolved against the root instead for the ignore checks below. | ||
| let base_dir = expanded_root.as_deref().unwrap_or(&cwd); |
There was a problem hiding this comment.
Good catch - fixed in the amended commit. The expanded directory is now recorded in a new WalkOptions::base_dir field: extract_paths_maybe_set_cwd sets it when it expands the sole input directory (the extract_aggregate_inputs_maybe_set_cwd delegation included), and iter_from_paths uses it in place of std::env::current_dir() as the base for ignore-pattern matching. Since aggregate, aggregate_tree, stacks and the interactive app (including refreshes and parent scans) all walk through iter_from_paths, descendants now resolve relative to the expanded root exactly as they would have after a successful chdir - e.g. subdir/ignored again excludes root/subdir/ignored. Verified on Windows against a 266-char root: --ignore-from output is now byte-for-byte identical to the equivalent short-path tree. Added base_dir_anchors_ignore_patterns_of_expanded_roots as a regression test.
A sole directory input is changed into so its entries can be listed and reported relative to it, but `set_current_dir` enforces `MAX_PATH` on Windows (os error 206) even though the directory itself can still be traversed through verbatim paths. When the change fails, expand the directory into absolute input paths directly instead of aborting, which makes a single long directory input work in list, aggregate, stacks and interactive modes alike. Reported paths are absolute then, consistent with how multiple inputs are already displayed. The expanded root is returned to callers so the interactive mode still knows which directory the inputs belong to, and recorded in the new `WalkOptions::base_dir`, which every traversal uses as the working directory stand-in for ignore-pattern matching. That keeps `--ignore-from` patterns matching descendants relative to the expanded root - identical to what a successful `chdir` would have produced. Fixes Byron#410
deb527e to
2fbb8f5
Compare
<!-- agent --> - [P1] Use the expanded root for interactive refreshes — /Users/byron/dev/github.com/Byron/dua-cli.fix-long-path-single-dir/src/main.rs:223-225 When changing directory fails and the expanded directory has at most one entry, pressing `R` at the initial view scans the launch directory instead. `AppState::refresh` resolves the still-empty synthetic tree root to `.` unless `root_paths.len() > 1`; neither `root_path` nor `base_dir` is consulted, so unrelated files replace the requested listing. Make interactive path resolution use the expanded root. The same omission also points the initial title and Git-ignore discovery at the wrong directory. - [P2] Measure the Windows test path in UTF-16 code units — /Users/byron/dev/github.com/Byron/dua-cli.fix-long-path-single-dir/src/main.rs:1318-1320 With a sufficiently non-ASCII temporary-directory path, such as one containing a CJK username, `OsStr::len()` can exceed 270 bytes while the path remains below `MAX_PATH` in UTF-16 code units. The directory change then succeeds, failing the unchanged-CWD assertion and potentially leaving other tests with a changed working directory. Count `encode_wide()` units when extending the fixture so it reliably exercises the fallback. Assisted-by: GPT 6.0 Astra Co-authored-by: GPT 6.0 Astra <codex@openai.com>

Fixes #410.
Bug
For a sole directory input,
extract_paths_maybe_set_cwd/extract_aggregate_inputs_maybe_set_cwdcallset_current_dir(path)so entries can be reported relative to it. On Windows,SetCurrentDirectoryWenforcesMAX_PATH(os error 206) — even for verbatim paths — although the directory itself is perfectly traversable. Sodua <dir>fails whenever the single dir arg is ≥259 chars, in every mode (list, aggregate,i, stacks). Measured boundary: 258 chars OK, 259 fails; a 277-char file arg and multi-arg dirs work fine.Fix (+97/-19,
src/main.rsonly)When
set_current_diron a sole dir fails, expand the directory into absolute input paths via a newdirlist()helper (plainfs::read_dirhandles long absolute paths because std verbatim-converts them, and dua-lib's walker handles them since #407). The aggregate fast path delegates toextract_paths_maybe_set_cwdon chdir failure — one fallback implementation, no duplication.expanded_rootis returned so interactive mode'sroot_pathstays correct.-ichecks resolve againstbase_dir(expanded root or cwd) — same semantics.Verified on real Windows
dua <259-char dir>Error: 文件名或扩展名太长。 (os error 206), exit 116 B D:\...\f.bin, exit 0dua <258-char dir>stacks/aggregate -d1/iTests
New
#[cfg(windows)]testsole_directory_beyond_max_path_expands_into_absolute_inputs: builds a >MAX_PATH tree via\\?\path, asserts the dir expands to absolute inputs without changing cwd. Passes on Windows via cross-compiled test exe.cargo test147/147 on Linux;cargo fmt --check+clippyclean.