Commit Diff


commit - 115dbcecc8d35d12b54d17dc1cba39089ad37b5f
commit + 286bb40b76f35ffee1e6789895782af203e0dae3
blob - 7de41ee622c593018db745c48c99576f907efa0e
blob + 3ce718df103aec47e1150743db80b47cf95c2ac6
--- man/man1/vac.1
+++ man/man1/vac.1
@@ -34,7 +34,7 @@ vac, unvac \- create, extract a vac archive on Venti
 .PP
 .B unvac
 [
-.B -Tctv
+.B -Tcdtv
 ] [
 .B -h
 .I host
@@ -207,6 +207,13 @@ to the time listed in the archive.
 .B -c
 Write extracted files to standard output instead of creating a file.
 .TP
+.B -d
+Reduce the number of blocks read from Venti by
+comparing the files to be stored with their counterparts
+in the file system.
+This option cannot be used with
+.BR -c .
+.TP
 .B -t
 Print a list of the files to standard output rather than extracting them.
 .TP
blob - 598dae092b6b3b7a5bfc422cb30be97750952401
blob + faa558f3df96ea9d8aff6b39bb11c77a5f293eb4
--- src/cmd/vac/file.c
+++ src/cmd/vac/file.c
@@ -2060,4 +2060,33 @@ vacfssync(VacFs *fs)
 	if(vtsync(fs->z) < 0)
 		return -1;
 	return 0;
+}
+
+int
+vacfiledsize(VacFile *f)
+{
+	VtEntry e;
+
+	if(vacfilegetentries(f,&e,nil) < 0)
+		return -1;
+	return e.dsize;
 }
+
+/*
+ * Does block b of f have the same SHA1 hash as the n bytes at buf?
+ */
+int
+sha1matches(VacFile *f, ulong b, uchar *buf, int n)
+{
+	uchar fscore[VtScoreSize];
+	uchar bufscore[VtScoreSize];
+	
+	if(vacfileblockscore(f, b, fscore) < 0)
+		return 0;
+	n = vtzerotruncate(VtDataType, buf, n);
+	sha1(buf, n, bufscore, nil);
+	if(memcmp(bufscore, fscore, VtScoreSize) == 0)
+		return 1;
+	return 0;
+}
+
blob - d4f863ccf86053e976b73c6c508b5fc73eef2638
blob + ab799cb0a9b79a31f283b2cc9a1821cc8fb52643
--- src/cmd/vac/unvac.c
+++ src/cmd/vac/unvac.c
@@ -8,6 +8,7 @@
 
 VacFs *fs;
 int tostdout;
+int diff;
 int nwant;
 char **want;
 int *found;
@@ -23,14 +24,20 @@ void unvac(VacFile*, char*, VacDir*);
 void
 usage(void)
 {
-	fprint(2, "usage: unvac [-TVctv] [-h host] file.vac [file ...]\n");
+	fprint(2, "usage: unvac [-TVcdtv] [-h host] file.vac [file ...]\n");
 	threadexitsall("usage");
 }
 
+struct
+{
+	vlong data;
+	vlong skipdata;
+} stats;
+
 void
 threadmain(int argc, char *argv[])
 {
-	int i;
+	int i, printstats;
 	char *host;
 	VacFile *f;
 
@@ -41,6 +48,8 @@ threadmain(int argc, char *argv[])
 	fmtinstall('M', dirmodefmt);
 	
 	host = nil;
+	printstats = 0;
+
 	ARGBEGIN{
 	case 'T':
 		settimes = 1;
@@ -50,10 +59,16 @@ threadmain(int argc, char *argv[])
 		break;
 	case 'c':
 		tostdout++;
+		break;
+	case 'd':
+		diff++;
 		break;
 	case 'h':
 		host = EARGF(usage());
 		break;
+	case 's':
+		printstats++;
+		break;
 	case 't':
 		table++;
 		break;
@@ -67,6 +82,11 @@ threadmain(int argc, char *argv[])
 	if(argc < 1)
 		usage();
 
+	if(tostdout && diff){
+		fprint(2, "cannot use -c with -d\n");
+		usage();
+	}
+
 	conn = vtdial(host);
 	if(conn == nil)
 		sysfatal("could not connect to server: %r");
@@ -94,6 +114,9 @@ threadmain(int argc, char *argv[])
 	}
 	if(errors)
 		threadexitsall("errors");
+	if(printstats)
+		fprint(2, "%lld bytes read, %lld bytes skipped\n",
+			stats.data, stats.skipdata);
 	threadexitsall(0);
 }
 
