nodejs / nodejs/node

fs: fs.link() on exFAT volumes (Windows) fails with misleading EISDIR instead of "not supported"

未关闭
#65,817 6 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

主要语言
JavaScript
星标
122k
派生
37.4k
平均合并
4 天 3 小时
30 天内合并 PR
272

描述

  • Version: v24.19.0
  • Platform: Windows 11 Home (10.0.22631), x64 — NTFS system drive; two USB exFAT volumes (4TB / 2TB)
  • Subsystem: fs
What is wrong?

fs.linkSync(src, dest) targeting a file on an exFAT volume fails with errno EISDIR ("illegal operation on a directory"). The destination path does not exist and is not a directory. The real reason is that exFAT does not support hard links, and the underlying Win32 error is ERROR_INVALID_FUNCTION (WinError 1).

The EISDIR diagnosis actively misleads: it sends developers hunting for a directory that isn't there, instead of pointing at the unsupported filesystem operation.

Reproduction

On an exFAT-formatted volume (e.g. X:\):

$ node -e "require('fs').linkSync('X:\\a.tmp','X:\\b.tmp')"
Error: EISDIR: illegal operation on a directory, link 'X:\a.tmp' -> 'X:\b.tmp'

Python cross-check on the same volume shows the true underlying Win32 error:

$ python -c "import os; os.link(r'X:\a.tmp', r'X:\b.tmp')"
OSError: [WinError 1] 函数不正确。 (ERROR_INVALID_FUNCTION)

Observations from our test matrix (single machine, Windows 11 build 22631, Node v24.19.0):

Target volume Filesystem fs.linkSync result
C:, D:, F: NTFS succeeds
E: (USB), H: (USB) exFAT always fails with EISDIR

The failure splits perfectly along filesystem type, independent of internal/USB. Reads are unaffected; plain file writes work fine on exFAT.

Expected behavior

When CreateHardLinkW fails with ERROR_INVALID_FUNCTION on a filesystem without hard-link support, Node/libuv should surface a meaningful errno — e.g. ENOSYS ("function not implemented"), EPERM, or EOPNOTSUPP — rather than EISDIR.

For reference, on Linux, link(2) on filesystems that do not support hard links reports EPERM/EOPNOTSUPP, and on a system without the syscall at all ENOSYS.

Hypothesis (for upstream to confirm)

Possibly a missing mapping for ERROR_INVALID_FUNCTION in libuv's win32 uv_translate_sys_error, letting the failed uv_fs_link fall through to a misleading errno. We have not traced the exact layer; we only report the observed mapping WinError 1 (ERROR_INVALID_FUNCTION) → EISDIR.

Context / impact

This surfaced while diagnosing a third-party agent tool that publishes files via temp-file + hard-link: on exFAT drives every write failed, and the EISDIR message misattributed the cause. Reported downstream at https://github.com/deepseek-ai/deepseek-harness/discussions/5704 (includes the consumer-side analysis and a fallback-to-rename mitigation).

exFAT is the factory default format for many USB drives and SD cards, so "write to my external drive" is a common end-user scenario that hits this.

贡献指南

打开贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

调研方向

沿着 Windows CreateHardLinkW 路径跟踪 fs.link 和 uv_fs_link,然后检查 libuv 针对 ERROR_INVALID_FUNCTION 的 uv_translate_sys_error 映射。通过在 exFAT 上复现来确认该映射,并添加覆盖所得 errno 的回归测试;完成的标准是该错误不再报告 EISDIR,并能识别出不支持的操作。

由索引模型根据 Issue 内容生成。

评估

技术栈
javascript, node.js
领域
operating-systems
Issue 类型
缺陷
难度
4/5
预计耗时
3-5 天
活跃度
活跃
描述清晰度
基本清楚
新手友好度
55/100

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。