diff --git a/criu/bfd.c b/criu/bfd.c index 535c4d354..e0d9ede7a 100644 --- a/criu/bfd.c +++ b/criu/bfd.c @@ -145,7 +145,7 @@ static int brefill(struct bfd *f) memmove(b->mem, b->data, b->sz); b->data = b->mem; - ret = read(f->fd, b->mem + b->sz, BUFSIZE - b->sz); + ret = read_all(f->fd, b->mem + b->sz, BUFSIZE - b->sz); if (ret < 0) { pr_perror("Error reading file"); return -1; @@ -241,7 +241,7 @@ static int bflush(struct bfd *bfd) if (!b->sz) return 0; - ret = write(bfd->fd, b->data, b->sz); + ret = write_all(bfd->fd, b->data, b->sz); if (ret != b->sz) return -1; @@ -261,7 +261,7 @@ static int __bwrite(struct bfd *bfd, const void *buf, int size) } if (size > BUFSIZE) - return write(bfd->fd, buf, size); + return write_all(bfd->fd, buf, size); memcpy(b->data + b->sz, buf, size); b->sz += size; @@ -271,7 +271,7 @@ static int __bwrite(struct bfd *bfd, const void *buf, int size) int bwrite(struct bfd *bfd, const void *buf, int size) { if (!bfd_buffered(bfd)) - return write(bfd->fd, buf, size); + return write_all(bfd->fd, buf, size); return __bwrite(bfd, buf, size); } @@ -280,8 +280,13 @@ int bwritev(struct bfd *bfd, const struct iovec *iov, int cnt) { int i, written = 0; - if (!bfd_buffered(bfd)) + if (!bfd_buffered(bfd)) { + /* + * FIXME writev() should be called again if writev() writes + * less bytes than requested. + */ return writev(bfd->fd, iov, cnt); + } for (i = 0; i < cnt; i++) { int ret; @@ -304,7 +309,7 @@ int bread(struct bfd *bfd, void *buf, int size) int more = 1, filled = 0; if (!bfd_buffered(bfd)) - return read(bfd->fd, buf, size); + return read_all(bfd->fd, buf, size); while (more > 0) { int chunk; diff --git a/criu/include/util.h b/criu/include/util.h index 039d42f4f..5a6829ed6 100644 --- a/criu/include/util.h +++ b/criu/include/util.h @@ -385,4 +385,7 @@ extern int mount_detached_fs(const char *fsname); extern char *get_legacy_iptables_bin(bool ipv6); +extern ssize_t read_all(int fd, void *buf, size_t size); +extern ssize_t write_all(int fd, const void *buf, size_t size); + #endif /* __CR_UTIL_H__ */ diff --git a/criu/util.c b/criu/util.c index 973553bbc..86bc22e62 100644 --- a/criu/util.c +++ b/criu/util.c @@ -1583,4 +1583,60 @@ char *get_legacy_iptables_bin(bool ipv6) iptables_present[ipv6] = 1; return iptables_bin[ipv6]; -} \ No newline at end of file +} + +/* + * read_all() behaves like read() without the possibility of partial reads. + * Use only with blocking I/O. + */ +ssize_t read_all(int fd, void *buf, size_t size) +{ + ssize_t n = 0; + while (size > 0) { + ssize_t ret = read(fd, buf, size); + if (ret == -1) { + if (errno == EINTR) + continue; + /* + * The caller should use standard read() for + * non-blocking I/O. + */ + if (errno == EAGAIN || errno == EWOULDBLOCK) + errno = EINVAL; + return ret; + } + if (ret == 0) + break; + n += ret; + buf = (char *)buf + ret; + size -= ret; + } + return n; +} + +/* + * write_all() behaves like write() without the possibility of partial writes. + * Use only with blocking I/O. + */ +ssize_t write_all(int fd, const void *buf, size_t size) +{ + ssize_t n = 0; + while (size > 0) { + ssize_t ret = write(fd, buf, size); + if (ret == -1) { + if (errno == EINTR) + continue; + /* + * The caller should use standard write() for + * non-blocking I/O. + */ + if (errno == EAGAIN || errno == EWOULDBLOCK) + errno = EINVAL; + return ret; + } + n += ret; + buf = (char *)buf + ret; + size -= ret; + } + return n; +}