@@ -143,7 +166,7 @@ void
 unvac(VacFile *f, char *name, VacDir *vdir)
 {
 	static char buf[65536];
-	int fd, n;
+	int fd, n, m,  bsize;
 	ulong mode, mode9;
 	char *newname;
 	char *what;
@@ -256,23 +279,53 @@ unvac(VacFile *f, char *name, VacDir *vdir)
 		vdeclose(vde);
 	}else{
 		if(!table){
+			off = 0;
 			if(tostdout)
 				fd = dup(1, -1);
+			else if(diff && (fd = open(name, ORDWR)) >= 0){
+				bsize = vacfiledsize(f);
+				while((n = readn(fd, buf, bsize)) > 0){
+					if(sha1matches(f, off/bsize, (uchar*)buf, n)){
+						off += n;
+						stats.skipdata += n;
+						continue;
+					}
+					seek(fd, off, 0);
+					if((m = vacfileread(f, buf, n, off)) < 0)
+						break;
+					if(writen(fd, buf, m) != m){
+						fprint(2, "write %s: %r\n", name);
+						goto Err;
+					}
+					off += m;
+					stats.data += m;
+					if(m < n){
+						nulldir(&d);
+						d.length = off;
+						if(dirfwstat(fd, &d) < 0){
+							fprint(2, "dirfwstat %s: %r\n", name);
+							goto Err;
+						}
+						break;
+					}
+				}
+			}
 			else if((fd = create(name, OWRITE, mode&0777)) < 0){
 				fprint(2, "create %s: %r\n", name);
 				errors++;
 				return;
 			}
-			off = 0;
 			while((n = vacfileread(f, buf, sizeof buf, off)) > 0){
 				if(writen(fd, buf, n) != n){
 					fprint(2, "write %s: %r\n", name);
+				Err:
 					errors++;
 					close(fd);
 					remove(name);
 					return;
 				}
 				off += n;
+				stats.data += n;
 			}
 			close(fd);
 		}
blob - 99651981b13c321e25a4fa5fc52f597a27203882
blob + d6c17b4b808274fe151a9f5f66258c5f3fc176ad
--- src/cmd/vac/vac.c
+++ src/cmd/vac/vac.c
@@ -438,24 +438,6 @@ enum {
 		DMDEVICE
 };
 #endif
-
-/*
- * Does block b of f have the same SHA1 hash as the n bytes at buf?
- */
-static int
-sha1matches(VacFile *f, ulong b, uchar *buf, int n)
-{
-	uchar fscore[VtScoreSize];
-	uchar bufscore[VtScoreSize];
-	
-	if(vacfileblockscore(f, b, fscore) < 0)
-		return 0;
-	n = vtzerotruncate(VtDataType, buf, n);
-	sha1(buf, n, bufscore, nil);
-	if(memcmp(bufscore, fscore, VtScoreSize) == 0)
-		return 1;
-	return 0;
-}
 
 /*
  * Archive the file named name, which has stat info d,
blob - 0b82d0ebf22965f92ad2d63a8320d1b229108fd2
blob + cb599a9c3c1b81a9ce6cae086343a6cd35dd4879
--- src/cmd/vac/vac.h
+++ src/cmd/vac/vac.h
@@ -142,3 +142,6 @@ int			vderead(VacDirEnum*, VacDir *);
 void			vdeclose(VacDirEnum*);
 int	vdeunread(VacDirEnum*);
 
+int	vacfiledsize(VacFile *f);
+int	sha1matches(VacFile *f, ulong b, uchar *buf, int n);
+