Skip to content

Commit dd56ae9

Browse files
committed
Fix Sys.rename under Windows
1 parent f9ad3ac commit dd56ae9

File tree

2 files changed

+50
-29
lines changed

2 files changed

+50
-29
lines changed

runtime/js/fs_node.js

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -144,33 +144,29 @@ if (globalThis.process?.platform === "win32") {
144144
try {
145145
var target = this.nm(n);
146146
var source = this.nm(o);
147-
var target_stats = this.fs.existsSync(target)
148-
? this.fs.statSync(target)
149-
: null;
150-
var source_stats = this.fs.existsSync(source)
151-
? this.fs.statSync(source)
152-
: null;
147+
var target_stats, source_stats;
153148
if (
154-
source_stats &&
155-
source_stats.isDirectory() &&
156-
target_stats &&
157-
!target_stats.isDirectory()
149+
(target_stats = this.fs.statSync(target, { throwIfNoEntry: 0 })) &&
150+
(source_stats = this.fs.statSync(source, { throwIfNoEntry: 0 })) &&
151+
source_stats.isDirectory()
158152
) {
159-
var err = new Error("rename");
160-
err.code = 26;
161-
err.path = n;
162-
this.raise_nodejs_error(err, raise_unix);
153+
if (target_stats.isDirectory()) {
154+
if (!target.startsWith(source))
155+
try {
156+
this.fs.rmdirSync(target);
157+
} catch {}
158+
} else {
159+
var err = new Error(
160+
`ENOTDIR: not a directory, rename '${source}' -> '${target}'`,
161+
);
162+
throw Object.assign(err, {
163+
errno: -20,
164+
code: "ENOTDIR",
165+
syscall: "rename",
166+
path: target,
167+
});
168+
}
163169
}
164-
if (
165-
source_stats &&
166-
source_stats.isDirectory() &&
167-
target_stats &&
168-
target_stats.isDirectory() &&
169-
!target.startsWith(source)
170-
)
171-
try {
172-
this.fs.rmdirSync(target);
173-
} catch {}
174170
this.fs.renameSync(this.nm(o), this.nm(n));
175171
} catch (err) {
176172
this.raise_nodejs_error(err, raise_unix);

runtime/wasm/runtime.js

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@
135135
return h ^ s.length;
136136
}
137137

138+
const on_windows = isNode && process.platform === "win32";
138139
const bindings = {
139140
jstag:
140141
WebAssembly.JSTag ||
@@ -398,7 +399,7 @@
398399
channel_list,
399400
exit: (n) => isNode && process.exit(n),
400401
argv: () => (isNode ? process.argv.slice(1) : ["a.out"]),
401-
on_windows: () => isNode && process.platform === "win32",
402+
on_windows: () => on_windows,
402403
getenv: (n) => (isNode ? process.env[n] : null),
403404
system: (c) => {
404405
var res = require("node:child_process").spawnSync(c, {
@@ -417,7 +418,32 @@
417418
readdir: (p) => fs.readdirSync(p),
418419
file_exists: (p) => +fs.existsSync(p),
419420
is_directory: (p) => +fs.lstatSync(p).isDirectory(),
420-
rename: (o, n) => fs.renameSync(o, n),
421+
rename: (o, n) => {
422+
var n_stat;
423+
if (
424+
on_windows &&
425+
(n_stat = fs.statSync(n, { throwIfNoEntry: 0 })) &&
426+
fs.statSync(o, { throwIfNoEntry: 0 })?.isDirectory()
427+
) {
428+
if (n_stat.isDirectory()) {
429+
if (!n.startsWith(o))
430+
try {
431+
fs.rmdirSync(target);
432+
} catch {}
433+
} else {
434+
var e = new Error(
435+
`ENOTDIR: not a directory, rename '${o}' -> '${n}'`,
436+
);
437+
throw Object.assign(e, {
438+
errno: -20,
439+
code: "ENOTDIR",
440+
syscall: "rename",
441+
path: n,
442+
});
443+
}
444+
}
445+
fs.renameSync(o, n);
446+
},
421447
throw: (e) => {
422448
throw e;
423449
},
@@ -529,9 +555,8 @@
529555

530556
start_fiber = make_promising(caml_start_fiber);
531557
var _initialize = make_promising(_initialize);
532-
var process = globalThis.process;
533-
if (process && process.on) {
534-
process.on("uncaughtException", (err, origin) =>
558+
if (globalThis.process && globalThis.process.on) {
559+
globalThis.process.on("uncaughtException", (err, origin) =>
535560
caml_handle_uncaught_exception(err),
536561
);
537562
} else if (globalThis.addEventListener) {

0 commit comments

Comments
 (0)