summaryrefslogtreecommitdiff
path: root/sys/src/cmd/replica/applychanges.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /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-xsys/src/cmd/replica/applychanges.c332
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;
+}