authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-08 23:03:34-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-23 22:15:08-08:00
log5b436d2c5125b9cf9a08b3bff0dcb0248c4d1ec0
tree67c4a021da0c5dd24b8e0369278a90fe81d65cf3
parent90f7259ef17e8e07c2c3f71bea65d103cfe52c07

build_runner compiling again


7 files changed, 111 insertions(+), 148 deletions(-)

lib/std/Io/Dir.zig+23-58
...@@ -198,7 +198,7 @@ pub const SelectiveWalker = struct {...@@ -198,7 +198,7 @@ pub const SelectiveWalker = struct {
198 // likely just fail with the same error.198 // likely just fail with the same error.
199 var item = self.stack.pop().?;199 var item = self.stack.pop().?;
200 if (self.stack.items.len != 0) {200 if (self.stack.items.len != 0) {
201 item.iter.dir.close(io);201 item.iter.reader.dir.close(io);
202 }202 }
203 return err;203 return err;
204 }) |entry| {204 }) |entry| {
...@@ -211,7 +211,7 @@ pub const SelectiveWalker = struct {...@@ -211,7 +211,7 @@ pub const SelectiveWalker = struct {
211 self.name_buffer.appendSliceAssumeCapacity(entry.name);211 self.name_buffer.appendSliceAssumeCapacity(entry.name);
212 self.name_buffer.appendAssumeCapacity(0);212 self.name_buffer.appendAssumeCapacity(0);
213 const walker_entry: Walker.Entry = .{213 const walker_entry: Walker.Entry = .{
214 .dir = top.iter.dir,214 .dir = top.iter.reader.dir,
215 .basename = self.name_buffer.items[dirname_len .. self.name_buffer.items.len - 1 :0],215 .basename = self.name_buffer.items[dirname_len .. self.name_buffer.items.len - 1 :0],
216 .path = self.name_buffer.items[0 .. self.name_buffer.items.len - 1 :0],216 .path = self.name_buffer.items[0 .. self.name_buffer.items.len - 1 :0],
217 .kind = entry.kind,217 .kind = entry.kind,
...@@ -220,7 +220,7 @@ pub const SelectiveWalker = struct {...@@ -220,7 +220,7 @@ pub const SelectiveWalker = struct {
220 } else {220 } else {
221 var item = self.stack.pop().?;221 var item = self.stack.pop().?;
222 if (self.stack.items.len != 0) {222 if (self.stack.items.len != 0) {
223 item.iter.dir.close(io);223 item.iter.reader.dir.close(io);
224 }224 }
225 }225 }
226 }226 }
...@@ -260,7 +260,7 @@ pub const SelectiveWalker = struct {...@@ -260,7 +260,7 @@ pub const SelectiveWalker = struct {
260 var item = self.stack.pop().?;260 var item = self.stack.pop().?;
261 if (self.stack.items.len != 0) {261 if (self.stack.items.len != 0) {
262 @branchHint(.likely);262 @branchHint(.likely);
263 item.iter.dir.close(io);263 item.iter.reader.dir.close(io);
264 }264 }
265 }265 }
266};266};
...@@ -741,7 +741,6 @@ pub const RealPathError = error{...@@ -741,7 +741,6 @@ pub const RealPathError = error{
741 FileNotFound,741 FileNotFound,
742 AccessDenied,742 AccessDenied,
743 PermissionDenied,743 PermissionDenied,
744 NameTooLong,
745 NotSupported,744 NotSupported,
746 NotDir,745 NotDir,
747 SymLinkLoop,746 SymLinkLoop,
...@@ -757,9 +756,6 @@ pub const RealPathError = error{...@@ -757,9 +756,6 @@ pub const RealPathError = error{
757 DeviceBusy,756 DeviceBusy,
758 SharingViolation,757 SharingViolation,
759 PipeBusy,758 PipeBusy,
760 /// Windows: file paths provided by the user must be valid WTF-8.
761 /// https://wtf-8.codeberg.page/
762 BadPathName,
763 /// On Windows, `\\server` or `\\server\share` was not found.759 /// On Windows, `\\server` or `\\server\share` was not found.
764 NetworkNotFound,760 NetworkNotFound,
765 PathAlreadyExists,761 PathAlreadyExists,
...@@ -772,7 +768,7 @@ pub const RealPathError = error{...@@ -772,7 +768,7 @@ pub const RealPathError = error{
772 /// On Windows, the volume does not contain a recognized file system. File768 /// On Windows, the volume does not contain a recognized file system. File
773 /// system drivers might not be loaded, or the volume may be corrupt.769 /// system drivers might not be loaded, or the volume may be corrupt.
774 UnrecognizedVolume,770 UnrecognizedVolume,
775} || Io.Cancelable || Io.UnexpectedError;771} || PathNameError || Io.Cancelable || Io.UnexpectedError;
776772
777/// This function returns the canonicalized absolute pathname of `pathname`773/// This function returns the canonicalized absolute pathname of `pathname`
778/// relative to this `Dir`. If `pathname` is absolute, ignores this `Dir`774/// relative to this `Dir`. If `pathname` is absolute, ignores this `Dir`
...@@ -824,19 +820,12 @@ pub const DeleteFileError = error{...@@ -824,19 +820,12 @@ pub const DeleteFileError = error{
824 FileSystem,820 FileSystem,
825 IsDir,821 IsDir,
826 SymLinkLoop,822 SymLinkLoop,
827 NameTooLong,
828 NotDir,823 NotDir,
829 SystemResources,824 SystemResources,
830 ReadOnlyFileSystem,825 ReadOnlyFileSystem,
831 /// WASI: file paths must be valid UTF-8.
832 /// Windows: file paths provided by the user must be valid WTF-8.
833 /// https://wtf-8.codeberg.page/
834 /// Windows: file paths cannot contain these characters:
835 /// '/', '*', '?', '"', '<', '>', '|'
836 BadPathName,
837 /// On Windows, `\\server` or `\\server\share` was not found.826 /// On Windows, `\\server` or `\\server\share` was not found.
838 NetworkNotFound,827 NetworkNotFound,
839} || Io.Cancelable || Io.UnexpectedError;828} || PathNameError || Io.Cancelable || Io.UnexpectedError;
840829
841/// Delete a file name and possibly the file it refers to, based on an open directory handle.830/// Delete a file name and possibly the file it refers to, based on an open directory handle.
842///831///
...@@ -864,17 +853,12 @@ pub const DeleteDirError = error{...@@ -864,17 +853,12 @@ pub const DeleteDirError = error{
864 FileBusy,853 FileBusy,
865 FileSystem,854 FileSystem,
866 SymLinkLoop,855 SymLinkLoop,
867 NameTooLong,
868 NotDir,856 NotDir,
869 SystemResources,857 SystemResources,
870 ReadOnlyFileSystem,858 ReadOnlyFileSystem,
871 /// WASI: file paths must be valid UTF-8.
872 /// Windows: file paths provided by the user must be valid WTF-8.
873 /// https://wtf-8.codeberg.page/
874 BadPathName,
875 /// On Windows, `\\server` or `\\server\share` was not found.859 /// On Windows, `\\server` or `\\server\share` was not found.
876 NetworkNotFound,860 NetworkNotFound,
877} || Io.Cancelable || Io.UnexpectedError;861} || PathNameError || Io.Cancelable || Io.UnexpectedError;
878862
879/// Returns `error.DirNotEmpty` if the directory is not empty.863/// Returns `error.DirNotEmpty` if the directory is not empty.
880///864///
...@@ -910,7 +894,6 @@ pub const RenameError = error{...@@ -910,7 +894,6 @@ pub const RenameError = error{
910 IsDir,894 IsDir,
911 SymLinkLoop,895 SymLinkLoop,
912 LinkQuotaExceeded,896 LinkQuotaExceeded,
913 NameTooLong,
914 FileNotFound,897 FileNotFound,
915 NotDir,898 NotDir,
916 SystemResources,899 SystemResources,
...@@ -918,10 +901,6 @@ pub const RenameError = error{...@@ -918,10 +901,6 @@ pub const RenameError = error{
918 PathAlreadyExists,901 PathAlreadyExists,
919 ReadOnlyFileSystem,902 ReadOnlyFileSystem,
920 RenameAcrossMountPoints,903 RenameAcrossMountPoints,
921 /// WASI: file paths must be valid UTF-8.
922 /// Windows: file paths provided by the user must be valid WTF-8.
923 /// https://wtf-8.codeberg.page/
924 BadPathName,
925 NoDevice,904 NoDevice,
926 SharingViolation,905 SharingViolation,
927 PipeBusy,906 PipeBusy,
...@@ -933,7 +912,7 @@ pub const RenameError = error{...@@ -933,7 +912,7 @@ pub const RenameError = error{
933 /// intercepts file system operations and makes them significantly slower912 /// intercepts file system operations and makes them significantly slower
934 /// in addition to possibly failing with this error code.913 /// in addition to possibly failing with this error code.
935 AntivirusInterference,914 AntivirusInterference,
936} || Io.Cancelable || Io.UnexpectedError;915} || PathNameError || Io.Cancelable || Io.UnexpectedError;
937916
938/// Change the name or location of a file or directory.917/// Change the name or location of a file or directory.
939///918///
...@@ -985,12 +964,7 @@ pub const SymLinkError = error{...@@ -985,12 +964,7 @@ pub const SymLinkError = error{
985 NoSpaceLeft,964 NoSpaceLeft,
986 ReadOnlyFileSystem,965 ReadOnlyFileSystem,
987 NotDir,966 NotDir,
988 NameTooLong,967} || PathNameError || Io.Cancelable || Io.UnexpectedError;
989 /// WASI: file paths must be valid UTF-8.
990 /// Windows: file paths provided by the user must be valid WTF-8.
991 /// https://wtf-8.codeberg.page/
992 BadPathName,
993} || Io.Cancelable || Io.UnexpectedError;
994968
995/// Creates a symbolic link named `sym_link_path` which contains the string `target_path`.969/// Creates a symbolic link named `sym_link_path` which contains the string `target_path`.
996///970///
...@@ -1075,15 +1049,10 @@ pub const ReadLinkError = error{...@@ -1075,15 +1049,10 @@ pub const ReadLinkError = error{
1075 PermissionDenied,1049 PermissionDenied,
1076 FileSystem,1050 FileSystem,
1077 SymLinkLoop,1051 SymLinkLoop,
1078 NameTooLong,
1079 FileNotFound,1052 FileNotFound,
1080 SystemResources,1053 SystemResources,
1081 NotLink,1054 NotLink,
1082 NotDir,1055 NotDir,
1083 /// WASI: file paths must be valid UTF-8.
1084 /// Windows: file paths provided by the user must be valid WTF-8.
1085 /// https://wtf-8.codeberg.page/
1086 BadPathName,
1087 /// Windows-only. This error may occur if the opened reparse point is1056 /// Windows-only. This error may occur if the opened reparse point is
1088 /// of unsupported type.1057 /// of unsupported type.
1089 UnsupportedReparsePointType,1058 UnsupportedReparsePointType,
...@@ -1095,7 +1064,7 @@ pub const ReadLinkError = error{...@@ -1095,7 +1064,7 @@ pub const ReadLinkError = error{
1095 /// intercepts file system operations and makes them significantly slower1064 /// intercepts file system operations and makes them significantly slower
1096 /// in addition to possibly failing with this error code.1065 /// in addition to possibly failing with this error code.
1097 AntivirusInterference,1066 AntivirusInterference,
1098} || Io.Cancelable || Io.UnexpectedError;1067} || PathNameError || Io.Cancelable || Io.UnexpectedError;
10991068
1100/// Obtain target of a symbolic link.1069/// Obtain target of a symbolic link.
1101///1070///
...@@ -1183,7 +1152,6 @@ pub const DeleteTreeError = error{...@@ -1183,7 +1152,6 @@ pub const DeleteTreeError = error{
1183 FileTooBig,1152 FileTooBig,
1184 SymLinkLoop,1153 SymLinkLoop,
1185 ProcessFdQuotaExceeded,1154 ProcessFdQuotaExceeded,
1186 NameTooLong,
1187 SystemFdQuotaExceeded,1155 SystemFdQuotaExceeded,
1188 NoDevice,1156 NoDevice,
1189 SystemResources,1157 SystemResources,
...@@ -1194,15 +1162,9 @@ pub const DeleteTreeError = error{...@@ -1194,15 +1162,9 @@ pub const DeleteTreeError = error{
1194 /// One of the path components was not a directory.1162 /// One of the path components was not a directory.
1195 /// This error is unreachable if `sub_path` does not contain a path separator.1163 /// This error is unreachable if `sub_path` does not contain a path separator.
1196 NotDir,1164 NotDir,
1197 /// WASI: file paths must be valid UTF-8.
1198 /// Windows: file paths provided by the user must be valid WTF-8.
1199 /// https://wtf-8.codeberg.page/
1200 /// On Windows, file paths cannot contain these characters:
1201 /// '/', '*', '?', '"', '<', '>', '|'
1202 BadPathName,
1203 /// On Windows, `\\server` or `\\server\share` was not found.1165 /// On Windows, `\\server` or `\\server\share` was not found.
1204 NetworkNotFound,1166 NetworkNotFound,
1205} || Io.Cancelable || Io.UnexpectedError;1167} || PathNameError || Io.Cancelable || Io.UnexpectedError;
12061168
1207/// Whether `sub_path` describes a symlink, file, or directory, this function1169/// Whether `sub_path` describes a symlink, file, or directory, this function
1208/// removes it. If it cannot be removed because it is a non-empty directory,1170/// removes it. If it cannot be removed because it is a non-empty directory,
...@@ -1222,7 +1184,7 @@ pub fn deleteTree(dir: Dir, io: Io, sub_path: []const u8) DeleteTreeError!void {...@@ -1222,7 +1184,7 @@ pub fn deleteTree(dir: Dir, io: Io, sub_path: []const u8) DeleteTreeError!void {
1222 iter: Dir.Iterator,1184 iter: Dir.Iterator,
12231185
1224 fn closeAll(inner_io: Io, items: []@This()) void {1186 fn closeAll(inner_io: Io, items: []@This()) void {
1225 for (items) |*item| item.iter.dir.close(inner_io);1187 for (items) |*item| item.iter.reader.dir.close(inner_io);
1226 }1188 }
1227 };1189 };
12281190
...@@ -1243,7 +1205,7 @@ pub fn deleteTree(dir: Dir, io: Io, sub_path: []const u8) DeleteTreeError!void {...@@ -1243,7 +1205,7 @@ pub fn deleteTree(dir: Dir, io: Io, sub_path: []const u8) DeleteTreeError!void {
1243 handle_entry: while (true) {1205 handle_entry: while (true) {
1244 if (treat_as_dir) {1206 if (treat_as_dir) {
1245 if (stack.unusedCapacitySlice().len >= 1) {1207 if (stack.unusedCapacitySlice().len >= 1) {
1246 var iterable_dir = top.iter.dir.openDir(io, entry.name, .{1208 var iterable_dir = top.iter.reader.dir.openDir(io, entry.name, .{
1247 .follow_symlinks = false,1209 .follow_symlinks = false,
1248 .iterate = true,1210 .iterate = true,
1249 }) catch |err| switch (err) {1211 }) catch |err| switch (err) {
...@@ -1273,16 +1235,16 @@ pub fn deleteTree(dir: Dir, io: Io, sub_path: []const u8) DeleteTreeError!void {...@@ -1273,16 +1235,16 @@ pub fn deleteTree(dir: Dir, io: Io, sub_path: []const u8) DeleteTreeError!void {
1273 };1235 };
1274 stack.appendAssumeCapacity(.{1236 stack.appendAssumeCapacity(.{
1275 .name = entry.name,1237 .name = entry.name,
1276 .parent_dir = top.iter.dir,1238 .parent_dir = top.iter.reader.dir,
1277 .iter = iterable_dir.iterateAssumeFirstIteration(),1239 .iter = iterable_dir.iterateAssumeFirstIteration(),
1278 });1240 });
1279 continue :process_stack;1241 continue :process_stack;
1280 } else {1242 } else {
1281 try top.iter.dir.deleteTreeMinStackSizeWithKindHint(io, entry.name, entry.kind);1243 try top.iter.reader.dir.deleteTreeMinStackSizeWithKindHint(io, entry.name, entry.kind);
1282 break :handle_entry;1244 break :handle_entry;
1283 }1245 }
1284 } else {1246 } else {
1285 if (top.iter.dir.deleteFile(io, entry.name)) {1247 if (top.iter.reader.dir.deleteFile(io, entry.name)) {
1286 break :handle_entry;1248 break :handle_entry;
1287 } else |err| switch (err) {1249 } else |err| switch (err) {
1288 error.FileNotFound => break :handle_entry,1250 error.FileNotFound => break :handle_entry,
...@@ -1305,6 +1267,7 @@ pub fn deleteTree(dir: Dir, io: Io, sub_path: []const u8) DeleteTreeError!void {...@@ -1305,6 +1267,7 @@ pub fn deleteTree(dir: Dir, io: Io, sub_path: []const u8) DeleteTreeError!void {
1305 error.FileBusy,1267 error.FileBusy,
1306 error.BadPathName,1268 error.BadPathName,
1307 error.NetworkNotFound,1269 error.NetworkNotFound,
1270 error.Canceled,
1308 error.Unexpected,1271 error.Unexpected,
1309 => |e| return e,1272 => |e| return e,
1310 }1273 }
...@@ -1314,7 +1277,7 @@ pub fn deleteTree(dir: Dir, io: Io, sub_path: []const u8) DeleteTreeError!void {...@@ -1314,7 +1277,7 @@ pub fn deleteTree(dir: Dir, io: Io, sub_path: []const u8) DeleteTreeError!void {
13141277
1315 // On Windows, we can't delete until the dir's handle has been closed, so1278 // On Windows, we can't delete until the dir's handle has been closed, so
1316 // close it before we try to delete.1279 // close it before we try to delete.
1317 top.iter.dir.close(io);1280 top.iter.reader.dir.close(io);
13181281
1319 // In order to avoid double-closing the directory when cleaning up1282 // In order to avoid double-closing the directory when cleaning up
1320 // the stack in the case of an error, we save the relevant portions and1283 // the stack in the case of an error, we save the relevant portions and
...@@ -1324,7 +1287,7 @@ pub fn deleteTree(dir: Dir, io: Io, sub_path: []const u8) DeleteTreeError!void {...@@ -1324,7 +1287,7 @@ pub fn deleteTree(dir: Dir, io: Io, sub_path: []const u8) DeleteTreeError!void {
1324 stack.items.len -= 1;1287 stack.items.len -= 1;
13251288
1326 var need_to_retry: bool = false;1289 var need_to_retry: bool = false;
1327 parent_dir.deleteDir(name) catch |err| switch (err) {1290 parent_dir.deleteDir(io, name) catch |err| switch (err) {
1328 error.FileNotFound => {},1291 error.FileNotFound => {},
1329 error.DirNotEmpty => need_to_retry = true,1292 error.DirNotEmpty => need_to_retry = true,
1330 else => |e| return e,1293 else => |e| return e,
...@@ -1389,6 +1352,7 @@ pub fn deleteTree(dir: Dir, io: Io, sub_path: []const u8) DeleteTreeError!void {...@@ -1389,6 +1352,7 @@ pub fn deleteTree(dir: Dir, io: Io, sub_path: []const u8) DeleteTreeError!void {
1389 error.FileBusy,1352 error.FileBusy,
1390 error.BadPathName,1353 error.BadPathName,
1391 error.NetworkNotFound,1354 error.NetworkNotFound,
1355 error.Canceled,
1392 error.Unexpected,1356 error.Unexpected,
1393 => |e| return e,1357 => |e| return e,
1394 }1358 }
...@@ -1437,7 +1401,7 @@ fn deleteTreeMinStackSizeWithKindHint(parent: Dir, io: Io, sub_path: []const u8,...@@ -1437,7 +1401,7 @@ fn deleteTreeMinStackSizeWithKindHint(parent: Dir, io: Io, sub_path: []const u8,
14371401
1438 scan_dir: while (true) {1402 scan_dir: while (true) {
1439 var dir_it = dir.iterateAssumeFirstIteration();1403 var dir_it = dir.iterateAssumeFirstIteration();
1440 dir_it: while (try dir_it.next()) |entry| {1404 dir_it: while (try dir_it.next(io)) |entry| {
1441 var treat_as_dir = entry.kind == .directory;1405 var treat_as_dir = entry.kind == .directory;
1442 handle_entry: while (true) {1406 handle_entry: while (true) {
1443 if (treat_as_dir) {1407 if (treat_as_dir) {
...@@ -1500,6 +1464,7 @@ fn deleteTreeMinStackSizeWithKindHint(parent: Dir, io: Io, sub_path: []const u8,...@@ -1500,6 +1464,7 @@ fn deleteTreeMinStackSizeWithKindHint(parent: Dir, io: Io, sub_path: []const u8,
1500 error.FileBusy,1464 error.FileBusy,
1501 error.BadPathName,1465 error.BadPathName,
1502 error.NetworkNotFound,1466 error.NetworkNotFound,
1467 error.Canceled,
1503 error.Unexpected,1468 error.Unexpected,
1504 => |e| return e,1469 => |e| return e,
1505 }1470 }
...@@ -1727,7 +1692,7 @@ pub fn setOwner(dir: Dir, io: Io, owner: ?File.Uid, group: ?File.Gid) SetOwnerEr...@@ -1727,7 +1692,7 @@ pub fn setOwner(dir: Dir, io: Io, owner: ?File.Uid, group: ?File.Gid) SetOwnerEr
1727 return io.vtable.dirSetOwner(io.userdata, dir, owner, group);1692 return io.vtable.dirSetOwner(io.userdata, dir, owner, group);
1728}1693}
17291694
1730pub const SetTimestampsError = File.SetTimestampsError;1695pub const SetTimestampsError = File.SetTimestampsError || PathNameError;
17311696
1732pub const SetTimestampsOptions = struct {1697pub const SetTimestampsOptions = struct {
1733 follow_symlinks: bool = true,1698 follow_symlinks: bool = true,
lib/std/Io/File.zig+3-14
...@@ -284,7 +284,9 @@ pub fn isTty(file: File, io: Io) bool {...@@ -284,7 +284,9 @@ pub fn isTty(file: File, io: Io) bool {
284 return io.vtable.fileIsTty(io.userdata, file);284 return io.vtable.fileIsTty(io.userdata, file);
285}285}
286286
287pub const EnableAnsiEscapeCodesError = error{} || Io.Cancelable || Io.UnexpectedError;287pub const EnableAnsiEscapeCodesError = error{
288 NotTerminalDevice,
289} || Io.Cancelable || Io.UnexpectedError;
288290
289pub fn enableAnsiEscapeCodes(file: File, io: Io) EnableAnsiEscapeCodesError!void {291pub fn enableAnsiEscapeCodes(file: File, io: Io) EnableAnsiEscapeCodesError!void {
290 return io.vtable.fileEnableAnsiEscapeCodes(io.userdata, file);292 return io.vtable.fileEnableAnsiEscapeCodes(io.userdata, file);
...@@ -492,19 +494,6 @@ pub fn writePositional(file: File, io: Io, buffer: []const []const u8, offset: u...@@ -492,19 +494,6 @@ pub fn writePositional(file: File, io: Io, buffer: []const []const u8, offset: u
492 return io.vtable.fileWritePositional(io.userdata, file, buffer, offset);494 return io.vtable.fileWritePositional(io.userdata, file, buffer, offset);
493}495}
494496
495pub const WriteFileStreamingError = error{
496 /// `out_fd` is an unconnected socket, or out_fd closed its read end.
497 BrokenPipe,
498 /// Descriptor is not valid or locked, or an mmap(2)-like operation is not available for in_fd.
499 UnsupportedOperation,
500 /// Nonblocking I/O has been selected but the write would block.
501 WouldBlock,
502 /// Unspecified error while reading from in_fd.
503 InputOutput,
504 /// Insufficient kernel memory to read from in_fd.
505 SystemResources,
506} || Io.Cancelable || Io.UnexpectedError;
507
508pub const SeekError = error{497pub const SeekError = error{
509 Unseekable,498 Unseekable,
510 /// The file descriptor does not hold the required rights to seek on it.499 /// The file descriptor does not hold the required rights to seek on it.
lib/std/Io/File/Writer.zig+14-11
...@@ -28,7 +28,9 @@ pub const Error = error{...@@ -28,7 +28,9 @@ pub const Error = error{
28 /// File descriptor does not hold the required rights to write to it.28 /// File descriptor does not hold the required rights to write to it.
29 AccessDenied,29 AccessDenied,
30 PermissionDenied,30 PermissionDenied,
31 /// File is an unconnected socket, or closed its read end.
31 BrokenPipe,32 BrokenPipe,
33 /// Insufficient kernel memory to read from in_fd.
32 SystemResources,34 SystemResources,
33 NotOpenForWriting,35 NotOpenForWriting,
34 /// The process cannot access the file because another process has locked36 /// The process cannot access the file because another process has locked
...@@ -39,20 +41,15 @@ pub const Error = error{...@@ -39,20 +41,15 @@ pub const Error = error{
39 /// This error occurs when a device gets disconnected before or mid-flush41 /// This error occurs when a device gets disconnected before or mid-flush
40 /// while it's being written to - errno(6): No such device or address.42 /// while it's being written to - errno(6): No such device or address.
41 NoDevice,43 NoDevice,
44 FileBusy,
42} || Io.Cancelable || Io.UnexpectedError;45} || Io.Cancelable || Io.UnexpectedError;
4346
44pub const WriteFileError = error{47pub const WriteFileError = Error || error{
45 /// `out_fd` is an unconnected socket, or out_fd closed its read end.
46 BrokenPipe,
47 /// Descriptor is not valid or locked, or an mmap(2)-like operation is not available for in_fd.48 /// Descriptor is not valid or locked, or an mmap(2)-like operation is not available for in_fd.
48 UnsupportedOperation,49 Unimplemented,
49 /// Nonblocking I/O has been selected but the write would block.50 EndOfStream,
50 WouldBlock,51 ReadFailed,
51 /// Unspecified error while reading from in_fd.52};
52 InputOutput,
53 /// Insufficient kernel memory to read from in_fd.
54 SystemResources,
55} || Io.Cancelable || Io.UnexpectedError;
5653
57pub const SeekError = Io.File.SeekError;54pub const SeekError = Io.File.SeekError;
5855
...@@ -175,6 +172,9 @@ fn sendFilePositional(w: *Writer, file_reader: *Io.File.Reader, limit: Io.Limit)...@@ -175,6 +172,9 @@ fn sendFilePositional(w: *Writer, file_reader: *Io.File.Reader, limit: Io.Limit)
175 w.err = error.Canceled;172 w.err = error.Canceled;
176 return error.WriteFailed;173 return error.WriteFailed;
177 },174 },
175 error.EndOfStream => return error.EndOfStream,
176 error.Unimplemented => return error.Unimplemented,
177 error.ReadFailed => return error.ReadFailed,
178 else => |e| {178 else => |e| {
179 w.write_file_err = e;179 w.write_file_err = e;
180 return error.WriteFailed;180 return error.WriteFailed;
...@@ -192,6 +192,9 @@ fn sendFileStreaming(w: *Writer, file_reader: *Io.File.Reader, limit: Io.Limit)...@@ -192,6 +192,9 @@ fn sendFileStreaming(w: *Writer, file_reader: *Io.File.Reader, limit: Io.Limit)
192 w.err = error.Canceled;192 w.err = error.Canceled;
193 return error.WriteFailed;193 return error.WriteFailed;
194 },194 },
195 error.EndOfStream => return error.EndOfStream,
196 error.Unimplemented => return error.Unimplemented,
197 error.ReadFailed => return error.ReadFailed,
195 else => |e| {198 else => |e| {
196 w.write_file_err = e;199 w.write_file_err = e;
197 return error.WriteFailed;200 return error.WriteFailed;
lib/std/Io/Threaded.zig+60-56
...@@ -696,6 +696,7 @@ pub fn io(t: *Threaded) Io {...@@ -696,6 +696,7 @@ pub fn io(t: *Threaded) Io {
696 .dirOpenFile = dirOpenFile,696 .dirOpenFile = dirOpenFile,
697 .dirOpenDir = dirOpenDir,697 .dirOpenDir = dirOpenDir,
698 .dirClose = dirClose,698 .dirClose = dirClose,
699 .dirRead = dirRead,
699 .dirRealPath = dirRealPath,700 .dirRealPath = dirRealPath,
700 .dirDeleteFile = dirDeleteFile,701 .dirDeleteFile = dirDeleteFile,
701 .dirDeleteDir = dirDeleteDir,702 .dirDeleteDir = dirDeleteDir,
...@@ -822,6 +823,7 @@ pub fn ioBasic(t: *Threaded) Io {...@@ -822,6 +823,7 @@ pub fn ioBasic(t: *Threaded) Io {
822 .dirOpenFile = dirOpenFile,823 .dirOpenFile = dirOpenFile,
823 .dirOpenDir = dirOpenDir,824 .dirOpenDir = dirOpenDir,
824 .dirClose = dirClose,825 .dirClose = dirClose,
826 .dirRead = dirRead,
825 .dirRealPath = dirRealPath,827 .dirRealPath = dirRealPath,
826 .dirDeleteFile = dirDeleteFile,828 .dirDeleteFile = dirDeleteFile,
827 .dirDeleteDir = dirDeleteDir,829 .dirDeleteDir = dirDeleteDir,
...@@ -1621,7 +1623,7 @@ fn dirMakeOpenPathPosix(...@@ -1621,7 +1623,7 @@ fn dirMakeOpenPathPosix(
1621) Dir.MakeOpenPathError!Dir {1623) Dir.MakeOpenPathError!Dir {
1622 const t: *Threaded = @ptrCast(@alignCast(userdata));1624 const t: *Threaded = @ptrCast(@alignCast(userdata));
1623 const t_io = ioBasic(t);1625 const t_io = ioBasic(t);
1624 return dirOpenDirPosix(t, dir, sub_path, permissions, options) catch |err| switch (err) {1626 return dirOpenDirPosix(t, dir, sub_path, options) catch |err| switch (err) {
1625 error.FileNotFound => {1627 error.FileNotFound => {
1626 _ = try dir.makePathStatus(t_io, sub_path, permissions);1628 _ = try dir.makePathStatus(t_io, sub_path, permissions);
1627 return dirOpenDirPosix(t, dir, sub_path, options);1629 return dirOpenDirPosix(t, dir, sub_path, options);
...@@ -2388,7 +2390,7 @@ fn dirCreateFilePosix(...@@ -2388,7 +2390,7 @@ fn dirCreateFilePosix(
23882390
2389 try current_thread.beginSyscall();2391 try current_thread.beginSyscall();
2390 const fd: posix.fd_t = while (true) {2392 const fd: posix.fd_t = while (true) {
2391 const rc = openat_sym(dir.handle, sub_path_posix, os_flags, flags.mode);2393 const rc = openat_sym(dir.handle, sub_path_posix, os_flags, flags.permissions.toMode());
2392 switch (posix.errno(rc)) {2394 switch (posix.errno(rc)) {
2393 .SUCCESS => {2395 .SUCCESS => {
2394 current_thread.endSyscall();2396 current_thread.endSyscall();
...@@ -3256,6 +3258,14 @@ fn dirClose(userdata: ?*anyopaque, dirs: []const Dir) void {...@@ -3256,6 +3258,14 @@ fn dirClose(userdata: ?*anyopaque, dirs: []const Dir) void {
3256 for (dirs) |dir| posix.close(dir.handle);3258 for (dirs) |dir| posix.close(dir.handle);
3257}3259}
32583260
3261fn dirRead(userdata: ?*anyopaque, dir_reader: *Dir.Reader, buffer: []Dir.Entry) Dir.Reader.Error!usize {
3262 const t: *Threaded = @ptrCast(@alignCast(userdata));
3263 _ = t;
3264 _ = dir_reader;
3265 _ = buffer;
3266 @panic("TODO");
3267}
3268
3259const dirRealPath = switch (native_os) {3269const dirRealPath = switch (native_os) {
3260 .windows => dirRealPathWindows,3270 .windows => dirRealPathWindows,
3261 else => dirRealPathPosix,3271 else => dirRealPathPosix,
...@@ -3412,7 +3422,6 @@ fn dirRealPathPosix(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, out_b...@@ -3412,7 +3422,6 @@ fn dirRealPathPosix(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, out_b
3412 switch (e) {3422 switch (e) {
3413 .ACCES => return error.AccessDenied,3423 .ACCES => return error.AccessDenied,
3414 .FAULT => |err| return errnoBug(err),3424 .FAULT => |err| return errnoBug(err),
3415 .INVAL => return error.NotLink,
3416 .IO => return error.FileSystem,3425 .IO => return error.FileSystem,
3417 .LOOP => return error.SymLinkLoop,3426 .LOOP => return error.SymLinkLoop,
3418 .NAMETOOLONG => return error.NameTooLong,3427 .NAMETOOLONG => return error.NameTooLong,
...@@ -4562,7 +4571,7 @@ fn fileSyncPosix(userdata: ?*anyopaque, file: File) File.SyncError!void {...@@ -4562,7 +4571,7 @@ fn fileSyncPosix(userdata: ?*anyopaque, file: File) File.SyncError!void {
4562 const current_thread = Thread.getCurrent(t);4571 const current_thread = Thread.getCurrent(t);
4563 try current_thread.beginSyscall();4572 try current_thread.beginSyscall();
4564 while (true) {4573 while (true) {
4565 switch (posix.system.fsync(file.handle)) {4574 switch (posix.errno(posix.system.fsync(file.handle))) {
4566 .SUCCESS => return current_thread.endSyscall(),4575 .SUCCESS => return current_thread.endSyscall(),
4567 .CANCELED => return current_thread.endSyscallCanceled(),4576 .CANCELED => return current_thread.endSyscallCanceled(),
4568 .INTR => {4577 .INTR => {
...@@ -4640,7 +4649,7 @@ fn isTty(current_thread: *Thread, file: File) Io.Cancelable!bool {...@@ -4640,7 +4649,7 @@ fn isTty(current_thread: *Thread, file: File) Io.Cancelable!bool {
4640 const linux = std.os.linux;4649 const linux = std.os.linux;
4641 try current_thread.beginSyscall();4650 try current_thread.beginSyscall();
4642 while (true) {4651 while (true) {
4643 var wsz: linux.winsize = undefined;4652 var wsz: posix.winsize = undefined;
4644 const fd: usize = @bitCast(@as(isize, file.handle));4653 const fd: usize = @bitCast(@as(isize, file.handle));
4645 const rc = linux.syscall3(.ioctl, fd, linux.T.IOCGWINSZ, @intFromPtr(&wsz));4654 const rc = linux.syscall3(.ioctl, fd, linux.T.IOCGWINSZ, @intFromPtr(&wsz));
4646 switch (linux.errno(rc)) {4655 switch (linux.errno(rc)) {
...@@ -4948,7 +4957,7 @@ fn dirSetTimestamps(...@@ -4948,7 +4957,7 @@ fn dirSetTimestamps(
4948 last_accessed: Io.Timestamp,4957 last_accessed: Io.Timestamp,
4949 last_modified: Io.Timestamp,4958 last_modified: Io.Timestamp,
4950 options: Dir.SetTimestampsOptions,4959 options: Dir.SetTimestampsOptions,
4951) File.SetTimestampsError!void {4960) Dir.SetTimestampsError!void {
4952 const t: *Threaded = @ptrCast(@alignCast(userdata));4961 const t: *Threaded = @ptrCast(@alignCast(userdata));
4953 const current_thread = Thread.getCurrent(t);4962 const current_thread = Thread.getCurrent(t);
49544963
...@@ -4961,8 +4970,8 @@ fn dirSetTimestamps(...@@ -4961,8 +4970,8 @@ fn dirSetTimestamps(
4961 }4970 }
49624971
4963 const times: [2]posix.timespec = .{4972 const times: [2]posix.timespec = .{
4964 timestampToPosix(last_accessed),4973 timestampToPosix(last_accessed.nanoseconds),
4965 timestampToPosix(last_modified),4974 timestampToPosix(last_modified.nanoseconds),
4966 };4975 };
49674976
4968 const flags: u32 = if (!options.follow_symlinks) posix.AT.SYMLINK_NOFOLLOW else 0;4977 const flags: u32 = if (!options.follow_symlinks) posix.AT.SYMLINK_NOFOLLOW else 0;
...@@ -5000,7 +5009,7 @@ fn dirSetTimestampsNow(...@@ -5000,7 +5009,7 @@ fn dirSetTimestampsNow(
5000 dir: Dir,5009 dir: Dir,
5001 sub_path: []const u8,5010 sub_path: []const u8,
5002 options: Dir.SetTimestampsOptions,5011 options: Dir.SetTimestampsOptions,
5003) File.SetTimestampsError!void {5012) Dir.SetTimestampsError!void {
5004 const t: *Threaded = @ptrCast(@alignCast(userdata));5013 const t: *Threaded = @ptrCast(@alignCast(userdata));
5005 const current_thread = Thread.getCurrent(t);5014 const current_thread = Thread.getCurrent(t);
50065015
...@@ -5068,8 +5077,8 @@ fn fileSetTimestamps(...@@ -5068,8 +5077,8 @@ fn fileSetTimestamps(
5068 }5077 }
50695078
5070 const times: [2]posix.timespec = .{5079 const times: [2]posix.timespec = .{
5071 timestampToPosix(last_accessed),5080 timestampToPosix(last_accessed.nanoseconds),
5072 timestampToPosix(last_modified),5081 timestampToPosix(last_modified.nanoseconds),
5073 };5082 };
50745083
5075 if (native_os == .wasi and !builtin.link_libc) {5084 if (native_os == .wasi and !builtin.link_libc) {
...@@ -5226,7 +5235,7 @@ fn fileLock(userdata: ?*anyopaque, file: File, lock: File.Lock) File.LockError!v...@@ -5226,7 +5235,7 @@ fn fileLock(userdata: ?*anyopaque, file: File, lock: File.Lock) File.LockError!v
5226 }5235 }
5227 }5236 }
52285237
5229 const operation = switch (lock) {5238 const operation: i32 = switch (lock) {
5230 .none => posix.LOCK.UN,5239 .none => posix.LOCK.UN,
5231 .shared => posix.LOCK.SH,5240 .shared => posix.LOCK.SH,
5232 .exclusive => posix.LOCK.EX,5241 .exclusive => posix.LOCK.EX,
...@@ -5288,7 +5297,7 @@ fn fileTryLock(userdata: ?*anyopaque, file: File, lock: File.Lock) File.LockErro...@@ -5288,7 +5297,7 @@ fn fileTryLock(userdata: ?*anyopaque, file: File, lock: File.Lock) File.LockErro
5288 }5297 }
5289 }5298 }
52905299
5291 const operation = switch (lock) {5300 const operation: i32 = switch (lock) {
5292 .none => posix.LOCK.UN,5301 .none => posix.LOCK.UN,
5293 .shared => posix.LOCK.SH | posix.LOCK.NB,5302 .shared => posix.LOCK.SH | posix.LOCK.NB,
5294 .exclusive => posix.LOCK.EX | posix.LOCK.NB,5303 .exclusive => posix.LOCK.EX | posix.LOCK.NB,
...@@ -5346,27 +5355,16 @@ fn fileUnlock(userdata: ?*anyopaque, file: File) void {...@@ -5346,27 +5355,16 @@ fn fileUnlock(userdata: ?*anyopaque, file: File) void {
5346 return;5355 return;
5347 }5356 }
53485357
5349 try current_thread.beginSyscall();
5350 while (true) {5358 while (true) {
5351 switch (posix.errno(posix.system.flock(file.handle, posix.LOCK.UN))) {5359 switch (posix.errno(posix.system.flock(file.handle, posix.LOCK.UN))) {
5352 .SUCCESS => return current_thread.endSyscall(),5360 .SUCCESS => return,
5353 .CANCELED => return current_thread.endSyscallCanceled(),5361 .CANCELED, .INTR => continue,
5354 .INTR => {5362 .AGAIN => return assert(!is_debug), // unlocking can't block
5355 try current_thread.checkCancel();5363 .BADF => return assert(!is_debug), // File descriptor used after closed.
5356 continue;5364 .INVAL => return assert(!is_debug), // invalid parameters
5357 },5365 .NOLCK => return assert(!is_debug), // Resource deallocation.
5358 else => |e| {5366 .OPNOTSUPP => return assert(!is_debug), // We already got the lock.
5359 current_thread.endSyscall();5367 else => return assert(!is_debug), // Resource deallocation must succeed.
5360 if (is_debug) switch (e) {
5361 .AGAIN => unreachable, // unlocking can't block
5362 .BADF => unreachable, // File descriptor used after closed.
5363 .INVAL => unreachable, // invalid parameters
5364 .NOLCK => unreachable, // Resource deallocation.
5365 .OPNOTSUPP => unreachable, // We already got the lock.
5366 else => unreachable, // Resource deallocation must succeed.
5367 };
5368 return;
5369 },
5370 }5368 }
5371 }5369 }
5372}5370}
...@@ -5424,7 +5422,7 @@ fn fileDowngradeLock(userdata: ?*anyopaque, file: File) File.DowngradeLockError!...@@ -5424,7 +5422,7 @@ fn fileDowngradeLock(userdata: ?*anyopaque, file: File) File.DowngradeLockError!
5424 switch (posix.errno(posix.system.flock(file.handle, operation))) {5422 switch (posix.errno(posix.system.flock(file.handle, operation))) {
5425 .SUCCESS => {5423 .SUCCESS => {
5426 current_thread.endSyscall();5424 current_thread.endSyscall();
5427 return true;5425 return;
5428 },5426 },
5429 .CANCELED => return current_thread.endSyscallCanceled(),5427 .CANCELED => return current_thread.endSyscallCanceled(),
5430 .INTR => {5428 .INTR => {
...@@ -6255,8 +6253,9 @@ fn fileWritePositional(...@@ -6255,8 +6253,9 @@ fn fileWritePositional(
6255 .NOSPC => return error.NoSpaceLeft,6253 .NOSPC => return error.NoSpaceLeft,
6256 .PERM => return error.PermissionDenied,6254 .PERM => return error.PermissionDenied,
6257 .PIPE => return error.BrokenPipe,6255 .PIPE => return error.BrokenPipe,
6258 .CONNRESET => return error.ConnectionResetByPeer,6256 .CONNRESET => |err| return errnoBug(err), // Not a socket handle.
6259 .BUSY => return error.DeviceBusy,6257 .BUSY => return error.DeviceBusy,
6258 .TXTBSY => return error.FileBusy,
6260 .NXIO => return error.Unseekable,6259 .NXIO => return error.Unseekable,
6261 .SPIPE => return error.Unseekable,6260 .SPIPE => return error.Unseekable,
6262 .OVERFLOW => return error.Unseekable,6261 .OVERFLOW => return error.Unseekable,
...@@ -6373,7 +6372,7 @@ fn fileWriteStreaming(...@@ -6373,7 +6372,7 @@ fn fileWriteStreaming(
6373 .NOSPC => return error.NoSpaceLeft,6372 .NOSPC => return error.NoSpaceLeft,
6374 .PERM => return error.PermissionDenied,6373 .PERM => return error.PermissionDenied,
6375 .PIPE => return error.BrokenPipe,6374 .PIPE => return error.BrokenPipe,
6376 .CONNRESET => return error.ConnectionResetByPeer,6375 .CONNRESET => |err| return errnoBug(err), // Not a socket handle.
6377 .BUSY => return error.DeviceBusy,6376 .BUSY => return error.DeviceBusy,
6378 else => |err| return posix.unexpectedErrno(err),6377 else => |err| return posix.unexpectedErrno(err),
6379 }6378 }
...@@ -6388,12 +6387,12 @@ fn fileWriteFileStreaming(...@@ -6388,12 +6387,12 @@ fn fileWriteFileStreaming(
6388 header: []const u8,6387 header: []const u8,
6389 file_reader: *File.Reader,6388 file_reader: *File.Reader,
6390 limit: Io.Limit,6389 limit: Io.Limit,
6391) File.WriteFileStreamingError!usize {6390) File.Writer.WriteFileError!usize {
6392 const t: *Threaded = @ptrCast(@alignCast(userdata));6391 const t: *Threaded = @ptrCast(@alignCast(userdata));
6393 const reader_buffered = file_reader.interface.buffered();6392 const reader_buffered = file_reader.interface.buffered();
6394 if (reader_buffered.len >= @intFromEnum(limit)) {6393 if (reader_buffered.len >= @intFromEnum(limit)) {
6395 const n = try fileWriteStreaming(t, file, header, &.{limit.slice(reader_buffered)}, 1);6394 const n = try fileWriteStreaming(t, file, header, &.{limit.slice(reader_buffered)}, 1);
6396 file_reader.seekBy(n -| header.len) catch return error.ReadFailed;6395 file_reader.interface.toss(n -| header.len);
6397 return n;6396 return n;
6398 }6397 }
6399 const file_limit = @intFromEnum(limit) - reader_buffered.len;6398 const file_limit = @intFromEnum(limit) - reader_buffered.len;
...@@ -6404,7 +6403,7 @@ fn fileWriteFileStreaming(...@@ -6404,7 +6403,7 @@ fn fileWriteFileStreaming(
6404 if (size - file_reader.pos == 0) {6403 if (size - file_reader.pos == 0) {
6405 if (reader_buffered.len != 0) {6404 if (reader_buffered.len != 0) {
6406 const n = try fileWriteStreaming(t, file, header, &.{limit.slice(reader_buffered)}, 1);6405 const n = try fileWriteStreaming(t, file, header, &.{limit.slice(reader_buffered)}, 1);
6407 file_reader.seekBy(n -| header.len) catch return error.ReadFailed;6406 file_reader.interface.toss(n -| header.len);
6408 return n;6407 return n;
6409 } else {6408 } else {
6410 return error.EndOfStream;6409 return error.EndOfStream;
...@@ -6495,7 +6494,7 @@ fn fileWriteFileStreaming(...@@ -6495,7 +6494,7 @@ fn fileWriteFileStreaming(
6495 return error.EndOfStream;6494 return error.EndOfStream;
6496 }6495 }
6497 const ubytes: usize = @intCast(sbytes);6496 const ubytes: usize = @intCast(sbytes);
6498 file_reader.seekBy(ubytes -| header.len) catch return error.ReadFailed;6497 file_reader.interface.toss(ubytes -| header.len);
6499 return ubytes;6498 return ubytes;
6500 }6499 }
65016500
...@@ -6581,7 +6580,7 @@ fn fileWriteFileStreaming(...@@ -6581,7 +6580,7 @@ fn fileWriteFileStreaming(
6581 return error.EndOfStream;6580 return error.EndOfStream;
6582 }6581 }
6583 const u_len: usize = @bitCast(len);6582 const u_len: usize = @bitCast(len);
6584 file_reader.seekBy(u_len -| header.len) catch return error.ReadFailed;6583 file_reader.interface.toss(u_len -| header.len);
6585 return u_len;6584 return u_len;
6586 }6585 }
65876586
...@@ -6591,7 +6590,7 @@ fn fileWriteFileStreaming(...@@ -6591,7 +6590,7 @@ fn fileWriteFileStreaming(
6591 // Linux sendfile does not support headers.6590 // Linux sendfile does not support headers.
6592 if (header.len != 0 or reader_buffered.len != 0) {6591 if (header.len != 0 or reader_buffered.len != 0) {
6593 const n = try fileWriteStreaming(t, file, header, &.{limit.slice(reader_buffered)}, 1);6592 const n = try fileWriteStreaming(t, file, header, &.{limit.slice(reader_buffered)}, 1);
6594 file_reader.seekBy(n -| header.len) catch return error.ReadFailed;6593 file_reader.interface.toss(n -| header.len);
6595 return n;6594 return n;
6596 }6595 }
6597 const max_count = 0x7ffff000; // Avoid EINVAL.6596 const max_count = 0x7ffff000; // Avoid EINVAL.
...@@ -6671,7 +6670,7 @@ fn fileWriteFileStreaming(...@@ -6671,7 +6670,7 @@ fn fileWriteFileStreaming(
6671 if (@atomicLoad(UseCopyFileRange, &t.use_copy_file_range, .monotonic) == .disabled) break :cfr;6670 if (@atomicLoad(UseCopyFileRange, &t.use_copy_file_range, .monotonic) == .disabled) break :cfr;
6672 if (header.len != 0 or reader_buffered.len != 0) {6671 if (header.len != 0 or reader_buffered.len != 0) {
6673 const n = try fileWriteStreaming(t, file, header, &.{limit.slice(reader_buffered)}, 1);6672 const n = try fileWriteStreaming(t, file, header, &.{limit.slice(reader_buffered)}, 1);
6674 file_reader.seekBy(n -| header.len) catch return error.ReadFailed;6673 file_reader.interface.toss(n -| header.len);
6675 return n;6674 return n;
6676 }6675 }
6677 var off_in: i64 = undefined;6676 var off_in: i64 = undefined;
...@@ -6682,7 +6681,7 @@ fn fileWriteFileStreaming(...@@ -6682,7 +6681,7 @@ fn fileWriteFileStreaming(
6682 break :p &off_in;6681 break :p &off_in;
6683 },6682 },
6684 .streaming => null,6683 .streaming => null,
6685 .failure => return error.WriteFailed,6684 .failure => return error.ReadFailed,
6686 };6685 };
6687 const current_thread = Thread.getCurrent(t);6686 const current_thread = Thread.getCurrent(t);
6688 const n: usize = switch (native_os) {6687 const n: usize = switch (native_os) {
...@@ -6712,13 +6711,16 @@ fn fileWriteFileStreaming(...@@ -6712,13 +6711,16 @@ fn fileWriteFileStreaming(
6712 assert(error.Unexpected == switch (e) {6711 assert(error.Unexpected == switch (e) {
6713 .FBIG => return error.FileTooBig,6712 .FBIG => return error.FileTooBig,
6714 .IO => return error.InputOutput,6713 .IO => return error.InputOutput,
6715 .ISDIR => return error.IsDir,
6716 .NOMEM => return error.SystemResources,6714 .NOMEM => return error.SystemResources,
6717 .NOSPC => return error.NoSpaceLeft,6715 .NOSPC => return error.NoSpaceLeft,
6718 .OVERFLOW => return error.Overflow,6716 .OVERFLOW => |err| errnoBug(err), // We avoid passing too large a count.
6719 .PERM => return error.PermissionDenied,6717 .PERM => return error.PermissionDenied,
6720 .TXTBSY => return error.SwapFile,6718 .BUSY => return error.DeviceBusy,
6721 .XDEV => return error.NotSameFileSystem,6719 .TXTBSY => return error.FileBusy,
6720 // copy_file_range can still work but not on
6721 // this pair of file descriptors.
6722 .XDEV => return error.Unimplemented,
6723 .ISDIR => |err| errnoBug(err),
6722 .BADF => |err| errnoBug(err),6724 .BADF => |err| errnoBug(err),
6723 else => |err| posix.unexpectedErrno(err),6725 else => |err| posix.unexpectedErrno(err),
6724 });6726 });
...@@ -6791,7 +6793,7 @@ fn netWriteFile(...@@ -6791,7 +6793,7 @@ fn netWriteFile(
6791 _ = header;6793 _ = header;
6792 _ = file_reader;6794 _ = file_reader;
6793 _ = limit;6795 _ = limit;
6794 return error.Unimplemented; // TODO6796 @panic("TODO");
6795}6797}
67966798
6797fn netWriteFileUnavailable(6799fn netWriteFileUnavailable(
...@@ -6822,7 +6824,7 @@ fn fileWriteFilePositional(...@@ -6822,7 +6824,7 @@ fn fileWriteFilePositional(
6822 const reader_buffered = file_reader.interface.buffered();6824 const reader_buffered = file_reader.interface.buffered();
6823 if (reader_buffered.len >= @intFromEnum(limit)) {6825 if (reader_buffered.len >= @intFromEnum(limit)) {
6824 const n = try fileWritePositional(t, file, header, &.{limit.slice(reader_buffered)}, 1, offset);6826 const n = try fileWritePositional(t, file, header, &.{limit.slice(reader_buffered)}, 1, offset);
6825 file_reader.seekBy(n -| header.len) catch return error.ReadFailed;6827 file_reader.interface.toss(n -| header.len);
6826 return n;6828 return n;
6827 }6829 }
6828 const out_fd = file.handle;6830 const out_fd = file.handle;
...@@ -6832,7 +6834,7 @@ fn fileWriteFilePositional(...@@ -6832,7 +6834,7 @@ fn fileWriteFilePositional(
6832 if (size - file_reader.pos == 0) {6834 if (size - file_reader.pos == 0) {
6833 if (reader_buffered.len != 0) {6835 if (reader_buffered.len != 0) {
6834 const n = try fileWritePositional(t, file, header, &.{limit.slice(reader_buffered)}, 1, offset);6836 const n = try fileWritePositional(t, file, header, &.{limit.slice(reader_buffered)}, 1, offset);
6835 file_reader.seekBy(n -| header.len) catch return error.ReadFailed;6837 file_reader.interface.toss(n -| header.len);
6836 return n;6838 return n;
6837 } else {6839 } else {
6838 return error.EndOfStream;6840 return error.EndOfStream;
...@@ -6844,7 +6846,7 @@ fn fileWriteFilePositional(...@@ -6844,7 +6846,7 @@ fn fileWriteFilePositional(
6844 if (@atomicLoad(UseCopyFileRange, &t.use_copy_file_range, .monotonic) == .disabled) break :cfr;6846 if (@atomicLoad(UseCopyFileRange, &t.use_copy_file_range, .monotonic) == .disabled) break :cfr;
6845 if (header.len != 0 or reader_buffered.len != 0) {6847 if (header.len != 0 or reader_buffered.len != 0) {
6846 const n = try fileWritePositional(t, file, header, &.{limit.slice(reader_buffered)}, 1, offset);6848 const n = try fileWritePositional(t, file, header, &.{limit.slice(reader_buffered)}, 1, offset);
6847 file_reader.seekBy(n -| header.len) catch return error.ReadFailed;6849 file_reader.interface.toss(n -| header.len);
6848 return n;6850 return n;
6849 }6851 }
6850 var off_in: i64 = undefined;6852 var off_in: i64 = undefined;
...@@ -6855,7 +6857,7 @@ fn fileWriteFilePositional(...@@ -6855,7 +6857,7 @@ fn fileWriteFilePositional(
6855 break :p &off_in;6857 break :p &off_in;
6856 },6858 },
6857 .streaming => null,6859 .streaming => null,
6858 .failure => return error.WriteFailed,6860 .failure => return error.ReadFailed,
6859 };6861 };
6860 var off_out: i64 = @intCast(offset);6862 var off_out: i64 = @intCast(offset);
6861 const current_thread = Thread.getCurrent(t);6863 const current_thread = Thread.getCurrent(t);
...@@ -6886,15 +6888,17 @@ fn fileWriteFilePositional(...@@ -6886,15 +6888,17 @@ fn fileWriteFilePositional(
6886 assert(error.Unexpected == switch (e) {6888 assert(error.Unexpected == switch (e) {
6887 .FBIG => return error.FileTooBig,6889 .FBIG => return error.FileTooBig,
6888 .IO => return error.InputOutput,6890 .IO => return error.InputOutput,
6889 .ISDIR => return error.IsDir,
6890 .NOMEM => return error.SystemResources,6891 .NOMEM => return error.SystemResources,
6891 .NOSPC => return error.NoSpaceLeft,6892 .NOSPC => return error.NoSpaceLeft,
6892 .OVERFLOW => return error.Unseekable,6893 .OVERFLOW => return error.Unseekable,
6893 .NXIO => return error.Unseekable,6894 .NXIO => return error.Unseekable,
6894 .SPIPE => return error.Unseekable,6895 .SPIPE => return error.Unseekable,
6895 .PERM => return error.PermissionDenied,6896 .PERM => return error.PermissionDenied,
6896 .TXTBSY => return error.SwapFile,6897 .TXTBSY => return error.FileBusy,
6897 .XDEV => return error.NotSameFileSystem,6898 // copy_file_range can still work but not on
6899 // this pair of file descriptors.
6900 .XDEV => return error.Unimplemented,
6901 .ISDIR => |err| errnoBug(err),
6898 .BADF => |err| errnoBug(err),6902 .BADF => |err| errnoBug(err),
6899 else => |err| posix.unexpectedErrno(err),6903 else => |err| posix.unexpectedErrno(err),
6900 });6904 });
...@@ -6962,7 +6966,7 @@ fn fileWriteFilePositional(...@@ -6962,7 +6966,7 @@ fn fileWriteFilePositional(
6962 const size = file_reader.getSize() catch break :fcf;6966 const size = file_reader.getSize() catch break :fcf;
6963 if (header.len != 0 or reader_buffered.len != 0) {6967 if (header.len != 0 or reader_buffered.len != 0) {
6964 const n = try fileWritePositional(t, file, header, &.{limit.slice(reader_buffered)}, 1, offset);6968 const n = try fileWritePositional(t, file, header, &.{limit.slice(reader_buffered)}, 1, offset);
6965 file_reader.seekBy(n -| header.len) catch return error.ReadFailed;6969 file_reader.interface.toss(n -| header.len);
6966 return n;6970 return n;
6967 }6971 }
6968 const current_thread = Thread.getCurrent(t);6972 const current_thread = Thread.getCurrent(t);
lib/std/Io/net.zig+3-1
...@@ -1290,7 +1290,9 @@ pub const Stream = struct {...@@ -1290,7 +1290,9 @@ pub const Stream = struct {
1290 SocketNotBound,1290 SocketNotBound,
1291 } || Io.UnexpectedError || Io.Cancelable;1291 } || Io.UnexpectedError || Io.Cancelable;
12921292
1293 pub const WriteFileError = error{} || Io.Cancelable || Io.UnexpectedError;1293 pub const WriteFileError = error{
1294 NetworkDown,
1295 } || Io.Cancelable || Io.UnexpectedError;
12941296
1295 pub fn init(stream: Stream, io: Io, buffer: []u8) Writer {1297 pub fn init(stream: Stream, io: Io, buffer: []u8) Writer {
1296 return .{1298 return .{
lib/std/fs/test.zig+6-6
...@@ -844,7 +844,7 @@ test "directory operations on files" {...@@ -844,7 +844,7 @@ test "directory operations on files" {
844844
845 try testing.expectError(error.PathAlreadyExists, ctx.dir.makeDir(io, test_file_name, .default_dir));845 try testing.expectError(error.PathAlreadyExists, ctx.dir.makeDir(io, test_file_name, .default_dir));
846 try testing.expectError(error.NotDir, ctx.dir.openDir(io, test_file_name, .{}));846 try testing.expectError(error.NotDir, ctx.dir.openDir(io, test_file_name, .{}));
847 try testing.expectError(error.NotDir, ctx.dir.deleteDir(test_file_name));847 try testing.expectError(error.NotDir, ctx.dir.deleteDir(io, test_file_name));
848848
849 if (ctx.path_type == .absolute and comptime PathType.absolute.isSupported(builtin.os)) {849 if (ctx.path_type == .absolute and comptime PathType.absolute.isSupported(builtin.os)) {
850 try testing.expectError(error.PathAlreadyExists, fs.makeDirAbsolute(test_file_name));850 try testing.expectError(error.PathAlreadyExists, fs.makeDirAbsolute(test_file_name));
...@@ -934,16 +934,16 @@ test "deleteDir" {...@@ -934,16 +934,16 @@ test "deleteDir" {
934 const test_file_path = try ctx.transformPath("test_dir" ++ fs.path.sep_str ++ "test_file");934 const test_file_path = try ctx.transformPath("test_dir" ++ fs.path.sep_str ++ "test_file");
935935
936 // deleting a non-existent directory936 // deleting a non-existent directory
937 try testing.expectError(error.FileNotFound, ctx.dir.deleteDir(test_dir_path));937 try testing.expectError(error.FileNotFound, ctx.dir.deleteDir(io, test_dir_path));
938938
939 // deleting a non-empty directory939 // deleting a non-empty directory
940 try ctx.dir.makeDir(io, test_dir_path, .default_dir);940 try ctx.dir.makeDir(io, test_dir_path, .default_dir);
941 try ctx.dir.writeFile(io, .{ .sub_path = test_file_path, .data = "" });941 try ctx.dir.writeFile(io, .{ .sub_path = test_file_path, .data = "" });
942 try testing.expectError(error.DirNotEmpty, ctx.dir.deleteDir(test_dir_path));942 try testing.expectError(error.DirNotEmpty, ctx.dir.deleteDir(io, test_dir_path));
943943
944 // deleting an empty directory944 // deleting an empty directory
945 try ctx.dir.deleteFile(io, test_file_path);945 try ctx.dir.deleteFile(io, test_file_path);
946 try ctx.dir.deleteDir(test_dir_path);946 try ctx.dir.deleteDir(io, test_dir_path);
947 }947 }
948 }.impl);948 }.impl);
949}949}
...@@ -2062,7 +2062,7 @@ test "'.' and '..' in Io.Dir functions" {...@@ -2062,7 +2062,7 @@ test "'.' and '..' in Io.Dir functions" {
2062 const prev_status = try dir.updateFile(io, file_path, dir, update_path, .{});2062 const prev_status = try dir.updateFile(io, file_path, dir, update_path, .{});
2063 try testing.expectEqual(Io.Dir.PrevStatus.stale, prev_status);2063 try testing.expectEqual(Io.Dir.PrevStatus.stale, prev_status);
20642064
2065 try ctx.dir.deleteDir(subdir_path);2065 try ctx.dir.deleteDir(io, subdir_path);
2066 }2066 }
2067 }.impl);2067 }.impl);
2068}2068}
...@@ -2174,7 +2174,7 @@ test "invalid UTF-8/WTF-8 paths" {...@@ -2174,7 +2174,7 @@ test "invalid UTF-8/WTF-8 paths" {
21742174
2175 try testing.expectError(expected_err, ctx.dir.deleteFile(invalid_path));2175 try testing.expectError(expected_err, ctx.dir.deleteFile(invalid_path));
21762176
2177 try testing.expectError(expected_err, ctx.dir.deleteDir(invalid_path));2177 try testing.expectError(expected_err, ctx.dir.deleteDir(io, invalid_path));
21782178
2179 try testing.expectError(expected_err, ctx.dir.rename(invalid_path, ctx.dir, invalid_path, io));2179 try testing.expectError(expected_err, ctx.dir.rename(invalid_path, ctx.dir, invalid_path, io));
21802180
src/Package/Fetch.zig+2-2
...@@ -578,7 +578,7 @@ fn runResource(...@@ -578,7 +578,7 @@ fn runResource(
578 };578 };
579 // Remove temporary directory root if not already renamed to global cache.579 // Remove temporary directory root if not already renamed to global cache.
580 if (!std.mem.eql(u8, package_sub_path, tmp_dir_sub_path)) {580 if (!std.mem.eql(u8, package_sub_path, tmp_dir_sub_path)) {
581 cache_root.handle.deleteDir(tmp_dir_sub_path) catch {};581 cache_root.handle.deleteDir(io, tmp_dir_sub_path) catch {};
582 }582 }
583583
584 // Validate the computed hash against the expected hash. If invalid, this584 // Validate the computed hash against the expected hash. If invalid, this
...@@ -1593,7 +1593,7 @@ fn computeHash(f: *Fetch, pkg_path: Cache.Path, filter: Filter) RunError!Compute...@@ -1593,7 +1593,7 @@ fn computeHash(f: *Fetch, pkg_path: Cache.Path, filter: Filter) RunError!Compute
1593 var i: usize = 0;1593 var i: usize = 0;
1594 while (i < sus_dirs.count()) : (i += 1) {1594 while (i < sus_dirs.count()) : (i += 1) {
1595 const sus_dir = sus_dirs.keys()[i];1595 const sus_dir = sus_dirs.keys()[i];
1596 root_dir.deleteDir(sus_dir) catch |err| switch (err) {1596 root_dir.deleteDir(io, sus_dir) catch |err| switch (err) {
1597 error.DirNotEmpty => continue,1597 error.DirNotEmpty => continue,
1598 error.FileNotFound => continue,1598 error.FileNotFound => continue,
1599 else => |e| {1599 else => |e| {