tunvac: add -d flag (David Swasey) - plan9port - [fork] Plan 9 from user space
 (HTM) git clone git://src.adamsgaard.dk/plan9port
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 286bb40b76f35ffee1e6789895782af203e0dae3
 (DIR) parent 115dbcecc8d35d12b54d17dc1cba39089ad37b5f
 (HTM) Author: Russ Cox <rsc@swtch.com>
       Date:   Sat,  6 Dec 2008 16:14:10 -0800
       
       unvac: add -d flag (David Swasey)
       
       Diffstat:
         M man/man1/vac.1                      |       9 ++++++++-
         M src/cmd/vac/file.c                  |      29 +++++++++++++++++++++++++++++
         M src/cmd/vac/unvac.c                 |      61 +++++++++++++++++++++++++++++--
         M src/cmd/vac/vac.c                   |      18 ------------------
         M src/cmd/vac/vac.h                   |       3 +++
       
       5 files changed, 97 insertions(+), 23 deletions(-)
       ---
 (DIR) diff --git a/man/man1/vac.1 b/man/man1/vac.1
       t@@ -34,7 +34,7 @@ vac, unvac \- create, extract a vac archive on Venti
        .PP
        .B unvac
        [
       -.B -Tctv
       +.B -Tcdtv
        ] [
        .B -h
        .I host
       t@@ -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
 (DIR) diff --git a/src/cmd/vac/file.c b/src/cmd/vac/file.c
       t@@ -2061,3 +2061,32 @@ vacfssync(VacFs *fs)
                        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;
       +}
       +
 (DIR) diff --git a/src/cmd/vac/unvac.c b/src/cmd/vac/unvac.c
       t@@ -8,6 +8,7 @@
        
        VacFs *fs;
        int tostdout;
       +int diff;
        int nwant;
        char **want;
        int *found;
       t@@ -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;
        
       t@@ -41,6 +48,8 @@ threadmain(int argc, char *argv[])
                fmtinstall('M', dirmodefmt);
                
                host = nil;
       +        printstats = 0;
       +
                ARGBEGIN{
                case 'T':
                        settimes = 1;
       t@@ -51,9 +60,15 @@ threadmain(int argc, char *argv[])
                case 'c':
                        tostdout++;
                        break;
       +        case 'd':
       +                diff++;
       +                break;
                case 'h':
                        host = EARGF(usage());
                        break;
       +        case 's':
       +                printstats++;
       +                break;
                case 't':
                        table++;
                        break;
       t@@ -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");
       t@@ -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);
        }
        
       t@@ -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;
       t@@ -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);
                        }
 (DIR) diff --git a/src/cmd/vac/vac.c b/src/cmd/vac/vac.c
       t@@ -440,24 +440,6 @@ enum {
        #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,
         * into the vac directory fp (p = parent).  
         *
 (DIR) diff --git a/src/cmd/vac/vac.h b/src/cmd/vac/vac.h
       t@@ -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);
       +