123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332 |
- /*
- * 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;
- }
|