diff options
Diffstat (limited to 'safe_rw.c')
| -rw-r--r-- | safe_rw.c | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/safe_rw.c b/safe_rw.c new file mode 100644 index 0000000..683d8b5 --- /dev/null +++ b/safe_rw.c @@ -0,0 +1,81 @@ + +#include <stdlib.h> +#include <sys/types.h> + +#include <assert.h> +#include <errno.h> +#include <limits.h> +#include <poll.h> +#include <unistd.h> + +#ifndef SSIZE_MAX +#define SSIZE_MAX (SIZE_MAX / 2 - 1) +#endif + +#include "safe_rw.h" + +ssize_t +safe_write(const int fd, const void *const buf_, size_t count, + const int timeout) +{ + struct pollfd pfd; + const char * buf = (const char *) buf_; + ssize_t written; + + pfd.fd = fd; + pfd.events = POLLOUT; + + assert(count <= SSIZE_MAX); + while (count > (size_t) 0) { + while ((written = write(fd, buf, count)) <= (ssize_t) 0) { + if (errno == EAGAIN) { + if (poll(&pfd, (nfds_t) 1, timeout) == 0) { + errno = ETIMEDOUT; + goto ret; + } + } else if (errno != EINTR) { + goto ret; + } + } + buf += written; + count -= (size_t) written; + } +ret: + return (ssize_t)(buf - (const char *) buf_); +} + +ssize_t +safe_read(const int fd, void *const buf_, size_t count) +{ + unsigned char *buf = (unsigned char *) buf_; + ssize_t readnb; + + assert(count <= SSIZE_MAX); + do { + while ((readnb = read(fd, buf, count)) < (ssize_t) 0 && errno == EINTR) + ; + if (readnb < (ssize_t) 0) { + return readnb; + } + if (readnb == (ssize_t) 0) { + break; + } + count -= (size_t) readnb; + buf += readnb; + } while (count > (ssize_t) 0); + + return (ssize_t)(buf - (unsigned char *) buf_); +} + +ssize_t +safe_read_partial(const int fd, void *const buf_, const size_t max_count) +{ + unsigned char *const buf = (unsigned char *) buf_; + ssize_t readnb; + + assert(max_count <= SSIZE_MAX); + while ((readnb = read(fd, buf, max_count)) < (ssize_t) 0 && errno == EINTR) + ; + + return readnb; +} |