Repository navigation
Fix os.rename deleting the destination when the source does not exist - #364
Conversation
FileSystem.Rename removed the destination file before checking that the source exists, so a failed os.rename lost the destination's contents. Check the source first, as rename(2) does. With the data no longer lost, the part of files.lua that the test harness skipped now runs unmodified.
There was a problem hiding this comment.
🟢 Approval recommended
The targeted fix addresses the reported data loss, with regression coverage for both entry points and no unresolved findings.
No open issues 🎉
What changed in this PR
Fixes os.rename deleting an existing destination when the source is missing, preserving destination data on this failure path.
Changes:
- Checks source existence before deleting the destination and removes the redundant post-move deletion.
- Adds regression tests for destination preservation through both filesystem and Lua APIs.
- Restores the previously skipped block of
files.luaassertions.
| File | Description |
|---|---|
| tests/Lua.Tests/LuaTests.cs | Removes the harness override that skipped the affected assertions. |
| tests/Lua.Tests/IOTests.cs | Adds missing-source rename regression tests for both entry points. |
| src/Lua/IO/FileSystem.cs | Validates source existence before destination deletion and removes redundant cleanup. |
Review effort: Balanced
|
Thank you for finding and fixing this data-loss bug, adding regression tests, and restoring the files.lua assertions! Your original commit has been merged through #368 with its authorship preserved. During review we added follow-up hardening for other rename failures, including a locked source on Windows and directory-to-file attempts. The implementation now replaces the destination through filesystem operations instead of deleting it before the move, with a compatible path for .NET Standard 2.1 and coverage for directory renames. The combined changes passed local tests and Linux CI. |
os.rename(old, new)deletednewbefore checking thatoldexists. With a missing source it returnednil, errorbut the destination file was already gone.FileSystem.Renamenow checks the source first, then deletes the destination, then moves.os.renamewith a missing source returnsnil, "...: No such file or directory"and leaves the destination alone, as in C Lua.This is also why
tests-lua/files.luaneeded thePatchFilesLuaSourcepatch ("UTF-16 text-mode" block): the failing assertion atfiles.lua:129was this bug, not an encoding issue. The patch is removed andfiles.luaruns unmodified.Verification
FileSystem_Rename_MissingSource_KeepsDestinationandOsRename_MissingSource_ReturnsNilAndKeepsDestinationfail onmainand pass with the change.dotnet test tests/Lua.Tests/Lua.Tests.csproj -c Release --filter "TestCategory!=ExpectedFailure": 612 passed, 0 failed (610 onmain+ 2 new).dotnet csharpier check .is clean.