diff --git a/usr.bin/xinstall/tests/install_test.sh b/usr.bin/xinstall/tests/install_test.sh --- a/usr.bin/xinstall/tests/install_test.sh +++ b/usr.bin/xinstall/tests/install_test.sh @@ -512,6 +512,42 @@ atf_check test ! -x testfile } +atf_test_case metalog +metalog_head() { + atf_set "descr" "Test metalog generation" +} +metalog_body() { + atf_check install -M metalog -D dst -m 0755 -d dst + echo ". type=dir mode=0755" >expect + atf_check install -M metalog -D dst -m 0705 -d dst/dir + echo "./dir type=dir mode=0705" >>expect + atf_check -o save:file echo "Hello, world!" + atf_check install -M metalog -D dst -m 0604 file dst/dir + echo "./dir/file type=file mode=0604 size=14" >>expect + atf_check install -M metalog -D dst -lrs dir/file dst/"li nk" + echo "./li\040nk type=link mode=0755 link=dir/file" >>expect + atf_check mtree -f expect -p dst + atf_check -o file:expect cat metalog +} + +atf_test_case digest +digest_head() { + atf_set "descr" "Compute digest while copying" +} +digest_body() { + atf_check mkdir src dst + atf_check -e ignore dd if=/dev/random of=src/file bs=1m count=1 + for alg in md5 rmd160 sha1 sha256 sha512 ; do + rm -f dst/file digest metalog + atf_check -o save:digest $alg -q src/file + atf_check install -M metalog -D dst -h $alg -m 0644 src/file dst + echo -n "./file type=file mode=0644 size=1048576 $alg=" >expect + cat digest >>expect + atf_check cmp src/file dst/file + atf_check -o file:expect cat metalog + done +} + atf_init_test_cases() { atf_add_test_case copy_to_empty atf_add_test_case copy_to_nonexistent @@ -557,4 +593,6 @@ atf_add_test_case set_owner_group_mode atf_add_test_case set_owner_group_mode_unpriv atf_add_test_case set_optional_exec + atf_add_test_case metalog + atf_add_test_case digest } diff --git a/usr.bin/xinstall/xinstall.c b/usr.bin/xinstall/xinstall.c --- a/usr.bin/xinstall/xinstall.c +++ b/usr.bin/xinstall/xinstall.c @@ -140,7 +140,7 @@ static int compare(int, const char *, size_t, int, const char *, size_t, char **); -static char *copy(int, const char *, int, const char *, off_t); +static char *copy(int, const char *, int, const char *); static int create_tempfile(const char *, char *, size_t); static char *quiet_mktemp(char *template); static char *digest_file(const char *); @@ -877,7 +877,7 @@ } if (!stripped) { digestresult = copy(from_fd, from_name, to_fd, - tempfile, from_sb.st_size); + tempfile); } } } @@ -1175,8 +1175,7 @@ * copy from one file to another */ static char * -copy(int from_fd, const char *from_name, int to_fd, const char *to_name, - off_t size) +copy(int from_fd, const char *from_name, int to_fd, const char *to_name) { static char *buf = NULL; static size_t bufsize; @@ -1198,8 +1197,8 @@ if (digesttype == DIGEST_NONE) { do { ret = copy_file_range(from_fd, NULL, to_fd, NULL, - (size_t)size, 0); - } while (ret > 0); + SSIZE_MAX, 0); + } while (ret > 0 || (ret < 0 && errno == EINTR)); if (ret == 0) goto done; if (errno != EINVAL) { @@ -1227,28 +1226,29 @@ if (buf == NULL) err(1, "Not enough memory"); } - while ((nr = read(from_fd, buf, bufsize)) > 0) { - if ((nw = write(to_fd, buf, nr)) != nr) { + for (;;) { + if ((nr = read(from_fd, buf, bufsize)) < 0) { + if (errno == EINTR) + continue; serrno = errno; (void)unlink(to_name); - if (nw >= 0) { - errx(EX_OSERR, - "short write to %s: %jd bytes written, " - "%jd bytes asked to write", - to_name, (uintmax_t)nw, - (uintmax_t)size); - } else { + errno = serrno; + err(EX_OSERR, "%s", from_name); + } + if (nr <= 0) + break; + digest_update(&ctx, buf, nr); + while (nr > 0) { + if ((nw = write(to_fd, buf, nr)) < 0) { + if (errno == EINTR) + continue; + serrno = errno; + (void)unlink(to_name); errno = serrno; err(EX_OSERR, "%s", to_name); } + nr -= nw; } - digest_update(&ctx, buf, nr); - } - if (nr != 0) { - serrno = errno; - (void)unlink(to_name); - errno = serrno; - err(EX_OSERR, "%s", from_name); } #ifndef BOOTSTRAP_XINSTALL done: