src/: +streamfer*
[nethome.git] / src / safeio.C
diff --git a/src/safeio.C b/src/safeio.C
new file mode 100644 (file)
index 0000000..fb76743
--- /dev/null
@@ -0,0 +1,87 @@
+#include "safeio.h"
+#include <sys/uio.h>
+
+const SafeIOError exception_SafeIOError;
+const SafeIOEOF   exception_SafeIOEOF  ;
+
+void read_safe(int fd,void *buf,size_t size) {
+  assert(size>0);
+  while (size>0) {
+    const ssize_t got(read(fd,buf,size));
+    assert(got>=-1);
+    if (got<=0) {
+      warning("read_safe: fd=%d size=%zu: %s",fd,size,(got==0?"EOF":strerror(errno)));
+      // Do not throw ?exc1:exc2 as it would get upcasted.
+      if (got==0||(got==-1&&errno==ECONNRESET))
+       throw exception_SafeIOEOF;
+      throw exception_SafeIOError;
+    }
+    assert(size_t(got)<=size);
+    buf=static_cast<uint8_t *>(buf)+got;
+    size-=got;
+  }
+}
+
+void read_safe(FILE *f,void *buf,size_t size) {
+  assert(size>0);
+  assert(!ferror(f));
+  assert(!feof(f));
+  const size_t got(fread(buf,1/*size*/,size/*nmemb*/,f));
+  if (ferror(f)||feof(f)) {
+    warning("read_safe: fd=%d size=%zu: %s",fileno(f),size,(ferror(f)?"error":"EOF"));
+    // Do not throw ?exc1:exc2 as it would get upcasted.
+    if (ferror(f))
+      throw exception_SafeIOError;
+    throw exception_SafeIOEOF;
+  }
+  // return [...] which is less than nitems only if a read error or end-of-file is encountered.
+  if (size_t(got)!=size) {
+    warning("read_safe: fd=%d size=%zu got=%zu",fileno(f),size,got);
+    throw exception_SafeIOError;
+  }
+}
+
+void write_safe(int fd,const void *buf,size_t size) {
+  assert(size>0);
+  const ssize_t got(write(fd,buf,size));
+  if (got==-1) {
+    warning("Error writing %zu to fd %d: %m",size,fd);
+    throw exception_SafeIOError;
+  }
+  assert(got>0);
+  if (size_t(got)!=size) {
+    warning("Wrote only %zd of %zu to fd %d",got,size,fd);
+    throw exception_SafeIOEOF;
+  }
+}
+
+void write_safe(FILE *f,const void *buf,size_t size) {
+  assert(size>0);
+  assert(!ferror(f));
+  const size_t got(fwrite(buf,1/*size*/,size/*nmemb*/,f));
+  if (ferror(f)) {
+    warning("Error writing %zu to FILE * of fd %d",size,fileno(f));
+    throw exception_SafeIOError;
+  }
+  if (got!=size) {
+    warning("Wrote only %zu of %zu to FILE * of fd %d",got,size,fileno(f));
+    throw exception_SafeIOEOF;
+  }
+}
+
+void writev_safe_(int fd,const struct iovec *iov, int iovcnt) {
+  size_t size=0;
+  for (int ix=0;ix<iovcnt;++ix)
+    size+=iov[ix].iov_len;
+  assert(size>0);
+  const ssize_t got(writev(fd,iov,iovcnt));
+  if (got==-1) {
+    warning("Error writing %zu iovec to fd %d: %m",size,fd);
+    throw exception_SafeIOError;
+  }
+  assert(got>0);
+  if (size_t(got)!=size) {
+    warning("Wrote only %zd of %zu iovec to fd %d",got,size,fd);
+    throw exception_SafeIOEOF;
+  }
+}