unvac.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. #include "stdinc.h"
  2. #include <fcall.h> /* dirmodefmt */
  3. #include "vac.h"
  4. #pragma varargck type "t" ulong
  5. VacFs *fs;
  6. int tostdout;
  7. int nwant;
  8. char **want;
  9. int *found;
  10. int chatty;
  11. VtConn *conn;
  12. int errors;
  13. int settimes;
  14. int table;
  15. int mtimefmt(Fmt*);
  16. void unvac(VacFile*, char*, VacDir*);
  17. void
  18. usage(void)
  19. {
  20. fprint(2, "usage: unvac [-TVctv] [-h host] file.vac [file ...]\n");
  21. threadexitsall("usage");
  22. }
  23. void
  24. threadmain(int argc, char *argv[])
  25. {
  26. int i;
  27. char *host;
  28. VacFile *f;
  29. fmtinstall('H', encodefmt);
  30. fmtinstall('V', vtscorefmt);
  31. fmtinstall('F', vtfcallfmt);
  32. fmtinstall('t', mtimefmt);
  33. fmtinstall('M', dirmodefmt);
  34. host = nil;
  35. ARGBEGIN{
  36. case 'T':
  37. settimes = 1;
  38. break;
  39. case 'V':
  40. chattyventi = 1;
  41. break;
  42. case 'c':
  43. tostdout++;
  44. break;
  45. case 'h':
  46. host = EARGF(usage());
  47. break;
  48. case 't':
  49. table++;
  50. break;
  51. case 'v':
  52. chatty++;
  53. break;
  54. default:
  55. usage();
  56. }ARGEND
  57. if(argc < 1)
  58. usage();
  59. conn = vtdial(host);
  60. if(conn == nil)
  61. sysfatal("could not connect to server: %r");
  62. if(vtconnect(conn) < 0)
  63. sysfatal("vtconnect: %r");
  64. fs = vacfsopen(conn, argv[0], VtOREAD, 128);
  65. if(fs == nil)
  66. sysfatal("vacfsopen: %r");
  67. nwant = argc-1;
  68. want = argv+1;
  69. found = vtmallocz(nwant*sizeof found[0]);
  70. if((f = vacfsgetroot(fs)) == nil)
  71. sysfatal("vacfsgetroot: %r");
  72. unvac(f, nil, nil);
  73. for(i=0; i<nwant; i++){
  74. if(want[i] && !found[i]){
  75. fprint(2, "warning: didn't find %s\n", want[i]);
  76. errors++;
  77. }
  78. }
  79. if(errors)
  80. threadexitsall("errors");
  81. threadexitsall(0);
  82. }
  83. int
  84. writen(int fd, char *buf, int n)
  85. {
  86. int m;
  87. int oldn;
  88. oldn = n;
  89. while(n > 0){
  90. m = write(fd, buf, n);
  91. if(m <= 0)
  92. return -1;
  93. buf += m;
  94. n -= m;
  95. }
  96. return oldn;
  97. }
  98. int
  99. wantfile(char *name)
  100. {
  101. int i, namelen, n;
  102. if(nwant == 0)
  103. return 1;
  104. namelen = strlen(name);
  105. for(i=0; i<nwant; i++){
  106. if(want[i] == nil)
  107. continue;
  108. n = strlen(want[i]);
  109. if(n < namelen && name[n] == '/' && memcmp(name, want[i], n) == 0)
  110. return 1;
  111. if(namelen < n && want[i][namelen] == '/' && memcmp(want[i], name, n) == 0)
  112. return 1;
  113. if(n == namelen && memcmp(name, want[i], n) == 0){
  114. found[i] = 1;
  115. return 1;
  116. }
  117. }
  118. return 0;
  119. }
  120. void
  121. unvac(VacFile *f, char *name, VacDir *vdir)
  122. {
  123. static char buf[65536];
  124. int fd, n;
  125. ulong mode, mode9;
  126. char *newname;
  127. char *what;
  128. vlong off;
  129. Dir d, *dp;
  130. VacDirEnum *vde;
  131. VacDir newvdir;
  132. VacFile *newf;
  133. if(vdir)
  134. mode = vdir->mode;
  135. else
  136. mode = vacfilegetmode(f);
  137. if(vdir){
  138. if(table){
  139. if(chatty){
  140. mode9 = vdir->mode&0777;
  141. if(mode&ModeDir)
  142. mode9 |= DMDIR;
  143. if(mode&ModeAppend)
  144. mode9 |= DMAPPEND;
  145. if(mode&ModeExclusive)
  146. mode9 |= DMEXCL;
  147. print("%M %-10s %-10s %11lld %t %s\n",
  148. mode9, vdir->uid, vdir->gid, vdir->size,
  149. vdir->mtime, name);
  150. }else
  151. print("%s%s\n", name, (mode&ModeDir) ? "/" : "");
  152. }
  153. else if(chatty)
  154. fprint(2, "%s%s\n", name, (mode&ModeDir) ? "/" : "");
  155. }
  156. if(mode&(ModeDevice|ModeLink|ModeNamedPipe|ModeExclusive)){
  157. if(table)
  158. return;
  159. if(mode&ModeDevice)
  160. what = "device";
  161. else if(mode&ModeLink)
  162. what = "link";
  163. else if(mode&ModeNamedPipe)
  164. what = "named pipe";
  165. else if(mode&ModeExclusive)
  166. what = "lock";
  167. else
  168. what = "unknown type of file";
  169. fprint(2, "warning: ignoring %s %s\n", what, name);
  170. return;
  171. }
  172. if(mode&ModeDir){
  173. if((vde = vdeopen(f)) == nil){
  174. fprint(2, "vdeopen %s: %r", name);
  175. errors++;
  176. return;
  177. }
  178. if(!table && !tostdout && vdir){
  179. // create directory
  180. if((dp = dirstat(name)) == nil){
  181. if((fd = create(name, OREAD, DMDIR|(mode&0777))) < 0){
  182. fprint(2, "mkdir %s: %r\n", name);
  183. vdeclose(vde);
  184. }
  185. close(fd);
  186. }else{
  187. if(!(dp->mode&DMDIR)){
  188. fprint(2, "%s already exists and is not a directory\n", name);
  189. errors++;
  190. free(dp);
  191. vdeclose(vde);
  192. return;
  193. }
  194. free(dp);
  195. }
  196. }
  197. while(vderead(vde, &newvdir) > 0){
  198. if(name == nil)
  199. newname = newvdir.elem;
  200. else
  201. newname = smprint("%s/%s", name, newvdir.elem);
  202. if(wantfile(newname)){
  203. if((newf = vacfilewalk(f, newvdir.elem)) == nil){
  204. fprint(2, "walk %s: %r\n", name);
  205. errors++;
  206. }else if(newf == f){
  207. fprint(2, "walk loop: %s\n", newname);
  208. vacfiledecref(newf);
  209. }else{
  210. unvac(newf, newname, &newvdir);
  211. vacfiledecref(newf);
  212. }
  213. }
  214. if(newname != newvdir.elem)
  215. free(newname);
  216. vdcleanup(&newvdir);
  217. }
  218. vdeclose(vde);
  219. }else{
  220. if(!table){
  221. if(tostdout)
  222. fd = dup(1, -1);
  223. else if((fd = create(name, OWRITE, mode&0777)) < 0){
  224. fprint(2, "create %s: %r\n", name);
  225. errors++;
  226. return;
  227. }
  228. off = 0;
  229. while((n = vacfileread(f, buf, sizeof buf, off)) > 0){
  230. if(writen(fd, buf, n) != n){
  231. fprint(2, "write %s: %r\n", name);
  232. errors++;
  233. close(fd);
  234. remove(name);
  235. return;
  236. }
  237. off += n;
  238. }
  239. close(fd);
  240. }
  241. }
  242. if(vdir && settimes && !tostdout){
  243. nulldir(&d);
  244. d.mtime = vdir->mtime;
  245. if(dirwstat(name, &d) < 0)
  246. fprint(2, "warning: setting mtime on %s: %r", name);
  247. }
  248. }
  249. int
  250. mtimefmt(Fmt *f)
  251. {
  252. Tm *tm;
  253. tm = localtime(va_arg(f->args, ulong));
  254. fmtprint(f, "%04d-%02d-%02d %02d:%02d",
  255. tm->year+1900, tm->mon+1, tm->mday,
  256. tm->hour, tm->min);
  257. return 0;
  258. }