fix(jsonl): bind MoveFileExW with the Win32 BOOL ABI

Declare MoveFileExW's return value as Koffi int and model it as a numeric 32-bit Win32 BOOL. The previous Koffi bool declaration represented a one-byte C boolean and could read the native return register with the wrong ABI.

Test zero and nonzero results explicitly and assert the binding result type while preserving the existing write-through flags, error translation, and durable directory race behavior.
This commit is contained in:
Tianyi Cui
2026-07-19 12:44:47 +08:00
parent 3dc82b1e87
commit 4bf2ef89c4
2 changed files with 15 additions and 14 deletions

View File

@@ -14,7 +14,7 @@
import { mkdtemp, rm, stat } from 'node:fs/promises'
import { basename, join, parse, resolve, toNamespacedPath } from 'node:path'
type MoveFileExW = (existing: string, replacement: string, flags: number) => boolean
type MoveFileExW = (existing: string, replacement: string, flags: number) => number
type GetLastError = () => number
interface Win32Bindings {
@@ -44,7 +44,7 @@ async function win32(): Promise<Win32Bindings> {
const koffi = (await import('koffi')).default
const kernel32 = koffi.load('kernel32.dll')
bindings = {
moveFileExW: kernel32.func('__stdcall', 'MoveFileExW', 'bool', ['str16', 'str16', 'uint']) as MoveFileExW,
moveFileExW: kernel32.func('__stdcall', 'MoveFileExW', 'int', ['str16', 'str16', 'uint']) as MoveFileExW,
getLastError: kernel32.func('__stdcall', 'GetLastError', 'uint', []) as GetLastError,
}
return bindings
@@ -113,7 +113,7 @@ async function assertDirectory(path: string): Promise<boolean> {
export async function publishNewFileWin32(existing: string, replacement: string): Promise<void> {
const api = await win32()
const ok = api.moveFileExW(toNamespacedPath(existing), toNamespacedPath(replacement), MOVEFILE_WRITE_THROUGH)
if (!ok) throw win32Error('MoveFileExW', api.getLastError(), existing, replacement)
if (ok === 0) throw win32Error('MoveFileExW', api.getLastError(), existing, replacement)
}
/**

View File

@@ -19,7 +19,7 @@ const ERROR_FILE_EXISTS = 80
const ERROR_INVALID_NAME = 123
const ERROR_ALREADY_EXISTS = 183
type MoveFileExW = (existing: string, replacement: string, flags: number, setLastError: (code: number) => void) => boolean
type MoveFileExW = (existing: string, replacement: string, flags: number, setLastError: (code: number) => void) => number
const roots: string[] = []
@@ -42,14 +42,15 @@ async function importWithMove(moveFileExW: MoveFileExW): Promise<typeof import('
const setLastError = (code: number): void => { lastError = code }
const move: MoveFileExW = (existing, replacement, flags, setError) => {
const ok = moveFileExW(existing, replacement, flags, setError)
lastError = ok ? 0 : lastError
lastError = ok === 0 ? lastError : 0
return ok
}
return {
default: {
load: () => ({
func: (_convention: string, name: string) => {
func: (_convention: string, name: string, result: string) => {
if (name === 'MoveFileExW') return (existing: string, replacement: string, flags: number) => {
expect(result).toBe('int')
const ok = move(existing, replacement, flags, setLastError)
return ok
}
@@ -68,7 +69,7 @@ async function importWithError(code: number): Promise<typeof import('../src/win3
default: {
load: () => ({
func: (_convention: string, name: string) => {
if (name === 'MoveFileExW') return () => false
if (name === 'MoveFileExW') return () => 0
return () => code
},
}),
@@ -82,10 +83,10 @@ async function importWithFilesystemMove(): Promise<typeof import('../src/win32.t
expect(flags).toBe(MOVEFILE_WRITE_THROUGH)
const from = stripNamespace(existing)
const to = stripNamespace(replacement)
if (!existsSync(from)) { setLastError(ERROR_FILE_NOT_FOUND); return false }
if (existsSync(to)) { setLastError(ERROR_ALREADY_EXISTS); return false }
if (!existsSync(from)) { setLastError(ERROR_FILE_NOT_FOUND); return 0 }
if (existsSync(to)) { setLastError(ERROR_ALREADY_EXISTS); return 0 }
renameSync(from, to)
return true
return 1
})
}
@@ -135,12 +136,12 @@ describe('Windows durable namespace helpers', () => {
if (to === raced) {
mkdirSync(to)
setLastError(ERROR_ALREADY_EXISTS)
return false
return 0
}
if (!existsSync(from)) { setLastError(ERROR_FILE_NOT_FOUND); return false }
if (existsSync(to)) { setLastError(ERROR_ALREADY_EXISTS); return false }
if (!existsSync(from)) { setLastError(ERROR_FILE_NOT_FOUND); return 0 }
if (existsSync(to)) { setLastError(ERROR_ALREADY_EXISTS); return 0 }
renameSync(from, to)
return true
return 1
})
await ensureDurableDirectoryWin32(join(root, 'a', 'b'))