Skip to content

fs,win: fix bug in paths with trailing slashes - #54160

Merged
nodejs-github-bot merged 3 commits into
nodejs:mainfrom
JaneaSystems:huseyin-5301-inconsistent-fs-module
Oct 10, 2024
Merged

fs,win: fix bug in paths with trailing slashes#54160
nodejs-github-bot merged 3 commits into
nodejs:mainfrom
JaneaSystems:huseyin-5301-inconsistent-fs-module

Conversation

@huseyinacacak-janea

Copy link
Copy Markdown
Contributor

This PR fixes the inconsistency across platforms by throwing the same exception on Windows as on Linux.

I've taken the logic and the code in the referenced PR and modified it slightly to allow it to run with the current implementation of Node. Thanks @lundibundi.

Fixes: #17801
Refs: #33831

@nodejs-github-botnodejs-github-bot added fs Issues and PRs related to the fs subsystem / file system. needs-ci PRs that need a full CI run. labels Aug 1, 2024
@codecov

codecovBot commented Aug 1, 2024

Copy link
Copy Markdown

Codecov Report

Attention: Patch coverage is 98.41270% with 1 line in your changes missing coverage. Please review.

Project coverage is 87.10%. Comparing base (01cf9bc) to head (6a733cc).
Report is 736 commits behind head on main.

Files with missing linesPatch %Lines
lib/internal/fs/utils.js97.56%1 Missing ⚠️
Additional details and impacted files
@@ Coverage Diff @@## main #54160 +/- ##
==========================================
+ Coverage 87.07% 87.10% +0.03% 
==========================================
Files 643 647 +4 Lines 181583 181816 +233 Branches 34886 34895 +9 ==========================================
+ Hits 158114 158375 +261 + Misses 16751 16745 -6 + Partials 6718 6696 -22 
Files with missing linesCoverage Δ
lib/fs.js93.22% <100.00%> (-0.11%)⬇️
lib/internal/fs/promises.js97.55% <100.00%> (ø)
lib/internal/fs/streams.js93.46% <100.00%> (ø)
lib/internal/fs/utils.js95.12% <97.56%> (+0.07%)⬆️

... and 82 files with indirect coverage changes

@huseyinacacak-janea
huseyinacacak-janeaforce-pushed the huseyin-5301-inconsistent-fs-module branch from 31da37f to c93a41eCompareAugust 1, 2024 13:46
@huseyinacacak-janea
huseyinacacak-janeaforce-pushed the huseyin-5301-inconsistent-fs-module branch from c93a41e to 733558fCompareAugust 1, 2024 14:42
Comment threadlib/internal/fs/utils.js Outdated
);

