aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2025-12-11 22:11:16 -0800
committerAndrew Kelley <andrew@ziglang.org>2025-12-23 22:15:09 -0800
commit68621afd2e203d82b6f53bf4ede951827fa98db8 (patch)
tree60899decd0062ce7786592e49ca77ab6f80d22fd
parent0e230993d51d0ecded40d5235ada4f2f64036b26 (diff)
downloadzig-68621afd2e203d82b6f53bf4ede951827fa98db8.tar.gz
zig-68621afd2e203d82b6f53bf4ede951827fa98db8.zip
std.tar: update fs API calls to take io argument
-rw-r--r--lib/compiler/aro/aro/Compilation.zig3
-rw-r--r--lib/std/Build/Cache/Path.zig4
-rw-r--r--lib/std/Io.zig2
-rw-r--r--lib/std/Io/Dir.zig12
-rw-r--r--lib/std/Io/File.zig3
-rw-r--r--lib/std/Io/Threaded.zig50
-rw-r--r--lib/std/fs/test.zig57
-rw-r--r--lib/std/tar.zig54
-rw-r--r--lib/std/tar/test.zig4
-rw-r--r--lib/std/zig/WindowsSdk.zig2
-rw-r--r--lib/std/zig/parser_test.zig2
-rw-r--r--src/Builtin.zig3
-rw-r--r--src/Package/Fetch.zig20
-rw-r--r--src/Package/Fetch/git.zig2
-rw-r--r--src/fmt.zig2
15 files changed, 110 insertions, 110 deletions
diff --git a/lib/compiler/aro/aro/Compilation.zig b/lib/compiler/aro/aro/Compilation.zig
index b3e4d5544d..a78f18dd74 100644
--- a/lib/compiler/aro/aro/Compilation.zig
+++ b/lib/compiler/aro/aro/Compilation.zig
@@ -2162,8 +2162,9 @@ pub fn locSlice(comp: *const Compilation, loc: Source.Location) []const u8 {
}
pub fn getSourceMTimeUncached(comp: *const Compilation, source_id: Source.Id) ?u64 {
+ const io = comp.io;
const source = comp.getSource(source_id);
- if (comp.cwd.statFile(source.path)) |stat| {
+ if (comp.cwd.statFile(io, source.path, .{})) |stat| {
return std.math.cast(u64, stat.mtime.toSeconds());
} else |_| {
return null;
diff --git a/lib/std/Build/Cache/Path.zig b/lib/std/Build/Cache/Path.zig
index 759eb143b8..54104afa41 100644
--- a/lib/std/Build/Cache/Path.zig
+++ b/lib/std/Build/Cache/Path.zig
@@ -94,14 +94,14 @@ pub fn makeOpenPath(p: Path, sub_path: []const u8, opts: Io.Dir.OpenOptions) !Io
return p.root_dir.handle.makeOpenPath(joined_path, opts);
}
-pub fn statFile(p: Path, sub_path: []const u8) !Io.Dir.Stat {
+pub fn statFile(p: Path, io: Io, sub_path: []const u8) !Io.Dir.Stat {
var buf: [fs.max_path_bytes]u8 = undefined;
const joined_path = if (p.sub_path.len == 0) sub_path else p: {
break :p std.fmt.bufPrint(&buf, "{s}" ++ fs.path.sep_str ++ "{s}", .{
p.sub_path, sub_path,
}) catch return error.NameTooLong;
};
- return p.root_dir.handle.statFile(joined_path);
+ return p.root_dir.handle.statFile(io, joined_path, .{});
}
pub fn atomicFile(
diff --git a/lib/std/Io.zig b/lib/std/Io.zig
index b76cbebe3a..83a2e940bf 100644
--- a/lib/std/Io.zig
+++ b/lib/std/Io.zig
@@ -671,7 +671,7 @@ pub const VTable = struct {
dirMakeOpenPath: *const fn (?*anyopaque, Dir, []const u8, Dir.Permissions, Dir.OpenOptions) Dir.MakeOpenPathError!Dir,
dirOpenDir: *const fn (?*anyopaque, Dir, []const u8, Dir.OpenOptions) Dir.OpenError!Dir,
dirStat: *const fn (?*anyopaque, Dir) Dir.StatError!Dir.Stat,
- dirStatPath: *const fn (?*anyopaque, Dir, []const u8, Dir.StatPathOptions) Dir.StatPathError!File.Stat,
+ dirStatFile: *const fn (?*anyopaque, Dir, []const u8, Dir.StatFileOptions) Dir.StatFileError!File.Stat,
dirAccess: *const fn (?*anyopaque, Dir, []const u8, Dir.AccessOptions) Dir.AccessError!void,
dirCreateFile: *const fn (?*anyopaque, Dir, []const u8, File.CreateFlags) File.OpenError!File,
dirOpenFile: *const fn (?*anyopaque, Dir, []const u8, File.OpenFlags) File.OpenError!File,
diff --git a/lib/std/Io/Dir.zig b/lib/std/Io/Dir.zig
index 085667edca..0bc3982a61 100644
--- a/lib/std/Io/Dir.zig
+++ b/lib/std/Io/Dir.zig
@@ -669,7 +669,7 @@ pub fn makeDirAbsolute(io: Io, absolute_path: []const u8, permissions: Permissio
test makeDirAbsolute {}
-pub const MakePathError = MakeError || StatPathError;
+pub const MakePathError = MakeError || StatFileError;
/// Creates parent directories with default permissions as necessary to ensure
/// `sub_path` exists as a directory.
@@ -708,7 +708,7 @@ pub fn makePathStatus(dir: Dir, io: Io, sub_path: []const u8, permissions: Permi
return io.vtable.dirMakePath(io.userdata, dir, sub_path, permissions);
}
-pub const MakeOpenPathError = MakeError || OpenError || StatPathError;
+pub const MakeOpenPathError = MakeError || OpenError || StatFileError;
pub const MakeOpenPathOptions = struct {
open_options: OpenOptions = .{},
@@ -734,9 +734,9 @@ pub fn stat(dir: Dir, io: Io) StatError!Stat {
return io.vtable.dirStat(io.userdata, dir);
}
-pub const StatPathError = File.OpenError || File.StatError;
+pub const StatFileError = File.OpenError || File.StatError;
-pub const StatPathOptions = struct {
+pub const StatFileOptions = struct {
follow_symlinks: bool = true,
};
@@ -752,8 +752,8 @@ pub const StatPathOptions = struct {
/// * On Windows, `sub_path` should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
/// * On WASI, `sub_path` should be encoded as valid UTF-8.
/// * On other platforms, `sub_path` is an opaque sequence of bytes with no particular encoding.
-pub fn statPath(dir: Dir, io: Io, sub_path: []const u8, options: StatPathOptions) StatPathError!Stat {
- return io.vtable.dirStatPath(io.userdata, dir, sub_path, options);
+pub fn statFile(dir: Dir, io: Io, sub_path: []const u8, options: StatFileOptions) StatFileError!Stat {
+ return io.vtable.dirStatFile(io.userdata, dir, sub_path, options);
}
pub const RealPathError = error{
diff --git a/lib/std/Io/File.zig b/lib/std/Io/File.zig
index ccf18a8f56..3c04909d46 100644
--- a/lib/std/Io/File.zig
+++ b/lib/std/Io/File.zig
@@ -372,6 +372,7 @@ pub const Permissions = std.options.FilePermissions orelse if (is_windows) enum(
_,
pub const default_dir: @This() = .default_file;
+ pub const executable_file: @This() = .default_file;
pub const has_executable_bit = false;
const windows = std.os.windows;
@@ -401,6 +402,7 @@ pub const Permissions = std.options.FilePermissions orelse if (is_windows) enum(
/// process-scoped "umask" setting to adjust this number for file creation.
default_file = 0o666,
default_dir = 0o755,
+ executable_file = 0o777,
_,
pub const has_executable_bit = true;
@@ -428,6 +430,7 @@ pub const Permissions = std.options.FilePermissions orelse if (is_windows) enum(
} else enum(u0) {
default_file = 0,
pub const default_dir: @This() = .default_file;
+ pub const executable_file: @This() = .default_file;
pub const has_executable_bit = false;
};
diff --git a/lib/std/Io/Threaded.zig b/lib/std/Io/Threaded.zig
index 2fb0f3ad1f..d4c4da3990 100644
--- a/lib/std/Io/Threaded.zig
+++ b/lib/std/Io/Threaded.zig
@@ -708,7 +708,7 @@ pub fn io(t: *Threaded) Io {
.dirMakePath = dirMakePath,
.dirMakeOpenPath = dirMakeOpenPath,
.dirStat = dirStat,
- .dirStatPath = dirStatPath,
+ .dirStatFile = dirStatFile,
.dirAccess = dirAccess,
.dirCreateFile = dirCreateFile,
.dirOpenFile = dirOpenFile,
@@ -840,7 +840,7 @@ pub fn ioBasic(t: *Threaded) Io {
.dirMakePath = dirMakePath,
.dirMakeOpenPath = dirMakeOpenPath,
.dirStat = dirStat,
- .dirStatPath = dirStatPath,
+ .dirStatFile = dirStatFile,
.dirAccess = dirAccess,
.dirCreateFile = dirCreateFile,
.dirOpenFile = dirOpenFile,
@@ -1623,7 +1623,7 @@ fn dirMakePath(
// could cause an infinite loop
check_dir: {
// workaround for windows, see https://github.com/ziglang/zig/issues/16738
- const fstat = dirStatPath(t, dir, component.path, .{}) catch |stat_err| switch (stat_err) {
+ const fstat = dirStatFile(t, dir, component.path, .{}) catch |stat_err| switch (stat_err) {
error.IsDir => break :check_dir,
else => |e| return e,
};
@@ -1752,7 +1752,7 @@ fn dirMakeOpenPathWindows(
// could cause an infinite loop
check_dir: {
// workaround for windows, see https://github.com/ziglang/zig/issues/16738
- const fstat = dirStatPathWindows(t, dir, component.path, .{
+ const fstat = dirStatFileWindows(t, dir, component.path, .{
.follow_symlinks = options.follow_symlinks,
}) catch |stat_err| switch (stat_err) {
error.IsDir => break :check_dir,
@@ -1806,19 +1806,19 @@ fn dirStat(userdata: ?*anyopaque, dir: Dir) Dir.StatError!Dir.Stat {
return fileStat(t, file);
}
-const dirStatPath = switch (native_os) {
- .linux => dirStatPathLinux,
- .windows => dirStatPathWindows,
- .wasi => dirStatPathWasi,
- else => dirStatPathPosix,
+const dirStatFile = switch (native_os) {
+ .linux => dirStatFileLinux,
+ .windows => dirStatFileWindows,
+ .wasi => dirStatFileWasi,
+ else => dirStatFilePosix,
};
-fn dirStatPathLinux(
+fn dirStatFileLinux(
userdata: ?*anyopaque,
dir: Dir,
sub_path: []const u8,
- options: Dir.StatPathOptions,
-) Dir.StatPathError!File.Stat {
+ options: Dir.StatFileOptions,
+) Dir.StatFileError!File.Stat {
const t: *Threaded = @ptrCast(@alignCast(userdata));
const current_thread = Thread.getCurrent(t);
const linux = std.os.linux;
@@ -1875,12 +1875,12 @@ fn dirStatPathLinux(
}
}
-fn dirStatPathPosix(
+fn dirStatFilePosix(
userdata: ?*anyopaque,
dir: Dir,
sub_path: []const u8,
- options: Dir.StatPathOptions,
-) Dir.StatPathError!File.Stat {
+ options: Dir.StatFileOptions,
+) Dir.StatFileError!File.Stat {
const t: *Threaded = @ptrCast(@alignCast(userdata));
const current_thread = Thread.getCurrent(t);
@@ -1889,10 +1889,10 @@ fn dirStatPathPosix(
const flags: u32 = if (!options.follow_symlinks) posix.AT.SYMLINK_NOFOLLOW else 0;
- return posixStatPath(current_thread, dir.handle, sub_path_posix, flags);
+ return posixStatFile(current_thread, dir.handle, sub_path_posix, flags);
}
-fn posixStatPath(current_thread: *Thread, dir_fd: posix.fd_t, sub_path: [:0]const u8, flags: u32) Dir.StatPathError!File.Stat {
+fn posixStatFile(current_thread: *Thread, dir_fd: posix.fd_t, sub_path: [:0]const u8, flags: u32) Dir.StatFileError!File.Stat {
try current_thread.beginSyscall();
while (true) {
var stat = std.mem.zeroes(posix.Stat);
@@ -1927,12 +1927,12 @@ fn posixStatPath(current_thread: *Thread, dir_fd: posix.fd_t, sub_path: [:0]cons
}
}
-fn dirStatPathWindows(
+fn dirStatFileWindows(
userdata: ?*anyopaque,
dir: Dir,
sub_path: []const u8,
- options: Dir.StatPathOptions,
-) Dir.StatPathError!File.Stat {
+ options: Dir.StatFileOptions,
+) Dir.StatFileError!File.Stat {
const t: *Threaded = @ptrCast(@alignCast(userdata));
const file = try dirOpenFileWindows(t, dir, sub_path, .{
.follow_symlinks = options.follow_symlinks,
@@ -1941,13 +1941,13 @@ fn dirStatPathWindows(
return fileStatWindows(t, file);
}
-fn dirStatPathWasi(
+fn dirStatFileWasi(
userdata: ?*anyopaque,
dir: Dir,
sub_path: []const u8,
- options: Dir.StatPathOptions,
-) Dir.StatPathError!File.Stat {
- if (builtin.link_libc) return dirStatPathPosix(userdata, dir, sub_path, options);
+ options: Dir.StatFileOptions,
+) Dir.StatFileError!File.Stat {
+ if (builtin.link_libc) return dirStatFilePosix(userdata, dir, sub_path, options);
const t: *Threaded = @ptrCast(@alignCast(userdata));
const current_thread = Thread.getCurrent(t);
const wasi = std.os.wasi;
@@ -3629,7 +3629,7 @@ fn dirReadIllumos(userdata: ?*anyopaque, dr: *Dir.Reader, buffer: []Dir.Entry) D
if (std.mem.eql(u8, name, ".") or std.mem.eql(u8, name, "..")) continue;
// illumos dirent doesn't expose type, so we have to call stat to get it.
- const stat = try posixStatPath(current_thread, dr.dir.handle, name, posix.AT.SYMLINK_NOFOLLOW);
+ const stat = try posixStatFile(current_thread, dr.dir.handle, name, posix.AT.SYMLINK_NOFOLLOW);
buffer[buffer_index] = .{
.name = name,
diff --git a/lib/std/fs/test.zig b/lib/std/fs/test.zig
index 3a4b551ae8..dd9b21d77b 100644
--- a/lib/std/fs/test.zig
+++ b/lib/std/fs/test.zig
@@ -160,8 +160,8 @@ fn testWithPathTypeIfSupported(comptime path_type: PathType, comptime path_sep:
// For use in test setup. If the symlink creation fails on Windows with
// AccessDenied, then make the test failure silent (it is not a Zig failure).
-fn setupSymlink(dir: Dir, target: []const u8, link: []const u8, flags: SymLinkFlags) !void {
- return dir.symLink(target, link, flags) catch |err| switch (err) {
+fn setupSymlink(io: Io, dir: Dir, target: []const u8, link: []const u8, flags: SymLinkFlags) !void {
+ return dir.symLink(io, target, link, flags) catch |err| switch (err) {
// Symlink requires admin privileges on windows, so this test can legitimately fail.
error.AccessDenied => if (native_os == .windows) return error.SkipZigTest else return err,
else => return err,
@@ -193,15 +193,15 @@ test "Dir.readLink" {
const canonical_dir_target_path = try ctx.toCanonicalPathSep(dir_target_path);
// test 1: symlink to a file
- try setupSymlink(ctx.dir, file_target_path, "symlink1", .{});
- try testReadLink(ctx.dir, canonical_file_target_path, "symlink1");
+ try setupSymlink(io, ctx.dir, file_target_path, "symlink1", .{});
+ try testReadLink(io, ctx.dir, canonical_file_target_path, "symlink1");
if (builtin.os.tag == .windows) {
try testReadLinkW(testing.allocator, ctx.dir, canonical_file_target_path, "symlink1");
}
// test 2: symlink to a directory (can be different on Windows)
- try setupSymlink(ctx.dir, dir_target_path, "symlink2", .{ .is_directory = true });
- try testReadLink(ctx.dir, canonical_dir_target_path, "symlink2");
+ try setupSymlink(io, ctx.dir, dir_target_path, "symlink2", .{ .is_directory = true });
+ try testReadLink(io, ctx.dir, canonical_dir_target_path, "symlink2");
if (builtin.os.tag == .windows) {
try testReadLinkW(testing.allocator, ctx.dir, canonical_dir_target_path, "symlink2");
}
@@ -211,8 +211,8 @@ test "Dir.readLink" {
const canonical_parent_file = try ctx.toCanonicalPathSep(parent_file);
var subdir = try ctx.dir.makeOpenPath("subdir", .{});
defer subdir.close(io);
- try setupSymlink(subdir, canonical_parent_file, "relative-link.txt", .{});
- try testReadLink(subdir, canonical_parent_file, "relative-link.txt");
+ try setupSymlink(io, subdir, canonical_parent_file, "relative-link.txt", .{});
+ try testReadLink(io, subdir, canonical_parent_file, "relative-link.txt");
if (builtin.os.tag == .windows) {
try testReadLinkW(testing.allocator, subdir, canonical_parent_file, "relative-link.txt");
}
@@ -246,9 +246,9 @@ test "Dir.readLink on non-symlinks" {
}.impl);
}
-fn testReadLink(dir: Dir, target_path: []const u8, symlink_path: []const u8) !void {
+fn testReadLink(io: Io, dir: Dir, target_path: []const u8, symlink_path: []const u8) !void {
var buffer: [fs.max_path_bytes]u8 = undefined;
- const actual = try dir.readLink(symlink_path, buffer[0..]);
+ const actual = try dir.readLink(io, symlink_path, &buffer);
try testing.expectEqualStrings(target_path, actual);
}
@@ -284,7 +284,7 @@ test "File.stat on a File that is a symlink returns Kind.sym_link" {
const dir_target_path = try ctx.transformPath("subdir");
try ctx.dir.makeDir(io, dir_target_path, .default_dir);
- try setupSymlink(ctx.dir, dir_target_path, "symlink", .{ .is_directory = true });
+ try setupSymlink(io, ctx.dir, dir_target_path, "symlink", .{ .is_directory = true });
var symlink: Dir = switch (builtin.target.os.tag) {
.windows => windows_symlink: {
@@ -809,11 +809,11 @@ test "Dir.statFile" {
const io = ctx.io;
const test_file_name = try ctx.transformPath("test_file");
- try testing.expectError(error.FileNotFound, ctx.dir.statFile(test_file_name));
+ try testing.expectError(error.FileNotFound, ctx.dir.statFile(io, test_file_name, .{}));
try ctx.dir.writeFile(io, .{ .sub_path = test_file_name, .data = "" });
- const stat = try ctx.dir.statFile(test_file_name);
+ const stat = try ctx.dir.statFile(io, test_file_name, .{});
try testing.expectEqual(File.Kind.file, stat.kind);
}
}.impl);
@@ -822,12 +822,13 @@ test "Dir.statFile" {
test "statFile on dangling symlink" {
try testWithAllSupportedPathTypes(struct {
fn impl(ctx: *TestContext) !void {
+ const io = ctx.io;
const symlink_name = try ctx.transformPath("dangling-symlink");
const symlink_target = "." ++ fs.path.sep_str ++ "doesnotexist";
- try setupSymlink(ctx.dir, symlink_target, symlink_name, .{});
+ try setupSymlink(io, ctx.dir, symlink_target, symlink_name, .{});
- try std.testing.expectError(error.FileNotFound, ctx.dir.statFile(symlink_name));
+ try std.testing.expectError(error.FileNotFound, ctx.dir.statFile(io, symlink_name, .{}));
}
}.impl);
}
@@ -1206,7 +1207,7 @@ test "deleteTree does not follow symlinks" {
var a = try tmp.dir.makeOpenPath("a", .{});
defer a.close(io);
- try setupSymlink(a, "../b", "b", .{ .is_directory = true });
+ try setupSymlink(io, a, "../b", "b", .{ .is_directory = true });
}
try tmp.dir.deleteTree(io, "a");
@@ -1223,7 +1224,7 @@ test "deleteTree on a symlink" {
// Symlink to a file
try tmp.dir.writeFile(io, .{ .sub_path = "file", .data = "" });
- try setupSymlink(tmp.dir, "file", "filelink", .{});
+ try setupSymlink(io, tmp.dir, "file", "filelink", .{});
try tmp.dir.deleteTree(io, "filelink");
try testing.expectError(error.FileNotFound, tmp.dir.access(io, "filelink", .{}));
@@ -1231,7 +1232,7 @@ test "deleteTree on a symlink" {
// Symlink to a directory
try tmp.dir.makePath(io, "dir");
- try setupSymlink(tmp.dir, "dir", "dirlink", .{ .is_directory = true });
+ try setupSymlink(io, tmp.dir, "dir", "dirlink", .{ .is_directory = true });
try tmp.dir.deleteTree(io, "dirlink");
try testing.expectError(error.FileNotFound, tmp.dir.access(io, "dirlink", .{}));
@@ -1337,7 +1338,7 @@ test "makepath through existing valid symlink" {
defer tmp.cleanup();
try tmp.dir.makeDir(io, "realfolder", .default_dir);
- try setupSymlink(tmp.dir, "." ++ fs.path.sep_str ++ "realfolder", "working-symlink", .{});
+ try setupSymlink(io, tmp.dir, "." ++ fs.path.sep_str ++ "realfolder", "working-symlink", .{});
try tmp.dir.makePath(io, "working-symlink" ++ fs.path.sep_str ++ "in-realfolder");
@@ -2178,12 +2179,12 @@ test "invalid UTF-8/WTF-8 paths" {
try testing.expectError(expected_err, ctx.dir.rename(invalid_path, ctx.dir, invalid_path, io));
- try testing.expectError(expected_err, ctx.dir.symLink(invalid_path, invalid_path, .{}));
+ try testing.expectError(expected_err, ctx.dir.symLink(io, invalid_path, invalid_path, .{}));
if (native_os == .wasi) {
try testing.expectError(expected_err, ctx.dir.symLinkWasi(invalid_path, invalid_path, .{}));
}
- try testing.expectError(expected_err, ctx.dir.readLink(invalid_path, &[_]u8{}));
+ try testing.expectError(expected_err, ctx.dir.readLink(io, invalid_path, &[_]u8{}));
if (native_os == .wasi) {
try testing.expectError(expected_err, ctx.dir.readLinkWasi(invalid_path, &[_]u8{}));
}
@@ -2386,14 +2387,16 @@ test "File.Writer sendfile with buffered contents" {
test "readlink on Windows" {
if (native_os != .windows) return error.SkipZigTest;
- try testReadlink("C:\\ProgramData", "C:\\Users\\All Users");
- try testReadlink("C:\\Users\\Default", "C:\\Users\\Default User");
- try testReadlink("C:\\Users", "C:\\Documents and Settings");
+ const io = testing.io;
+
+ try testReadLinkWindows(io, "C:\\ProgramData", "C:\\Users\\All Users");
+ try testReadLinkWindows(io, "C:\\Users\\Default", "C:\\Users\\Default User");
+ try testReadLinkWindows(io, "C:\\Users", "C:\\Documents and Settings");
}
-fn testReadlink(target_path: []const u8, symlink_path: []const u8) !void {
+fn testReadLinkWindows(io: Io, target_path: []const u8, symlink_path: []const u8) !void {
var buffer: [fs.max_path_bytes]u8 = undefined;
- const given = try Dir.readLinkAbsolute(symlink_path, buffer[0..]);
+ const given = try Dir.readLinkAbsolute(io, symlink_path, &buffer);
try expect(mem.eql(u8, target_path, given));
}
@@ -2424,6 +2427,6 @@ test "readlinkat" {
// read the link
var buffer: [fs.max_path_bytes]u8 = undefined;
- const read_link = try tmp.dir.readLink("link", &buffer);
+ const read_link = try tmp.dir.readLink(io, "link", &buffer);
try expect(mem.eql(u8, "file.txt", read_link));
}
diff --git a/lib/std/tar.zig b/lib/std/tar.zig
index 92dc8b88f9..d45aa99443 100644
--- a/lib/std/tar.zig
+++ b/lib/std/tar.zig
@@ -653,11 +653,11 @@ fn createDirAndFile(io: Io, dir: Io.Dir, file_name: []const u8, permissions: Io.
// Creates a symbolic link at path `file_name` which points to `link_name`.
fn createDirAndSymlink(io: Io, dir: Io.Dir, link_name: []const u8, file_name: []const u8) !void {
- dir.symLink(link_name, file_name, .{}) catch |err| {
+ dir.symLink(io, link_name, file_name, .{}) catch |err| {
if (err == error.FileNotFound) {
if (std.fs.path.dirname(file_name)) |dir_name| {
try dir.makePath(io, dir_name);
- return try dir.symLink(link_name, file_name, .{});
+ return try dir.symLink(io, link_name, file_name, .{});
}
}
return err;
@@ -996,15 +996,15 @@ test pipeToFileSystem {
return err;
};
- try testing.expectError(error.FileNotFound, dir.statFile("empty"));
- try testing.expect((try dir.statFile("a/file")).kind == .file);
- try testing.expect((try dir.statFile("b/symlink")).kind == .file); // statFile follows symlink
+ try testing.expectError(error.FileNotFound, dir.statFile(io, "empty", .{}));
+ try testing.expect((try dir.statFile(io, "a/file", .{})).kind == .file);
+ try testing.expect((try dir.statFile(io, "b/symlink", .{})).kind == .file); // statFile follows symlink
var buf: [32]u8 = undefined;
try testing.expectEqualSlices(
u8,
"../a/file",
- normalizePath(try dir.readLink("b/symlink", &buf)),
+ normalizePath(buf[0..try dir.readLink(io, "b/symlink", &buf)]),
);
}
@@ -1120,28 +1120,18 @@ fn normalizePath(bytes: []u8) []u8 {
// File system mode based on tar header mode and mode_mode options.
fn filePermissions(mode: u32, options: PipeOptions) Io.File.Permissions {
- const default_mode = 0o666;
-
- if (!Io.File.Permissions.has_executable_bit or options.mode_mode == .ignore)
- return .fromMode(default_mode);
-
- const S = std.posix.S;
-
- // The mode from the tar file is inspected for the owner executable bit.
- if (mode & S.IXUSR == 0)
- return .fromMode(default_mode);
-
- // This bit is copied to the group and other executable bits.
- // Other bits of the mode are left as the default when creating files.
- return .fromMode(default_mode | S.IXUSR | S.IXGRP | S.IXOTH);
+ return if (!Io.File.Permissions.has_executable_bit or options.mode_mode == .ignore or (mode & 0o100) == 0)
+ .default_file
+ else
+ .executable_file;
}
test filePermissions {
if (!Io.File.Permissions.has_executable_bit) return error.SkipZigTest;
- try testing.expectEqual(0o666, filePermissions(0o744, PipeOptions{ .mode_mode = .ignore }));
- try testing.expectEqual(0o777, filePermissions(0o744, PipeOptions{}));
- try testing.expectEqual(0o666, filePermissions(0o644, PipeOptions{}));
- try testing.expectEqual(0o666, filePermissions(0o655, PipeOptions{}));
+ try testing.expectEqual(.default_file, filePermissions(0o744, .{ .mode_mode = .ignore }));
+ try testing.expectEqual(.executable_file, filePermissions(0o744, .{}));
+ try testing.expectEqual(.default_file, filePermissions(0o644, .{}));
+ try testing.expectEqual(.default_file, filePermissions(0o655, .{}));
}
test "executable bit" {
@@ -1167,19 +1157,21 @@ test "executable bit" {
return err;
};
- const fs = try tmp.dir.statFile("a/file");
+ const fs = try tmp.dir.statFile(io, "a/file", .{});
try testing.expect(fs.kind == .file);
+ const mode = fs.permissions.toMode();
+
if (opt == .executable_bit_only) {
// Executable bit is set for user, group and others
- try testing.expect(fs.mode & S.IXUSR > 0);
- try testing.expect(fs.mode & S.IXGRP > 0);
- try testing.expect(fs.mode & S.IXOTH > 0);
+ try testing.expect(mode & S.IXUSR > 0);
+ try testing.expect(mode & S.IXGRP > 0);
+ try testing.expect(mode & S.IXOTH > 0);
}
if (opt == .ignore) {
- try testing.expect(fs.mode & S.IXUSR == 0);
- try testing.expect(fs.mode & S.IXGRP == 0);
- try testing.expect(fs.mode & S.IXOTH == 0);
+ try testing.expect(mode & S.IXUSR == 0);
+ try testing.expect(mode & S.IXGRP == 0);
+ try testing.expect(mode & S.IXOTH == 0);
}
}
}
diff --git a/lib/std/tar/test.zig b/lib/std/tar/test.zig
index b3fbd8f4b3..61aeb03519 100644
--- a/lib/std/tar/test.zig
+++ b/lib/std/tar/test.zig
@@ -504,6 +504,6 @@ test "case sensitivity" {
};
// on case sensitive os both files are created
- try testing.expect((try root.dir.statFile("alacritty/darkermatrix.yml")).kind == .file);
- try testing.expect((try root.dir.statFile("alacritty/Darkermatrix.yml")).kind == .file);
+ try testing.expect((try root.dir.statFile(io, "alacritty/darkermatrix.yml", .{})).kind == .file);
+ try testing.expect((try root.dir.statFile(io, "alacritty/Darkermatrix.yml", .{})).kind == .file);
}
diff --git a/lib/std/zig/WindowsSdk.zig b/lib/std/zig/WindowsSdk.zig
index 3f6d58b6ba..6da25822ca 100644
--- a/lib/std/zig/WindowsSdk.zig
+++ b/lib/std/zig/WindowsSdk.zig
@@ -1012,7 +1012,7 @@ const MsvcLibDir = struct {
var dir = std.fs.openDirAbsolute(lib_dir_path, .{}) catch return false;
defer dir.close(io);
- const stat = dir.statFile("vcruntime.lib") catch return false;
+ const stat = dir.statFile(io, "vcruntime.lib", .{}) catch return false;
if (stat.kind != .file)
return false;
diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig
index 6064d3b540..9d9a6a48ce 100644
--- a/lib/std/zig/parser_test.zig
+++ b/lib/std/zig/parser_test.zig
@@ -4539,7 +4539,7 @@ test "zig fmt: Only indent multiline string literals in function calls" {
test "zig fmt: Don't add extra newline after if" {
try testCanonical(
\\pub fn atomicSymLink(allocator: Allocator, existing_path: []const u8, new_path: []const u8) !void {
- \\ if (cwd().symLink(existing_path, new_path, .{})) {
+ \\ if (foo().bar(existing_path, new_path, .{})) {
\\ return;
\\ }
\\}
diff --git a/src/Builtin.zig b/src/Builtin.zig
index b0077f2276..9e4fae8e6a 100644
--- a/src/Builtin.zig
+++ b/src/Builtin.zig
@@ -313,8 +313,9 @@ pub fn updateFileOnDisk(file: *File, comp: *Compilation) !void {
assert(file.source != null);
const root_dir, const sub_path = file.path.openInfo(comp.dirs);
+ const io = comp.io;
- if (root_dir.statFile(sub_path)) |stat| {
+ if (root_dir.statFile(io, sub_path, .{})) |stat| {
if (stat.size != file.source.?.len) {
std.log.warn(
"the cached file '{f}' had the wrong size. Expected {d}, found {d}. " ++
diff --git a/src/Package/Fetch.zig b/src/Package/Fetch.zig
index 844acf9339..d25ee55c32 100644
--- a/src/Package/Fetch.zig
+++ b/src/Package/Fetch.zig
@@ -1440,13 +1440,13 @@ fn recursiveDirectoryCopy(f: *Fetch, dir: Io.Dir, tmp_dir: Io.Dir) anyerror!void
},
.sym_link => {
var buf: [fs.max_path_bytes]u8 = undefined;
- const link_name = try dir.readLink(entry.path, &buf);
+ const link_name = try dir.readLink(io, entry.path, &buf);
// TODO: if this would create a symlink to outside
// the destination directory, fail with an error instead.
- tmp_dir.symLink(link_name, entry.path, .{}) catch |err| switch (err) {
+ tmp_dir.symLink(io, link_name, entry.path, .{}) catch |err| switch (err) {
error.FileNotFound => {
if (fs.path.dirname(entry.path)) |dirname| try tmp_dir.makePath(io, dirname);
- try tmp_dir.symLink(link_name, entry.path, .{});
+ try tmp_dir.symLink(io, link_name, entry.path, .{});
},
else => |e| return e,
};
@@ -1698,7 +1698,7 @@ fn hashFileFallible(io: Io, dir: Io.Dir, hashed_file: *HashedFile) HashedFile.Er
}
},
.link => {
- const link_name = try dir.readLink(hashed_file.fs_path, &buf);
+ const link_name = try dir.readLink(io, hashed_file.fs_path, &buf);
if (fs.path.sep != canonical_sep) {
// Package hashes are intended to be consistent across
// platforms which means we must normalize path separators
@@ -2218,13 +2218,13 @@ test "set executable bit based on file content" {
defer out.close(io);
const S = std.posix.S;
// expect executable bit not set
- try std.testing.expect((try out.statFile("file1")).mode & S.IXUSR == 0);
- try std.testing.expect((try out.statFile("script_without_shebang")).mode & S.IXUSR == 0);
+ try std.testing.expect((try out.statFile(io, "file1", .{})).mode & S.IXUSR == 0);
+ try std.testing.expect((try out.statFile(io, "script_without_shebang", .{})).mode & S.IXUSR == 0);
// expect executable bit set
- try std.testing.expect((try out.statFile("hello")).mode & S.IXUSR != 0);
- try std.testing.expect((try out.statFile("script")).mode & S.IXUSR != 0);
- try std.testing.expect((try out.statFile("script_with_shebang_without_exec_bit")).mode & S.IXUSR != 0);
- try std.testing.expect((try out.statFile("hello_ln")).mode & S.IXUSR != 0);
+ try std.testing.expect((try out.statFile(io, "hello", .{})).mode & S.IXUSR != 0);
+ try std.testing.expect((try out.statFile(io, "script", .{})).mode & S.IXUSR != 0);
+ try std.testing.expect((try out.statFile(io, "script_with_shebang_without_exec_bit", .{})).mode & S.IXUSR != 0);
+ try std.testing.expect((try out.statFile(io, "hello_ln", .{})).mode & S.IXUSR != 0);
//
// $ ls -al zig-cache/tmp/OCz9ovUcstDjTC_U/zig-global-cache/p/1220fecb4c06a9da8673c87fe8810e15785f1699212f01728eadce094d21effeeef3
diff --git a/src/Package/Fetch/git.zig b/src/Package/Fetch/git.zig
index 33ff982b66..255f0e6f69 100644
--- a/src/Package/Fetch/git.zig
+++ b/src/Package/Fetch/git.zig
@@ -281,7 +281,7 @@ pub const Repository = struct {
const symlink_object = try repository.odb.readObject();
if (symlink_object.type != .blob) return error.InvalidFile;
const link_name = symlink_object.data;
- dir.symLink(link_name, entry.name, .{}) catch |e| {
+ dir.symLink(io, link_name, entry.name, .{}) catch |e| {
const file_name = try std.fs.path.join(diagnostics.allocator, &.{ current_path, entry.name });
errdefer diagnostics.allocator.free(file_name);
const link_name_dup = try diagnostics.allocator.dupe(u8, link_name);
diff --git a/src/fmt.zig b/src/fmt.zig
index 1a1e5298e2..59b4470f81 100644
--- a/src/fmt.zig
+++ b/src/fmt.zig
@@ -182,7 +182,7 @@ pub fn run(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8) !
// Mark any excluded files/directories as already seen,
// so that they are skipped later during actual processing
for (excluded_files.items) |file_path| {
- const stat = Io.Dir.cwd().statFile(file_path) catch |err| switch (err) {
+ const stat = Io.Dir.cwd().statFile(io, file_path, .{}) catch |err| switch (err) {
error.FileNotFound => continue,
// On Windows, statFile does not work for directories
error.IsDir => dir: {