mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
std: fix some surface level compilation errors
And boldly remove preadv, pwritev, readv, writev, pread, pwrite from std.posix.
This commit is contained in:
parent
fc8b792251
commit
470e2d6796
8 changed files with 64 additions and 407 deletions
|
|
@ -705,8 +705,8 @@ pub const VTable = struct {
|
||||||
fileSetLength: *const fn (?*anyopaque, File, u64) File.SetLengthError!void,
|
fileSetLength: *const fn (?*anyopaque, File, u64) File.SetLengthError!void,
|
||||||
fileSetOwner: *const fn (?*anyopaque, File, ?File.Uid, ?File.Gid) File.SetOwnerError!void,
|
fileSetOwner: *const fn (?*anyopaque, File, ?File.Uid, ?File.Gid) File.SetOwnerError!void,
|
||||||
fileSetPermissions: *const fn (?*anyopaque, File, File.Permissions) File.SetPermissionsError!void,
|
fileSetPermissions: *const fn (?*anyopaque, File, File.Permissions) File.SetPermissionsError!void,
|
||||||
fileSetTimestamps: *const fn (?*anyopaque, File, last_accessed: Timestamp, last_modified: Timestamp, File.SetTimestampsOptions) File.SetTimestampsError!void,
|
fileSetTimestamps: *const fn (?*anyopaque, File, last_accessed: Timestamp, last_modified: Timestamp) File.SetTimestampsError!void,
|
||||||
fileSetTimestampsNow: *const fn (?*anyopaque, File, File.SetTimestampsOptions) File.SetTimestampsError!void,
|
fileSetTimestampsNow: *const fn (?*anyopaque, File) File.SetTimestampsError!void,
|
||||||
fileLock: *const fn (?*anyopaque, File, File.Lock) File.LockError!void,
|
fileLock: *const fn (?*anyopaque, File, File.Lock) File.LockError!void,
|
||||||
fileTryLock: *const fn (?*anyopaque, File, File.Lock) File.LockError!bool,
|
fileTryLock: *const fn (?*anyopaque, File, File.Lock) File.LockError!bool,
|
||||||
fileUnlock: *const fn (?*anyopaque, File) void,
|
fileUnlock: *const fn (?*anyopaque, File) void,
|
||||||
|
|
@ -726,7 +726,7 @@ pub const VTable = struct {
|
||||||
/// Returns 0 on end of stream.
|
/// Returns 0 on end of stream.
|
||||||
netRead: *const fn (?*anyopaque, src: net.Socket.Handle, data: [][]u8) net.Stream.Reader.Error!usize,
|
netRead: *const fn (?*anyopaque, src: net.Socket.Handle, data: [][]u8) net.Stream.Reader.Error!usize,
|
||||||
netWrite: *const fn (?*anyopaque, dest: net.Socket.Handle, header: []const u8, data: []const []const u8, splat: usize) net.Stream.Writer.Error!usize,
|
netWrite: *const fn (?*anyopaque, dest: net.Socket.Handle, header: []const u8, data: []const []const u8, splat: usize) net.Stream.Writer.Error!usize,
|
||||||
netWriteFile: *const fn (?*anyopaque, net.Socket.Handle, header: []const u8, *Io.File.Reader, Io.Limit) net.Stream.WriteFileError!usize,
|
netWriteFile: *const fn (?*anyopaque, net.Socket.Handle, header: []const u8, *Io.File.Reader, Io.Limit) net.Stream.Writer.WriteFileError!usize,
|
||||||
netClose: *const fn (?*anyopaque, handle: net.Socket.Handle) void,
|
netClose: *const fn (?*anyopaque, handle: net.Socket.Handle) void,
|
||||||
netInterfaceNameResolve: *const fn (?*anyopaque, *const net.Interface.Name) net.Interface.Name.ResolveError!net.Interface,
|
netInterfaceNameResolve: *const fn (?*anyopaque, *const net.Interface.Name) net.Interface.Name.ResolveError!net.Interface,
|
||||||
netInterfaceName: *const fn (?*anyopaque, net.Interface) net.Interface.NameError!net.Interface.Name,
|
netInterfaceName: *const fn (?*anyopaque, net.Interface) net.Interface.NameError!net.Interface.Name,
|
||||||
|
|
|
||||||
|
|
@ -274,7 +274,7 @@ pub fn sync(file: File, io: Io) SyncError!void {
|
||||||
/// Test whether the file refers to a terminal.
|
/// Test whether the file refers to a terminal.
|
||||||
///
|
///
|
||||||
/// See also:
|
/// See also:
|
||||||
/// * `getOrEnableAnsiEscapeSupport`
|
/// * `enableAnsiEscapeCodes`
|
||||||
/// * `supportsAnsiEscapeCodes`.
|
/// * `supportsAnsiEscapeCodes`.
|
||||||
pub fn isTty(file: File, io: Io) bool {
|
pub fn isTty(file: File, io: Io) bool {
|
||||||
return io.vtable.fileIsTty(io.userdata, file);
|
return io.vtable.fileIsTty(io.userdata, file);
|
||||||
|
|
@ -282,7 +282,7 @@ pub fn isTty(file: File, io: Io) bool {
|
||||||
|
|
||||||
pub const EnableAnsiEscapeCodesError = error{} || Io.Cancelable || Io.UnexpectedError;
|
pub const EnableAnsiEscapeCodesError = error{} || Io.Cancelable || Io.UnexpectedError;
|
||||||
|
|
||||||
pub fn enableAnsiEscapeCodes(file: File, io: Io) EnableAnsiEscapeCodesError {
|
pub fn enableAnsiEscapeCodes(file: File, io: Io) EnableAnsiEscapeCodesError!void {
|
||||||
return io.vtable.fileEnableAnsiEscapeCodes(io.userdata, file);
|
return io.vtable.fileEnableAnsiEscapeCodes(io.userdata, file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ const assert = std.debug.assert;
|
||||||
|
|
||||||
io: Io,
|
io: Io,
|
||||||
file: File,
|
file: File,
|
||||||
err: ?File.WriteError = null,
|
err: ?Error = null,
|
||||||
mode: Mode = .positional,
|
mode: Mode = .positional,
|
||||||
/// Tracks the true seek position in the file. To obtain the logical
|
/// Tracks the true seek position in the file. To obtain the logical
|
||||||
/// position, add the buffer size to this value.
|
/// position, add the buffer size to this value.
|
||||||
|
|
@ -18,6 +18,29 @@ interface: Io.Writer,
|
||||||
|
|
||||||
pub const Mode = File.Reader.Mode;
|
pub const Mode = File.Reader.Mode;
|
||||||
|
|
||||||
|
pub const Error = error{
|
||||||
|
DiskQuota,
|
||||||
|
FileTooBig,
|
||||||
|
InputOutput,
|
||||||
|
NoSpaceLeft,
|
||||||
|
DeviceBusy,
|
||||||
|
InvalidArgument,
|
||||||
|
/// File descriptor does not hold the required rights to write to it.
|
||||||
|
AccessDenied,
|
||||||
|
PermissionDenied,
|
||||||
|
BrokenPipe,
|
||||||
|
SystemResources,
|
||||||
|
NotOpenForWriting,
|
||||||
|
/// The process cannot access the file because another process has locked
|
||||||
|
/// a portion of the file. Windows-only.
|
||||||
|
LockViolation,
|
||||||
|
/// Non-blocking has been enabled and this operation would block.
|
||||||
|
WouldBlock,
|
||||||
|
/// This error occurs when a device gets disconnected before or mid-flush
|
||||||
|
/// while it's being written to - errno(6): No such device or address.
|
||||||
|
NoDevice,
|
||||||
|
} || Io.Cancelable || Io.UnexpectedError;
|
||||||
|
|
||||||
pub const WriteFileError = error{
|
pub const WriteFileError = error{
|
||||||
/// `out_fd` is an unconnected socket, or out_fd closed its read end.
|
/// `out_fd` is an unconnected socket, or out_fd closed its read end.
|
||||||
BrokenPipe,
|
BrokenPipe,
|
||||||
|
|
|
||||||
|
|
@ -6400,6 +6400,22 @@ fn fileWriteFileStreaming(
|
||||||
return error.Unimplemented;
|
return error.Unimplemented;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn netWriteFile(
|
||||||
|
userdata: ?*anyopaque,
|
||||||
|
socket_handle: net.Socket.Handle,
|
||||||
|
header: []const u8,
|
||||||
|
file_reader: *Io.File.Reader,
|
||||||
|
limit: Io.Limit,
|
||||||
|
) net.Stream.WriteFileError!usize {
|
||||||
|
const t: *Threaded = @ptrCast(@alignCast(userdata));
|
||||||
|
_ = t;
|
||||||
|
_ = socket_handle;
|
||||||
|
_ = header;
|
||||||
|
_ = file_reader;
|
||||||
|
_ = limit;
|
||||||
|
return error.Unimplemented; // TODO
|
||||||
|
}
|
||||||
|
|
||||||
fn fileWriteFilePositional(
|
fn fileWriteFilePositional(
|
||||||
userdata: ?*anyopaque,
|
userdata: ?*anyopaque,
|
||||||
file: Io.File,
|
file: Io.File,
|
||||||
|
|
|
||||||
|
|
@ -1256,6 +1256,7 @@ pub const Stream = struct {
|
||||||
interface: Io.Writer,
|
interface: Io.Writer,
|
||||||
stream: Stream,
|
stream: Stream,
|
||||||
err: ?Error = null,
|
err: ?Error = null,
|
||||||
|
write_file_err: ?WriteFileError = null,
|
||||||
|
|
||||||
pub const Error = error{
|
pub const Error = error{
|
||||||
/// Another TCP Fast Open is already in progress.
|
/// Another TCP Fast Open is already in progress.
|
||||||
|
|
@ -1285,12 +1286,17 @@ pub const Stream = struct {
|
||||||
SocketNotBound,
|
SocketNotBound,
|
||||||
} || Io.UnexpectedError || Io.Cancelable;
|
} || Io.UnexpectedError || Io.Cancelable;
|
||||||
|
|
||||||
|
pub const WriteFileError = error{} || Io.Cancelable || Io.UnexpectedError;
|
||||||
|
|
||||||
pub fn init(stream: Stream, io: Io, buffer: []u8) Writer {
|
pub fn init(stream: Stream, io: Io, buffer: []u8) Writer {
|
||||||
return .{
|
return .{
|
||||||
.io = io,
|
.io = io,
|
||||||
.stream = stream,
|
.stream = stream,
|
||||||
.interface = .{
|
.interface = .{
|
||||||
.vtable = &.{ .drain = drain },
|
.vtable = &.{
|
||||||
|
.drain = drain,
|
||||||
|
.sendFile = sendFile,
|
||||||
|
},
|
||||||
.buffer = buffer,
|
.buffer = buffer,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
@ -1307,6 +1313,13 @@ pub const Stream = struct {
|
||||||
};
|
};
|
||||||
return io_w.consume(n);
|
return io_w.consume(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn sendFile(io_w: *Io.Writer, file_reader: *Io.File.Reader, limit: Io.Limit) Io.Writer.FileError!usize {
|
||||||
|
_ = io_w;
|
||||||
|
_ = file_reader;
|
||||||
|
_ = limit;
|
||||||
|
return error.Unimplemented; // TODO
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn reader(stream: Stream, io: Io, buffer: []u8) Reader {
|
pub fn reader(stream: Stream, io: Io, buffer: []u8) Reader {
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,9 @@ pub const Config = union(enum) {
|
||||||
|
|
||||||
if (force_color == false) return .no_color;
|
if (force_color == false) return .no_color;
|
||||||
|
|
||||||
if (file.getOrEnableAnsiEscapeSupport()) return .escape_codes;
|
if (file.enableAnsiEscapeCodes()) |_| {
|
||||||
|
return .escape_codes;
|
||||||
|
} else |_| {}
|
||||||
|
|
||||||
if (native_os == .windows and file.isTty()) {
|
if (native_os == .windows and file.isTty()) {
|
||||||
var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;
|
var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;
|
||||||
|
|
|
||||||
|
|
@ -474,9 +474,9 @@ pub fn start(options: Options) Node {
|
||||||
}
|
}
|
||||||
const stderr: std.fs.File = .stderr();
|
const stderr: std.fs.File = .stderr();
|
||||||
global_progress.terminal = stderr;
|
global_progress.terminal = stderr;
|
||||||
if (stderr.getOrEnableAnsiEscapeSupport()) {
|
if (stderr.enableAnsiEscapeCodes()) |_| {
|
||||||
global_progress.terminal_mode = .ansi_escape_codes;
|
global_progress.terminal_mode = .ansi_escape_codes;
|
||||||
} else if (is_windows and stderr.isTty()) {
|
} else |_| if (is_windows and stderr.isTty()) {
|
||||||
global_progress.terminal_mode = TerminalMode{ .windows_api = .{
|
global_progress.terminal_mode = TerminalMode{ .windows_api = .{
|
||||||
.code_page = windows.kernel32.GetConsoleOutputCP(),
|
.code_page = windows.kernel32.GetConsoleOutputCP(),
|
||||||
} };
|
} };
|
||||||
|
|
|
||||||
|
|
@ -796,226 +796,6 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Number of bytes read is returned. Upon reading end-of-file, zero is returned.
|
|
||||||
///
|
|
||||||
/// For POSIX systems, if `fd` is opened in non blocking mode, the function will
|
|
||||||
/// return error.WouldBlock when EAGAIN is received.
|
|
||||||
/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are
|
|
||||||
/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.
|
|
||||||
///
|
|
||||||
/// This operation is non-atomic on the following systems:
|
|
||||||
/// * Windows
|
|
||||||
/// On these systems, the read races with concurrent writes to the same file descriptor.
|
|
||||||
///
|
|
||||||
/// This function assumes that all vectors, including zero-length vectors, have
|
|
||||||
/// a pointer within the address space of the application.
|
|
||||||
pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize {
|
|
||||||
if (native_os == .windows) {
|
|
||||||
if (iov.len == 0) return 0;
|
|
||||||
const first = iov[0];
|
|
||||||
return read(fd, first.base[0..first.len]);
|
|
||||||
}
|
|
||||||
if (native_os == .wasi and !builtin.link_libc) {
|
|
||||||
var nread: usize = undefined;
|
|
||||||
switch (wasi.fd_read(fd, iov.ptr, iov.len, &nread)) {
|
|
||||||
.SUCCESS => return nread,
|
|
||||||
.INTR => unreachable,
|
|
||||||
.INVAL => unreachable,
|
|
||||||
.FAULT => unreachable,
|
|
||||||
.AGAIN => unreachable, // currently not support in WASI
|
|
||||||
.BADF => return error.NotOpenForReading, // can be a race condition
|
|
||||||
.IO => return error.InputOutput,
|
|
||||||
.ISDIR => return error.IsDir,
|
|
||||||
.NOBUFS => return error.SystemResources,
|
|
||||||
.NOMEM => return error.SystemResources,
|
|
||||||
.NOTCONN => return error.SocketUnconnected,
|
|
||||||
.CONNRESET => return error.ConnectionResetByPeer,
|
|
||||||
.TIMEDOUT => return error.Timeout,
|
|
||||||
.NOTCAPABLE => return error.AccessDenied,
|
|
||||||
else => |err| return unexpectedErrno(err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
const rc = system.readv(fd, iov.ptr, @min(iov.len, IOV_MAX));
|
|
||||||
switch (errno(rc)) {
|
|
||||||
.SUCCESS => return @intCast(rc),
|
|
||||||
.INTR => continue,
|
|
||||||
.INVAL => unreachable,
|
|
||||||
.FAULT => unreachable,
|
|
||||||
.SRCH => return error.ProcessNotFound,
|
|
||||||
.AGAIN => return error.WouldBlock,
|
|
||||||
.BADF => return error.NotOpenForReading, // can be a race condition
|
|
||||||
.IO => return error.InputOutput,
|
|
||||||
.ISDIR => return error.IsDir,
|
|
||||||
.NOBUFS => return error.SystemResources,
|
|
||||||
.NOMEM => return error.SystemResources,
|
|
||||||
.NOTCONN => return error.SocketUnconnected,
|
|
||||||
.CONNRESET => return error.ConnectionResetByPeer,
|
|
||||||
.TIMEDOUT => return error.Timeout,
|
|
||||||
else => |err| return unexpectedErrno(err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const PReadError = std.Io.File.ReadPositionalError;
|
|
||||||
|
|
||||||
/// Number of bytes read is returned. Upon reading end-of-file, zero is returned.
|
|
||||||
///
|
|
||||||
/// Retries when interrupted by a signal.
|
|
||||||
///
|
|
||||||
/// For POSIX systems, if `fd` is opened in non blocking mode, the function will
|
|
||||||
/// return error.WouldBlock when EAGAIN is received.
|
|
||||||
/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are
|
|
||||||
/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.
|
|
||||||
///
|
|
||||||
/// Linux has a limit on how many bytes may be transferred in one `pread` call, which is `0x7ffff000`
|
|
||||||
/// on both 64-bit and 32-bit systems. This is due to using a signed C int as the return value, as
|
|
||||||
/// well as stuffing the errno codes into the last `4096` values. This is noted on the `read` man page.
|
|
||||||
/// The limit on Darwin is `0x7fffffff`, trying to read more than that returns EINVAL.
|
|
||||||
/// The corresponding POSIX limit is `maxInt(isize)`.
|
|
||||||
pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize {
|
|
||||||
if (buf.len == 0) return 0;
|
|
||||||
if (native_os == .windows) {
|
|
||||||
return windows.ReadFile(fd, buf, offset);
|
|
||||||
}
|
|
||||||
if (native_os == .wasi and !builtin.link_libc) {
|
|
||||||
const iovs = [1]iovec{iovec{
|
|
||||||
.base = buf.ptr,
|
|
||||||
.len = buf.len,
|
|
||||||
}};
|
|
||||||
|
|
||||||
var nread: usize = undefined;
|
|
||||||
switch (wasi.fd_pread(fd, &iovs, iovs.len, offset, &nread)) {
|
|
||||||
.SUCCESS => return nread,
|
|
||||||
.INTR => unreachable,
|
|
||||||
.INVAL => unreachable,
|
|
||||||
.FAULT => unreachable,
|
|
||||||
.AGAIN => unreachable,
|
|
||||||
.BADF => return error.NotOpenForReading, // Can be a race condition.
|
|
||||||
.IO => return error.InputOutput,
|
|
||||||
.ISDIR => return error.IsDir,
|
|
||||||
.NOBUFS => return error.SystemResources,
|
|
||||||
.NOMEM => return error.SystemResources,
|
|
||||||
.NOTCONN => return error.SocketUnconnected,
|
|
||||||
.CONNRESET => return error.ConnectionResetByPeer,
|
|
||||||
.TIMEDOUT => return error.Timeout,
|
|
||||||
.NXIO => return error.Unseekable,
|
|
||||||
.SPIPE => return error.Unseekable,
|
|
||||||
.OVERFLOW => return error.Unseekable,
|
|
||||||
.NOTCAPABLE => return error.AccessDenied,
|
|
||||||
else => |err| return unexpectedErrno(err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prevent EINVAL.
|
|
||||||
const max_count = switch (native_os) {
|
|
||||||
.linux => 0x7ffff000,
|
|
||||||
.driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos => maxInt(i32),
|
|
||||||
else => maxInt(isize),
|
|
||||||
};
|
|
||||||
|
|
||||||
const pread_sym = if (lfs64_abi) system.pread64 else system.pread;
|
|
||||||
while (true) {
|
|
||||||
const rc = pread_sym(fd, buf.ptr, @min(buf.len, max_count), @bitCast(offset));
|
|
||||||
switch (errno(rc)) {
|
|
||||||
.SUCCESS => return @intCast(rc),
|
|
||||||
.INTR => continue,
|
|
||||||
.INVAL => unreachable,
|
|
||||||
.FAULT => unreachable,
|
|
||||||
.SRCH => return error.ProcessNotFound,
|
|
||||||
.AGAIN => return error.WouldBlock,
|
|
||||||
.BADF => return error.NotOpenForReading, // Can be a race condition.
|
|
||||||
.IO => return error.InputOutput,
|
|
||||||
.ISDIR => return error.IsDir,
|
|
||||||
.NOBUFS => return error.SystemResources,
|
|
||||||
.NOMEM => return error.SystemResources,
|
|
||||||
.NOTCONN => return error.SocketUnconnected,
|
|
||||||
.CONNRESET => return error.ConnectionResetByPeer,
|
|
||||||
.TIMEDOUT => return error.Timeout,
|
|
||||||
.NXIO => return error.Unseekable,
|
|
||||||
.SPIPE => return error.Unseekable,
|
|
||||||
.OVERFLOW => return error.Unseekable,
|
|
||||||
else => |err| return unexpectedErrno(err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Number of bytes read is returned. Upon reading end-of-file, zero is returned.
|
|
||||||
///
|
|
||||||
/// Retries when interrupted by a signal.
|
|
||||||
///
|
|
||||||
/// For POSIX systems, if `fd` is opened in non blocking mode, the function will
|
|
||||||
/// return error.WouldBlock when EAGAIN is received.
|
|
||||||
/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are
|
|
||||||
/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.
|
|
||||||
///
|
|
||||||
/// This operation is non-atomic on the following systems:
|
|
||||||
/// * Darwin
|
|
||||||
/// * Windows
|
|
||||||
/// On these systems, the read races with concurrent writes to the same file descriptor.
|
|
||||||
pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) PReadError!usize {
|
|
||||||
const have_pread_but_not_preadv = switch (native_os) {
|
|
||||||
.windows, .driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos, .haiku => true,
|
|
||||||
else => false,
|
|
||||||
};
|
|
||||||
if (have_pread_but_not_preadv) {
|
|
||||||
// We could loop here; but proper usage of `preadv` must handle partial reads anyway.
|
|
||||||
// So we simply read into the first vector only.
|
|
||||||
if (iov.len == 0) return 0;
|
|
||||||
const first = iov[0];
|
|
||||||
return pread(fd, first.base[0..first.len], offset);
|
|
||||||
}
|
|
||||||
if (native_os == .wasi and !builtin.link_libc) {
|
|
||||||
var nread: usize = undefined;
|
|
||||||
switch (wasi.fd_pread(fd, iov.ptr, iov.len, offset, &nread)) {
|
|
||||||
.SUCCESS => return nread,
|
|
||||||
.INTR => unreachable,
|
|
||||||
.INVAL => unreachable,
|
|
||||||
.FAULT => unreachable,
|
|
||||||
.AGAIN => unreachable,
|
|
||||||
.BADF => return error.NotOpenForReading, // can be a race condition
|
|
||||||
.IO => return error.InputOutput,
|
|
||||||
.ISDIR => return error.IsDir,
|
|
||||||
.NOBUFS => return error.SystemResources,
|
|
||||||
.NOMEM => return error.SystemResources,
|
|
||||||
.NOTCONN => return error.SocketUnconnected,
|
|
||||||
.CONNRESET => return error.ConnectionResetByPeer,
|
|
||||||
.TIMEDOUT => return error.Timeout,
|
|
||||||
.NXIO => return error.Unseekable,
|
|
||||||
.SPIPE => return error.Unseekable,
|
|
||||||
.OVERFLOW => return error.Unseekable,
|
|
||||||
.NOTCAPABLE => return error.AccessDenied,
|
|
||||||
else => |err| return unexpectedErrno(err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const preadv_sym = if (lfs64_abi) system.preadv64 else system.preadv;
|
|
||||||
while (true) {
|
|
||||||
const rc = preadv_sym(fd, iov.ptr, @min(iov.len, IOV_MAX), @bitCast(offset));
|
|
||||||
switch (errno(rc)) {
|
|
||||||
.SUCCESS => return @bitCast(rc),
|
|
||||||
.INTR => continue,
|
|
||||||
.INVAL => unreachable,
|
|
||||||
.FAULT => unreachable,
|
|
||||||
.SRCH => return error.ProcessNotFound,
|
|
||||||
.AGAIN => return error.WouldBlock,
|
|
||||||
.BADF => return error.NotOpenForReading, // can be a race condition
|
|
||||||
.IO => return error.InputOutput,
|
|
||||||
.ISDIR => return error.IsDir,
|
|
||||||
.NOBUFS => return error.SystemResources,
|
|
||||||
.NOMEM => return error.SystemResources,
|
|
||||||
.NOTCONN => return error.SocketUnconnected,
|
|
||||||
.CONNRESET => return error.ConnectionResetByPeer,
|
|
||||||
.TIMEDOUT => return error.Timeout,
|
|
||||||
.NXIO => return error.Unseekable,
|
|
||||||
.SPIPE => return error.Unseekable,
|
|
||||||
.OVERFLOW => return error.Unseekable,
|
|
||||||
else => |err| return unexpectedErrno(err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const WriteError = error{
|
pub const WriteError = error{
|
||||||
DiskQuota,
|
DiskQuota,
|
||||||
FileTooBig,
|
FileTooBig,
|
||||||
|
|
@ -1140,183 +920,6 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const PWriteError = WriteError || error{Unseekable};
|
|
||||||
|
|
||||||
/// Write to a file descriptor, with a position offset.
|
|
||||||
/// Retries when interrupted by a signal.
|
|
||||||
/// Returns the number of bytes written. If nonzero bytes were supplied, this will be nonzero.
|
|
||||||
///
|
|
||||||
/// Note that a successful write() may transfer fewer bytes than supplied. Such partial writes can
|
|
||||||
/// occur for various reasons; for example, because there was insufficient space on the disk
|
|
||||||
/// device to write all of the requested bytes, or because a blocked write() to a socket, pipe, or
|
|
||||||
/// similar was interrupted by a signal handler after it had transferred some, but before it had
|
|
||||||
/// transferred all of the requested bytes. In the event of a partial write, the caller can make
|
|
||||||
/// another write() call to transfer the remaining bytes. The subsequent call will either
|
|
||||||
/// transfer further bytes or may result in an error (e.g., if the disk is now full).
|
|
||||||
///
|
|
||||||
/// For POSIX systems, if `fd` is opened in non blocking mode, the function will
|
|
||||||
/// return error.WouldBlock when EAGAIN is received.
|
|
||||||
/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are
|
|
||||||
/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.
|
|
||||||
///
|
|
||||||
/// Linux has a limit on how many bytes may be transferred in one `pwrite` call, which is `0x7ffff000`
|
|
||||||
/// on both 64-bit and 32-bit systems. This is due to using a signed C int as the return value, as
|
|
||||||
/// well as stuffing the errno codes into the last `4096` values. This is noted on the `write` man page.
|
|
||||||
/// The limit on Darwin is `0x7fffffff`, trying to write more than that returns EINVAL.
|
|
||||||
/// The corresponding POSIX limit is `maxInt(isize)`.
|
|
||||||
pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize {
|
|
||||||
if (bytes.len == 0) return 0;
|
|
||||||
if (native_os == .windows) {
|
|
||||||
return windows.WriteFile(fd, bytes, offset);
|
|
||||||
}
|
|
||||||
if (native_os == .wasi and !builtin.link_libc) {
|
|
||||||
const ciovs = [1]iovec_const{iovec_const{
|
|
||||||
.base = bytes.ptr,
|
|
||||||
.len = bytes.len,
|
|
||||||
}};
|
|
||||||
|
|
||||||
var nwritten: usize = undefined;
|
|
||||||
switch (wasi.fd_pwrite(fd, &ciovs, ciovs.len, offset, &nwritten)) {
|
|
||||||
.SUCCESS => return nwritten,
|
|
||||||
.INTR => unreachable,
|
|
||||||
.INVAL => unreachable,
|
|
||||||
.FAULT => unreachable,
|
|
||||||
.AGAIN => unreachable,
|
|
||||||
.BADF => return error.NotOpenForWriting, // can be a race condition.
|
|
||||||
.DESTADDRREQ => unreachable, // `connect` was never called.
|
|
||||||
.DQUOT => return error.DiskQuota,
|
|
||||||
.FBIG => return error.FileTooBig,
|
|
||||||
.IO => return error.InputOutput,
|
|
||||||
.NOSPC => return error.NoSpaceLeft,
|
|
||||||
.PERM => return error.PermissionDenied,
|
|
||||||
.PIPE => return error.BrokenPipe,
|
|
||||||
.NXIO => return error.Unseekable,
|
|
||||||
.SPIPE => return error.Unseekable,
|
|
||||||
.OVERFLOW => return error.Unseekable,
|
|
||||||
.NOTCAPABLE => return error.AccessDenied,
|
|
||||||
else => |err| return unexpectedErrno(err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prevent EINVAL.
|
|
||||||
const max_count = switch (native_os) {
|
|
||||||
.linux => 0x7ffff000,
|
|
||||||
.driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos => maxInt(i32),
|
|
||||||
else => maxInt(isize),
|
|
||||||
};
|
|
||||||
|
|
||||||
const pwrite_sym = if (lfs64_abi) system.pwrite64 else system.pwrite;
|
|
||||||
while (true) {
|
|
||||||
const rc = pwrite_sym(fd, bytes.ptr, @min(bytes.len, max_count), @bitCast(offset));
|
|
||||||
switch (errno(rc)) {
|
|
||||||
.SUCCESS => return @intCast(rc),
|
|
||||||
.INTR => continue,
|
|
||||||
.INVAL => return error.InvalidArgument,
|
|
||||||
.FAULT => unreachable,
|
|
||||||
.SRCH => return error.ProcessNotFound,
|
|
||||||
.AGAIN => return error.WouldBlock,
|
|
||||||
.BADF => return error.NotOpenForWriting, // Can be a race condition.
|
|
||||||
.DESTADDRREQ => unreachable, // `connect` was never called.
|
|
||||||
.DQUOT => return error.DiskQuota,
|
|
||||||
.FBIG => return error.FileTooBig,
|
|
||||||
.IO => return error.InputOutput,
|
|
||||||
.NOSPC => return error.NoSpaceLeft,
|
|
||||||
.PERM => return error.PermissionDenied,
|
|
||||||
.PIPE => return error.BrokenPipe,
|
|
||||||
.NXIO => return error.Unseekable,
|
|
||||||
.SPIPE => return error.Unseekable,
|
|
||||||
.OVERFLOW => return error.Unseekable,
|
|
||||||
.BUSY => return error.DeviceBusy,
|
|
||||||
else => |err| return unexpectedErrno(err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Write multiple buffers to a file descriptor, with a position offset.
|
|
||||||
/// Retries when interrupted by a signal.
|
|
||||||
/// Returns the number of bytes written. If nonzero bytes were supplied, this will be nonzero.
|
|
||||||
///
|
|
||||||
/// Note that a successful write() may transfer fewer than count bytes. Such partial writes can
|
|
||||||
/// occur for various reasons; for example, because there was insufficient space on the disk
|
|
||||||
/// device to write all of the requested bytes, or because a blocked write() to a socket, pipe, or
|
|
||||||
/// similar was interrupted by a signal handler after it had transferred some, but before it had
|
|
||||||
/// transferred all of the requested bytes. In the event of a partial write, the caller can make
|
|
||||||
/// another write() call to transfer the remaining bytes. The subsequent call will either
|
|
||||||
/// transfer further bytes or may result in an error (e.g., if the disk is now full).
|
|
||||||
///
|
|
||||||
/// If `fd` is opened in non blocking mode, the function will
|
|
||||||
/// return error.WouldBlock when EAGAIN is received.
|
|
||||||
///
|
|
||||||
/// The following systems do not have this syscall, and will return partial writes if more than one
|
|
||||||
/// vector is provided:
|
|
||||||
/// * Darwin
|
|
||||||
/// * Windows
|
|
||||||
///
|
|
||||||
/// If `iov.len` is larger than `IOV_MAX`, a partial write will occur.
|
|
||||||
pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) PWriteError!usize {
|
|
||||||
const have_pwrite_but_not_pwritev = switch (native_os) {
|
|
||||||
.windows, .driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos, .haiku => true,
|
|
||||||
else => false,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (have_pwrite_but_not_pwritev) {
|
|
||||||
// We could loop here; but proper usage of `pwritev` must handle partial writes anyway.
|
|
||||||
// So we simply write the first vector only.
|
|
||||||
if (iov.len == 0) return 0;
|
|
||||||
const first = iov[0];
|
|
||||||
return pwrite(fd, first.base[0..first.len], offset);
|
|
||||||
}
|
|
||||||
if (native_os == .wasi and !builtin.link_libc) {
|
|
||||||
var nwritten: usize = undefined;
|
|
||||||
switch (wasi.fd_pwrite(fd, iov.ptr, iov.len, offset, &nwritten)) {
|
|
||||||
.SUCCESS => return nwritten,
|
|
||||||
.INTR => unreachable,
|
|
||||||
.INVAL => unreachable,
|
|
||||||
.FAULT => unreachable,
|
|
||||||
.AGAIN => unreachable,
|
|
||||||
.BADF => return error.NotOpenForWriting, // Can be a race condition.
|
|
||||||
.DESTADDRREQ => unreachable, // `connect` was never called.
|
|
||||||
.DQUOT => return error.DiskQuota,
|
|
||||||
.FBIG => return error.FileTooBig,
|
|
||||||
.IO => return error.InputOutput,
|
|
||||||
.NOSPC => return error.NoSpaceLeft,
|
|
||||||
.PERM => return error.PermissionDenied,
|
|
||||||
.PIPE => return error.BrokenPipe,
|
|
||||||
.NXIO => return error.Unseekable,
|
|
||||||
.SPIPE => return error.Unseekable,
|
|
||||||
.OVERFLOW => return error.Unseekable,
|
|
||||||
.NOTCAPABLE => return error.AccessDenied,
|
|
||||||
else => |err| return unexpectedErrno(err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const pwritev_sym = if (lfs64_abi) system.pwritev64 else system.pwritev;
|
|
||||||
while (true) {
|
|
||||||
const rc = pwritev_sym(fd, iov.ptr, @min(iov.len, IOV_MAX), @bitCast(offset));
|
|
||||||
switch (errno(rc)) {
|
|
||||||
.SUCCESS => return @intCast(rc),
|
|
||||||
.INTR => continue,
|
|
||||||
.INVAL => return error.InvalidArgument,
|
|
||||||
.FAULT => unreachable,
|
|
||||||
.SRCH => return error.ProcessNotFound,
|
|
||||||
.AGAIN => return error.WouldBlock,
|
|
||||||
.BADF => return error.NotOpenForWriting, // Can be a race condition.
|
|
||||||
.DESTADDRREQ => unreachable, // `connect` was never called.
|
|
||||||
.DQUOT => return error.DiskQuota,
|
|
||||||
.FBIG => return error.FileTooBig,
|
|
||||||
.IO => return error.InputOutput,
|
|
||||||
.NOSPC => return error.NoSpaceLeft,
|
|
||||||
.PERM => return error.PermissionDenied,
|
|
||||||
.PIPE => return error.BrokenPipe,
|
|
||||||
.NXIO => return error.Unseekable,
|
|
||||||
.SPIPE => return error.Unseekable,
|
|
||||||
.OVERFLOW => return error.Unseekable,
|
|
||||||
.BUSY => return error.DeviceBusy,
|
|
||||||
else => |err| return unexpectedErrno(err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const OpenError = std.Io.File.OpenError || error{WouldBlock};
|
pub const OpenError = std.Io.File.OpenError || error{WouldBlock};
|
||||||
|
|
||||||
/// Open and possibly create a file. Keeps trying if it gets interrupted.
|
/// Open and possibly create a file. Keeps trying if it gets interrupted.
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue