1
0
Fork 0
mirror of https://passt.top/passt synced 2025-06-15 20:05:34 +02:00

util: Add read_remainder() and read_all_buf()

These are symmetric to write_remainder() and write_all_buf() and
almost a copy and paste of them, with the most notable differences
being reversed reads/writes and a couple of better-safe-than-sorry
asserts to keep Coverity happy.

I'll use them in the next patch. At least for the moment, they're
going to be used for vhost-user mode only, so I'm not unconditionally
enabling readv() in the seccomp profile: the caller has to ensure it's
there.

[dgibson: make read_remainder() take const pointer to iovec]
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
This commit is contained in:
Stefano Brivio 2025-01-26 09:05:03 +01:00
parent 71fa736277
commit e25a93032f
2 changed files with 86 additions and 0 deletions

84
util.c
View file

@ -606,6 +606,90 @@ int write_remainder(int fd, const struct iovec *iov, size_t iovcnt, size_t skip)
return 0;
}
/**
* read_all_buf() - Fill a whole buffer from a file descriptor
* @fd: File descriptor
* @buf: Pointer to base of buffer
* @len: Length of buffer
*
* Return: 0 on success, -1 on error (with errno set)
*
* #syscalls read
*/
int read_all_buf(int fd, void *buf, size_t len)
{
size_t left = len;
char *p = buf;
while (left) {
ssize_t rc;
ASSERT(left <= len);
do
rc = read(fd, p, left);
while ((rc < 0) && errno == EINTR);
if (rc < 0)
return -1;
if (rc == 0) {
errno = ENODATA;
return -1;
}
p += rc;
left -= rc;
}
return 0;
}
/**
* read_remainder() - Read the tail of an IO vector from a file descriptor
* @fd: File descriptor
* @iov: IO vector
* @cnt: Number of entries in @iov
* @skip: Number of bytes of the vector to skip reading
*
* Return: 0 on success, -1 on error (with errno set)
*
* Note: mode-specific seccomp profiles need to enable readv() to use this.
*/
/* cppcheck-suppress unusedFunction */
int read_remainder(int fd, const struct iovec *iov, size_t cnt, size_t skip)
{
size_t i = 0, offset;
while ((i += iov_skip_bytes(iov + i, cnt - i, skip, &offset)) < cnt) {
ssize_t rc;
if (offset) {
ASSERT(offset < iov[i].iov_len);
/* Read the remainder of the partially read buffer */
if (read_all_buf(fd, (char *)iov[i].iov_base + offset,
iov[i].iov_len - offset) < 0)
return -1;
i++;
}
if (cnt == i)
break;
/* Fill as many of the remaining buffers as we can */
rc = readv(fd, &iov[i], cnt - i);
if (rc < 0)
return -1;
if (rc == 0) {
errno = ENODATA;
return -1;
}
skip = rc;
}
return 0;
}
/** sockaddr_ntop() - Convert a socket address to text format
* @sa: Socket address
* @dst: output buffer, minimum SOCKADDR_STRLEN bytes

2
util.h
View file

@ -203,6 +203,8 @@ int fls(unsigned long x);
int write_file(const char *path, const char *buf);
int write_all_buf(int fd, const void *buf, size_t len);
int write_remainder(int fd, const struct iovec *iov, size_t iovcnt, size_t skip);
int read_all_buf(int fd, void *buf, size_t len);
int read_remainder(int fd, const struct iovec *iov, size_t cnt, size_t skip);
void close_open_files(int argc, char **argv);
bool snprintf_check(char *str, size_t size, const char *format, ...);