| ... | @@ -1829,276 +1829,277 @@ pub const Stream = struct { | ... | @@ -1829,276 +1829,277 @@ pub const Stream = struct { |
| 1829 | } | 1829 | } |
| 1830 | } | 1830 | } |
| 1831 | | 1831 | |
| 1832 | pub const Reader = struct { | 1832 | const ReadError = posix.ReadError; |
| 1833 | impl: switch (native_os) { | 1833 | |
| 1834 | .windows => Stream, | 1834 | const WriteError = posix.SendMsgError || error{ |
| 1835 | else => struct { | 1835 | ConnectionResetByPeer, |
| 1836 | fr: std.fs.File.Reader, | 1836 | SocketNotBound, |
| 1837 | err: Error!void, | 1837 | MessageTooBig, |
| 1838 | }, | 1838 | NetworkSubsystemFailed, |
| 1839 | }, | 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 { | 1849 | pub const Error = ReadError; |
| 1844 | return switch (native_os) { | 1850 | |
| 1845 | .windows => .{ | 1851 | pub fn interface(r: *Reader) std.io.Reader { |
| 1846 | .context = r.impl.stream.handle, | 1852 | return .{ |
| | 1853 | .context = r.stream.handle, |
| 1847 | .vtable = &.{ | 1854 | .vtable = &.{ |
| 1848 | .read = windows_read, | 1855 | .read = read, |
| 1849 | .readVec = windows_readVec, | 1856 | .readVec = readVec, |
| 1850 | .discard = windows_discard, | 1857 | .discard = discard, |
| 1851 | }, | 1858 | }, |
| 1852 | }, | 1859 | }; |
| 1853 | else => r.interface(), | 1860 | } |
| 1854 | }; | | |
| 1855 | } | | |
| 1856 | | 1861 | |
| 1857 | fn windows_read( | 1862 | fn read( |
| 1858 | context: ?*anyopaque, | 1863 | context: ?*anyopaque, |
| 1859 | bw: *std.io.BufferedWriter, | 1864 | bw: *std.io.BufferedWriter, |
| 1860 | limit: std.io.Reader.Limit, | 1865 | limit: std.io.Reader.Limit, |
| 1861 | ) std.io.Reader.Error!usize { | 1866 | ) std.io.Reader.Error!usize { |
| 1862 | const buf = limit.slice(try bw.writableSliceGreedy(1)); | 1867 | const buf = limit.slice(try bw.writableSliceGreedy(1)); |
| 1863 | const status = try windows_readVec(context, &.{buf}); | 1868 | const status = try readVec(context, &.{buf}); |
| 1864 | bw.advance(status.len); | 1869 | bw.advance(status.len); |
| 1865 | return status; | 1870 | return status; |
| 1866 | } | 1871 | } |
| 1867 | | 1872 | |
| 1868 | fn windows_readVec(context: ?*anyopaque, data: []const []u8) std.io.Reader.Error!usize { | 1873 | fn readVec(context: ?*anyopaque, data: []const []u8) std.io.Reader.Error!usize { |
| 1869 | var iovecs: [max_buffers_len]windows.WSABUF = undefined; | 1874 | var iovecs: [max_buffers_len]windows.WSABUF = undefined; |
| 1870 | var iovecs_i: usize = 0; | 1875 | var iovecs_i: usize = 0; |
| 1871 | for (data) |d| { | 1876 | for (data) |d| { |
| 1872 | // In case Windows checks pointer address before length, we must omit | 1877 | // In case Windows checks pointer address before length, we must omit |
| 1873 | // length-zero vectors. | 1878 | // length-zero vectors. |
| 1874 | if (d.len == 0) continue; | 1879 | if (d.len == 0) continue; |
| 1875 | iovecs[iovecs_i] = .{ .buf = d.ptr, .len = d.len }; | 1880 | iovecs[iovecs_i] = .{ .buf = d.ptr, .len = d.len }; |
| 1876 | iovecs_i += 1; | 1881 | iovecs_i += 1; |
| 1877 | if (iovecs_i >= iovecs.len) break; | 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 { | 1907 | fn discard(context: ?*anyopaque, limit: std.io.Reader.Limit) std.io.Reader.Error!usize { |
| 1903 | _ = context; | 1908 | _ = context; |
| 1904 | _ = limit; | 1909 | _ = limit; |
| 1905 | @panic("TODO"); | 1910 | @panic("TODO"); |
| 1906 | } | 1911 | } |
| 1907 | }; | 1912 | }, |
| | 1913 | else => struct { |
| | 1914 | file_reader: std.fs.File.Reader, |
| | 1915 | |
| | 1916 | pub const Error = ReadError; |
| 1908 | | 1917 | |
| 1909 | pub const Writer = struct { | 1918 | pub fn interface(r: *Reader) std.io.Reader { |
| 1910 | impl: switch (native_os) { | 1919 | return r.file_reader.interface(); |
| 1911 | .windows => Stream, | 1920 | } |
| 1912 | else => PosixImpl, | | |
| 1913 | }, | 1921 | }, |
| | 1922 | }; |
| 1914 | | 1923 | |
| 1915 | const PosixImpl = struct { | 1924 | pub const Writer = switch (native_os) { |
| 1916 | fw: std.fs.File.Writer, | 1925 | .windows => struct { |
| 1917 | err: Error!void, | 1926 | stream: Stream, |
| 1918 | }; | | |
| 1919 | | 1927 | |
| 1920 | pub const Error = posix.SendMsgError || error{ | 1928 | pub const Error = WriteError; |
| 1921 | ConnectionResetByPeer, | | |
| 1922 | SocketNotBound, | | |
| 1923 | MessageTooBig, | | |
| 1924 | NetworkSubsystemFailed, | | |
| 1925 | SystemResources, | | |
| 1926 | SocketNotConnected, | | |
| 1927 | Unexpected, | | |
| 1928 | }; | | |
| 1929 | | 1929 | |
| 1930 | pub fn interface(w: *Writer) std.io.Writer { | 1930 | pub fn interface(w: *Writer) std.io.Writer { |
| 1931 | return switch (native_os) { | 1931 | return .{ |
| 1932 | .windows => .{ | 1932 | .context = w.stream.handle, |
| 1933 | .context = w.impl.stream.handle, | | |
| 1934 | .vtable = &.{ | 1933 | .vtable = &.{ |
| 1935 | .writeSplat = windows_writeSplat, | 1934 | .writeSplat = writeSplat, |
| 1936 | .writeFile = windows_writeFile, | 1935 | .writeFile = writeFile, |
| 1937 | }, | 1936 | }, |
| 1938 | }, | 1937 | }; |
| 1939 | else => .{ | 1938 | } |
| 1940 | .context = &w.impl, | 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 | .vtable = &.{ | 2027 | .vtable = &.{ |
| 1942 | .writeSplat = posix_writeSplat, | 2028 | .writeSplat = writeSplat, |
| 1943 | .writeFile = std.fs.File.Writer.writeFile, | 2029 | .writeFile = std.fs.File.Writer.writeFile, |
| 1944 | }, | 2030 | }, |
| 1945 | }, | 2031 | }; |
| 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 | }, | | |
| 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 { | 2034 | fn writeSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) std.io.Writer.Error!usize { |
| 2008 | const fw: *std.fs.File.Writer = @alignCast(@ptrCast(context)); | 2035 | const fw: *std.fs.File.Writer = @alignCast(@ptrCast(context)); |
| 2009 | const impl: *PosixImpl = @fieldParentPtr("fw", fw); | 2036 | const w: *Writer = @fieldParentPtr("file_writer", fw); |
| 2010 | comptime assert(native_os != .windows); | 2037 | var splat_buffer: [256]u8 = undefined; |
| 2011 | var splat_buffer: [256]u8 = undefined; | 2038 | var iovecs: [max_buffers_len]std.posix.iovec_const = undefined; |
| 2012 | var iovecs: [max_buffers_len]std.posix.iovec_const = undefined; | 2039 | var len: usize = @min(iovecs.len, data.len); |
| 2013 | var len: usize = @min(iovecs.len, data.len); | 2040 | for (iovecs[0..len], data[0..len]) |*v, d| v.* = .{ |
| 2014 | 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. |
| 2015 | .base = if (d.len == 0) "" else d.ptr, // OS sadly checks ptr addr before length. | 2042 | .len = d.len, |
| 2016 | .len = d.len, | 2043 | }; |
| 2017 | }; | 2044 | var msg: posix.msghdr_const = .{ |
| 2018 | var msg: posix.msghdr_const = .{ | 2045 | .name = null, |
| 2019 | .name = null, | 2046 | .namelen = 0, |
| 2020 | .namelen = 0, | 2047 | .iov = &iovecs, |
| 2021 | .iov = &iovecs, | 2048 | .iovlen = len, |
| 2022 | .iovlen = len, | 2049 | .control = null, |
| 2023 | .control = null, | 2050 | .controllen = 0, |
| 2024 | .controllen = 0, | 2051 | .flags = 0, |
| 2025 | .flags = 0, | 2052 | }; |
| 2026 | }; | 2053 | switch (splat) { |
| 2027 | switch (splat) { | 2054 | 0 => msg.iovlen = len - 1, |
| 2028 | 0 => msg.iovlen = len - 1, | 2055 | 1 => {}, |
| 2029 | 1 => {}, | 2056 | else => { |
| 2030 | else => { | 2057 | const pattern = data[data.len - 1]; |
| 2031 | const pattern = data[data.len - 1]; | 2058 | if (pattern.len == 1) { |
| 2032 | if (pattern.len == 1) { | 2059 | const memset_len = @min(splat_buffer.len, splat); |
| 2033 | const memset_len = @min(splat_buffer.len, splat); | 2060 | const buf = splat_buffer[0..memset_len]; |
| 2034 | const buf = splat_buffer[0..memset_len]; | 2061 | @memset(buf, pattern[0]); |
| 2035 | @memset(buf, pattern[0]); | 2062 | iovecs[len - 1] = .{ .base = buf.ptr, .len = buf.len }; |
| 2036 | iovecs[len - 1] = .{ .base = buf.ptr, .len = buf.len }; | 2063 | var remaining_splat = splat - buf.len; |
| 2037 | var remaining_splat = splat - buf.len; | 2064 | while (remaining_splat > splat_buffer.len and len < iovecs.len) { |
| 2038 | while (remaining_splat > splat_buffer.len and len < iovecs.len) { | 2065 | iovecs[len] = .{ .base = &splat_buffer, .len = splat_buffer.len }; |
| 2039 | iovecs[len] = .{ .base = &splat_buffer, .len = splat_buffer.len }; | 2066 | remaining_splat -= splat_buffer.len; |
| 2040 | remaining_splat -= splat_buffer.len; | 2067 | len += 1; |
| 2041 | len += 1; | 2068 | } |
| 2042 | } | 2069 | if (remaining_splat > 0 and len < iovecs.len) { |
| 2043 | if (remaining_splat > 0 and len < iovecs.len) { | 2070 | iovecs[len] = .{ .base = &splat_buffer, .len = remaining_splat }; |
| 2044 | iovecs[len] = .{ .base = &splat_buffer, .len = remaining_splat }; | 2071 | len += 1; |
| 2045 | len += 1; | 2072 | } |
| | 2073 | msg.iovlen = len; |
| 2046 | } | 2074 | } |
| 2047 | msg.iovlen = len; | 2075 | }, |
| 2048 | } | 2076 | } |
| 2049 | }, | 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; | 2083 | }, |
| 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 | } | | |
| 2077 | }; | 2084 | }; |
| 2078 | | 2085 | |
| 2079 | pub fn reader(stream: Stream) Reader { | 2086 | pub fn reader(stream: Stream) Reader { |
| 2080 | return switch (native_os) { | 2087 | return switch (native_os) { |
| 2081 | .windows => .{ .impl = stream }, | 2088 | .windows => .{ .stream = stream }, |
| 2082 | else => .{ .impl = .{ | 2089 | else => .{ .file_reader = .{ |
| 2083 | .fr = .{ | 2090 | .file = .{ .handle = stream.handle }, |
| 2084 | .file = .{ .handle = stream.handle }, | 2091 | .mode = .streaming, |
| 2085 | .mode = .streaming, | 2092 | .seek_err = error.Unseekable, |
| 2086 | .seek_err = error.Unseekable, | | |
| 2087 | }, | | |
| 2088 | .err = {}, | | |
| 2089 | } }, | 2093 | } }, |
| 2090 | }; | 2094 | }; |
| 2091 | } | 2095 | } |
| 2092 | | 2096 | |
| 2093 | pub fn writer(stream: Stream) Writer { | 2097 | pub fn writer(stream: Stream) Writer { |
| 2094 | return switch (native_os) { | 2098 | return switch (native_os) { |
| 2095 | .windows => .{ .impl = stream }, | 2099 | .windows => .{ .stream = stream }, |
| 2096 | else => .{ .impl = .{ | 2100 | else => .{ .file_writer = .{ |
| 2097 | .fw = .{ | 2101 | .file = .{ .handle = stream.handle }, |
| 2098 | .file = .{ .handle = stream.handle }, | 2102 | .mode = .streaming, |
| 2099 | .mode = .streaming, | | |
| 2100 | }, | | |
| 2101 | .err = {}, | | |
| 2102 | } }, | 2103 | } }, |
| 2103 | }; | 2104 | }; |
| 2104 | } | 2105 | } |