Skip to content

Commit

Permalink
Watch.zig: refactor; simplifies error management
Browse files Browse the repository at this point in the history
  • Loading branch information
jayrod246 committed Jul 23, 2024
1 parent 6070094 commit 91b02c0
Showing 1 changed file with 69 additions and 73 deletions.
142 changes: 69 additions & 73 deletions lib/std/Build/Watch.zig
Original file line number Diff line number Diff line change
Expand Up @@ -307,26 +307,82 @@ const Os = switch (builtin.os.tag) {
return self.overlapped.hEvent.?;
}

fn init(gpa: Allocator, handle: windows.HANDLE, id: FileId) !*@This() {
const event = try windows.CreateEventExW(
fn init(gpa: Allocator, path: Cache.Path) !*@This() {
// The following code is a drawn out NtCreateFile call. (mostly adapted from std.fs.Dir.makeOpenDirAccessMaskW)
// It's necessary in order to get the flags are required when calling ReadDirectoryChangesW.
var dir_handle: windows.HANDLE = undefined;
{
const root_fd = path.root_dir.handle.fd;
const sub_path = path.subPathOrDot();
const sub_path_w = try windows.sliceToPrefixedFileW(root_fd, sub_path);
const path_len_bytes = std.math.cast(u16, sub_path_w.len * 2) orelse return error.NameTooLong;

var nt_name = windows.UNICODE_STRING{
.Length = @intCast(path_len_bytes),
.MaximumLength = @intCast(path_len_bytes),
.Buffer = @constCast(sub_path_w.span().ptr),
};
var attr = windows.OBJECT_ATTRIBUTES{
.Length = @sizeOf(windows.OBJECT_ATTRIBUTES),
.RootDirectory = if (std.fs.path.isAbsoluteWindowsW(sub_path_w.span())) null else root_fd,
.Attributes = 0, // Note we do not use OBJ_CASE_INSENSITIVE here.
.ObjectName = &nt_name,
.SecurityDescriptor = null,
.SecurityQualityOfService = null,
};
var io: windows.IO_STATUS_BLOCK = undefined;
const rc = windows.ntdll.NtCreateFile(
&dir_handle,
windows.SYNCHRONIZE | windows.GENERIC_READ | windows.FILE_LIST_DIRECTORY,
&attr,
&io,
null,
0,
windows.FILE_SHARE_READ | windows.FILE_SHARE_WRITE | windows.FILE_SHARE_DELETE,
windows.FILE_OPEN,
windows.FILE_DIRECTORY_FILE | windows.FILE_OPEN_FOR_BACKUP_INTENT,
null,
0,
);

switch (rc) {
.SUCCESS => {},
.OBJECT_NAME_INVALID => return error.BadPathName,
.OBJECT_NAME_NOT_FOUND => return error.FileNotFound,
.OBJECT_NAME_COLLISION => return error.PathAlreadyExists,
.OBJECT_PATH_NOT_FOUND => return error.FileNotFound,
.NOT_A_DIRECTORY => return error.NotDir,
// This can happen if the directory has 'List folder contents' permission set to 'Deny'
.ACCESS_DENIED => return error.AccessDenied,
.INVALID_PARAMETER => unreachable,
else => return windows.unexpectedStatus(rc),
}
}
assert(dir_handle != windows.INVALID_HANDLE_VALUE);
errdefer windows.CloseHandle(dir_handle);

const dir_id = try getFileId(dir_handle);

const wait_handle = try windows.CreateEventExW(
null,
null,
windows.CREATE_EVENT_MANUAL_RESET,
windows.EVENT_ALL_ACCESS,
);
errdefer windows.CloseHandle(wait_handle);

const result = try gpa.create(@This());
result.* = .{
.handle = handle,
.id = id,
const dir_ptr = try gpa.create(@This());
dir_ptr.* = .{
.handle = dir_handle,
.id = dir_id,
.overlapped = std.mem.zeroInit(
windows.OVERLAPPED,
.{
.hEvent = event,
.hEvent = wait_handle,
},
),
};
return result;
return dir_ptr;
}

fn deinit(self: *@This(), gpa: Allocator) void {
Expand Down Expand Up @@ -407,81 +463,21 @@ const Os = switch (builtin.os.tag) {
const reaction_set = rs: {
const gop = try w.dir_table.getOrPut(gpa, path);
if (!gop.found_existing) {
// The following code is a drawn out NtCreateFile call. (mostly adapted from std.fs.Dir.makeOpenDirAccessMaskW)
// It's necessary in order to get the flags are required when calling ReadDirectoryChangesW.
var dir_handle: windows.HANDLE = undefined;
{
const root_fd = path.root_dir.handle.fd;
const sub_path = path.subPathOrDot();
const sub_path_w = try windows.sliceToPrefixedFileW(root_fd, sub_path);
const path_len_bytes = std.math.cast(u16, sub_path_w.len * 2) orelse return error.NameTooLong;

var nt_name = windows.UNICODE_STRING{
.Length = @intCast(path_len_bytes),
.MaximumLength = @intCast(path_len_bytes),
.Buffer = @constCast(sub_path_w.span().ptr),
};
var attr = windows.OBJECT_ATTRIBUTES{
.Length = @sizeOf(windows.OBJECT_ATTRIBUTES),
.RootDirectory = if (std.fs.path.isAbsoluteWindowsW(sub_path_w.span())) null else root_fd,
.Attributes = 0, // Note we do not use OBJ_CASE_INSENSITIVE here.
.ObjectName = &nt_name,
.SecurityDescriptor = null,
.SecurityQualityOfService = null,
};
var io: windows.IO_STATUS_BLOCK = undefined;
const rc = windows.ntdll.NtCreateFile(
&dir_handle,
windows.SYNCHRONIZE | windows.GENERIC_READ | windows.FILE_LIST_DIRECTORY,
&attr,
&io,
null,
0,
windows.FILE_SHARE_READ | windows.FILE_SHARE_WRITE | windows.FILE_SHARE_DELETE,
windows.FILE_OPEN,
windows.FILE_DIRECTORY_FILE | windows.FILE_OPEN_FOR_BACKUP_INTENT,
null,
0,
);

switch (rc) {
.SUCCESS => {},
.OBJECT_NAME_INVALID => return error.BadPathName,
.OBJECT_NAME_NOT_FOUND => return error.FileNotFound,
.OBJECT_NAME_COLLISION => return error.PathAlreadyExists,
.OBJECT_PATH_NOT_FOUND => return error.FileNotFound,
.NOT_A_DIRECTORY => return error.NotDir,
// This can happen if the directory has 'List folder contents' permission set to 'Deny'
.ACCESS_DENIED => return error.AccessDenied,
.INVALID_PARAMETER => unreachable,
else => return windows.unexpectedStatus(rc),
}
assert(dir_handle != windows.INVALID_HANDLE_VALUE);
}

const dir_id = getFileId(dir_handle) catch |err| {
windows.CloseHandle(dir_handle);
return err;
};

// `dir_id` may already be present in the table in
const dir = try Os.Directory.init(gpa, path);
errdefer dir.deinit(gpa);
// `dir.id` may already be present in the table in
// the case that we have multiple Cache.Path instances
// that compare inequal but ultimately point to the same
// directory on the file system.
// In such case, we must revert adding this directory, but keep
// the additions to the step set.
const dh_gop = w.os.handle_table.getOrPut(gpa, dir_id) catch |err| {
windows.CloseHandle(dir_handle);
return err;
};
const dh_gop = try w.os.handle_table.getOrPut(gpa, dir.id);
if (dh_gop.found_existing) {
windows.CloseHandle(dir_handle);
dir.deinit(gpa);
_ = w.dir_table.pop();
} else {
assert(dh_gop.index == gop.index);
dh_gop.value_ptr.* = .{};
const dir = try Os.Directory.init(gpa, dir_handle, dir_id);
errdefer dir.deinit(gpa);
try dir.readChanges();
try w.os.handle_extra.insert(gpa, dh_gop.index, .{
.dir = dir,
Expand Down

0 comments on commit 91b02c0

Please sign in to comment.