Skip to content

Commit 91b02c0

Browse files
committed
Watch.zig: refactor; simplifies error management
1 parent 6070094 commit 91b02c0

File tree

1 file changed

+69
-73
lines changed

1 file changed

+69
-73
lines changed

lib/std/Build/Watch.zig

Lines changed: 69 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -307,26 +307,82 @@ const Os = switch (builtin.os.tag) {
307307
return self.overlapped.hEvent.?;
308308
}
309309

310-
fn init(gpa: Allocator, handle: windows.HANDLE, id: FileId) !*@This() {
311-
const event = try windows.CreateEventExW(
310+
fn init(gpa: Allocator, path: Cache.Path) !*@This() {
311+
// The following code is a drawn out NtCreateFile call. (mostly adapted from std.fs.Dir.makeOpenDirAccessMaskW)
312+
// It's necessary in order to get the flags are required when calling ReadDirectoryChangesW.
313+
var dir_handle: windows.HANDLE = undefined;
314+
{
315+
const root_fd = path.root_dir.handle.fd;
316+
const sub_path = path.subPathOrDot();
317+
const sub_path_w = try windows.sliceToPrefixedFileW(root_fd, sub_path);
318+
const path_len_bytes = std.math.cast(u16, sub_path_w.len * 2) orelse return error.NameTooLong;
319+
320+
var nt_name = windows.UNICODE_STRING{
321+
.Length = @intCast(path_len_bytes),
322+
.MaximumLength = @intCast(path_len_bytes),
323+
.Buffer = @constCast(sub_path_w.span().ptr),
324+
};
325+
var attr = windows.OBJECT_ATTRIBUTES{
326+
.Length = @sizeOf(windows.OBJECT_ATTRIBUTES),
327+
.RootDirectory = if (std.fs.path.isAbsoluteWindowsW(sub_path_w.span())) null else root_fd,
328+
.Attributes = 0, // Note we do not use OBJ_CASE_INSENSITIVE here.
329+
.ObjectName = &nt_name,
330+
.SecurityDescriptor = null,
331+
.SecurityQualityOfService = null,
332+
};
333+
var io: windows.IO_STATUS_BLOCK = undefined;
334+
const rc = windows.ntdll.NtCreateFile(
335+
&dir_handle,
336+
windows.SYNCHRONIZE | windows.GENERIC_READ | windows.FILE_LIST_DIRECTORY,
337+
&attr,
338+
&io,
339+
null,
340+
0,
341+
windows.FILE_SHARE_READ | windows.FILE_SHARE_WRITE | windows.FILE_SHARE_DELETE,
342+
windows.FILE_OPEN,
343+
windows.FILE_DIRECTORY_FILE | windows.FILE_OPEN_FOR_BACKUP_INTENT,
344+
null,
345+
0,
346+
);
347+
348+
switch (rc) {
349+
.SUCCESS => {},
350+
.OBJECT_NAME_INVALID => return error.BadPathName,
351+
.OBJECT_NAME_NOT_FOUND => return error.FileNotFound,
352+
.OBJECT_NAME_COLLISION => return error.PathAlreadyExists,
353+
.OBJECT_PATH_NOT_FOUND => return error.FileNotFound,
354+
.NOT_A_DIRECTORY => return error.NotDir,
355+
// This can happen if the directory has 'List folder contents' permission set to 'Deny'
356+
.ACCESS_DENIED => return error.AccessDenied,
357+
.INVALID_PARAMETER => unreachable,
358+
else => return windows.unexpectedStatus(rc),
359+
}
360+
}
361+
assert(dir_handle != windows.INVALID_HANDLE_VALUE);
362+
errdefer windows.CloseHandle(dir_handle);
363+
364+
const dir_id = try getFileId(dir_handle);
365+
366+
const wait_handle = try windows.CreateEventExW(
312367
null,
313368
null,
314369
windows.CREATE_EVENT_MANUAL_RESET,
315370
windows.EVENT_ALL_ACCESS,
316371
);
372+
errdefer windows.CloseHandle(wait_handle);
317373

318-
const result = try gpa.create(@This());
319-
result.* = .{
320-
.handle = handle,
321-
.id = id,
374+
const dir_ptr = try gpa.create(@This());
375+
dir_ptr.* = .{
376+
.handle = dir_handle,
377+
.id = dir_id,
322378
.overlapped = std.mem.zeroInit(
323379
windows.OVERLAPPED,
324380
.{
325-
.hEvent = event,
381+
.hEvent = wait_handle,
326382
},
327383
),
328384
};
329-
return result;
385+
return dir_ptr;
330386
}
331387

332388
fn deinit(self: *@This(), gpa: Allocator) void {
@@ -407,81 +463,21 @@ const Os = switch (builtin.os.tag) {
407463
const reaction_set = rs: {
408464
const gop = try w.dir_table.getOrPut(gpa, path);
409465
if (!gop.found_existing) {
410-
// The following code is a drawn out NtCreateFile call. (mostly adapted from std.fs.Dir.makeOpenDirAccessMaskW)
411-
// It's necessary in order to get the flags are required when calling ReadDirectoryChangesW.
412-
var dir_handle: windows.HANDLE = undefined;
413-
{
414-
const root_fd = path.root_dir.handle.fd;
415-
const sub_path = path.subPathOrDot();
416-
const sub_path_w = try windows.sliceToPrefixedFileW(root_fd, sub_path);
417-
const path_len_bytes = std.math.cast(u16, sub_path_w.len * 2) orelse return error.NameTooLong;
418-
419-
var nt_name = windows.UNICODE_STRING{
420-
.Length = @intCast(path_len_bytes),
421-
.MaximumLength = @intCast(path_len_bytes),
422-
.Buffer = @constCast(sub_path_w.span().ptr),
423-
};
424-
var attr = windows.OBJECT_ATTRIBUTES{
425-
.Length = @sizeOf(windows.OBJECT_ATTRIBUTES),
426-
.RootDirectory = if (std.fs.path.isAbsoluteWindowsW(sub_path_w.span())) null else root_fd,
427-
.Attributes = 0, // Note we do not use OBJ_CASE_INSENSITIVE here.
428-
.ObjectName = &nt_name,
429-
.SecurityDescriptor = null,
430-
.SecurityQualityOfService = null,
431-
};
432-
var io: windows.IO_STATUS_BLOCK = undefined;
433-
const rc = windows.ntdll.NtCreateFile(
434-
&dir_handle,
435-
windows.SYNCHRONIZE | windows.GENERIC_READ | windows.FILE_LIST_DIRECTORY,
436-
&attr,
437-
&io,
438-
null,
439-
0,
440-
windows.FILE_SHARE_READ | windows.FILE_SHARE_WRITE | windows.FILE_SHARE_DELETE,
441-
windows.FILE_OPEN,
442-
windows.FILE_DIRECTORY_FILE | windows.FILE_OPEN_FOR_BACKUP_INTENT,
443-
null,
444-
0,
445-
);
446-
447-
switch (rc) {
448-
.SUCCESS => {},
449-
.OBJECT_NAME_INVALID => return error.BadPathName,
450-
.OBJECT_NAME_NOT_FOUND => return error.FileNotFound,
451-
.OBJECT_NAME_COLLISION => return error.PathAlreadyExists,
452-
.OBJECT_PATH_NOT_FOUND => return error.FileNotFound,
453-
.NOT_A_DIRECTORY => return error.NotDir,
454-
// This can happen if the directory has 'List folder contents' permission set to 'Deny'
455-
.ACCESS_DENIED => return error.AccessDenied,
456-
.INVALID_PARAMETER => unreachable,
457-
else => return windows.unexpectedStatus(rc),
458-
}
459-
assert(dir_handle != windows.INVALID_HANDLE_VALUE);
460-
}
461-
462-
const dir_id = getFileId(dir_handle) catch |err| {
463-
windows.CloseHandle(dir_handle);
464-
return err;
465-
};
466-
467-
// `dir_id` may already be present in the table in
466+
const dir = try Os.Directory.init(gpa, path);
467+
errdefer dir.deinit(gpa);
468+
// `dir.id` may already be present in the table in
468469
// the case that we have multiple Cache.Path instances
469470
// that compare inequal but ultimately point to the same
470471
// directory on the file system.
471472
// In such case, we must revert adding this directory, but keep
472473
// the additions to the step set.
473-
const dh_gop = w.os.handle_table.getOrPut(gpa, dir_id) catch |err| {
474-
windows.CloseHandle(dir_handle);
475-
return err;
476-
};
474+
const dh_gop = try w.os.handle_table.getOrPut(gpa, dir.id);
477475
if (dh_gop.found_existing) {
478-
windows.CloseHandle(dir_handle);
476+
dir.deinit(gpa);
479477
_ = w.dir_table.pop();
480478
} else {
481479
assert(dh_gop.index == gop.index);
482480
dh_gop.value_ptr.* = .{};
483-
const dir = try Os.Directory.init(gpa, dir_handle, dir_id);
484-
errdefer dir.deinit(gpa);
485481
try dir.readChanges();
486482
try w.os.handle_extra.insert(gpa, dh_gop.index, .{
487483
.dir = dir,

0 commit comments

Comments
 (0)