diff --git a/build/bootstrap/ar.com b/build/bootstrap/ar.com index 304bb55c3..25393e16f 100755 Binary files a/build/bootstrap/ar.com and b/build/bootstrap/ar.com differ diff --git a/build/bootstrap/mkdeps.com b/build/bootstrap/mkdeps.com index 5dbcfeec5..dd06f96b0 100755 Binary files a/build/bootstrap/mkdeps.com and b/build/bootstrap/mkdeps.com differ diff --git a/build/bootstrap/package.com b/build/bootstrap/package.com index b7a169cc6..c166f1018 100755 Binary files a/build/bootstrap/package.com and b/build/bootstrap/package.com differ diff --git a/build/bootstrap/zipobj.com b/build/bootstrap/zipobj.com index c9361bf7a..d148bd22d 100755 Binary files a/build/bootstrap/zipobj.com and b/build/bootstrap/zipobj.com differ diff --git a/libc/calls/read-nt.c b/libc/calls/read-nt.c index e1c86084e..024acb67b 100644 --- a/libc/calls/read-nt.c +++ b/libc/calls/read-nt.c @@ -26,35 +26,37 @@ #include "libc/nt/struct/overlapped.h" #include "libc/sysv/errfuns.h" +static textwindows ssize_t sys_read_nt_impl(struct Fd *fd, void *data, + size_t size, ssize_t offset) { + uint32_t got; + struct NtOverlapped overlap; + if (ReadFile(fd->handle, data, clampio(size), &got, + offset2overlap(offset, &overlap))) { + return got; + } else if (GetLastError() == kNtErrorBrokenPipe) { + return 0; + } else { + return __winerr(); + } +} + textwindows ssize_t sys_read_nt(struct Fd *fd, const struct iovec *iov, size_t iovlen, ssize_t opt_offset) { + ssize_t rc; + uint32_t size; size_t i, total; - uint32_t got, size; - struct NtOverlapped overlap; while (iovlen && !iov[0].iov_len) iov++, iovlen--; if (iovlen) { for (total = i = 0; i < iovlen; ++i) { - size = clampio(iov[i].iov_len); - if (ReadFile(fd->handle, iov[i].iov_base, size, &got, - offset2overlap(opt_offset, &overlap))) { - total += got; - if (opt_offset != -1) opt_offset += got; - if (got < iov[i].iov_len) break; - } else if (GetLastError() == kNtErrorBrokenPipe) { - break; /* read() doesn't EPIPE lool */ - } else { - return __winerr(); - } + if (!iov[i].iov_len) continue; + rc = sys_read_nt_impl(fd, iov[i].iov_base, iov[i].iov_len, opt_offset); + if (rc == -1) return -1; + total += rc; + if (opt_offset != -1) opt_offset += rc; + if (rc < iov[i].iov_len) break; } return total; } else { - if (ReadFile(fd->handle, NULL, 0, &got, - offset2overlap(opt_offset, &overlap))) { - return got; - } else if (GetLastError() == kNtErrorBrokenPipe) { - return 0; - } else { - return __winerr(); - } + return sys_read_nt_impl(fd, NULL, 0, opt_offset); } } diff --git a/libc/calls/write-nt.c b/libc/calls/write-nt.c index c2ebb80a9..5ae5a59b0 100644 --- a/libc/calls/write-nt.c +++ b/libc/calls/write-nt.c @@ -25,8 +25,22 @@ #include "libc/nt/struct/overlapped.h" #include "libc/sysv/errfuns.h" +static textwindows ssize_t sys_write_nt_impl(struct Fd *fd, void *data, + size_t size, ssize_t offset) { + uint32_t sent; + struct NtOverlapped overlap; + if (WriteFile(fd->handle, data, clampio(size), &sent, + offset2overlap(offset, &overlap))) { + /* TODO(jart): Trigger SIGPIPE on kNtErrorBrokenPipe */ + return sent; + } else { + return __winerr(); + } +} + textwindows ssize_t sys_write_nt(struct Fd *fd, const struct iovec *iov, size_t iovlen, ssize_t opt_offset) { + ssize_t rc; size_t i, total; uint32_t size, wrote; struct NtOverlapped overlap; @@ -34,15 +48,11 @@ textwindows ssize_t sys_write_nt(struct Fd *fd, const struct iovec *iov, if (iovlen) { for (total = i = 0; i < iovlen; ++i) { if (!iov[i].iov_len) continue; - size = clampio(iov[0].iov_len); - if (WriteFile(fd->handle, iov[i].iov_base, size, &wrote, - offset2overlap(opt_offset, &overlap))) { - total += wrote; - if (opt_offset != -1) opt_offset += wrote; - if (wrote < iov[i].iov_len) break; - } else { - return __winerr(); - } + rc = sys_write_nt_impl(fd, iov[i].iov_base, iov[i].iov_len, opt_offset); + if (rc == -1) return -1; + total += rc; + if (opt_offset != -1) opt_offset += rc; + if (rc < iov[i].iov_len) break; } if (!total) assert(!__iovec_size(iov, iovlen)); return total; diff --git a/test/libc/calls/writev_test.c b/test/libc/calls/writev_test.c new file mode 100644 index 000000000..0c712743a --- /dev/null +++ b/test/libc/calls/writev_test.c @@ -0,0 +1,70 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2021 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/calls.h" +#include "libc/calls/struct/iovec.h" +#include "libc/errno.h" +#include "libc/macros.internal.h" +#include "libc/sock/sock.h" +#include "libc/sysv/consts/o.h" +#include "libc/testlib/testlib.h" + +char testlib_enable_tmp_setup_teardown; + +TEST(writev, test) { + int fd; + char ba[1] = "a"; + char bb[1] = "b"; + char bc[2] = "cd"; + struct iovec iov[] = {{"", 0}, {ba, 1}, {NULL, 0}, {bb, 1}, {bc, 2}}; + ASSERT_NE(-1, (fd = open("file", O_RDWR | O_CREAT | O_TRUNC, 0644))); + EXPECT_EQ(4, writev(fd, iov, ARRAYLEN(iov))); + EXPECT_EQ(1, lseek(fd, 1, SEEK_SET)); + EXPECT_EQ(3, readv(fd, iov, ARRAYLEN(iov))); + EXPECT_EQ('b', ba[0]); + EXPECT_EQ('c', bb[0]); + EXPECT_EQ('d', bc[0]); + EXPECT_NE(-1, close(fd)); +} + +TEST(writev, big_fullCompletion) { + int fd; + char *ba = malloc(2 * 1024 * 1024); + char *bb = malloc(2 * 1024 * 1024); + char *bc = malloc(2 * 1024 * 1024); + struct iovec iov[] = { + {"", 0}, // + {ba, 2 * 1024 * 1024}, // + {NULL, 0}, // + {bb, 2 * 1024 * 1024}, // + {bc, 2 * 1024 * 1024}, // + }; + ASSERT_NE(-1, (fd = open("file", O_RDWR | O_CREAT | O_TRUNC, 0644))); + EXPECT_EQ(6 * 1024 * 1024, writev(fd, iov, ARRAYLEN(iov))); + EXPECT_NE(-1, close(fd)); +} + +TEST(writev, empty_stillPerformsIoOperation) { + int fd; + struct iovec iov[] = {{"", 0}, {NULL, 0}}; + ASSERT_NE(-1, touch("file", 0644)); + ASSERT_NE(-1, (fd = open("file", O_RDONLY))); + EXPECT_EQ(-1, writev(fd, iov, ARRAYLEN(iov))); + EXPECT_EQ(-1, writev(fd, NULL, 0)); + EXPECT_NE(-1, close(fd)); +} diff --git a/test/libc/stdio/spawn_test.c b/test/libc/stdio/spawn_test.c index b03c8c9ff..c834a6a9c 100644 --- a/test/libc/stdio/spawn_test.c +++ b/test/libc/stdio/spawn_test.c @@ -61,7 +61,7 @@ const char kTinyLinuxExit[128] = { 0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, // ⌂ELF☻☺☺  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //          0x02, 0x00, 0x3e, 0x00, 0x01, 0x00, 0x00, 0x00, // ☻ > ☺    - 0x78, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, // x @      + 0x78, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, // x @      0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // @        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //          0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x38, 0x00, //     @ 8