@@ -340,19 +340,55 @@ const Os = switch (builtin.os.tag) {
340
340
const reaction_set = rs : {
341
341
const gop = try w .dir_table .getOrPut (gpa , path );
342
342
if (! gop .found_existing ) {
343
- var realpath_buf : [std .fs .max_path_bytes ]u8 = undefined ;
344
- const realpath = try path .root_dir .handle .realpath (path .sub_path , & realpath_buf );
345
- const realpath_w = try windows .sliceToPrefixedFileW (null , realpath );
346
- const dir_handle = windows .kernel32 .CreateFileW (
347
- realpath_w .span ().ptr ,
348
- windows .GENERIC_READ ,
349
- windows .FILE_SHARE_DELETE | windows .FILE_SHARE_READ | windows .FILE_SHARE_WRITE ,
343
+ // The following code is a drawn out NtCreateFile call. (mostly adapted from std.fs.Dir.makeOpenDirAccessMaskW)
344
+ // It's necessary in order to get the flags are required when calling ReadDirectoryChangesW.
345
+ const root_fd = path .root_dir .handle .fd ;
346
+ const sub_path = path .subPathOrDot ();
347
+ const sub_path_w = try windows .sliceToPrefixedFileW (root_fd , sub_path );
348
+ const path_len_bytes = std .math .cast (u16 , sub_path_w .len * 2 ) orelse return error .NameTooLong ;
349
+
350
+ var nt_name = windows.UNICODE_STRING {
351
+ .Length = @intCast (path_len_bytes ),
352
+ .MaximumLength = @intCast (path_len_bytes ),
353
+ .Buffer = @constCast (sub_path_w .span ().ptr ),
354
+ };
355
+ var attr = windows.OBJECT_ATTRIBUTES {
356
+ .Length = @sizeOf (windows .OBJECT_ATTRIBUTES ),
357
+ .RootDirectory = if (std .fs .path .isAbsoluteWindowsW (sub_path_w .span ())) null else root_fd ,
358
+ .Attributes = 0 , // Note we do not use OBJ_CASE_INSENSITIVE here.
359
+ .ObjectName = & nt_name ,
360
+ .SecurityDescriptor = null ,
361
+ .SecurityQualityOfService = null ,
362
+ };
363
+ var io : windows.IO_STATUS_BLOCK = undefined ;
364
+ var dir_handle : windows.HANDLE = undefined ;
365
+ const rc = windows .ntdll .NtCreateFile (
366
+ & dir_handle ,
367
+ windows .SYNCHRONIZE | windows .GENERIC_READ | windows .FILE_LIST_DIRECTORY ,
368
+ & attr ,
369
+ & io ,
350
370
null ,
351
- windows .OPEN_EXISTING ,
352
- windows .FILE_FLAG_BACKUP_SEMANTICS | windows .FILE_FLAG_OVERLAPPED ,
371
+ 0 ,
372
+ windows .FILE_SHARE_READ | windows .FILE_SHARE_WRITE | windows .FILE_SHARE_DELETE ,
373
+ windows .FILE_OPEN ,
374
+ windows .FILE_DIRECTORY_FILE | windows .FILE_OPEN_FOR_BACKUP_INTENT ,
353
375
null ,
376
+ 0 ,
354
377
);
355
378
379
+ switch (rc ) {
380
+ .SUCCESS = > {},
381
+ .OBJECT_NAME_INVALID = > return error .BadPathName ,
382
+ .OBJECT_NAME_NOT_FOUND = > return error .FileNotFound ,
383
+ .OBJECT_NAME_COLLISION = > return error .PathAlreadyExists ,
384
+ .OBJECT_PATH_NOT_FOUND = > return error .FileNotFound ,
385
+ .NOT_A_DIRECTORY = > return error .NotDir ,
386
+ // This can happen if the directory has 'List folder contents' permission set to 'Deny'
387
+ .ACCESS_DENIED = > return error .AccessDenied ,
388
+ .INVALID_PARAMETER = > unreachable ,
389
+ else = > return windows .unexpectedStatus (rc ),
390
+ }
391
+
356
392
assert (dir_handle != windows .INVALID_HANDLE_VALUE );
357
393
358
394
// `dir_handle` may already be present in the table in
0 commit comments