authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-19 21:27:16-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-29 06:20:50-07:00
logb561d5f3feda6b1251fc2b8ab2430e78f546577c
tree4f4a289296f8dda8f52aa62b5892905df7df09f5
parentaa6e8eff40bdf35c838c8cd93080f2e9d4fad3b2

std.Io.Threaded: implement dirCreateFile for Windows


5 files changed, 59 insertions(+), 64 deletions(-)

lib/std/Io/Dir.zig+7
......@@ -101,6 +101,13 @@ pub fn openFile(dir: Dir, io: Io, sub_path: []const u8, flags: File.OpenFlags) F
101101 return io.vtable.dirOpenFile(io.userdata, dir, sub_path, flags);
102102}
103103
104/// Creates, opens, or overwrites a file with write access.
105///
106/// Allocates a resource to be dellocated with `File.close`.
107///
108/// On Windows, `sub_path` should be encoded as [WTF-8](https://wtf-8.codeberg.page/).
109/// On WASI, `sub_path` should be encoded as valid UTF-8.
110/// On other platforms, `sub_path` is an opaque sequence of bytes with no particular encoding.
104111pub fn createFile(dir: Dir, io: Io, sub_path: []const u8, flags: File.CreateFlags) File.OpenError!File {
105112 return io.vtable.dirCreateFile(io.userdata, dir, sub_path, flags);
106113}
lib/std/Io/Threaded.zig+49-1
......@@ -187,7 +187,7 @@ pub fn io(t: *Threaded) Io {
187187 else => dirAccessPosix,
188188 },
189189 .dirCreateFile = switch (builtin.os.tag) {
190 .windows => @panic("TODO"),
190 .windows => dirCreateFileWindows,
191191 .wasi => dirCreateFileWasi,
192192 else => dirCreateFilePosix,
193193 },
......@@ -1483,6 +1483,54 @@ fn dirCreateFilePosix(
14831483 return .{ .handle = fd };
14841484}
14851485
1486fn dirCreateFileWindows(
1487 userdata: ?*anyopaque,
1488 dir: Io.Dir,
1489 sub_path: []const u8,
1490 flags: Io.File.CreateFlags,
1491) Io.File.OpenError!Io.File {
1492 const w = windows;
1493 const t: *Threaded = @ptrCast(@alignCast(userdata));
1494 try t.checkCancel();
1495
1496 const sub_path_w_array = try w.sliceToPrefixedFileW(dir.handle, sub_path);
1497 const sub_path_w = sub_path_w_array.span();
1498
1499 const read_flag = if (flags.read) @as(u32, w.GENERIC_READ) else 0;
1500 const handle = try w.OpenFile(sub_path_w, .{
1501 .dir = dir.handle,
1502 .access_mask = w.SYNCHRONIZE | w.GENERIC_WRITE | read_flag,
1503 .creation = if (flags.exclusive)
1504 @as(u32, w.FILE_CREATE)
1505 else if (flags.truncate)
1506 @as(u32, w.FILE_OVERWRITE_IF)
1507 else
1508 @as(u32, w.FILE_OPEN_IF),
1509 });
1510 errdefer w.CloseHandle(handle);
1511 var io_status_block: w.IO_STATUS_BLOCK = undefined;
1512 const range_off: w.LARGE_INTEGER = 0;
1513 const range_len: w.LARGE_INTEGER = 1;
1514 const exclusive = switch (flags.lock) {
1515 .none => return .{ .handle = handle },
1516 .shared => false,
1517 .exclusive => true,
1518 };
1519 try w.LockFile(
1520 handle,
1521 null,
1522 null,
1523 null,
1524 &io_status_block,
1525 &range_off,
1526 &range_len,
1527 null,
1528 @intFromBool(flags.lock_nonblocking),
1529 @intFromBool(exclusive),
1530 );
1531 return .{ .handle = handle };
1532}
1533
14861534fn dirCreateFileWasi(
14871535 userdata: ?*anyopaque,
14881536 dir: Io.Dir,
lib/std/fs.zig-6
......@@ -299,12 +299,6 @@ pub fn createFileAbsolute(absolute_path: []const u8, flags: File.CreateFlags) Fi
299299 return cwd().createFile(absolute_path, flags);
300300}
301301
302/// Same as `createFileAbsolute` but the path parameter is WTF-16 encoded.
303pub fn createFileAbsoluteW(absolute_path_w: [*:0]const u16, flags: File.CreateFlags) File.OpenError!File {
304 assert(path.isAbsoluteWindowsW(absolute_path_w));
305 return cwd().createFileW(mem.span(absolute_path_w), flags);
306}
307
308302/// Delete a file name and possibly the file it refers to, based on an absolute path.
309303/// Asserts that the path is absolute. See `Dir.deleteFile` for a function that
310304/// operates on both absolute and relative paths.
lib/std/fs/Dir.zig+1-51
......@@ -900,64 +900,14 @@ pub fn openFileW(self: Dir, sub_path_w: []const u16, flags: File.OpenFlags) File
900900 return file;
901901}
902902
903/// Creates, opens, or overwrites a file with write access.
904/// Call `File.close` on the result when done.
905/// Asserts that the path parameter has no null bytes.
906/// On Windows, `sub_path` should be encoded as [WTF-8](https://wtf-8.codeberg.page/).
907/// On WASI, `sub_path` should be encoded as valid UTF-8.
908/// On other platforms, `sub_path` is an opaque sequence of bytes with no particular encoding.
903/// Deprecated in favor of `Io.Dir.createFile`.
909904pub fn createFile(self: Dir, sub_path: []const u8, flags: File.CreateFlags) File.OpenError!File {
910 if (native_os == .windows) {
911 const path_w = try windows.sliceToPrefixedFileW(self.fd, sub_path);
912 return self.createFileW(path_w.span(), flags);
913 }
914905 var threaded: Io.Threaded = .init_single_threaded;
915906 const io = threaded.io();
916907 const new_file = try Io.Dir.createFile(self.adaptToNewApi(), io, sub_path, flags);
917908 return .adaptFromNewApi(new_file);
918909}
919910
920/// Same as `createFile` but Windows-only and the path parameter is
921/// [WTF-16](https://wtf-8.codeberg.page/#potentially-ill-formed-utf-16) encoded.
922pub fn createFileW(self: Dir, sub_path_w: []const u16, flags: File.CreateFlags) File.OpenError!File {
923 const w = windows;
924 const read_flag = if (flags.read) @as(u32, w.GENERIC_READ) else 0;
925 const file: File = .{
926 .handle = try w.OpenFile(sub_path_w, .{
927 .dir = self.fd,
928 .access_mask = w.SYNCHRONIZE | w.GENERIC_WRITE | read_flag,
929 .creation = if (flags.exclusive)
930 @as(u32, w.FILE_CREATE)
931 else if (flags.truncate)
932 @as(u32, w.FILE_OVERWRITE_IF)
933 else
934 @as(u32, w.FILE_OPEN_IF),
935 }),
936 };
937 errdefer file.close();
938 var io: w.IO_STATUS_BLOCK = undefined;
939 const range_off: w.LARGE_INTEGER = 0;
940 const range_len: w.LARGE_INTEGER = 1;
941 const exclusive = switch (flags.lock) {
942 .none => return file,
943 .shared => false,
944 .exclusive => true,
945 };
946 try w.LockFile(
947 file.handle,
948 null,
949 null,
950 null,
951 &io,
952 &range_off,
953 &range_len,
954 null,
955 @intFromBool(flags.lock_nonblocking),
956 @intFromBool(exclusive),
957 );
958 return file;
959}
960
961911/// Deprecated in favor of `Io.Dir.MakeError`.
962912pub const MakeError = Io.Dir.MakeError;
963913
lib/std/posix.zig+2-6
......@@ -4684,9 +4684,7 @@ pub const AccessError = error{
46844684/// Windows. See `fs` for the cross-platform file system API.
46854685pub fn access(path: []const u8, mode: u32) AccessError!void {
46864686 if (native_os == .windows) {
4687 const path_w = try windows.sliceToPrefixedFileW(null, path);
4688 _ = try windows.GetFileAttributesW(path_w.span().ptr);
4689 return;
4687 @compileError("use std.Io instead");
46904688 } else if (native_os == .wasi and !builtin.link_libc) {
46914689 @compileError("wasi doesn't support absolute paths");
46924690 }
......@@ -4697,9 +4695,7 @@ pub fn access(path: []const u8, mode: u32) AccessError!void {
46974695/// Same as `access` except `path` is null-terminated.
46984696pub fn accessZ(path: [*:0]const u8, mode: u32) AccessError!void {
46994697 if (native_os == .windows) {
4700 const path_w = try windows.cStrToPrefixedFileW(null, path);
4701 _ = try windows.GetFileAttributesW(path_w.span().ptr);
4702 return;
4698 @compileError("use std.Io instead");
47034699 } else if (native_os == .wasi and !builtin.link_libc) {
47044700 return access(mem.sliceTo(path, 0), mode);
47054701 }