5477
5478
5479
5480
5481
5482
5483
5484
5485
5486
5487
5488
5489
5490
5491
5492
5493
5494
5495
5496
5497
5498
5499
5500
5501
5502
5503
5504
5505
5506
5507
5508
5509
5510
5511
5512
5513
5514
5515
5516
5517
5518
5519
5520
5521
5522
5523
5524
5525
5526
5527
5528
5529
5530
5531
5532
5533
5534
5535
5536
5537
5538
5539
5540
5541
5542
pub fn dirOpenDirWindows(
dir: Dir,
sub_path_w: []const u16,
options: Dir.OpenOptions,
) Dir.OpenError!Dir {
const w = windows;
var io_status_block: w.IO_STATUS_BLOCK = undefined;
var result: Dir = .{ .handle = undefined };
const attr: w.OBJECT.ATTRIBUTES = .{
.RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w)) null else dir.handle,
.ObjectName = @constCast(&w.UNICODE_STRING.init(sub_path_w)),
};
const syscall: Syscall = try .start();
while (true) switch (w.ntdll.NtCreateFile(
&result.handle,
// TODO remove some of these flags if options.access_sub_paths is false
.{
.SPECIFIC = .{ .FILE_DIRECTORY = .{
.LIST = options.iterate,
.READ_EA = true,
.TRAVERSE = true,
.READ_ATTRIBUTES = true,
} },
.STANDARD = .{
.RIGHTS = .READ,
.SYNCHRONIZE = true,
},
},
&attr,
&io_status_block,
null,
.{ .NORMAL = true },
.VALID_FLAGS,
.OPEN,
.{
.DIRECTORY_FILE = true,
.IO = .SYNCHRONOUS_NONALERT,
.OPEN_FOR_BACKUP_INTENT = true,
.OPEN_REPARSE_POINT = !options.follow_symlinks,
},
null,
0,
)) {
.SUCCESS => {
syscall.finish();
return result;
},
.CANCELLED => {
try syscall.checkCancel();
continue;
},
.OBJECT_NAME_INVALID => return syscall.fail(error.BadPathName),
.OBJECT_NAME_NOT_FOUND => return syscall.fail(error.FileNotFound),
.OBJECT_NAME_COLLISION => |err| return w.statusBug(err),
.OBJECT_PATH_NOT_FOUND => return syscall.fail(error.FileNotFound),
.NOT_A_DIRECTORY => return syscall.fail(error.NotDir),
// This can happen if the directory has 'List folder contents' permission set to 'Deny'
// and the directory is trying to be opened for iteration.
.ACCESS_DENIED => return syscall.fail(error.AccessDenied),
.INVALID_PARAMETER => |err| return syscall.ntstatusBug(err),
else => |rc| return syscall.unexpectedNtstatus(rc),
};
}