aboutsummaryrefslogtreecommitdiff
path: root/lib/std/os/linux.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2025-06-27 20:05:22 -0700
committerAndrew Kelley <andrew@ziglang.org>2025-07-07 22:43:51 -0700
commit0e37ff0d591dd75ceec9208196bec29efaec607a (patch)
treec126fa823a1f3864e9c363aac70e3a3db0219957 /lib/std/os/linux.zig
parent0b3f0124dc33403d329fb8ee63a93215d9af1f1e (diff)
downloadzig-0e37ff0d591dd75ceec9208196bec29efaec607a.tar.gz
zig-0e37ff0d591dd75ceec9208196bec29efaec607a.zip
std.fmt: breaking API changes
added adapter to AnyWriter and GenericWriter to help bridge the gap between old and new API make std.testing.expectFmt work at compile-time std.fmt no longer has a dependency on std.unicode. Formatted printing was never properly unicode-aware. Now it no longer pretends to be. Breakage/deprecations: * std.fs.File.reader -> std.fs.File.deprecatedReader * std.fs.File.writer -> std.fs.File.deprecatedWriter * std.io.GenericReader -> std.io.Reader * std.io.GenericWriter -> std.io.Writer * std.io.AnyReader -> std.io.Reader * std.io.AnyWriter -> std.io.Writer * std.fmt.format -> std.fmt.deprecatedFormat * std.fmt.fmtSliceEscapeLower -> std.ascii.hexEscape * std.fmt.fmtSliceEscapeUpper -> std.ascii.hexEscape * std.fmt.fmtSliceHexLower -> {x} * std.fmt.fmtSliceHexUpper -> {X} * std.fmt.fmtIntSizeDec -> {B} * std.fmt.fmtIntSizeBin -> {Bi} * std.fmt.fmtDuration -> {D} * std.fmt.fmtDurationSigned -> {D} * {} -> {f} when there is a format method * format method signature - anytype -> *std.io.Writer - inferred error set -> error{WriteFailed} - options -> (deleted) * std.fmt.Formatted - now takes context type explicitly - no fmt string
Diffstat (limited to 'lib/std/os/linux.zig')
-rw-r--r--lib/std/os/linux.zig130
1 files changed, 129 insertions, 1 deletions
diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig
index 3b2f51464e..75494145b9 100644
--- a/lib/std/os/linux.zig
+++ b/lib/std/os/linux.zig
@@ -9420,4 +9420,132 @@ pub const msghdr_const = extern struct {
control: ?*const anyopaque,
controllen: usize,
flags: u32,
-}; \ No newline at end of file
+};
+
+/// The syscalls, but with Zig error sets, going through libc if linking libc,
+/// and with some footguns eliminated.
+pub const wrapped = struct {
+ pub const lfs64_abi = builtin.link_libc and (builtin.abi.isGnu() or builtin.abi.isAndroid());
+ const system = if (builtin.link_libc) std.c else std.os.linux;
+
+ pub const SendfileError = std.posix.UnexpectedError || error{
+ /// `out_fd` is an unconnected socket, or out_fd closed its read end.
+ BrokenPipe,
+ /// Descriptor is not valid or locked, or an mmap(2)-like operation is not available for in_fd.
+ UnsupportedOperation,
+ /// Nonblocking I/O has been selected but the write would block.
+ WouldBlock,
+ /// Unspecified error while reading from in_fd.
+ InputOutput,
+ /// Insufficient kernel memory to read from in_fd.
+ SystemResources,
+ /// `offset` is not `null` but the input file is not seekable.
+ Unseekable,
+ };
+
+ pub fn sendfile(
+ out_fd: fd_t,
+ in_fd: fd_t,
+ in_offset: ?*off_t,
+ in_len: usize,
+ ) SendfileError!usize {
+ const adjusted_len = @min(in_len, 0x7ffff000); // Prevents EOVERFLOW.
+ const sendfileSymbol = if (lfs64_abi) system.sendfile64 else system.sendfile;
+ const rc = sendfileSymbol(out_fd, in_fd, in_offset, adjusted_len);
+ switch (errno(rc)) {
+ .SUCCESS => return @intCast(rc),
+ .BADF => return invalidApiUsage(), // Always a race condition.
+ .FAULT => return invalidApiUsage(), // Segmentation fault.
+ .OVERFLOW => return unexpectedErrno(.OVERFLOW), // We avoid passing too large of a `count`.
+ .NOTCONN => return error.BrokenPipe, // `out_fd` is an unconnected socket
+ .INVAL => return error.UnsupportedOperation,
+ .AGAIN => return error.WouldBlock,
+ .IO => return error.InputOutput,
+ .PIPE => return error.BrokenPipe,
+ .NOMEM => return error.SystemResources,
+ .NXIO => return error.Unseekable,
+ .SPIPE => return error.Unseekable,
+ else => |err| return unexpectedErrno(err),
+ }
+ }
+
+ pub const CopyFileRangeError = std.posix.UnexpectedError || error{
+ /// One of:
+ /// * One or more file descriptors are not valid.
+ /// * fd_in is not open for reading; or fd_out is not open for writing.
+ /// * The O_APPEND flag is set for the open file description referred
+ /// to by the file descriptor fd_out.
+ BadFileFlags,
+ /// One of:
+ /// * An attempt was made to write at a position past the maximum file
+ /// offset the kernel supports.
+ /// * An attempt was made to write a range that exceeds the allowed
+ /// maximum file size. The maximum file size differs between
+ /// filesystem implementations and can be different from the maximum
+ /// allowed file offset.
+ /// * An attempt was made to write beyond the process's file size
+ /// resource limit. This may also result in the process receiving a
+ /// SIGXFSZ signal.
+ FileTooBig,
+ /// One of:
+ /// * either fd_in or fd_out is not a regular file
+ /// * flags argument is not zero
+ /// * fd_in and fd_out refer to the same file and the source and target ranges overlap.
+ InvalidArguments,
+ /// A low-level I/O error occurred while copying.
+ InputOutput,
+ /// Either fd_in or fd_out refers to a directory.
+ IsDir,
+ OutOfMemory,
+ /// There is not enough space on the target filesystem to complete the copy.
+ NoSpaceLeft,
+ /// (since Linux 5.19) the filesystem does not support this operation.
+ OperationNotSupported,
+ /// The requested source or destination range is too large to represent
+ /// in the specified data types.
+ Overflow,
+ /// fd_out refers to an immutable file.
+ PermissionDenied,
+ /// Either fd_in or fd_out refers to an active swap file.
+ SwapFile,
+ /// The files referred to by fd_in and fd_out are not on the same
+ /// filesystem, and the source and target filesystems are not of the
+ /// same type, or do not support cross-filesystem copy.
+ NotSameFileSystem,
+ };
+
+ pub fn copy_file_range(fd_in: fd_t, off_in: ?*i64, fd_out: fd_t, off_out: ?*i64, len: usize, flags: u32) CopyFileRangeError!usize {
+ const rc = system.copy_file_range(fd_in, off_in, fd_out, off_out, len, flags);
+ switch (errno(rc)) {
+ .SUCCESS => return @intCast(rc),
+ .BADF => return error.BadFileFlags,
+ .FBIG => return error.FileTooBig,
+ .INVAL => return error.InvalidArguments,
+ .IO => return error.InputOutput,
+ .ISDIR => return error.IsDir,
+ .NOMEM => return error.OutOfMemory,
+ .NOSPC => return error.NoSpaceLeft,
+ .OPNOTSUPP => return error.OperationNotSupported,
+ .OVERFLOW => return error.Overflow,
+ .PERM => return error.PermissionDenied,
+ .TXTBSY => return error.SwapFile,
+ .XDEV => return error.NotSameFileSystem,
+ else => |err| return unexpectedErrno(err),
+ }
+ }
+
+ const unexpectedErrno = std.posix.unexpectedErrno;
+
+ fn invalidApiUsage() error{Unexpected} {
+ if (builtin.mode == .Debug) @panic("invalid API usage");
+ return error.Unexpected;
+ }
+
+ fn errno(rc: anytype) E {
+ if (builtin.link_libc) {
+ return if (rc == -1) @enumFromInt(std.c._errno().*) else .SUCCESS;
+ } else {
+ return errnoFromSyscall(rc);
+ }
+ }
+};