feature. See also
. The project being documented here (as the example) is the Zig library itself.
Threaded.dirOpenFileWtf16
pub fn dirOpenFileWtf16(
dir_handle: ?windows.HANDLE,
sub_path_w: []const u16,
flags: Dir.OpenFileOptions,
) File.OpenError!File
File
Code
pub fn dirOpenFileWtf16(
dir_handle: ?windows.HANDLE,
sub_path_w: []const u16,
flags: Dir.OpenFileOptions,
) File.OpenError!File {
const allow_directory = flags.allow_directory and !flags.isWrite();
if (!allow_directory and std.mem.eql(u16, sub_path_w, &.{'.'})) return error.IsDir;
if (!allow_directory and std.mem.eql(u16, sub_path_w, &.{ '.', '.' })) return error.IsDir;
const w = windows;
var io_status_block: w.IO_STATUS_BLOCK = undefined;
var attempt: u5 = 0;
var syscall: Syscall = try .start();
const handle = while (true) {
var result: w.HANDLE = undefined;
switch (w.ntdll.NtCreateFile(
&result,
.{
.STANDARD = .{ .SYNCHRONIZE = true },
.GENERIC = .{
.READ = flags.isRead(),
.WRITE = flags.isWrite(),
},
},
&.{
.RootDirectory = dir_handle,
.ObjectName = @constCast(&w.UNICODE_STRING.init(sub_path_w)),
},
&io_status_block,
null,
.{ .NORMAL = true },
.VALID_FLAGS,
.OPEN,
.{
.IO = .SYNCHRONOUS_NONALERT,
.NON_DIRECTORY_FILE = !allow_directory,
.OPEN_REPARSE_POINT = !flags.follow_symlinks,
},
null,
0,
)) {
.SUCCESS => {
syscall.finish();
break result;
},
.OBJECT_NAME_INVALID => return syscall.fail(error.BadPathName),
.OBJECT_NAME_NOT_FOUND => return syscall.fail(error.FileNotFound),
.OBJECT_PATH_NOT_FOUND => return syscall.fail(error.FileNotFound),
.BAD_NETWORK_PATH => return syscall.fail(error.NetworkNotFound),
.BAD_NETWORK_NAME => return syscall.fail(error.NetworkNotFound),
.NO_MEDIA_IN_DEVICE => return syscall.fail(error.NoDevice),
.INVALID_PARAMETER => |err| return syscall.ntstatusBug(err),
.CANCELLED => {
try syscall.checkCancel();
continue;
},
.SHARING_VIOLATION => {
// executable. However, there's a kernel bug: the error may be
// incorrectly returned for an indeterminate amount of time
// after an executable file is closed. Here we work around the
// kernel bug with retry attempts.
syscall.finish();
if (max_windows_kernel_bug_retries - attempt == 0) return error.FileBusy;
try parking_sleep.sleep(.{ .duration = .{
.raw = .fromMilliseconds((@as(u32, 1) << attempt) >> 1),
.clock = .awake,
} });
attempt += 1;
syscall = try .start();
continue;
},
.ACCESS_DENIED => return syscall.fail(error.AccessDenied),
.PIPE_BUSY => return syscall.fail(error.PipeBusy),
.PIPE_NOT_AVAILABLE => return syscall.fail(error.NoDevice),
.OBJECT_PATH_SYNTAX_BAD => |err| return syscall.ntstatusBug(err),
.OBJECT_NAME_COLLISION => return syscall.fail(error.PathAlreadyExists),
.FILE_IS_A_DIRECTORY => return syscall.fail(error.IsDir),
.NOT_A_DIRECTORY => return syscall.fail(error.NotDir),
.USER_MAPPED_FILE => return syscall.fail(error.AccessDenied),
.INVALID_HANDLE => |err| return syscall.ntstatusBug(err),
.DELETE_PENDING => {
// the file system, but it was deleted. However, the OS is not
// finished with the deletion operation, and so this CreateFile
// call has failed. Here, we simulate the kernel bug being
// fixed by sleeping and retrying until the error goes away.
syscall.finish();
if (max_windows_kernel_bug_retries - attempt == 0) return error.FileBusy;
try parking_sleep.sleep(.{ .duration = .{
.raw = .fromMilliseconds((@as(u32, 1) << attempt) >> 1),
.clock = .awake,
} });
attempt += 1;
syscall = try .start();
continue;
},
.VIRUS_INFECTED, .VIRUS_DELETED => return syscall.fail(error.AntivirusInterference),
else => |rc| return syscall.unexpectedNtstatus(rc),
}
};
errdefer w.CloseHandle(handle);
const exclusive = switch (flags.lock) {
.none => return .{
.handle = handle,
.flags = .{ .nonblocking = false },
},
.shared => false,
.exclusive => true,
};
syscall = try .start();
while (true) switch (w.ntdll.NtLockFile(
handle,
null,
null,
null,
&io_status_block,
&windows_lock_range_off,
&windows_lock_range_len,
null,
.fromBool(flags.lock_nonblocking),
.fromBool(exclusive),
)) {
.SUCCESS => break syscall.finish(),
.INSUFFICIENT_RESOURCES => return syscall.fail(error.SystemResources),
.LOCK_NOT_GRANTED => return syscall.fail(error.WouldBlock),
.ACCESS_VIOLATION => |err| return syscall.ntstatusBug(err),
else => |status| return syscall.unexpectedNtstatus(status),
};
return .{
.handle = handle,
.flags = .{ .nonblocking = false },
};
}