Skip to content

Consolidate node fs/path/types helpers#32021

Open
alii wants to merge 8 commits into
mainfrom
claude/split/node-compat
Open

Consolidate node fs/path/types helpers#32021
alii wants to merge 8 commits into
mainfrom
claude/split/node-compat

Conversation

@alii

@alii alii commented Jun 9, 2026

Copy link
Copy Markdown
Member

What this does

Dedupes repeated argument-conversion and error-path blocks in node_fs.rs and removes dead helpers in node path/types. Net −500 lines.

Split from #31912 (whole-repo simplification pass; closing that PR in favor of module-scoped splits). This PR only moves and removes code — zero intended behavior change. Verified there by a per-file behavioral-equivalence audit and full CI; verified here by a standalone full-workspace compile check.

Tests

test/js/node/fs/fs-chown-utimes.test.ts pins the consolidated surface: chown/fchown/lchown must validate uid and gid identically and name the failing argument itself, utimes/futimes/lutimes likewise for atime/mtime, and utimesSync must follow symlinks while lutimesSync must not (the dispatch the merged utimes_with preserves). Because this PR intends zero behavior change, these tests pass before and after the refactor by design; they guard the shared readers against future drift. A test that fails on main cannot exist for this PR: any such failure would mean the consolidation changed observable behavior, which is the one outcome it must not have. The correctness argument is the behavioral-equivalence audit plus the full existing suite passing on both sides, not a fail-before proof. The wider surface is already covered by the existing basename/extname/parse tables, fs.test.ts, cp.test.ts, and the ported Node tests, all verified locally against this branch.

@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: b3c9aec7-ac96-44e3-8a47-9c981cd2b9c0

📥 Commits

Reviewing files that changed from the base of the PR and between 7b9b632 and d9ec253.

📒 Files selected for processing (1)
  • test/js/node/fs/fs-chown-utimes.test.ts

Walkthrough

Refactors Node filesystem and path runtime: shared UID/GID and timestamp argument parsers, centralized Linux/Android copy_file_range with EINTR policy and fallbacks, unified utimes/lutimes helper, path-scanning core for basename/extname, macro-generated enum labels, a type-detection simplification, and added tests.

Changes

Node Runtime Consolidation

Layer / File(s) Summary
Argument parsing helpers
src/runtime/node/node_fs.rs
id_from_js, time_arg_from_js, and times_from_js helpers eliminate duplicated uid/gid and timestamp validation; Chown, Fchown, Lutimes, and Futimes now delegate to these helpers.
Copy file range EINTR and fallback logic
src/runtime/node/node_fs.rs
EintrPolicy enum and copy_file_range_with_fallbacks() helper centralize Linux/Android copy logic: chunked syscalls with policy-based EINTR handling, unsupported-error detection, and sendfile/read-write fallback.
Copy operations routing
src/runtime/node/node_fs.rs
copy_file_inner and _copy_single_file_sync delegate to the shared copy helper with appropriate EINTR policies (Retry vs Surface), removing inline loop and fallback scaffolding.
Timestamp operations consolidation
src/runtime/node/node_fs.rs
utimes_with() helper unifies Windows and non-Windows timestamp syscall invocation; utimes and lutimes delegate to it with platform-specific function pointers, eliminating duplicated branching.
Function enum codegen
src/runtime/node/node_fs.rs
node_fs_function_enum! macro generates both NodeFSFunctionEnum variants and the heap_label() match mapping, replacing hand-written enum and function.
Path basename refactoring
src/runtime/node/path.rs
is_sep_t predicate and basename_t::<T, IS_WINDOWS> const-generic implementation unify POSIX and Windows separator and drive-letter handling; public entry points delegate to the shared core.
Path component scanning
src/runtime/node/path.rs
LastComponentScan struct and scan_last_component_t helper centralize reverse-scanning for path components; extname_t::<T, IS_WINDOWS> consumes this to compute extensions for both platforms.
Path parse integration
src/runtime/node/path.rs
parse_posix_t and parse_windows_t use scan_last_component_t for non-dir info extraction, eliminating duplicated reverse-scanning loops.
Type predicate simplification
src/runtime/node/types.rs
StringOrBuffer::from_js_maybe_async_into uses is_array_buffer_like() predicate instead of explicit JSType enumeration, simplifying ArrayBufferView detection.
FS tests added
test/js/node/fs/fs-chown-utimes.test.ts
Adds tests for chown*/utimes* argument validation and symlink vs target behavior for utimesSync/lutimesSync.
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: consolidating helper functions in node fs/path/types modules.
Description check ✅ Passed The description exceeds template requirements with detailed "What this does" and "Tests" sections covering the refactoring scope, verification approach, and test strategy.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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