const validatePath = hideStackFrames((path, propName = 'path') => {
const validatePath = hideStackFrames((path, propName = 'path', isFile) => {

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.

Can you add a JSDoc to this function and adding a small comment that explains the behavior of this new flag?

Suggested change
constvalidatePath=hideStackFrames((path,propName='path',isFile)=>{
constvalidatePath=hideStackFrames((path,propName='path',expectFile)=>{

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Fixed.

Comment threadlib/internal/fs/utils.js Outdated
code: 'ERR_FS_EISDIR',
message: 'is a directory',
path,
syscall: 'validatePath',

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.

Suggested change
syscall: 'validatePath',

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.

This is not a syscall.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I've applied the fix you suggested, but as you can see the CI doesn't accept throwing an error without a syscall. I didn't get this on Windows, only Linux.
This function is being called from a number of functions that contain different syscalls. Do you have any idea what I can write here?

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.

I think this syscall should be the name of the fs caller function. Maybe passing it as an argument would be the correct call here? For example, if fs.cpSync() is throwing this error, syscall should be cp. IMHO, Ideally we should throw this error from C++.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks for the review. Fixed.

Comment threadlib/internal/fs/utils.js
Comment threadlib/internal/fs/utils.js Outdated
* @throws {TypeError} Throws if the path is not a string, Uint8Array, or URL without null bytes.
* @throws {Error} Throws if the path does not meet the expected type (file).
*/
const validatePath = hideStackFrames((path, propName = 'path', expectFile) => {

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.

maybe we should go for options instead of expectFile and pass { expectFile: true, syscall: 'cp' }?

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.

And just check for options != null in 729?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Fixed.

@jasnelljasnell added the request-ci Add this label to start a Jenkins CI on a PR. label Aug 11, 2024
@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 11, 2024
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@anonrig

Copy link
Copy Markdown
Member

cc @nodejs/fs @nodejs/performance

@mcollinamcollina 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

Copy link
Copy Markdown
Member

I have a rough feeling that we might be better to land this as semver-major, or at the bare minimum to not backport to v20 and v18. Wdyt?

@RafaelGSS

RafaelGSS commented Aug 14, 2024

Copy link
Copy Markdown
Member

I have a rough feeling that we might be better to land this as semver-major, or at the bare minimum to not backport to v20 and v18. Wdyt?

That's my feeling too. I'd not land it on 22 too.


Honestly, I'm not confident this design is good/desirable. I can see people forgetting to pass such parameters in a future fs API.

@huseyinacacak-janea

Copy link
Copy Markdown
ContributorAuthor

Is there anything else I can do to help this PR move forward?

@mcollinamcollina added the semver-major PRs that contain breaking changes and should be released in the next major version. label Aug 29, 2024
@mcollina

Copy link
Copy Markdown
Member

@anonrig@RafaelGSS PTAL

@huseyinacacak-janea

Copy link
Copy Markdown
ContributorAuthor

Can someone take a look at this PR?

@anonriganonrig added the commit-queue Add this label to land a pull request using GitHub Actions. label Oct 10, 2024
@nodejs-github-botnodejs-github-bot removed the commit-queue Add this label to land a pull request using GitHub Actions. label Oct 10, 2024
@nodejs-github-bot
nodejs-github-bot merged commit 00b2f07 into nodejs:mainOct 10, 2024
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Landed in 00b2f07

@aduh95aduh95 mentioned this pull request Oct 10, 2024
@aduh95

Copy link
Copy Markdown
Contributor

This landed without a recent CI run, resulting in failing linter on main.

@ShenHongFei

ShenHongFei commented Oct 14, 2024

Copy link
Copy Markdown
Contributor

@huseyinacacak-janea@anonrig This change will cause webpack on windows to fail to save cache files.
[webpack.cache.PackFileCacheStrategy/webpack.FileSystemInfo] Error snapshotting file timestamp hash combination of T:\: SystemError [ERR_FS_EISDIR]: Path is a directory: read returned ERR_FS_EISDIR (is a directory) D:\.

Remove the following lines of code and recompile node.js to restore to normal. I'm not sure if the problem lies with webpack or here.

 if (options?.expectFile) {
const lastCharacter = path[path.length - 1];
if (
lastCharacter === '/' || lastCharacter === 47 ||
(isWindows && (lastCharacter === '\\' || lastCharacter === 92))
) {
throw new ERR_FS_EISDIR({
code: 'ERR_FS_EISDIR',
message: 'is a directory',
path,
syscall: options.syscall,
errno: ERR_FS_EISDIR,
});
}
}

I wrote an example project that can reproduce this error

https://github.com/ShenHongFei/webpack-bug

webpack error log
 [webpack.cache.PackFileCacheStrategy] No pack exists at T:\webpack-bug\node_modules\.cache\webpack\default-production.pack: Error: ENOENT: no such file or directory, stat 'T:\webpack-bug\node_modules\.cache\webpack\default-production\index.pack'
<t> [webpack.cache.PackFileCacheStrategy] restore cache container: 30.6804 ms
[webpack.cache.PackFileCacheStrategy] Pack got invalid because of write to: Compilation/modules|T:\webpack-bug\node_modules\.pnpm\ts-loader@9.5.1_typescript@5.6.3_webpack@5.95.0\node_modules\ts-loader\index.js??ruleSet[1].rules[0]!T:\webpack-bug\entry.ts
[webpack.cache.PackFileCacheStrategy] Storing pack...
[webpack.cache.PackFileCacheStrategy] Capturing build dependencies... (T:\webpack-bug\node_modules\.pnpm\webpack@5.95.0\node_modules\webpack\lib\, T:\webpack-bug\tsconfig.json, T:\webpack-bug\node_modules\.pnpm\ts-loader@9.5.1_typescript@5.6.3_webpack@5.95.0\node_modules\ts-loader\index.js)
<t> [webpack.cache.PackFileCacheStrategy] resolve build dependencies: 533.4064 ms
[webpack.cache.PackFileCacheStrategy/webpack.FileSystemInfo] Error snapshotting file timestamp hash combination of T:\: SystemError [ERR_FS_EISDIR]: Path is a directory: read returned ERR_FS_EISDIR (is a directory) T:\
at readFile (node:fs:389:5)
at go$readFile (T:\webpack-bug\node_modules\.pnpm\graceful-fs@4.2.11\node_modules\graceful-fs\graceful-fs.js:118:14)
at Object.readFile (T:\webpack-bug\node_modules\.pnpm\graceful-fs@4.2.11\node_modules\graceful-fs\graceful-fs.js:115:12)
at FileSystemInfo._readFileHash (T:\webpack-bug\node_modules\.pnpm\webpack@5.95.0\node_modules\webpack\lib\FileSystemInfo.js:3268:11)
at T:\webpack-bug\node_modules\.pnpm\webpack@5.95.0\node_modules\webpack\lib\util\AsyncQueue.js:324:10
at Hook.eval [as callAsync] (eval at create (T:\webpack-bug\node_modules\.pnpm\tapable@2.2.1\node_modules\tapable\lib\HookCodeFactory.js:33:10), <anonymous>:6:1)
at AsyncQueue._startProcessing (T:\webpack-bug\node_modules\.pnpm\webpack@5.95.0\node_modules\webpack\lib\util\AsyncQueue.js:314:26)
at AsyncQueue._ensureProcessing (T:\webpack-bug\node_modules\.pnpm\webpack@5.95.0\node_modules\webpack\lib\util\AsyncQueue.js:290:9)
at process.processImmediate (node:internal/timers:511:21)
<t> [webpack.cache.PackFileCacheStrategy] snapshot build dependencies: 3.4601 ms
<w> [webpack.cache.PackFileCacheStrategy] Caching failed for pack: Error: Unable to snapshot resolve dependencies
[webpack.cache.PackFileCacheStrategy] Error: Unable to snapshot resolve dependencies
at T:\webpack-bug\node_modules\.pnpm\webpack@5.95.0\node_modules\webpack\lib\cache\PackFileCacheStrategy.js:1385:13
at jobError (T:\webpack-bug\node_modules\.pnpm\webpack@5.95.0\node_modules\webpack\lib\FileSystemInfo.js:2232:5)
at T:\webpack-bug\node_modules\.pnpm\webpack@5.95.0\node_modules\webpack\lib\FileSystemInfo.js:2314:10
at T:\webpack-bug\node_modules\.pnpm\webpack@5.95.0\node_modules\webpack\lib\FileSystemInfo.js:3344:13
at T:\webpack-bug\node_modules\.pnpm\webpack@5.95.0\node_modules\webpack\lib\util\AsyncQueue.js:373:5
at Hook.eval [as callAsync] (eval at create (T:\webpack-bug\node_modules\.pnpm\tapable@2.2.1\node_modules\tapable\lib\HookCodeFactory.js:33:10), <anonymous>:6:1)
at Hook.CALL_ASYNC_DELEGATE [as _callAsync] (T:\webpack-bug\node_modules\.pnpm\tapable@2.2.1\node_modules\tapable\lib\Hook.js:18:14)
at AsyncQueue._handleResult (T:\webpack-bug\node_modules\.pnpm\webpack@5.95.0\node_modules\webpack\lib\util\AsyncQueue.js:343:21)
at T:\webpack-bug\node_modules\.pnpm\webpack@5.95.0\node_modules\webpack\lib\util\AsyncQueue.js:330:10
at Hook.eval [as callAsync] (eval at create (T:\webpack-bug\node_modules\.pnpm\tapable@2.2.1\node_modules\tapable\lib\HookCodeFactory.js:33:10), <anonymous>:6:1)

@blexrob

Copy link
Copy Markdown

This also causes trouble for emscripten: emscripten-core/emscripten#22812

@juanarboljuanarbol mentioned this pull request Oct 31, 2024
jeremybobbin added a commit to jeremybobbin/webpack that referenced this pull request Dec 5, 2024
…6417
Looks like a nodejs bug, introduced in v23.0.0 - commit hash 00b2f07f
It should be fixed in v23.2.0 - dd9b6833
bug: nodejs/node#54160fix: nodejs/node#55527
I am able to replicate this on v23.1.0.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fsIssues and PRs related to the fs subsystem / file system.needs-ciPRs that need a full CI run.semver-majorPRs that contain breaking changes and should be released in the next major version.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Inconsistent behavior with fs module accross platforms

9 participants

@huseyinacacak-janea@nodejs-github-bot@anonrig@mcollina@RafaelGSS@aduh95@ShenHongFei@blexrob@jasnell