Merge pull request #12060 from Vexu/IterableDir
std.fs: split `Dir` into `IterableDir`
This commit is contained in:
@@ -3245,7 +3245,7 @@ pub const LibExeObjStep = struct {
|
|||||||
const build_output_dir = mem.trimRight(u8, output_dir_nl, "\r\n");
|
const build_output_dir = mem.trimRight(u8, output_dir_nl, "\r\n");
|
||||||
|
|
||||||
if (self.output_dir) |output_dir| {
|
if (self.output_dir) |output_dir| {
|
||||||
var src_dir = try std.fs.cwd().openDir(build_output_dir, .{ .iterate = true });
|
var src_dir = try std.fs.cwd().openIterableDir(build_output_dir, .{});
|
||||||
defer src_dir.close();
|
defer src_dir.close();
|
||||||
|
|
||||||
// Create the output directory if it doesn't exist.
|
// Create the output directory if it doesn't exist.
|
||||||
@@ -3265,7 +3265,7 @@ pub const LibExeObjStep = struct {
|
|||||||
mem.eql(u8, entry.name, "zld.id") or
|
mem.eql(u8, entry.name, "zld.id") or
|
||||||
mem.eql(u8, entry.name, "lld.id")) continue;
|
mem.eql(u8, entry.name, "lld.id")) continue;
|
||||||
|
|
||||||
_ = try src_dir.updateFile(entry.name, dest_dir, entry.name, .{});
|
_ = try src_dir.dir.updateFile(entry.name, dest_dir, entry.name, .{});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.output_dir = build_output_dir;
|
self.output_dir = build_output_dir;
|
||||||
@@ -3480,7 +3480,7 @@ pub const InstallDirStep = struct {
|
|||||||
const self = @fieldParentPtr(InstallDirStep, "step", step);
|
const self = @fieldParentPtr(InstallDirStep, "step", step);
|
||||||
const dest_prefix = self.builder.getInstallPath(self.options.install_dir, self.options.install_subdir);
|
const dest_prefix = self.builder.getInstallPath(self.options.install_dir, self.options.install_subdir);
|
||||||
const full_src_dir = self.builder.pathFromRoot(self.options.source_dir);
|
const full_src_dir = self.builder.pathFromRoot(self.options.source_dir);
|
||||||
var src_dir = try std.fs.cwd().openDir(full_src_dir, .{ .iterate = true });
|
var src_dir = try std.fs.cwd().openIterableDir(full_src_dir, .{});
|
||||||
defer src_dir.close();
|
defer src_dir.close();
|
||||||
var it = try src_dir.walk(self.builder.allocator);
|
var it = try src_dir.walk(self.builder.allocator);
|
||||||
next_entry: while (try it.next()) |entry| {
|
next_entry: while (try it.next()) |entry| {
|
||||||
|
|||||||
163
lib/std/fs.zig
163
lib/std/fs.zig
@@ -283,8 +283,10 @@ pub fn renameW(old_dir: Dir, old_sub_path_w: []const u16, new_dir: Dir, new_sub_
|
|||||||
return os.renameatW(old_dir.fd, old_sub_path_w, new_dir.fd, new_sub_path_w);
|
return os.renameatW(old_dir.fd, old_sub_path_w, new_dir.fd, new_sub_path_w);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const Dir = struct {
|
/// A directory that can be iterated. It is *NOT* legal to initialize this with a regular `Dir`
|
||||||
fd: os.fd_t,
|
/// that has been opened without iteration permission.
|
||||||
|
pub const IterableDir = struct {
|
||||||
|
dir: Dir,
|
||||||
|
|
||||||
pub const Entry = struct {
|
pub const Entry = struct {
|
||||||
name: []const u8,
|
name: []const u8,
|
||||||
@@ -779,7 +781,7 @@ pub const Dir = struct {
|
|||||||
else => @compileError("unimplemented"),
|
else => @compileError("unimplemented"),
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn iterate(self: Dir) Iterator {
|
pub fn iterate(self: IterableDir) Iterator {
|
||||||
switch (builtin.os.tag) {
|
switch (builtin.os.tag) {
|
||||||
.macos,
|
.macos,
|
||||||
.ios,
|
.ios,
|
||||||
@@ -789,7 +791,7 @@ pub const Dir = struct {
|
|||||||
.openbsd,
|
.openbsd,
|
||||||
.solaris,
|
.solaris,
|
||||||
=> return Iterator{
|
=> return Iterator{
|
||||||
.dir = self,
|
.dir = self.dir,
|
||||||
.seek = 0,
|
.seek = 0,
|
||||||
.index = 0,
|
.index = 0,
|
||||||
.end_index = 0,
|
.end_index = 0,
|
||||||
@@ -797,14 +799,14 @@ pub const Dir = struct {
|
|||||||
.first_iter = true,
|
.first_iter = true,
|
||||||
},
|
},
|
||||||
.linux, .haiku => return Iterator{
|
.linux, .haiku => return Iterator{
|
||||||
.dir = self,
|
.dir = self.dir,
|
||||||
.index = 0,
|
.index = 0,
|
||||||
.end_index = 0,
|
.end_index = 0,
|
||||||
.buf = undefined,
|
.buf = undefined,
|
||||||
.first_iter = true,
|
.first_iter = true,
|
||||||
},
|
},
|
||||||
.windows => return Iterator{
|
.windows => return Iterator{
|
||||||
.dir = self,
|
.dir = self.dir,
|
||||||
.index = 0,
|
.index = 0,
|
||||||
.end_index = 0,
|
.end_index = 0,
|
||||||
.first_iter = true,
|
.first_iter = true,
|
||||||
@@ -812,7 +814,7 @@ pub const Dir = struct {
|
|||||||
.name_data = undefined,
|
.name_data = undefined,
|
||||||
},
|
},
|
||||||
.wasi => return Iterator{
|
.wasi => return Iterator{
|
||||||
.dir = self,
|
.dir = self.dir,
|
||||||
.cookie = os.wasi.DIRCOOKIE_START,
|
.cookie = os.wasi.DIRCOOKIE_START,
|
||||||
.index = 0,
|
.index = 0,
|
||||||
.end_index = 0,
|
.end_index = 0,
|
||||||
@@ -833,11 +835,11 @@ pub const Dir = struct {
|
|||||||
dir: Dir,
|
dir: Dir,
|
||||||
basename: []const u8,
|
basename: []const u8,
|
||||||
path: []const u8,
|
path: []const u8,
|
||||||
kind: Dir.Entry.Kind,
|
kind: IterableDir.Entry.Kind,
|
||||||
};
|
};
|
||||||
|
|
||||||
const StackItem = struct {
|
const StackItem = struct {
|
||||||
iter: Dir.Iterator,
|
iter: IterableDir.Iterator,
|
||||||
dirname_len: usize,
|
dirname_len: usize,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -857,7 +859,7 @@ pub const Dir = struct {
|
|||||||
}
|
}
|
||||||
try self.name_buffer.appendSlice(base.name);
|
try self.name_buffer.appendSlice(base.name);
|
||||||
if (base.kind == .Directory) {
|
if (base.kind == .Directory) {
|
||||||
var new_dir = top.iter.dir.openDir(base.name, .{ .iterate = true }) catch |err| switch (err) {
|
var new_dir = top.iter.dir.openIterableDir(base.name, .{}) catch |err| switch (err) {
|
||||||
error.NameTooLong => unreachable, // no path sep in base.name
|
error.NameTooLong => unreachable, // no path sep in base.name
|
||||||
else => |e| return e,
|
else => |e| return e,
|
||||||
};
|
};
|
||||||
@@ -896,11 +898,10 @@ pub const Dir = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Recursively iterates over a directory.
|
/// Recursively iterates over a directory.
|
||||||
/// `self` must have been opened with `OpenDirOptions{.iterate = true}`.
|
|
||||||
/// Must call `Walker.deinit` when done.
|
/// Must call `Walker.deinit` when done.
|
||||||
/// The order of returned file system entries is undefined.
|
/// The order of returned file system entries is undefined.
|
||||||
/// `self` will not be closed after walking it.
|
/// `self` will not be closed after walking it.
|
||||||
pub fn walk(self: Dir, allocator: Allocator) !Walker {
|
pub fn walk(self: IterableDir, allocator: Allocator) !Walker {
|
||||||
var name_buffer = std.ArrayList(u8).init(allocator);
|
var name_buffer = std.ArrayList(u8).init(allocator);
|
||||||
errdefer name_buffer.deinit();
|
errdefer name_buffer.deinit();
|
||||||
|
|
||||||
@@ -918,6 +919,49 @@ pub const Dir = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn close(self: *IterableDir) void {
|
||||||
|
self.dir.close();
|
||||||
|
self.* = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const ChmodError = File.ChmodError;
|
||||||
|
|
||||||
|
/// Changes the mode of the directory.
|
||||||
|
/// The process must have the correct privileges in order to do this
|
||||||
|
/// successfully, or must have the effective user ID matching the owner
|
||||||
|
/// of the directory.
|
||||||
|
pub fn chmod(self: IterableDir, new_mode: File.Mode) ChmodError!void {
|
||||||
|
const file: File = .{
|
||||||
|
.handle = self.dir.fd,
|
||||||
|
.capable_io_mode = .blocking,
|
||||||
|
};
|
||||||
|
try file.chmod(new_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Changes the owner and group of the directory.
|
||||||
|
/// The process must have the correct privileges in order to do this
|
||||||
|
/// successfully. The group may be changed by the owner of the directory to
|
||||||
|
/// any group of which the owner is a member. If the
|
||||||
|
/// owner or group is specified as `null`, the ID is not changed.
|
||||||
|
pub fn chown(self: IterableDir, owner: ?File.Uid, group: ?File.Gid) ChownError!void {
|
||||||
|
const file: File = .{
|
||||||
|
.handle = self.dir.fd,
|
||||||
|
.capable_io_mode = .blocking,
|
||||||
|
};
|
||||||
|
try file.chown(owner, group);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const ChownError = File.ChownError;
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Dir = struct {
|
||||||
|
fd: os.fd_t,
|
||||||
|
|
||||||
|
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{
|
pub const OpenError = error{
|
||||||
FileNotFound,
|
FileNotFound,
|
||||||
NotDir,
|
NotDir,
|
||||||
@@ -1334,6 +1378,15 @@ pub const Dir = struct {
|
|||||||
return self.openDir(sub_path, open_dir_options);
|
return self.openDir(sub_path, open_dir_options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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 {
|
||||||
|
// TODO improve this implementation on Windows; we can avoid 1 call to NtClose
|
||||||
|
try self.makePath(sub_path);
|
||||||
|
return self.openIterableDir(sub_path, open_dir_options);
|
||||||
|
}
|
||||||
|
|
||||||
/// This function returns the canonicalized absolute pathname of
|
/// This function returns the canonicalized absolute pathname of
|
||||||
/// `pathname` relative to this `Dir`. If `pathname` is absolute, ignores this
|
/// `pathname` relative to this `Dir`. If `pathname` is absolute, ignores this
|
||||||
/// `Dir` handle and returns the canonicalized absolute pathname of `pathname`
|
/// `Dir` handle and returns the canonicalized absolute pathname of `pathname`
|
||||||
@@ -1483,10 +1536,6 @@ pub const Dir = struct {
|
|||||||
/// such operations are Illegal Behavior.
|
/// such operations are Illegal Behavior.
|
||||||
access_sub_paths: bool = true,
|
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.
|
/// `true` means it won't dereference the symlinks.
|
||||||
no_follow: bool = false,
|
no_follow: bool = false,
|
||||||
};
|
};
|
||||||
@@ -1498,12 +1547,28 @@ pub const Dir = struct {
|
|||||||
pub fn openDir(self: Dir, sub_path: []const u8, args: OpenDirOptions) OpenError!Dir {
|
pub fn openDir(self: Dir, sub_path: []const u8, args: OpenDirOptions) OpenError!Dir {
|
||||||
if (builtin.os.tag == .windows) {
|
if (builtin.os.tag == .windows) {
|
||||||
const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);
|
const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);
|
||||||
return self.openDirW(sub_path_w.span().ptr, args);
|
return self.openDirW(sub_path_w.span().ptr, args, false);
|
||||||
} else if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
} else if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||||
return self.openDirWasi(sub_path, args);
|
return self.openDirWasi(sub_path, args);
|
||||||
} else {
|
} else {
|
||||||
const sub_path_c = try os.toPosixPath(sub_path);
|
const sub_path_c = try os.toPosixPath(sub_path);
|
||||||
return self.openDirZ(&sub_path_c, args);
|
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(sub_path);
|
||||||
|
return IterableDir{ .dir = try self.openDirW(sub_path_w.span().ptr, args, true) };
|
||||||
|
} else if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||||
|
return IterableDir{ .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) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1556,13 +1621,13 @@ pub const Dir = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Same as `openDir` except the parameter is null-terminated.
|
/// Same as `openDir` except the parameter is null-terminated.
|
||||||
pub fn openDirZ(self: Dir, sub_path_c: [*:0]const u8, args: OpenDirOptions) OpenError!Dir {
|
pub fn openDirZ(self: Dir, sub_path_c: [*:0]const u8, args: OpenDirOptions, iterable: bool) OpenError!Dir {
|
||||||
if (builtin.os.tag == .windows) {
|
if (builtin.os.tag == .windows) {
|
||||||
const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path_c);
|
const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path_c);
|
||||||
return self.openDirW(sub_path_w.span().ptr, args);
|
return self.openDirW(sub_path_w.span().ptr, args);
|
||||||
}
|
}
|
||||||
const symlink_flags: u32 = if (args.no_follow) os.O.NOFOLLOW else 0x0;
|
const symlink_flags: u32 = if (args.no_follow) os.O.NOFOLLOW else 0x0;
|
||||||
if (!args.iterate) {
|
if (!iterable) {
|
||||||
const O_PATH = if (@hasDecl(os.O, "PATH")) os.O.PATH else 0;
|
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);
|
return self.openDirFlagsZ(sub_path_c, os.O.DIRECTORY | os.O.RDONLY | os.O.CLOEXEC | O_PATH | symlink_flags);
|
||||||
} else {
|
} else {
|
||||||
@@ -1572,13 +1637,14 @@ pub const Dir = struct {
|
|||||||
|
|
||||||
/// Same as `openDir` except the path parameter is WTF-16 encoded, NT-prefixed.
|
/// Same as `openDir` except the path parameter is WTF-16 encoded, NT-prefixed.
|
||||||
/// This function asserts the target OS is Windows.
|
/// This function asserts the target OS is Windows.
|
||||||
pub fn openDirW(self: Dir, sub_path_w: [*:0]const u16, args: OpenDirOptions) OpenError!Dir {
|
pub fn openDirW(self: Dir, sub_path_w: [*:0]const u16, args: OpenDirOptions, iterable: bool) OpenError!Dir {
|
||||||
const w = os.windows;
|
const w = os.windows;
|
||||||
// TODO remove some of these flags if args.access_sub_paths is false
|
// 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 |
|
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;
|
||||||
const flags: u32 = if (args.iterate) base_flags | w.FILE_LIST_DIRECTORY else base_flags;
|
const flags: u32 = if (iterable) base_flags | w.FILE_LIST_DIRECTORY else base_flags;
|
||||||
return self.openDirAccessMaskW(sub_path_w, flags, args.no_follow);
|
var dir = try self.openDirAccessMaskW(sub_path_w, flags, args.no_follow);
|
||||||
|
return dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `flags` must contain `os.O.DIRECTORY`.
|
/// `flags` must contain `os.O.DIRECTORY`.
|
||||||
@@ -1958,7 +2024,7 @@ pub const Dir = struct {
|
|||||||
error.Unexpected,
|
error.Unexpected,
|
||||||
=> |e| return e,
|
=> |e| return e,
|
||||||
}
|
}
|
||||||
var dir = self.openDir(sub_path, .{ .iterate = true, .no_follow = true }) catch |err| switch (err) {
|
var iterable_dir = self.openIterableDir(sub_path, .{ .no_follow = true }) catch |err| switch (err) {
|
||||||
error.NotDir => {
|
error.NotDir => {
|
||||||
if (got_access_denied) {
|
if (got_access_denied) {
|
||||||
return error.AccessDenied;
|
return error.AccessDenied;
|
||||||
@@ -1984,11 +2050,11 @@ pub const Dir = struct {
|
|||||||
error.DeviceBusy,
|
error.DeviceBusy,
|
||||||
=> |e| return e,
|
=> |e| return e,
|
||||||
};
|
};
|
||||||
var cleanup_dir_parent: ?Dir = null;
|
var cleanup_dir_parent: ?IterableDir = null;
|
||||||
defer if (cleanup_dir_parent) |*d| d.close();
|
defer if (cleanup_dir_parent) |*d| d.close();
|
||||||
|
|
||||||
var cleanup_dir = true;
|
var cleanup_dir = true;
|
||||||
defer if (cleanup_dir) dir.close();
|
defer if (cleanup_dir) iterable_dir.close();
|
||||||
|
|
||||||
// Valid use of MAX_PATH_BYTES because dir_name_buf will only
|
// Valid use of MAX_PATH_BYTES because dir_name_buf will only
|
||||||
// ever store a single path component that was returned from the
|
// ever store a single path component that was returned from the
|
||||||
@@ -2001,9 +2067,9 @@ pub const Dir = struct {
|
|||||||
// open it, and close the original directory. Repeat. Then start the entire operation over.
|
// open it, and close the original directory. Repeat. Then start the entire operation over.
|
||||||
|
|
||||||
scan_dir: while (true) {
|
scan_dir: while (true) {
|
||||||
var dir_it = dir.iterate();
|
var dir_it = iterable_dir.iterate();
|
||||||
while (try dir_it.next()) |entry| {
|
while (try dir_it.next()) |entry| {
|
||||||
if (dir.deleteFile(entry.name)) {
|
if (iterable_dir.dir.deleteFile(entry.name)) {
|
||||||
continue;
|
continue;
|
||||||
} else |err| switch (err) {
|
} else |err| switch (err) {
|
||||||
error.FileNotFound => continue,
|
error.FileNotFound => continue,
|
||||||
@@ -2026,7 +2092,7 @@ pub const Dir = struct {
|
|||||||
=> |e| return e,
|
=> |e| return e,
|
||||||
}
|
}
|
||||||
|
|
||||||
const new_dir = dir.openDir(entry.name, .{ .iterate = true, .no_follow = true }) catch |err| switch (err) {
|
const new_dir = iterable_dir.dir.openIterableDir(entry.name, .{ .no_follow = true }) catch |err| switch (err) {
|
||||||
error.NotDir => {
|
error.NotDir => {
|
||||||
if (got_access_denied) {
|
if (got_access_denied) {
|
||||||
return error.AccessDenied;
|
return error.AccessDenied;
|
||||||
@@ -2053,19 +2119,19 @@ pub const Dir = struct {
|
|||||||
=> |e| return e,
|
=> |e| return e,
|
||||||
};
|
};
|
||||||
if (cleanup_dir_parent) |*d| d.close();
|
if (cleanup_dir_parent) |*d| d.close();
|
||||||
cleanup_dir_parent = dir;
|
cleanup_dir_parent = iterable_dir;
|
||||||
dir = new_dir;
|
iterable_dir = new_dir;
|
||||||
mem.copy(u8, &dir_name_buf, entry.name);
|
mem.copy(u8, &dir_name_buf, entry.name);
|
||||||
dir_name = dir_name_buf[0..entry.name.len];
|
dir_name = dir_name_buf[0..entry.name.len];
|
||||||
continue :scan_dir;
|
continue :scan_dir;
|
||||||
}
|
}
|
||||||
// Reached the end of the directory entries, which means we successfully deleted all of them.
|
// Reached the end of the directory entries, which means we successfully deleted all of them.
|
||||||
// Now to remove the directory itself.
|
// Now to remove the directory itself.
|
||||||
dir.close();
|
iterable_dir.close();
|
||||||
cleanup_dir = false;
|
cleanup_dir = false;
|
||||||
|
|
||||||
if (cleanup_dir_parent) |d| {
|
if (cleanup_dir_parent) |d| {
|
||||||
d.deleteDir(dir_name) catch |err| switch (err) {
|
d.dir.deleteDir(dir_name) catch |err| switch (err) {
|
||||||
// These two things can happen due to file system race conditions.
|
// These two things can happen due to file system race conditions.
|
||||||
error.FileNotFound, error.DirNotEmpty => continue :start_over,
|
error.FileNotFound, error.DirNotEmpty => continue :start_over,
|
||||||
else => |e| return e,
|
else => |e| return e,
|
||||||
@@ -2246,37 +2312,6 @@ pub const Dir = struct {
|
|||||||
return file.stat();
|
return file.stat();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const ChmodError = File.ChmodError;
|
|
||||||
|
|
||||||
/// Changes the mode of the directory.
|
|
||||||
/// The process must have the correct privileges in order to do this
|
|
||||||
/// successfully, or must have the effective user ID matching the owner
|
|
||||||
/// of the directory. Additionally, the directory must have been opened
|
|
||||||
/// with `OpenDirOptions{ .iterate = true }`.
|
|
||||||
pub fn chmod(self: Dir, new_mode: File.Mode) ChmodError!void {
|
|
||||||
const file: File = .{
|
|
||||||
.handle = self.fd,
|
|
||||||
.capable_io_mode = .blocking,
|
|
||||||
};
|
|
||||||
try file.chmod(new_mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Changes the owner and group of the directory.
|
|
||||||
/// The process must have the correct privileges in order to do this
|
|
||||||
/// successfully. The group may be changed by the owner of the directory to
|
|
||||||
/// any group of which the owner is a member. Additionally, the directory
|
|
||||||
/// must have been opened with `OpenDirOptions{ .iterate = true }`. If the
|
|
||||||
/// owner or group is specified as `null`, the ID is not changed.
|
|
||||||
pub fn chown(self: Dir, owner: ?File.Uid, group: ?File.Gid) ChownError!void {
|
|
||||||
const file: File = .{
|
|
||||||
.handle = self.fd,
|
|
||||||
.capable_io_mode = .blocking,
|
|
||||||
};
|
|
||||||
try file.chown(owner, group);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const ChownError = File.ChownError;
|
|
||||||
|
|
||||||
const Permissions = File.Permissions;
|
const Permissions = File.Permissions;
|
||||||
pub const SetPermissionsError = File.SetPermissionsError;
|
pub const SetPermissionsError = File.SetPermissionsError;
|
||||||
|
|
||||||
|
|||||||
@@ -8,8 +8,10 @@ const wasi = std.os.wasi;
|
|||||||
|
|
||||||
const ArenaAllocator = std.heap.ArenaAllocator;
|
const ArenaAllocator = std.heap.ArenaAllocator;
|
||||||
const Dir = std.fs.Dir;
|
const Dir = std.fs.Dir;
|
||||||
|
const IterableDir = std.fs.IterableDir;
|
||||||
const File = std.fs.File;
|
const File = std.fs.File;
|
||||||
const tmpDir = testing.tmpDir;
|
const tmpDir = testing.tmpDir;
|
||||||
|
const tmpIterableDir = testing.tmpIterableDir;
|
||||||
|
|
||||||
test "Dir.readLink" {
|
test "Dir.readLink" {
|
||||||
var tmp = tmpDir(.{});
|
var tmp = tmpDir(.{});
|
||||||
@@ -155,44 +157,44 @@ fn testReadLinkAbsolute(target_path: []const u8, symlink_path: []const u8) !void
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "Dir.Iterator" {
|
test "Dir.Iterator" {
|
||||||
var tmp_dir = tmpDir(.{ .iterate = true });
|
var tmp_dir = tmpIterableDir(.{});
|
||||||
defer tmp_dir.cleanup();
|
defer tmp_dir.cleanup();
|
||||||
|
|
||||||
// First, create a couple of entries to iterate over.
|
// First, create a couple of entries to iterate over.
|
||||||
const file = try tmp_dir.dir.createFile("some_file", .{});
|
const file = try tmp_dir.iterable_dir.dir.createFile("some_file", .{});
|
||||||
file.close();
|
file.close();
|
||||||
|
|
||||||
try tmp_dir.dir.makeDir("some_dir");
|
try tmp_dir.iterable_dir.dir.makeDir("some_dir");
|
||||||
|
|
||||||
var arena = ArenaAllocator.init(testing.allocator);
|
var arena = ArenaAllocator.init(testing.allocator);
|
||||||
defer arena.deinit();
|
defer arena.deinit();
|
||||||
const allocator = arena.allocator();
|
const allocator = arena.allocator();
|
||||||
|
|
||||||
var entries = std.ArrayList(Dir.Entry).init(allocator);
|
var entries = std.ArrayList(IterableDir.Entry).init(allocator);
|
||||||
|
|
||||||
// Create iterator.
|
// Create iterator.
|
||||||
var iter = tmp_dir.dir.iterate();
|
var iter = tmp_dir.iterable_dir.iterate();
|
||||||
while (try iter.next()) |entry| {
|
while (try iter.next()) |entry| {
|
||||||
// We cannot just store `entry` as on Windows, we're re-using the name buffer
|
// 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!
|
// which means we'll actually share the `name` pointer between entries!
|
||||||
const name = try allocator.dupe(u8, entry.name);
|
const name = try allocator.dupe(u8, entry.name);
|
||||||
try entries.append(Dir.Entry{ .name = name, .kind = entry.kind });
|
try entries.append(.{ .name = name, .kind = entry.kind });
|
||||||
}
|
}
|
||||||
|
|
||||||
try testing.expect(entries.items.len == 2); // note that the Iterator skips '.' and '..'
|
try testing.expect(entries.items.len == 2); // note that the Iterator skips '.' and '..'
|
||||||
try testing.expect(contains(&entries, Dir.Entry{ .name = "some_file", .kind = Dir.Entry.Kind.File }));
|
try testing.expect(contains(&entries, .{ .name = "some_file", .kind = .File }));
|
||||||
try testing.expect(contains(&entries, Dir.Entry{ .name = "some_dir", .kind = Dir.Entry.Kind.Directory }));
|
try testing.expect(contains(&entries, .{ .name = "some_dir", .kind = .Directory }));
|
||||||
}
|
}
|
||||||
|
|
||||||
test "Dir.Iterator twice" {
|
test "Dir.Iterator twice" {
|
||||||
var tmp_dir = tmpDir(.{ .iterate = true });
|
var tmp_dir = tmpIterableDir(.{});
|
||||||
defer tmp_dir.cleanup();
|
defer tmp_dir.cleanup();
|
||||||
|
|
||||||
// First, create a couple of entries to iterate over.
|
// First, create a couple of entries to iterate over.
|
||||||
const file = try tmp_dir.dir.createFile("some_file", .{});
|
const file = try tmp_dir.iterable_dir.dir.createFile("some_file", .{});
|
||||||
file.close();
|
file.close();
|
||||||
|
|
||||||
try tmp_dir.dir.makeDir("some_dir");
|
try tmp_dir.iterable_dir.dir.makeDir("some_dir");
|
||||||
|
|
||||||
var arena = ArenaAllocator.init(testing.allocator);
|
var arena = ArenaAllocator.init(testing.allocator);
|
||||||
defer arena.deinit();
|
defer arena.deinit();
|
||||||
@@ -200,28 +202,28 @@ test "Dir.Iterator twice" {
|
|||||||
|
|
||||||
var i: u8 = 0;
|
var i: u8 = 0;
|
||||||
while (i < 2) : (i += 1) {
|
while (i < 2) : (i += 1) {
|
||||||
var entries = std.ArrayList(Dir.Entry).init(allocator);
|
var entries = std.ArrayList(IterableDir.Entry).init(allocator);
|
||||||
|
|
||||||
// Create iterator.
|
// Create iterator.
|
||||||
var iter = tmp_dir.dir.iterate();
|
var iter = tmp_dir.iterable_dir.iterate();
|
||||||
while (try iter.next()) |entry| {
|
while (try iter.next()) |entry| {
|
||||||
// We cannot just store `entry` as on Windows, we're re-using the name buffer
|
// 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!
|
// which means we'll actually share the `name` pointer between entries!
|
||||||
const name = try allocator.dupe(u8, entry.name);
|
const name = try allocator.dupe(u8, entry.name);
|
||||||
try entries.append(Dir.Entry{ .name = name, .kind = entry.kind });
|
try entries.append(.{ .name = name, .kind = entry.kind });
|
||||||
}
|
}
|
||||||
|
|
||||||
try testing.expect(entries.items.len == 2); // note that the Iterator skips '.' and '..'
|
try testing.expect(entries.items.len == 2); // note that the Iterator skips '.' and '..'
|
||||||
try testing.expect(contains(&entries, Dir.Entry{ .name = "some_file", .kind = Dir.Entry.Kind.File }));
|
try testing.expect(contains(&entries, .{ .name = "some_file", .kind = .File }));
|
||||||
try testing.expect(contains(&entries, Dir.Entry{ .name = "some_dir", .kind = Dir.Entry.Kind.Directory }));
|
try testing.expect(contains(&entries, .{ .name = "some_dir", .kind = .Directory }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn entryEql(lhs: Dir.Entry, rhs: Dir.Entry) bool {
|
fn entryEql(lhs: IterableDir.Entry, rhs: IterableDir.Entry) bool {
|
||||||
return mem.eql(u8, lhs.name, rhs.name) and lhs.kind == rhs.kind;
|
return mem.eql(u8, lhs.name, rhs.name) and lhs.kind == rhs.kind;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn contains(entries: *const std.ArrayList(Dir.Entry), el: Dir.Entry) bool {
|
fn contains(entries: *const std.ArrayList(IterableDir.Entry), el: IterableDir.Entry) bool {
|
||||||
for (entries.items) |entry| {
|
for (entries.items) |entry| {
|
||||||
if (entryEql(entry, el)) return true;
|
if (entryEql(entry, el)) return true;
|
||||||
}
|
}
|
||||||
@@ -985,7 +987,7 @@ test "walker" {
|
|||||||
if (builtin.os.tag == .wasi and builtin.link_libc) return error.SkipZigTest;
|
if (builtin.os.tag == .wasi and builtin.link_libc) return error.SkipZigTest;
|
||||||
if (builtin.os.tag == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/");
|
if (builtin.os.tag == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/");
|
||||||
|
|
||||||
var tmp = tmpDir(.{ .iterate = true });
|
var tmp = tmpIterableDir(.{});
|
||||||
defer tmp.cleanup();
|
defer tmp.cleanup();
|
||||||
|
|
||||||
// iteration order of walker is undefined, so need lookup maps to check against
|
// iteration order of walker is undefined, so need lookup maps to check against
|
||||||
@@ -1011,10 +1013,10 @@ test "walker" {
|
|||||||
});
|
});
|
||||||
|
|
||||||
for (expected_paths.kvs) |kv| {
|
for (expected_paths.kvs) |kv| {
|
||||||
try tmp.dir.makePath(kv.key);
|
try tmp.iterable_dir.dir.makePath(kv.key);
|
||||||
}
|
}
|
||||||
|
|
||||||
var walker = try tmp.dir.walk(testing.allocator);
|
var walker = try tmp.iterable_dir.walk(testing.allocator);
|
||||||
defer walker.deinit();
|
defer walker.deinit();
|
||||||
|
|
||||||
var num_walked: usize = 0;
|
var num_walked: usize = 0;
|
||||||
@@ -1121,11 +1123,11 @@ test "chmod" {
|
|||||||
try testing.expect((try file.stat()).mode & 0o7777 == 0o644);
|
try testing.expect((try file.stat()).mode & 0o7777 == 0o644);
|
||||||
|
|
||||||
try tmp.dir.makeDir("test_dir");
|
try tmp.dir.makeDir("test_dir");
|
||||||
var dir = try tmp.dir.openDir("test_dir", .{ .iterate = true });
|
var iterable_dir = try tmp.dir.openIterableDir("test_dir", .{});
|
||||||
defer dir.close();
|
defer iterable_dir.close();
|
||||||
|
|
||||||
try dir.chmod(0o700);
|
try iterable_dir.chmod(0o700);
|
||||||
try testing.expect((try dir.stat()).mode & 0o7777 == 0o700);
|
try testing.expect((try iterable_dir.dir.stat()).mode & 0o7777 == 0o700);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "chown" {
|
test "chown" {
|
||||||
@@ -1141,9 +1143,9 @@ test "chown" {
|
|||||||
|
|
||||||
try tmp.dir.makeDir("test_dir");
|
try tmp.dir.makeDir("test_dir");
|
||||||
|
|
||||||
var dir = try tmp.dir.openDir("test_dir", .{ .iterate = true });
|
var iterable_dir = try tmp.dir.openIterableDir("test_dir", .{});
|
||||||
defer dir.close();
|
defer iterable_dir.close();
|
||||||
try dir.chown(null, null);
|
try iterable_dir.chown(null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "File.Metadata" {
|
test "File.Metadata" {
|
||||||
|
|||||||
@@ -308,7 +308,7 @@ pub fn fchmod(fd: fd_t, mode: mode_t) FChmodError!void {
|
|||||||
switch (system.getErrno(res)) {
|
switch (system.getErrno(res)) {
|
||||||
.SUCCESS => return,
|
.SUCCESS => return,
|
||||||
.INTR => continue,
|
.INTR => continue,
|
||||||
.BADF => unreachable, // Can be reached if the fd refers to a directory opened without `OpenDirOptions{ .iterate = true }`
|
.BADF => unreachable, // Can be reached if the fd refers to a non-iterable directory.
|
||||||
|
|
||||||
.FAULT => unreachable,
|
.FAULT => unreachable,
|
||||||
.INVAL => unreachable,
|
.INVAL => unreachable,
|
||||||
@@ -349,7 +349,7 @@ pub fn fchown(fd: fd_t, owner: ?uid_t, group: ?gid_t) FChownError!void {
|
|||||||
switch (system.getErrno(res)) {
|
switch (system.getErrno(res)) {
|
||||||
.SUCCESS => return,
|
.SUCCESS => return,
|
||||||
.INTR => continue,
|
.INTR => continue,
|
||||||
.BADF => unreachable, // Can be reached if the fd refers to a directory opened without `OpenDirOptions{ .iterate = true }`
|
.BADF => unreachable, // Can be reached if the fd refers to a non-iterable directory.
|
||||||
|
|
||||||
.FAULT => unreachable,
|
.FAULT => unreachable,
|
||||||
.INVAL => unreachable,
|
.INVAL => unreachable,
|
||||||
|
|||||||
@@ -363,6 +363,22 @@ 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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
fn getCwdOrWasiPreopen() std.fs.Dir {
|
fn getCwdOrWasiPreopen() std.fs.Dir {
|
||||||
if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||||
var preopens = std.fs.wasi.PreopenList.init(allocator);
|
var preopens = std.fs.wasi.PreopenList.init(allocator);
|
||||||
@@ -400,6 +416,28 @@ 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);
|
||||||
|
|
||||||
|
var cwd = getCwdOrWasiPreopen();
|
||||||
|
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();
|
||||||
|
var parent_dir = cache_dir.makeOpenPath("tmp", .{}) catch
|
||||||
|
@panic("unable to make tmp dir for testing: unable to make and open zig-cache/tmp dir");
|
||||||
|
var 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" {
|
test "expectEqual nested array" {
|
||||||
const a = [2][2]f32{
|
const a = [2][2]f32{
|
||||||
[_]f32{ 1.0, 0.0 },
|
[_]f32{ 1.0, 0.0 },
|
||||||
|
|||||||
12
src/main.zig
12
src/main.zig
@@ -4212,13 +4212,13 @@ fn fmtPathDir(
|
|||||||
parent_dir: fs.Dir,
|
parent_dir: fs.Dir,
|
||||||
parent_sub_path: []const u8,
|
parent_sub_path: []const u8,
|
||||||
) FmtError!void {
|
) FmtError!void {
|
||||||
var dir = try parent_dir.openDir(parent_sub_path, .{ .iterate = true });
|
var iterable_dir = try parent_dir.openIterableDir(parent_sub_path, .{});
|
||||||
defer dir.close();
|
defer iterable_dir.close();
|
||||||
|
|
||||||
const stat = try dir.stat();
|
const stat = try iterable_dir.dir.stat();
|
||||||
if (try fmt.seen.fetchPut(stat.inode, {})) |_| return;
|
if (try fmt.seen.fetchPut(stat.inode, {})) |_| return;
|
||||||
|
|
||||||
var dir_it = dir.iterate();
|
var dir_it = iterable_dir.iterate();
|
||||||
while (try dir_it.next()) |entry| {
|
while (try dir_it.next()) |entry| {
|
||||||
const is_dir = entry.kind == .Directory;
|
const is_dir = entry.kind == .Directory;
|
||||||
|
|
||||||
@@ -4229,9 +4229,9 @@ fn fmtPathDir(
|
|||||||
defer fmt.gpa.free(full_path);
|
defer fmt.gpa.free(full_path);
|
||||||
|
|
||||||
if (is_dir) {
|
if (is_dir) {
|
||||||
try fmtPathDir(fmt, full_path, check_mode, dir, entry.name);
|
try fmtPathDir(fmt, full_path, check_mode, iterable_dir.dir, entry.name);
|
||||||
} else {
|
} else {
|
||||||
fmtPathFile(fmt, full_path, check_mode, dir, entry.name) catch |err| {
|
fmtPathFile(fmt, full_path, check_mode, iterable_dir.dir, entry.name) catch |err| {
|
||||||
warn("unable to format '{s}': {s}", .{ full_path, @errorName(err) });
|
warn("unable to format '{s}': {s}", .{ full_path, @errorName(err) });
|
||||||
fmt.any_error = true;
|
fmt.any_error = true;
|
||||||
return;
|
return;
|
||||||
|
|||||||
10
src/test.zig
10
src/test.zig
@@ -54,7 +54,7 @@ test {
|
|||||||
std.fs.path.dirname(@src().file).?, "..", "test", "cases",
|
std.fs.path.dirname(@src().file).?, "..", "test", "cases",
|
||||||
});
|
});
|
||||||
|
|
||||||
var dir = try std.fs.cwd().openDir(dir_path, .{ .iterate = true });
|
var dir = try std.fs.cwd().openIterableDir(dir_path, .{});
|
||||||
defer dir.close();
|
defer dir.close();
|
||||||
|
|
||||||
ctx.addTestCasesFromDir(dir);
|
ctx.addTestCasesFromDir(dir);
|
||||||
@@ -1080,7 +1080,7 @@ pub const TestContext = struct {
|
|||||||
/// Each file should include a test manifest as a contiguous block of comments at
|
/// Each file should include a test manifest as a contiguous block of comments at
|
||||||
/// the end of the file. The first line should be the test type, followed by a set of
|
/// the end of the file. The first line should be the test type, followed by a set of
|
||||||
/// key-value config values, followed by a blank line, then the expected output.
|
/// key-value config values, followed by a blank line, then the expected output.
|
||||||
pub fn addTestCasesFromDir(ctx: *TestContext, dir: std.fs.Dir) void {
|
pub fn addTestCasesFromDir(ctx: *TestContext, dir: std.fs.IterableDir) void {
|
||||||
var current_file: []const u8 = "none";
|
var current_file: []const u8 = "none";
|
||||||
ctx.addTestCasesFromDirInner(dir, ¤t_file) catch |err| {
|
ctx.addTestCasesFromDirInner(dir, ¤t_file) catch |err| {
|
||||||
std.debug.panic("test harness failed to process file '{s}': {s}\n", .{
|
std.debug.panic("test harness failed to process file '{s}': {s}\n", .{
|
||||||
@@ -1091,12 +1091,12 @@ pub const TestContext = struct {
|
|||||||
|
|
||||||
fn addTestCasesFromDirInner(
|
fn addTestCasesFromDirInner(
|
||||||
ctx: *TestContext,
|
ctx: *TestContext,
|
||||||
dir: std.fs.Dir,
|
iterable_dir: std.fs.IterableDir,
|
||||||
/// This is kept up to date with the currently being processed file so
|
/// This is kept up to date with the currently being processed file so
|
||||||
/// that if any errors occur the caller knows it happened during this file.
|
/// that if any errors occur the caller knows it happened during this file.
|
||||||
current_file: *[]const u8,
|
current_file: *[]const u8,
|
||||||
) !void {
|
) !void {
|
||||||
var it = try dir.walk(ctx.arena);
|
var it = try iterable_dir.walk(ctx.arena);
|
||||||
var filenames = std.ArrayList([]const u8).init(ctx.arena);
|
var filenames = std.ArrayList([]const u8).init(ctx.arena);
|
||||||
|
|
||||||
while (try it.next()) |entry| {
|
while (try it.next()) |entry| {
|
||||||
@@ -1123,7 +1123,7 @@ pub const TestContext = struct {
|
|||||||
current_file.* = filename;
|
current_file.* = filename;
|
||||||
|
|
||||||
const max_file_size = 10 * 1024 * 1024;
|
const max_file_size = 10 * 1024 * 1024;
|
||||||
const src = try dir.readFileAllocOptions(ctx.arena, filename, max_file_size, null, 1, 0);
|
const src = try iterable_dir.dir.readFileAllocOptions(ctx.arena, filename, max_file_size, null, 1, 0);
|
||||||
|
|
||||||
// Parse the manifest
|
// Parse the manifest
|
||||||
var manifest = try TestManifest.parse(ctx.arena, src);
|
var manifest = try TestManifest.parse(ctx.arena, src);
|
||||||
|
|||||||
@@ -381,14 +381,14 @@ pub fn main() !void {
|
|||||||
try dir_stack.append(target_include_dir);
|
try dir_stack.append(target_include_dir);
|
||||||
|
|
||||||
while (dir_stack.popOrNull()) |full_dir_name| {
|
while (dir_stack.popOrNull()) |full_dir_name| {
|
||||||
var dir = std.fs.cwd().openDir(full_dir_name, .{ .iterate = true }) catch |err| switch (err) {
|
var iterable_dir = std.fs.cwd().openIterableDir(full_dir_name, .{}) catch |err| switch (err) {
|
||||||
error.FileNotFound => continue :search,
|
error.FileNotFound => continue :search,
|
||||||
error.AccessDenied => continue :search,
|
error.AccessDenied => continue :search,
|
||||||
else => return err,
|
else => return err,
|
||||||
};
|
};
|
||||||
defer dir.close();
|
defer iterable_dir.close();
|
||||||
|
|
||||||
var dir_it = dir.iterate();
|
var dir_it = iterable_dir.iterate();
|
||||||
|
|
||||||
while (try dir_it.next()) |entry| {
|
while (try dir_it.next()) |entry| {
|
||||||
const full_path = try std.fs.path.join(allocator, &[_][]const u8{ full_dir_name, entry.name });
|
const full_path = try std.fs.path.join(allocator, &[_][]const u8{ full_dir_name, entry.name });
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ pub fn main() !void {
|
|||||||
|
|
||||||
const args = try std.process.argsAlloc(arena);
|
const args = try std.process.argsAlloc(arena);
|
||||||
const path_to_walk = args[1];
|
const path_to_walk = args[1];
|
||||||
const dir = try std.fs.cwd().openDir(path_to_walk, .{ .iterate = true });
|
const iterable_dir = try std.fs.cwd().openIterableDir(path_to_walk, .{});
|
||||||
|
|
||||||
var walker = try dir.walk(arena);
|
var walker = try iterable_dir.walk(arena);
|
||||||
defer walker.deinit();
|
defer walker.deinit();
|
||||||
|
|
||||||
var buffer: [500]u8 = undefined;
|
var buffer: [500]u8 = undefined;
|
||||||
@@ -30,7 +30,7 @@ pub fn main() !void {
|
|||||||
node.activate();
|
node.activate();
|
||||||
defer node.end();
|
defer node.end();
|
||||||
|
|
||||||
const source = try dir.readFileAlloc(arena, entry.path, 20 * 1024 * 1024);
|
const source = try iterable_dir.dir.readFileAlloc(arena, entry.path, 20 * 1024 * 1024);
|
||||||
if (!std.mem.startsWith(u8, source, expected_header)) {
|
if (!std.mem.startsWith(u8, source, expected_header)) {
|
||||||
std.debug.print("no match: {s}\n", .{entry.path});
|
std.debug.print("no match: {s}\n", .{entry.path});
|
||||||
continue;
|
continue;
|
||||||
@@ -42,6 +42,6 @@ pub fn main() !void {
|
|||||||
std.mem.copy(u8, new_source, new_header);
|
std.mem.copy(u8, new_source, new_header);
|
||||||
std.mem.copy(u8, new_source[new_header.len..], truncated_source);
|
std.mem.copy(u8, new_source[new_header.len..], truncated_source);
|
||||||
|
|
||||||
try dir.writeFile(entry.path, new_source);
|
try iterable_dir.dir.writeFile(entry.path, new_source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -181,14 +181,14 @@ pub fn main() !void {
|
|||||||
try dir_stack.append(target_include_dir);
|
try dir_stack.append(target_include_dir);
|
||||||
|
|
||||||
while (dir_stack.popOrNull()) |full_dir_name| {
|
while (dir_stack.popOrNull()) |full_dir_name| {
|
||||||
var dir = std.fs.cwd().openDir(full_dir_name, .{ .iterate = true }) catch |err| switch (err) {
|
var iterable_dir = std.fs.cwd().openIterableDir(full_dir_name, .{}) catch |err| switch (err) {
|
||||||
error.FileNotFound => continue :search,
|
error.FileNotFound => continue :search,
|
||||||
error.AccessDenied => continue :search,
|
error.AccessDenied => continue :search,
|
||||||
else => return err,
|
else => return err,
|
||||||
};
|
};
|
||||||
defer dir.close();
|
defer iterable_dir.close();
|
||||||
|
|
||||||
var dir_it = dir.iterate();
|
var dir_it = iterable_dir.iterate();
|
||||||
|
|
||||||
while (try dir_it.next()) |entry| {
|
while (try dir_it.next()) |entry| {
|
||||||
const full_path = try std.fs.path.join(arena, &[_][]const u8{ full_dir_name, entry.name });
|
const full_path = try std.fs.path.join(arena, &[_][]const u8{ full_dir_name, entry.name });
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ pub fn main() !void {
|
|||||||
|
|
||||||
const dest_dir_path = try std.fmt.allocPrint(arena, "{s}/lib/libc/glibc", .{zig_src_path});
|
const dest_dir_path = try std.fmt.allocPrint(arena, "{s}/lib/libc/glibc", .{zig_src_path});
|
||||||
|
|
||||||
var dest_dir = fs.cwd().openDir(dest_dir_path, .{ .iterate = true }) catch |err| {
|
var dest_dir = fs.cwd().openIterableDir(dest_dir_path, .{}) catch |err| {
|
||||||
fatal("unable to open destination directory '{s}': {s}", .{
|
fatal("unable to open destination directory '{s}': {s}", .{
|
||||||
dest_dir_path, @errorName(err),
|
dest_dir_path, @errorName(err),
|
||||||
});
|
});
|
||||||
@@ -63,14 +63,14 @@ pub fn main() !void {
|
|||||||
if (mem.eql(u8, entry.path, p)) continue :walk;
|
if (mem.eql(u8, entry.path, p)) continue :walk;
|
||||||
}
|
}
|
||||||
|
|
||||||
glibc_src_dir.copyFile(entry.path, dest_dir, entry.path, .{}) catch |err| {
|
glibc_src_dir.copyFile(entry.path, dest_dir.dir, entry.path, .{}) catch |err| {
|
||||||
log.warn("unable to copy '{s}/{s}' to '{s}/{s}': {s}", .{
|
log.warn("unable to copy '{s}/{s}' to '{s}/{s}': {s}", .{
|
||||||
glibc_src_path, entry.path,
|
glibc_src_path, entry.path,
|
||||||
dest_dir_path, entry.path,
|
dest_dir_path, entry.path,
|
||||||
@errorName(err),
|
@errorName(err),
|
||||||
});
|
});
|
||||||
if (err == error.FileNotFound) {
|
if (err == error.FileNotFound) {
|
||||||
try dest_dir.deleteFile(entry.path);
|
try dest_dir.dir.deleteFile(entry.path);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -79,7 +79,7 @@ pub fn main() !void {
|
|||||||
// Warn about duplicated files inside glibc/include/* that can be omitted
|
// Warn about duplicated files inside glibc/include/* that can be omitted
|
||||||
// because they are already in generic-glibc/*.
|
// because they are already in generic-glibc/*.
|
||||||
|
|
||||||
var include_dir = dest_dir.openDir("include", .{ .iterate = true }) catch |err| {
|
var include_dir = dest_dir.dir.openIterableDir("include", .{}) catch |err| {
|
||||||
fatal("unable to open directory '{s}/include': {s}", .{
|
fatal("unable to open directory '{s}/include': {s}", .{
|
||||||
dest_dir_path, @errorName(err),
|
dest_dir_path, @errorName(err),
|
||||||
});
|
});
|
||||||
@@ -116,7 +116,7 @@ pub fn main() !void {
|
|||||||
generic_glibc_path, entry.path, @errorName(e),
|
generic_glibc_path, entry.path, @errorName(e),
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
const glibc_include_contents = include_dir.readFileAlloc(
|
const glibc_include_contents = include_dir.dir.readFileAlloc(
|
||||||
arena,
|
arena,
|
||||||
entry.path,
|
entry.path,
|
||||||
max_file_size,
|
max_file_size,
|
||||||
|
|||||||
@@ -218,7 +218,7 @@ pub fn main() !void {
|
|||||||
/// TODO: Unfortunately, neither repository contains a machine-readable list of extension dependencies.
|
/// TODO: Unfortunately, neither repository contains a machine-readable list of extension dependencies.
|
||||||
fn gather_extensions(allocator: Allocator, spirv_registry_root: []const u8) ![]const []const u8 {
|
fn gather_extensions(allocator: Allocator, spirv_registry_root: []const u8) ![]const []const u8 {
|
||||||
const extensions_path = try fs.path.join(allocator, &.{ spirv_registry_root, "extensions" });
|
const extensions_path = try fs.path.join(allocator, &.{ spirv_registry_root, "extensions" });
|
||||||
var extensions_dir = try fs.cwd().openDir(extensions_path, .{ .iterate = true });
|
var extensions_dir = try fs.cwd().openIterableDir(extensions_path, .{});
|
||||||
defer extensions_dir.close();
|
defer extensions_dir.close();
|
||||||
|
|
||||||
var extensions = std.ArrayList([]const u8).init(allocator);
|
var extensions = std.ArrayList([]const u8).init(allocator);
|
||||||
@@ -227,7 +227,7 @@ fn gather_extensions(allocator: Allocator, spirv_registry_root: []const u8) ![]c
|
|||||||
while (try vendor_it.next()) |vendor_entry| {
|
while (try vendor_it.next()) |vendor_entry| {
|
||||||
std.debug.assert(vendor_entry.kind == .Directory); // If this fails, the structure of SPIRV-Registry has changed.
|
std.debug.assert(vendor_entry.kind == .Directory); // If this fails, the structure of SPIRV-Registry has changed.
|
||||||
|
|
||||||
const vendor_dir = try extensions_dir.openDir(vendor_entry.name, .{ .iterate = true });
|
const vendor_dir = try extensions_dir.dir.openIterableDir(vendor_entry.name, .{});
|
||||||
var ext_it = vendor_dir.iterate();
|
var ext_it = vendor_dir.iterate();
|
||||||
while (try ext_it.next()) |ext_entry| {
|
while (try ext_it.next()) |ext_entry| {
|
||||||
// There is both a HTML and asciidoc version of every spec (as well as some other directories),
|
// There is both a HTML and asciidoc version of every spec (as well as some other directories),
|
||||||
@@ -250,7 +250,7 @@ fn gather_extensions(allocator: Allocator, spirv_registry_root: []const u8) ![]c
|
|||||||
// SPV_EXT_name
|
// SPV_EXT_name
|
||||||
// ```
|
// ```
|
||||||
|
|
||||||
const ext_spec = try vendor_dir.readFileAlloc(allocator, ext_entry.name, std.math.maxInt(usize));
|
const ext_spec = try vendor_dir.dir.readFileAlloc(allocator, ext_entry.name, std.math.maxInt(usize));
|
||||||
const name_strings = "Name Strings";
|
const name_strings = "Name Strings";
|
||||||
|
|
||||||
const name_strings_offset = std.mem.indexOf(u8, ext_spec, name_strings) orelse return error.InvalidRegistry;
|
const name_strings_offset = std.mem.indexOf(u8, ext_spec, name_strings) orelse return error.InvalidRegistry;
|
||||||
|
|||||||
Reference in New Issue
Block a user