From c1b9c46319ff6c76484121c177086b1fbe70d50c Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 18 Dec 2025 23:28:10 -0800 Subject: [PATCH] std.Io: introduce path_only to File.OpenFlags --- lib/std/Io/File.zig | 6 ++++++ lib/std/Io/Threaded.zig | 3 +++ lib/std/fs/test.zig | 9 ++++++--- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/lib/std/Io/File.zig b/lib/std/Io/File.zig index 601a88260588b6eb58b4b14f3cbfe86009d7a1e6..75921948ccefdffff8b95149bf73c729f621acd9 100644 --- a/lib/std/Io/File.zig +++ b/lib/std/Io/File.zig @@ -115,6 +115,12 @@ pub const OpenFlags = struct { /// * On other operating systems, the behavior is implemented with an additional /// `fstat` syscall. allow_directory: bool = true, + /// Indicates intent for only some operations to be performed on this + /// opened file: + /// * `close` + /// * `stat` + /// On Linux and FreeBSD, this corresponds to `std.posix.O.PATH`. + path_only: bool = false, /// Open the file with an advisory lock to coordinate with other processes /// accessing it at the same time. An exclusive lock will prevent other diff --git a/lib/std/Io/Threaded.zig b/lib/std/Io/Threaded.zig index ffa292a0409fba2ef742b5608d107177bfd2952e..5f8ce2c101e31f42434daf111369ea432279a63f 100644 --- a/lib/std/Io/Threaded.zig +++ b/lib/std/Io/Threaded.zig @@ -2721,6 +2721,7 @@ fn dirOpenFilePosix( .wasi => .{ .read = flags.mode != .write_only, .write = flags.mode != .read_only, + .NOFOLLOW = !flags.follow_symlinks, }, else => .{ .ACCMODE = switch (flags.mode) { @@ -2728,11 +2729,13 @@ fn dirOpenFilePosix( .write_only => .WRONLY, .read_write => .RDWR, }, + .NOFOLLOW = !flags.follow_symlinks, }, }; if (@hasField(posix.O, "CLOEXEC")) os_flags.CLOEXEC = true; if (@hasField(posix.O, "LARGEFILE")) os_flags.LARGEFILE = true; if (@hasField(posix.O, "NOCTTY")) os_flags.NOCTTY = !flags.allow_ctty; + if (@hasField(posix.O, "PATH") and flags.path_only) os_flags.PATH = true; // Use the O locking flags if the os supports them to acquire the lock // atomically. Note that the NONBLOCK flag is removed after the openat() diff --git a/lib/std/fs/test.zig b/lib/std/fs/test.zig index 88d348d0a8dceae9b03fe2e6b413d0a1c60df438..5d03b7c64dd43495f5468c0d6c2c4ab5ef5c7964 100644 --- a/lib/std/fs/test.zig +++ b/lib/std/fs/test.zig @@ -295,8 +295,8 @@ fn testReadLinkAbsolute(io: Io, target_path: []const u8, symlink_path: []const u test "File.stat on a File that is a symlink returns Kind.sym_link" { const io = testing.io; - // This test requires getting a file descriptor of a symlink which - // is not possible on all targets + // This test requires getting a file descriptor of a symlink which is not + // possible on all targets. switch (builtin.target.os.tag) { .windows, .linux => {}, else => return error.SkipZigTest, @@ -309,7 +309,10 @@ test "File.stat on a File that is a symlink returns Kind.sym_link" { try setupSymlink(io, ctx.dir, dir_target_path, "symlink", .{ .is_directory = true }); - var symlink: Dir = try ctx.dir.openDir(io, "symlink", .{ .follow_symlinks = false }); + var symlink: File = try ctx.dir.openFile(io, "symlink", .{ + .follow_symlinks = false, + .path_only = true, + }); defer symlink.close(io); const stat = try symlink.stat(io); -- 2.54.0