applychanges.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. /*
  2. * push changes from client to server.
  3. */
  4. #include "all.h"
  5. int douid;
  6. Db *db;
  7. char **x;
  8. int nx;
  9. int justshow;
  10. int verbose;
  11. int conflicts;
  12. char newpath[10000];
  13. char oldpath[10000];
  14. char *clientroot;
  15. char *serverroot;
  16. int copyfile(char*, char*, Dir*, int);
  17. int metafile(char*, Dir*);
  18. char **match;
  19. int nmatch;
  20. int
  21. ismatch(char *s)
  22. {
  23. int i, len;
  24. if(nmatch == 0)
  25. return 1;
  26. for(i=0; i<nmatch; i++){
  27. if(strcmp(s, match[i]) == 0)
  28. return 1;
  29. len = strlen(match[i]);
  30. if(strncmp(s, match[i], len) == 0 && s[len]=='/')
  31. return 1;
  32. }
  33. return 0;
  34. }
  35. void
  36. xlog(char c, char *path, Dir *d)
  37. {
  38. if(!verbose)
  39. return;
  40. print("%c %s %luo %s %s %lud\n", c, path, d->mode, d->uid, d->gid, d->mtime);
  41. }
  42. void
  43. walk(char *new, char *old, Dir *pd, void*)
  44. {
  45. int i, len;
  46. Dir od, d;
  47. static Dir *xd;
  48. new = unroot(new, "/");
  49. old = unroot(old, serverroot);
  50. if(!ismatch(new))
  51. return;
  52. if(xd != nil){
  53. free(xd);
  54. xd = nil;
  55. }
  56. for(i=0; i<nx; i++){
  57. if(strcmp(new, x[i]) == 0)
  58. return;
  59. len = strlen(x[i]);
  60. if(strncmp(new, x[i], len)==0 && new[len]=='/')
  61. return;
  62. }
  63. d = *pd;
  64. d.name = old;
  65. memset(&od, 0, sizeof od);
  66. snprint(newpath, sizeof newpath, "%s/%s", clientroot, new);
  67. snprint(oldpath, sizeof oldpath, "%s/%s", serverroot, old);
  68. xd = dirstat(oldpath);
  69. if(markdb(db, new, &od) < 0){
  70. if(xd != nil){
  71. print("x %s create/create conflict\n", new);
  72. conflicts = 1;
  73. return;
  74. }
  75. xlog('a', new, &d);
  76. d.muid = "mark"; /* mark bit */
  77. if(!justshow){
  78. if(copyfile(newpath, oldpath, &d, 1) == 0)
  79. insertdb(db, new, &d);
  80. }
  81. }else{
  82. if((d.mode&DMDIR)==0 && od.mtime!=d.mtime){
  83. if(xd==nil){
  84. print("%s update/remove conflict\n", new);
  85. conflicts = 1;
  86. return;
  87. }
  88. if(xd->mtime != od.mtime){
  89. print("%s update/update conflict\n", new);
  90. conflicts = 1;
  91. return;
  92. }
  93. od.mtime = d.mtime;
  94. od.muid = "mark";
  95. xlog('c', new, &od);
  96. if(!justshow){
  97. if(copyfile(newpath, oldpath, &od, 0) == 0)
  98. insertdb(db, new, &od);
  99. }
  100. }
  101. if((douid&&strcmp(od.uid,d.uid)!=0)
  102. || strcmp(od.gid,d.gid)!=0
  103. || od.mode!=d.mode){
  104. if(xd==nil){
  105. print("%s metaupdate/remove conflict\n", new);
  106. conflicts = 1;
  107. return;
  108. }
  109. if((douid&&strcmp(od.uid,xd->uid)!=0)
  110. || strcmp(od.uid,xd->gid)!=0
  111. || od.mode!=xd->mode){
  112. print("%s metaupdate/metaupdate conflict\n", new);
  113. conflicts = 1;
  114. return;
  115. }
  116. if(douid)
  117. od.uid = d.uid;
  118. od.gid = d.gid;
  119. od.mode = d.mode;
  120. od.muid = "mark";
  121. xlog('m', new, &od);
  122. if(!justshow){
  123. if(metafile(oldpath, &od) == 0)
  124. insertdb(db, new, &od);
  125. }
  126. }
  127. }
  128. }
  129. void
  130. usage(void)
  131. {
  132. fprint(2, "usage: replica/applychanges [-nuv] [-p proto] [-x path]... clientdb clientroot serverroot [path ...]\n");
  133. exits("usage");
  134. }
  135. void
  136. main(int argc, char **argv)
  137. {
  138. char *proto;
  139. Avlwalk *w;
  140. Dir *xd, d;
  141. Entry *e;
  142. quotefmtinstall();
  143. proto = "/sys/lib/sysconfig/proto/allproto";
  144. ARGBEGIN{
  145. case 'n':
  146. justshow = 1;
  147. verbose = 1;
  148. break;
  149. case 'p':
  150. proto = EARGF(usage());
  151. break;
  152. case 'u':
  153. douid = 1;
  154. break;
  155. case 'v':
  156. verbose = 1;
  157. break;
  158. case 'x':
  159. if(nx%16 == 0)
  160. x = erealloc(x, (nx+16)*sizeof(x[0]));
  161. x[nx++] = EARGF(usage());
  162. break;
  163. default:
  164. usage();
  165. }ARGEND
  166. if(argc < 3)
  167. usage();
  168. db = opendb(argv[0]);
  169. clientroot = argv[1];
  170. serverroot = argv[2];
  171. match = argv+3;
  172. nmatch = argc-3;
  173. if(revrdproto(proto, clientroot, serverroot, walk, nil, nil) < 0)
  174. sysfatal("rdproto: %r");
  175. w = avlwalk(db->avl);
  176. while(e = (Entry*)avlprev(w)){
  177. if(!ismatch(e->name))
  178. continue;
  179. if(!e->d.mark){ /* not visited during walk */
  180. snprint(newpath, sizeof newpath, "%s/%s", clientroot, e->name);
  181. snprint(oldpath, sizeof oldpath, "%s/%s", serverroot, e->d.name);
  182. xd = dirstat(oldpath);
  183. if(xd == nil){
  184. removedb(db, e->name);
  185. continue;
  186. }
  187. if(xd->mtime != e->d.mtime && (e->d.mode&xd->mode&DMDIR)==0){
  188. print("x %q remove/update conflict\n", e->name);
  189. free(xd);
  190. continue;
  191. }
  192. memset(&d, 0, sizeof d);
  193. d.name = e->d.name;
  194. d.uid = e->d.uid;
  195. d.gid = e->d.gid;
  196. d.mtime = e->d.mtime;
  197. d.mode = e->d.mode;
  198. xlog('d', e->name, &d);
  199. if(!justshow){
  200. if(remove(oldpath) == 0)
  201. removedb(db, e->name);
  202. }
  203. free(xd);
  204. }
  205. }
  206. if(conflicts)
  207. exits("conflicts");
  208. exits(nil);
  209. }
  210. enum { DEFB = 8192 };
  211. static int
  212. copy1(int fdf, int fdt, char *from, char *to)
  213. {
  214. char buf[DEFB];
  215. long n, n1, rcount;
  216. int rv;
  217. char err[ERRMAX];
  218. /* clear any residual error */
  219. err[0] = '\0';
  220. errstr(err, ERRMAX);
  221. rv = 0;
  222. for(rcount=0;; rcount++) {
  223. n = read(fdf, buf, DEFB);
  224. if(n <= 0)
  225. break;
  226. n1 = write(fdt, buf, n);
  227. if(n1 != n) {
  228. fprint(2, "error writing %q: %r\n", to);
  229. rv = -1;
  230. break;
  231. }
  232. }
  233. if(n < 0) {
  234. fprint(2, "error reading %q: %r\n", from);
  235. rv = -1;
  236. }
  237. return rv;
  238. }
  239. int
  240. copyfile(char *from, char *to, Dir *d, int dowstat)
  241. {
  242. Dir nd;
  243. int rfd, wfd, didcreate;
  244. if((rfd = open(from, OREAD)) < 0)
  245. return -1;
  246. didcreate = 0;
  247. if(d->mode&DMDIR){
  248. if((wfd = create(to, OREAD, DMDIR)) < 0){
  249. fprint(2, "mkdir %q: %r\n", to);
  250. close(rfd);
  251. return -1;
  252. }
  253. }else{
  254. if((wfd = open(to, OTRUNC|OWRITE)) < 0){
  255. if((wfd = create(to, OWRITE, 0)) < 0){
  256. close(rfd);
  257. return -1;
  258. }
  259. didcreate = 1;
  260. }
  261. if(copy1(rfd, wfd, from, to) < 0){
  262. close(rfd);
  263. close(wfd);
  264. return -1;
  265. }
  266. }
  267. close(rfd);
  268. if(didcreate || dowstat){
  269. nulldir(&nd);
  270. nd.mode = d->mode;
  271. if(dirfwstat(wfd, &nd) < 0)
  272. fprint(2, "warning: cannot set mode on %q\n", to);
  273. nulldir(&nd);
  274. nd.gid = d->gid;
  275. if(dirfwstat(wfd, &nd) < 0)
  276. fprint(2, "warning: cannot set gid on %q\n", to);
  277. if(douid){
  278. nulldir(&nd);
  279. nd.uid = d->uid;
  280. if(dirfwstat(wfd, &nd) < 0)
  281. fprint(2, "warning: cannot set uid on %q\n", to);
  282. }
  283. }
  284. nulldir(&nd);
  285. nd.mtime = d->mtime;
  286. if(dirfwstat(wfd, &nd) < 0)
  287. fprint(2, "warning: cannot set mtime on %q\n", to);
  288. close(wfd);
  289. return 0;
  290. }
  291. int
  292. metafile(char *path, Dir *d)
  293. {
  294. Dir nd;
  295. nulldir(&nd);
  296. nd.gid = d->gid;
  297. nd.mode = d->mode;
  298. if(douid)
  299. nd.uid = d->uid;
  300. if(dirwstat(path, &nd) < 0){
  301. fprint(2, "dirwstat %q: %r\n", path);
  302. return -1;
  303. }
  304. return 0;
  305. }