@@ -83,8 +83,23 @@ CAMLprim value caml_eio_windows_pwritev(value v_fd, value v_bufs, value v_offset
8383
8484// File-system operations
8585
86+ // No follow
87+ void no_follow (HANDLE h ) {
88+ BY_HANDLE_FILE_INFORMATION b ;
89+
90+ if (!GetFileInformationByHandle (h , & b )) {
91+ caml_win32_maperr (GetLastError ());
92+ uerror ("nofollow" , Nothing );
93+ }
94+
95+ if (b .dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT ) {
96+ CloseHandle (h );
97+ caml_unix_error (ELOOP , "nofollow" , Nothing );
98+ }
99+ }
100+
86101// We recreate an openat like function using NtCreateFile
87- CAMLprim value caml_eio_windows_openat (value v_dirfd , value v_pathname , value v_desired_access , value v_create_disposition , value v_create_options )
102+ CAMLprim value caml_eio_windows_openat (value v_dirfd , value v_nofollow , value v_pathname , value v_desired_access , value v_create_disposition , value v_create_options )
88103{
89104 CAMLparam2 (v_dirfd , v_pathname );
90105 HANDLE h , dir ;
@@ -121,14 +136,17 @@ CAMLprim value caml_eio_windows_openat(value v_dirfd, value v_pathname, value v_
121136 // Create the file
122137 r = NtCreatefile (
123138 & h ,
124- Int_val (v_desired_access ),
139+ Int_val (v_desired_access ) | FILE_READ_ATTRIBUTES ,
125140 & obj_attr ,
126141 & io_status ,
127142 0 , // Allocation size
128143 FILE_ATTRIBUTE_NORMAL , // TODO: Could check flags to see if we can do READONLY here a la OCaml
129144 (FILE_SHARE_READ | FILE_SHARE_WRITE ),
130145 Int_val (v_create_disposition ),
131- (Int_val (v_create_options ) | FILE_SYNCHRONOUS_IO_NONALERT ),
146+ (
147+ FILE_SYNCHRONOUS_IO_NONALERT
148+ | FILE_OPEN_FOR_BACKUP_INTENT
149+ | (Bool_val (v_nofollow ) ? FILE_FLAG_OPEN_REPARSE_POINT : Int_val (v_create_options ))),
132150 NULL , // Extended attribute buffer
133151 0 // Extended attribute buffer length
134152 );
@@ -138,17 +156,28 @@ CAMLprim value caml_eio_windows_openat(value v_dirfd, value v_pathname, value v_
138156
139157 if (h == INVALID_HANDLE_VALUE ) {
140158 caml_win32_maperr (RtlNtStatusToDosError (r ));
141- uerror ("openat" , v_pathname );
159+ uerror ("openat handle " , v_pathname );
142160 }
143161
144- if (!NT_SUCCESS (r )) {
162+ if (!NT_SUCCESS (r )) {
145163 caml_win32_maperr (RtlNtStatusToDosError (r ));
146164 uerror ("openat" , Nothing );
147165 }
166+
167+ // No follow check -- Windows doesn't actually have that ability
168+ // so we have to do it after the fact. This will raise if a symbolic
169+ // link is encountered and will close the handle.
170+ if (Bool_val (v_nofollow )) {
171+ no_follow (h );
172+ }
148173
149174 CAMLreturn (caml_win32_alloc_handle (h ));
150175}
151176
177+ value caml_eio_windows_openat_bytes (value * values , int argc ) {
178+ return caml_eio_windows_openat (values [0 ], values [1 ], values [2 ], values [3 ], values [4 ], values [5 ]);
179+ }
180+
152181CAMLprim value caml_eio_windows_unlinkat (value v_dirfd , value v_pathname , value v_dir )
153182{
154183 CAMLparam2 (v_dirfd , v_pathname );
0 commit comments