fix(windows): Fs.remove removes an empty directory, as POSIX remove does
The UCRT's remove() deletes files only, so a tree removed bottom-up left every
directory behind. emit_win defines remove over DeleteFileA, falling back to
RemoveDirectoryA. Found by Maroon Lake's selftest26 ("1 left behind"), which now
passes on Windows with the rest of that game's self-tests.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
cb05721a89
commit
1bc255bc40
3 changed files with 13458 additions and 13433 deletions
|
|
@ -91,8 +91,8 @@ function emit_mime_ns(meth: pointer, e: Node) -> Val {
|
|||
# emit_fs_prelude — the Fs/Path/Mime runtime, emitted once per program that uses
|
||||
# any of the three namespaces (g_uses_fsrt). Pure libc + byte IR.
|
||||
function emit_fs_prelude() -> void {
|
||||
emith("declare i32 @remove(ptr)\n")
|
||||
if not g_target_win { # defined by emit_win_prelude on Windows
|
||||
emith("declare i32 @remove(ptr)\n")
|
||||
emith("declare i32 @access(ptr, i32)\n")
|
||||
emith("declare i32 @mkdir(ptr, i32)\n")
|
||||
emith("declare i32 @rename(ptr, ptr)\n")
|
||||
|
|
|
|||
|
|
@ -55,6 +55,8 @@ function emit_win_prelude() -> void {
|
|||
emith("declare i32 @_open_osfhandle(i64, i32)\n")
|
||||
emith("declare ptr @_fdopen(i32, ptr)\n")
|
||||
emith("declare i32 @MoveFileExA(ptr, ptr, i32)\n")
|
||||
emith("declare i32 @DeleteFileA(ptr)\n")
|
||||
emith("declare i32 @RemoveDirectoryA(ptr)\n")
|
||||
emith("declare ptr @FindFirstFileA(ptr, ptr)\n")
|
||||
emith("declare i32 @FindNextFileA(ptr, ptr)\n")
|
||||
emith("declare i32 @FindClose(ptr)\n")
|
||||
|
|
@ -120,6 +122,15 @@ function emit_win_files() -> void {
|
|||
# rename over an existing file: MOVEFILE_REPLACE_EXISTING | COPY_ALLOWED | WRITE_THROUGH
|
||||
emith("define internal i32 @rename(ptr %a, ptr %b) {\nentry:\n %r = call i32 @MoveFileExA(ptr %a, ptr %b, i32 11)\n %ok = icmp ne i32 %r, 0\n %v = select i1 %ok, i32 0, i32 -1\n ret i32 %v\n}\n")
|
||||
|
||||
# remove: POSIX removes a file OR an empty directory; the UCRT's only removes files,
|
||||
# so a tree deleted bottom-up (Fs.remove on each file, then on each directory) left
|
||||
# every directory behind
|
||||
emith("define internal i32 @remove(ptr %p) {\n")
|
||||
emith("entry:\n %d = call i32 @DeleteFileA(ptr %p)\n %ok = icmp ne i32 %d, 0\n br i1 %ok, label %yes, label %dir\n")
|
||||
emith("dir:\n %r = call i32 @RemoveDirectoryA(ptr %p)\n %ok2 = icmp ne i32 %r, 0\n br i1 %ok2, label %yes, label %no\n")
|
||||
emith("yes:\n ret i32 0\n")
|
||||
emith("no:\n ret i32 -1\n}\n")
|
||||
|
||||
emith("define internal i32 @access(ptr %p, i32 %m) {\nentry:\n %r = call i32 @_access(ptr %p, i32 %m)\n ret i32 %r\n}\n")
|
||||
emith("define internal i32 @mkdir(ptr %p, i32 %mode) {\nentry:\n %r = call i32 @_mkdir(ptr %p)\n ret i32 %r\n}\n")
|
||||
# O_RDONLY is 0 on both; _O_BINARY = 0x8000
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue