summaryrefslogtreecommitdiff
path: root/bin/cp
diff options
context:
space:
mode:
authorTed Unangst <tedu@cvs.openbsd.org>2007-04-06 06:50:01 +0000
committerTed Unangst <tedu@cvs.openbsd.org>2007-04-06 06:50:01 +0000
commit6b0096fa8cd214ebd47963815eca5df17a7fb9c0 (patch)
treeb0c8ea05fafadde1b1742080c7fc5d92844f7e70 /bin/cp
parentae4bd25363a42e533d1655f3f8676a5ce572624f (diff)
when copying regular files, look for blocks of zeroes. when we see them,
just lseek ahead to create a sparse file. saves disk and time. note this behavior in the man page. ok? deraadt millert
Diffstat (limited to 'bin/cp')
-rw-r--r--bin/cp/cp.16
-rw-r--r--bin/cp/utils.c30
2 files changed, 31 insertions, 5 deletions
diff --git a/bin/cp/cp.1 b/bin/cp/cp.1
index 3c7a7ac6bc3..66702981e63 100644
--- a/bin/cp/cp.1
+++ b/bin/cp/cp.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: cp.1,v 1.25 2004/12/10 10:23:30 jmc Exp $
+.\" $OpenBSD: cp.1,v 1.26 2007/04/06 06:50:00 tedu Exp $
.\" $NetBSD: cp.1,v 1.9 1995/07/25 19:36:45 jtc Exp $
.\"
.\" Copyright (c) 1989, 1990, 1993, 1994
@@ -166,6 +166,10 @@ conditions must be fulfilled or both bits are removed.
.Pp
Appropriate permissions are required for file creation or overwriting.
.Pp
+When a file containing large blocks of zero-valued bytes is copied,
+.Nm
+will attempt to create a sparse file.
+.Pp
Symbolic links are always followed unless the
.Fl R
flag is set, in which case symbolic links are not followed, by default.
diff --git a/bin/cp/utils.c b/bin/cp/utils.c
index 7e1185fd48b..fa62660fe76 100644
--- a/bin/cp/utils.c
+++ b/bin/cp/utils.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: utils.c,v 1.26 2004/12/10 10:23:30 jmc Exp $ */
+/* $OpenBSD: utils.c,v 1.27 2007/04/06 06:50:00 tedu Exp $ */
/* $NetBSD: utils.c,v 1.6 1997/02/26 14:40:51 cgd Exp $ */
/*-
@@ -34,7 +34,7 @@
#if 0
static char sccsid[] = "@(#)utils.c 8.3 (Berkeley) 4/1/94";
#else
-static char rcsid[] = "$OpenBSD: utils.c,v 1.26 2004/12/10 10:23:30 jmc Exp $";
+static char rcsid[] = "$OpenBSD: utils.c,v 1.27 2007/04/06 06:50:00 tedu Exp $";
#endif
#endif /* not lint */
@@ -57,13 +57,26 @@ static char rcsid[] = "$OpenBSD: utils.c,v 1.26 2004/12/10 10:23:30 jmc Exp $";
int
copy_file(FTSENT *entp, int dne)
{
- static char buf[MAXBSIZE];
+ static char *buf;
+ static char *zeroes;
struct stat to_stat, *fs;
int ch, checkch, from_fd, rcount, rval, to_fd, wcount;
#ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED
char *p;
#endif
+ if (!buf) {
+ buf = malloc(MAXBSIZE);
+ if (!buf)
+ err(1, "malloc");
+ }
+ if (!zeroes) {
+ zeroes = malloc(MAXBSIZE);
+ if (!zeroes)
+ err(1, "malloc");
+ memset(zeroes, 0, MAXBSIZE);
+ }
+
if ((from_fd = open(entp->fts_path, O_RDONLY, 0)) == -1) {
warn("%s", entp->fts_path);
return (1);
@@ -136,14 +149,23 @@ copy_file(FTSENT *entp, int dne)
} else
#endif
{
+ int skipholes = 0;
+ struct stat tosb;
+ if (!fstat(to_fd, &tosb) && S_ISREG(tosb.st_mode))
+ skipholes = 1;
while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) {
- wcount = write(to_fd, buf, rcount);
+ if (skipholes && memcmp(buf, zeroes, rcount) == 0)
+ wcount = lseek(to_fd, rcount, SEEK_CUR) == -1 ? -1 : rcount;
+ else
+ wcount = write(to_fd, buf, rcount);
if (rcount != wcount || wcount == -1) {
warn("%s", to.p_path);
rval = 1;
break;
}
}
+ if (skipholes && rcount >= 0)
+ rcount = ftruncate(to_fd, fs->st_size);
if (rcount < 0) {
warn("%s", entp->fts_path);
rval = 1;