diff --git a/libmisc/copydir.c b/libmisc/copydir.c index 90895cfb..95042187 100644 --- a/libmisc/copydir.c +++ b/libmisc/copydir.c @@ -691,6 +691,42 @@ static int copy_special (const char *src, const char *dst, return err; } +/* + * full_write - write entire buffer + * + * Write up to count bytes from the buffer starting at buf to the + * file referred to by the file descriptor fd. + * Retry in case of a short write. + * + * Returns the number of bytes written on success, -1 on error. + */ +static ssize_t full_write(int fd, const void *buf, size_t count) { + ssize_t written = 0; + + while (count > 0) { + ssize_t res; + + res = write(fd, buf, count); + if (res < 0) { + if (errno == EINTR) { + continue; + } + + return res; + } + + if (res == 0) { + break; + } + + written += res; + buf = (const unsigned char*)buf + res; + count -= (size_t)res; + } + + return written; +} + /* * copy_file - copy a file * @@ -710,8 +746,6 @@ static int copy_file (const char *src, const char *dst, int err = 0; int ifd; int ofd; - char buf[1024]; - ssize_t cnt; ifd = open (src, O_RDONLY|O_NOFOLLOW); if (ifd < 0) { @@ -753,8 +787,24 @@ static int copy_file (const char *src, const char *dst, return -1; } - while ((cnt = read (ifd, buf, sizeof buf)) > 0) { - if (write (ofd, buf, (size_t)cnt) != cnt) { + while (true) { + char buf[8192]; + ssize_t cnt; + + cnt = read (ifd, buf, sizeof buf); + if (cnt < 0) { + if (errno == EINTR) { + continue; + } + (void) close (ofd); + (void) close (ifd); + return -1; + } + if (cnt == 0) { + break; + } + + if (full_write (ofd, buf, (size_t)cnt) < 0) { (void) close (ofd); (void) close (ifd); return -1;