Changes to pull. - ignore "d" log entries if file has not been deleted on sources - suppress "locally modified" conflicts when the local file and the remote file are identical. - make conflict messages begin with "!" verb The first change is intended to make things like the db snafu last week less painful. The second change makes submitting patches nicer. Assuming the patch is accepted verbatim, pulling will not complain about the files that you patched and got changed on sources. The second change also makes it possible to copy files from sources directly instead of using pull -s. That is, you can do: % pull ! sys/src/libc/port/lock.c locally modified; will not update % diff /sys/src/libc/port/lock.c /n/sources/plan9/sys/src/libc/port/lock.c ... (decide changes are worth throwing away) % cp /n/sources/plan9/sys/src/libc/port/lock.c . % pull This also helps if you submit a patch and the files get tweaked a little on the way to sources. Reference: /n/sources/patch/applied/applylog Date: Tue Nov 27 18:45:01 CET 2007 Signed-off-by: rsc@swtch.com --- /sys/src/cmd/replica/applylog.c Tue Nov 27 18:40:45 2007 +++ /sys/src/cmd/replica/applylog.c Tue Nov 27 18:40:45 2007 @@ -18,7 +18,6 @@ int errors; int nconf; int donothing; -char **conf; int verbose; char **match; int nmatch; @@ -37,6 +36,7 @@ int maxn; char *timefile; int timefd; +int samecontents(char*, char*); Db *copyerr; @@ -288,6 +288,8 @@ delce(local); if(!havelocal) /* doesn't exist; who cares? */ break; + if(access(remote, AEXIST) >= 0) /* got recreated! */ + break; if(!ismatch(name)){ if(!skip) fprint(2, "stopped updating log apply time because of %s\n", name); @@ -307,6 +309,10 @@ assert(havelocal && havedb); if(dbd.mtime > rd.mtime) /* we have a newer file than what was deleted */ break; + if(samecontents(local, remote) > 0){ /* going to get recreated */ + chat("= %q %luo %q %q %lud\n", name, rd.mode, rd.uid, rd.gid, rd.mtime); + break; + } if(!(dbd.mode&DMDIR) && (dbd.mtime != ld.mtime || dbd.length != ld.length)){ /* locally modified since we downloaded it */ if(resolve1 == 's') goto DoRemove; @@ -319,11 +325,11 @@ DoRemove: USED(checkedmatch1); assert(ismatch(name)); - chat("d %q\n", name); + chat("a %q %luo %q %q %lud\n", name, rd.mode, rd.uid, rd.gid, rd.mtime); if(donothing) break; if(remove(local) < 0){ - error("removing %q", name); + error("removing %q: %r", name); skip = 1; continue; } @@ -346,6 +352,10 @@ goto DoCreate; if((ld.mode&DMDIR) && (rd.mode&DMDIR)) break; + if(samecontents(local, remote) > 0){ + chat("= %q %luo %q %q %lud\n", name, rd.mode, rd.uid, rd.gid, rd.mtime); + goto DoCreateDb; + } if(resolve1 == 's') goto DoCreate; else if(resolve1 == 'c') @@ -367,6 +377,10 @@ continue; } SET(checkedmatch2); + if(samecontents(local, remote) > 0){ + chat("= %q %luo %q %q %lud\n", name, rd.mode, rd.uid, rd.gid, rd.mtime); + goto DoCreateDb; + } if(dbd.mtime==ld.mtime && dbd.length==ld.length) goto DoCreate; if(resolve1=='s') @@ -449,6 +463,10 @@ goto DoCopy; else if(resolve1=='c') goto DoCopyDb; + if(samecontents(local, remote) > 0){ + chat("= %q %luo %q %q %lud\n", name, rd.mode, rd.uid, rd.gid, rd.mtime); + goto DoCopyDb; + } if(havelocal) conflict(name, "locally created; will not update"); else @@ -486,11 +504,15 @@ /* no skip=1 */ break; } + if(samecontents(local, remote) > 0){ + chat("= %q %luo %q %q %lud\n", name, rd.mode, rd.uid, rd.gid, rd.mtime); + goto DoCopyDb; + } if(resolve1 == 's') goto DoCopy; else if(resolve1 == 'c') break; - conflict(name, "locally modified; will not update"); + conflict(name, "locally modified; will not update [%llud %lud -> %llud %lud]", dbd.length, dbd.mtime, ld.length, ld.mtime); skip = 1; continue; } @@ -596,7 +618,7 @@ continue; } SET(checkedmatch4); - if(resolve1 == 's') + if(resolve1 == 's' || samecontents(local, remote) > 0) goto DoMeta; else if(resolve1 == 'c') break; @@ -732,13 +754,10 @@ s = vsmprint(f, arg); va_end(arg); - fprint(2, "%s: %s\n", name, s); + fprint(2, "! %s: %s\n", name, s); free(s); nconf++; -// if(nconf%16 == 0) -// conf = erealloc(conf, (nconf+16)*sizeof(conf[0])); -// conf[nconf++] = estrdup(name); } void @@ -787,6 +806,27 @@ enum { DEFB = 8192 }; static int +cmp1(int fd1, int fd2) +{ + char buf1[DEFB]; + char buf2[DEFB]; + int n1, n2; + + for(;;){ + n1 = readn(fd1, buf1, DEFB); + n2 = readn(fd2, buf2, DEFB); + if(n1 < 0 || n2 < 0) + return -1; + if(n1 != n2) + return 0; + if(n1 == 0) + return 1; + if(memcmp(buf1, buf2, n1) != 0) + return 0; + } +} + +static int copy1(int fdf, int fdt, char *from, char *to) { int i, n, rv, pid[Nwork]; @@ -1057,6 +1097,80 @@ close(wfd); return 0; +} + +int +samecontents(char *local, char *remote) +{ + Dir *d0, *d1; + int rfd, tfd, lfd, ret; + char tmp[32]; + + /* quick check: sizes must match */ + d1 = nil; + if((d0 = dirstat(local)) == nil || (d1 = dirstat(remote)) == nil){ + free(d0); + free(d1); + return -1; + } + if(d0->length != d1->length){ + free(d0); + free(d1); + return 0; + } + +Again: + if((rfd = open(remote, OREAD)) < 0) + return -1; + d0 = dirfstat(rfd); + if(d0 == nil){ + close(rfd); + return -1; + } + + strcpy(tmp, "/tmp/replicaXXXXXXXX"); + tfd = opentemp(tmp); + if(tfd < 0){ + close(rfd); + free(d0); + return -1; + } + if(copy1(rfd, tfd, remote, tmp) < 0 || (d1 = dirfstat(rfd)) == nil){ + close(rfd); + close(tfd); + free(d0); + return -1; + } + close(rfd); + if(d0->qid.path != d1->qid.path + || d0->qid.vers != d1->qid.vers + || d0->mtime != d1->mtime + || d0->length != d1->length){ + /* file changed underfoot; go around again */ + close(tfd); + free(d0); + free(d1); + goto Again; + } + free(d1); + free(d0); + if(seek(tfd, 0, 0) != 0){ + close(tfd); + return -1; + } + + /* + * now compare + */ + if((lfd = open(local, OREAD)) < 0){ + close(tfd); + return -1; + } + + ret = cmp1(lfd, tfd); + close(lfd); + close(tfd); + return ret; } /*