authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-03-26 21:07:59-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-03-27 01:23:04-07:00
log6f467e436dab4f6b12e6dc5f29e96f8ce5e060ad
treebdbee9770efbad73cf303d953c0641df56197605
parent0d25302d43557d89b868b8925b2e98395d1ebe60

std.Io: move File.CreateFlags to Dir.CreateFileOptions

for naming consistency. same thing with File.OpenFlags -> Dir.OpenFileFlags

4 files changed, 129 insertions(+), 134 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+112-5
......@@ -495,6 +495,72 @@ 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
553 pub const Mode = enum { read_only, write_only, read_write };
554
555 pub fn isRead(self: OpenFileOptions) bool {
556 return self.mode != .write_only;
557 }
558
559 pub fn isWrite(self: OpenFileOptions) bool {
560 return self.mode != .read_only;
561 }
562};
563
498564/// Opens a file for reading or writing, without attempting to create a new file.
499565///
500566/// To create a new file, see `createFile`.
......@@ -504,15 +570,56 @@ pub fn closeMany(io: Io, dirs: []const Dir) void {
504570/// On Windows, `sub_path` should be encoded as [WTF-8](https://wtf-8.codeberg.page/).
505571/// On WASI, `sub_path` should be encoded as valid UTF-8.
506572/// 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 {
573pub fn openFile(dir: Dir, io: Io, sub_path: []const u8, flags: OpenFileOptions) File.OpenError!File {
508574 return io.vtable.dirOpenFile(io.userdata, dir, sub_path, flags);
509575}
510576
511pub fn openFileAbsolute(io: Io, absolute_path: []const u8, flags: File.OpenFlags) File.OpenError!File {
577pub fn openFileAbsolute(io: Io, absolute_path: []const u8, flags: OpenFileOptions) File.OpenError!File {
512578 assert(path.isAbsolute(absolute_path));
513579 return openFile(.cwd(), io, absolute_path, flags);
514580}
515581
582pub const CreateFileOptions = struct {
583 /// Whether the file will be created with read access.
584 read: bool = false,
585 /// If the file already exists, and is a regular file, and the access
586 /// mode allows writing, it will be truncated to length 0.
587 truncate: bool = true,
588 /// Ensures that this open call creates the file, otherwise causes
589 /// `error.PathAlreadyExists` to be returned.
590 exclusive: bool = false,
591 /// Open the file with an advisory lock to coordinate with other processes
592 /// accessing it at the same time. An exclusive lock will prevent other
593 /// processes from acquiring a lock. A shared lock will prevent other
594 /// processes from acquiring a exclusive lock, but does not prevent
595 /// other process from getting their own shared locks.
596 ///
597 /// The lock is advisory, except on Linux in very specific circumstances[1].
598 /// This means that a process that does not respect the locking API can still get access
599 /// to the file, despite the lock.
600 ///
601 /// On these operating systems, the lock is acquired atomically with
602 /// opening the file:
603 /// * Darwin
604 /// * DragonFlyBSD
605 /// * FreeBSD
606 /// * Haiku
607 /// * NetBSD
608 /// * OpenBSD
609 /// On these operating systems, the lock is acquired via a separate syscall
610 /// after opening the file:
611 /// * Linux
612 /// * Windows
613 ///
614 /// [1]: https://www.kernel.org/doc/Documentation/filesystems/mandatory-locking.txt
615 lock: File.Lock = .none,
616 /// Sets whether or not to wait until the file is locked to return. If set to true,
617 /// `error.WouldBlock` will be returned. Otherwise, the file will wait until the file
618 /// is available to proceed.
619 lock_nonblocking: bool = false,
620 permissions: Permissions = .default_file,
621};
622
516623/// Creates, opens, or overwrites a file with write access.
517624///
518625/// Allocates a resource to be dellocated with `File.close`.
......@@ -520,11 +627,11 @@ pub fn openFileAbsolute(io: Io, absolute_path: []const u8, flags: File.OpenFlags
520627/// On Windows, `sub_path` should be encoded as [WTF-8](https://wtf-8.codeberg.page/).
521628/// On WASI, `sub_path` should be encoded as valid UTF-8.
522629/// 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 {
630pub fn createFile(dir: Dir, io: Io, sub_path: []const u8, flags: CreateFileOptions) File.OpenError!File {
524631 return io.vtable.dirCreateFile(io.userdata, dir, sub_path, flags);
525632}
526633
527pub fn createFileAbsolute(io: Io, absolute_path: []const u8, flags: File.CreateFlags) File.OpenError!File {
634pub fn createFileAbsolute(io: Io, absolute_path: []const u8, flags: CreateFileOptions) File.OpenError!File {
528635 return createFile(.cwd(), io, absolute_path, flags);
529636}
530637
......@@ -534,7 +641,7 @@ pub const WriteFileOptions = struct {
534641 /// On other platforms, `sub_path` is an opaque sequence of bytes with no particular encoding.
535642 sub_path: []const u8,
536643 data: []const u8,
537 flags: File.CreateFlags = .{},
644 flags: CreateFileOptions = .{},
538645};
539646
540647pub 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+8-8
......@@ -4217,7 +4217,7 @@ fn dirCreateFilePosix(
42174217 userdata: ?*anyopaque,
42184218 dir: Dir,
42194219 sub_path: []const u8,
4220 flags: File.CreateFlags,
4220 flags: Dir.CreateFileOptions,
42214221) File.OpenError!File {
42224222 const t: *Threaded = @ptrCast(@alignCast(userdata));
42234223 _ = t;
......@@ -4385,7 +4385,7 @@ fn dirCreateFileWindows(
43854385 userdata: ?*anyopaque,
43864386 dir: Dir,
43874387 sub_path: []const u8,
4388 flags: File.CreateFlags,
4388 flags: Dir.CreateFileOptions,
43894389) File.OpenError!File {
43904390 const t: *Threaded = @ptrCast(@alignCast(userdata));
43914391 _ = t;
......@@ -4535,7 +4535,7 @@ fn dirCreateFileWasi(
45354535 userdata: ?*anyopaque,
45364536 dir: Dir,
45374537 sub_path: []const u8,
4538 flags: File.CreateFlags,
4538 flags: Dir.CreateFileOptions,
45394539) File.OpenError!File {
45404540 const t: *Threaded = @ptrCast(@alignCast(userdata));
45414541 _ = t;
......@@ -4785,7 +4785,7 @@ fn dirOpenFilePosix(
47854785 userdata: ?*anyopaque,
47864786 dir: Dir,
47874787 sub_path: []const u8,
4788 flags: File.OpenFlags,
4788 flags: Dir.OpenFileOptions,
47894789) File.OpenError!File {
47904790 const t: *Threaded = @ptrCast(@alignCast(userdata));
47914791
......@@ -4979,7 +4979,7 @@ fn dirOpenFileWindows(
49794979 userdata: ?*anyopaque,
49804980 dir: Dir,
49814981 sub_path: []const u8,
4982 flags: File.OpenFlags,
4982 flags: Dir.OpenFileOptions,
49834983) File.OpenError!File {
49844984 const t: *Threaded = @ptrCast(@alignCast(userdata));
49854985 _ = t;
......@@ -4992,7 +4992,7 @@ fn dirOpenFileWindows(
49924992pub fn dirOpenFileWtf16(
49934993 dir_handle: ?windows.HANDLE,
49944994 sub_path_w: []const u16,
4995 flags: File.OpenFlags,
4995 flags: Dir.OpenFileOptions,
49964996) File.OpenError!File {
49974997 const allow_directory = flags.allow_directory and !flags.isWrite();
49984998 if (!allow_directory and std.mem.eql(u16, sub_path_w, &.{'.'})) return error.IsDir;
......@@ -5129,7 +5129,7 @@ fn dirOpenFileWasi(
51295129 userdata: ?*anyopaque,
51305130 dir: Dir,
51315131 sub_path: []const u8,
5132 flags: File.OpenFlags,
5132 flags: Dir.OpenFileOptions,
51335133) File.OpenError!File {
51345134 if (builtin.link_libc) return dirOpenFilePosix(userdata, dir, sub_path, flags);
51355135 const t: *Threaded = @ptrCast(@alignCast(userdata));
......@@ -10193,7 +10193,7 @@ fn posixSeekTo(fd: posix.fd_t, offset: u64) File.SeekError!void {
1019310193 }
1019410194}
1019510195
10196fn processExecutableOpen(userdata: ?*anyopaque, flags: File.OpenFlags) process.OpenExecutableError!File {
10196fn processExecutableOpen(userdata: ?*anyopaque, flags: Dir.OpenFileOptions) process.OpenExecutableError!File {
1019710197 const t: *Threaded = @ptrCast(@alignCast(userdata));
1019810198 switch (native_os) {
1019910199 .wasi => return error.OperationUnsupported,