fix(runtime): extend fs::validate to fsync/fdatasync/fchown/lchown/lchmod/copyFile/write/writev (#2013)#2181
Merged
Merged
Conversation
…hmod/copyFile/write/writev (#2013) Extends the #2035 validator surface to the rest-of-fs slice the #2013 update flagged as still falling through. Same Node-compatible error shape (TypeError [ERR_INVALID_ARG_TYPE] / RangeError [ERR_OUT_OF_RANGE] with the per-error side table from #2035 carrying `.code`). New validators in `fs::validate`: - `validate_fd(value)` — Node-compatible int32 fd check (`>= 0 && <= 2^31-1`). - `validate_int32(value, name, min, max)` — reused for uid / gid / mode. - `validate_function(name, value)` — TypeError if the value isn't a Perry closure, via `extract_closure_ptr`. Wired in: - `fsyncSync` / `fdatasyncSync` / `writeSync*` / `writevSync` — fd. `writevSync` skips fd validation when the buffers array is empty (matches Node: empty writev returns 0 without touching the fd). - `fchownSync` — fd, uid, gid. - `lchownSync` — path, uid, gid. - `lchmodSync` — path only (mode range deferred; Node opens the path first so `ENOENT` wins on non-existent paths). - `copyFileSync` / async — src, dest, mode (range-checked when supplied). - `exists` callback — `cb` must be a function (path bad-type is silent in Node). - `lchown` / `lchmod` async — same as their sync siblings + callback. To keep the `FileHandle` path safe (it may hold a `-1` fd sentinel from a failed open), extract `fsync_sync_inner` / `fdatasync_sync_inner` / `fchown_sync_inner` / `write_string_sync_inner` / `write_buffer_sync_inner` / `writev_sync_inner` helpers without validation and route `filehandle_*_impl` through those. The C-ABI `js_fs_*_sync` entry points still validate as before. Verification: - New `test-parity/node-suite/fs/sync/arg-validation.ts` is byte-identical to `node --experimental-strip-types` across 27 cases covering fd type+range, path-type, uid/gid type+range, copyFile src/dest/mode, write/writev fd, and the writev empty-array no-throw contract. - Direct re-run of `node-suite/fs/fd/{fdatasync, fstat-ftruncate-fsync, readv-writev, read-write-optional}.ts`, `callbacks/{chown, copyfile-excl, lchmod}.ts`, and `sync/captured-methods.ts` all byte-identical with Node — no regressions in the affected paths. - `cargo fmt --all -- --check` clean. Follow-ups still in #2013: `lchmodSync` mode + `lchownSync` range on existing paths (paired with `ENOENT` propagation), required-callback validation on `fsync`/`fdatasync`/`fchown` async wrappers, and the non-fs APIs (buffer, net, http, zlib, crypto, process, url, timers).
This was referenced May 29, 2026
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Extends the
fs::validatehelpers from #2035 to the rest-of-fssliceof #2013 — the 27
assert.throws-style tests the issue update flaggedas still falling through:
fsyncSync/fdatasyncSyncfchownSynclchownSynclchmodSynccopyFileSync(+ async)writeSyncfamilywritevSyncexists(callback)lchown/lchmodasyncNew validators in
fs::validatevalidate_fd(value)— TypeError for non-number, RangeError forNaN/Infinity/non-integer/out-of-range. Matches Node'svalidateInt32(fd, 'fd', 0).validate_int32(value, name, min, max)— reused for uid / gid / mode where Node validates a bounded integer.validate_function(name, value)— TypeError if the value isn't a Perry closure (via the existingextract_closure_ptrhelper). Mirrors Node'svalidateFunction.Range errors are surfaced through
js_rangeerror_newand registered in the per-error side table from #2035 soerr.code === 'ERR_OUT_OF_RANGE'round-trips correctly.Deliberate scope limits
lchmodSyncmode range: Node opens the path first, so a bad mode on a non-existent path surfacesENOENTbefore mode validation fires. Validating mode here in Perry would diverge from Node's ordering. The mode-on-existing-path validation is a separate follow-up paired with properENOENTpropagation.writevSyncempty buffers: Node skips fd validation when the buffers array is empty (returns 0 without touching the fd). Perry now gates fd validation onarray.length > 0to match.existsSyncis unchanged — it never throws on bad input under Node and Perry already returnsfalseviadecode_path_value.fsync/fdatasync/fchown/copyFilearen't validated at the top of the callback wrapper — those already dispatch into the sync impl which now validates fd, so anassert.throws(() => fs.fsync(input))with bad input throws regardless. Required-callback-on-valid-input is left for the next slice.Verification
test-parity/node-suite/fs/sync/arg-validation.ts— byte-identical tonode --experimental-strip-typesacross 27 cases covering fd type/range, path-type, uid/gid type/range, copyFile src/dest/mode, write/writev fd, and the writev empty-array no-throw contract.node-suite/fs(filehandle path still uses real fds;lchmodSyncmode pass-through unchanged).cargo fmt --all -- --checkclean.Follow-ups (still in #2013)
lchmodSync/lchownSyncmode + range validation on existing paths (paired withENOENTpropagation).fsync/fdatasync/fchownasync wrappers.