[PATCH] adding two new options to 'cp'

Eric Anderson anderson at centtech.com
Thu Jul 27 02:51:36 UTC 2006


I'm tired of trying to use rsync or gcp (which doesn't like symlinks 
often) to copy trees of files/directories using hard links, so I added 
the gcp-ish options -a and -l.

-a is 'archive' mode, which is just a quick form of -PpR.
-l is 'link' mode, where regular files get hard linked instead of copied.

So, you can mimic an entire tree with something like:

cp -al /from/ /to/

and it's fast too!

Patch is against 6-STABLE, but works well on 7-CURRENT as well.

Patch is here (with man page edits):
http://www.googlebit.com/freebsd/patches/cp-patch

cd /tmp/
fetch http://www.googlebit.com/freebsd/patches/cp-patch
cd /usr/src/
patch < /tmp/cp-patch
cd bin/cp
make && make install

Patch was done for rsnapshot users mainly (there are quite a few of us).

Comments? Flames? Committers willing to commit?

Eric


-- 
------------------------------------------------------------------------
Eric Anderson        Sr. Systems Administrator        Centaur Technology
Anything that works is better than anything that doesn't.
------------------------------------------------------------------------
-------------- next part --------------
Index: bin/cp/cp.1
===================================================================
RCS file: /alt/ncvs/src/bin/cp/cp.1,v
retrieving revision 1.33
diff -u -u -r1.33 cp.1
--- bin/cp/cp.1	25 Feb 2005 00:40:46 -0000	1.33
+++ bin/cp/cp.1	26 Jul 2006 19:52:42 -0000
@@ -45,7 +45,7 @@
 .Op Fl H | Fl L | Fl P
 .Oc
 .Op Fl f | i | n
-.Op Fl pv
+.Op Fl aplv
 .Ar source_file target_file
 .Nm
 .Oo
@@ -53,7 +53,7 @@
 .Op Fl H | Fl L | Fl P
 .Oc
 .Op Fl f | i | n
-.Op Fl pv
+.Op Fl aplv
 .Ar source_file ... target_directory
 .Sh DESCRIPTION
 In the first synopsis form, the
@@ -116,6 +116,10 @@
 or
 .Xr pax 1
 instead.
+.It Fl a
+Archive mode.  Same as -PpR
+.It Fl l
+Create hard links to regular files instead of copying.
 .It Fl f
 For each existing destination pathname, remove it and
 create a new file, without prompting for confirmation
Index: bin/cp/cp.c
===================================================================
RCS file: /alt/ncvs/src/bin/cp/cp.c,v
retrieving revision 1.51.2.1
diff -u -u -r1.51.2.1 cp.c
--- bin/cp/cp.c	12 Nov 2005 21:21:45 -0000	1.51.2.1
+++ bin/cp/cp.c	26 Jul 2006 17:49:55 -0000
@@ -83,7 +83,7 @@
 
 PATH_T to = { to.p_path, emptystring, "" };
 
-int fflag, iflag, nflag, pflag, vflag;
+int fflag, iflag, lflag, nflag, pflag, vflag;
 static int Rflag, rflag;
 volatile sig_atomic_t info;
 
@@ -102,7 +102,7 @@
 	char *target;
 
 	Hflag = Lflag = Pflag = 0;
-	while ((ch = getopt(argc, argv, "HLPRfinprv")) != -1)
+	while ((ch = getopt(argc, argv, "HLPRfinprvla")) != -1)
 		switch (ch) {
 		case 'H':
 			Hflag = 1;
@@ -140,6 +140,15 @@
 		case 'v':
 			vflag = 1;
 			break;
+		case 'l':
+			lflag = 1;
+			break;
+		case 'a':
+			Pflag = 1;
+			pflag = 1;
+			Rflag = 1;
+			Hflag = Lflag = 0;
+			break;
 		default:
 			usage();
 			break;
Index: bin/cp/extern.h
===================================================================
RCS file: /alt/ncvs/src/bin/cp/extern.h,v
retrieving revision 1.19.8.1
diff -u -u -r1.19.8.1 extern.h
--- bin/cp/extern.h	12 Nov 2005 21:21:45 -0000	1.19.8.1
+++ bin/cp/extern.h	26 Jul 2006 17:49:55 -0000
@@ -37,7 +37,7 @@
 } PATH_T;
 
 extern PATH_T to;
-extern int fflag, iflag, nflag, pflag, vflag;
+extern int fflag, iflag, lflag, nflag, pflag, vflag;
 extern volatile sig_atomic_t info;
 
 __BEGIN_DECLS
