aboutsummaryrefslogtreecommitdiff
path: root/lib/std
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2023-11-22 12:35:33 -0700
committerAndrew Kelley <andrew@ziglang.org>2023-11-22 12:35:33 -0700
commit519ba9bb654a4d5caf7440160f018b7a3ae1e95a (patch)
tree2308d007f7e1bf1a8aed846ad4faef8e729e0598 /lib/std
parente4977f3e89fcc164a4d02cd38eb066cfe1a1124f (diff)
downloadzig-519ba9bb654a4d5caf7440160f018b7a3ae1e95a.tar.gz
zig-519ba9bb654a4d5caf7440160f018b7a3ae1e95a.zip
Revert "Merge pull request #12060 from Vexu/IterableDir"
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.
Diffstat (limited to 'lib/std')
-rw-r--r--lib/std/fs.zig234
-rw-r--r--lib/std/fs/test.zig68
-rw-r--r--lib/std/os.zig2
-rw-r--r--lib/std/testing.zig38
4 files changed, 122 insertions, 220 deletions
diff --git a/lib/std/fs.zig b/lib/std/fs.zig
index 2bcf4ee309..12e1ac34ab 100644
--- a/lib/std/fs.zig
+++ b/lib/std/fs.zig
@@ -310,10 +310,8 @@ 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);
}
-/// 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 Dir = struct {
+ fd: os.fd_t,
pub const Entry = struct {
name: []const u8,
@@ -879,18 +877,18 @@ pub const IterableDir = struct {
else => @compileError("unimplemented"),
};
- pub fn iterate(self: IterableDir) Iterator {
+ pub fn iterate(self: Dir) Iterator {
return self.iterateImpl(true);
}
/// Like `iterate`, but will not reset the directory cursor before the first
/// iteration. This should only be used in cases where it is known that the
- /// `IterableDir` has not had its cursor modified yet (e.g. it was just opened).
- pub fn iterateAssumeFirstIteration(self: IterableDir) Iterator {
+ /// `Dir` has not had its cursor modified yet (e.g. it was just opened).
+ pub fn iterateAssumeFirstIteration(self: Dir) Iterator {
return self.iterateImpl(false);
}
- fn iterateImpl(self: IterableDir, first_iter_start_value: bool) Iterator {
+ fn iterateImpl(self: Dir, first_iter_start_value: bool) Iterator {
switch (builtin.os.tag) {
.macos,
.ios,
@@ -901,7 +899,7 @@ pub const IterableDir = struct {
.solaris,
.illumos,
=> return Iterator{
- .dir = self.dir,
+ .dir = self,
.seek = 0,
.index = 0,
.end_index = 0,
@@ -909,14 +907,14 @@ pub const IterableDir = struct {
.first_iter = first_iter_start_value,
},
.linux, .haiku => return Iterator{
- .dir = self.dir,
+ .dir = self,
.index = 0,
.end_index = 0,
.buf = undefined,
.first_iter = first_iter_start_value,
},
.windows => return Iterator{
- .dir = self.dir,
+ .dir = self,
.index = 0,
.end_index = 0,
.first_iter = first_iter_start_value,
@@ -924,7 +922,7 @@ pub const IterableDir = struct {
.name_data = undefined,
},
.wasi => return Iterator{
- .dir = self.dir,
+ .dir = self,
.cookie = os.wasi.DIRCOOKIE_START,
.index = 0,
.end_index = 0,
@@ -945,11 +943,11 @@ pub const IterableDir = struct {
dir: Dir,
basename: []const u8,
path: []const u8,
- kind: IterableDir.Entry.Kind,
+ kind: Dir.Entry.Kind,
};
const StackItem = struct {
- iter: IterableDir.Iterator,
+ iter: Dir.Iterator,
dirname_len: usize,
};
@@ -980,7 +978,7 @@ pub const IterableDir = struct {
}
try self.name_buffer.appendSlice(base.name);
if (base.kind == .directory) {
- var new_dir = top.iter.dir.openIterableDir(base.name, .{}) catch |err| switch (err) {
+ var new_dir = top.iter.dir.openDir(base.name, .{ .iterate = true }) catch |err| switch (err) {
error.NameTooLong => unreachable, // no path sep in base.name
else => |e| return e,
};
@@ -1023,10 +1021,11 @@ pub const IterableDir = 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: IterableDir, allocator: Allocator) !Walker {
+ pub fn walk(self: Dir, allocator: Allocator) !Walker {
var name_buffer = std.ArrayList(u8).init(allocator);
errdefer name_buffer.deinit();
@@ -1044,49 +1043,6 @@ pub const IterableDir = 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,
-
- pub const iterate = @compileError("only 'IterableDir' can be iterated; 'IterableDir' can be obtained with 'openIterableDir'");
- pub const walk = @compileError("only 'IterableDir' can be walked; 'IterableDir' can be obtained with 'openIterableDir'");
- pub const chmod = @compileError("only 'IterableDir' can have its mode changed; 'IterableDir' can be obtained with 'openIterableDir'");
- pub const chown = @compileError("only 'IterableDir' can have its owner changed; 'IterableDir' can be obtained with 'openIterableDir'");
-
pub const OpenError = error{
FileNotFound,
NotDir,
@@ -1529,7 +1485,8 @@ pub const Dir = struct {
.windows => {
const w = os.windows;
const base_flags = w.STANDARD_RIGHTS_READ | w.FILE_READ_ATTRIBUTES | w.FILE_READ_EA |
- w.SYNCHRONIZE | w.FILE_TRAVERSE;
+ w.SYNCHRONIZE | w.FILE_TRAVERSE |
+ (if (open_dir_options.iterate) w.FILE_LIST_DIRECTORY else 0);
return self.makeOpenPathAccessMaskW(sub_path, base_flags, open_dir_options.no_follow);
},
@@ -1545,32 +1502,6 @@ pub const Dir = struct {
};
}
- /// This function performs `makePath`, followed by `openIterableDir`.
- /// If supported by the OS, this operation is atomic. It is not atomic on
- /// all operating systems.
- pub fn makeOpenPathIterable(self: Dir, sub_path: []const u8, open_dir_options: OpenDirOptions) !IterableDir {
- return switch (builtin.os.tag) {
- .windows => {
- const w = os.windows;
- const base_flags = w.STANDARD_RIGHTS_READ | w.FILE_READ_ATTRIBUTES | w.FILE_READ_EA |
- w.SYNCHRONIZE | w.FILE_TRAVERSE | w.FILE_LIST_DIRECTORY;
-
- return IterableDir{
- .dir = try self.makeOpenPathAccessMaskW(sub_path, base_flags, open_dir_options.no_follow),
- };
- },
- else => {
- return self.openIterableDir(sub_path, open_dir_options) catch |err| switch (err) {
- error.FileNotFound => {
- try self.makePath(sub_path);
- return self.openIterableDir(sub_path, open_dir_options);
- },
- else => |e| return e,
- };
- },
- };
- }
-
/// This function returns the canonicalized absolute pathname of
/// `pathname` relative to this `Dir`. If `pathname` is absolute, ignores this
/// `Dir` handle and returns the canonicalized absolute pathname of `pathname`
@@ -1706,39 +1637,28 @@ pub const Dir = struct {
/// such operations are Illegal Behavior.
access_sub_paths: bool = true,
+ /// `true` means the opened directory can be scanned for the files and sub-directories
+ /// of the result. It means the `iterate` function can be called.
+ iterate: bool = false,
+
/// `true` means it won't dereference the symlinks.
no_follow: bool = false,
};
/// Opens a directory at the given path. The directory is a system resource that remains
/// open until `close` is called on the result.
+ /// The directory cannot be iterated unless the `iterate` option is set to `true`.
///
/// Asserts that the path parameter has no null bytes.
pub fn openDir(self: Dir, sub_path: []const u8, args: OpenDirOptions) OpenError!Dir {
if (builtin.os.tag == .windows) {
const sub_path_w = try os.windows.sliceToPrefixedFileW(self.fd, sub_path);
- return self.openDirW(sub_path_w.span().ptr, args, false);
- } else if (builtin.os.tag == .wasi and !builtin.link_libc) {
- return self.openDirWasi(sub_path, args);
- } else {
- const sub_path_c = try os.toPosixPath(sub_path);
- return self.openDirZ(&sub_path_c, args, false);
- }
- }
-
- /// 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 {
- if (builtin.os.tag == .windows) {
- const sub_path_w = try os.windows.sliceToPrefixedFileW(self.fd, sub_path);
- return IterableDir{ .dir = try self.openDirW(sub_path_w.span().ptr, args, true) };
+ return .{ .dir = try self.openDirW(sub_path_w.span().ptr, args) };
} else if (builtin.os.tag == .wasi and !builtin.link_libc) {
- return IterableDir{ .dir = try self.openDirWasi(sub_path, args) };
+ return .{ .dir = try self.openDirWasi(sub_path, args) };
} else {
const sub_path_c = try os.toPosixPath(sub_path);
- return IterableDir{ .dir = try self.openDirZ(&sub_path_c, args, true) };
+ return .{ .dir = try self.openDirZ(&sub_path_c, args) };
}
}
@@ -1790,13 +1710,13 @@ pub const Dir = struct {
}
/// Same as `openDir` except the parameter is null-terminated.
- pub fn openDirZ(self: Dir, sub_path_c: [*:0]const u8, args: OpenDirOptions, iterable: bool) OpenError!Dir {
+ pub fn openDirZ(self: Dir, sub_path_c: [*:0]const u8, args: OpenDirOptions) OpenError!Dir {
if (builtin.os.tag == .windows) {
const sub_path_w = try os.windows.cStrToPrefixedFileW(self.fd, sub_path_c);
- return self.openDirW(sub_path_w.span().ptr, args, iterable);
+ return self.openDirW(sub_path_w.span().ptr, args);
}
const symlink_flags: u32 = if (args.no_follow) os.O.NOFOLLOW else 0x0;
- if (!iterable) {
+ if (!args.iterate) {
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 {
@@ -1806,12 +1726,12 @@ pub const Dir = struct {
/// Same as `openDir` except the path parameter is WTF-16 encoded, NT-prefixed.
/// This function asserts the target OS is Windows.
- pub fn openDirW(self: Dir, sub_path_w: [*:0]const u16, args: OpenDirOptions, iterable: bool) OpenError!Dir {
+ pub fn openDirW(self: Dir, sub_path_w: [*:0]const u16, args: OpenDirOptions) OpenError!Dir {
const w = os.windows;
// TODO remove some of these flags if args.access_sub_paths is false
const base_flags = w.STANDARD_RIGHTS_READ | w.FILE_READ_ATTRIBUTES | w.FILE_READ_EA |
w.SYNCHRONIZE | w.FILE_TRAVERSE;
- const flags: u32 = if (iterable) base_flags | w.FILE_LIST_DIRECTORY else base_flags;
+ const flags: u32 = if (args.iterate) base_flags | w.FILE_LIST_DIRECTORY else base_flags;
const dir = try self.makeOpenDirAccessMaskW(sub_path_w, flags, .{
.no_follow = args.no_follow,
.create_disposition = w.FILE_OPEN,
@@ -2203,7 +2123,7 @@ pub const Dir = struct {
const StackItem = struct {
name: []const u8,
parent_dir: Dir,
- iter: IterableDir.Iterator,
+ iter: Dir.Iterator,
fn closeAll(items: []@This()) void {
for (items) |*item| item.iter.dir.close();
@@ -2227,7 +2147,10 @@ pub const Dir = struct {
handle_entry: while (true) {
if (treat_as_dir) {
if (stack.unusedCapacitySlice().len >= 1) {
- var iterable_dir = top.iter.dir.openIterableDir(entry.name, .{ .no_follow = true }) catch |err| switch (err) {
+ var iterable_dir = top.iter.dir.openDir(entry.name, .{
+ .no_follow = true,
+ .iterate = true,
+ }) catch |err| switch (err) {
error.NotDir => {
treat_as_dir = false;
continue :handle_entry;
@@ -2318,7 +2241,10 @@ pub const Dir = struct {
var treat_as_dir = true;
handle_entry: while (true) {
if (treat_as_dir) {
- break :iterable_dir parent_dir.openIterableDir(name, .{ .no_follow = true }) catch |err| switch (err) {
+ break :iterable_dir parent_dir.openDir(name, .{
+ .no_follow = true,
+ .iterate = true,
+ }) catch |err| switch (err) {
error.NotDir => {
treat_as_dir = false;
continue :handle_entry;
@@ -2393,12 +2319,12 @@ pub const Dir = struct {
fn deleteTreeMinStackSizeWithKindHint(self: Dir, sub_path: []const u8, kind_hint: File.Kind) DeleteTreeError!void {
start_over: while (true) {
- var iterable_dir = (try self.deleteTreeOpenInitialSubpath(sub_path, kind_hint)) orelse return;
- var cleanup_dir_parent: ?IterableDir = null;
+ var dir = (try self.deleteTreeOpenInitialSubpath(sub_path, kind_hint)) orelse return;
+ var cleanup_dir_parent: ?Dir = null;
defer if (cleanup_dir_parent) |*d| d.close();
var cleanup_dir = true;
- defer if (cleanup_dir) iterable_dir.close();
+ defer if (cleanup_dir) 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
@@ -2411,12 +2337,15 @@ 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 = iterable_dir.iterateAssumeFirstIteration();
+ var dir_it = dir.iterateAssumeFirstIteration();
dir_it: while (try dir_it.next()) |entry| {
var treat_as_dir = entry.kind == .directory;
handle_entry: while (true) {
if (treat_as_dir) {
- const new_dir = iterable_dir.dir.openIterableDir(entry.name, .{ .no_follow = true }) catch |err| switch (err) {
+ const new_dir = dir.openDir(entry.name, .{
+ .no_follow = true,
+ .iterate = true,
+ }) catch |err| switch (err) {
error.NotDir => {
treat_as_dir = false;
continue :handle_entry;
@@ -2442,14 +2371,14 @@ pub const Dir = struct {
=> |e| return e,
};
if (cleanup_dir_parent) |*d| d.close();
- cleanup_dir_parent = iterable_dir;
- iterable_dir = new_dir;
+ cleanup_dir_parent = dir;
+ dir = new_dir;
const result = dir_name_buf[0..entry.name.len];
@memcpy(result, entry.name);
dir_name = result;
continue :scan_dir;
} else {
- if (iterable_dir.dir.deleteFile(entry.name)) {
+ if (dir.deleteFile(entry.name)) {
continue :dir_it;
} else |err| switch (err) {
error.FileNotFound => continue :dir_it,
@@ -2480,11 +2409,11 @@ pub const Dir = struct {
}
// Reached the end of the directory entries, which means we successfully deleted all of them.
// Now to remove the directory itself.
- iterable_dir.close();
+ dir.close();
cleanup_dir = false;
if (cleanup_dir_parent) |d| {
- d.dir.deleteDir(dir_name) catch |err| switch (err) {
+ d.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,
@@ -2503,14 +2432,17 @@ pub const Dir = struct {
}
/// On successful delete, returns null.
- fn deleteTreeOpenInitialSubpath(self: Dir, sub_path: []const u8, kind_hint: File.Kind) !?IterableDir {
+ fn deleteTreeOpenInitialSubpath(self: Dir, sub_path: []const u8, kind_hint: File.Kind) !?Dir {
return iterable_dir: {
// Treat as a file by default
var treat_as_dir = kind_hint == .directory;
handle_entry: while (true) {
if (treat_as_dir) {
- break :iterable_dir self.openIterableDir(sub_path, .{ .no_follow = true }) catch |err| switch (err) {
+ break :iterable_dir self.openDir(sub_path, .{
+ .no_follow = true,
+ .iterate = true,
+ }) catch |err| switch (err) {
error.NotDir => {
treat_as_dir = false;
continue :handle_entry;
@@ -2764,6 +2696,37 @@ pub const Dir = struct {
return Stat.fromSystem(st);
}
+ 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;
@@ -2829,27 +2792,6 @@ pub fn openDirAbsoluteW(absolute_path_c: [*:0]const u16, flags: Dir.OpenDirOptio
return cwd().openDirW(absolute_path_c, flags, false);
}
-/// Opens a directory at the given path. The directory is a system resource that remains
-/// open until `close` is called on the result.
-/// See `openIterableDirAbsoluteZ` for a function that accepts a null-terminated path.
-///
-/// Asserts that the path parameter has no null bytes.
-pub fn openIterableDirAbsolute(absolute_path: []const u8, flags: Dir.OpenDirOptions) File.OpenError!IterableDir {
- assert(path.isAbsolute(absolute_path));
- return cwd().openIterableDir(absolute_path, flags);
-}
-
-/// Same as `openIterableDirAbsolute` but the path parameter is null-terminated.
-pub fn openIterableDirAbsoluteZ(absolute_path_c: [*:0]const u8, flags: Dir.OpenDirOptions) File.OpenError!IterableDir {
- assert(path.isAbsoluteZ(absolute_path_c));
- return IterableDir{ .dir = try cwd().openDirZ(absolute_path_c, flags, true) };
-}
-/// Same as `openIterableDirAbsolute` but the path parameter is null-terminated.
-pub fn openIterableDirAbsoluteW(absolute_path_c: [*:0]const u16, flags: Dir.OpenDirOptions) File.OpenError!IterableDir {
- assert(path.isAbsoluteWindowsW(absolute_path_c));
- return IterableDir{ .dir = try cwd().openDirW(absolute_path_c, flags, true) };
-}
-
/// Opens a file for reading or writing, without attempting to create a new file, based on an absolute path.
/// Call `File.close` to release the resource.
/// Asserts that the path is absolute. See `Dir.openFile` for a function that
diff --git a/lib/std/fs/test.zig b/lib/std/fs/test.zig
index 6786aec4b0..fcf978d307 100644
--- a/lib/std/fs/test.zig
+++ b/lib/std/fs/test.zig
@@ -8,10 +8,8 @@ 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;
-const tmpIterableDir = testing.tmpIterableDir;
const PathType = enum {
relative,
@@ -76,11 +74,11 @@ const TestContext = struct {
arena: ArenaAllocator,
tmp: testing.TmpIterableDir,
dir: std.fs.Dir,
- iterable_dir: std.fs.IterableDir,
+ iterable_dir: std.fs.Dir,
transform_fn: *const PathType.TransformFn,
pub fn init(path_type: PathType, allocator: mem.Allocator, transform_fn: *const PathType.TransformFn) TestContext {
- const tmp = tmpIterableDir(.{});
+ const tmp = tmpDir(.{ .iterate = true });
return .{
.path_type = path_type,
.arena = ArenaAllocator.init(allocator),
@@ -323,28 +321,28 @@ fn testReadLinkAbsolute(target_path: []const u8, symlink_path: []const u8) !void
}
test "Dir.Iterator" {
- var tmp_dir = tmpIterableDir(.{});
+ var tmp_dir = tmpDir(.{ .iterate = true });
defer tmp_dir.cleanup();
// First, create a couple of entries to iterate over.
- const file = try tmp_dir.iterable_dir.dir.createFile("some_file", .{});
+ const file = try tmp_dir.dir.createFile("some_file", .{});
file.close();
- try tmp_dir.iterable_dir.dir.makeDir("some_dir");
+ try tmp_dir.dir.makeDir("some_dir");
var arena = ArenaAllocator.init(testing.allocator);
defer arena.deinit();
const allocator = arena.allocator();
- var entries = std.ArrayList(IterableDir.Entry).init(allocator);
+ var entries = std.ArrayList(Dir.Entry).init(allocator);
// Create iterator.
- var iter = tmp_dir.iterable_dir.iterate();
+ var iter = tmp_dir.dir.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(.{ .name = name, .kind = entry.kind });
+ try entries.append(Dir.Entry{ .name = name, .kind = entry.kind });
}
try testing.expectEqual(@as(usize, 2), entries.items.len); // note that the Iterator skips '.' and '..'
@@ -353,7 +351,7 @@ test "Dir.Iterator" {
}
test "Dir.Iterator many entries" {
- var tmp_dir = tmpIterableDir(.{});
+ var tmp_dir = tmpDir(.{ .iterate = true });
defer tmp_dir.cleanup();
const num = 1024;
@@ -369,7 +367,7 @@ test "Dir.Iterator many entries" {
defer arena.deinit();
const allocator = arena.allocator();
- var entries = std.ArrayList(IterableDir.Entry).init(allocator);
+ var entries = std.ArrayList(Dir.Entry).init(allocator);
// Create iterator.
var iter = tmp_dir.iterable_dir.iterate();
@@ -388,14 +386,14 @@ test "Dir.Iterator many entries" {
}
test "Dir.Iterator twice" {
- var tmp_dir = tmpIterableDir(.{});
+ var tmp_dir = tmpDir(.{ .iterate = true });
defer tmp_dir.cleanup();
// First, create a couple of entries to iterate over.
- const file = try tmp_dir.iterable_dir.dir.createFile("some_file", .{});
+ const file = try tmp_dir.dir.createFile("some_file", .{});
file.close();
- try tmp_dir.iterable_dir.dir.makeDir("some_dir");
+ try tmp_dir.dir.makeDir("some_dir");
var arena = ArenaAllocator.init(testing.allocator);
defer arena.deinit();
@@ -403,15 +401,15 @@ test "Dir.Iterator twice" {
var i: u8 = 0;
while (i < 2) : (i += 1) {
- var entries = std.ArrayList(IterableDir.Entry).init(allocator);
+ var entries = std.ArrayList(Dir.Entry).init(allocator);
// Create iterator.
- var iter = tmp_dir.iterable_dir.iterate();
+ var iter = tmp_dir.dir.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(.{ .name = name, .kind = entry.kind });
+ try entries.append(Dir.Entry{ .name = name, .kind = entry.kind });
}
try testing.expectEqual(@as(usize, 2), entries.items.len); // note that the Iterator skips '.' and '..'
@@ -421,7 +419,7 @@ test "Dir.Iterator twice" {
}
test "Dir.Iterator reset" {
- var tmp_dir = tmpIterableDir(.{});
+ var tmp_dir = tmpDir(.{ .iterate = true });
defer tmp_dir.cleanup();
// First, create a couple of entries to iterate over.
@@ -439,7 +437,7 @@ test "Dir.Iterator reset" {
var i: u8 = 0;
while (i < 2) : (i += 1) {
- var entries = std.ArrayList(IterableDir.Entry).init(allocator);
+ var entries = std.ArrayList(Dir.Entry).init(allocator);
while (try iter.next()) |entry| {
// 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" {
}
}
-fn entryEql(lhs: IterableDir.Entry, rhs: IterableDir.Entry) bool {
+fn entryEql(lhs: Dir.Entry, rhs: Dir.Entry) bool {
return mem.eql(u8, lhs.name, rhs.name) and lhs.kind == rhs.kind;
}
-fn contains(entries: *const std.ArrayList(IterableDir.Entry), el: IterableDir.Entry) bool {
+fn contains(entries: *const std.ArrayList(Dir.Entry), el: Dir.Entry) bool {
for (entries.items) |entry| {
if (entryEql(entry, el)) return true;
}
@@ -963,7 +961,7 @@ test "makePath in a directory that no longer exists" {
try testing.expectError(error.FileNotFound, tmp.dir.makePath("sub-path"));
}
-fn testFilenameLimits(iterable_dir: IterableDir, maxed_filename: []const u8) !void {
+fn testFilenameLimits(iterable_dir: Dir, maxed_filename: []const u8) !void {
// setup, create a dir and a nested file both with maxed filenames, and walk the dir
{
var maxed_dir = try iterable_dir.dir.makeOpenPath(maxed_filename, .{});
@@ -987,7 +985,7 @@ fn testFilenameLimits(iterable_dir: IterableDir, maxed_filename: []const u8) !vo
}
test "max file name component lengths" {
- var tmp = tmpIterableDir(.{});
+ var tmp = tmpDir(.{ .iterate = true });
defer tmp.cleanup();
if (builtin.os.tag == .windows) {
@@ -1384,7 +1382,7 @@ test "open file with exclusive nonblocking lock twice (absolute paths)" {
test "walker" {
if (builtin.os.tag == .wasi and builtin.link_libc) return error.SkipZigTest;
- var tmp = tmpIterableDir(.{});
+ var tmp = tmpDir(.{ .iterate = true });
defer tmp.cleanup();
// iteration order of walker is undefined, so need lookup maps to check against
@@ -1410,10 +1408,10 @@ test "walker" {
});
for (expected_paths.kvs) |kv| {
- try tmp.iterable_dir.dir.makePath(kv.key);
+ try tmp.dir.makePath(kv.key);
}
- var walker = try tmp.iterable_dir.walk(testing.allocator);
+ var walker = try tmp.dir.walk(testing.allocator);
defer walker.deinit();
var num_walked: usize = 0;
@@ -1437,7 +1435,7 @@ test "walker" {
test "walker without fully iterating" {
if (builtin.os.tag == .wasi and builtin.link_libc) return error.SkipZigTest;
- var tmp = tmpIterableDir(.{});
+ var tmp = tmpDir(.{ .iterate = true });
defer tmp.cleanup();
var walker = try tmp.iterable_dir.walk(testing.allocator);
@@ -1556,11 +1554,11 @@ test "chmod" {
try testing.expectEqual(@as(File.Mode, 0o644), (try file.stat()).mode & 0o7777);
try tmp.dir.makeDir("test_dir");
- var iterable_dir = try tmp.dir.openIterableDir("test_dir", .{});
- defer iterable_dir.close();
+ var dir = try tmp.dir.openDir("test_dir", .{ .iterate = true });
+ defer dir.close();
- try iterable_dir.chmod(0o700);
- try testing.expectEqual(@as(File.Mode, 0o700), (try iterable_dir.dir.stat()).mode & 0o7777);
+ try dir.chmod(0o700);
+ try testing.expectEqual(@as(File.Mode, 0o700), (try dir.stat()).mode & 0o7777);
}
test "chown" {
@@ -1576,9 +1574,9 @@ test "chown" {
try tmp.dir.makeDir("test_dir");
- var iterable_dir = try tmp.dir.openIterableDir("test_dir", .{});
- defer iterable_dir.close();
- try iterable_dir.chown(null, null);
+ var dir = try tmp.dir.openDir("test_dir", .{ .iterate = true });
+ defer dir.close();
+ try dir.chown(null, null);
}
test "File.Metadata" {
diff --git a/lib/std/os.zig b/lib/std/os.zig
index cf388f76e9..10697b970f 100644
--- a/lib/std/os.zig
+++ b/lib/std/os.zig
@@ -402,7 +402,7 @@ pub fn fchown(fd: fd_t, owner: ?uid_t, group: ?gid_t) FChownError!void {
switch (system.getErrno(res)) {
.SUCCESS => return,
.INTR => continue,
- .BADF => unreachable, // Can be reached if the fd refers to a non-iterable directory.
+ .BADF => unreachable, // Can be reached if the fd refers to a directory opened without `OpenDirOptions{ .iterate = true }`
.FAULT => unreachable,
.INVAL => unreachable,
diff --git a/lib/std/testing.zig b/lib/std/testing.zig
index 09507a2392..a26b6ff321 100644
--- a/lib/std/testing.zig
+++ b/lib/std/testing.zig
@@ -543,22 +543,6 @@ pub const TmpDir = struct {
}
};
-pub const TmpIterableDir = struct {
- iterable_dir: std.fs.IterableDir,
- parent_dir: std.fs.Dir,
- sub_path: [sub_path_len]u8,
-
- const random_bytes_count = 12;
- const sub_path_len = std.fs.base64_encoder.calcSize(random_bytes_count);
-
- pub fn cleanup(self: *TmpIterableDir) void {
- self.iterable_dir.close();
- self.parent_dir.deleteTree(&self.sub_path) catch {};
- self.parent_dir.close();
- self.* = undefined;
- }
-};
-
pub fn tmpDir(opts: std.fs.Dir.OpenDirOptions) TmpDir {
var random_bytes: [TmpDir.random_bytes_count]u8 = undefined;
std.crypto.random.bytes(&random_bytes);
@@ -581,28 +565,6 @@ pub fn tmpDir(opts: std.fs.Dir.OpenDirOptions) TmpDir {
};
}
-pub fn tmpIterableDir(opts: std.fs.Dir.OpenDirOptions) TmpIterableDir {
- var random_bytes: [TmpIterableDir.random_bytes_count]u8 = undefined;
- std.crypto.random.bytes(&random_bytes);
- var sub_path: [TmpIterableDir.sub_path_len]u8 = undefined;
- _ = std.fs.base64_encoder.encode(&sub_path, &random_bytes);
-
- const cwd = std.fs.cwd();
- var cache_dir = cwd.makeOpenPath("zig-cache", .{}) catch
- @panic("unable to make tmp dir for testing: unable to make and open zig-cache dir");
- defer cache_dir.close();
- const parent_dir = cache_dir.makeOpenPath("tmp", .{}) catch
- @panic("unable to make tmp dir for testing: unable to make and open zig-cache/tmp dir");
- const dir = parent_dir.makeOpenPathIterable(&sub_path, opts) catch
- @panic("unable to make tmp dir for testing: unable to make and open the tmp dir");
-
- return .{
- .iterable_dir = dir,
- .parent_dir = parent_dir,
- .sub_path = sub_path,
- };
-}
-
test "expectEqual nested array" {
const a = [2][2]f32{
[_]f32{ 1.0, 0.0 },