--- /n/sources/plan9/sys/src/cmd/replica/all.h Sat Aug 7 18:47:01 2004 +++ /sys/src/cmd/replica/all.h Sun Jun 21 00:00:00 2026 @@ -2,6 +2,7 @@ #include #include #include +#include /* avl.c */ typedef struct Avl Avl; @@ -42,6 +43,7 @@ ulong mode; int mark; vlong length; + char *hash; } d; }; @@ -56,7 +58,9 @@ int finddb(Db*, char*, Dir*); void removedb(Db*, char*); void insertdb(Db*, char*, Dir*); +void insertdbh(Db*, char*, Dir*, char*); int markdb(Db*, char*, Dir*); +char *dbhash(Db*, char*); /* util.c */ void *erealloc(void*, int); @@ -64,6 +68,8 @@ char *estrdup(char*); char *atom(char*); char *unroot(char*, char*); +char *hashfd(int, char*); +char *hashfile(char*, char*); /* revproto.c */ int revrdproto(char*, char*, char*, Protoenum*, Protowarn*, void*); --- /n/sources/plan9/sys/src/cmd/replica/compactdb.c Tue Apr 9 03:37:55 2002 +++ /sys/src/cmd/replica/compactdb.c Sun Jun 21 00:00:00 2026 @@ -32,9 +32,9 @@ db = opendb(argv[0]); w = avlwalk(db->avl); while(e = (Entry*)avlnext(w)) - Bprint(&bout, "%q %q %luo %q %q %lud %lld\n", + Bprint(&bout, "%q %q %luo %q %q %lud %lld %s\n", e->name, strcmp(e->name, e->d.name)==0 ? "-" : e->d.name, e->d.mode, - e->d.uid, e->d.gid, e->d.mtime, e->d.length); + e->d.uid, e->d.gid, e->d.mtime, e->d.length, e->d.hash ? e->d.hash : "-"); if(Bterm(&bout) < 0) sysfatal("writing output: %r"); --- /n/sources/plan9/sys/src/cmd/replica/db.c Tue Sep 17 21:22:07 2013 +++ /sys/src/cmd/replica/db.c Sun Jun 21 00:00:00 2026 @@ -89,7 +89,7 @@ for(; s=Brdstr(&b, '\n', 1); free(s)){ t = estrdup(s); nf = tokenize(s, f, nelem(f)); - if(nf != 7) + if(nf != 7 && nf != 8) sysfatal("bad database entry '%s'", t); free(t); if(strcmp(f[2], "REMOVED") == 0) @@ -105,6 +105,7 @@ e.d.gid = atom(f[4]); e.d.mtime = strtoul(f[5], 0, 10); e.d.length = strtoll(f[6], 0, 10); + e.d.hash = atom(nf==8 ? f[7] : "-"); _insertdb(db, &e); i++; } @@ -158,6 +159,12 @@ void insertdb(Db *db, char *name, Dir *d) { + insertdbh(db, name, d, "-"); +} + +void +insertdbh(Db *db, char *name, Dir *d, char *hash) +{ char *dname; Entry e; @@ -169,13 +176,27 @@ e.d.mtime = d->mtime; e.d.mode = d->mode; e.d.length = d->length; + e.d.hash = atom(hash); e.d.mark = d->muid!=0; dname = d->name; if(strcmp(name, dname) == 0) dname = "-"; - if(db->fd>=0 && fprint(db->fd, "%q %q %luo %q %q %lud %lld\n", name, dname, d->mode, d->uid, d->gid, d->mtime, d->length) < 0) + if(db->fd>=0 && fprint(db->fd, "%q %q %luo %q %q %lud %lld %s\n", name, dname, d->mode, d->uid, d->gid, d->mtime, d->length, hash) < 0) sysfatal("appending to db: %r"); _insertdb(db, &e); } +char* +dbhash(Db *db, char *name) +{ + Entry *e, k; + + memset(&k, 0, sizeof k); + k.name = name; + e = (Entry*)lookupavl(db->avl, (Avl*)&k); + if(e == nil || e->d.hash == nil) + return "-"; + return e->d.hash; +} + --- /n/sources/plan9/sys/src/cmd/replica/updatedb.c Wed Nov 28 18:11:10 2007 +++ /sys/src/cmd/replica/updatedb.c Sun Jun 21 00:00:00 2026 @@ -35,7 +35,7 @@ } void -xlog(int c, char *name, Dir *d) +xlog(int c, char *name, Dir *d, char *hash) { char *dname; @@ -44,8 +44,8 @@ dname = "-"; if(!justlog) Bprint(&blog, "%lud %d ", now, n++); - Bprint(&blog, "%c %q %q %luo %q %q %lud %lld\n", - c, name, dname, d->mode, uid ? uid : d->uid, d->gid, d->mtime, d->length); + Bprint(&blog, "%c %q %q %luo %q %q %lud %lld %s\n", + c, name, dname, d->mode, uid ? uid : d->uid, d->gid, d->mtime, d->length, hash); } void @@ -53,7 +53,9 @@ { int i, change, len; Dir od, d; + char *path, *h, hbuf[2*SHA1dlen+1]; + path = old; /* full on-disk path, before unroot */ new = unroot(new, "/"); old = unroot(old, root); @@ -71,20 +73,34 @@ d.name = old; memset(&od, 0, sizeof od); change = 0; + h = "-"; if(markdb(db, new, &od) < 0){ if(!changesonly){ - xlog('a', new, &d); + if((d.mode&DMDIR)==0 && hashfile(path, hbuf)!=nil) + h = hbuf; + xlog('a', new, &d, h); change = 1; } }else{ + h = dbhash(db, new); /* keep the stored hash unless content changed */ if((d.mode&DMDIR)==0 && (od.mtime!=d.mtime || od.length!=d.length)){ - xlog('c', new, &d); - change = 1; + if(hashfile(path, hbuf) == nil){ + h = "-"; /* can't hash: fall back to mtime|length */ + xlog('c', new, &d, h); + change = 1; + }else if(strcmp(hbuf, h) == 0){ + h = hbuf; /* churn only: refresh the db, no log entry */ + change = 1; + }else{ + h = hbuf; + xlog('c', new, &d, h); + change = 1; + } } if((!uid&&strcmp(od.uid,d.uid)!=0) - || strcmp(od.gid,d.gid)!=0 + || strcmp(od.gid,d.gid)!=0 || od.mode!=d.mode){ - xlog('m', new, &d); + xlog('m', new, &d, "-"); change = 1; } } @@ -92,7 +108,7 @@ if(uid) d.uid = uid; d.muid = "mark"; /* mark bit */ - insertdb(db, new, &d); + insertdbh(db, new, &d, h); } } @@ -199,7 +215,7 @@ d.gid = e->d.gid; d.mtime = e->d.mtime; d.mode = e->d.mode; - xlog('d', e->name, &d); + xlog('d', e->name, &d, "-"); if(!justlog) removedb(db, e->name); } --- /n/sources/plan9/sys/src/cmd/replica/util.c Fri May 24 21:11:56 2002 +++ /sys/src/cmd/replica/util.c Sun Jun 21 00:00:00 2026 @@ -135,3 +135,51 @@ } return path; } + +/* + * SHA1 an open file by pread (so the caller's seek position is left + * alone) into buf as lowercase hex. buf must hold 2*SHA1dlen+1 bytes. + * Returns buf, or nil if the file cannot be read. + */ +char* +hashfd(int fd, char *buf) +{ + static char hex[] = "0123456789abcdef"; + uchar digest[SHA1dlen], data[8192]; + DigestState *s; + vlong o; + int n; + + s = nil; + o = 0; + while((n = pread(fd, data, sizeof data, o)) > 0){ + s = sha1(data, n, nil, s); + o += n; + } + if(n < 0) + return nil; + sha1(nil, 0, digest, s); + for(n = 0; n < SHA1dlen; n++){ + buf[2*n] = hex[digest[n]>>4]; + buf[2*n+1] = hex[digest[n]&0xf]; + } + buf[2*SHA1dlen] = 0; + return buf; +} + +/* + * SHA1 the file at path. Returns buf, or nil if it cannot be read, + * in which case the caller uses "-". + */ +char* +hashfile(char *path, char *buf) +{ + int fd; + char *r; + + if((fd = open(path, OREAD)) < 0) + return nil; + r = hashfd(fd, buf); + close(fd); + return r; +}