diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/replica/applychanges.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/replica/applychanges.c')
-rwxr-xr-x | sys/src/cmd/replica/applychanges.c | 332 |
1 files changed, 332 insertions, 0 deletions
diff --git a/sys/src/cmd/replica/applychanges.c b/sys/src/cmd/replica/applychanges.c new file mode 100755 index 000000000..70534e804 --- /dev/null +++ b/sys/src/cmd/replica/applychanges.c @@ -0,0 +1,332 @@ +/* + * push changes from client to server. + */ +#include "all.h" + +int douid; +Db *db; +char **x; +int nx; +int justshow; +int verbose; +int conflicts; +char newpath[10000]; +char oldpath[10000]; +char *clientroot; +char *serverroot; +int copyfile(char*, char*, Dir*, int); +int metafile(char*, Dir*); +char **match; +int nmatch; + +int +ismatch(char *s) +{ + int i, len; + + if(nmatch == 0) + return 1; + for(i=0; i<nmatch; i++){ + if(strcmp(s, match[i]) == 0) + return 1; + len = strlen(match[i]); + if(strncmp(s, match[i], len) == 0 && s[len]=='/') + return 1; + } + return 0; +} + +void +xlog(char c, char *path, Dir *d) +{ + if(!verbose) + return; + print("%c %s %luo %s %s %lud\n", c, path, d->mode, d->uid, d->gid, d->mtime); +} + +void +walk(char *new, char *old, Dir *pd, void*) +{ + int i, len; + Dir od, d; + static Dir *xd; + + new = unroot(new, "/"); + old = unroot(old, serverroot); + + if(!ismatch(new)) + return; + if(xd != nil){ + free(xd); + xd = nil; + } + + for(i=0; i<nx; i++){ + if(strcmp(new, x[i]) == 0) + return; + len = strlen(x[i]); + if(strncmp(new, x[i], len)==0 && new[len]=='/') + return; + } + + d = *pd; + d.name = old; + memset(&od, 0, sizeof od); + snprint(newpath, sizeof newpath, "%s/%s", clientroot, new); + snprint(oldpath, sizeof oldpath, "%s/%s", serverroot, old); + + xd = dirstat(oldpath); + if(markdb(db, new, &od) < 0){ + if(xd != nil){ + print("x %s create/create conflict\n", new); + conflicts = 1; + return; + } + xlog('a', new, &d); + d.muid = "mark"; /* mark bit */ + if(!justshow){ + if(copyfile(newpath, oldpath, &d, 1) == 0) + insertdb(db, new, &d); + } + }else{ + if((d.mode&DMDIR)==0 && od.mtime!=d.mtime){ + if(xd==nil){ + print("%s update/remove conflict\n", new); + conflicts = 1; + return; + } + if(xd->mtime != od.mtime){ + print("%s update/update conflict\n", new); + conflicts = 1; + return; + } + od.mtime = d.mtime; + od.muid = "mark"; + xlog('c', new, &od); + if(!justshow){ + if(copyfile(newpath, oldpath, &od, 0) == 0) + insertdb(db, new, &od); + } + } + if((douid&&strcmp(od.uid,d.uid)!=0) + || strcmp(od.gid,d.gid)!=0 + || od.mode!=d.mode){ + if(xd==nil){ + print("%s metaupdate/remove conflict\n", new); + conflicts = 1; + return; + } + if((douid&&strcmp(od.uid,xd->uid)!=0) + || strcmp(od.uid,xd->gid)!=0 + || od.mode!=xd->mode){ + print("%s metaupdate/metaupdate conflict\n", new); + conflicts = 1; + return; + } + if(douid) + od.uid = d.uid; + od.gid = d.gid; + od.mode = d.mode; + od.muid = "mark"; + xlog('m', new, &od); + if(!justshow){ + if(metafile(oldpath, &od) == 0) + insertdb(db, new, &od); + } + } + } +} + +void +usage(void) +{ + fprint(2, "usage: replica/applychanges [-nuv] [-p proto] [-x path]... clientdb clientroot serverroot [path ...]\n"); + exits("usage"); +} + +void +main(int argc, char **argv) +{ + char *proto; + Avlwalk *w; + Dir *xd, d; + Entry *e; + + quotefmtinstall(); + proto = "/sys/lib/sysconfig/proto/allproto"; + ARGBEGIN{ + case 'n': + justshow = 1; + verbose = 1; + break; + case 'p': + proto = EARGF(usage()); + break; + case 'u': + douid = 1; + break; + case 'v': + verbose = 1; + break; + case 'x': + if(nx%16 == 0) + x = erealloc(x, (nx+16)*sizeof(x[0])); + x[nx++] = EARGF(usage()); + break; + default: + usage(); + }ARGEND + + if(argc < 3) + usage(); + + db = opendb(argv[0]); + clientroot = argv[1]; + serverroot = argv[2]; + match = argv+3; + nmatch = argc-3; + + + if(revrdproto(proto, clientroot, serverroot, walk, nil, nil) < 0) + sysfatal("rdproto: %r"); + + w = avlwalk(db->avl); + while(e = (Entry*)avlprev(w)){ + if(!ismatch(e->name)) + continue; + if(!e->d.mark){ /* not visited during walk */ + snprint(newpath, sizeof newpath, "%s/%s", clientroot, e->name); + snprint(oldpath, sizeof oldpath, "%s/%s", serverroot, e->d.name); + xd = dirstat(oldpath); + if(xd == nil){ + removedb(db, e->name); + continue; + } + if(xd->mtime != e->d.mtime && (e->d.mode&xd->mode&DMDIR)==0){ + print("x %q remove/update conflict\n", e->name); + free(xd); + continue; + } + memset(&d, 0, sizeof d); + d.name = e->d.name; + d.uid = e->d.uid; + d.gid = e->d.gid; + d.mtime = e->d.mtime; + d.mode = e->d.mode; + xlog('d', e->name, &d); + if(!justshow){ + if(remove(oldpath) == 0) + removedb(db, e->name); + } + free(xd); + } + } + + if(conflicts) + exits("conflicts"); + exits(nil); +} + +enum { DEFB = 8192 }; + +static int +copy1(int fdf, int fdt, char *from, char *to) +{ + char buf[DEFB]; + long n, n1, rcount; + int rv; + char err[ERRMAX]; + + /* clear any residual error */ + err[0] = '\0'; + errstr(err, ERRMAX); + rv = 0; + for(rcount=0;; rcount++) { + n = read(fdf, buf, DEFB); + if(n <= 0) + break; + n1 = write(fdt, buf, n); + if(n1 != n) { + fprint(2, "error writing %q: %r\n", to); + rv = -1; + break; + } + } + if(n < 0) { + fprint(2, "error reading %q: %r\n", from); + rv = -1; + } + return rv; +} + +int +copyfile(char *from, char *to, Dir *d, int dowstat) +{ + Dir nd; + int rfd, wfd, didcreate; + + if((rfd = open(from, OREAD)) < 0) + return -1; + + didcreate = 0; + if(d->mode&DMDIR){ + if((wfd = create(to, OREAD, DMDIR)) < 0){ + fprint(2, "mkdir %q: %r\n", to); + close(rfd); + return -1; + } + }else{ + if((wfd = open(to, OTRUNC|OWRITE)) < 0){ + if((wfd = create(to, OWRITE, 0)) < 0){ + close(rfd); + return -1; + } + didcreate = 1; + } + if(copy1(rfd, wfd, from, to) < 0){ + close(rfd); + close(wfd); + return -1; + } + } + close(rfd); + if(didcreate || dowstat){ + nulldir(&nd); + nd.mode = d->mode; + if(dirfwstat(wfd, &nd) < 0) + fprint(2, "warning: cannot set mode on %q\n", to); + nulldir(&nd); + nd.gid = d->gid; + if(dirfwstat(wfd, &nd) < 0) + fprint(2, "warning: cannot set gid on %q\n", to); + if(douid){ + nulldir(&nd); + nd.uid = d->uid; + if(dirfwstat(wfd, &nd) < 0) + fprint(2, "warning: cannot set uid on %q\n", to); + } + } + nulldir(&nd); + nd.mtime = d->mtime; + if(dirfwstat(wfd, &nd) < 0) + fprint(2, "warning: cannot set mtime on %q\n", to); + close(wfd); + return 0; +} + +int +metafile(char *path, Dir *d) +{ + Dir nd; + + nulldir(&nd); + nd.gid = d->gid; + nd.mode = d->mode; + if(douid) + nd.uid = d->uid; + if(dirwstat(path, &nd) < 0){ + fprint(2, "dirwstat %q: %r\n", path); + return -1; + } + return 0; +} |