| author | |
| committer | |
| log | 519ba9bb654a4d5caf7440160f018b7a3ae1e95a |
| tree | 2308d007f7e1bf1a8aed846ad4faef8e729e0598 |
| parent | e4977f3e89fcc164a4d02cd38eb066cfe1a1124f |
This reverts commit da94227f783ec3c92859c4713b80a668f1183f96, reversing
changes made to 8f943b3d33432a26b7e242c1181e4220ed400501.
I was against this change originally, but decided to approve it to keep
an open mind. After a year of trying it in practice, I firmly believe
that the previous way of doing it was better.10 files changed, 146 insertions(+), 244 deletions(-)
lib/std/fs.zig+88-146| ... | ... | @@ -310,10 +310,8 @@ pub fn renameW(old_dir: Dir, old_sub_path_w: []const u16, new_dir: Dir, new_sub_ |
| 310 | 310 | return os.renameatW(old_dir.fd, old_sub_path_w, new_dir.fd, new_sub_path_w); |
| 311 | 311 | } |
| 312 | 312 | |
| 313 | /// A directory that can be iterated. It is *NOT* legal to initialize this with a regular `Dir` | |
| 314 | /// that has been opened without iteration permission. | |
| 315 | pub const IterableDir = struct { | |
| 316 | dir: Dir, | |
| 313 | pub const Dir = struct { | |
| 314 | fd: os.fd_t, | |
| 317 | 315 | |
| 318 | 316 | pub const Entry = struct { |
| 319 | 317 | name: []const u8, |
| ... | ... | @@ -879,18 +877,18 @@ pub const IterableDir = struct { |
| 879 | 877 | else => @compileError("unimplemented"), |
| 880 | 878 | }; |
| 881 | 879 | |
| 882 | pub fn iterate(self: IterableDir) Iterator { | |
| 880 | pub fn iterate(self: Dir) Iterator { | |
| 883 | 881 | return self.iterateImpl(true); |
| 884 | 882 | } |
| 885 | 883 | |
| 886 | 884 | /// Like `iterate`, but will not reset the directory cursor before the first |
| 887 | 885 | /// iteration. This should only be used in cases where it is known that the |
| 888 | /// `IterableDir` has not had its cursor modified yet (e.g. it was just opened). | |
| 889 | pub fn iterateAssumeFirstIteration(self: IterableDir) Iterator { | |
| 886 | /// `Dir` has not had its cursor modified yet (e.g. it was just opened). | |
| 887 | pub fn iterateAssumeFirstIteration(self: Dir) Iterator { | |
| 890 | 888 | return self.iterateImpl(false); |
| 891 | 889 | } |
| 892 | 890 | |
| 893 | fn iterateImpl(self: IterableDir, first_iter_start_value: bool) Iterator { | |
| 891 | fn iterateImpl(self: Dir, first_iter_start_value: bool) Iterator { | |
| 894 | 892 | switch (builtin.os.tag) { |
| 895 | 893 | .macos, |
| 896 | 894 | .ios, |
| ... | ... | @@ -901,7 +899,7 @@ pub const IterableDir = struct { |
| 901 | 899 | .solaris, |
| 902 | 900 | .illumos, |
| 903 | 901 | => return Iterator{ |
| 904 | .dir = self.dir, | |
| 902 | .dir = self, | |
| 905 | 903 | .seek = 0, |
| 906 | 904 | .index = 0, |
| 907 | 905 | .end_index = 0, |
| ... | ... | @@ -909,14 +907,14 @@ pub const IterableDir = struct { |
| 909 | 907 | .first_iter = first_iter_start_value, |
| 910 | 908 | }, |
| 911 | 909 | .linux, .haiku => return Iterator{ |
| 912 | .dir = self.dir, | |
| 910 | .dir = self, | |
| 913 | 911 | .index = 0, |
| 914 | 912 | .end_index = 0, |
| 915 | 913 | .buf = undefined, |
| 916 | 914 | .first_iter = first_iter_start_value, |
| 917 | 915 | }, |
| 918 | 916 | .windows => return Iterator{ |
| 919 | .dir = self.dir, | |
| 917 | .dir = self, | |
| 920 | 918 | .index = 0, |
| 921 | 919 | .end_index = 0, |
| 922 | 920 | .first_iter = first_iter_start_value, |
| ... | ... | @@ -924,7 +922,7 @@ pub const IterableDir = struct { |
| 924 | 922 | .name_data = undefined, |
| 925 | 923 | }, |
| 926 | 924 | .wasi => return Iterator{ |
| 927 | .dir = self.dir, | |
| 925 | .dir = self, | |
| 928 | 926 | .cookie = os.wasi.DIRCOOKIE_START, |
| 929 | 927 | .index = 0, |
| 930 | 928 | .end_index = 0, |
| ... | ... | @@ -945,11 +943,11 @@ pub const IterableDir = struct { |
| 945 | 943 | dir: Dir, |
| 946 | 944 | basename: []const u8, |
| 947 | 945 | path: []const u8, |
| 948 | kind: IterableDir.Entry.Kind, | |
| 946 | kind: Dir.Entry.Kind, | |
| 949 | 947 | }; |
| 950 | 948 | |
| 951 | 949 | const StackItem = struct { |
| 952 | iter: IterableDir.Iterator, | |
| 950 | iter: Dir.Iterator, | |
| 953 | 951 | dirname_len: usize, |
| 954 | 952 | }; |
| 955 | 953 | |
| ... | ... | @@ -980,7 +978,7 @@ pub const IterableDir = struct { |
| 980 | 978 | } |
| 981 | 979 | try self.name_buffer.appendSlice(base.name); |
| 982 | 980 | if (base.kind == .directory) { |
| 983 | var new_dir = top.iter.dir.openIterableDir(base.name, .{}) catch |err| switch (err) { | |
| 981 | var new_dir = top.iter.dir.openDir(base.name, .{ .iterate = true }) catch |err| switch (err) { | |
| 984 | 982 | error.NameTooLong => unreachable, // no path sep in base.name |
| 985 | 983 | else => |e| return e, |
| 986 | 984 | }; |
| ... | ... | @@ -1023,10 +1021,11 @@ pub const IterableDir = struct { |
| 1023 | 1021 | }; |
| 1024 | 1022 | |
| 1025 | 1023 | /// Recursively iterates over a directory. |
| 1024 | /// `self` must have been opened with `OpenDirOptions{.iterate = true}`. | |
| 1026 | 1025 | /// Must call `Walker.deinit` when done. |
| 1027 | 1026 | /// The order of returned file system entries is undefined. |
| 1028 | 1027 | /// `self` will not be closed after walking it. |
| 1029 | pub fn walk(self: IterableDir, allocator: Allocator) !Walker { | |
| 1028 | pub fn walk(self: Dir, allocator: Allocator) !Walker { | |
| 1030 | 1029 | var name_buffer = std.ArrayList(u8).init(allocator); |
| 1031 | 1030 | errdefer name_buffer.deinit(); |
| 1032 | 1031 | |
| ... | ... | @@ -1044,49 +1043,6 @@ pub const IterableDir = struct { |
| 1044 | 1043 | }; |
| 1045 | 1044 | } |
| 1046 | 1045 | |
| 1047 | pub fn close(self: *IterableDir) void { | |
| 1048 | self.dir.close(); | |
| 1049 | self.* = undefined; | |
| 1050 | } | |
| 1051 | ||
| 1052 | pub const ChmodError = File.ChmodError; | |
| 1053 | ||
| 1054 | /// Changes the mode of the directory. | |
| 1055 | /// The process must have the correct privileges in order to do this | |
| 1056 | /// successfully, or must have the effective user ID matching the owner | |
| 1057 | /// of the directory. | |
| 1058 | pub fn chmod(self: IterableDir, new_mode: File.Mode) ChmodError!void { | |
| 1059 | const file: File = .{ | |
| 1060 | .handle = self.dir.fd, | |
| 1061 | .capable_io_mode = .blocking, | |
| 1062 | }; | |
| 1063 | try file.chmod(new_mode); | |
| 1064 | } | |
| 1065 | ||
| 1066 | /// Changes the owner and group of the directory. | |
| 1067 | /// The process must have the correct privileges in order to do this | |
| 1068 | /// successfully. The group may be changed by the owner of the directory to | |
| 1069 | /// any group of which the owner is a member. If the | |
| 1070 | /// owner or group is specified as `null`, the ID is not changed. | |
| 1071 | pub fn chown(self: IterableDir, owner: ?File.Uid, group: ?File.Gid) ChownError!void { | |
| 1072 | const file: File = .{ | |
| 1073 | .handle = self.dir.fd, | |
| 1074 | .capable_io_mode = .blocking, | |
| 1075 | }; | |
| 1076 | try file.chown(owner, group); | |
| 1077 | } | |
| 1078 | ||
| 1079 | pub const ChownError = File.ChownError; | |
| 1080 | }; | |
| 1081 | ||
| 1082 | pub const Dir = struct { | |
| 1083 | fd: os.fd_t, | |
| 1084 | ||
| 1085 | pub const iterate = @compileError("only 'IterableDir' can be iterated; 'IterableDir' can be obtained with 'openIterableDir'"); | |
| 1086 | pub const walk = @compileError("only 'IterableDir' can be walked; 'IterableDir' can be obtained with 'openIterableDir'"); | |
| 1087 | pub const chmod = @compileError("only 'IterableDir' can have its mode changed; 'IterableDir' can be obtained with 'openIterableDir'"); | |
| 1088 | pub const chown = @compileError("only 'IterableDir' can have its owner changed; 'IterableDir' can be obtained with 'openIterableDir'"); | |
| 1089 | ||
| 1090 | 1046 | pub const OpenError = error{ |
| 1091 | 1047 | FileNotFound, |
| 1092 | 1048 | NotDir, |
| ... | ... | @@ -1529,7 +1485,8 @@ pub const Dir = struct { |
| 1529 | 1485 | .windows => { |
| 1530 | 1486 | const w = os.windows; |
| 1531 | 1487 | const base_flags = w.STANDARD_RIGHTS_READ | w.FILE_READ_ATTRIBUTES | w.FILE_READ_EA | |
| 1532 | w.SYNCHRONIZE | w.FILE_TRAVERSE; | |
| 1488 | w.SYNCHRONIZE | w.FILE_TRAVERSE | | |
| 1489 | (if (open_dir_options.iterate) w.FILE_LIST_DIRECTORY else 0); | |
| 1533 | 1490 | |
| 1534 | 1491 | return self.makeOpenPathAccessMaskW(sub_path, base_flags, open_dir_options.no_follow); |
| 1535 | 1492 | }, |
| ... | ... | @@ -1545,32 +1502,6 @@ pub const Dir = struct { |
| 1545 | 1502 | }; |
| 1546 | 1503 | } |
| 1547 | 1504 | |
| 1548 | /// This function performs `makePath`, followed by `openIterableDir`. | |
| 1549 | /// If supported by the OS, this operation is atomic. It is not atomic on | |
| 1550 | /// all operating systems. | |
| 1551 | pub fn makeOpenPathIterable(self: Dir, sub_path: []const u8, open_dir_options: OpenDirOptions) !IterableDir { | |
| 1552 | return switch (builtin.os.tag) { | |
| 1553 | .windows => { | |
| 1554 | const w = os.windows; | |
| 1555 | const base_flags = w.STANDARD_RIGHTS_READ | w.FILE_READ_ATTRIBUTES | w.FILE_READ_EA | | |
| 1556 | w.SYNCHRONIZE | w.FILE_TRAVERSE | w.FILE_LIST_DIRECTORY; | |
| 1557 | ||
| 1558 | return IterableDir{ | |
| 1559 | .dir = try self.makeOpenPathAccessMaskW(sub_path, base_flags, open_dir_options.no_follow), | |
| 1560 | }; | |
| 1561 | }, | |
| 1562 | else => { | |
| 1563 | return self.openIterableDir(sub_path, open_dir_options) catch |err| switch (err) { | |
| 1564 | error.FileNotFound => { | |
| 1565 | try self.makePath(sub_path); | |
| 1566 | return self.openIterableDir(sub_path, open_dir_options); | |
| 1567 | }, | |
| 1568 | else => |e| return e, | |
| 1569 | }; | |
| 1570 | }, | |
| 1571 | }; | |
| 1572 | } | |
| 1573 | ||
| 1574 | 1505 | /// This function returns the canonicalized absolute pathname of |
| 1575 | 1506 | /// `pathname` relative to this `Dir`. If `pathname` is absolute, ignores this |
| 1576 | 1507 | /// `Dir` handle and returns the canonicalized absolute pathname of `pathname` |
| ... | ... | @@ -1706,39 +1637,28 @@ pub const Dir = struct { |
| 1706 | 1637 | /// such operations are Illegal Behavior. |
| 1707 | 1638 | access_sub_paths: bool = true, |
| 1708 | 1639 | |
| 1640 | /// `true` means the opened directory can be scanned for the files and sub-directories | |
| 1641 | /// of the result. It means the `iterate` function can be called. | |
| 1642 | iterate: bool = false, | |
| 1643 | ||
| 1709 | 1644 | /// `true` means it won't dereference the symlinks. |
| 1710 | 1645 | no_follow: bool = false, |
| 1711 | 1646 | }; |
| 1712 | 1647 | |
| 1713 | 1648 | /// Opens a directory at the given path. The directory is a system resource that remains |
| 1714 | 1649 | /// open until `close` is called on the result. |
| 1650 | /// The directory cannot be iterated unless the `iterate` option is set to `true`. | |
| 1715 | 1651 | /// |
| 1716 | 1652 | /// Asserts that the path parameter has no null bytes. |
| 1717 | 1653 | pub fn openDir(self: Dir, sub_path: []const u8, args: OpenDirOptions) OpenError!Dir { |
| 1718 | 1654 | if (builtin.os.tag == .windows) { |
| 1719 | 1655 | const sub_path_w = try os.windows.sliceToPrefixedFileW(self.fd, sub_path); |
| 1720 | return self.openDirW(sub_path_w.span().ptr, args, false); | |
| 1721 | } else if (builtin.os.tag == .wasi and !builtin.link_libc) { | |
| 1722 | return self.openDirWasi(sub_path, args); | |
| 1723 | } else { | |
| 1724 | const sub_path_c = try os.toPosixPath(sub_path); | |
| 1725 | return self.openDirZ(&sub_path_c, args, false); | |
| 1726 | } | |
| 1727 | } | |
| 1728 | ||
| 1729 | /// Opens an iterable directory at the given path. The directory is a system resource that remains | |
| 1730 | /// open until `close` is called on the result. | |
| 1731 | /// | |
| 1732 | /// Asserts that the path parameter has no null bytes. | |
| 1733 | pub fn openIterableDir(self: Dir, sub_path: []const u8, args: OpenDirOptions) OpenError!IterableDir { | |
| 1734 | if (builtin.os.tag == .windows) { | |
| 1735 | const sub_path_w = try os.windows.sliceToPrefixedFileW(self.fd, sub_path); | |
| 1736 | return IterableDir{ .dir = try self.openDirW(sub_path_w.span().ptr, args, true) }; | |
| 1656 | return .{ .dir = try self.openDirW(sub_path_w.span().ptr, args) }; | |
| 1737 | 1657 | } else if (builtin.os.tag == .wasi and !builtin.link_libc) { |
| 1738 | return IterableDir{ .dir = try self.openDirWasi(sub_path, args) }; | |
| 1658 | return .{ .dir = try self.openDirWasi(sub_path, args) }; | |
| 1739 | 1659 | } else { |
| 1740 | 1660 | const sub_path_c = try os.toPosixPath(sub_path); |
| 1741 | return IterableDir{ .dir = try self.openDirZ(&sub_path_c, args, true) }; | |
| 1661 | return .{ .dir = try self.openDirZ(&sub_path_c, args) }; | |
| 1742 | 1662 | } |
| 1743 | 1663 | } |
| 1744 | 1664 | |
| ... | ... | @@ -1790,13 +1710,13 @@ pub const Dir = struct { |
| 1790 | 1710 | } |
| 1791 | 1711 | |
| 1792 | 1712 | /// Same as `openDir` except the parameter is null-terminated. |
| 1793 | pub fn openDirZ(self: Dir, sub_path_c: [*:0]const u8, args: OpenDirOptions, iterable: bool) OpenError!Dir { | |
| 1713 | pub fn openDirZ(self: Dir, sub_path_c: [*:0]const u8, args: OpenDirOptions) OpenError!Dir { | |
| 1794 | 1714 | if (builtin.os.tag == .windows) { |
| 1795 | 1715 | const sub_path_w = try os.windows.cStrToPrefixedFileW(self.fd, sub_path_c); |
| 1796 | return self.openDirW(sub_path_w.span().ptr, args, iterable); | |
| 1716 | return self.openDirW(sub_path_w.span().ptr, args); | |
| 1797 | 1717 | } |
| 1798 | 1718 | const symlink_flags: u32 = if (args.no_follow) os.O.NOFOLLOW else 0x0; |
| 1799 | if (!iterable) { | |
| 1719 | if (!args.iterate) { | |
| 1800 | 1720 | const O_PATH = if (@hasDecl(os.O, "PATH")) os.O.PATH else 0; |
| 1801 | 1721 | return self.openDirFlagsZ(sub_path_c, os.O.DIRECTORY | os.O.RDONLY | os.O.CLOEXEC | O_PATH | symlink_flags); |
| 1802 | 1722 | } else { |
| ... | ... | @@ -1806,12 +1726,12 @@ pub const Dir = struct { |
| 1806 | 1726 | |
| 1807 | 1727 | /// Same as `openDir` except the path parameter is WTF-16 encoded, NT-prefixed. |
| 1808 | 1728 | /// This function asserts the target OS is Windows. |
| 1809 | pub fn openDirW(self: Dir, sub_path_w: [*:0]const u16, args: OpenDirOptions, iterable: bool) OpenError!Dir { | |
| 1729 | pub fn openDirW(self: Dir, sub_path_w: [*:0]const u16, args: OpenDirOptions) OpenError!Dir { | |
| 1810 | 1730 | const w = os.windows; |
| 1811 | 1731 | // TODO remove some of these flags if args.access_sub_paths is false |
| 1812 | 1732 | const base_flags = w.STANDARD_RIGHTS_READ | w.FILE_READ_ATTRIBUTES | w.FILE_READ_EA | |
| 1813 | 1733 | w.SYNCHRONIZE | w.FILE_TRAVERSE; |
| 1814 | const flags: u32 = if (iterable) base_flags | w.FILE_LIST_DIRECTORY else base_flags; | |
| 1734 | const flags: u32 = if (args.iterate) base_flags | w.FILE_LIST_DIRECTORY else base_flags; | |
| 1815 | 1735 | const dir = try self.makeOpenDirAccessMaskW(sub_path_w, flags, .{ |
| 1816 | 1736 | .no_follow = args.no_follow, |
| 1817 | 1737 | .create_disposition = w.FILE_OPEN, |
| ... | ... | @@ -2203,7 +2123,7 @@ pub const Dir = struct { |
| 2203 | 2123 | const StackItem = struct { |
| 2204 | 2124 | name: []const u8, |
| 2205 | 2125 | parent_dir: Dir, |
| 2206 | iter: IterableDir.Iterator, | |
| 2126 | iter: Dir.Iterator, | |
| 2207 | 2127 | |
| 2208 | 2128 | fn closeAll(items: []@This()) void { |
| 2209 | 2129 | for (items) |*item| item.iter.dir.close(); |
| ... | ... | @@ -2227,7 +2147,10 @@ pub const Dir = struct { |
| 2227 | 2147 | handle_entry: while (true) { |
| 2228 | 2148 | if (treat_as_dir) { |
| 2229 | 2149 | if (stack.unusedCapacitySlice().len >= 1) { |
| 2230 | var iterable_dir = top.iter.dir.openIterableDir(entry.name, .{ .no_follow = true }) catch |err| switch (err) { | |
| 2150 | var iterable_dir = top.iter.dir.openDir(entry.name, .{ | |
| 2151 | .no_follow = true, | |
| 2152 | .iterate = true, | |
| 2153 | }) catch |err| switch (err) { | |
| 2231 | 2154 | error.NotDir => { |
| 2232 | 2155 | treat_as_dir = false; |
| 2233 | 2156 | continue :handle_entry; |
| ... | ... | @@ -2318,7 +2241,10 @@ pub const Dir = struct { |
| 2318 | 2241 | var treat_as_dir = true; |
| 2319 | 2242 | handle_entry: while (true) { |
| 2320 | 2243 | if (treat_as_dir) { |
| 2321 | break :iterable_dir parent_dir.openIterableDir(name, .{ .no_follow = true }) catch |err| switch (err) { | |
| 2244 | break :iterable_dir parent_dir.openDir(name, .{ | |
| 2245 | .no_follow = true, | |
| 2246 | .iterate = true, | |
| 2247 | }) catch |err| switch (err) { | |
| 2322 | 2248 | error.NotDir => { |
| 2323 | 2249 | treat_as_dir = false; |
| 2324 | 2250 | continue :handle_entry; |
| ... | ... | @@ -2393,12 +2319,12 @@ pub const Dir = struct { |
| 2393 | 2319 | |
| 2394 | 2320 | fn deleteTreeMinStackSizeWithKindHint(self: Dir, sub_path: []const u8, kind_hint: File.Kind) DeleteTreeError!void { |
| 2395 | 2321 | start_over: while (true) { |
| 2396 | var iterable_dir = (try self.deleteTreeOpenInitialSubpath(sub_path, kind_hint)) orelse return; | |
| 2397 | var cleanup_dir_parent: ?IterableDir = null; | |
| 2322 | var dir = (try self.deleteTreeOpenInitialSubpath(sub_path, kind_hint)) orelse return; | |
| 2323 | var cleanup_dir_parent: ?Dir = null; | |
| 2398 | 2324 | defer if (cleanup_dir_parent) |*d| d.close(); |
| 2399 | 2325 | |
| 2400 | 2326 | var cleanup_dir = true; |
| 2401 | defer if (cleanup_dir) iterable_dir.close(); | |
| 2327 | defer if (cleanup_dir) dir.close(); | |
| 2402 | 2328 | |
| 2403 | 2329 | // Valid use of MAX_PATH_BYTES because dir_name_buf will only |
| 2404 | 2330 | // ever store a single path component that was returned from the |
| ... | ... | @@ -2411,12 +2337,15 @@ pub const Dir = struct { |
| 2411 | 2337 | // open it, and close the original directory. Repeat. Then start the entire operation over. |
| 2412 | 2338 | |
| 2413 | 2339 | scan_dir: while (true) { |
| 2414 | var dir_it = iterable_dir.iterateAssumeFirstIteration(); | |
| 2340 | var dir_it = dir.iterateAssumeFirstIteration(); | |
| 2415 | 2341 | dir_it: while (try dir_it.next()) |entry| { |
| 2416 | 2342 | var treat_as_dir = entry.kind == .directory; |
| 2417 | 2343 | handle_entry: while (true) { |
| 2418 | 2344 | if (treat_as_dir) { |
| 2419 | const new_dir = iterable_dir.dir.openIterableDir(entry.name, .{ .no_follow = true }) catch |err| switch (err) { | |
| 2345 | const new_dir = dir.openDir(entry.name, .{ | |
| 2346 | .no_follow = true, | |
| 2347 | .iterate = true, | |
| 2348 | }) catch |err| switch (err) { | |
| 2420 | 2349 | error.NotDir => { |
| 2421 | 2350 | treat_as_dir = false; |
| 2422 | 2351 | continue :handle_entry; |
| ... | ... | @@ -2442,14 +2371,14 @@ pub const Dir = struct { |
| 2442 | 2371 | => |e| return e, |
| 2443 | 2372 | }; |
| 2444 | 2373 | if (cleanup_dir_parent) |*d| d.close(); |
| 2445 | cleanup_dir_parent = iterable_dir; | |
| 2446 | iterable_dir = new_dir; | |
| 2374 | cleanup_dir_parent = dir; | |
| 2375 | dir = new_dir; | |
| 2447 | 2376 | const result = dir_name_buf[0..entry.name.len]; |
| 2448 | 2377 | @memcpy(result, entry.name); |
| 2449 | 2378 | dir_name = result; |
| 2450 | 2379 | continue :scan_dir; |
| 2451 | 2380 | } else { |
| 2452 | if (iterable_dir.dir.deleteFile(entry.name)) { | |
| 2381 | if (dir.deleteFile(entry.name)) { | |
| 2453 | 2382 | continue :dir_it; |
| 2454 | 2383 | } else |err| switch (err) { |
| 2455 | 2384 | error.FileNotFound => continue :dir_it, |
| ... | ... | @@ -2480,11 +2409,11 @@ pub const Dir = struct { |
| 2480 | 2409 | } |
| 2481 | 2410 | // Reached the end of the directory entries, which means we successfully deleted all of them. |
| 2482 | 2411 | // Now to remove the directory itself. |
| 2483 | iterable_dir.close(); | |
| 2412 | dir.close(); | |
| 2484 | 2413 | cleanup_dir = false; |
| 2485 | 2414 | |
| 2486 | 2415 | if (cleanup_dir_parent) |d| { |
| 2487 | d.dir.deleteDir(dir_name) catch |err| switch (err) { | |
| 2416 | d.deleteDir(dir_name) catch |err| switch (err) { | |
| 2488 | 2417 | // These two things can happen due to file system race conditions. |
| 2489 | 2418 | error.FileNotFound, error.DirNotEmpty => continue :start_over, |
| 2490 | 2419 | else => |e| return e, |
| ... | ... | @@ -2503,14 +2432,17 @@ pub const Dir = struct { |
| 2503 | 2432 | } |
| 2504 | 2433 | |
| 2505 | 2434 | /// On successful delete, returns null. |
| 2506 | fn deleteTreeOpenInitialSubpath(self: Dir, sub_path: []const u8, kind_hint: File.Kind) !?IterableDir { | |
| 2435 | fn deleteTreeOpenInitialSubpath(self: Dir, sub_path: []const u8, kind_hint: File.Kind) !?Dir { | |
| 2507 | 2436 | return iterable_dir: { |
| 2508 | 2437 | // Treat as a file by default |
| 2509 | 2438 | var treat_as_dir = kind_hint == .directory; |
| 2510 | 2439 | |
| 2511 | 2440 | handle_entry: while (true) { |
| 2512 | 2441 | if (treat_as_dir) { |
| 2513 | break :iterable_dir self.openIterableDir(sub_path, .{ .no_follow = true }) catch |err| switch (err) { | |
| 2442 | break :iterable_dir self.openDir(sub_path, .{ | |
| 2443 | .no_follow = true, | |
| 2444 | .iterate = true, | |
| 2445 | }) catch |err| switch (err) { | |
| 2514 | 2446 | error.NotDir => { |
| 2515 | 2447 | treat_as_dir = false; |
| 2516 | 2448 | continue :handle_entry; |
| ... | ... | @@ -2764,6 +2696,37 @@ pub const Dir = struct { |
| 2764 | 2696 | return Stat.fromSystem(st); |
| 2765 | 2697 | } |
| 2766 | 2698 | |
| 2699 | pub const ChmodError = File.ChmodError; | |
| 2700 | ||
| 2701 | /// Changes the mode of the directory. | |
| 2702 | /// The process must have the correct privileges in order to do this | |
| 2703 | /// successfully, or must have the effective user ID matching the owner | |
| 2704 | /// of the directory. Additionally, the directory must have been opened | |
| 2705 | /// with `OpenDirOptions{ .iterate = true }`. | |
| 2706 | pub fn chmod(self: Dir, new_mode: File.Mode) ChmodError!void { | |
| 2707 | const file: File = .{ | |
| 2708 | .handle = self.fd, | |
| 2709 | .capable_io_mode = .blocking, | |
| 2710 | }; | |
| 2711 | try file.chmod(new_mode); | |
| 2712 | } | |
| 2713 | ||
| 2714 | /// Changes the owner and group of the directory. | |
| 2715 | /// The process must have the correct privileges in order to do this | |
| 2716 | /// successfully. The group may be changed by the owner of the directory to | |
| 2717 | /// any group of which the owner is a member. Additionally, the directory | |
| 2718 | /// must have been opened with `OpenDirOptions{ .iterate = true }`. If the | |
| 2719 | /// owner or group is specified as `null`, the ID is not changed. | |
| 2720 | pub fn chown(self: Dir, owner: ?File.Uid, group: ?File.Gid) ChownError!void { | |
| 2721 | const file: File = .{ | |
| 2722 | .handle = self.fd, | |
| 2723 | .capable_io_mode = .blocking, | |
| 2724 | }; | |
| 2725 | try file.chown(owner, group); | |
| 2726 | } | |
| 2727 | ||
| 2728 | pub const ChownError = File.ChownError; | |
| 2729 | ||
| 2767 | 2730 | const Permissions = File.Permissions; |
| 2768 | 2731 | pub const SetPermissionsError = File.SetPermissionsError; |
| 2769 | 2732 | |
| ... | ... | @@ -2829,27 +2792,6 @@ pub fn openDirAbsoluteW(absolute_path_c: [*:0]const u16, flags: Dir.OpenDirOptio |
| 2829 | 2792 | return cwd().openDirW(absolute_path_c, flags, false); |
| 2830 | 2793 | } |
| 2831 | 2794 | |
| 2832 | /// Opens a directory at the given path. The directory is a system resource that remains | |
| 2833 | /// open until `close` is called on the result. | |
| 2834 | /// See `openIterableDirAbsoluteZ` for a function that accepts a null-terminated path. | |
| 2835 | /// | |
| 2836 | /// Asserts that the path parameter has no null bytes. | |
| 2837 | pub fn openIterableDirAbsolute(absolute_path: []const u8, flags: Dir.OpenDirOptions) File.OpenError!IterableDir { | |
| 2838 | assert(path.isAbsolute(absolute_path)); | |
| 2839 | return cwd().openIterableDir(absolute_path, flags); | |
| 2840 | } | |
| 2841 | ||
| 2842 | /// Same as `openIterableDirAbsolute` but the path parameter is null-terminated. | |
| 2843 | pub fn openIterableDirAbsoluteZ(absolute_path_c: [*:0]const u8, flags: Dir.OpenDirOptions) File.OpenError!IterableDir { | |
| 2844 | assert(path.isAbsoluteZ(absolute_path_c)); | |
| 2845 | return IterableDir{ .dir = try cwd().openDirZ(absolute_path_c, flags, true) }; | |
| 2846 | } | |
| 2847 | /// Same as `openIterableDirAbsolute` but the path parameter is null-terminated. | |
| 2848 | pub fn openIterableDirAbsoluteW(absolute_path_c: [*:0]const u16, flags: Dir.OpenDirOptions) File.OpenError!IterableDir { | |
| 2849 | assert(path.isAbsoluteWindowsW(absolute_path_c)); | |
| 2850 | return IterableDir{ .dir = try cwd().openDirW(absolute_path_c, flags, true) }; | |
| 2851 | } | |
| 2852 | ||
| 2853 | 2795 | /// Opens a file for reading or writing, without attempting to create a new file, based on an absolute path. |
| 2854 | 2796 | /// Call `File.close` to release the resource. |
| 2855 | 2797 | /// Asserts that the path is absolute. See `Dir.openFile` for a function that |
lib/std/fs/test.zig+33-35| ... | ... | @@ -8,10 +8,8 @@ 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; | |
| 12 | 11 | const File = std.fs.File; |
| 13 | 12 | const tmpDir = testing.tmpDir; |
| 14 | const tmpIterableDir = testing.tmpIterableDir; | |
| 15 | 13 | |
| 16 | 14 | const PathType = enum { |
| 17 | 15 | relative, |
| ... | ... | @@ -76,11 +74,11 @@ const TestContext = struct { |
| 76 | 74 | arena: ArenaAllocator, |
| 77 | 75 | tmp: testing.TmpIterableDir, |
| 78 | 76 | dir: std.fs.Dir, |
| 79 | iterable_dir: std.fs.IterableDir, | |
| 77 | iterable_dir: std.fs.Dir, | |
| 80 | 78 | transform_fn: *const PathType.TransformFn, |
| 81 | 79 | |
| 82 | 80 | pub fn init(path_type: PathType, allocator: mem.Allocator, transform_fn: *const PathType.TransformFn) TestContext { |
| 83 | const tmp = tmpIterableDir(.{}); | |
| 81 | const tmp = tmpDir(.{ .iterate = true }); | |
| 84 | 82 | return .{ |
| 85 | 83 | .path_type = path_type, |
| 86 | 84 | .arena = ArenaAllocator.init(allocator), |
| ... | ... | @@ -323,28 +321,28 @@ fn testReadLinkAbsolute(target_path: []const u8, symlink_path: []const u8) !void |
| 323 | 321 | } |
| 324 | 322 | |
| 325 | 323 | test "Dir.Iterator" { |
| 326 | var tmp_dir = tmpIterableDir(.{}); | |
| 324 | var tmp_dir = tmpDir(.{ .iterate = true }); | |
| 327 | 325 | defer tmp_dir.cleanup(); |
| 328 | 326 | |
| 329 | 327 | // First, create a couple of entries to iterate over. |
| 330 | const file = try tmp_dir.iterable_dir.dir.createFile("some_file", .{}); | |
| 328 | const file = try tmp_dir.dir.createFile("some_file", .{}); | |
| 331 | 329 | file.close(); |
| 332 | 330 | |
| 333 | try tmp_dir.iterable_dir.dir.makeDir("some_dir"); | |
| 331 | try tmp_dir.dir.makeDir("some_dir"); | |
| 334 | 332 | |
| 335 | 333 | var arena = ArenaAllocator.init(testing.allocator); |
| 336 | 334 | defer arena.deinit(); |
| 337 | 335 | const allocator = arena.allocator(); |
| 338 | 336 | |
| 339 | var entries = std.ArrayList(IterableDir.Entry).init(allocator); | |
| 337 | var entries = std.ArrayList(Dir.Entry).init(allocator); | |
| 340 | 338 | |
| 341 | 339 | // Create iterator. |
| 342 | var iter = tmp_dir.iterable_dir.iterate(); | |
| 340 | var iter = tmp_dir.dir.iterate(); | |
| 343 | 341 | while (try iter.next()) |entry| { |
| 344 | 342 | // We cannot just store `entry` as on Windows, we're re-using the name buffer |
| 345 | 343 | // which means we'll actually share the `name` pointer between entries! |
| 346 | 344 | const name = try allocator.dupe(u8, entry.name); |
| 347 | try entries.append(.{ .name = name, .kind = entry.kind }); | |
| 345 | try entries.append(Dir.Entry{ .name = name, .kind = entry.kind }); | |
| 348 | 346 | } |
| 349 | 347 | |
| 350 | 348 | try testing.expectEqual(@as(usize, 2), entries.items.len); // note that the Iterator skips '.' and '..' |
| ... | ... | @@ -353,7 +351,7 @@ test "Dir.Iterator" { |
| 353 | 351 | } |
| 354 | 352 | |
| 355 | 353 | test "Dir.Iterator many entries" { |
| 356 | var tmp_dir = tmpIterableDir(.{}); | |
| 354 | var tmp_dir = tmpDir(.{ .iterate = true }); | |
| 357 | 355 | defer tmp_dir.cleanup(); |
| 358 | 356 | |
| 359 | 357 | const num = 1024; |
| ... | ... | @@ -369,7 +367,7 @@ test "Dir.Iterator many entries" { |
| 369 | 367 | defer arena.deinit(); |
| 370 | 368 | const allocator = arena.allocator(); |
| 371 | 369 | |
| 372 | var entries = std.ArrayList(IterableDir.Entry).init(allocator); | |
| 370 | var entries = std.ArrayList(Dir.Entry).init(allocator); | |
| 373 | 371 | |
| 374 | 372 | // Create iterator. |
| 375 | 373 | var iter = tmp_dir.iterable_dir.iterate(); |
| ... | ... | @@ -388,14 +386,14 @@ test "Dir.Iterator many entries" { |
| 388 | 386 | } |
| 389 | 387 | |
| 390 | 388 | test "Dir.Iterator twice" { |
| 391 | var tmp_dir = tmpIterableDir(.{}); | |
| 389 | var tmp_dir = tmpDir(.{ .iterate = true }); | |
| 392 | 390 | defer tmp_dir.cleanup(); |
| 393 | 391 | |
| 394 | 392 | // First, create a couple of entries to iterate over. |
| 395 | const file = try tmp_dir.iterable_dir.dir.createFile("some_file", .{}); | |
| 393 | const file = try tmp_dir.dir.createFile("some_file", .{}); | |
| 396 | 394 | file.close(); |
| 397 | 395 | |
| 398 | try tmp_dir.iterable_dir.dir.makeDir("some_dir"); | |
| 396 | try tmp_dir.dir.makeDir("some_dir"); | |
| 399 | 397 | |
| 400 | 398 | var arena = ArenaAllocator.init(testing.allocator); |
| 401 | 399 | defer arena.deinit(); |
| ... | ... | @@ -403,15 +401,15 @@ test "Dir.Iterator twice" { |
| 403 | 401 | |
| 404 | 402 | var i: u8 = 0; |
| 405 | 403 | while (i < 2) : (i += 1) { |
| 406 | var entries = std.ArrayList(IterableDir.Entry).init(allocator); | |
| 404 | var entries = std.ArrayList(Dir.Entry).init(allocator); | |
| 407 | 405 | |
| 408 | 406 | // Create iterator. |
| 409 | var iter = tmp_dir.iterable_dir.iterate(); | |
| 407 | var iter = tmp_dir.dir.iterate(); | |
| 410 | 408 | while (try iter.next()) |entry| { |
| 411 | 409 | // We cannot just store `entry` as on Windows, we're re-using the name buffer |
| 412 | 410 | // which means we'll actually share the `name` pointer between entries! |
| 413 | 411 | const name = try allocator.dupe(u8, entry.name); |
| 414 | try entries.append(.{ .name = name, .kind = entry.kind }); | |
| 412 | try entries.append(Dir.Entry{ .name = name, .kind = entry.kind }); | |
| 415 | 413 | } |
| 416 | 414 | |
| 417 | 415 | try testing.expectEqual(@as(usize, 2), entries.items.len); // note that the Iterator skips '.' and '..' |
| ... | ... | @@ -421,7 +419,7 @@ test "Dir.Iterator twice" { |
| 421 | 419 | } |
| 422 | 420 | |
| 423 | 421 | test "Dir.Iterator reset" { |
| 424 | var tmp_dir = tmpIterableDir(.{}); | |
| 422 | var tmp_dir = tmpDir(.{ .iterate = true }); | |
| 425 | 423 | defer tmp_dir.cleanup(); |
| 426 | 424 | |
| 427 | 425 | // First, create a couple of entries to iterate over. |
| ... | ... | @@ -439,7 +437,7 @@ test "Dir.Iterator reset" { |
| 439 | 437 | |
| 440 | 438 | var i: u8 = 0; |
| 441 | 439 | while (i < 2) : (i += 1) { |
| 442 | var entries = std.ArrayList(IterableDir.Entry).init(allocator); | |
| 440 | var entries = std.ArrayList(Dir.Entry).init(allocator); | |
| 443 | 441 | |
| 444 | 442 | while (try iter.next()) |entry| { |
| 445 | 443 | // We cannot just store `entry` as on Windows, we're re-using the name buffer |
| ... | ... | @@ -485,11 +483,11 @@ test "Dir.Iterator but dir is deleted during iteration" { |
| 485 | 483 | } |
| 486 | 484 | } |
| 487 | 485 | |
| 488 | fn entryEql(lhs: IterableDir.Entry, rhs: IterableDir.Entry) bool { | |
| 486 | fn entryEql(lhs: Dir.Entry, rhs: Dir.Entry) bool { | |
| 489 | 487 | return mem.eql(u8, lhs.name, rhs.name) and lhs.kind == rhs.kind; |
| 490 | 488 | } |
| 491 | 489 | |
| 492 | fn contains(entries: *const std.ArrayList(IterableDir.Entry), el: IterableDir.Entry) bool { | |
| 490 | fn contains(entries: *const std.ArrayList(Dir.Entry), el: Dir.Entry) bool { | |
| 493 | 491 | for (entries.items) |entry| { |
| 494 | 492 | if (entryEql(entry, el)) return true; |
| 495 | 493 | } |
| ... | ... | @@ -963,7 +961,7 @@ test "makePath in a directory that no longer exists" { |
| 963 | 961 | try testing.expectError(error.FileNotFound, tmp.dir.makePath("sub-path")); |
| 964 | 962 | } |
| 965 | 963 | |
| 966 | fn testFilenameLimits(iterable_dir: IterableDir, maxed_filename: []const u8) !void { | |
| 964 | fn testFilenameLimits(iterable_dir: Dir, maxed_filename: []const u8) !void { | |
| 967 | 965 | // setup, create a dir and a nested file both with maxed filenames, and walk the dir |
| 968 | 966 | { |
| 969 | 967 | var maxed_dir = try iterable_dir.dir.makeOpenPath(maxed_filename, .{}); |
| ... | ... | @@ -987,7 +985,7 @@ fn testFilenameLimits(iterable_dir: IterableDir, maxed_filename: []const u8) !vo |
| 987 | 985 | } |
| 988 | 986 | |
| 989 | 987 | test "max file name component lengths" { |
| 990 | var tmp = tmpIterableDir(.{}); | |
| 988 | var tmp = tmpDir(.{ .iterate = true }); | |
| 991 | 989 | defer tmp.cleanup(); |
| 992 | 990 | |
| 993 | 991 | if (builtin.os.tag == .windows) { |
| ... | ... | @@ -1384,7 +1382,7 @@ test "open file with exclusive nonblocking lock twice (absolute paths)" { |
| 1384 | 1382 | test "walker" { |
| 1385 | 1383 | if (builtin.os.tag == .wasi and builtin.link_libc) return error.SkipZigTest; |
| 1386 | 1384 | |
| 1387 | var tmp = tmpIterableDir(.{}); | |
| 1385 | var tmp = tmpDir(.{ .iterate = true }); | |
| 1388 | 1386 | defer tmp.cleanup(); |
| 1389 | 1387 | |
| 1390 | 1388 | // iteration order of walker is undefined, so need lookup maps to check against |
| ... | ... | @@ -1410,10 +1408,10 @@ test "walker" { |
| 1410 | 1408 | }); |
| 1411 | 1409 | |
| 1412 | 1410 | for (expected_paths.kvs) |kv| { |
| 1413 | try tmp.iterable_dir.dir.makePath(kv.key); | |
| 1411 | try tmp.dir.makePath(kv.key); | |
| 1414 | 1412 | } |
| 1415 | 1413 | |
| 1416 | var walker = try tmp.iterable_dir.walk(testing.allocator); | |
| 1414 | var walker = try tmp.dir.walk(testing.allocator); | |
| 1417 | 1415 | defer walker.deinit(); |
| 1418 | 1416 | |
| 1419 | 1417 | var num_walked: usize = 0; |
| ... | ... | @@ -1437,7 +1435,7 @@ test "walker" { |
| 1437 | 1435 | test "walker without fully iterating" { |
| 1438 | 1436 | if (builtin.os.tag == .wasi and builtin.link_libc) return error.SkipZigTest; |
| 1439 | 1437 | |
| 1440 | var tmp = tmpIterableDir(.{}); | |
| 1438 | var tmp = tmpDir(.{ .iterate = true }); | |
| 1441 | 1439 | defer tmp.cleanup(); |
| 1442 | 1440 | |
| 1443 | 1441 | var walker = try tmp.iterable_dir.walk(testing.allocator); |
| ... | ... | @@ -1556,11 +1554,11 @@ test "chmod" { |
| 1556 | 1554 | try testing.expectEqual(@as(File.Mode, 0o644), (try file.stat()).mode & 0o7777); |
| 1557 | 1555 | |
| 1558 | 1556 | try tmp.dir.makeDir("test_dir"); |
| 1559 | var iterable_dir = try tmp.dir.openIterableDir("test_dir", .{}); | |
| 1560 | defer iterable_dir.close(); | |
| 1557 | var dir = try tmp.dir.openDir("test_dir", .{ .iterate = true }); | |
| 1558 | defer dir.close(); | |
| 1561 | 1559 | |
| 1562 | try iterable_dir.chmod(0o700); | |
| 1563 | try testing.expectEqual(@as(File.Mode, 0o700), (try iterable_dir.dir.stat()).mode & 0o7777); | |
| 1560 | try dir.chmod(0o700); | |
| 1561 | try testing.expectEqual(@as(File.Mode, 0o700), (try dir.stat()).mode & 0o7777); | |
| 1564 | 1562 | } |
| 1565 | 1563 | |
| 1566 | 1564 | test "chown" { |
| ... | ... | @@ -1576,9 +1574,9 @@ test "chown" { |
| 1576 | 1574 | |
| 1577 | 1575 | try tmp.dir.makeDir("test_dir"); |
| 1578 | 1576 | |
| 1579 | var iterable_dir = try tmp.dir.openIterableDir("test_dir", .{}); | |
| 1580 | defer iterable_dir.close(); | |
| 1581 | try iterable_dir.chown(null, null); | |
| 1577 | var dir = try tmp.dir.openDir("test_dir", .{ .iterate = true }); | |
| 1578 | defer dir.close(); | |
| 1579 | try dir.chown(null, null); | |
| 1582 | 1580 | } |
| 1583 | 1581 | |
| 1584 | 1582 | test "File.Metadata" { |
lib/std/os.zig+1-1| ... | ... | @@ -402,7 +402,7 @@ pub fn fchown(fd: fd_t, owner: ?uid_t, group: ?gid_t) FChownError!void { |
| 402 | 402 | switch (system.getErrno(res)) { |
| 403 | 403 | .SUCCESS => return, |
| 404 | 404 | .INTR => continue, |
| 405 | .BADF => unreachable, // Can be reached if the fd refers to a non-iterable directory. | |
| 405 | .BADF => unreachable, // Can be reached if the fd refers to a directory opened without `OpenDirOptions{ .iterate = true }` | |
| 406 | 406 | |
| 407 | 407 | .FAULT => unreachable, |
| 408 | 408 | .INVAL => unreachable, |
lib/std/testing.zig-38| ... | ... | @@ -543,22 +543,6 @@ pub const TmpDir = struct { |
| 543 | 543 | } |
| 544 | 544 | }; |
| 545 | 545 | |
| 546 | pub const TmpIterableDir = struct { | |
| 547 | iterable_dir: std.fs.IterableDir, | |
| 548 | parent_dir: std.fs.Dir, | |
| 549 | sub_path: [sub_path_len]u8, | |
| 550 | ||
| 551 | const random_bytes_count = 12; | |
| 552 | const sub_path_len = std.fs.base64_encoder.calcSize(random_bytes_count); | |
| 553 | ||
| 554 | pub fn cleanup(self: *TmpIterableDir) void { | |
| 555 | self.iterable_dir.close(); | |
| 556 | self.parent_dir.deleteTree(&self.sub_path) catch {}; | |
| 557 | self.parent_dir.close(); | |
| 558 | self.* = undefined; | |
| 559 | } | |
| 560 | }; | |
| 561 | ||
| 562 | 546 | pub fn tmpDir(opts: std.fs.Dir.OpenDirOptions) TmpDir { |
| 563 | 547 | var random_bytes: [TmpDir.random_bytes_count]u8 = undefined; |
| 564 | 548 | std.crypto.random.bytes(&random_bytes); |
| ... | ... | @@ -581,28 +565,6 @@ pub fn tmpDir(opts: std.fs.Dir.OpenDirOptions) TmpDir { |
| 581 | 565 | }; |
| 582 | 566 | } |
| 583 | 567 | |
| 584 | pub fn tmpIterableDir(opts: std.fs.Dir.OpenDirOptions) TmpIterableDir { | |
| 585 | var random_bytes: [TmpIterableDir.random_bytes_count]u8 = undefined; | |
| 586 | std.crypto.random.bytes(&random_bytes); | |
| 587 | var sub_path: [TmpIterableDir.sub_path_len]u8 = undefined; | |
| 588 | _ = std.fs.base64_encoder.encode(&sub_path, &random_bytes); | |
| 589 | ||
| 590 | const cwd = std.fs.cwd(); | |
| 591 | var cache_dir = cwd.makeOpenPath("zig-cache", .{}) catch | |
| 592 | @panic("unable to make tmp dir for testing: unable to make and open zig-cache dir"); | |
| 593 | defer cache_dir.close(); | |
| 594 | const parent_dir = cache_dir.makeOpenPath("tmp", .{}) catch | |
| 595 | @panic("unable to make tmp dir for testing: unable to make and open zig-cache/tmp dir"); | |
| 596 | const dir = parent_dir.makeOpenPathIterable(&sub_path, opts) catch | |
| 597 | @panic("unable to make tmp dir for testing: unable to make and open the tmp dir"); | |
| 598 | ||
| 599 | return .{ | |
| 600 | .iterable_dir = dir, | |
| 601 | .parent_dir = parent_dir, | |
| 602 | .sub_path = sub_path, | |
| 603 | }; | |
| 604 | } | |
| 605 | ||
| 606 | 568 | test "expectEqual nested array" { |
| 607 | 569 | const a = [2][2]f32{ |
| 608 | 570 | [_]f32{ 1.0, 0.0 }, |
src/main.zig+6-6| ... | ... | @@ -5698,13 +5698,13 @@ fn fmtPathDir( |
| 5698 | 5698 | parent_dir: fs.Dir, |
| 5699 | 5699 | parent_sub_path: []const u8, |
| 5700 | 5700 | ) FmtError!void { |
| 5701 | var iterable_dir = try parent_dir.openIterableDir(parent_sub_path, .{}); | |
| 5702 | defer iterable_dir.close(); | |
| 5701 | var dir = try parent_dir.openDir(parent_sub_path, .{ .iterate = true }); | |
| 5702 | defer dir.close(); | |
| 5703 | 5703 | |
| 5704 | const stat = try iterable_dir.dir.stat(); | |
| 5704 | const stat = try dir.stat(); | |
| 5705 | 5705 | if (try fmt.seen.fetchPut(stat.inode, {})) |_| return; |
| 5706 | 5706 | |
| 5707 | var dir_it = iterable_dir.iterate(); | |
| 5707 | var dir_it = dir.iterate(); | |
| 5708 | 5708 | while (try dir_it.next()) |entry| { |
| 5709 | 5709 | const is_dir = entry.kind == .directory; |
| 5710 | 5710 | |
| ... | ... | @@ -5715,9 +5715,9 @@ fn fmtPathDir( |
| 5715 | 5715 | defer fmt.gpa.free(full_path); |
| 5716 | 5716 | |
| 5717 | 5717 | if (is_dir) { |
| 5718 | try fmtPathDir(fmt, full_path, check_mode, iterable_dir.dir, entry.name); | |
| 5718 | try fmtPathDir(fmt, full_path, check_mode, dir, entry.name); | |
| 5719 | 5719 | } else { |
| 5720 | fmtPathFile(fmt, full_path, check_mode, iterable_dir.dir, entry.name) catch |err| { | |
| 5720 | fmtPathFile(fmt, full_path, check_mode, dir, entry.name) catch |err| { | |
| 5721 | 5721 | warn("unable to format '{s}': {s}", .{ full_path, @errorName(err) }); |
| 5722 | 5722 | fmt.any_error = true; |
| 5723 | 5723 | return; |
tools/process_headers.zig+3-3| ... | ... | @@ -382,14 +382,14 @@ pub fn main() !void { |
| 382 | 382 | try dir_stack.append(target_include_dir); |
| 383 | 383 | |
| 384 | 384 | while (dir_stack.popOrNull()) |full_dir_name| { |
| 385 | var iterable_dir = std.fs.cwd().openIterableDir(full_dir_name, .{}) catch |err| switch (err) { | |
| 385 | var dir = std.fs.cwd().openDir(full_dir_name, .{ .iterate = true }) catch |err| switch (err) { | |
| 386 | 386 | error.FileNotFound => continue :search, |
| 387 | 387 | error.AccessDenied => continue :search, |
| 388 | 388 | else => return err, |
| 389 | 389 | }; |
| 390 | defer iterable_dir.close(); | |
| 390 | defer dir.close(); | |
| 391 | 391 | |
| 392 | var dir_it = iterable_dir.iterate(); | |
| 392 | var dir_it = dir.iterate(); | |
| 393 | 393 | |
| 394 | 394 | while (try dir_it.next()) |entry| { |
| 395 | 395 | 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 iterable_dir = try std.fs.cwd().openIterableDir(path_to_walk, .{}); | |
| 17 | const dir = try std.fs.cwd().openDir(path_to_walk, .{ .iterate = true }); | |
| 18 | 18 | |
| 19 | var walker = try iterable_dir.walk(arena); | |
| 19 | var walker = try 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 iterable_dir.dir.readFileAlloc(arena, entry.path, 20 * 1024 * 1024); | |
| 33 | const source = try 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 iterable_dir.dir.writeFile(entry.path, new_source); | |
| 45 | try dir.writeFile(entry.path, new_source); | |
| 46 | 46 | } |
| 47 | 47 | } |
tools/update-linux-headers.zig+3-3| ... | ... | @@ -190,14 +190,14 @@ pub fn main() !void { |
| 190 | 190 | try dir_stack.append(target_include_dir); |
| 191 | 191 | |
| 192 | 192 | while (dir_stack.popOrNull()) |full_dir_name| { |
| 193 | var iterable_dir = std.fs.cwd().openIterableDir(full_dir_name, .{}) catch |err| switch (err) { | |
| 193 | var dir = std.fs.cwd().openDir(full_dir_name, .{ .iterate = true }) catch |err| switch (err) { | |
| 194 | 194 | error.FileNotFound => continue :search, |
| 195 | 195 | error.AccessDenied => continue :search, |
| 196 | 196 | else => return err, |
| 197 | 197 | }; |
| 198 | defer iterable_dir.close(); | |
| 198 | defer dir.close(); | |
| 199 | 199 | |
| 200 | var dir_it = iterable_dir.iterate(); | |
| 200 | var dir_it = dir.iterate(); | |
| 201 | 201 | |
| 202 | 202 | while (try dir_it.next()) |entry| { |
| 203 | 203 | const full_path = try std.fs.path.join(arena, &[_][]const u8{ full_dir_name, entry.name }); |
tools/update_glibc.zig+5-5| ... | ... | @@ -47,7 +47,7 @@ pub fn main() !void { |
| 47 | 47 | |
| 48 | 48 | const dest_dir_path = try std.fmt.allocPrint(arena, "{s}/lib/libc/glibc", .{zig_src_path}); |
| 49 | 49 | |
| 50 | var dest_dir = fs.cwd().openIterableDir(dest_dir_path, .{}) catch |err| { | |
| 50 | var dest_dir = fs.cwd().openDir(dest_dir_path, .{ .iterate = true }) catch |err| { | |
| 51 | 51 | fatal("unable to open destination directory '{s}': {s}", .{ |
| 52 | 52 | dest_dir_path, @errorName(err), |
| 53 | 53 | }); |
| ... | ... | @@ -72,14 +72,14 @@ pub fn main() !void { |
| 72 | 72 | if (mem.endsWith(u8, entry.path, ext)) continue :walk; |
| 73 | 73 | } |
| 74 | 74 | |
| 75 | glibc_src_dir.copyFile(entry.path, dest_dir.dir, entry.path, .{}) catch |err| { | |
| 75 | glibc_src_dir.copyFile(entry.path, dest_dir, entry.path, .{}) catch |err| { | |
| 76 | 76 | log.warn("unable to copy '{s}/{s}' to '{s}/{s}': {s}", .{ |
| 77 | 77 | glibc_src_path, entry.path, |
| 78 | 78 | dest_dir_path, entry.path, |
| 79 | 79 | @errorName(err), |
| 80 | 80 | }); |
| 81 | 81 | if (err == error.FileNotFound) { |
| 82 | try dest_dir.dir.deleteFile(entry.path); | |
| 82 | try dest_dir.deleteFile(entry.path); | |
| 83 | 83 | } |
| 84 | 84 | }; |
| 85 | 85 | } |
| ... | ... | @@ -88,7 +88,7 @@ pub fn main() !void { |
| 88 | 88 | // Warn about duplicated files inside glibc/include/* that can be omitted |
| 89 | 89 | // because they are already in generic-glibc/*. |
| 90 | 90 | |
| 91 | var include_dir = dest_dir.dir.openIterableDir("include", .{}) catch |err| { | |
| 91 | var include_dir = dest_dir.openDir("include", .{ .iterate = true }) catch |err| { | |
| 92 | 92 | fatal("unable to open directory '{s}/include': {s}", .{ |
| 93 | 93 | dest_dir_path, @errorName(err), |
| 94 | 94 | }); |
| ... | ... | @@ -125,7 +125,7 @@ pub fn main() !void { |
| 125 | 125 | generic_glibc_path, entry.path, @errorName(e), |
| 126 | 126 | }), |
| 127 | 127 | }; |
| 128 | const glibc_include_contents = include_dir.dir.readFileAlloc( | |
| 128 | const glibc_include_contents = include_dir.readFileAlloc( | |
| 129 | 129 | arena, |
| 130 | 130 | entry.path, |
| 131 | 131 | max_file_size, |
tools/update_spirv_features.zig+3-3| ... | ... | @@ -226,7 +226,7 @@ pub fn main() !void { |
| 226 | 226 | /// TODO: Unfortunately, neither repository contains a machine-readable list of extension dependencies. |
| 227 | 227 | fn gather_extensions(allocator: Allocator, spirv_registry_root: []const u8) ![]const []const u8 { |
| 228 | 228 | const extensions_path = try fs.path.join(allocator, &.{ spirv_registry_root, "extensions" }); |
| 229 | var extensions_dir = try fs.cwd().openIterableDir(extensions_path, .{}); | |
| 229 | var extensions_dir = try fs.cwd().openDir(extensions_path, .{ .iterate = true }); | |
| 230 | 230 | defer extensions_dir.close(); |
| 231 | 231 | |
| 232 | 232 | var extensions = std.ArrayList([]const u8).init(allocator); |
| ... | ... | @@ -235,7 +235,7 @@ fn gather_extensions(allocator: Allocator, spirv_registry_root: []const u8) ![]c |
| 235 | 235 | while (try vendor_it.next()) |vendor_entry| { |
| 236 | 236 | std.debug.assert(vendor_entry.kind == .directory); // If this fails, the structure of SPIRV-Registry has changed. |
| 237 | 237 | |
| 238 | const vendor_dir = try extensions_dir.dir.openIterableDir(vendor_entry.name, .{}); | |
| 238 | const vendor_dir = try extensions_dir.openDir(vendor_entry.name, .{ .iterate = true }); | |
| 239 | 239 | var ext_it = vendor_dir.iterate(); |
| 240 | 240 | while (try ext_it.next()) |ext_entry| { |
| 241 | 241 | // There is both a HTML and asciidoc version of every spec (as well as some other directories), |
| ... | ... | @@ -258,7 +258,7 @@ fn gather_extensions(allocator: Allocator, spirv_registry_root: []const u8) ![]c |
| 258 | 258 | // SPV_EXT_name |
| 259 | 259 | // ``` |
| 260 | 260 | |
| 261 | const ext_spec = try vendor_dir.dir.readFileAlloc(allocator, ext_entry.name, std.math.maxInt(usize)); | |
| 261 | const ext_spec = try vendor_dir.readFileAlloc(allocator, ext_entry.name, std.math.maxInt(usize)); | |
| 262 | 262 | const name_strings = "Name Strings"; |
| 263 | 263 | |
| 264 | 264 | const name_strings_offset = std.mem.indexOf(u8, ext_spec, name_strings) orelse return error.InvalidRegistry; |