authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-03-27 12:24:09+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-03-27 12:24:09+01:00
log2d3694ab42b73ba09124d5f1ddbfd9adaea79c47
tree8c0adc21784e13f0c7a5ce9d88167b84c8c62b2c
parent1f79a9e4e300affd111b51ec172bbeff42ca755a
parent2e4482cd14d6af958c2e16d7db4d6cf73bd043b8

Merge pull request 'std.Io.Dir: add resolve_beneath flag and implement for freebsd,macos' (#31684) from resolve_beneath into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/31684

5 files changed, 181 insertions(+), 175 deletions(-)

lib/std/Io.zig+3-3
......@@ -160,9 +160,9 @@ pub const VTable = struct {
160160 dirStat: *const fn (?*anyopaque, Dir) Dir.StatError!Dir.Stat,
161161 dirStatFile: *const fn (?*anyopaque, Dir, []const u8, Dir.StatFileOptions) Dir.StatFileError!File.Stat,
162162 dirAccess: *const fn (?*anyopaque, Dir, []const u8, Dir.AccessOptions) Dir.AccessError!void,
163 dirCreateFile: *const fn (?*anyopaque, Dir, []const u8, File.CreateFlags) File.OpenError!File,
163 dirCreateFile: *const fn (?*anyopaque, Dir, []const u8, Dir.CreateFileOptions) File.OpenError!File,
164164 dirCreateFileAtomic: *const fn (?*anyopaque, Dir, []const u8, Dir.CreateFileAtomicOptions) Dir.CreateFileAtomicError!File.Atomic,
165 dirOpenFile: *const fn (?*anyopaque, Dir, []const u8, File.OpenFlags) File.OpenError!File,
165 dirOpenFile: *const fn (?*anyopaque, Dir, []const u8, Dir.OpenFileOptions) File.OpenError!File,
166166 dirClose: *const fn (?*anyopaque, []const Dir) void,
167167 dirRead: *const fn (?*anyopaque, *Dir.Reader, []Dir.Entry) Dir.Reader.Error!usize,
168168 dirRealPath: *const fn (?*anyopaque, Dir, out_buffer: []u8) Dir.RealPathError!usize,
......@@ -211,7 +211,7 @@ pub const VTable = struct {
211211 fileMemoryMapRead: *const fn (?*anyopaque, *File.MemoryMap) File.ReadPositionalError!void,
212212 fileMemoryMapWrite: *const fn (?*anyopaque, *File.MemoryMap) File.WritePositionalError!void,
213213
214 processExecutableOpen: *const fn (?*anyopaque, File.OpenFlags) std.process.OpenExecutableError!File,
214 processExecutableOpen: *const fn (?*anyopaque, Dir.OpenFileOptions) std.process.OpenExecutableError!File,
215215 processExecutablePath: *const fn (?*anyopaque, buffer: []u8) std.process.ExecutablePathError!usize,
216216 lockStderr: *const fn (?*anyopaque, ?Terminal.Mode) Cancelable!LockedStderr,
217217 tryLockStderr: *const fn (?*anyopaque, ?Terminal.Mode) Cancelable!?LockedStderr,
lib/std/Io/Dir.zig+122-7
......@@ -495,6 +495,76 @@ pub fn closeMany(io: Io, dirs: []const Dir) void {
495495 return io.vtable.dirClose(io.userdata, dirs);
496496}
497497
498pub const OpenFileOptions = struct {
499 mode: Mode = .read_only,
500 /// Determines the behavior when opening a path that refers to a directory.
501 ///
502 /// If set to true, directories may be opened, but `error.IsDir` is still
503 /// possible in certain scenarios, e.g. attempting to open a directory with
504 /// write permissions.
505 ///
506 /// If set to false, `error.IsDir` will always be returned when opening a directory.
507 ///
508 /// When set to false:
509 /// * On Windows, the behavior is implemented without any extra syscalls.
510 /// * On other operating systems, the behavior is implemented with an additional
511 /// `fstat` syscall.
512 allow_directory: bool = true,
513 /// Indicates intent for only some operations to be performed on this
514 /// opened file:
515 /// * `close`
516 /// * `stat`
517 /// On Linux and FreeBSD, this corresponds to `std.posix.O.PATH`.
518 path_only: bool = false,
519 /// Open the file with an advisory lock to coordinate with other processes
520 /// accessing it at the same time. An exclusive lock will prevent other
521 /// processes from acquiring a lock. A shared lock will prevent other
522 /// processes from acquiring a exclusive lock, but does not prevent
523 /// other process from getting their own shared locks.
524 ///
525 /// The lock is advisory, except on Linux in very specific circumstances[1].
526 /// This means that a process that does not respect the locking API can still get access
527 /// to the file, despite the lock.
528 ///
529 /// On these operating systems, the lock is acquired atomically with
530 /// opening the file:
531 /// * Darwin
532 /// * DragonFlyBSD
533 /// * FreeBSD
534 /// * Haiku
535 /// * NetBSD
536 /// * OpenBSD
537 /// On these operating systems, the lock is acquired via a separate syscall
538 /// after opening the file:
539 /// * Linux
540 /// * Windows
541 ///
542 /// [1]: https://www.kernel.org/doc/Documentation/filesystems/mandatory-locking.txt
543 lock: File.Lock = .none,
544 /// Sets whether or not to wait until the file is locked to return. If set to true,
545 /// `error.WouldBlock` will be returned. Otherwise, the file will wait until the file
546 /// is available to proceed.
547 lock_nonblocking: bool = false,
548 /// Set this to allow the opened file to automatically become the
549 /// controlling TTY for the current process.
550 allow_ctty: bool = false,
551 follow_symlinks: bool = true,
552 /// If supported by the operating system, attempted path resolution that
553 /// would escape the directory instead returns `error.AccessDenied`. If
554 /// unsupported, this option is ignored.
555 resolve_beneath: bool = false,
556
557 pub const Mode = enum { read_only, write_only, read_write };
558
559 pub fn isRead(self: OpenFileOptions) bool {
560 return self.mode != .write_only;
561 }
562
563 pub fn isWrite(self: OpenFileOptions) bool {
564 return self.mode != .read_only;
565 }
566};
567
498568/// Opens a file for reading or writing, without attempting to create a new file.
499569///
500570/// To create a new file, see `createFile`.
......@@ -504,15 +574,60 @@ pub fn closeMany(io: Io, dirs: []const Dir) void {
504574/// On Windows, `sub_path` should be encoded as [WTF-8](https://wtf-8.codeberg.page/).
505575/// On WASI, `sub_path` should be encoded as valid UTF-8.
506576/// On other platforms, `sub_path` is an opaque sequence of bytes with no particular encoding.
507pub fn openFile(dir: Dir, io: Io, sub_path: []const u8, flags: File.OpenFlags) File.OpenError!File {
508 return io.vtable.dirOpenFile(io.userdata, dir, sub_path, flags);
577pub fn openFile(dir: Dir, io: Io, sub_path: []const u8, options: OpenFileOptions) File.OpenError!File {
578 return io.vtable.dirOpenFile(io.userdata, dir, sub_path, options);
509579}
510580
511pub fn openFileAbsolute(io: Io, absolute_path: []const u8, flags: File.OpenFlags) File.OpenError!File {
581pub fn openFileAbsolute(io: Io, absolute_path: []const u8, options: OpenFileOptions) File.OpenError!File {
512582 assert(path.isAbsolute(absolute_path));
513 return openFile(.cwd(), io, absolute_path, flags);
583 return openFile(.cwd(), io, absolute_path, options);
514584}
515585
586pub const CreateFileOptions = struct {
587 /// Whether the file will be created with read access.
588 read: bool = false,
589 /// If the file already exists, and is a regular file, and the access
590 /// mode allows writing, it will be truncated to length 0.
591 truncate: bool = true,
592 /// Ensures that this open call creates the file, otherwise causes
593 /// `error.PathAlreadyExists` to be returned.
594 exclusive: bool = false,
595 /// Open the file with an advisory lock to coordinate with other processes
596 /// accessing it at the same time. An exclusive lock will prevent other
597 /// processes from acquiring a lock. A shared lock will prevent other
598 /// processes from acquiring a exclusive lock, but does not prevent
599 /// other process from getting their own shared locks.
600 ///
601 /// The lock is advisory, except on Linux in very specific circumstances[1].
602 /// This means that a process that does not respect the locking API can still get access
603 /// to the file, despite the lock.
604 ///
605 /// On these operating systems, the lock is acquired atomically with
606 /// opening the file:
607 /// * Darwin
608 /// * DragonFlyBSD
609 /// * FreeBSD
610 /// * Haiku
611 /// * NetBSD
612 /// * OpenBSD
613 /// On these operating systems, the lock is acquired via a separate syscall
614 /// after opening the file:
615 /// * Linux
616 /// * Windows
617 ///
618 /// [1]: https://www.kernel.org/doc/Documentation/filesystems/mandatory-locking.txt
619 lock: File.Lock = .none,
620 /// Sets whether or not to wait until the file is locked to return. If set to true,
621 /// `error.WouldBlock` will be returned. Otherwise, the file will wait until the file
622 /// is available to proceed.
623 lock_nonblocking: bool = false,
624 permissions: Permissions = .default_file,
625 /// If supported by the operating system, attempted path resolution that
626 /// would escape the directory instead returns `error.AccessDenied`. If
627 /// unsupported, this option is ignored.
628 resolve_beneath: bool = false,
629};
630
516631/// Creates, opens, or overwrites a file with write access.
517632///
518633/// Allocates a resource to be dellocated with `File.close`.
......@@ -520,11 +635,11 @@ pub fn openFileAbsolute(io: Io, absolute_path: []const u8, flags: File.OpenFlags
520635/// On Windows, `sub_path` should be encoded as [WTF-8](https://wtf-8.codeberg.page/).
521636/// On WASI, `sub_path` should be encoded as valid UTF-8.
522637/// On other platforms, `sub_path` is an opaque sequence of bytes with no particular encoding.
523pub fn createFile(dir: Dir, io: Io, sub_path: []const u8, flags: File.CreateFlags) File.OpenError!File {
638pub fn createFile(dir: Dir, io: Io, sub_path: []const u8, flags: CreateFileOptions) File.OpenError!File {
524639 return io.vtable.dirCreateFile(io.userdata, dir, sub_path, flags);
525640}
526641
527pub fn createFileAbsolute(io: Io, absolute_path: []const u8, flags: File.CreateFlags) File.OpenError!File {
642pub fn createFileAbsolute(io: Io, absolute_path: []const u8, flags: CreateFileOptions) File.OpenError!File {
528643 return createFile(.cwd(), io, absolute_path, flags);
529644}
530645
......@@ -534,7 +649,7 @@ pub const WriteFileOptions = struct {
534649 /// On other platforms, `sub_path` is an opaque sequence of bytes with no particular encoding.
535650 sub_path: []const u8,
536651 data: []const u8,
537 flags: File.CreateFlags = .{},
652 flags: CreateFileOptions = .{},
538653};
539654
540655pub const WriteFileError = File.Writer.Error || File.OpenError;
lib/std/Io/File.zig+6-118
......@@ -142,11 +142,8 @@ pub fn stat(file: File, io: Io) StatError!Stat {
142142 return io.vtable.fileStat(io.userdata, file);
143143}
144144
145pub const OpenMode = enum {
146 read_only,
147 write_only,
148 read_write,
149};
145/// Deprecated, renamed to `Dir.OpenFileOptions.Mode`.
146pub const OpenMode = Dir.OpenFileOptions.Mode;
150147
151148pub const Lock = enum {
152149 none,
......@@ -154,120 +151,11 @@ pub const Lock = enum {
154151 exclusive,
155152};
156153
157pub const OpenFlags = struct {
158 mode: OpenMode = .read_only,
159
160 /// Determines the behavior when opening a path that refers to a directory.
161 ///
162 /// If set to true, directories may be opened, but `error.IsDir` is still
163 /// possible in certain scenarios, e.g. attempting to open a directory with
164 /// write permissions.
165 ///
166 /// If set to false, `error.IsDir` will always be returned when opening a directory.
167 ///
168 /// When set to false:
169 /// * On Windows, the behavior is implemented without any extra syscalls.
170 /// * On other operating systems, the behavior is implemented with an additional
171 /// `fstat` syscall.
172 allow_directory: bool = true,
173 /// Indicates intent for only some operations to be performed on this
174 /// opened file:
175 /// * `close`
176 /// * `stat`
177 /// On Linux and FreeBSD, this corresponds to `std.posix.O.PATH`.
178 path_only: bool = false,
179
180 /// Open the file with an advisory lock to coordinate with other processes
181 /// accessing it at the same time. An exclusive lock will prevent other
182 /// processes from acquiring a lock. A shared lock will prevent other
183 /// processes from acquiring a exclusive lock, but does not prevent
184 /// other process from getting their own shared locks.
185 ///
186 /// The lock is advisory, except on Linux in very specific circumstances[1].
187 /// This means that a process that does not respect the locking API can still get access
188 /// to the file, despite the lock.
189 ///
190 /// On these operating systems, the lock is acquired atomically with
191 /// opening the file:
192 /// * Darwin
193 /// * DragonFlyBSD
194 /// * FreeBSD
195 /// * Haiku
196 /// * NetBSD
197 /// * OpenBSD
198 /// On these operating systems, the lock is acquired via a separate syscall
199 /// after opening the file:
200 /// * Linux
201 /// * Windows
202 ///
203 /// [1]: https://www.kernel.org/doc/Documentation/filesystems/mandatory-locking.txt
204 lock: Lock = .none,
205
206 /// Sets whether or not to wait until the file is locked to return. If set to true,
207 /// `error.WouldBlock` will be returned. Otherwise, the file will wait until the file
208 /// is available to proceed.
209 lock_nonblocking: bool = false,
210
211 /// Set this to allow the opened file to automatically become the
212 /// controlling TTY for the current process.
213 allow_ctty: bool = false,
214
215 follow_symlinks: bool = true,
216
217 pub fn isRead(self: OpenFlags) bool {
218 return self.mode != .write_only;
219 }
154/// Deprecated, renamed to `Dir.OpenFileOptions`
155pub const OpenFlags = Dir.OpenFileOptions;
220156
221 pub fn isWrite(self: OpenFlags) bool {
222 return self.mode != .read_only;
223 }
224};
225
226pub const CreateFlags = struct {
227 /// Whether the file will be created with read access.
228 read: bool = false,
229
230 /// If the file already exists, and is a regular file, and the access
231 /// mode allows writing, it will be truncated to length 0.
232 truncate: bool = true,
233
234 /// Ensures that this open call creates the file, otherwise causes
235 /// `error.PathAlreadyExists` to be returned.
236 exclusive: bool = false,
237
238 /// Open the file with an advisory lock to coordinate with other processes
239 /// accessing it at the same time. An exclusive lock will prevent other
240 /// processes from acquiring a lock. A shared lock will prevent other
241 /// processes from acquiring a exclusive lock, but does not prevent
242 /// other process from getting their own shared locks.
243 ///
244 /// The lock is advisory, except on Linux in very specific circumstances[1].
245 /// This means that a process that does not respect the locking API can still get access
246 /// to the file, despite the lock.
247 ///
248 /// On these operating systems, the lock is acquired atomically with
249 /// opening the file:
250 /// * Darwin
251 /// * DragonFlyBSD
252 /// * FreeBSD
253 /// * Haiku
254 /// * NetBSD
255 /// * OpenBSD
256 /// On these operating systems, the lock is acquired via a separate syscall
257 /// after opening the file:
258 /// * Linux
259 /// * Windows
260 ///
261 /// [1]: https://www.kernel.org/doc/Documentation/filesystems/mandatory-locking.txt
262 lock: Lock = .none,
263
264 /// Sets whether or not to wait until the file is locked to return. If set to true,
265 /// `error.WouldBlock` will be returned. Otherwise, the file will wait until the file
266 /// is available to proceed.
267 lock_nonblocking: bool = false,
268
269 permissions: Permissions = .default_file,
270};
157/// Deprecated, renamed to `Dir.CreateFileOptions`.
158pub const CreateFlags = Dir.CreateFileOptions;
271159
272160pub const OpenError = error{
273161 PipeBusy,
lib/std/Io/Threaded.zig+48-46
......@@ -4217,7 +4217,7 @@ fn dirCreateFilePosix(
42174217 userdata: ?*anyopaque,
42184218 dir: Dir,
42194219 sub_path: []const u8,
4220 flags: File.CreateFlags,
4220 options: Dir.CreateFileOptions,
42214221) File.OpenError!File {
42224222 const t: *Threaded = @ptrCast(@alignCast(userdata));
42234223 _ = t;
......@@ -4225,34 +4225,35 @@ fn dirCreateFilePosix(
42254225 var path_buffer: [posix.PATH_MAX]u8 = undefined;
42264226 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);
42274227
4228 var os_flags: posix.O = .{
4229 .ACCMODE = if (flags.read) .RDWR else .WRONLY,
4228 var flags: posix.O = .{
4229 .ACCMODE = if (options.read) .RDWR else .WRONLY,
42304230 .CREAT = true,
4231 .TRUNC = flags.truncate,
4232 .EXCL = flags.exclusive,
4231 .TRUNC = options.truncate,
4232 .EXCL = options.exclusive,
42334233 };
4234 if (@hasField(posix.O, "LARGEFILE")) os_flags.LARGEFILE = true;
4235 if (@hasField(posix.O, "CLOEXEC")) os_flags.CLOEXEC = true;
4234 if (@hasField(posix.O, "LARGEFILE")) flags.LARGEFILE = true;
4235 if (@hasField(posix.O, "CLOEXEC")) flags.CLOEXEC = true;
4236 if (@hasField(posix.O, "RESOLVE_BENEATH")) flags.RESOLVE_BENEATH = options.resolve_beneath;
42364237
42374238 // Use the O locking flags if the os supports them to acquire the lock
42384239 // atomically. Note that the NONBLOCK flag is removed after the openat()
42394240 // call is successful.
4240 if (have_flock_open_flags) switch (flags.lock) {
4241 if (have_flock_open_flags) switch (options.lock) {
42414242 .none => {},
42424243 .shared => {
4243 os_flags.SHLOCK = true;
4244 os_flags.NONBLOCK = flags.lock_nonblocking;
4244 flags.SHLOCK = true;
4245 flags.NONBLOCK = options.lock_nonblocking;
42454246 },
42464247 .exclusive => {
4247 os_flags.EXLOCK = true;
4248 os_flags.NONBLOCK = flags.lock_nonblocking;
4248 flags.EXLOCK = true;
4249 flags.NONBLOCK = options.lock_nonblocking;
42494250 },
42504251 };
42514252
42524253 const fd: posix.fd_t = fd: {
42534254 const syscall: Syscall = try .start();
42544255 while (true) {
4255 const rc = openat_sym(dir.handle, sub_path_posix, os_flags, flags.permissions.toMode());
4256 const rc = openat_sym(dir.handle, sub_path_posix, flags, options.permissions.toMode());
42564257 switch (posix.errno(rc)) {
42574258 .SUCCESS => {
42584259 syscall.finish();
......@@ -4298,9 +4299,9 @@ fn dirCreateFilePosix(
42984299 };
42994300 errdefer closeFd(fd);
43004301
4301 if (have_flock and !have_flock_open_flags and flags.lock != .none) {
4302 const lock_nonblocking: i32 = if (flags.lock_nonblocking) posix.LOCK.NB else 0;
4303 const lock_flags = switch (flags.lock) {
4302 if (have_flock and !have_flock_open_flags and options.lock != .none) {
4303 const lock_nonblocking: i32 = if (options.lock_nonblocking) posix.LOCK.NB else 0;
4304 const lock_flags = switch (options.lock) {
43044305 .none => unreachable,
43054306 .shared => posix.LOCK.SH | lock_nonblocking,
43064307 .exclusive => posix.LOCK.EX | lock_nonblocking,
......@@ -4332,7 +4333,7 @@ fn dirCreateFilePosix(
43324333 }
43334334 }
43344335
4335 if (have_flock_open_flags and flags.lock_nonblocking) {
4336 if (have_flock_open_flags and options.lock_nonblocking) {
43364337 var fl_flags: usize = fl: {
43374338 const syscall: Syscall = try .start();
43384339 while (true) {
......@@ -4385,7 +4386,7 @@ fn dirCreateFileWindows(
43854386 userdata: ?*anyopaque,
43864387 dir: Dir,
43874388 sub_path: []const u8,
4388 flags: File.CreateFlags,
4389 flags: Dir.CreateFileOptions,
43894390) File.OpenError!File {
43904391 const t: *Threaded = @ptrCast(@alignCast(userdata));
43914392 _ = t;
......@@ -4535,7 +4536,7 @@ fn dirCreateFileWasi(
45354536 userdata: ?*anyopaque,
45364537 dir: Dir,
45374538 sub_path: []const u8,
4538 flags: File.CreateFlags,
4539 flags: Dir.CreateFileOptions,
45394540) File.OpenError!File {
45404541 const t: *Threaded = @ptrCast(@alignCast(userdata));
45414542 _ = t;
......@@ -4785,45 +4786,46 @@ fn dirOpenFilePosix(
47854786 userdata: ?*anyopaque,
47864787 dir: Dir,
47874788 sub_path: []const u8,
4788 flags: File.OpenFlags,
4789 options: Dir.OpenFileOptions,
47894790) File.OpenError!File {
47904791 const t: *Threaded = @ptrCast(@alignCast(userdata));
47914792
47924793 var path_buffer: [posix.PATH_MAX]u8 = undefined;
47934794 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);
47944795
4795 var os_flags: posix.O = switch (native_os) {
4796 var flags: posix.O = switch (native_os) {
47964797 .wasi => .{
4797 .read = flags.mode != .write_only,
4798 .write = flags.mode != .read_only,
4799 .NOFOLLOW = !flags.follow_symlinks,
4798 .read = options.mode != .write_only,
4799 .write = options.mode != .read_only,
4800 .NOFOLLOW = !options.follow_symlinks,
48004801 },
48014802 else => .{
4802 .ACCMODE = switch (flags.mode) {
4803 .ACCMODE = switch (options.mode) {
48034804 .read_only => .RDONLY,
48044805 .write_only => .WRONLY,
48054806 .read_write => .RDWR,
48064807 },
4807 .NOFOLLOW = !flags.follow_symlinks,
4808 .NOFOLLOW = !options.follow_symlinks,
48084809 },
48094810 };
4810 if (@hasField(posix.O, "CLOEXEC")) os_flags.CLOEXEC = true;
4811 if (@hasField(posix.O, "LARGEFILE")) os_flags.LARGEFILE = true;
4812 if (@hasField(posix.O, "NOCTTY")) os_flags.NOCTTY = !flags.allow_ctty;
4813 if (@hasField(posix.O, "PATH") and flags.path_only) os_flags.PATH = true;
4811 if (@hasField(posix.O, "CLOEXEC")) flags.CLOEXEC = true;
4812 if (@hasField(posix.O, "LARGEFILE")) flags.LARGEFILE = true;
4813 if (@hasField(posix.O, "NOCTTY")) flags.NOCTTY = !options.allow_ctty;
4814 if (@hasField(posix.O, "PATH")) flags.PATH = options.path_only;
4815 if (@hasField(posix.O, "RESOLVE_BENEATH")) flags.RESOLVE_BENEATH = options.resolve_beneath;
48144816
4815 // Use the O locking flags if the os supports them to acquire the lock
4817 // Use the O locking options if the os supports them to acquire the lock
48164818 // atomically. Note that the NONBLOCK flag is removed after the openat()
48174819 // call is successful.
4818 if (have_flock_open_flags) switch (flags.lock) {
4820 if (have_flock_open_flags) switch (options.lock) {
48194821 .none => {},
48204822 .shared => {
4821 os_flags.SHLOCK = true;
4822 os_flags.NONBLOCK = flags.lock_nonblocking;
4823 flags.SHLOCK = true;
4824 flags.NONBLOCK = options.lock_nonblocking;
48234825 },
48244826 .exclusive => {
4825 os_flags.EXLOCK = true;
4826 os_flags.NONBLOCK = flags.lock_nonblocking;
4827 flags.EXLOCK = true;
4828 flags.NONBLOCK = options.lock_nonblocking;
48274829 },
48284830 };
48294831
......@@ -4832,7 +4834,7 @@ fn dirOpenFilePosix(
48324834 const fd: posix.fd_t = fd: {
48334835 const syscall: Syscall = try .start();
48344836 while (true) {
4835 const rc = openat_sym(dir.handle, sub_path_posix, os_flags, mode);
4837 const rc = openat_sym(dir.handle, sub_path_posix, flags, mode);
48364838 switch (posix.errno(rc)) {
48374839 .SUCCESS => {
48384840 syscall.finish();
......@@ -4878,7 +4880,7 @@ fn dirOpenFilePosix(
48784880 };
48794881 errdefer closeFd(fd);
48804882
4881 if (!flags.allow_directory) {
4883 if (!options.allow_directory) {
48824884 const is_dir = is_dir: {
48834885 const stat = fileStat(t, .{
48844886 .handle = fd,
......@@ -4893,9 +4895,9 @@ fn dirOpenFilePosix(
48934895 if (is_dir) return error.IsDir;
48944896 }
48954897
4896 if (have_flock and !have_flock_open_flags and flags.lock != .none) {
4897 const lock_nonblocking: i32 = if (flags.lock_nonblocking) posix.LOCK.NB else 0;
4898 const lock_flags = switch (flags.lock) {
4898 if (have_flock and !have_flock_open_flags and options.lock != .none) {
4899 const lock_nonblocking: i32 = if (options.lock_nonblocking) posix.LOCK.NB else 0;
4900 const lock_flags = switch (options.lock) {
48994901 .none => unreachable,
49004902 .shared => posix.LOCK.SH | lock_nonblocking,
49014903 .exclusive => posix.LOCK.EX | lock_nonblocking,
......@@ -4926,7 +4928,7 @@ fn dirOpenFilePosix(
49264928 }
49274929 }
49284930
4929 if (have_flock_open_flags and flags.lock_nonblocking) {
4931 if (have_flock_open_flags and options.lock_nonblocking) {
49304932 var fl_flags: usize = fl: {
49314933 const syscall: Syscall = try .start();
49324934 while (true) {
......@@ -4979,7 +4981,7 @@ fn dirOpenFileWindows(
49794981 userdata: ?*anyopaque,
49804982 dir: Dir,
49814983 sub_path: []const u8,
4982 flags: File.OpenFlags,
4984 flags: Dir.OpenFileOptions,
49834985) File.OpenError!File {
49844986 const t: *Threaded = @ptrCast(@alignCast(userdata));
49854987 _ = t;
......@@ -4992,7 +4994,7 @@ fn dirOpenFileWindows(
49924994pub fn dirOpenFileWtf16(
49934995 dir_handle: ?windows.HANDLE,
49944996 sub_path_w: []const u16,
4995 flags: File.OpenFlags,
4997 flags: Dir.OpenFileOptions,
49964998) File.OpenError!File {
49974999 const allow_directory = flags.allow_directory and !flags.isWrite();
49985000 if (!allow_directory and std.mem.eql(u16, sub_path_w, &.{'.'})) return error.IsDir;
......@@ -5129,7 +5131,7 @@ fn dirOpenFileWasi(
51295131 userdata: ?*anyopaque,
51305132 dir: Dir,
51315133 sub_path: []const u8,
5132 flags: File.OpenFlags,
5134 flags: Dir.OpenFileOptions,
51335135) File.OpenError!File {
51345136 if (builtin.link_libc) return dirOpenFilePosix(userdata, dir, sub_path, flags);
51355137 const t: *Threaded = @ptrCast(@alignCast(userdata));
......@@ -10193,7 +10195,7 @@ fn posixSeekTo(fd: posix.fd_t, offset: u64) File.SeekError!void {
1019310195 }
1019410196}
1019510197
10196fn processExecutableOpen(userdata: ?*anyopaque, flags: File.OpenFlags) process.OpenExecutableError!File {
10198fn processExecutableOpen(userdata: ?*anyopaque, flags: Dir.OpenFileOptions) process.OpenExecutableError!File {
1019710199 const t: *Threaded = @ptrCast(@alignCast(userdata));
1019810200 switch (native_os) {
1019910201 .wasi => return error.OperationUnsupported,
lib/std/c.zig+2-1
......@@ -8535,7 +8535,8 @@ pub const O = switch (native_os) {
85358535 CREAT: bool = false,
85368536 TRUNC: bool = false,
85378537 EXCL: bool = false,
8538 _12: u3 = 0,
8538 RESOLVE_BENEATH: bool = false,
8539 _13: u2 = 0,
85398540 EVTONLY: bool = false,
85408541 _16: u1 = 0,
85418542 NOCTTY: bool = false,