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:
parent
71fa736277
commit
e25a93032f
2 changed files with 86 additions and 0 deletions
84
util.c
84
util.c
|
@ -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
2
util.h
|
@ -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, ...);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue