| ... | ... | @@ -1829,276 +1829,277 @@ pub const Stream = struct { |
| 1829 | 1829 | } |
| 1830 | 1830 | } |
| 1831 | 1831 | |
| 1832 | | pub const Reader = struct { |
| 1833 | | impl: switch (native_os) { |
| 1834 | | .windows => Stream, |
| 1835 | | else => struct { |
| 1836 | | fr: std.fs.File.Reader, |
| 1837 | | err: Error!void, |
| 1838 | | }, |
| 1839 | | }, |
| 1832 | const ReadError = posix.ReadError; |
| 1833 | |
| 1834 | const WriteError = posix.SendMsgError || error{ |
| 1835 | ConnectionResetByPeer, |
| 1836 | SocketNotBound, |
| 1837 | MessageTooBig, |
| 1838 | NetworkSubsystemFailed, |
| 1839 | SystemResources, |
| 1840 | SocketNotConnected, |
| 1841 | Unexpected, |
| 1842 | }; |
| 1840 | 1843 | |
| 1841 | | pub const Error = posix.ReadError; |
| 1844 | pub const Reader = switch (native_os) { |
| 1845 | .windows => struct { |
| 1846 | stream: Stream, |
| 1847 | err: ?Error = null, |
| 1842 | 1848 | |
| 1843 | | pub fn interface(r: *Reader) std.io.Reader { |
| 1844 | | return switch (native_os) { |
| 1845 | | .windows => .{ |
| 1846 | | .context = r.impl.stream.handle, |
| 1849 | pub const Error = ReadError; |
| 1850 | |
| 1851 | pub fn interface(r: *Reader) std.io.Reader { |
| 1852 | return .{ |
| 1853 | .context = r.stream.handle, |
| 1847 | 1854 | .vtable = &.{ |
| 1848 | | .read = windows_read, |
| 1849 | | .readVec = windows_readVec, |
| 1850 | | .discard = windows_discard, |
| 1855 | .read = read, |
| 1856 | .readVec = readVec, |
| 1857 | .discard = discard, |
| 1851 | 1858 | }, |
| 1852 | | }, |
| 1853 | | else => r.interface(), |
| 1854 | | }; |
| 1855 | | } |
| 1859 | }; |
| 1860 | } |
| 1856 | 1861 | |
| 1857 | | fn windows_read( |
| 1858 | | context: ?*anyopaque, |
| 1859 | | bw: *std.io.BufferedWriter, |
| 1860 | | limit: std.io.Reader.Limit, |
| 1861 | | ) std.io.Reader.Error!usize { |
| 1862 | | const buf = limit.slice(try bw.writableSliceGreedy(1)); |
| 1863 | | const status = try windows_readVec(context, &.{buf}); |
| 1864 | | bw.advance(status.len); |
| 1865 | | return status; |
| 1866 | | } |
| 1862 | fn read( |
| 1863 | context: ?*anyopaque, |
| 1864 | bw: *std.io.BufferedWriter, |
| 1865 | limit: std.io.Reader.Limit, |
| 1866 | ) std.io.Reader.Error!usize { |
| 1867 | const buf = limit.slice(try bw.writableSliceGreedy(1)); |
| 1868 | const status = try readVec(context, &.{buf}); |
| 1869 | bw.advance(status.len); |
| 1870 | return status; |
| 1871 | } |
| 1867 | 1872 | |
| 1868 | | fn windows_readVec(context: ?*anyopaque, data: []const []u8) std.io.Reader.Error!usize { |
| 1869 | | var iovecs: [max_buffers_len]windows.WSABUF = undefined; |
| 1870 | | var iovecs_i: usize = 0; |
| 1871 | | for (data) |d| { |
| 1872 | | // In case Windows checks pointer address before length, we must omit |
| 1873 | | // length-zero vectors. |
| 1874 | | if (d.len == 0) continue; |
| 1875 | | iovecs[iovecs_i] = .{ .buf = d.ptr, .len = d.len }; |
| 1876 | | iovecs_i += 1; |
| 1877 | | if (iovecs_i >= iovecs.len) break; |
| 1873 | fn readVec(context: ?*anyopaque, data: []const []u8) std.io.Reader.Error!usize { |
| 1874 | var iovecs: [max_buffers_len]windows.WSABUF = undefined; |
| 1875 | var iovecs_i: usize = 0; |
| 1876 | for (data) |d| { |
| 1877 | // In case Windows checks pointer address before length, we must omit |
| 1878 | // length-zero vectors. |
| 1879 | if (d.len == 0) continue; |
| 1880 | iovecs[iovecs_i] = .{ .buf = d.ptr, .len = d.len }; |
| 1881 | iovecs_i += 1; |
| 1882 | if (iovecs_i >= iovecs.len) break; |
| 1883 | } |
| 1884 | const bufs = iovecs[0..iovecs_i]; |
| 1885 | if (bufs.len == 0) return .{}; // Prevent false positive end detection on empty `data`. |
| 1886 | var n: u32 = undefined; |
| 1887 | var flags: u32 = 0; |
| 1888 | const rc = windows.ws2_32.WSARecvFrom(context, bufs.ptr, bufs.len, &n, &flags, null, null, null, null); |
| 1889 | if (rc != 0) switch (windows.ws2_32.WSAGetLastError()) { |
| 1890 | .WSAECONNRESET => return error.ConnectionResetByPeer, |
| 1891 | .WSAEFAULT => unreachable, // a pointer is not completely contained in user address space. |
| 1892 | .WSAEINPROGRESS, .WSAEINTR => unreachable, // deprecated and removed in WSA 2.2 |
| 1893 | .WSAEINVAL => return error.SocketNotBound, |
| 1894 | .WSAEMSGSIZE => return error.MessageTooBig, |
| 1895 | .WSAENETDOWN => return error.NetworkSubsystemFailed, |
| 1896 | .WSAENETRESET => return error.ConnectionResetByPeer, |
| 1897 | .WSAENOTCONN => return error.SocketNotConnected, |
| 1898 | .WSAEWOULDBLOCK => return error.WouldBlock, |
| 1899 | .WSANOTINITIALISED => unreachable, // WSAStartup must be called before this function |
| 1900 | .WSA_IO_PENDING => unreachable, // not using overlapped I/O |
| 1901 | .WSA_OPERATION_ABORTED => unreachable, // not using overlapped I/O |
| 1902 | else => |err| return windows.unexpectedWSAError(err), |
| 1903 | }; |
| 1904 | return .{ .len = n, .end = n == 0 }; |
| 1878 | 1905 | } |
| 1879 | | const bufs = iovecs[0..iovecs_i]; |
| 1880 | | if (bufs.len == 0) return .{}; // Prevent false positive end detection on empty `data`. |
| 1881 | | var n: u32 = undefined; |
| 1882 | | var flags: u32 = 0; |
| 1883 | | const rc = windows.ws2_32.WSARecvFrom(context, bufs.ptr, bufs.len, &n, &flags, null, null, null, null); |
| 1884 | | if (rc != 0) switch (windows.ws2_32.WSAGetLastError()) { |
| 1885 | | .WSAECONNRESET => return error.ConnectionResetByPeer, |
| 1886 | | .WSAEFAULT => unreachable, // a pointer is not completely contained in user address space. |
| 1887 | | .WSAEINPROGRESS, .WSAEINTR => unreachable, // deprecated and removed in WSA 2.2 |
| 1888 | | .WSAEINVAL => return error.SocketNotBound, |
| 1889 | | .WSAEMSGSIZE => return error.MessageTooBig, |
| 1890 | | .WSAENETDOWN => return error.NetworkSubsystemFailed, |
| 1891 | | .WSAENETRESET => return error.ConnectionResetByPeer, |
| 1892 | | .WSAENOTCONN => return error.SocketNotConnected, |
| 1893 | | .WSAEWOULDBLOCK => return error.WouldBlock, |
| 1894 | | .WSANOTINITIALISED => unreachable, // WSAStartup must be called before this function |
| 1895 | | .WSA_IO_PENDING => unreachable, // not using overlapped I/O |
| 1896 | | .WSA_OPERATION_ABORTED => unreachable, // not using overlapped I/O |
| 1897 | | else => |err| return windows.unexpectedWSAError(err), |
| 1898 | | }; |
| 1899 | | return .{ .len = n, .end = n == 0 }; |
| 1900 | | } |
| 1901 | 1906 | |
| 1902 | | fn windows_discard(context: ?*anyopaque, limit: std.io.Reader.Limit) std.io.Reader.Error!usize { |
| 1903 | | _ = context; |
| 1904 | | _ = limit; |
| 1905 | | @panic("TODO"); |
| 1906 | | } |
| 1907 | | }; |
| 1907 | fn discard(context: ?*anyopaque, limit: std.io.Reader.Limit) std.io.Reader.Error!usize { |
| 1908 | _ = context; |
| 1909 | _ = limit; |
| 1910 | @panic("TODO"); |
| 1911 | } |
| 1912 | }, |
| 1913 | else => struct { |
| 1914 | file_reader: std.fs.File.Reader, |
| 1915 | |
| 1916 | pub const Error = ReadError; |
| 1908 | 1917 | |
| 1909 | | pub const Writer = struct { |
| 1910 | | impl: switch (native_os) { |
| 1911 | | .windows => Stream, |
| 1912 | | else => PosixImpl, |
| 1918 | pub fn interface(r: *Reader) std.io.Reader { |
| 1919 | return r.file_reader.interface(); |
| 1920 | } |
| 1913 | 1921 | }, |
| 1922 | }; |
| 1914 | 1923 | |
| 1915 | | const PosixImpl = struct { |
| 1916 | | fw: std.fs.File.Writer, |
| 1917 | | err: Error!void, |
| 1918 | | }; |
| 1924 | pub const Writer = switch (native_os) { |
| 1925 | .windows => struct { |
| 1926 | stream: Stream, |
| 1919 | 1927 | |
| 1920 | | pub const Error = posix.SendMsgError || error{ |
| 1921 | | ConnectionResetByPeer, |
| 1922 | | SocketNotBound, |
| 1923 | | MessageTooBig, |
| 1924 | | NetworkSubsystemFailed, |
| 1925 | | SystemResources, |
| 1926 | | SocketNotConnected, |
| 1927 | | Unexpected, |
| 1928 | | }; |
| 1928 | pub const Error = WriteError; |
| 1929 | 1929 | |
| 1930 | | pub fn interface(w: *Writer) std.io.Writer { |
| 1931 | | return switch (native_os) { |
| 1932 | | .windows => .{ |
| 1933 | | .context = w.impl.stream.handle, |
| 1930 | pub fn interface(w: *Writer) std.io.Writer { |
| 1931 | return .{ |
| 1932 | .context = w.stream.handle, |
| 1934 | 1933 | .vtable = &.{ |
| 1935 | | .writeSplat = windows_writeSplat, |
| 1936 | | .writeFile = windows_writeFile, |
| 1934 | .writeSplat = writeSplat, |
| 1935 | .writeFile = writeFile, |
| 1937 | 1936 | }, |
| 1938 | | }, |
| 1939 | | else => .{ |
| 1940 | | .context = &w.impl, |
| 1937 | }; |
| 1938 | } |
| 1939 | |
| 1940 | fn writeSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) std.io.Writer.Error!usize { |
| 1941 | comptime assert(native_os == .windows); |
| 1942 | if (data.len == 1 and splat == 0) return 0; |
| 1943 | var splat_buffer: [256]u8 = undefined; |
| 1944 | var iovecs: [max_buffers_len]windows.WSABUF = undefined; |
| 1945 | var len: u32 = @min(iovecs.len, data.len); |
| 1946 | for (iovecs[0..len], data[0..len]) |*v, d| v.* = .{ |
| 1947 | .buf = if (d.len == 0) "" else d.ptr, // TODO: does Windows allow ptr=undefined len=0 ? |
| 1948 | .len = d.len, |
| 1949 | }; |
| 1950 | switch (splat) { |
| 1951 | 0 => len -= 1, |
| 1952 | 1 => {}, |
| 1953 | else => { |
| 1954 | const pattern = data[data.len - 1]; |
| 1955 | if (pattern.len == 1) { |
| 1956 | const memset_len = @min(splat_buffer.len, splat); |
| 1957 | const buf = splat_buffer[0..memset_len]; |
| 1958 | @memset(buf, pattern[0]); |
| 1959 | iovecs[len - 1] = .{ .base = buf.ptr, .len = buf.len }; |
| 1960 | var remaining_splat = splat - buf.len; |
| 1961 | while (remaining_splat > splat_buffer.len and len < iovecs.len) { |
| 1962 | iovecs[len] = .{ .base = &splat_buffer, .len = splat_buffer.len }; |
| 1963 | remaining_splat -= splat_buffer.len; |
| 1964 | len += 1; |
| 1965 | } |
| 1966 | if (remaining_splat > 0 and len < iovecs.len) { |
| 1967 | iovecs[len] = .{ .base = &splat_buffer, .len = remaining_splat }; |
| 1968 | len += 1; |
| 1969 | } |
| 1970 | } |
| 1971 | }, |
| 1972 | } |
| 1973 | var n: u32 = undefined; |
| 1974 | const rc = windows.ws2_32.WSASend(context, &iovecs, len, &n, 0, null, null); |
| 1975 | if (rc == windows.ws2_32.SOCKET_ERROR) switch (windows.ws2_32.WSAGetLastError()) { |
| 1976 | .WSAECONNABORTED => return error.ConnectionResetByPeer, |
| 1977 | .WSAECONNRESET => return error.ConnectionResetByPeer, |
| 1978 | .WSAEFAULT => unreachable, // a pointer is not completely contained in user address space. |
| 1979 | .WSAEINPROGRESS, .WSAEINTR => unreachable, // deprecated and removed in WSA 2.2 |
| 1980 | .WSAEINVAL => return error.SocketNotBound, |
| 1981 | .WSAEMSGSIZE => return error.MessageTooBig, |
| 1982 | .WSAENETDOWN => return error.NetworkSubsystemFailed, |
| 1983 | .WSAENETRESET => return error.ConnectionResetByPeer, |
| 1984 | .WSAENOBUFS => return error.SystemResources, |
| 1985 | .WSAENOTCONN => return error.SocketNotConnected, |
| 1986 | .WSAENOTSOCK => unreachable, // not a socket |
| 1987 | .WSAEOPNOTSUPP => unreachable, // only for message-oriented sockets |
| 1988 | .WSAESHUTDOWN => unreachable, // cannot send on a socket after write shutdown |
| 1989 | .WSAEWOULDBLOCK => return error.WouldBlock, |
| 1990 | .WSANOTINITIALISED => unreachable, // WSAStartup must be called before this function |
| 1991 | .WSA_IO_PENDING => unreachable, // not using overlapped I/O |
| 1992 | .WSA_OPERATION_ABORTED => unreachable, // not using overlapped I/O |
| 1993 | else => |err| return windows.unexpectedWSAError(err), |
| 1994 | }; |
| 1995 | return n; |
| 1996 | } |
| 1997 | |
| 1998 | fn writeFile( |
| 1999 | context: *anyopaque, |
| 2000 | in_file: std.fs.File, |
| 2001 | in_offset: u64, |
| 2002 | in_len: std.io.Writer.FileLen, |
| 2003 | headers_and_trailers: []const []const u8, |
| 2004 | headers_len: usize, |
| 2005 | ) std.io.Writer.FileError!usize { |
| 2006 | const len_int = switch (in_len) { |
| 2007 | .zero => return writeSplat(context, headers_and_trailers, 1), |
| 2008 | .entire_file => std.math.maxInt(usize), |
| 2009 | else => in_len.int(), |
| 2010 | }; |
| 2011 | if (headers_len > 0) return writeSplat(context, headers_and_trailers[0..headers_len], 1); |
| 2012 | var file_contents_buffer: [4096]u8 = undefined; |
| 2013 | const read_buffer = file_contents_buffer[0..@min(file_contents_buffer.len, len_int)]; |
| 2014 | const n = try windows.ReadFile(in_file.handle, read_buffer, in_offset); |
| 2015 | return writeSplat(context, &.{read_buffer[0..n]}, 1); |
| 2016 | } |
| 2017 | }, |
| 2018 | else => struct { |
| 2019 | file_writer: std.fs.File.Writer, |
| 2020 | err: ?Error = null, |
| 2021 | |
| 2022 | pub const Error = WriteError; |
| 2023 | |
| 2024 | pub fn interface(w: *Writer) std.io.Writer { |
| 2025 | return .{ |
| 2026 | .context = &w.file_writer, |
| 1941 | 2027 | .vtable = &.{ |
| 1942 | | .writeSplat = posix_writeSplat, |
| 2028 | .writeSplat = writeSplat, |
| 1943 | 2029 | .writeFile = std.fs.File.Writer.writeFile, |
| 1944 | 2030 | }, |
| 1945 | | }, |
| 1946 | | }; |
| 1947 | | } |
| 1948 | | |
| 1949 | | fn windows_writeSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) std.io.Writer.Error!usize { |
| 1950 | | comptime assert(native_os == .windows); |
| 1951 | | if (data.len == 1 and splat == 0) return 0; |
| 1952 | | var splat_buffer: [256]u8 = undefined; |
| 1953 | | var iovecs: [max_buffers_len]windows.WSABUF = undefined; |
| 1954 | | var len: u32 = @min(iovecs.len, data.len); |
| 1955 | | for (iovecs[0..len], data[0..len]) |*v, d| v.* = .{ |
| 1956 | | .buf = if (d.len == 0) "" else d.ptr, // TODO: does Windows allow ptr=undefined len=0 ? |
| 1957 | | .len = d.len, |
| 1958 | | }; |
| 1959 | | switch (splat) { |
| 1960 | | 0 => len -= 1, |
| 1961 | | 1 => {}, |
| 1962 | | else => { |
| 1963 | | const pattern = data[data.len - 1]; |
| 1964 | | if (pattern.len == 1) { |
| 1965 | | const memset_len = @min(splat_buffer.len, splat); |
| 1966 | | const buf = splat_buffer[0..memset_len]; |
| 1967 | | @memset(buf, pattern[0]); |
| 1968 | | iovecs[len - 1] = .{ .base = buf.ptr, .len = buf.len }; |
| 1969 | | var remaining_splat = splat - buf.len; |
| 1970 | | while (remaining_splat > splat_buffer.len and len < iovecs.len) { |
| 1971 | | iovecs[len] = .{ .base = &splat_buffer, .len = splat_buffer.len }; |
| 1972 | | remaining_splat -= splat_buffer.len; |
| 1973 | | len += 1; |
| 1974 | | } |
| 1975 | | if (remaining_splat > 0 and len < iovecs.len) { |
| 1976 | | iovecs[len] = .{ .base = &splat_buffer, .len = remaining_splat }; |
| 1977 | | len += 1; |
| 1978 | | } |
| 1979 | | } |
| 1980 | | }, |
| 2031 | }; |
| 1981 | 2032 | } |
| 1982 | | var n: u32 = undefined; |
| 1983 | | const rc = windows.ws2_32.WSASend(context, &iovecs, len, &n, 0, null, null); |
| 1984 | | if (rc == windows.ws2_32.SOCKET_ERROR) switch (windows.ws2_32.WSAGetLastError()) { |
| 1985 | | .WSAECONNABORTED => return error.ConnectionResetByPeer, |
| 1986 | | .WSAECONNRESET => return error.ConnectionResetByPeer, |
| 1987 | | .WSAEFAULT => unreachable, // a pointer is not completely contained in user address space. |
| 1988 | | .WSAEINPROGRESS, .WSAEINTR => unreachable, // deprecated and removed in WSA 2.2 |
| 1989 | | .WSAEINVAL => return error.SocketNotBound, |
| 1990 | | .WSAEMSGSIZE => return error.MessageTooBig, |
| 1991 | | .WSAENETDOWN => return error.NetworkSubsystemFailed, |
| 1992 | | .WSAENETRESET => return error.ConnectionResetByPeer, |
| 1993 | | .WSAENOBUFS => return error.SystemResources, |
| 1994 | | .WSAENOTCONN => return error.SocketNotConnected, |
| 1995 | | .WSAENOTSOCK => unreachable, // not a socket |
| 1996 | | .WSAEOPNOTSUPP => unreachable, // only for message-oriented sockets |
| 1997 | | .WSAESHUTDOWN => unreachable, // cannot send on a socket after write shutdown |
| 1998 | | .WSAEWOULDBLOCK => return error.WouldBlock, |
| 1999 | | .WSANOTINITIALISED => unreachable, // WSAStartup must be called before this function |
| 2000 | | .WSA_IO_PENDING => unreachable, // not using overlapped I/O |
| 2001 | | .WSA_OPERATION_ABORTED => unreachable, // not using overlapped I/O |
| 2002 | | else => |err| return windows.unexpectedWSAError(err), |
| 2003 | | }; |
| 2004 | | return n; |
| 2005 | | } |
| 2006 | 2033 | |
| 2007 | | fn posix_writeSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) std.io.Writer.Error!usize { |
| 2008 | | const fw: *std.fs.File.Writer = @alignCast(@ptrCast(context)); |
| 2009 | | const impl: *PosixImpl = @fieldParentPtr("fw", fw); |
| 2010 | | comptime assert(native_os != .windows); |
| 2011 | | var splat_buffer: [256]u8 = undefined; |
| 2012 | | var iovecs: [max_buffers_len]std.posix.iovec_const = undefined; |
| 2013 | | var len: usize = @min(iovecs.len, data.len); |
| 2014 | | for (iovecs[0..len], data[0..len]) |*v, d| v.* = .{ |
| 2015 | | .base = if (d.len == 0) "" else d.ptr, // OS sadly checks ptr addr before length. |
| 2016 | | .len = d.len, |
| 2017 | | }; |
| 2018 | | var msg: posix.msghdr_const = .{ |
| 2019 | | .name = null, |
| 2020 | | .namelen = 0, |
| 2021 | | .iov = &iovecs, |
| 2022 | | .iovlen = len, |
| 2023 | | .control = null, |
| 2024 | | .controllen = 0, |
| 2025 | | .flags = 0, |
| 2026 | | }; |
| 2027 | | switch (splat) { |
| 2028 | | 0 => msg.iovlen = len - 1, |
| 2029 | | 1 => {}, |
| 2030 | | else => { |
| 2031 | | const pattern = data[data.len - 1]; |
| 2032 | | if (pattern.len == 1) { |
| 2033 | | const memset_len = @min(splat_buffer.len, splat); |
| 2034 | | const buf = splat_buffer[0..memset_len]; |
| 2035 | | @memset(buf, pattern[0]); |
| 2036 | | iovecs[len - 1] = .{ .base = buf.ptr, .len = buf.len }; |
| 2037 | | var remaining_splat = splat - buf.len; |
| 2038 | | while (remaining_splat > splat_buffer.len and len < iovecs.len) { |
| 2039 | | iovecs[len] = .{ .base = &splat_buffer, .len = splat_buffer.len }; |
| 2040 | | remaining_splat -= splat_buffer.len; |
| 2041 | | len += 1; |
| 2042 | | } |
| 2043 | | if (remaining_splat > 0 and len < iovecs.len) { |
| 2044 | | iovecs[len] = .{ .base = &splat_buffer, .len = remaining_splat }; |
| 2045 | | len += 1; |
| 2034 | fn writeSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) std.io.Writer.Error!usize { |
| 2035 | const fw: *std.fs.File.Writer = @alignCast(@ptrCast(context)); |
| 2036 | const w: *Writer = @fieldParentPtr("file_writer", fw); |
| 2037 | var splat_buffer: [256]u8 = undefined; |
| 2038 | var iovecs: [max_buffers_len]std.posix.iovec_const = undefined; |
| 2039 | var len: usize = @min(iovecs.len, data.len); |
| 2040 | for (iovecs[0..len], data[0..len]) |*v, d| v.* = .{ |
| 2041 | .base = if (d.len == 0) "" else d.ptr, // OS sadly checks ptr addr before length. |
| 2042 | .len = d.len, |
| 2043 | }; |
| 2044 | var msg: posix.msghdr_const = .{ |
| 2045 | .name = null, |
| 2046 | .namelen = 0, |
| 2047 | .iov = &iovecs, |
| 2048 | .iovlen = len, |
| 2049 | .control = null, |
| 2050 | .controllen = 0, |
| 2051 | .flags = 0, |
| 2052 | }; |
| 2053 | switch (splat) { |
| 2054 | 0 => msg.iovlen = len - 1, |
| 2055 | 1 => {}, |
| 2056 | else => { |
| 2057 | const pattern = data[data.len - 1]; |
| 2058 | if (pattern.len == 1) { |
| 2059 | const memset_len = @min(splat_buffer.len, splat); |
| 2060 | const buf = splat_buffer[0..memset_len]; |
| 2061 | @memset(buf, pattern[0]); |
| 2062 | iovecs[len - 1] = .{ .base = buf.ptr, .len = buf.len }; |
| 2063 | var remaining_splat = splat - buf.len; |
| 2064 | while (remaining_splat > splat_buffer.len and len < iovecs.len) { |
| 2065 | iovecs[len] = .{ .base = &splat_buffer, .len = splat_buffer.len }; |
| 2066 | remaining_splat -= splat_buffer.len; |
| 2067 | len += 1; |
| 2068 | } |
| 2069 | if (remaining_splat > 0 and len < iovecs.len) { |
| 2070 | iovecs[len] = .{ .base = &splat_buffer, .len = remaining_splat }; |
| 2071 | len += 1; |
| 2072 | } |
| 2073 | msg.iovlen = len; |
| 2046 | 2074 | } |
| 2047 | | msg.iovlen = len; |
| 2048 | | } |
| 2049 | | }, |
| 2075 | }, |
| 2076 | } |
| 2077 | const flags = posix.MSG.NOSIGNAL; |
| 2078 | return std.posix.sendmsg(fw.file.handle, &msg, flags) catch |err| { |
| 2079 | w.err = err; |
| 2080 | return error.WriteFailed; |
| 2081 | }; |
| 2050 | 2082 | } |
| 2051 | | const flags = posix.MSG.NOSIGNAL; |
| 2052 | | return std.posix.sendmsg(fw.file.handle, &msg, flags) catch |err| { |
| 2053 | | impl.err = err; |
| 2054 | | return error.WriteFailed; |
| 2055 | | }; |
| 2056 | | } |
| 2057 | | |
| 2058 | | fn windows_writeFile( |
| 2059 | | context: *anyopaque, |
| 2060 | | in_file: std.fs.File, |
| 2061 | | in_offset: u64, |
| 2062 | | in_len: std.io.Writer.FileLen, |
| 2063 | | headers_and_trailers: []const []const u8, |
| 2064 | | headers_len: usize, |
| 2065 | | ) std.io.Writer.FileError!usize { |
| 2066 | | const len_int = switch (in_len) { |
| 2067 | | .zero => return windows_writeSplat(context, headers_and_trailers, 1), |
| 2068 | | .entire_file => std.math.maxInt(usize), |
| 2069 | | else => in_len.int(), |
| 2070 | | }; |
| 2071 | | if (headers_len > 0) return windows_writeSplat(context, headers_and_trailers[0..headers_len], 1); |
| 2072 | | var file_contents_buffer: [4096]u8 = undefined; |
| 2073 | | const read_buffer = file_contents_buffer[0..@min(file_contents_buffer.len, len_int)]; |
| 2074 | | const n = try windows.ReadFile(in_file.handle, read_buffer, in_offset); |
| 2075 | | return windows_writeSplat(context, &.{read_buffer[0..n]}, 1); |
| 2076 | | } |
| 2083 | }, |
| 2077 | 2084 | }; |
| 2078 | 2085 | |
| 2079 | 2086 | pub fn reader(stream: Stream) Reader { |
| 2080 | 2087 | return switch (native_os) { |
| 2081 | | .windows => .{ .impl = stream }, |
| 2082 | | else => .{ .impl = .{ |
| 2083 | | .fr = .{ |
| 2084 | | .file = .{ .handle = stream.handle }, |
| 2085 | | .mode = .streaming, |
| 2086 | | .seek_err = error.Unseekable, |
| 2087 | | }, |
| 2088 | | .err = {}, |
| 2088 | .windows => .{ .stream = stream }, |
| 2089 | else => .{ .file_reader = .{ |
| 2090 | .file = .{ .handle = stream.handle }, |
| 2091 | .mode = .streaming, |
| 2092 | .seek_err = error.Unseekable, |
| 2089 | 2093 | } }, |
| 2090 | 2094 | }; |
| 2091 | 2095 | } |
| 2092 | 2096 | |
| 2093 | 2097 | pub fn writer(stream: Stream) Writer { |
| 2094 | 2098 | return switch (native_os) { |
| 2095 | | .windows => .{ .impl = stream }, |
| 2096 | | else => .{ .impl = .{ |
| 2097 | | .fw = .{ |
| 2098 | | .file = .{ .handle = stream.handle }, |
| 2099 | | .mode = .streaming, |
| 2100 | | }, |
| 2101 | | .err = {}, |
| 2099 | .windows => .{ .stream = stream }, |
| 2100 | else => .{ .file_writer = .{ |
| 2101 | .file = .{ .handle = stream.handle }, |
| 2102 | .mode = .streaming, |
| 2102 | 2103 | } }, |
| 2103 | 2104 | }; |
| 2104 | 2105 | } |