authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-02-01 01:08:01-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-02-01 01:08:01-08:00
log59073484baf89072aa02f23fe9a09662e5def100
tree80091d7af70172ec2c656dce9b407bc21119ae78
parente5454ff780ae4571cfa71a2edb6f4287eb8cf4de

std.Io: add ioctl / DeviceIoControlFile API


5 files changed, 211 insertions(+), 58 deletions(-)

lib/std/Io.zig+28-1
...@@ -257,6 +257,9 @@ pub const VTable = struct {...@@ -257,6 +257,9 @@ pub const VTable = struct {
257pub const Operation = union(enum) {257pub const Operation = union(enum) {
258 file_read_streaming: FileReadStreaming,258 file_read_streaming: FileReadStreaming,
259 file_write_streaming: FileWriteStreaming,259 file_write_streaming: FileWriteStreaming,
260 /// On Windows this is NtDeviceIoControlFile. On POSIX this is ioctl. On
261 /// other systems this tag is unreachable.
262 device_io_control: DeviceIoControl,
260263
261 pub const Tag = @typeInfo(Operation).@"union".tag_type.?;264 pub const Tag = @typeInfo(Operation).@"union".tag_type.?;
262265
...@@ -324,13 +327,37 @@ pub const Operation = union(enum) {...@@ -324,13 +327,37 @@ pub const Operation = union(enum) {
324 pub const Result = Error!usize;327 pub const Result = Error!usize;
325 };328 };
326329
330 pub const DeviceIoControl = switch (builtin.os.tag) {
331 .wasi => noreturn,
332 .windows => struct {
333 file: File,
334 IoControlCode: std.os.windows.CTL_CODE,
335 InputBuffer: ?*const anyopaque,
336 InputBufferLength: u32,
337 OutputBuffer: ?*anyopaque,
338 OutputBufferLength: u32,
339
340 pub const Result = std.os.windows.IO_STATUS_BLOCK;
341 },
342 else => struct {
343 file: File,
344 /// Device-dependent operation code.
345 code: u32,
346 arg: ?*anyopaque,
347
348 /// Device and operation dependent result. Negative values are
349 /// negative errno.
350 pub const Result = i32;
351 },
352 };
353
327 pub const Result = Result: {354 pub const Result = Result: {
328 const operation_fields = @typeInfo(Operation).@"union".fields;355 const operation_fields = @typeInfo(Operation).@"union".fields;
329 var field_names: [operation_fields.len][]const u8 = undefined;356 var field_names: [operation_fields.len][]const u8 = undefined;
330 var field_types: [operation_fields.len]type = undefined;357 var field_types: [operation_fields.len]type = undefined;
331 for (operation_fields, &field_names, &field_types) |field, *field_name, *field_type| {358 for (operation_fields, &field_names, &field_types) |field, *field_name, *field_type| {
332 field_name.* = field.name;359 field_name.* = field.name;
333 field_type.* = field.type.Result;360 field_type.* = if (field.type == noreturn) noreturn else field.type.Result;
334 }361 }
335 break :Result @Union(.auto, Tag, &field_names, &field_types, &@splat(.{}));362 break :Result @Union(.auto, Tag, &field_names, &field_types, &@splat(.{}));
336 };363 };
lib/std/Io/Threaded.zig+163-25
...@@ -2500,6 +2500,9 @@ fn operate(userdata: ?*anyopaque, operation: Io.Operation) Io.Cancelable!Io.Oper...@@ -2500,6 +2500,9 @@ fn operate(userdata: ?*anyopaque, operation: Io.Operation) Io.Cancelable!Io.Oper
2500 else => |e| e,2500 else => |e| e,
2501 },2501 },
2502 },2502 },
2503 .device_io_control => |*o| return .{
2504 .device_io_control = try deviceIoControl(t, o),
2505 },
2503 }2506 }
2504}2507}
25052508
...@@ -2531,6 +2534,14 @@ fn batchAwaitAsync(userdata: ?*anyopaque, b: *Io.Batch) Io.Cancelable!void {...@@ -2531,6 +2534,14 @@ fn batchAwaitAsync(userdata: ?*anyopaque, b: *Io.Batch) Io.Cancelable!void {
2531 poll_buffer[poll_len] = .{ .fd = o.file.handle, .events = posix.POLL.OUT, .revents = 0 };2534 poll_buffer[poll_len] = .{ .fd = o.file.handle, .events = posix.POLL.OUT, .revents = 0 };
2532 poll_len += 1;2535 poll_len += 1;
2533 },2536 },
2537 .device_io_control => |o| {
2538 poll_buffer[poll_len] = .{
2539 .fd = o.file.handle,
2540 .events = posix.POLL.OUT | posix.POLL.IN | posix.POLL.ERR,
2541 .revents = 0,
2542 };
2543 poll_len += 1;
2544 },
2534 }2545 }
2535 index = submission.node.next;2546 index = submission.node.next;
2536 }2547 }
...@@ -2696,6 +2707,7 @@ fn batchAwaitConcurrent(userdata: ?*anyopaque, b: *Io.Batch, timeout: Io.Timeout...@@ -2696,6 +2707,7 @@ fn batchAwaitConcurrent(userdata: ?*anyopaque, b: *Io.Batch, timeout: Io.Timeout
2696 switch (submission.operation) {2707 switch (submission.operation) {
2697 .file_read_streaming => |o| try poll_storage.add(o.file, posix.POLL.IN),2708 .file_read_streaming => |o| try poll_storage.add(o.file, posix.POLL.IN),
2698 .file_write_streaming => |o| try poll_storage.add(o.file, posix.POLL.OUT),2709 .file_write_streaming => |o| try poll_storage.add(o.file, posix.POLL.OUT),
2710 .device_io_control => |o| try poll_storage.add(o.file, posix.POLL.IN | posix.POLL.OUT | posix.POLL.ERR),
2699 }2711 }
2700 index = submission.node.next;2712 index = submission.node.next;
2701 }2713 }
...@@ -2874,6 +2886,7 @@ fn batchApc(apc_context: ?*anyopaque, iosb: *windows.IO_STATUS_BLOCK, _: windows...@@ -2874,6 +2886,7 @@ fn batchApc(apc_context: ?*anyopaque, iosb: *windows.IO_STATUS_BLOCK, _: windows
2874 const result: Io.Operation.Result = switch (pending.tag) {2886 const result: Io.Operation.Result = switch (pending.tag) {
2875 .file_read_streaming => .{ .file_read_streaming = ntReadFileResult(iosb) },2887 .file_read_streaming => .{ .file_read_streaming = ntReadFileResult(iosb) },
2876 .file_write_streaming => .{ .file_write_streaming = ntWriteFileResult(iosb) },2888 .file_write_streaming => .{ .file_write_streaming = ntWriteFileResult(iosb) },
2889 .device_io_control => .{ .device_io_control = iosb.* },
2877 };2890 };
2878 storage.* = .{ .completion = .{ .node = .{ .next = .none }, .result = result } };2891 storage.* = .{ .completion = .{ .node = .{ .next = .none }, .result = result } };
2879 },2892 },
...@@ -3020,6 +3033,59 @@ fn batchAwaitWindows(b: *Io.Batch, concurrency: bool) error{ Canceled, Concurren...@@ -3020,6 +3033,59 @@ fn batchAwaitWindows(b: *Io.Batch, concurrency: bool) error{ Canceled, Concurren
3020 else => |status| {3033 else => |status| {
3021 syscall.finish();3034 syscall.finish();
30223035
3036 context.iosb.u.Status = status;
3037 batchApc(b, &context.iosb, 0);
3038 break;
3039 },
3040 };
3041 }
3042 },
3043 .device_io_control => |o| {
3044 if (o.file.flags.nonblocking) {
3045 context.file = o.file.handle;
3046 switch (windows.ntdll.NtDeviceIoControlFile(
3047 o.file.handle,
3048 null, // event
3049 &batchApc,
3050 b,
3051 &context.iosb,
3052 o.IoControlCode,
3053 o.InputBuffer,
3054 o.InputBufferLength,
3055 o.OutputBuffer,
3056 o.OutputBufferLength,
3057 )) {
3058 .PENDING, .SUCCESS => {},
3059 .CANCELLED => unreachable,
3060 else => |status| {
3061 context.iosb.u.Status = status;
3062 batchApc(b, &context.iosb, 0);
3063 },
3064 }
3065 } else {
3066 if (concurrency) return error.ConcurrencyUnavailable;
3067
3068 const syscall: Syscall = try .start();
3069 while (true) switch (windows.ntdll.NtDeviceIoControlFile(
3070 o.file.handle,
3071 null, // event
3072 null, // APC routine
3073 null, // APC context
3074 &context.iosb,
3075 o.IoControlCode,
3076 o.InputBuffer,
3077 o.InputBufferLength,
3078 o.OutputBuffer,
3079 o.OutputBufferLength,
3080 )) {
3081 .PENDING => unreachable, // unrecoverable: wrong File nonblocking flag
3082 .CANCELLED => {
3083 try syscall.checkCancel();
3084 continue;
3085 },
3086 else => |status| {
3087 syscall.finish();
3088
3023 context.iosb.u.Status = status;3089 context.iosb.u.Status = status;
3024 batchApc(b, &context.iosb, 0);3090 batchApc(b, &context.iosb, 0);
3025 break;3091 break;
...@@ -12986,31 +13052,18 @@ fn netInterfaceNameResolve(...@@ -12986,31 +13052,18 @@ fn netInterfaceNameResolve(
12986 };13052 };
1298713053
12988 const syscall: Syscall = try .start();13054 const syscall: Syscall = try .start();
12989 while (true) {13055 while (true) switch (posix.errno(posix.system.ioctl(sock_fd, posix.SIOCGIFINDEX, @intFromPtr(&ifr)))) {
12990 switch (posix.errno(posix.system.ioctl(sock_fd, posix.SIOCGIFINDEX, @intFromPtr(&ifr)))) {13056 .SUCCESS => {
12991 .SUCCESS => {13057 syscall.finish();
12992 syscall.finish();13058 return .{ .index = @bitCast(ifr.ifru.ivalue) };
12993 return .{ .index = @bitCast(ifr.ifru.ivalue) };13059 },
12994 },13060 .INTR => {
12995 .INTR => {13061 try syscall.checkCancel();
12996 try syscall.checkCancel();13062 continue;
12997 continue;13063 },
12998 },13064 .NODEV => return syscall.fail(error.InterfaceNotFound),
12999 else => |e| {13065 else => |err| return syscall.unexpectedErrno(err),
13000 syscall.finish();13066 };
13001 switch (e) {
13002 .INVAL => |err| return errnoBug(err), // Bad parameters.
13003 .NOTTY => |err| return errnoBug(err),
13004 .NXIO => |err| return errnoBug(err),
13005 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
13006 .FAULT => |err| return errnoBug(err), // Bad pointer parameter.
13007 .IO => |err| return errnoBug(err), // sock_fd is not a file descriptor
13008 .NODEV => return error.InterfaceNotFound,
13009 else => |err| return posix.unexpectedErrno(err),
13010 }
13011 },
13012 }
13013 }
13014 }13067 }
1301513068
13016 if (is_windows) {13069 if (is_windows) {
...@@ -17849,3 +17902,88 @@ fn mmSyncWrite(file: File, memory: []u8, offset: u64) File.WritePositionalError!...@@ -17849,3 +17902,88 @@ fn mmSyncWrite(file: File, memory: []u8, offset: u64) File.WritePositionalError!
17849 }17902 }
17850 }17903 }
17851}17904}
17905
17906fn deviceIoControl(t: *Threaded, o: *const Io.Operation.DeviceIoControl) Io.Cancelable!Io.Operation.DeviceIoControl.Result {
17907 _ = t;
17908 if (is_windows) {
17909 var iosb: windows.IO_STATUS_BLOCK = undefined;
17910 if (o.file.flags.nonblocking) {
17911 var done: bool = false;
17912 switch (windows.ntdll.NtDeviceIoControlFile(
17913 o.file.handle,
17914 null, // event
17915 flagApc,
17916 &done, // APC context
17917 &iosb,
17918 o.IoControlCode,
17919 o.InputBuffer,
17920 o.InputBufferLength,
17921 o.OutputBuffer,
17922 o.OutputBufferLength,
17923 )) {
17924 // We must wait for the APC routine.
17925 .PENDING, .SUCCESS => while (!done) {
17926 // Once we get here we must not return from the function until the
17927 // operation completes, thereby releasing reference to io_status_block.
17928 const alertable_syscall = AlertableSyscall.start() catch |err| switch (err) {
17929 error.Canceled => |e| {
17930 var cancel_iosb: windows.IO_STATUS_BLOCK = undefined;
17931 _ = windows.ntdll.NtCancelIoFileEx(o.file.handle, &iosb, &cancel_iosb);
17932 while (!done) waitForApcOrAlert();
17933 return e;
17934 },
17935 };
17936 waitForApcOrAlert();
17937 alertable_syscall.finish();
17938 },
17939 else => |status| iosb.u.Status = status,
17940 }
17941 } else {
17942 const syscall: Syscall = try .start();
17943 while (true) switch (windows.ntdll.NtDeviceIoControlFile(
17944 o.file.handle,
17945 null, // event
17946 null, // APC routine
17947 null, // APC context
17948 &iosb,
17949 o.IoControlCode,
17950 o.InputBuffer,
17951 o.InputBufferLength,
17952 o.OutputBuffer,
17953 o.OutputBufferLength,
17954 )) {
17955 .PENDING => unreachable, // unrecoverable: wrong asynchronous flag
17956 .CANCELLED => {
17957 try syscall.checkCancel();
17958 continue;
17959 },
17960 else => |status| {
17961 syscall.finish();
17962 iosb.u.Status = status;
17963 break;
17964 },
17965 };
17966 }
17967 return iosb;
17968 } else {
17969 const syscall: Syscall = try .start();
17970 while (true) {
17971 const rc = posix.system.ioctl(o.file.handle, @bitCast(o.code), @intFromPtr(o.arg));
17972 switch (posix.errno(rc)) {
17973 .SUCCESS => {
17974 syscall.finish();
17975 if (@TypeOf(rc) == usize) return @bitCast(@as(u32, @truncate(rc)));
17976 return rc;
17977 },
17978 .INTR => {
17979 try syscall.checkCancel();
17980 continue;
17981 },
17982 else => |err| {
17983 syscall.finish();
17984 return -@as(i32, @intFromEnum(err));
17985 },
17986 }
17987 }
17988 }
17989}
lib/std/Progress.zig+14-9
...@@ -573,7 +573,7 @@ fn updateTask(io: Io) void {...@@ -573,7 +573,7 @@ fn updateTask(io: Io) void {
573 {573 {
574 const resize_flag = wait(io, global_progress.initial_delay_ns);574 const resize_flag = wait(io, global_progress.initial_delay_ns);
575 if (@atomicLoad(bool, &global_progress.done, .monotonic)) return;575 if (@atomicLoad(bool, &global_progress.done, .monotonic)) return;
576 maybeUpdateSize(resize_flag);576 maybeUpdateSize(io, resize_flag) catch return;
577577
578 const buffer, _ = computeRedraw(&serialized_buffer);578 const buffer, _ = computeRedraw(&serialized_buffer);
579 if (io.vtable.tryLockStderr(io.userdata, null) catch return) |locked_stderr| {579 if (io.vtable.tryLockStderr(io.userdata, null) catch return) |locked_stderr| {
...@@ -592,7 +592,7 @@ fn updateTask(io: Io) void {...@@ -592,7 +592,7 @@ fn updateTask(io: Io) void {
592 return clearWrittenWithEscapeCodes(stderr.file_writer) catch {};592 return clearWrittenWithEscapeCodes(stderr.file_writer) catch {};
593 }593 }
594594
595 maybeUpdateSize(resize_flag);595 maybeUpdateSize(io, resize_flag) catch return;
596596
597 const buffer, _ = computeRedraw(&serialized_buffer);597 const buffer, _ = computeRedraw(&serialized_buffer);
598 if (io.vtable.tryLockStderr(io.userdata, null) catch return) |locked_stderr| {598 if (io.vtable.tryLockStderr(io.userdata, null) catch return) |locked_stderr| {
...@@ -622,7 +622,7 @@ fn windowsApiUpdateTask(io: Io) void {...@@ -622,7 +622,7 @@ fn windowsApiUpdateTask(io: Io) void {
622 {622 {
623 const resize_flag = wait(io, global_progress.initial_delay_ns);623 const resize_flag = wait(io, global_progress.initial_delay_ns);
624 if (@atomicLoad(bool, &global_progress.done, .monotonic)) return;624 if (@atomicLoad(bool, &global_progress.done, .monotonic)) return;
625 maybeUpdateSize(resize_flag);625 maybeUpdateSize(io, resize_flag) catch return;
626626
627 const buffer, const nl_n = computeRedraw(&serialized_buffer);627 const buffer, const nl_n = computeRedraw(&serialized_buffer);
628 if (io.vtable.tryLockStderr(io.userdata, null) catch return) |locked_stderr| {628 if (io.vtable.tryLockStderr(io.userdata, null) catch return) |locked_stderr| {
...@@ -643,7 +643,7 @@ fn windowsApiUpdateTask(io: Io) void {...@@ -643,7 +643,7 @@ fn windowsApiUpdateTask(io: Io) void {
643 return clearWrittenWindowsApi() catch {};643 return clearWrittenWindowsApi() catch {};
644 }644 }
645645
646 maybeUpdateSize(resize_flag);646 maybeUpdateSize(io, resize_flag) catch return;
647647
648 const buffer, const nl_n = computeRedraw(&serialized_buffer);648 const buffer, const nl_n = computeRedraw(&serialized_buffer);
649 if (io.vtable.tryLockStderr(io.userdata, null) catch return) |locked_stderr| {649 if (io.vtable.tryLockStderr(io.userdata, null) catch return) |locked_stderr| {
...@@ -1484,15 +1484,15 @@ fn writevNonblock(io: Io, file: Io.File, iov: [][]const u8) Io.File.Writer.Error...@@ -1484,15 +1484,15 @@ fn writevNonblock(io: Io, file: Io.File, iov: [][]const u8) Io.File.Writer.Error
1484 }1484 }
1485}1485}
14861486
1487fn maybeUpdateSize(resize_flag: bool) void {1487fn maybeUpdateSize(io: Io, resize_flag: bool) !void {
1488 if (!resize_flag) return;1488 if (!resize_flag) return;
14891489
1490 const fd = global_progress.terminal.handle;1490 const file = global_progress.terminal;
14911491
1492 if (is_windows) {1492 if (is_windows) {
1493 var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;1493 var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;
14941494
1495 if (windows.kernel32.GetConsoleScreenBufferInfo(fd, &info) != windows.FALSE) {1495 if (windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info) != windows.FALSE) {
1496 // In the old Windows console, dwSize.Y is the line count of the1496 // In the old Windows console, dwSize.Y is the line count of the
1497 // entire scrollback buffer, so we use this instead so that we1497 // entire scrollback buffer, so we use this instead so that we
1498 // always get the size of the screen.1498 // always get the size of the screen.
...@@ -1512,8 +1512,13 @@ fn maybeUpdateSize(resize_flag: bool) void {...@@ -1512,8 +1512,13 @@ fn maybeUpdateSize(resize_flag: bool) void {
1512 .ypixel = 0,1512 .ypixel = 0,
1513 };1513 };
15141514
1515 const err = posix.system.ioctl(fd, posix.T.IOCGWINSZ, @intFromPtr(&winsize));1515 const err = (try io.operate(.{ .device_io_control = .{
1516 if (posix.errno(err) == .SUCCESS) {1516 .file = file,
1517 .code = posix.T.IOCGWINSZ,
1518 .arg = &winsize,
1519 } })).device_io_control;
1520
1521 if (err >= 0) {
1517 global_progress.rows = winsize.row;1522 global_progress.rows = winsize.row;
1518 global_progress.cols = winsize.col;1523 global_progress.cols = winsize.col;
1519 } else {1524 } else {
lib/std/c.zig+6-1
...@@ -10731,7 +10731,6 @@ pub extern "c" fn sysctlnametomib(name: [*:0]const u8, mibp: ?*c_int, sizep: ?*u...@@ -10731,7 +10731,6 @@ pub extern "c" fn sysctlnametomib(name: [*:0]const u8, mibp: ?*c_int, sizep: ?*u
10731pub extern "c" fn tcgetattr(fd: fd_t, termios_p: *termios) c_int;10731pub extern "c" fn tcgetattr(fd: fd_t, termios_p: *termios) c_int;
10732pub extern "c" fn tcsetattr(fd: fd_t, optional_action: TCSA, termios_p: *const termios) c_int;10732pub extern "c" fn tcsetattr(fd: fd_t, optional_action: TCSA, termios_p: *const termios) c_int;
10733pub extern "c" fn fcntl(fd: fd_t, cmd: c_int, ...) c_int;10733pub extern "c" fn fcntl(fd: fd_t, cmd: c_int, ...) c_int;
10734pub extern "c" fn ioctl(fd: fd_t, request: c_int, ...) c_int;
10735pub extern "c" fn uname(buf: *utsname) c_int;10734pub extern "c" fn uname(buf: *utsname) c_int;
1073610735
10737pub extern "c" fn gethostname(name: [*]u8, len: usize) c_int;10736pub extern "c" fn gethostname(name: [*]u8, len: usize) c_int;
...@@ -11108,6 +11107,11 @@ pub const clock_nanosleep = switch (native_os) {...@@ -11108,6 +11107,11 @@ pub const clock_nanosleep = switch (native_os) {
11108 else => {},11107 else => {},
11109};11108};
1111011109
11110pub const ioctl = switch (native_os) {
11111 .windows, .wasi => {},
11112 else => private.ioctl,
11113};
11114
11111// OS-specific bits. These are protected from being used on the wrong OS by11115// OS-specific bits. These are protected from being used on the wrong OS by
11112// comptime assertions inside each OS-specific file.11116// comptime assertions inside each OS-specific file.
1111311117
...@@ -11495,6 +11499,7 @@ const private = struct {...@@ -11495,6 +11499,7 @@ const private = struct {
11495 };11499 };
11496 extern "c" fn getrusage(who: c_int, usage: *rusage) c_int;11500 extern "c" fn getrusage(who: c_int, usage: *rusage) c_int;
11497 extern "c" fn gettimeofday(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int;11501 extern "c" fn gettimeofday(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int;
11502 extern "c" fn ioctl(fd: fd_t, request: c_int, ...) c_int;
11498 extern "c" fn msync(addr: *align(page_size) const anyopaque, len: usize, flags: c_int) c_int;11503 extern "c" fn msync(addr: *align(page_size) const anyopaque, len: usize, flags: c_int) c_int;
11499 extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int;11504 extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int;
11500 extern "c" fn clock_nanosleep(clockid: clockid_t, flags: TIMER, t: *const timespec, remain: ?*timespec) c_int;11505 extern "c" fn clock_nanosleep(clockid: clockid_t, flags: TIMER, t: *const timespec, remain: ?*timespec) c_int;
lib/std/posix.zig-22
...@@ -1800,28 +1800,6 @@ pub fn name_to_handle_atZ(...@@ -1800,28 +1800,6 @@ pub fn name_to_handle_atZ(
1800 }1800 }
1801}1801}
18021802
1803pub const IoCtl_SIOCGIFINDEX_Error = error{
1804 FileSystem,
1805 InterfaceNotFound,
1806} || UnexpectedError;
1807
1808pub fn ioctl_SIOCGIFINDEX(fd: fd_t, ifr: *ifreq) IoCtl_SIOCGIFINDEX_Error!void {
1809 while (true) {
1810 switch (errno(system.ioctl(fd, SIOCGIFINDEX, @intFromPtr(ifr)))) {
1811 .SUCCESS => return,
1812 .INVAL => unreachable, // Bad parameters.
1813 .NOTTY => unreachable,
1814 .NXIO => unreachable,
1815 .BADF => unreachable, // Always a race condition.
1816 .FAULT => unreachable, // Bad pointer parameter.
1817 .INTR => continue,
1818 .IO => return error.FileSystem,
1819 .NODEV => return error.InterfaceNotFound,
1820 else => |err| return unexpectedErrno(err),
1821 }
1822 }
1823}
1824
1825pub const lfs64_abi = native_os == .linux and builtin.link_libc and (builtin.abi.isGnu() or builtin.abi.isAndroid());1803pub const lfs64_abi = native_os == .linux and builtin.link_libc and (builtin.abi.isGnu() or builtin.abi.isAndroid());
18261804
1827/// Whether or not `error.Unexpected` will print its value and a stack trace.1805/// Whether or not `error.Unexpected` will print its value and a stack trace.