| author | |
| committer | |
| log | da94227f783ec3c92859c4713b80a668f1183f96 |
| tree | 74e36b830f8fdff1c836df1c74024c5477bd0f7c |
| parent | 8f943b3d33432a26b7e242c1181e4220ed400501 |
| parent | 262f4c7b3a850594a75ec154db2ba8d5f9f517ab |
| signature |
std.fs: split `Dir` into `IterableDir`12 files changed, 201 insertions(+), 126 deletions(-)
lib/std/build.zig+3-3| ... | ... | @@ -3245,7 +3245,7 @@ pub const LibExeObjStep = struct { |
| 3245 | 3245 | const build_output_dir = mem.trimRight(u8, output_dir_nl, "\r\n"); |
| 3246 | 3246 | |
| 3247 | 3247 | if (self.output_dir) |output_dir| { |
| 3248 | var src_dir = try std.fs.cwd().openDir(build_output_dir, .{ .iterate = true }); | |
| 3248 | var src_dir = try std.fs.cwd().openIterableDir(build_output_dir, .{}); | |
| 3249 | 3249 | defer src_dir.close(); |
| 3250 | 3250 | |
| 3251 | 3251 | // Create the output directory if it doesn't exist. |
| ... | ... | @@ -3265,7 +3265,7 @@ pub const LibExeObjStep = struct { |
| 3265 | 3265 | mem.eql(u8, entry.name, "zld.id") or |
| 3266 | 3266 | mem.eql(u8, entry.name, "lld.id")) continue; |
| 3267 | 3267 | |
| 3268 | _ = try src_dir.updateFile(entry.name, dest_dir, entry.name, .{}); | |
| 3268 | _ = try src_dir.dir.updateFile(entry.name, dest_dir, entry.name, .{}); | |
| 3269 | 3269 | } |
| 3270 | 3270 | } else { |
| 3271 | 3271 | self.output_dir = build_output_dir; |
| ... | ... | @@ -3480,7 +3480,7 @@ pub const InstallDirStep = struct { |
| 3480 | 3480 | const self = @fieldParentPtr(InstallDirStep, "step", step); |
| 3481 | 3481 | const dest_prefix = self.builder.getInstallPath(self.options.install_dir, self.options.install_subdir); |
| 3482 | 3482 | const full_src_dir = self.builder.pathFromRoot(self.options.source_dir); |
| 3483 | var src_dir = try std.fs.cwd().openDir(full_src_dir, .{ .iterate = true }); | |
| 3483 | var src_dir = try std.fs.cwd().openIterableDir(full_src_dir, .{}); | |
| 3484 | 3484 | defer src_dir.close(); |
| 3485 | 3485 | var it = try src_dir.walk(self.builder.allocator); |
| 3486 | 3486 | next_entry: while (try it.next()) |entry| { |
lib/std/fs.zig+99-64| ... | ... | @@ -283,8 +283,10 @@ pub fn renameW(old_dir: Dir, old_sub_path_w: []const u16, new_dir: Dir, new_sub_ |
| 283 | 283 | return os.renameatW(old_dir.fd, old_sub_path_w, new_dir.fd, new_sub_path_w); |
| 284 | 284 | } |
| 285 | 285 | |
| 286 | pub const Dir = struct { | |
| 287 | fd: os.fd_t, | |
| 286 | /// A directory that can be iterated. It is *NOT* legal to initialize this with a regular `Dir` | |
| 287 | /// that has been opened without iteration permission. | |
| 288 | pub const IterableDir = struct { | |
| 289 | dir: Dir, | |
| 288 | 290 | |
| 289 | 291 | pub const Entry = struct { |
| 290 | 292 | name: []const u8, |
| ... | ... | @@ -779,7 +781,7 @@ pub const Dir = struct { |
| 779 | 781 | else => @compileError("unimplemented"), |
| 780 | 782 | }; |
| 781 | 783 | |
| 782 | pub fn iterate(self: Dir) Iterator { | |
| 784 | pub fn iterate(self: IterableDir) Iterator { | |
| 783 | 785 | switch (builtin.os.tag) { |
| 784 | 786 | .macos, |
| 785 | 787 | .ios, |
| ... | ... | @@ -789,7 +791,7 @@ pub const Dir = struct { |
| 789 | 791 | .openbsd, |
| 790 | 792 | .solaris, |
| 791 | 793 | => return Iterator{ |
| 792 | .dir = self, | |
| 794 | .dir = self.dir, | |
| 793 | 795 | .seek = 0, |
| 794 | 796 | .index = 0, |
| 795 | 797 | .end_index = 0, |
| ... | ... | @@ -797,14 +799,14 @@ pub const Dir = struct { |
| 797 | 799 | .first_iter = true, |
| 798 | 800 | }, |
| 799 | 801 | .linux, .haiku => return Iterator{ |
| 800 | .dir = self, | |
| 802 | .dir = self.dir, | |
| 801 | 803 | .index = 0, |
| 802 | 804 | .end_index = 0, |
| 803 | 805 | .buf = undefined, |
| 804 | 806 | .first_iter = true, |
| 805 | 807 | }, |
| 806 | 808 | .windows => return Iterator{ |
| 807 | .dir = self, | |
| 809 | .dir = self.dir, | |
| 808 | 810 | .index = 0, |
| 809 | 811 | .end_index = 0, |
| 810 | 812 | .first_iter = true, |
| ... | ... | @@ -812,7 +814,7 @@ pub const Dir = struct { |
| 812 | 814 | .name_data = undefined, |
| 813 | 815 | }, |
| 814 | 816 | .wasi => return Iterator{ |
| 815 | .dir = self, | |
| 817 | .dir = self.dir, | |
| 816 | 818 | .cookie = os.wasi.DIRCOOKIE_START, |
| 817 | 819 | .index = 0, |
| 818 | 820 | .end_index = 0, |
| ... | ... | @@ -833,11 +835,11 @@ pub const Dir = struct { |
| 833 | 835 | dir: Dir, |
| 834 | 836 | basename: []const u8, |
| 835 | 837 | path: []const u8, |
| 836 | kind: Dir.Entry.Kind, | |
| 838 | kind: IterableDir.Entry.Kind, | |
| 837 | 839 | }; |
| 838 | 840 | |
| 839 | 841 | const StackItem = struct { |
| 840 | iter: Dir.Iterator, | |
| 842 | iter: IterableDir.Iterator, | |
| 841 | 843 | dirname_len: usize, |
| 842 | 844 | }; |
| 843 | 845 | |
| ... | ... | @@ -857,7 +859,7 @@ pub const Dir = struct { |
| 857 | 859 | } |
| 858 | 860 | try self.name_buffer.appendSlice(base.name); |
| 859 | 861 | if (base.kind == .Directory) { |
| 860 | var new_dir = top.iter.dir.openDir(base.name, .{ .iterate = true }) catch |err| switch (err) { | |
| 862 | var new_dir = top.iter.dir.openIterableDir(base.name, .{}) catch |err| switch (err) { | |
| 861 | 863 | error.NameTooLong => unreachable, // no path sep in base.name |
| 862 | 864 | else => |e| return e, |
| 863 | 865 | }; |
| ... | ... | @@ -896,11 +898,10 @@ pub const Dir = struct { |
| 896 | 898 | }; |
| 897 | 899 | |
| 898 | 900 | /// Recursively iterates over a directory. |
| 899 | /// `self` must have been opened with `OpenDirOptions{.iterate = true}`. | |
| 900 | 901 | /// Must call `Walker.deinit` when done. |
| 901 | 902 | /// The order of returned file system entries is undefined. |
| 902 | 903 | /// `self` will not be closed after walking it. |
| 903 | pub fn walk(self: Dir, allocator: Allocator) !Walker { | |
| 904 | pub fn walk(self: IterableDir, allocator: Allocator) !Walker { | |
| 904 | 905 | var name_buffer = std.ArrayList(u8).init(allocator); |
| 905 | 906 | errdefer name_buffer.deinit(); |
| 906 | 907 | |
| ... | ... | @@ -918,6 +919,49 @@ pub const Dir = struct { |
| 918 | 919 | }; |
| 919 | 920 | } |
| 920 | 921 | |
| 922 | pub fn close(self: *IterableDir) void { | |
| 923 | self.dir.close(); | |
| 924 | self.* = undefined; | |
| 925 | } | |
| 926 | ||
| 927 | pub const ChmodError = File.ChmodError; | |
| 928 | ||
| 929 | /// Changes the mode of the directory. | |
| 930 | /// The process must have the correct privileges in order to do this | |
| 931 | /// successfully, or must have the effective user ID matching the owner | |
| 932 | /// of the directory. | |
| 933 | pub fn chmod(self: IterableDir, new_mode: File.Mode) ChmodError!void { | |
| 934 | const file: File = .{ | |
| 935 | .handle = self.dir.fd, | |
| 936 | .capable_io_mode = .blocking, | |
| 937 | }; | |
| 938 | try file.chmod(new_mode); | |
| 939 | } | |
| 940 | ||
| 941 | /// Changes the owner and group of the directory. | |
| 942 | /// The process must have the correct privileges in order to do this | |
| 943 | /// successfully. The group may be changed by the owner of the directory to | |
| 944 | /// any group of which the owner is a member. If the | |
| 945 | /// owner or group is specified as `null`, the ID is not changed. | |
| 946 | pub fn chown(self: IterableDir, owner: ?File.Uid, group: ?File.Gid) ChownError!void { | |
| 947 | const file: File = .{ | |
| 948 | .handle = self.dir.fd, | |
| 949 | .capable_io_mode = .blocking, | |
| 950 | }; | |
| 951 | try file.chown(owner, group); | |
| 952 | } | |
| 953 | ||
| 954 | pub const ChownError = File.ChownError; | |
| 955 | }; | |
| 956 | ||
| 957 | pub const Dir = struct { | |
| 958 | fd: os.fd_t, | |
| 959 | ||
| 960 | pub const iterate = @compileError("only 'IterableDir' can be iterated; 'IterableDir' can be obtained with 'openIterableDir'"); | |
| 961 | pub const walk = @compileError("only 'IterableDir' can be walked; 'IterableDir' can be obtained with 'openIterableDir'"); | |
| 962 | pub const chmod = @compileError("only 'IterableDir' can have its mode changed; 'IterableDir' can be obtained with 'openIterableDir'"); | |
| 963 | pub const chown = @compileError("only 'IterableDir' can have its owner changed; 'IterableDir' can be obtained with 'openIterableDir'"); | |
| 964 | ||
| 921 | 965 | pub const OpenError = error{ |
| 922 | 966 | FileNotFound, |
| 923 | 967 | NotDir, |
| ... | ... | @@ -1334,6 +1378,15 @@ pub const Dir = struct { |
| 1334 | 1378 | return self.openDir(sub_path, open_dir_options); |
| 1335 | 1379 | } |
| 1336 | 1380 | |
| 1381 | /// This function performs `makePath`, followed by `openIterableDir`. | |
| 1382 | /// If supported by the OS, this operation is atomic. It is not atomic on | |
| 1383 | /// all operating systems. | |
| 1384 | pub fn makeOpenPathIterable(self: Dir, sub_path: []const u8, open_dir_options: OpenDirOptions) !IterableDir { | |
| 1385 | // TODO improve this implementation on Windows; we can avoid 1 call to NtClose | |
| 1386 | try self.makePath(sub_path); | |
| 1387 | return self.openIterableDir(sub_path, open_dir_options); | |
| 1388 | } | |
| 1389 | ||
| 1337 | 1390 | /// This function returns the canonicalized absolute pathname of |
| 1338 | 1391 | /// `pathname` relative to this `Dir`. If `pathname` is absolute, ignores this |
| 1339 | 1392 | /// `Dir` handle and returns the canonicalized absolute pathname of `pathname` |
| ... | ... | @@ -1483,10 +1536,6 @@ pub const Dir = struct { |
| 1483 | 1536 | /// such operations are Illegal Behavior. |
| 1484 | 1537 | access_sub_paths: bool = true, |
| 1485 | 1538 | |
| 1486 | /// `true` means the opened directory can be scanned for the files and sub-directories | |
| 1487 | /// of the result. It means the `iterate` function can be called. | |
| 1488 | iterate: bool = false, | |
| 1489 | ||
| 1490 | 1539 | /// `true` means it won't dereference the symlinks. |
| 1491 | 1540 | no_follow: bool = false, |
| 1492 | 1541 | }; |
| ... | ... | @@ -1498,12 +1547,28 @@ pub const Dir = struct { |
| 1498 | 1547 | pub fn openDir(self: Dir, sub_path: []const u8, args: OpenDirOptions) OpenError!Dir { |
| 1499 | 1548 | if (builtin.os.tag == .windows) { |
| 1500 | 1549 | const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path); |
| 1501 | return self.openDirW(sub_path_w.span().ptr, args); | |
| 1550 | return self.openDirW(sub_path_w.span().ptr, args, false); | |
| 1502 | 1551 | } else if (builtin.os.tag == .wasi and !builtin.link_libc) { |
| 1503 | 1552 | return self.openDirWasi(sub_path, args); |
| 1504 | 1553 | } else { |
| 1505 | 1554 | const sub_path_c = try os.toPosixPath(sub_path); |
| 1506 | return self.openDirZ(&sub_path_c, args); | |
| 1555 | return self.openDirZ(&sub_path_c, args, false); | |
| 1556 | } | |
| 1557 | } | |
| 1558 | ||
| 1559 | /// Opens an iterable directory at the given path. The directory is a system resource that remains | |
| 1560 | /// open until `close` is called on the result. | |
| 1561 | /// | |
| 1562 | /// Asserts that the path parameter has no null bytes. | |
| 1563 | pub fn openIterableDir(self: Dir, sub_path: []const u8, args: OpenDirOptions) OpenError!IterableDir { | |
| 1564 | if (builtin.os.tag == .windows) { | |
| 1565 | const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path); | |
| 1566 | return IterableDir{ .dir = try self.openDirW(sub_path_w.span().ptr, args, true) }; | |
| 1567 | } else if (builtin.os.tag == .wasi and !builtin.link_libc) { | |
| 1568 | return IterableDir{ .dir = try self.openDirWasi(sub_path, args) }; | |
| 1569 | } else { | |
| 1570 | const sub_path_c = try os.toPosixPath(sub_path); | |
| 1571 | return IterableDir{ .dir = try self.openDirZ(&sub_path_c, args, true) }; | |
| 1507 | 1572 | } |
| 1508 | 1573 | } |
| 1509 | 1574 | |
| ... | ... | @@ -1556,13 +1621,13 @@ pub const Dir = struct { |
| 1556 | 1621 | } |
| 1557 | 1622 | |
| 1558 | 1623 | /// Same as `openDir` except the parameter is null-terminated. |
| 1559 | pub fn openDirZ(self: Dir, sub_path_c: [*:0]const u8, args: OpenDirOptions) OpenError!Dir { | |
| 1624 | pub fn openDirZ(self: Dir, sub_path_c: [*:0]const u8, args: OpenDirOptions, iterable: bool) OpenError!Dir { | |
| 1560 | 1625 | if (builtin.os.tag == .windows) { |
| 1561 | 1626 | const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path_c); |
| 1562 | 1627 | return self.openDirW(sub_path_w.span().ptr, args); |
| 1563 | 1628 | } |
| 1564 | 1629 | const symlink_flags: u32 = if (args.no_follow) os.O.NOFOLLOW else 0x0; |
| 1565 | if (!args.iterate) { | |
| 1630 | if (!iterable) { | |
| 1566 | 1631 | const O_PATH = if (@hasDecl(os.O, "PATH")) os.O.PATH else 0; |
| 1567 | 1632 | return self.openDirFlagsZ(sub_path_c, os.O.DIRECTORY | os.O.RDONLY | os.O.CLOEXEC | O_PATH | symlink_flags); |
| 1568 | 1633 | } else { |
| ... | ... | @@ -1572,13 +1637,14 @@ pub const Dir = struct { |
| 1572 | 1637 | |
| 1573 | 1638 | /// Same as `openDir` except the path parameter is WTF-16 encoded, NT-prefixed. |
| 1574 | 1639 | /// This function asserts the target OS is Windows. |
| 1575 | pub fn openDirW(self: Dir, sub_path_w: [*:0]const u16, args: OpenDirOptions) OpenError!Dir { | |
| 1640 | pub fn openDirW(self: Dir, sub_path_w: [*:0]const u16, args: OpenDirOptions, iterable: bool) OpenError!Dir { | |
| 1576 | 1641 | const w = os.windows; |
| 1577 | 1642 | // TODO remove some of these flags if args.access_sub_paths is false |
| 1578 | 1643 | const base_flags = w.STANDARD_RIGHTS_READ | w.FILE_READ_ATTRIBUTES | w.FILE_READ_EA | |
| 1579 | 1644 | w.SYNCHRONIZE | w.FILE_TRAVERSE; |
| 1580 | const flags: u32 = if (args.iterate) base_flags | w.FILE_LIST_DIRECTORY else base_flags; | |
| 1581 | return self.openDirAccessMaskW(sub_path_w, flags, args.no_follow); | |
| 1645 | const flags: u32 = if (iterable) base_flags | w.FILE_LIST_DIRECTORY else base_flags; | |
| 1646 | var dir = try self.openDirAccessMaskW(sub_path_w, flags, args.no_follow); | |
| 1647 | return dir; | |
| 1582 | 1648 | } |
| 1583 | 1649 | |
| 1584 | 1650 | /// `flags` must contain `os.O.DIRECTORY`. |
| ... | ... | @@ -1958,7 +2024,7 @@ pub const Dir = struct { |
| 1958 | 2024 | error.Unexpected, |
| 1959 | 2025 | => |e| return e, |
| 1960 | 2026 | } |
| 1961 | var dir = self.openDir(sub_path, .{ .iterate = true, .no_follow = true }) catch |err| switch (err) { | |
| 2027 | var iterable_dir = self.openIterableDir(sub_path, .{ .no_follow = true }) catch |err| switch (err) { | |
| 1962 | 2028 | error.NotDir => { |
| 1963 | 2029 | if (got_access_denied) { |
| 1964 | 2030 | return error.AccessDenied; |
| ... | ... | @@ -1984,11 +2050,11 @@ pub const Dir = struct { |
| 1984 | 2050 | error.DeviceBusy, |
| 1985 | 2051 | => |e| return e, |
| 1986 | 2052 | }; |
| 1987 | var cleanup_dir_parent: ?Dir = null; | |
| 2053 | var cleanup_dir_parent: ?IterableDir = null; | |
| 1988 | 2054 | defer if (cleanup_dir_parent) |*d| d.close(); |
| 1989 | 2055 | |
| 1990 | 2056 | var cleanup_dir = true; |
| 1991 | defer if (cleanup_dir) dir.close(); | |
| 2057 | defer if (cleanup_dir) iterable_dir.close(); | |
| 1992 | 2058 | |
| 1993 | 2059 | // Valid use of MAX_PATH_BYTES because dir_name_buf will only |
| 1994 | 2060 | // ever store a single path component that was returned from the |
| ... | ... | @@ -2001,9 +2067,9 @@ pub const Dir = struct { |
| 2001 | 2067 | // open it, and close the original directory. Repeat. Then start the entire operation over. |
| 2002 | 2068 | |
| 2003 | 2069 | scan_dir: while (true) { |
| 2004 | var dir_it = dir.iterate(); | |
| 2070 | var dir_it = iterable_dir.iterate(); | |
| 2005 | 2071 | while (try dir_it.next()) |entry| { |
| 2006 | if (dir.deleteFile(entry.name)) { | |
| 2072 | if (iterable_dir.dir.deleteFile(entry.name)) { | |
| 2007 | 2073 | continue; |
| 2008 | 2074 | } else |err| switch (err) { |
| 2009 | 2075 | error.FileNotFound => continue, |
| ... | ... | @@ -2026,7 +2092,7 @@ pub const Dir = struct { |
| 2026 | 2092 | => |e| return e, |
| 2027 | 2093 | } |
| 2028 | 2094 | |
| 2029 | const new_dir = dir.openDir(entry.name, .{ .iterate = true, .no_follow = true }) catch |err| switch (err) { | |
| 2095 | const new_dir = iterable_dir.dir.openIterableDir(entry.name, .{ .no_follow = true }) catch |err| switch (err) { | |
| 2030 | 2096 | error.NotDir => { |
| 2031 | 2097 | if (got_access_denied) { |
| 2032 | 2098 | return error.AccessDenied; |
| ... | ... | @@ -2053,19 +2119,19 @@ pub const Dir = struct { |
| 2053 | 2119 | => |e| return e, |
| 2054 | 2120 | }; |
| 2055 | 2121 | if (cleanup_dir_parent) |*d| d.close(); |
| 2056 | cleanup_dir_parent = dir; | |
| 2057 | dir = new_dir; | |
| 2122 | cleanup_dir_parent = iterable_dir; | |
| 2123 | iterable_dir = new_dir; | |
| 2058 | 2124 | mem.copy(u8, &dir_name_buf, entry.name); |
| 2059 | 2125 | dir_name = dir_name_buf[0..entry.name.len]; |
| 2060 | 2126 | continue :scan_dir; |
| 2061 | 2127 | } |
| 2062 | 2128 | // Reached the end of the directory entries, which means we successfully deleted all of them. |
| 2063 | 2129 | // Now to remove the directory itself. |
| 2064 | dir.close(); | |
| 2130 | iterable_dir.close(); | |
| 2065 | 2131 | cleanup_dir = false; |
| 2066 | 2132 | |
| 2067 | 2133 | if (cleanup_dir_parent) |d| { |
| 2068 | d.deleteDir(dir_name) catch |err| switch (err) { | |
| 2134 | d.dir.deleteDir(dir_name) catch |err| switch (err) { | |
| 2069 | 2135 | // These two things can happen due to file system race conditions. |
| 2070 | 2136 | error.FileNotFound, error.DirNotEmpty => continue :start_over, |
| 2071 | 2137 | else => |e| return e, |
| ... | ... | @@ -2246,37 +2312,6 @@ pub const Dir = struct { |
| 2246 | 2312 | return file.stat(); |
| 2247 | 2313 | } |
| 2248 | 2314 | |
| 2249 | pub const ChmodError = File.ChmodError; | |
| 2250 | ||
| 2251 | /// Changes the mode of the directory. | |
| 2252 | /// The process must have the correct privileges in order to do this | |
| 2253 | /// successfully, or must have the effective user ID matching the owner | |
| 2254 | /// of the directory. Additionally, the directory must have been opened | |
| 2255 | /// with `OpenDirOptions{ .iterate = true }`. | |
| 2256 | pub fn chmod(self: Dir, new_mode: File.Mode) ChmodError!void { | |
| 2257 | const file: File = .{ | |
| 2258 | .handle = self.fd, | |
| 2259 | .capable_io_mode = .blocking, | |
| 2260 | }; | |
| 2261 | try file.chmod(new_mode); | |
| 2262 | } | |
| 2263 | ||
| 2264 | /// Changes the owner and group of the directory. | |
| 2265 | /// The process must have the correct privileges in order to do this | |
| 2266 | /// successfully. The group may be changed by the owner of the directory to | |
| 2267 | /// any group of which the owner is a member. Additionally, the directory | |
| 2268 | /// must have been opened with `OpenDirOptions{ .iterate = true }`. If the | |
| 2269 | /// owner or group is specified as `null`, the ID is not changed. | |
| 2270 | pub fn chown(self: Dir, owner: ?File.Uid, group: ?File.Gid) ChownError!void { | |
| 2271 | const file: File = .{ | |
| 2272 | .handle = self.fd, | |
| 2273 | .capable_io_mode = .blocking, | |
| 2274 | }; | |
| 2275 | try file.chown(owner, group); | |
| 2276 | } | |
| 2277 | ||
| 2278 | pub const ChownError = File.ChownError; | |
| 2279 | ||
| 2280 | 2315 | const Permissions = File.Permissions; |
| 2281 | 2316 | pub const SetPermissionsError = File.SetPermissionsError; |
| 2282 | 2317 |
lib/std/fs/test.zig+30-28| ... | ... | @@ -8,8 +8,10 @@ const wasi = std.os.wasi; |
| 8 | 8 | |
| 9 | 9 | const ArenaAllocator = std.heap.ArenaAllocator; |
| 10 | 10 | const Dir = std.fs.Dir; |
| 11 | const IterableDir = std.fs.IterableDir; | |
| 11 | 12 | const File = std.fs.File; |
| 12 | 13 | const tmpDir = testing.tmpDir; |
| 14 | const tmpIterableDir = testing.tmpIterableDir; | |
| 13 | 15 | |
| 14 | 16 | test "Dir.readLink" { |
| 15 | 17 | var tmp = tmpDir(.{}); |
| ... | ... | @@ -155,44 +157,44 @@ fn testReadLinkAbsolute(target_path: []const u8, symlink_path: []const u8) !void |
| 155 | 157 | } |
| 156 | 158 | |
| 157 | 159 | test "Dir.Iterator" { |
| 158 | var tmp_dir = tmpDir(.{ .iterate = true }); | |
| 160 | var tmp_dir = tmpIterableDir(.{}); | |
| 159 | 161 | defer tmp_dir.cleanup(); |
| 160 | 162 | |
| 161 | 163 | // First, create a couple of entries to iterate over. |
| 162 | const file = try tmp_dir.dir.createFile("some_file", .{}); | |
| 164 | const file = try tmp_dir.iterable_dir.dir.createFile("some_file", .{}); | |
| 163 | 165 | file.close(); |
| 164 | 166 | |
| 165 | try tmp_dir.dir.makeDir("some_dir"); | |
| 167 | try tmp_dir.iterable_dir.dir.makeDir("some_dir"); | |
| 166 | 168 | |
| 167 | 169 | var arena = ArenaAllocator.init(testing.allocator); |
| 168 | 170 | defer arena.deinit(); |
| 169 | 171 | const allocator = arena.allocator(); |
| 170 | 172 | |
| 171 | var entries = std.ArrayList(Dir.Entry).init(allocator); | |
| 173 | var entries = std.ArrayList(IterableDir.Entry).init(allocator); | |
| 172 | 174 | |
| 173 | 175 | // Create iterator. |
| 174 | var iter = tmp_dir.dir.iterate(); | |
| 176 | var iter = tmp_dir.iterable_dir.iterate(); | |
| 175 | 177 | while (try iter.next()) |entry| { |
| 176 | 178 | // We cannot just store `entry` as on Windows, we're re-using the name buffer |
| 177 | 179 | // which means we'll actually share the `name` pointer between entries! |
| 178 | 180 | const name = try allocator.dupe(u8, entry.name); |
| 179 | try entries.append(Dir.Entry{ .name = name, .kind = entry.kind }); | |
| 181 | try entries.append(.{ .name = name, .kind = entry.kind }); | |
| 180 | 182 | } |
| 181 | 183 | |
| 182 | 184 | try testing.expect(entries.items.len == 2); // note that the Iterator skips '.' and '..' |
| 183 | try testing.expect(contains(&entries, Dir.Entry{ .name = "some_file", .kind = Dir.Entry.Kind.File })); | |
| 184 | try testing.expect(contains(&entries, Dir.Entry{ .name = "some_dir", .kind = Dir.Entry.Kind.Directory })); | |
| 185 | try testing.expect(contains(&entries, .{ .name = "some_file", .kind = .File })); | |
| 186 | try testing.expect(contains(&entries, .{ .name = "some_dir", .kind = .Directory })); | |
| 185 | 187 | } |
| 186 | 188 | |
| 187 | 189 | test "Dir.Iterator twice" { |
| 188 | var tmp_dir = tmpDir(.{ .iterate = true }); | |
| 190 | var tmp_dir = tmpIterableDir(.{}); | |
| 189 | 191 | defer tmp_dir.cleanup(); |
| 190 | 192 | |
| 191 | 193 | // First, create a couple of entries to iterate over. |
| 192 | const file = try tmp_dir.dir.createFile("some_file", .{}); | |
| 194 | const file = try tmp_dir.iterable_dir.dir.createFile("some_file", .{}); | |
| 193 | 195 | file.close(); |
| 194 | 196 | |
| 195 | try tmp_dir.dir.makeDir("some_dir"); | |
| 197 | try tmp_dir.iterable_dir.dir.makeDir("some_dir"); | |
| 196 | 198 | |
| 197 | 199 | var arena = ArenaAllocator.init(testing.allocator); |
| 198 | 200 | defer arena.deinit(); |
| ... | ... | @@ -200,28 +202,28 @@ test "Dir.Iterator twice" { |
| 200 | 202 | |
| 201 | 203 | var i: u8 = 0; |
| 202 | 204 | while (i < 2) : (i += 1) { |
| 203 | var entries = std.ArrayList(Dir.Entry).init(allocator); | |
| 205 | var entries = std.ArrayList(IterableDir.Entry).init(allocator); | |
| 204 | 206 | |
| 205 | 207 | // Create iterator. |
| 206 | var iter = tmp_dir.dir.iterate(); | |
| 208 | var iter = tmp_dir.iterable_dir.iterate(); | |
| 207 | 209 | while (try iter.next()) |entry| { |
| 208 | 210 | // We cannot just store `entry` as on Windows, we're re-using the name buffer |
| 209 | 211 | // which means we'll actually share the `name` pointer between entries! |
| 210 | 212 | const name = try allocator.dupe(u8, entry.name); |
| 211 | try entries.append(Dir.Entry{ .name = name, .kind = entry.kind }); | |
| 213 | try entries.append(.{ .name = name, .kind = entry.kind }); | |
| 212 | 214 | } |
| 213 | 215 | |
| 214 | 216 | try testing.expect(entries.items.len == 2); // note that the Iterator skips '.' and '..' |
| 215 | try testing.expect(contains(&entries, Dir.Entry{ .name = "some_file", .kind = Dir.Entry.Kind.File })); | |
| 216 | try testing.expect(contains(&entries, Dir.Entry{ .name = "some_dir", .kind = Dir.Entry.Kind.Directory })); | |
| 217 | try testing.expect(contains(&entries, .{ .name = "some_file", .kind = .File })); | |
| 218 | try testing.expect(contains(&entries, .{ .name = "some_dir", .kind = .Directory })); | |
| 217 | 219 | } |
| 218 | 220 | } |
| 219 | 221 | |
| 220 | fn entryEql(lhs: Dir.Entry, rhs: Dir.Entry) bool { | |
| 222 | fn entryEql(lhs: IterableDir.Entry, rhs: IterableDir.Entry) bool { | |
| 221 | 223 | return mem.eql(u8, lhs.name, rhs.name) and lhs.kind == rhs.kind; |
| 222 | 224 | } |
| 223 | 225 | |
| 224 | fn contains(entries: *const std.ArrayList(Dir.Entry), el: Dir.Entry) bool { | |
| 226 | fn contains(entries: *const std.ArrayList(IterableDir.Entry), el: IterableDir.Entry) bool { | |
| 225 | 227 | for (entries.items) |entry| { |
| 226 | 228 | if (entryEql(entry, el)) return true; |
| 227 | 229 | } |
| ... | ... | @@ -985,7 +987,7 @@ test "walker" { |
| 985 | 987 | if (builtin.os.tag == .wasi and builtin.link_libc) return error.SkipZigTest; |
| 986 | 988 | if (builtin.os.tag == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/"); |
| 987 | 989 | |
| 988 | var tmp = tmpDir(.{ .iterate = true }); | |
| 990 | var tmp = tmpIterableDir(.{}); | |
| 989 | 991 | defer tmp.cleanup(); |
| 990 | 992 | |
| 991 | 993 | // iteration order of walker is undefined, so need lookup maps to check against |
| ... | ... | @@ -1011,10 +1013,10 @@ test "walker" { |
| 1011 | 1013 | }); |
| 1012 | 1014 | |
| 1013 | 1015 | for (expected_paths.kvs) |kv| { |
| 1014 | try tmp.dir.makePath(kv.key); | |
| 1016 | try tmp.iterable_dir.dir.makePath(kv.key); | |
| 1015 | 1017 | } |
| 1016 | 1018 | |
| 1017 | var walker = try tmp.dir.walk(testing.allocator); | |
| 1019 | var walker = try tmp.iterable_dir.walk(testing.allocator); | |
| 1018 | 1020 | defer walker.deinit(); |
| 1019 | 1021 | |
| 1020 | 1022 | var num_walked: usize = 0; |
| ... | ... | @@ -1121,11 +1123,11 @@ test "chmod" { |
| 1121 | 1123 | try testing.expect((try file.stat()).mode & 0o7777 == 0o644); |
| 1122 | 1124 | |
| 1123 | 1125 | try tmp.dir.makeDir("test_dir"); |
| 1124 | var dir = try tmp.dir.openDir("test_dir", .{ .iterate = true }); | |
| 1125 | defer dir.close(); | |
| 1126 | var iterable_dir = try tmp.dir.openIterableDir("test_dir", .{}); | |
| 1127 | defer iterable_dir.close(); | |
| 1126 | 1128 | |
| 1127 | try dir.chmod(0o700); | |
| 1128 | try testing.expect((try dir.stat()).mode & 0o7777 == 0o700); | |
| 1129 | try iterable_dir.chmod(0o700); | |
| 1130 | try testing.expect((try iterable_dir.dir.stat()).mode & 0o7777 == 0o700); | |
| 1129 | 1131 | } |
| 1130 | 1132 | |
| 1131 | 1133 | test "chown" { |
| ... | ... | @@ -1141,9 +1143,9 @@ test "chown" { |
| 1141 | 1143 | |
| 1142 | 1144 | try tmp.dir.makeDir("test_dir"); |
| 1143 | 1145 | |
| 1144 | var dir = try tmp.dir.openDir("test_dir", .{ .iterate = true }); | |
| 1145 | defer dir.close(); | |
| 1146 | try dir.chown(null, null); | |
| 1146 | var iterable_dir = try tmp.dir.openIterableDir("test_dir", .{}); | |
| 1147 | defer iterable_dir.close(); | |
| 1148 | try iterable_dir.chown(null, null); | |
| 1147 | 1149 | } |
| 1148 | 1150 | |
| 1149 | 1151 | test "File.Metadata" { |
lib/std/os.zig+2-2| ... | ... | @@ -308,7 +308,7 @@ pub fn fchmod(fd: fd_t, mode: mode_t) FChmodError!void { |
| 308 | 308 | switch (system.getErrno(res)) { |
| 309 | 309 | .SUCCESS => return, |
| 310 | 310 | .INTR => continue, |
| 311 | .BADF => unreachable, // Can be reached if the fd refers to a directory opened without `OpenDirOptions{ .iterate = true }` | |
| 311 | .BADF => unreachable, // Can be reached if the fd refers to a non-iterable directory. | |
| 312 | 312 | |
| 313 | 313 | .FAULT => unreachable, |
| 314 | 314 | .INVAL => unreachable, |
| ... | ... | @@ -349,7 +349,7 @@ pub fn fchown(fd: fd_t, owner: ?uid_t, group: ?gid_t) FChownError!void { |
| 349 | 349 | switch (system.getErrno(res)) { |
| 350 | 350 | .SUCCESS => return, |
| 351 | 351 | .INTR => continue, |
| 352 | .BADF => unreachable, // Can be reached if the fd refers to a directory opened without `OpenDirOptions{ .iterate = true }` | |
| 352 | .BADF => unreachable, // Can be reached if the fd refers to a non-iterable directory. | |
| 353 | 353 | |
| 354 | 354 | .FAULT => unreachable, |
| 355 | 355 | .INVAL => unreachable, |
lib/std/testing.zig+38| ... | ... | @@ -363,6 +363,22 @@ pub const TmpDir = struct { |
| 363 | 363 | } |
| 364 | 364 | }; |
| 365 | 365 | |
| 366 | pub const TmpIterableDir = struct { | |
| 367 | iterable_dir: std.fs.IterableDir, | |
| 368 | parent_dir: std.fs.Dir, | |
| 369 | sub_path: [sub_path_len]u8, | |
| 370 | ||
| 371 | const random_bytes_count = 12; | |
| 372 | const sub_path_len = std.fs.base64_encoder.calcSize(random_bytes_count); | |
| 373 | ||
| 374 | pub fn cleanup(self: *TmpIterableDir) void { | |
| 375 | self.iterable_dir.close(); | |
| 376 | self.parent_dir.deleteTree(&self.sub_path) catch {}; | |
| 377 | self.parent_dir.close(); | |
| 378 | self.* = undefined; | |
| 379 | } | |
| 380 | }; | |
| 381 | ||
| 366 | 382 | fn getCwdOrWasiPreopen() std.fs.Dir { |
| 367 | 383 | if (builtin.os.tag == .wasi and !builtin.link_libc) { |
| 368 | 384 | var preopens = std.fs.wasi.PreopenList.init(allocator); |
| ... | ... | @@ -400,6 +416,28 @@ pub fn tmpDir(opts: std.fs.Dir.OpenDirOptions) TmpDir { |
| 400 | 416 | }; |
| 401 | 417 | } |
| 402 | 418 | |
| 419 | pub fn tmpIterableDir(opts: std.fs.Dir.OpenDirOptions) TmpIterableDir { | |
| 420 | var random_bytes: [TmpIterableDir.random_bytes_count]u8 = undefined; | |
| 421 | std.crypto.random.bytes(&random_bytes); | |
| 422 | var sub_path: [TmpIterableDir.sub_path_len]u8 = undefined; | |
| 423 | _ = std.fs.base64_encoder.encode(&sub_path, &random_bytes); | |
| 424 | ||
| 425 | var cwd = getCwdOrWasiPreopen(); | |
| 426 | var cache_dir = cwd.makeOpenPath("zig-cache", .{}) catch | |
| 427 | @panic("unable to make tmp dir for testing: unable to make and open zig-cache dir"); | |
| 428 | defer cache_dir.close(); | |
| 429 | var parent_dir = cache_dir.makeOpenPath("tmp", .{}) catch | |
| 430 | @panic("unable to make tmp dir for testing: unable to make and open zig-cache/tmp dir"); | |
| 431 | var dir = parent_dir.makeOpenPathIterable(&sub_path, opts) catch | |
| 432 | @panic("unable to make tmp dir for testing: unable to make and open the tmp dir"); | |
| 433 | ||
| 434 | return .{ | |
| 435 | .iterable_dir = dir, | |
| 436 | .parent_dir = parent_dir, | |
| 437 | .sub_path = sub_path, | |
| 438 | }; | |
| 439 | } | |
| 440 | ||
| 403 | 441 | test "expectEqual nested array" { |
| 404 | 442 | const a = [2][2]f32{ |
| 405 | 443 | [_]f32{ 1.0, 0.0 }, |
src/main.zig+6-6| ... | ... | @@ -4212,13 +4212,13 @@ fn fmtPathDir( |
| 4212 | 4212 | parent_dir: fs.Dir, |
| 4213 | 4213 | parent_sub_path: []const u8, |
| 4214 | 4214 | ) FmtError!void { |
| 4215 | var dir = try parent_dir.openDir(parent_sub_path, .{ .iterate = true }); | |
| 4216 | defer dir.close(); | |
| 4215 | var iterable_dir = try parent_dir.openIterableDir(parent_sub_path, .{}); | |
| 4216 | defer iterable_dir.close(); | |
| 4217 | 4217 | |
| 4218 | const stat = try dir.stat(); | |
| 4218 | const stat = try iterable_dir.dir.stat(); | |
| 4219 | 4219 | if (try fmt.seen.fetchPut(stat.inode, {})) |_| return; |
| 4220 | 4220 | |
| 4221 | var dir_it = dir.iterate(); | |
| 4221 | var dir_it = iterable_dir.iterate(); | |
| 4222 | 4222 | while (try dir_it.next()) |entry| { |
| 4223 | 4223 | const is_dir = entry.kind == .Directory; |
| 4224 | 4224 | |
| ... | ... | @@ -4229,9 +4229,9 @@ fn fmtPathDir( |
| 4229 | 4229 | defer fmt.gpa.free(full_path); |
| 4230 | 4230 | |
| 4231 | 4231 | if (is_dir) { |
| 4232 | try fmtPathDir(fmt, full_path, check_mode, dir, entry.name); | |
| 4232 | try fmtPathDir(fmt, full_path, check_mode, iterable_dir.dir, entry.name); | |
| 4233 | 4233 | } else { |
| 4234 | fmtPathFile(fmt, full_path, check_mode, dir, entry.name) catch |err| { | |
| 4234 | fmtPathFile(fmt, full_path, check_mode, iterable_dir.dir, entry.name) catch |err| { | |
| 4235 | 4235 | warn("unable to format '{s}': {s}", .{ full_path, @errorName(err) }); |
| 4236 | 4236 | fmt.any_error = true; |
| 4237 | 4237 | return; |
src/test.zig+5-5| ... | ... | @@ -54,7 +54,7 @@ test { |
| 54 | 54 | std.fs.path.dirname(@src().file).?, "..", "test", "cases", |
| 55 | 55 | }); |
| 56 | 56 | |
| 57 | var dir = try std.fs.cwd().openDir(dir_path, .{ .iterate = true }); | |
| 57 | var dir = try std.fs.cwd().openIterableDir(dir_path, .{}); | |
| 58 | 58 | defer dir.close(); |
| 59 | 59 | |
| 60 | 60 | ctx.addTestCasesFromDir(dir); |
| ... | ... | @@ -1080,7 +1080,7 @@ pub const TestContext = struct { |
| 1080 | 1080 | /// Each file should include a test manifest as a contiguous block of comments at |
| 1081 | 1081 | /// the end of the file. The first line should be the test type, followed by a set of |
| 1082 | 1082 | /// key-value config values, followed by a blank line, then the expected output. |
| 1083 | pub fn addTestCasesFromDir(ctx: *TestContext, dir: std.fs.Dir) void { | |
| 1083 | pub fn addTestCasesFromDir(ctx: *TestContext, dir: std.fs.IterableDir) void { | |
| 1084 | 1084 | var current_file: []const u8 = "none"; |
| 1085 | 1085 | ctx.addTestCasesFromDirInner(dir, &current_file) catch |err| { |
| 1086 | 1086 | std.debug.panic("test harness failed to process file '{s}': {s}\n", .{ |
| ... | ... | @@ -1091,12 +1091,12 @@ pub const TestContext = struct { |
| 1091 | 1091 | |
| 1092 | 1092 | fn addTestCasesFromDirInner( |
| 1093 | 1093 | ctx: *TestContext, |
| 1094 | dir: std.fs.Dir, | |
| 1094 | iterable_dir: std.fs.IterableDir, | |
| 1095 | 1095 | /// This is kept up to date with the currently being processed file so |
| 1096 | 1096 | /// that if any errors occur the caller knows it happened during this file. |
| 1097 | 1097 | current_file: *[]const u8, |
| 1098 | 1098 | ) !void { |
| 1099 | var it = try dir.walk(ctx.arena); | |
| 1099 | var it = try iterable_dir.walk(ctx.arena); | |
| 1100 | 1100 | var filenames = std.ArrayList([]const u8).init(ctx.arena); |
| 1101 | 1101 | |
| 1102 | 1102 | while (try it.next()) |entry| { |
| ... | ... | @@ -1123,7 +1123,7 @@ pub const TestContext = struct { |
| 1123 | 1123 | current_file.* = filename; |
| 1124 | 1124 | |
| 1125 | 1125 | const max_file_size = 10 * 1024 * 1024; |
| 1126 | const src = try dir.readFileAllocOptions(ctx.arena, filename, max_file_size, null, 1, 0); | |
| 1126 | const src = try iterable_dir.dir.readFileAllocOptions(ctx.arena, filename, max_file_size, null, 1, 0); | |
| 1127 | 1127 | |
| 1128 | 1128 | // Parse the manifest |
| 1129 | 1129 | var manifest = try TestManifest.parse(ctx.arena, src); |
tools/process_headers.zig+3-3| ... | ... | @@ -381,14 +381,14 @@ pub fn main() !void { |
| 381 | 381 | try dir_stack.append(target_include_dir); |
| 382 | 382 | |
| 383 | 383 | while (dir_stack.popOrNull()) |full_dir_name| { |
| 384 | var dir = std.fs.cwd().openDir(full_dir_name, .{ .iterate = true }) catch |err| switch (err) { | |
| 384 | var iterable_dir = std.fs.cwd().openIterableDir(full_dir_name, .{}) catch |err| switch (err) { | |
| 385 | 385 | error.FileNotFound => continue :search, |
| 386 | 386 | error.AccessDenied => continue :search, |
| 387 | 387 | else => return err, |
| 388 | 388 | }; |
| 389 | defer dir.close(); | |
| 389 | defer iterable_dir.close(); | |
| 390 | 390 | |
| 391 | var dir_it = dir.iterate(); | |
| 391 | var dir_it = iterable_dir.iterate(); | |
| 392 | 392 | |
| 393 | 393 | while (try dir_it.next()) |entry| { |
| 394 | 394 | const full_path = try std.fs.path.join(allocator, &[_][]const u8{ full_dir_name, entry.name }); |
tools/update-license-headers.zig+4-4| ... | ... | @@ -14,9 +14,9 @@ pub fn main() !void { |
| 14 | 14 | |
| 15 | 15 | const args = try std.process.argsAlloc(arena); |
| 16 | 16 | const path_to_walk = args[1]; |
| 17 | const dir = try std.fs.cwd().openDir(path_to_walk, .{ .iterate = true }); | |
| 17 | const iterable_dir = try std.fs.cwd().openIterableDir(path_to_walk, .{}); | |
| 18 | 18 | |
| 19 | var walker = try dir.walk(arena); | |
| 19 | var walker = try iterable_dir.walk(arena); | |
| 20 | 20 | defer walker.deinit(); |
| 21 | 21 | |
| 22 | 22 | var buffer: [500]u8 = undefined; |
| ... | ... | @@ -30,7 +30,7 @@ pub fn main() !void { |
| 30 | 30 | node.activate(); |
| 31 | 31 | defer node.end(); |
| 32 | 32 | |
| 33 | const source = try dir.readFileAlloc(arena, entry.path, 20 * 1024 * 1024); | |
| 33 | const source = try iterable_dir.dir.readFileAlloc(arena, entry.path, 20 * 1024 * 1024); | |
| 34 | 34 | if (!std.mem.startsWith(u8, source, expected_header)) { |
| 35 | 35 | std.debug.print("no match: {s}\n", .{entry.path}); |
| 36 | 36 | continue; |
| ... | ... | @@ -42,6 +42,6 @@ pub fn main() !void { |
| 42 | 42 | std.mem.copy(u8, new_source, new_header); |
| 43 | 43 | std.mem.copy(u8, new_source[new_header.len..], truncated_source); |
| 44 | 44 | |
| 45 | try dir.writeFile(entry.path, new_source); | |
| 45 | try iterable_dir.dir.writeFile(entry.path, new_source); | |
| 46 | 46 | } |
| 47 | 47 | } |
tools/update-linux-headers.zig+3-3| ... | ... | @@ -181,14 +181,14 @@ pub fn main() !void { |
| 181 | 181 | try dir_stack.append(target_include_dir); |
| 182 | 182 | |
| 183 | 183 | while (dir_stack.popOrNull()) |full_dir_name| { |
| 184 | var dir = std.fs.cwd().openDir(full_dir_name, .{ .iterate = true }) catch |err| switch (err) { | |
| 184 | var iterable_dir = std.fs.cwd().openIterableDir(full_dir_name, .{}) catch |err| switch (err) { | |
| 185 | 185 | error.FileNotFound => continue :search, |
| 186 | 186 | error.AccessDenied => continue :search, |
| 187 | 187 | else => return err, |
| 188 | 188 | }; |
| 189 | defer dir.close(); | |
| 189 | defer iterable_dir.close(); | |
| 190 | 190 | |
| 191 | var dir_it = dir.iterate(); | |
| 191 | var dir_it = iterable_dir.iterate(); | |
| 192 | 192 | |
| 193 | 193 | while (try dir_it.next()) |entry| { |
| 194 | 194 | const full_path = try std.fs.path.join(arena, &[_][]const u8{ full_dir_name, entry.name }); |
tools/update_glibc.zig+5-5| ... | ... | @@ -41,7 +41,7 @@ pub fn main() !void { |
| 41 | 41 | |
| 42 | 42 | const dest_dir_path = try std.fmt.allocPrint(arena, "{s}/lib/libc/glibc", .{zig_src_path}); |
| 43 | 43 | |
| 44 | var dest_dir = fs.cwd().openDir(dest_dir_path, .{ .iterate = true }) catch |err| { | |
| 44 | var dest_dir = fs.cwd().openIterableDir(dest_dir_path, .{}) catch |err| { | |
| 45 | 45 | fatal("unable to open destination directory '{s}': {s}", .{ |
| 46 | 46 | dest_dir_path, @errorName(err), |
| 47 | 47 | }); |
| ... | ... | @@ -63,14 +63,14 @@ pub fn main() !void { |
| 63 | 63 | if (mem.eql(u8, entry.path, p)) continue :walk; |
| 64 | 64 | } |
| 65 | 65 | |
| 66 | glibc_src_dir.copyFile(entry.path, dest_dir, entry.path, .{}) catch |err| { | |
| 66 | glibc_src_dir.copyFile(entry.path, dest_dir.dir, entry.path, .{}) catch |err| { | |
| 67 | 67 | log.warn("unable to copy '{s}/{s}' to '{s}/{s}': {s}", .{ |
| 68 | 68 | glibc_src_path, entry.path, |
| 69 | 69 | dest_dir_path, entry.path, |
| 70 | 70 | @errorName(err), |
| 71 | 71 | }); |
| 72 | 72 | if (err == error.FileNotFound) { |
| 73 | try dest_dir.deleteFile(entry.path); | |
| 73 | try dest_dir.dir.deleteFile(entry.path); | |
| 74 | 74 | } |
| 75 | 75 | }; |
| 76 | 76 | } |
| ... | ... | @@ -79,7 +79,7 @@ pub fn main() !void { |
| 79 | 79 | // Warn about duplicated files inside glibc/include/* that can be omitted |
| 80 | 80 | // because they are already in generic-glibc/*. |
| 81 | 81 | |
| 82 | var include_dir = dest_dir.openDir("include", .{ .iterate = true }) catch |err| { | |
| 82 | var include_dir = dest_dir.dir.openIterableDir("include", .{}) catch |err| { | |
| 83 | 83 | fatal("unable to open directory '{s}/include': {s}", .{ |
| 84 | 84 | dest_dir_path, @errorName(err), |
| 85 | 85 | }); |
| ... | ... | @@ -116,7 +116,7 @@ pub fn main() !void { |
| 116 | 116 | generic_glibc_path, entry.path, @errorName(e), |
| 117 | 117 | }), |
| 118 | 118 | }; |
| 119 | const glibc_include_contents = include_dir.readFileAlloc( | |
| 119 | const glibc_include_contents = include_dir.dir.readFileAlloc( | |
| 120 | 120 | arena, |
| 121 | 121 | entry.path, |
| 122 | 122 | max_file_size, |
tools/update_spirv_features.zig+3-3| ... | ... | @@ -218,7 +218,7 @@ pub fn main() !void { |
| 218 | 218 | /// TODO: Unfortunately, neither repository contains a machine-readable list of extension dependencies. |
| 219 | 219 | fn gather_extensions(allocator: Allocator, spirv_registry_root: []const u8) ![]const []const u8 { |
| 220 | 220 | const extensions_path = try fs.path.join(allocator, &.{ spirv_registry_root, "extensions" }); |
| 221 | var extensions_dir = try fs.cwd().openDir(extensions_path, .{ .iterate = true }); | |
| 221 | var extensions_dir = try fs.cwd().openIterableDir(extensions_path, .{}); | |
| 222 | 222 | defer extensions_dir.close(); |
| 223 | 223 | |
| 224 | 224 | var extensions = std.ArrayList([]const u8).init(allocator); |
| ... | ... | @@ -227,7 +227,7 @@ fn gather_extensions(allocator: Allocator, spirv_registry_root: []const u8) ![]c |
| 227 | 227 | while (try vendor_it.next()) |vendor_entry| { |
| 228 | 228 | std.debug.assert(vendor_entry.kind == .Directory); // If this fails, the structure of SPIRV-Registry has changed. |
| 229 | 229 | |
| 230 | const vendor_dir = try extensions_dir.openDir(vendor_entry.name, .{ .iterate = true }); | |
| 230 | const vendor_dir = try extensions_dir.dir.openIterableDir(vendor_entry.name, .{}); | |
| 231 | 231 | var ext_it = vendor_dir.iterate(); |
| 232 | 232 | while (try ext_it.next()) |ext_entry| { |
| 233 | 233 | // 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 |
| 250 | 250 | // SPV_EXT_name |
| 251 | 251 | // ``` |
| 252 | 252 | |
| 253 | const ext_spec = try vendor_dir.readFileAlloc(allocator, ext_entry.name, std.math.maxInt(usize)); | |
| 253 | const ext_spec = try vendor_dir.dir.readFileAlloc(allocator, ext_entry.name, std.math.maxInt(usize)); | |
| 254 | 254 | const name_strings = "Name Strings"; |
| 255 | 255 | |
| 256 | 256 | const name_strings_offset = std.mem.indexOf(u8, ext_spec, name_strings) orelse return error.InvalidRegistry; |