@robobun

robobun commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator
Updated 5:05 AM PT - Jun 10th, 2026

@robobun, your commit d9ec253 has some failures in Build #61738 (All Failures)


🧪   To try this PR locally:

bunx bun-pr 32021

That installs a local version of the PR into your bun-32021 executable, so you can run:

bun-32021 --bun

@alii

alii commented Jun 9, 2026

Copy link
Copy Markdown
Member Author

@robobun adopt

@robobun

robobun commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator

Adopted. I audited the full diff against main for behavior changes and found none. The basename/extname/parse merges keep the exact loop bounds and drive-letter gating of the split posix/win32 versions. copy_file_range_with_fallbacks preserves the EINTR split between its callers (fs.copyFile retries, fs.cp surfaces the error), the fallback errno set, and the scopeguard ordering. is_array_buffer_like() covers exactly the 14 types the deleted enumeration listed.

Verified on a local debug build: the node path suites, upstream test-path-, fs.test.ts, cp.test.ts, promises.test.js, and test-fs-{utimes,chown-type-check,copyfile} all pass. Added test/js/node/fs/fs-chown-utimes.test.ts pinning the consolidated uid/gid and atime/mtime readers and the utimes/lutimes symlink dispatch; it surfaced two pre-existing gaps now tracked separately (#32047, #32050).

CI state: in the latest build (61738), every job that executed passed on all platforms (284 green, zero test failures). The build is red only because two darwin-14-aarch64 test shards expired in the agent queue before running, twice in a row, same as an earlier debian shard. This needs either a job retry in the Buildkite UI or a merge decision on the green lanes; another push from me would just re-enter the same starved queues.

@coderabbitai coderabbitai Bot left a comment

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.

Caution

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

⚠️ Outside diff range comments (1)
src/runtime/node/node_fs.rs (1)

8083-8142: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

lutimes() now reports the wrong syscall on Windows failures.

utimes_with() hardcodes sys::Tag::utime, and lutimes() now funnels through it. On Windows that changes the exposed err.syscall from lutime to utime for fs.lutimes() failures.

Suggested fix
     fn utimes_with(
         &mut self,
         args: &args::Utimes,
+        syscall: sys::Tag,
         #[cfg(windows)] uv_utime: unsafe extern "C" fn(
             *mut uv::Loop,
             *mut uv::fs_t,
             *const core::ffi::c_char,
@@
             return if let Some(errno) = rc.errno() {
                 Err(sys::Error {
                     errno,
-                    syscall: sys::Tag::utime,
+                    syscall,
                     path: args.path.slice().into(),
                     ..Default::default()
                 })
             } else {
                 Ok(())
@@
     pub fn utimes(&mut self, args: &args::Utimes, _: Flavor) -> Maybe<ret::Utimes> {
         #[cfg(windows)]
-        return self.utimes_with(args, uv::uv_fs_utime);
+        return self.utimes_with(args, sys::Tag::utime, uv::uv_fs_utime);
         #[cfg(not(windows))]
-        self.utimes_with(args, Syscall::utimens)
+        self.utimes_with(args, sys::Tag::utime, Syscall::utimens)
     }

     pub fn lutimes(&mut self, args: &args::Lutimes, _: Flavor) -> Maybe<ret::Lutimes> {
         #[cfg(windows)]
-        return self.utimes_with(args, uv::uv_fs_lutime);
+        return self.utimes_with(args, sys::Tag::lutime, uv::uv_fs_lutime);
         #[cfg(not(windows))]
-        self.utimes_with(args, Syscall::lutimens)
+        self.utimes_with(args, sys::Tag::lutime, Syscall::lutimens)
     }

As per coding guidelines: "Node.js compatibility: match Node's full error contract including error code, constructor class, message text, properties, and check ordering."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/runtime/node/node_fs.rs` around lines 8083 - 8142, The Windows branch in
utimes_with() always sets sys::Tag::utime, so when lutimes() calls utimes_with()
failures report the wrong syscall; update utimes_with() to accept an explicit
sys::Tag (or a boolean flag) and use that tag when constructing the Error (i.e.,
pass sys::Tag::lutime from lutimes() and sys::Tag::utime from utimes()), or
alternatively detect which wrapper called it and set errno.syscall accordingly;
change the signatures/call sites (utimes(), lutimes(), and utimes_with()) to
thread the correct tag through so errors on Windows report sys::Tag::lutime for
lutimes() failures.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/runtime/node/node_fs.rs`:
- Around line 8083-8142: The Windows branch in utimes_with() always sets
sys::Tag::utime, so when lutimes() calls utimes_with() failures report the wrong
syscall; update utimes_with() to accept an explicit sys::Tag (or a boolean flag)
and use that tag when constructing the Error (i.e., pass sys::Tag::lutime from
lutimes() and sys::Tag::utime from utimes()), or alternatively detect which
wrapper called it and set errno.syscall accordingly; change the signatures/call
sites (utimes(), lutimes(), and utimes_with()) to thread the correct tag through
so errors on Windows report sys::Tag::lutime for lutimes() failures.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: ef6ee141-6998-469a-861e-af590e172bf8

📥 Commits

Reviewing files that changed from the base of the PR and between 09703da and 68223b1.

📒 Files selected for processing (3)
  • src/runtime/node/node_fs.rs
  • src/runtime/node/path.rs
  • src/runtime/node/types.rs

@robobun

robobun commented Jun 10, 2026

Copy link
Copy Markdown
Collaborator

On the CodeRabbit finding that lutimes() "now reports the wrong syscall on Windows": the premise is wrong, this PR does not change the reported syscall. The pre-PR Windows lutimes block already built its error with sys::Tag::utime:

return if let Some(errno) = rc.errno() {
Err(sys::Error {
errno,
syscall: sys::Tag::utime,
path: args.path.slice().into(),
..Default::default()
})

utimes_with keeps that exact tag, so before and after are identical. The POSIX side is also unchanged: Syscall::utimens and Syscall::lutimens both tag Tag::utimensat, so fs.utimesSync and fs.lutimesSync both report syscall: "utimensat" on Linux today, while Node reports "utime" and "lutime".

That divergence from Node's error contract is real but pre-existing and cross-platform, and fixing it here would contradict this PR's zero-behavior-change contract. Tracked in #32047.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/js/node/fs/fs-chown-utimes.test.ts`:
- Line 10: The test suite describe blocks for "chown/fchown/lchown argument
validation" (and the other describe at the same file) should be switched to
concurrent execution to speed up tests: replace describe("chown/fchown/lchown
argument validation", ...) with describe.concurrent("chown/fchown/lchown
argument validation", ...) and do the same for the second describe block
referenced in the comment so both describe blocks run tests in parallel safely
(each test already uses tmpdirSync()).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 1057555e-b5da-443a-a082-55d9fb630623

📥 Commits

Reviewing files that changed from the base of the PR and between 68223b1 and 26e1333.

📒 Files selected for processing (1)
  • test/js/node/fs/fs-chown-utimes.test.ts

Comment thread test/js/node/fs/fs-chown-utimes.test.ts Outdated
robobun added 2 commits June 10, 2026 05:55
fs.lchown is a TODO stub on Windows (#32050); argument validation still
throws before the stub, so those assertions keep running everywhere.
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.

2 participants