From 2b67f56c35d0a61be43f8ca23535096ae3ca4948 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Sat, 9 Jul 2022 18:59:21 +0300 Subject: [PATCH] std.fs: split `Dir` into `IterableDir` Also adds safety check for attempting to iterate directory not opened with `iterate = true`. --- lib/std/build.zig | 6 +- lib/std/fs.zig | 152 +++++++++++++++++++------------ lib/std/fs/test.zig | 41 +++++---- src/main.zig | 12 +-- src/test.zig | 2 +- tools/process_headers.zig | 6 +- tools/update-license-headers.zig | 8 +- tools/update-linux-headers.zig | 6 +- tools/update_glibc.zig | 10 +- tools/update_spirv_features.zig | 6 +- 10 files changed, 145 insertions(+), 104 deletions(-) diff --git a/lib/std/build.zig b/lib/std/build.zig index b17420db09..87dacbb5e4 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -3245,7 +3245,7 @@ pub const LibExeObjStep = struct { const build_output_dir = mem.trimRight(u8, output_dir_nl, "\r\n"); if (self.output_dir) |output_dir| { - var src_dir = try std.fs.cwd().openDir(build_output_dir, .{ .iterate = true }); + var src_dir = try std.fs.cwd().openIterableDir(build_output_dir, .{}); defer src_dir.close(); // Create the output directory if it doesn't exist. @@ -3265,7 +3265,7 @@ pub const LibExeObjStep = struct { mem.eql(u8, entry.name, "zld.id") or mem.eql(u8, entry.name, "lld.id")) continue; - _ = try src_dir.updateFile(entry.name, dest_dir, entry.name, .{}); + _ = try src_dir.dir.updateFile(entry.name, dest_dir, entry.name, .{}); } } else { self.output_dir = build_output_dir; @@ -3480,7 +3480,7 @@ pub const InstallDirStep = struct { const self = @fieldParentPtr(InstallDirStep, "step", step); const dest_prefix = self.builder.getInstallPath(self.options.install_dir, self.options.install_subdir); const full_src_dir = self.builder.pathFromRoot(self.options.source_dir); - var src_dir = try std.fs.cwd().openDir(full_src_dir, .{ .iterate = true }); + var src_dir = try std.fs.cwd().openIterableDir(full_src_dir, .{}); defer src_dir.close(); var it = try src_dir.walk(self.builder.allocator); next_entry: while (try it.next()) |entry| { diff --git a/lib/std/fs.zig b/lib/std/fs.zig index 4a21af806e..0b2a908c31 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -283,8 +283,10 @@ pub fn renameW(old_dir: Dir, old_sub_path_w: []const u16, new_dir: Dir, new_sub_ return os.renameatW(old_dir.fd, old_sub_path_w, new_dir.fd, new_sub_path_w); } -pub const Dir = struct { - fd: os.fd_t, +/// A directory that can be iterated. It is *NOT* legal to initialize this with a regular `Dir` +/// that has been opened without iteration permission. +pub const IterableDir = struct { + dir: Dir, pub const Entry = struct { name: []const u8, @@ -779,7 +781,7 @@ pub const Dir = struct { else => @compileError("unimplemented"), }; - pub fn iterate(self: Dir) Iterator { + pub fn iterate(self: IterableDir) Iterator { switch (builtin.os.tag) { .macos, .ios, @@ -789,7 +791,7 @@ pub const Dir = struct { .openbsd, .solaris, => return Iterator{ - .dir = self, + .dir = self.dir, .seek = 0, .index = 0, .end_index = 0, @@ -797,14 +799,14 @@ pub const Dir = struct { .first_iter = true, }, .linux, .haiku => return Iterator{ - .dir = self, + .dir = self.dir, .index = 0, .end_index = 0, .buf = undefined, .first_iter = true, }, .windows => return Iterator{ - .dir = self, + .dir = self.dir, .index = 0, .end_index = 0, .first_iter = true, @@ -812,7 +814,7 @@ pub const Dir = struct { .name_data = undefined, }, .wasi => return Iterator{ - .dir = self, + .dir = self.dir, .cookie = os.wasi.DIRCOOKIE_START, .index = 0, .end_index = 0, @@ -833,11 +835,11 @@ pub const Dir = struct { dir: Dir, basename: []const u8, path: []const u8, - kind: Dir.Entry.Kind, + kind: IterableDir.Entry.Kind, }; const StackItem = struct { - iter: Dir.Iterator, + iter: IterableDir.Iterator, dirname_len: usize, }; @@ -857,7 +859,7 @@ pub const Dir = struct { } try self.name_buffer.appendSlice(base.name); if (base.kind == .Directory) { - var new_dir = top.iter.dir.openDir(base.name, .{ .iterate = true }) catch |err| switch (err) { + var new_dir = top.iter.dir.openIterableDir(base.name, .{}) catch |err| switch (err) { error.NameTooLong => unreachable, // no path sep in base.name else => |e| return e, }; @@ -896,11 +898,10 @@ pub const Dir = struct { }; /// Recursively iterates over a directory. - /// `self` must have been opened with `OpenDirOptions{.iterate = true}`. /// Must call `Walker.deinit` when done. /// The order of returned file system entries is undefined. /// `self` will not be closed after walking it. - pub fn walk(self: Dir, allocator: Allocator) !Walker { + pub fn walk(self: IterableDir, allocator: Allocator) !Walker { var name_buffer = std.ArrayList(u8).init(allocator); errdefer name_buffer.deinit(); @@ -918,6 +919,52 @@ pub const Dir = struct { }; } + pub fn close(self: *IterableDir) void { + self.dir.close(); + self.* = undefined; + } + + pub const ChmodError = File.ChmodError; + + /// Changes the mode of the directory. + /// The process must have the correct privileges in order to do this + /// successfully, or must have the effective user ID matching the owner + /// of the directory. + pub fn chmod(self: IterableDir, new_mode: File.Mode) ChmodError!void { + const file: File = .{ + .handle = self.dir.fd, + .capable_io_mode = .blocking, + }; + try file.chmod(new_mode); + } + + /// Changes the owner and group of the directory. + /// The process must have the correct privileges in order to do this + /// successfully. The group may be changed by the owner of the directory to + /// any group of which the owner is a member. If the + /// owner or group is specified as `null`, the ID is not changed. + pub fn chown(self: IterableDir, owner: ?File.Uid, group: ?File.Gid) ChownError!void { + const file: File = .{ + .handle = self.dir.fd, + .capable_io_mode = .blocking, + }; + try file.chown(owner, group); + } + + pub const ChownError = File.ChownError; +}; + +pub const Dir = struct { + fd: os.fd_t, + iterable: @TypeOf(iterable_safety) = iterable_safety, + + const iterable_safety = if (builtin.mode == .Debug) false else {}; + + pub const iterate = @compileError("only 'IterableDir' can be iterated; 'IterableDir' can be obtained with 'openIterableDir' or by opening with 'iterate = true' and using 'intoIterable'"); + pub const walk = @compileError("only 'IterableDir' can be walked; 'IterableDir' can be obtained with 'openIterableDir' or by opening with 'iterate = true' and using 'intoIterable'"); + pub const chmod = @compileError("only 'IterableDir' can have its mode changed; 'IterableDir' can be obtained with 'openIterableDir' or by opening with 'iterate = true' and using 'intoIterable'"); + pub const chown = @compileError("only 'IterableDir' can have its owner changed; 'IterableDir' can be obtained with 'openIterableDir' or by opening with 'iterate = true' and using 'intoIterable'"); + pub const OpenError = error{ FileNotFound, NotDir, @@ -1507,6 +1554,26 @@ pub const Dir = struct { } } + /// Opens an iterable directory at the given path. The directory is a system resource that remains + /// open until `close` is called on the result. + /// + /// Asserts that the path parameter has no null bytes. + pub fn openIterableDir(self: Dir, sub_path: []const u8, args: OpenDirOptions) OpenError!IterableDir { + var adjusted_args = args; + adjusted_args.iterate = true; + const new_dir = try self.openDir(sub_path, adjusted_args); + return IterableDir{ .dir = new_dir }; + } + + /// Convert `self` into an iterable directory. + /// Asserts that `self` was opened with `iterate = true`. + pub fn intoIterable(self: Dir) IterableDir { + if (builtin.mode == .Debug) { + assert(self.iterable); + } + return .{ .dir = self }; + } + /// Same as `openDir` except only WASI. pub fn openDirWasi(self: Dir, sub_path: []const u8, args: OpenDirOptions) OpenError!Dir { const w = os.wasi; @@ -1552,7 +1619,7 @@ pub const Dir = struct { error.FileBusy => unreachable, // can't happen for directories else => |e| return e, }; - return Dir{ .fd = fd }; + return Dir{ .fd = fd, .iterable = if (builtin.mode == .Debug) args.iterate else {} }; } /// Same as `openDir` except the parameter is null-terminated. @@ -1566,7 +1633,9 @@ pub const Dir = struct { const O_PATH = if (@hasDecl(os.O, "PATH")) os.O.PATH else 0; return self.openDirFlagsZ(sub_path_c, os.O.DIRECTORY | os.O.RDONLY | os.O.CLOEXEC | O_PATH | symlink_flags); } else { - return self.openDirFlagsZ(sub_path_c, os.O.DIRECTORY | os.O.RDONLY | os.O.CLOEXEC | symlink_flags); + var dir = try self.openDirFlagsZ(sub_path_c, os.O.DIRECTORY | os.O.RDONLY | os.O.CLOEXEC | symlink_flags); + if (builtin.mode == .Debug) dir.iterable = true; + return dir; } } @@ -1578,7 +1647,9 @@ pub const Dir = struct { const base_flags = w.STANDARD_RIGHTS_READ | w.FILE_READ_ATTRIBUTES | w.FILE_READ_EA | w.SYNCHRONIZE | w.FILE_TRAVERSE; const flags: u32 = if (args.iterate) base_flags | w.FILE_LIST_DIRECTORY else base_flags; - return self.openDirAccessMaskW(sub_path_w, flags, args.no_follow); + var dir = try self.openDirAccessMaskW(sub_path_w, flags, args.no_follow); + if (builtin.mode == .Debug) dir.iterable = args.iterate; + return dir; } /// `flags` must contain `os.O.DIRECTORY`. @@ -1958,7 +2029,7 @@ pub const Dir = struct { error.Unexpected, => |e| return e, } - var dir = self.openDir(sub_path, .{ .iterate = true, .no_follow = true }) catch |err| switch (err) { + var iterable_dir = self.openIterableDir(sub_path, .{ .no_follow = true }) catch |err| switch (err) { error.NotDir => { if (got_access_denied) { return error.AccessDenied; @@ -1984,11 +2055,11 @@ pub const Dir = struct { error.DeviceBusy, => |e| return e, }; - var cleanup_dir_parent: ?Dir = null; + var cleanup_dir_parent: ?IterableDir = null; defer if (cleanup_dir_parent) |*d| d.close(); var cleanup_dir = true; - defer if (cleanup_dir) dir.close(); + defer if (cleanup_dir) iterable_dir.close(); // Valid use of MAX_PATH_BYTES because dir_name_buf will only // ever store a single path component that was returned from the @@ -2001,9 +2072,9 @@ pub const Dir = struct { // open it, and close the original directory. Repeat. Then start the entire operation over. scan_dir: while (true) { - var dir_it = dir.iterate(); + var dir_it = iterable_dir.iterate(); while (try dir_it.next()) |entry| { - if (dir.deleteFile(entry.name)) { + if (iterable_dir.dir.deleteFile(entry.name)) { continue; } else |err| switch (err) { error.FileNotFound => continue, @@ -2026,7 +2097,7 @@ pub const Dir = struct { => |e| return e, } - const new_dir = dir.openDir(entry.name, .{ .iterate = true, .no_follow = true }) catch |err| switch (err) { + const new_dir = iterable_dir.dir.openIterableDir(entry.name, .{ .no_follow = true }) catch |err| switch (err) { error.NotDir => { if (got_access_denied) { return error.AccessDenied; @@ -2053,19 +2124,19 @@ pub const Dir = struct { => |e| return e, }; if (cleanup_dir_parent) |*d| d.close(); - cleanup_dir_parent = dir; - dir = new_dir; + cleanup_dir_parent = iterable_dir; + iterable_dir = new_dir; mem.copy(u8, &dir_name_buf, entry.name); dir_name = dir_name_buf[0..entry.name.len]; continue :scan_dir; } // Reached the end of the directory entries, which means we successfully deleted all of them. // Now to remove the directory itself. - dir.close(); + iterable_dir.close(); cleanup_dir = false; if (cleanup_dir_parent) |d| { - d.deleteDir(dir_name) catch |err| switch (err) { + d.dir.deleteDir(dir_name) catch |err| switch (err) { // These two things can happen due to file system race conditions. error.FileNotFound, error.DirNotEmpty => continue :start_over, else => |e| return e, @@ -2246,37 +2317,6 @@ pub const Dir = struct { return file.stat(); } - pub const ChmodError = File.ChmodError; - - /// Changes the mode of the directory. - /// The process must have the correct privileges in order to do this - /// successfully, or must have the effective user ID matching the owner - /// of the directory. Additionally, the directory must have been opened - /// with `OpenDirOptions{ .iterate = true }`. - pub fn chmod(self: Dir, new_mode: File.Mode) ChmodError!void { - const file: File = .{ - .handle = self.fd, - .capable_io_mode = .blocking, - }; - try file.chmod(new_mode); - } - - /// Changes the owner and group of the directory. - /// The process must have the correct privileges in order to do this - /// successfully. The group may be changed by the owner of the directory to - /// any group of which the owner is a member. Additionally, the directory - /// must have been opened with `OpenDirOptions{ .iterate = true }`. If the - /// owner or group is specified as `null`, the ID is not changed. - pub fn chown(self: Dir, owner: ?File.Uid, group: ?File.Gid) ChownError!void { - const file: File = .{ - .handle = self.fd, - .capable_io_mode = .blocking, - }; - try file.chown(owner, group); - } - - pub const ChownError = File.ChownError; - const Permissions = File.Permissions; pub const SetPermissionsError = File.SetPermissionsError; diff --git a/lib/std/fs/test.zig b/lib/std/fs/test.zig index f4003c1803..ac6e5fad87 100644 --- a/lib/std/fs/test.zig +++ b/lib/std/fs/test.zig @@ -8,6 +8,7 @@ const wasi = std.os.wasi; const ArenaAllocator = std.heap.ArenaAllocator; const Dir = std.fs.Dir; +const IterableDir = std.fs.IterableDir; const File = std.fs.File; const tmpDir = testing.tmpDir; @@ -168,20 +169,20 @@ test "Dir.Iterator" { defer arena.deinit(); const allocator = arena.allocator(); - var entries = std.ArrayList(Dir.Entry).init(allocator); + var entries = std.ArrayList(IterableDir.Entry).init(allocator); // Create iterator. - var iter = tmp_dir.dir.iterate(); + var iter = tmp_dir.dir.intoIterable().iterate(); while (try iter.next()) |entry| { // We cannot just store `entry` as on Windows, we're re-using the name buffer // which means we'll actually share the `name` pointer between entries! const name = try allocator.dupe(u8, entry.name); - try entries.append(Dir.Entry{ .name = name, .kind = entry.kind }); + try entries.append(.{ .name = name, .kind = entry.kind }); } try testing.expect(entries.items.len == 2); // note that the Iterator skips '.' and '..' - try testing.expect(contains(&entries, Dir.Entry{ .name = "some_file", .kind = Dir.Entry.Kind.File })); - try testing.expect(contains(&entries, Dir.Entry{ .name = "some_dir", .kind = Dir.Entry.Kind.Directory })); + try testing.expect(contains(&entries, .{ .name = "some_file", .kind = .File })); + try testing.expect(contains(&entries, .{ .name = "some_dir", .kind = .Directory })); } test "Dir.Iterator twice" { @@ -200,28 +201,28 @@ test "Dir.Iterator twice" { var i: u8 = 0; while (i < 2) : (i += 1) { - var entries = std.ArrayList(Dir.Entry).init(allocator); + var entries = std.ArrayList(IterableDir.Entry).init(allocator); // Create iterator. - var iter = tmp_dir.dir.iterate(); + var iter = tmp_dir.dir.intoIterable().iterate(); while (try iter.next()) |entry| { // We cannot just store `entry` as on Windows, we're re-using the name buffer // which means we'll actually share the `name` pointer between entries! const name = try allocator.dupe(u8, entry.name); - try entries.append(Dir.Entry{ .name = name, .kind = entry.kind }); + try entries.append(.{ .name = name, .kind = entry.kind }); } try testing.expect(entries.items.len == 2); // note that the Iterator skips '.' and '..' - try testing.expect(contains(&entries, Dir.Entry{ .name = "some_file", .kind = Dir.Entry.Kind.File })); - try testing.expect(contains(&entries, Dir.Entry{ .name = "some_dir", .kind = Dir.Entry.Kind.Directory })); + try testing.expect(contains(&entries, .{ .name = "some_file", .kind = .File })); + try testing.expect(contains(&entries, .{ .name = "some_dir", .kind = .Directory })); } } -fn entryEql(lhs: Dir.Entry, rhs: Dir.Entry) bool { +fn entryEql(lhs: IterableDir.Entry, rhs: IterableDir.Entry) bool { return mem.eql(u8, lhs.name, rhs.name) and lhs.kind == rhs.kind; } -fn contains(entries: *const std.ArrayList(Dir.Entry), el: Dir.Entry) bool { +fn contains(entries: *const std.ArrayList(IterableDir.Entry), el: IterableDir.Entry) bool { for (entries.items) |entry| { if (entryEql(entry, el)) return true; } @@ -1014,7 +1015,7 @@ test "walker" { try tmp.dir.makePath(kv.key); } - var walker = try tmp.dir.walk(testing.allocator); + var walker = try tmp.dir.intoIterable().walk(testing.allocator); defer walker.deinit(); var num_walked: usize = 0; @@ -1121,11 +1122,11 @@ test "chmod" { try testing.expect((try file.stat()).mode & 0o7777 == 0o644); try tmp.dir.makeDir("test_dir"); - var dir = try tmp.dir.openDir("test_dir", .{ .iterate = true }); - defer dir.close(); + var iterable_dir = try tmp.dir.openIterableDir("test_dir", .{}); + defer iterable_dir.close(); - try dir.chmod(0o700); - try testing.expect((try dir.stat()).mode & 0o7777 == 0o700); + try iterable_dir.chmod(0o700); + try testing.expect((try iterable_dir.stat()).mode & 0o7777 == 0o700); } test "chown" { @@ -1141,9 +1142,9 @@ test "chown" { try tmp.dir.makeDir("test_dir"); - var dir = try tmp.dir.openDir("test_dir", .{ .iterate = true }); - defer dir.close(); - try dir.chown(null, null); + var iterable_dir = try tmp.dir.openDir("test_dir", .{}); + defer iterable_dir.close(); + try iterable_dir.chown(null, null); } test "File.Metadata" { diff --git a/src/main.zig b/src/main.zig index 3d77fc242a..8e34c8ee56 100644 --- a/src/main.zig +++ b/src/main.zig @@ -4206,13 +4206,13 @@ fn fmtPathDir( parent_dir: fs.Dir, parent_sub_path: []const u8, ) FmtError!void { - var dir = try parent_dir.openDir(parent_sub_path, .{ .iterate = true }); - defer dir.close(); + var iterable_dir = try parent_dir.openIterableDir(parent_sub_path, .{}); + defer iterable_dir.close(); - const stat = try dir.stat(); + const stat = try iterable_dir.dir.stat(); if (try fmt.seen.fetchPut(stat.inode, {})) |_| return; - var dir_it = dir.iterate(); + var dir_it = iterable_dir.iterate(); while (try dir_it.next()) |entry| { const is_dir = entry.kind == .Directory; @@ -4223,9 +4223,9 @@ fn fmtPathDir( defer fmt.gpa.free(full_path); if (is_dir) { - try fmtPathDir(fmt, full_path, check_mode, dir, entry.name); + try fmtPathDir(fmt, full_path, check_mode, iterable_dir.dir, entry.name); } else { - fmtPathFile(fmt, full_path, check_mode, dir, entry.name) catch |err| { + fmtPathFile(fmt, full_path, check_mode, iterable_dir.dir, entry.name) catch |err| { warn("unable to format '{s}': {s}", .{ full_path, @errorName(err) }); fmt.any_error = true; return; diff --git a/src/test.zig b/src/test.zig index a1ae2fe238..c4a0fd7709 100644 --- a/src/test.zig +++ b/src/test.zig @@ -1096,7 +1096,7 @@ pub const TestContext = struct { /// that if any errors occur the caller knows it happened during this file. current_file: *[]const u8, ) !void { - var it = try dir.walk(ctx.arena); + var it = try dir.intoIterable().walk(ctx.arena); var filenames = std.ArrayList([]const u8).init(ctx.arena); while (try it.next()) |entry| { diff --git a/tools/process_headers.zig b/tools/process_headers.zig index 84126635dc..04baeee68d 100644 --- a/tools/process_headers.zig +++ b/tools/process_headers.zig @@ -381,14 +381,14 @@ pub fn main() !void { try dir_stack.append(target_include_dir); while (dir_stack.popOrNull()) |full_dir_name| { - var dir = std.fs.cwd().openDir(full_dir_name, .{ .iterate = true }) catch |err| switch (err) { + var iterable_dir = std.fs.cwd().openIterableDir(full_dir_name, .{}) catch |err| switch (err) { error.FileNotFound => continue :search, error.AccessDenied => continue :search, else => return err, }; - defer dir.close(); + defer iterable_dir.close(); - var dir_it = dir.iterate(); + var dir_it = iterable_dir.iterate(); while (try dir_it.next()) |entry| { const full_path = try std.fs.path.join(allocator, &[_][]const u8{ full_dir_name, entry.name }); diff --git a/tools/update-license-headers.zig b/tools/update-license-headers.zig index b2aed7ccdb..7756cf898c 100644 --- a/tools/update-license-headers.zig +++ b/tools/update-license-headers.zig @@ -14,9 +14,9 @@ pub fn main() !void { const args = try std.process.argsAlloc(arena); const path_to_walk = args[1]; - const dir = try std.fs.cwd().openDir(path_to_walk, .{ .iterate = true }); + const iterable_dir = try std.fs.cwd().openIterableDir(path_to_walk, .{}); - var walker = try dir.walk(arena); + var walker = try iterable_dir.walk(arena); defer walker.deinit(); var buffer: [500]u8 = undefined; @@ -30,7 +30,7 @@ pub fn main() !void { node.activate(); defer node.end(); - const source = try dir.readFileAlloc(arena, entry.path, 20 * 1024 * 1024); + const source = try iterable_dir.dir.readFileAlloc(arena, entry.path, 20 * 1024 * 1024); if (!std.mem.startsWith(u8, source, expected_header)) { std.debug.print("no match: {s}\n", .{entry.path}); continue; @@ -42,6 +42,6 @@ pub fn main() !void { std.mem.copy(u8, new_source, new_header); std.mem.copy(u8, new_source[new_header.len..], truncated_source); - try dir.writeFile(entry.path, new_source); + try iterable_dir.dir.writeFile(entry.path, new_source); } } diff --git a/tools/update-linux-headers.zig b/tools/update-linux-headers.zig index cfa16fcd38..38fbab6645 100644 --- a/tools/update-linux-headers.zig +++ b/tools/update-linux-headers.zig @@ -181,14 +181,14 @@ pub fn main() !void { try dir_stack.append(target_include_dir); while (dir_stack.popOrNull()) |full_dir_name| { - var dir = std.fs.cwd().openDir(full_dir_name, .{ .iterate = true }) catch |err| switch (err) { + var iterable_dir = std.fs.cwd().openIterableDir(full_dir_name, .{}) catch |err| switch (err) { error.FileNotFound => continue :search, error.AccessDenied => continue :search, else => return err, }; - defer dir.close(); + defer iterable_dir.close(); - var dir_it = dir.iterate(); + var dir_it = iterable_dir.iterate(); while (try dir_it.next()) |entry| { const full_path = try std.fs.path.join(arena, &[_][]const u8{ full_dir_name, entry.name }); diff --git a/tools/update_glibc.zig b/tools/update_glibc.zig index c15123a6de..24b0f45de7 100644 --- a/tools/update_glibc.zig +++ b/tools/update_glibc.zig @@ -41,7 +41,7 @@ pub fn main() !void { const dest_dir_path = try std.fmt.allocPrint(arena, "{s}/lib/libc/glibc", .{zig_src_path}); - var dest_dir = fs.cwd().openDir(dest_dir_path, .{ .iterate = true }) catch |err| { + var dest_dir = fs.cwd().openIterableDir(dest_dir_path, .{}) catch |err| { fatal("unable to open destination directory '{s}': {s}", .{ dest_dir_path, @errorName(err), }); @@ -63,14 +63,14 @@ pub fn main() !void { if (mem.eql(u8, entry.path, p)) continue :walk; } - glibc_src_dir.copyFile(entry.path, dest_dir, entry.path, .{}) catch |err| { + glibc_src_dir.copyFile(entry.path, dest_dir.dir, entry.path, .{}) catch |err| { log.warn("unable to copy '{s}/{s}' to '{s}/{s}': {s}", .{ glibc_src_path, entry.path, dest_dir_path, entry.path, @errorName(err), }); if (err == error.FileNotFound) { - try dest_dir.deleteFile(entry.path); + try dest_dir.dir.deleteFile(entry.path); } }; } @@ -79,7 +79,7 @@ pub fn main() !void { // Warn about duplicated files inside glibc/include/* that can be omitted // because they are already in generic-glibc/*. - var include_dir = dest_dir.openDir("include", .{ .iterate = true }) catch |err| { + var include_dir = dest_dir.dir.openIterableDir("include", .{}) catch |err| { fatal("unable to open directory '{s}/include': {s}", .{ dest_dir_path, @errorName(err), }); @@ -116,7 +116,7 @@ pub fn main() !void { generic_glibc_path, entry.path, @errorName(e), }), }; - const glibc_include_contents = include_dir.readFileAlloc( + const glibc_include_contents = include_dir.dir.readFileAlloc( arena, entry.path, max_file_size, diff --git a/tools/update_spirv_features.zig b/tools/update_spirv_features.zig index 8972ab641c..b32356e815 100644 --- a/tools/update_spirv_features.zig +++ b/tools/update_spirv_features.zig @@ -218,7 +218,7 @@ pub fn main() !void { /// TODO: Unfortunately, neither repository contains a machine-readable list of extension dependencies. fn gather_extensions(allocator: Allocator, spirv_registry_root: []const u8) ![]const []const u8 { const extensions_path = try fs.path.join(allocator, &.{ spirv_registry_root, "extensions" }); - var extensions_dir = try fs.cwd().openDir(extensions_path, .{ .iterate = true }); + var extensions_dir = try fs.cwd().openIterableDir(extensions_path, .{}); defer extensions_dir.close(); var extensions = std.ArrayList([]const u8).init(allocator); @@ -227,7 +227,7 @@ fn gather_extensions(allocator: Allocator, spirv_registry_root: []const u8) ![]c while (try vendor_it.next()) |vendor_entry| { std.debug.assert(vendor_entry.kind == .Directory); // If this fails, the structure of SPIRV-Registry has changed. - const vendor_dir = try extensions_dir.openDir(vendor_entry.name, .{ .iterate = true }); + const vendor_dir = try extensions_dir.dir.openIterableDir(vendor_entry.name, .{}); var ext_it = vendor_dir.iterate(); while (try ext_it.next()) |ext_entry| { // There is both a HTML and asciidoc version of every spec (as well as some other directories), @@ -250,7 +250,7 @@ fn gather_extensions(allocator: Allocator, spirv_registry_root: []const u8) ![]c // SPV_EXT_name // ``` - const ext_spec = try vendor_dir.readFileAlloc(allocator, ext_entry.name, std.math.maxInt(usize)); + const ext_spec = try vendor_dir.dir.readFileAlloc(allocator, ext_entry.name, std.math.maxInt(usize)); const name_strings = "Name Strings"; const name_strings_offset = std.mem.indexOf(u8, ext_spec, name_strings) orelse return error.InvalidRegistry;