fix(filesystem): harden file replacement with EPERM fallback#3610
fix(filesystem): harden file replacement with EPERM fallback#3610Chelebii wants to merge 4 commits into
Conversation
Extract replaceFileFromTemp helper that falls back to fs.cp when fs.rename fails with EPERM (Windows locked files). Temp file cleanup is best-effort so a successful write is never masked by a cleanup failure (e.g. antivirus holding the temp file). Changes: - Extract replaceFileFromTemp from inline rename logic in writeFileContent and applyFileEdits - Add EPERM fallback: rename -> cp + best-effort unlink - Document FILE_SHARE_DELETE limitation and non-atomic fallback in JSDoc - Add tests for EPERM fallback through both writeFileContent and applyFileEdits - Add tests for successful writes despite temp cleanup failure Fixes modelcontextprotocol#3430
|
Follow-up: all checks are now passing after the lockfile refresh commit (c22fad2). The earlier Python failure was caused by src/fetch/uv.lock being out of sync with src/fetch/pyproject.toml, and that is now resolved.\n\nAt this point the PR looks blocked only on maintainer review / merge, not on CI. |
|
@codex review focus on bugs, edge cases and missing tests |
|
@claude review |
|
Claude finished @cliffhall's task in 1m 49s —— View job Code Review
Overall this is a clean, well-motivated change. The refactoring reduces duplication, the JSDoc is excellent, and the new tests cover the primary scenarios. There are a couple of real issues worth addressing before merge. Bug: orphaned temp file when
|
|
Addressed the Claude review feedback in What changed:
Validation:
|
LuuOW
left a comment
There was a problem hiding this comment.
Technical audit: Verified MCP server implementation for consistency with current SDK patterns.
|
@Chelebii @olaservo, thank you both for the work and detailed investigation here. Is #3610 still the preferred path for resolving #3199/#3430? I noticed that the later review on #3296 recommends trying writeFile first before falling back to fs.cp for better symlink safety. If that change is still desired and additional help would be useful, I’d be happy to contribute a follow-up or prepare a fresh PR—whichever you prefer. |
|
Thanks for checking in. #3610 is still open and the current CI checks are passing. I agree that trying Your help with this change would be appreciated. A follow-up contribution to #3610 would probably be preferable, unless the maintainers would rather have a fresh PR. @olaservo, what do you think? |
|
@Chelebii Thanks, I’d be happy to help. Are you planning to implement the |
|
Thanks — I’m not planning to implement it myself. Rather than granting direct write access, could you make the change in your fork and open a PR against |
|
@Chelebii I opened Chelebii#2 with the |
|
Follow-up: merged @hxaxd's contribution from Chelebii#2 into this branch as Validation:
Thanks @hxaxd for the contribution. |
Problem
When \s.rename\ fails with \EPERM\ on Windows (e.g. VS Code or antivirus holding a file lock), both \writeFileContent\ and \�pplyFileEdits\ propagate the error even though the write could succeed via a fallback path. Additionally, if the fallback copy succeeds but temp file cleanup fails (antivirus briefly locks the temp), the user sees an error despite the target file being written correctly.
Ref: #3430, #3199
What changed
eplaceFileFromTemp\ helper from the inline rename logic in \writeFileContent\ and \�pplyFileEdits, eliminating code duplication.
Validation
\
npx vitest run
✓ tests/lib.test.ts (49 tests)
✓ tests/path-utils.test.ts (29 tests)
✓ tests/roots-utils.test.ts (3 tests)
✓ tests/path-validation.test.ts (53 tests)
✓ tests/directory-tree.test.ts (7 tests)
✓ tests/structured-content.test.ts (5 tests)
✓ tests/startup-validation.test.ts (4 tests)
Test Files 7 passed (7)
Tests 150 passed (150)
\\
\ sc --noEmit\ — 0 errors.
Checklist (from #3430)
eplaceFileFromTemp)
Fixes #3430