diff options
| author | Kacper <kacper@mail.openlinux.dev> | 2025-12-07 20:10:31 +0100 |
|---|---|---|
| committer | Kacper <kacper@mail.openlinux.dev> | 2025-12-07 20:10:31 +0100 |
| commit | fc00c656c96528112d05cf0edf8631bd5eaea446 (patch) | |
| tree | a6e0e6c588191a8bd1c64afc3b7a258e3e66c236 /lib/libc/uio/readv.c | |
Add build system scaffolding and libc headers
Diffstat (limited to 'lib/libc/uio/readv.c')
| -rw-r--r-- | lib/libc/uio/readv.c | 55 |
1 files changed, 55 insertions, 0 deletions
diff --git a/lib/libc/uio/readv.c b/lib/libc/uio/readv.c new file mode 100644 index 00000000..8a2d9216 --- /dev/null +++ b/lib/libc/uio/readv.c @@ -0,0 +1,55 @@ +#include <unistd.h> +#include <linux/uio.h> +#include <syscall.h> +#include <errno.h> +#include <string.h> + +ssize_t readv(int fd, const struct iovec *iov, int iovcnt) +{ + ssize_t total = 0; + + if (iovcnt == 0) { + return 0; + } + + if (iovcnt < 0) { + errno = EINVAL; + return -1; + } + + while (iovcnt > 0) { + int chunk = iovcnt > UIO_MAXIOV ? UIO_MAXIOV : iovcnt; + + struct iovec local[UIO_MAXIOV]; + memcpy(local, iov, chunk * sizeof(struct iovec)); + + ssize_t ret = syscall(readv, fd, local, chunk); + if (ret < 0) { + if (total > 0 && (errno == EAGAIN || errno == EINTR)) + return total; + return ret; + } + if (ret == 0) + break; // EOF + + total += ret; + + ssize_t remaining = ret; + while (remaining > 0 && iovcnt > 0) { + if ((size_t)remaining >= iov->iov_len) { + remaining -= iov->iov_len; + iov++; + iovcnt--; + } else { + struct iovec tmp = *iov; + tmp.iov_base = (char *)tmp.iov_base + remaining; + tmp.iov_len -= remaining; + memcpy(local, &tmp, sizeof(tmp)); + remaining = 0; + break; + } + } + } + + return total; +} |
