Skip to content

fs: support removing read-only files in rmSync on Windows - #64453

Open
SparshGarg999 wants to merge 2 commits into
nodejs:mainfrom
SparshGarg999:fix/fs-rmSync-readonly-win
Open

fs: support removing read-only files in rmSync on Windows#64453
SparshGarg999 wants to merge 2 commits into
nodejs:mainfrom
SparshGarg999:fix/fs-rmSync-readonly-win

Conversation

@SparshGarg999

Copy link
Copy Markdown

Summary

Ensure fs.rmSync can delete read-only files and directories containing them on Windows when Node is built with clang libc++ (e.g. inside Electron).

Description

Since the migration to std::filesystem::remove and std::filesystem::remove_all on Windows, Node's fs.rmSync behaves differently depending on whether it was built with MSVC STL or clang libc++.

MSVC STL's implementation of std::filesystem::remove automatically clears the read-only attribute of a file before attempting to delete it. However, libc++'s implementation on Windows does not clear the read-only attribute, which causes the deletion to fail with operation_not_permitted (EPERM). This issue directly impacts downstream platforms like Electron that compile Node.js with libc++ on Windows (see electron/electron#52253).

This commit introduces a Windows-specific helper ClearReadOnlyAttributeW in src/node_file.cc that is called if operation_not_permitted is encountered. It manually clears the FILE_ATTRIBUTE_READONLY attribute from the file (or recursively from files inside a directory) and retries the removal operation, bringing libc++ builds to parity with MSVC STL builds.

Verification

Added a new test in test/parallel/test-fs-rm.js that makes files read-only using fs.chmodSync(file, 0o444) (which sets the file attribute on Windows) and validates that fs.rmSync can delete them both directly and recursively as part of a directory.

Fixes: #64374

@nodejs-github-bot nodejs-github-bot added c++ Issues and PRs that require attention from people who are familiar with C++. fs Issues and PRs related to the fs subsystem / file system. needs-ci PRs that need a full CI run. labels Jul 12, 2026
@SparshGarg999
SparshGarg999 force-pushed the fix/fs-rmSync-readonly-win branch from 93e7ab9 to 8d6ce84 Compare July 12, 2026 15:44
@codecov

codecov Bot commented Jul 13, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.24%. Comparing base (892976d) to head (b81d55a).
⚠️ Report is 517 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #64453      +/-   ##
==========================================
- Coverage   90.24%   90.24%   -0.01%     
==========================================
  Files         741      739       -2     
  Lines      241424   241653     +229     
  Branches    45494    45552      +58     
==========================================
+ Hits       217883   218082     +199     
- Misses      15085    15103      +18     
- Partials     8456     8468      +12     
Files with missing lines Coverage Δ
src/node_file.cc 74.19% <ø> (ø)

... and 46 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.

@SparshGarg999
SparshGarg999 force-pushed the fix/fs-rmSync-readonly-win branch from 8d6ce84 to 3d732cb Compare July 13, 2026 14:14
@SparshGarg999

Copy link
Copy Markdown
Author

I have updated the PR to address the CI failures and the Codecov warning:

  1. Commit Message Guidelines: Reworded the commit message to ensure all lines in the body are under 72 characters.
  2. C++ Code Formatting: Formatted src/node_file.cc using clang-format to conform with the project's style guidelines.
  3. Codecov Patch Coverage: Reordered the Windows-specific preprocessing block in RmSync() so that the compiled code path on non-Windows platforms (like Linux) remains completely identical to main, resolving the Codecov partial coverage warning on !can_omit_error(error).

Comment thread src/node_file.cc Outdated
Comment thread src/node_file.cc Outdated
Comment thread src/node_file.cc
On Windows, libc++ std::filesystem::remove and remove_all do not
automatically clear the read-only attribute before deleting a file
(unlike MSVC STL). This causes fs.rmSync to fail with EPERM when
trying to remove read-only files in environments where Node.js is
built using clang libc++ (such as Electron).

This commit introduces a Windows-specific helper
ClearReadOnlyAttributeW which clears the FILE_ATTRIBUTE_READONLY
attribute recursively (or for a single file) when
operation_not_permitted is returned, allowing rmSync to
successfully delete read-only files/folders.

Fixes: nodejs#64374

Signed-off-by: SparshGarg999 <sparshgarg999@gmail.com>
@SparshGarg999
SparshGarg999 force-pushed the fix/fs-rmSync-readonly-win branch from 3d732cb to b81d55a Compare July 15, 2026 09:21
@SparshGarg999

SparshGarg999 commented Jul 15, 2026

Copy link
Copy Markdown
Author

Thanks for the review! I've pushed an update that:

  • Declares file_status once above the block.
  • Moves the duplicate logic into ClearReadOnlyAttributeWHelper.
  • Uses a cleared_readonly flag so the helper only runs once across retries.

@StefanStojanovic StefanStojanovic added the request-ci Add this label to start a Jenkins CI on a PR. label Aug 18, 2026
@github-actions github-actions Bot removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 18, 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

c++ Issues and PRs that require attention from people who are familiar with C++. fs Issues and PRs related to the fs subsystem / file system. needs-ci PRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fs.rmSync cannot remove read-only files on Windows when Node is built with libc++

4 participants