aboutsummaryrefslogtreecommitdiffstats
path: root/safe_rw.c
diff options
context:
space:
mode:
Diffstat (limited to 'safe_rw.c')
-rw-r--r--safe_rw.c81
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;
+}