Skip to content

vfs: fix readlink, realpath and mkdtemp encoding - #66352

Open
christianaurichzm wants to merge 1 commit into
nodejs:mainfrom
christianaurichzm:vfs-path-encoding
Open

christianaurichzm wants to merge 1 commit into
nodejs:mainfrom
christianaurichzm:vfs-path-encoding

Conversation

@christianaurichzm

Copy link
Copy Markdown
Contributor

On a mounted VFS, readlink(), realpath() and mkdtemp() only honor { encoding: 'buffer' }. The string form 'buffer' and other encodings like 'hex' are ignored, and so is a Buffer mkdtemp() prefix:

const fs = require('node:fs');
const path = require('node:path');
const vfs = require('node:vfs');

const myVfs = vfs.create();
myVfs.writeFileSync('/file.txt', 'x');
myVfs.symlinkSync('file.txt', '/link');
const link = path.join(myVfs.mount(), 'link');

fs.readlinkSync(link, 'buffer'); // 'file.txt' instead of a Buffer
fs.readlinkSync(link, 'hex');    // 'file.txt' instead of '66696c652e747874'

With RealFSProvider the options are passed on to the host fs, so readlink() with 'buffer' throws ERR_INVALID_ARG_TYPE and myVfs.realpathSync(p, 'hex') fails with EACCES.

The VirtualFileSystem readlink and realpath methods now get a string from the provider and apply the encoding with getOptions() and encodeRealpathResult(), as fs does. The helper moves from lib/fs.js to internal/fs/utils. The mkdtemp hooks do the same, which replaces the per-hook Buffer conversions for these methods in setup.js.

Since the VFS works with string paths, a RealFSProvider link target that isn't valid UTF-8 won't keep its bytes with 'buffer'. readdir() has a similar gap, which I'll leave for a separate PR.

The new test covers the sync, callback and promise variants on a memory and a real mount, and fails on main. The test-vfs-* tests and the fs realpath/readlink/mkdtemp tests pass on x64 Linux.

@nodejs-github-bot nodejs-github-bot added fs Issues and PRs related to file-system APIs and the fs module. needs-ci PRs that need a full CI run. vfs Issues and PRs related to the virtual filesystem subsystem. labels Sep 27, 2026
@codecov

codecov Bot commented Sep 27, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.57%. Comparing base (53f037e) to head (5b7bfe0).

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #66352      +/-   ##
==========================================
- Coverage   90.59%   90.57%   -0.02%     
==========================================
  Files         797      797              
  Lines      278475   278481       +6     
  Branches    53533    53535       +2     
==========================================
- Hits       252293   252247      -46     
- Misses      16532    16572      +40     
- Partials     9650     9662      +12     
Files with missing lines Coverage Δ
lib/fs.js 97.17% <100.00%> (-0.01%) ⬇️
lib/internal/fs/utils.js 96.32% <100.00%> (+0.03%) ⬆️
lib/internal/vfs/file_system.js 99.64% <100.00%> (+<0.01%) ⬆️
lib/internal/vfs/setup.js 87.59% <100.00%> (+0.13%) ⬆️

... and 34 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@pipobscure pipobscure 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.

lgtm

On a mounted VFS, `readlink()`, `realpath()` and `mkdtemp()` only
returned a Buffer for `{ encoding: 'buffer' }`. The string form
`'buffer'`, any other encoding, and a Buffer `mkdtemp()` prefix were
ignored. The `VirtualFileSystem` `readlink` and `realpath` methods
ignored the encoding with `MemoryProvider` and passed it on to
`RealFSProvider`, which threw `ERR_INVALID_ARG_TYPE` for `'buffer'`,
while for other encodings `realpath()` failed and `readlink()`
returned the host path of absolute targets.

Get these paths from the provider as strings and apply the encoding
to the result, normalizing the options with `getOptions()` and
converting with `encodeRealpathResult()` as `fs` does. The latter
moves to `internal/fs/utils` so the VFS can use it.

Signed-off-by: Christian Aurich Zanettini Martins <christian.aurichzm@gmail.com>
@pipobscure

Copy link
Copy Markdown
Contributor

@trivikr @mcollina this might be something you want have a look at.

@christianaurichzm

christianaurichzm commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor Author

I rebased this on main and switched the test to --disable-warning=ExperimentalWarning, like the other VFS tests after #66318.

@mcollina mcollina left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

lgtm

@mcollina mcollina added the request-ci Add this label to start a Jenkins CI on a PR. Only starts once the PR has an approving review. label Oct 22, 2026
@github-actions github-actions Bot removed the request-ci Add this label to start a Jenkins CI on a PR. Only starts once the PR has an approving review. label Oct 22, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fs Issues and PRs related to file-system APIs and the fs module. needs-ci PRs that need a full CI run. vfs Issues and PRs related to the virtual filesystem subsystem.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants