Author: asomers Date: Fri Sep 11 20:49:36 2020 New Revision: 365643 URL: https://svnweb.freebsd.org/changeset/base/365643
Log: cp: fall back to read/write if copy_file_range fails Even though copy_file_range has a file-system agnostic version, it still fails on devfs (perhaps because the file descriptor is non-seekable?) In that case, fallback to old-fashioned read/write. Fixes "cp /dev/null /tmp/null" PR: 249248 Reported by: Michael Butler Reviewed by: mjg MFC-With: 365549 Differential Revision: https://reviews.freebsd.org/D26395 Modified: head/bin/cp/utils.c Modified: head/bin/cp/utils.c ============================================================================== --- head/bin/cp/utils.c Fri Sep 11 20:32:40 2020 (r365642) +++ head/bin/cp/utils.c Fri Sep 11 20:49:36 2020 (r365643) @@ -74,6 +74,26 @@ __FBSDID("$FreeBSD$"); */ #define BUFSIZE_SMALL (MAXPHYS) +static int +copy_fallback(int from_fd, int to_fd, char *buf, size_t bufsize) +{ + int rcount; + ssize_t wresid, wcount = 0; + char *bufp; + + rcount = read(from_fd, buf, bufsize); + if (rcount <= 0) + return (rcount); + for (bufp = buf, wresid = rcount; ; bufp += wcount, wresid -= wcount) { + wcount = write(to_fd, bufp, wresid); + if (wcount <= 0) + break; + if (wcount >= (ssize_t)wresid) + break; + } + return (wcount < 0 ? wcount : rcount); +} + int copy_file(const FTSENT *entp, int dne) { @@ -88,6 +108,7 @@ copy_file(const FTSENT *entp, int dne) #ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED char *p; #endif + int use_copy_file_range = 1; from_fd = to_fd = -1; if (!lflag && !sflag && @@ -212,9 +233,19 @@ copy_file(const FTSENT *entp, int dne) err(1, "Not enough memory"); } wtotal = 0; - while ((rcount = copy_file_range(from_fd, NULL, - to_fd, NULL, bufsize, 0)) > 0) - { + do { + if (use_copy_file_range) { + rcount = copy_file_range(from_fd, NULL, + to_fd, NULL, bufsize, 0); + if (rcount < 0 && errno == EINVAL) { + /* Prob a non-seekable FD */ + use_copy_file_range = 0; + } + } + if (!use_copy_file_range) { + rcount = copy_fallback(from_fd, to_fd, + buf, bufsize); + } wtotal += rcount; if (info) { info = 0; @@ -223,7 +254,7 @@ copy_file(const FTSENT *entp, int dne) entp->fts_path, to.p_path, cp_pct(wtotal, fs->st_size)); } - } + } while (rcount > 0); if (rcount < 0) { warn("%s", entp->fts_path); rval = 1; _______________________________________________ svn-src-head@freebsd.org mailing list https://lists.freebsd.org/mailman/listinfo/svn-src-head To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"