-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Unix.utimes on a missing file results in EUKNOWNERR instead of ENOENT on Win32 #8857
Description
I believe this is caused by this code
ocaml/otherlibs/win32unix/utimes.c
Lines 54 to 66 in 301e1e6
| hFile = CreateFile(wpath, | |
| FILE_WRITE_ATTRIBUTES, | |
| FILE_SHARE_READ | FILE_SHARE_WRITE, | |
| NULL, | |
| OPEN_EXISTING, | |
| 0, | |
| NULL); | |
| caml_leave_blocking_section(); | |
| caml_stat_free(wpath); | |
| if (hFile == INVALID_HANDLE_VALUE) { | |
| win32_maperr(GetLastError()); | |
| uerror("utimes", path); | |
| } |
As you can see, caml_leave_blocking_section is called after CreateFile, but before GetLastError.
caml_leave_blocking_section preserves errno, but not the Win32 error code accessed by GetLastError/SetLastError:
Lines 177 to 182 in 301e1e6
| CAMLexport void caml_leave_blocking_section(void) | |
| { | |
| int saved_errno; | |
| /* Save the value of errno (PR#5982). */ | |
| saved_errno = errno; | |
| caml_leave_blocking_section_hook (); |
caml_leave_blocking_section_hook calls st_tls_get:
ocaml/otherlibs/systhreads/st_stubs.c
Lines 245 to 254 in 301e1e6
| static void caml_thread_leave_blocking_section(void) | |
| { | |
| /* Wait until the runtime is free */ | |
| st_masterlock_acquire(&caml_master_lock); | |
| /* Update curr_thread to point to the thread descriptor corresponding | |
| to the thread currently executing */ | |
| curr_thread = st_tls_get(thread_descriptor_key); | |
| /* Restore the runtime state from the curr_thread descriptor */ | |
| caml_thread_restore_runtime_state(); | |
| } |
On Windows, this calls TlsGetValue:
ocaml/otherlibs/systhreads/st_win32.h
Lines 115 to 118 in 301e1e6
| static INLINE void * st_tls_get(st_tlskey k) | |
| { | |
| return TlsGetValue(k); | |
| } |
TlsGetValue clobbers the error code that would be returned by GetLastError.
cc @dra27