Skip to content

chroot: report ENAMETOOLONG instead of "no such directory" for long NEWROOT - #13881

Open
MsfPablo wants to merge 1 commit into
uutils:mainfrom
MsfPablo:fix-chroot-enametoolong
Open

chroot: report ENAMETOOLONG instead of "no such directory" for long NEWROOT#13881
MsfPablo wants to merge 1 commit into
uutils:mainfrom
MsfPablo:fix-chroot-enametoolong

Conversation

@MsfPablo

Copy link
Copy Markdown
Contributor

Fixes #13156.

Problem

GNU chroot reports File name too long when NEWROOT exceeds NAME_MAX (255 bytes on Linux). uutils was reporting no such directory instead.

$ gnuchroot "$(python3 -c "print(\"A\"*256)")"
gnuchroot: cannot change root directory to 'AAA…': File name too long

$ uuchroot "$(python3 -c "print(\"A\"*256)")"
chroot: cannot change root directory to 'AAA…': no such directory   ← wrong

Cause

Path::is_dir() swallows any I/O error and reports false. For a path longer than NAME_MAX the kernel returns ENAMETOOLONG, but is_dir() flattens it to false, so the existing NoSuchDirectory branch always wins.

Fix

Probe the path with std::fs::metadata() first and surface the real io::Error via a new ChrootError::CannotStat variant. The is_dir() check still runs afterward, so the existing "is not a directory" behavior is preserved unchanged.

$ uuchroot "$(python3 -c "print(\"A\"*256)")"
chroot: cannot change root directory to 'AAA…': File name too long (os error 63)

Tests

  • test_no_such_directory (existing, unchanged) — confirms path that exists but is not a directory still gets no such directory.
  • test_filename_too_long (new) — confirms 256-char NEWROOT now reports File name too long (os error 63).

cargo test -p coreutils --test tests --features chroot test_chroot → 20 passed, 0 failed.

🤖 Generated with Claude Code

…EWROOT

GNU chroot reports 'File name too long' when NEWROOT exceeds NAME_MAX;
uutils was reporting 'no such directory' because Path::is_dir() silently
swallowed the ENAMETOOLONG error from metadata().

This change probes the path with std::fs::metadata() first and surfaces the
real io::Error via a new CannotStat variant. Existing 'is not a directory'
behavior is preserved.

Fixes uutils#13156.
options.chroot_target = resolved;
}

// Probe the path with `metadata` so the *original* I/O error reaches the

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

please make the comment shorter

// `Path::is_dir()` swallows ENAMETOOLONG. GNU surfaces the real error.
let long_name = "A".repeat(256);
let expected = format!(
"chroot: cannot change root directory to '{long_name}': File name too long (os error 63)\n"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

please use the strip_errno in the code to remove the (os error 63)

@codspeed-hq

codspeed-hq Bot commented Aug 11, 2026

Copy link
Copy Markdown

Merging this PR will degrade performance by 3.96%

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

⚡ 2 improved benchmarks
❌ 1 regressed benchmark
✅ 76 untouched benchmarks
⏩ 314 skipped benchmarks1

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Mode Benchmark BASE HEAD Efficiency
Simulation df_with_path 573.7 µs 704.6 µs -18.58%
Simulation du_max_depth_balanced_tree[(6, 4, 10)] 65.2 ms 62.4 ms +4.49%
Simulation du_summarize_balanced_tree[(5, 4, 10)] 16.8 ms 16.1 ms +4.14%

Tip

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


Comparing MsfPablo:fix-chroot-enametoolong (e649307) with main (822aa83)

Open in CodSpeed

Footnotes

  1. 314 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

// would be misreported as "no such directory".
if let Err(e) = std::fs::metadata(&options.newroot) {
return Err(ChrootError::CannotStat(options.newroot, e).into());
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We should remove .is_dir() on many platforms instead of adding such hack to extract err from ctual chroot call instead.

/// The given path could not be stat'd (e.g. ENAMETOOLONG, EACCES).
#[error("{}", translate!("chroot-error-cannot-stat", "dir" => _0.quote(), "err" => _1))]
CannotStat(PathBuf, #[source] Error),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why is this needed even it is extracted from OS?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I opened a better alternative #13881 .

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.

bug(chroot): when a filename larger it produces incorrect error messages

4 participants