applychanges.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  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. xlog('c', new, &od);
  95. if(!justshow){
  96. if(copyfile(new, old, &od, 0) == 0)
  97. insertdb(db, new, &od);
  98. }
  99. }
  100. if((douid&&strcmp(od.uid,d.uid)!=0)
  101. || strcmp(od.gid,d.gid)!=0
  102. || od.mode!=d.mode){
  103. if(xd==nil){
  104. print("%s metaupdate/remove conflict\n", new);
  105. conflicts = 1;
  106. return;
  107. }
  108. if((douid&&strcmp(od.uid,xd->uid)!=0)
  109. || strcmp(od.uid,xd->gid)!=0
  110. || od.mode!=xd->mode){
  111. print("%s metaupdate/metaupdate conflict\n", new);
  112. conflicts = 1;
  113. return;
  114. }
  115. if(douid)
  116. od.uid = d.uid;
  117. od.gid = d.gid;
  118. od.mode = d.mode;
  119. xlog('m', new, &od);
  120. if(!justshow){
  121. if(metafile(oldpath, &od) == 0)
  122. insertdb(db, new, &od);
  123. }
  124. }
  125. }
  126. }
  127. void
  128. usage(void)
  129. {
  130. fprint(2, "usage: replica/applychanges [-p proto] [-r root] [-t now n] [-u uid] [-x path]... clientdb [path ...]\n");
  131. exits("usage");
  132. }
  133. void
  134. main(int argc, char **argv)
  135. {
  136. char *proto;
  137. Avlwalk *w;
  138. Dir *xd, d;
  139. Entry *e;
  140. quotefmtinstall();
  141. proto = "/sys/lib/sysconfig/proto/allproto";
  142. ARGBEGIN{
  143. case 'n':
  144. justshow = 1;
  145. verbose = 1;
  146. break;
  147. case 'p':
  148. proto = EARGF(usage());
  149. break;
  150. case 'u':
  151. douid = 1;
  152. break;
  153. case 'v':
  154. verbose = 1;
  155. break;
  156. case 'x':
  157. if(nx%16 == 0)
  158. x = erealloc(x, (nx+16)*sizeof(x[0]));
  159. x[nx++] = EARGF(usage());
  160. break;
  161. default:
  162. usage();
  163. }ARGEND
  164. if(argc < 3)
  165. usage();
  166. db = opendb(argv[0]);
  167. clientroot = argv[1];
  168. serverroot = argv[2];
  169. match = argv+3;
  170. nmatch = argc-3;
  171. if(revrdproto(proto, clientroot, serverroot, walk, nil, nil) < 0)
  172. sysfatal("rdproto: %r");
  173. w = avlwalk(db->avl);
  174. while(e = (Entry*)avlnext(w)){
  175. if(!ismatch(e->name))
  176. continue;
  177. if(!e->d.mark){ /* not visited during walk */
  178. snprint(newpath, sizeof newpath, "%s/%s", clientroot, e->name);
  179. snprint(oldpath, sizeof oldpath, "%s/%s", serverroot, e->d.name);
  180. xd = dirstat(oldpath);
  181. if(xd == nil){
  182. removedb(db, e->name);
  183. continue;
  184. }
  185. if(xd->mtime != e->d.mtime){
  186. print("x %q remove/update conflict\n", e->name);
  187. free(xd);
  188. continue;
  189. }
  190. memset(&d, 0, sizeof d);
  191. d.name = e->d.name;
  192. d.uid = e->d.uid;
  193. d.gid = e->d.gid;
  194. d.mtime = e->d.mtime;
  195. d.mode = e->d.mode;
  196. xlog('d', e->name, &d);
  197. if(!justshow){
  198. if(remove(oldpath) == 0)
  199. removedb(db, e->name);
  200. }
  201. }
  202. }
  203. if(conflicts)
  204. exits("conflicts");
  205. exits(nil);
  206. }
  207. enum { DEFB = 8192 };
  208. static int
  209. copy1(int fdf, int fdt, char *from, char *to)
  210. {
  211. char buf[DEFB];
  212. long n, n1, rcount;
  213. int rv;
  214. char err[ERRMAX];
  215. /* clear any residual error */
  216. err[0] = '\0';
  217. errstr(err, ERRMAX);
  218. rv = 0;
  219. for(rcount=0;; rcount++) {
  220. n = read(fdf, buf, DEFB);
  221. if(n <= 0)
  222. break;
  223. n1 = write(fdt, buf, n);
  224. if(n1 != n) {
  225. fprint(2, "error writing %q: %r\n", to);
  226. rv = -1;
  227. break;
  228. }
  229. }
  230. if(n < 0) {
  231. fprint(2, "error reading %q: %r\n", from);
  232. rv = -1;
  233. }
  234. return rv;
  235. }
  236. int
  237. copyfile(char *from, char *to, Dir *d, int dowstat)
  238. {
  239. Dir nd;
  240. int rfd, wfd, didcreate;
  241. if((rfd = open(from, OREAD)) < 0)
  242. return -1;
  243. didcreate = 0;
  244. if((wfd = open(to, OTRUNC|OWRITE)) < 0){
  245. if((wfd = create(to, OWRITE, 0)) < 0){
  246. close(rfd);
  247. return -1;
  248. }
  249. didcreate = 1;
  250. }
  251. if(copy1(rfd, wfd, from, to) < 0){
  252. close(rfd);
  253. close(wfd);
  254. return -1;
  255. }
  256. if(didcreate || dowstat){
  257. nulldir(&nd);
  258. nd.mode = d->mode;
  259. if(dirfwstat(wfd, &nd) < 0)
  260. fprint(2, "warning: cannot set mode on %q\n", to);
  261. nulldir(&nd);
  262. nd.gid = d->gid;
  263. if(dirfwstat(wfd, &nd) < 0)
  264. fprint(2, "warning: cannot set gid on %q\n", to);
  265. if(douid){
  266. nulldir(&nd);
  267. nd.uid = d->uid;
  268. if(dirfwstat(wfd, &nd) < 0)
  269. fprint(2, "warning: cannot set uid on %q\n", to);
  270. }
  271. }
  272. nulldir(&nd);
  273. nd.mtime = d->mtime;
  274. if(dirfwstat(wfd, &nd) < 0)
  275. fprint(2, "warning: cannot set mtime on %q\n", to);
  276. close(wfd);
  277. return 0;
  278. }
  279. int
  280. metafile(char *path, Dir *d)
  281. {
  282. Dir nd;
  283. nulldir(&nd);
  284. nd.gid = d->gid;
  285. nd.mode = d->mode;
  286. if(douid)
  287. nd.uid = d->uid;
  288. if(dirwstat(path, &nd) < 0){
  289. fprint(2, "dirwstat %q: %r\n", path);
  290. return -1;
  291. }
  292. return 0;
  293. }