Index: bin/cp/utils.c
===================================================================
RCS file: /alt/ncvs/src/bin/cp/utils.c,v
retrieving revision 1.45.2.1
diff -u -u -r1.45.2.1 utils.c
--- bin/cp/utils.c	12 Nov 2005 21:21:45 -0000	1.45.2.1
+++ bin/cp/utils.c	26 Jul 2006 19:39:09 -0000
@@ -61,7 +61,7 @@
 {
 	static char buf[MAXBSIZE];
 	struct stat *fs;
-	int ch, checkch, from_fd, rcount, rval, to_fd;
+	int ch, checkch, from_fd = 0, rcount, rval, to_fd = 0;
 	ssize_t wcount;
 	size_t wresid;
 	size_t wtotal;
@@ -109,15 +109,20 @@
 		    /* remove existing destination file name, 
 		     * create a new file  */
 		    (void)unlink(to.p_path);
-		    to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT,
-				 fs->st_mode & ~(S_ISUID | S_ISGID));
-		} else 
-		    /* overwrite existing destination file name */
-		    to_fd = open(to.p_path, O_WRONLY | O_TRUNC, 0);
-	} else
-		to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT,
-		    fs->st_mode & ~(S_ISUID | S_ISGID));
-
+				if (!lflag)
+		    	to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT,
+				  fs->st_mode & ~(S_ISUID | S_ISGID));
+		} else {
+				if (!lflag)
+		    	/* overwrite existing destination file name */
+		    	to_fd = open(to.p_path, O_WRONLY | O_TRUNC, 0);
+		}
+	} else {
+		if (!lflag)
+			to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT,
+		  fs->st_mode & ~(S_ISUID | S_ISGID));
+	}
+	
 	if (to_fd == -1) {
 		warn("%s", to.p_path);
 		(void)close(from_fd);
@@ -126,73 +131,81 @@
 
 	rval = 0;
 
-	/*
-	 * Mmap and write if less than 8M (the limit is so we don't totally
-	 * trash memory on big files.  This is really a minor hack, but it
-	 * wins some CPU back.
-	 */
+	if (!lflag) {
+		/*
+		 * Mmap and write if less than 8M (the limit is so we don't totally
+		 * trash memory on big files.  This is really a minor hack, but it
+		 * wins some CPU back.
+		 */
 #ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED
-	if (S_ISREG(fs->st_mode) && fs->st_size > 0 &&
-	    fs->st_size <= 8 * 1048576) {
-		if ((p = mmap(NULL, (size_t)fs->st_size, PROT_READ,
-		    MAP_SHARED, from_fd, (off_t)0)) == MAP_FAILED) {
-			warn("%s", entp->fts_path);
-			rval = 1;
-		} else {
-			wtotal = 0;
-			for (bufp = p, wresid = fs->st_size; ;
-			    bufp += wcount, wresid -= (size_t)wcount) {
-				wcount = write(to_fd, bufp, wresid);
-				wtotal += wcount;
-				if (info) {
-					info = 0;
-					(void)fprintf(stderr,
-						"%s -> %s %3d%%\n",
-						entp->fts_path, to.p_path,
-						cp_pct(wtotal, fs->st_size));
-						
-				}
-				if (wcount >= (ssize_t)wresid || wcount <= 0)
-					break;
-			}
-			if (wcount != (ssize_t)wresid) {
-				warn("%s", to.p_path);
-				rval = 1;
-			}
-			/* Some systems don't unmap on close(2). */
-			if (munmap(p, fs->st_size) < 0) {
+		if (S_ISREG(fs->st_mode) && fs->st_size > 0 &&
+	    	fs->st_size <= 8 * 1048576) {
+			if ((p = mmap(NULL, (size_t)fs->st_size, PROT_READ,
+		    	MAP_SHARED, from_fd, (off_t)0)) == MAP_FAILED) {
 				warn("%s", entp->fts_path);
 				rval = 1;
+			} else {
+				wtotal = 0;
+				for (bufp = p, wresid = fs->st_size; ;
+			    	bufp += wcount, wresid -= (size_t)wcount) {
+					wcount = write(to_fd, bufp, wresid);
+					wtotal += wcount;
+					if (info) {
+						info = 0;
+						(void)fprintf(stderr,
+							"%s -> %s %3d%%\n",
+							entp->fts_path, to.p_path,
+							cp_pct(wtotal, fs->st_size));
+
+					}
+					if (wcount >= (ssize_t)wresid || wcount <= 0)
+						break;
+				}
+				if (wcount != (ssize_t)wresid) {
+					warn("%s", to.p_path);
+					rval = 1;
+				}
+				/* Some systems don't unmap on close(2). */
+				if (munmap(p, fs->st_size) < 0) {
+					warn("%s", entp->fts_path);
+					rval = 1;
+				}
 			}
-		}
-	} else
+		} else
 #endif
-	{
-		wtotal = 0;
-		while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) {
-			for (bufp = buf, wresid = rcount; ;
-			    bufp += wcount, wresid -= wcount) {
-				wcount = write(to_fd, bufp, wresid);
-				wtotal += wcount;
-				if (info) {
-					info = 0;
-					(void)fprintf(stderr,
-						"%s -> %s %3d%%\n",
-						entp->fts_path, to.p_path,
-						cp_pct(wtotal, fs->st_size));
-						
+		{
+			wtotal = 0;
+			while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) {
+				for (bufp = buf, wresid = rcount; ;
+			    	bufp += wcount, wresid -= wcount) {
+					wcount = write(to_fd, bufp, wresid);
+					wtotal += wcount;
+					if (info) {
+						info = 0;
+						(void)fprintf(stderr,
+							"%s -> %s %3d%%\n",
+							entp->fts_path, to.p_path,
+							cp_pct(wtotal, fs->st_size));
+
+					}
+					if (wcount >= (ssize_t)wresid || wcount <= 0)
+						break;
 				}
-				if (wcount >= (ssize_t)wresid || wcount <= 0)
+				if (wcount != (ssize_t)wresid) {
+					warn("%s", to.p_path);
+					rval = 1;
 					break;
+				}
 			}
-			if (wcount != (ssize_t)wresid) {
-				warn("%s", to.p_path);
+			if (rcount < 0) {
+				warn("%s", entp->fts_path);
 				rval = 1;
-				break;
 			}
 		}
-		if (rcount < 0) {
-			warn("%s", entp->fts_path);
+	} else {
+		if (link(entp->fts_path, to.p_path)) {
+			(void)close(from_fd);
+			warn("%s", to.p_path);
 			rval = 1;
 		}
 	}
@@ -204,14 +217,16 @@
 	 * to remove it if we created it and its length is 0.
 	 */
 
-	if (pflag && setfile(fs, to_fd))
-		rval = 1;
-	if (pflag && preserve_fd_acls(from_fd, to_fd) != 0)
-		rval = 1;
-	(void)close(from_fd);
-	if (close(to_fd)) {
-		warn("%s", to.p_path);
-		rval = 1;
+	if (!lflag) {
+		if (pflag && setfile(fs, to_fd))
+			rval = 1;
+		if (pflag && preserve_fd_acls(from_fd, to_fd) != 0)
+			rval = 1;
+		(void)close(from_fd);
+		if (close(to_fd)) {
+			warn("%s", to.p_path);
+			rval = 1;
+		}
 	}
 	return (rval);
 }
Index: etc/mtree/BSD.include.dist
===================================================================
RCS file: /alt/ncvs/src/etc/mtree/BSD.include.dist,v
retrieving revision 1.100.2.2
diff -u -u -r1.100.2.2 BSD.include.dist
--- etc/mtree/BSD.include.dist	16 Nov 2005 10:50:10 -0000	1.100.2.2
+++ etc/mtree/BSD.include.dist	26 Jul 2006 03:42:10 -0000
@@ -100,6 +100,8 @@
         ..
         gate
         ..
+        journal
+        ..
         label
         ..
         mirror
Index: include/Makefile
===================================================================
RCS file: /alt/ncvs/src/include/Makefile,v
retrieving revision 1.244.2.4
diff -u -u -r1.244.2.4 Makefile
--- include/Makefile	17 Jul 2006 10:09:54 -0000	1.244.2.4
+++ include/Makefile	26 Jul 2006 03:42:10 -0000
@@ -42,8 +42,8 @@
 	fs/devfs fs/fdescfs fs/fifofs fs/msdosfs fs/ntfs fs/nullfs \
 	fs/nwfs fs/portalfs fs/procfs fs/smbfs fs/udf fs/umapfs \
 	fs/unionfs \
-	geom/concat geom/eli geom/gate geom/label geom/mirror geom/nop \
-	geom/raid3 geom/shsec geom/stripe \
+	geom/concat geom/eli geom/gate geom/journal geom/label geom/mirror \
+	geom/nop geom/raid3 geom/shsec geom/stripe \
 	isofs/cd9660 \
 	netatm/ipatm netatm/sigpvc netatm/spans netatm/uni \
 	netgraph/atm netgraph/netflow \


More information about the freebsd-hackers mailing list