mkext.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include <u.h>
  10. #include <libc.h>
  11. #include <bio.h>
  12. enum{
  13. LEN = 8*1024,
  14. NFLDS = 6, /* filename, modes, uid, gid, mtime, bytes */
  15. };
  16. int selected(char*, int, char*[]);
  17. void mkdirs(char*, char*);
  18. void mkdir(char*, uint32_t, uint32_t, char*, char*);
  19. void extract(char*, uint32_t, uint32_t, char*, char*,
  20. uint64_t);
  21. void seekpast(uint64_t);
  22. void error(char*, ...);
  23. void warn(char*, ...);
  24. void usage(void);
  25. //#pragma varargck argpos warn 1
  26. //#pragma varargck argpos error 1
  27. Biobufhdr bin;
  28. unsigned char binbuf[2*LEN];
  29. char linebuf[LEN];
  30. int uflag;
  31. int hflag;
  32. int vflag;
  33. int Tflag;
  34. void
  35. main(int argc, char **argv)
  36. {
  37. Biobuf bout;
  38. char *fields[NFLDS], name[2*LEN], *p, *namep;
  39. char *uid, *gid;
  40. uint32_t mode, mtime;
  41. uint64_t bytes;
  42. quotefmtinstall();
  43. namep = name;
  44. ARGBEGIN{
  45. case 'd':
  46. p = ARGF();
  47. if(strlen(p) >= LEN)
  48. error("destination fs name too long\n");
  49. strcpy(name, p);
  50. namep = name + strlen(name);
  51. break;
  52. case 'h':
  53. hflag = 1;
  54. Binit(&bout, 1, OWRITE);
  55. break;
  56. case 'u':
  57. uflag = 1;
  58. Tflag = 1;
  59. break;
  60. case 'T':
  61. Tflag = 1;
  62. break;
  63. case 'v':
  64. vflag = 1;
  65. break;
  66. default:
  67. usage();
  68. }ARGEND
  69. Binits(&bin, 0, OREAD, binbuf, sizeof binbuf);
  70. while((p = Brdline(&bin, '\n')) != nil){
  71. p[Blinelen(&bin)-1] = '\0';
  72. strcpy(linebuf, p);
  73. p = linebuf;
  74. if(strcmp(p, "end of archive") == 0){
  75. Bterm(&bout);
  76. fprint(2, "done\n");
  77. exits(0);
  78. }
  79. if (gettokens(p, fields, NFLDS, " \t") != NFLDS){
  80. warn("too few fields in file header");
  81. continue;
  82. }
  83. p = unquotestrdup(fields[0]);
  84. strcpy(namep, p);
  85. free(p);
  86. mode = strtoul(fields[1], 0, 8);
  87. uid = fields[2];
  88. gid = fields[3];
  89. mtime = strtoul(fields[4], 0, 10);
  90. bytes = strtoull(fields[5], 0, 10);
  91. if(argc){
  92. if(!selected(namep, argc, argv)){
  93. if(bytes)
  94. seekpast(bytes);
  95. continue;
  96. }
  97. mkdirs(name, namep);
  98. }
  99. if(hflag){
  100. Bprint(&bout, "%q %lo %q %q %lu %llu\n",
  101. name, mode, uid, gid, mtime, bytes);
  102. if(bytes)
  103. seekpast(bytes);
  104. continue;
  105. }
  106. if(mode & DMDIR)
  107. mkdir(name, mode, mtime, uid, gid);
  108. else
  109. extract(name, mode, mtime, uid, gid, bytes);
  110. }
  111. fprint(2, "premature end of archive\n");
  112. exits("premature end of archive");
  113. }
  114. int
  115. fileprefix(char *prefix, char *s)
  116. {
  117. while(*prefix)
  118. if(*prefix++ != *s++)
  119. return 0;
  120. if(*s && *s != '/')
  121. return 0;
  122. return 1;
  123. }
  124. int
  125. selected(char *s, int argc, char *argv[])
  126. {
  127. int i;
  128. for(i=0; i<argc; i++)
  129. if(fileprefix(argv[i], s))
  130. return 1;
  131. return 0;
  132. }
  133. void
  134. mkdirs(char *name, char *namep)
  135. {
  136. char buf[2*LEN], *p;
  137. int fd;
  138. strcpy(buf, name);
  139. for(p = &buf[namep - name]; (p = utfrune(p, '/')) != nil; p++){
  140. if(p[1] == '\0')
  141. return;
  142. *p = 0;
  143. fd = create(buf, OREAD, 0775|DMDIR);
  144. close(fd);
  145. *p = '/';
  146. }
  147. }
  148. void
  149. mkdir(char *name, uint32_t mode, uint32_t mtime, char *uid,
  150. char *gid)
  151. {
  152. Dir *d, xd;
  153. int fd;
  154. char *p;
  155. char olderr[256];
  156. fd = create(name, OREAD, mode);
  157. if(fd < 0){
  158. rerrstr(olderr, sizeof(olderr));
  159. if((d = dirstat(name)) == nil || !(d->mode & DMDIR)){
  160. free(d);
  161. warn("can't make directory %q, mode %lo: %s", name, mode, olderr);
  162. return;
  163. }
  164. free(d);
  165. }
  166. close(fd);
  167. d = &xd;
  168. nulldir(d);
  169. p = utfrrune(name, L'/');
  170. if(p)
  171. p++;
  172. else
  173. p = name;
  174. d->name = p;
  175. if(uflag){
  176. d->uid = uid;
  177. d->gid = gid;
  178. }
  179. if(Tflag)
  180. d->mtime = mtime;
  181. d->mode = mode;
  182. if(dirwstat(name, d) < 0)
  183. warn("can't set modes for %q: %r", name);
  184. if(uflag||Tflag){
  185. if((d = dirstat(name)) == nil){
  186. warn("can't reread modes for %q: %r", name);
  187. return;
  188. }
  189. if(Tflag && d->mtime != mtime)
  190. warn("%q: time mismatch %lu %lu\n", name, mtime, d->mtime);
  191. if(uflag && strcmp(uid, d->uid))
  192. warn("%q: uid mismatch %q %q", name, uid, d->uid);
  193. if(uflag && strcmp(gid, d->gid))
  194. warn("%q: gid mismatch %q %q", name, gid, d->gid);
  195. }
  196. }
  197. void
  198. extract(char *name, uint32_t mode, uint32_t mtime, char *uid,
  199. char *gid,
  200. uint64_t bytes)
  201. {
  202. Dir d, *nd;
  203. Biobuf *b;
  204. char buf[LEN];
  205. char *p;
  206. uint32_t n;
  207. uint64_t tot;
  208. if(vflag)
  209. print("x %q %llu bytes\n", name, bytes);
  210. b = Bopen(name, OWRITE);
  211. if(!b){
  212. warn("can't make file %q: %r", name);
  213. seekpast(bytes);
  214. return;
  215. }
  216. for(tot = 0; tot < bytes; tot += n){
  217. n = sizeof buf;
  218. if(tot + n > bytes)
  219. n = bytes - tot;
  220. n = Bread(&bin, buf, n);
  221. if(n <= 0)
  222. error("premature eof reading %q", name);
  223. if(Bwrite(b, buf, n) != n)
  224. warn("error writing %q: %r", name);
  225. }
  226. nulldir(&d);
  227. p = utfrrune(name, '/');
  228. if(p)
  229. p++;
  230. else
  231. p = name;
  232. d.name = p;
  233. if(uflag){
  234. d.uid = uid;
  235. d.gid = gid;
  236. }
  237. if(Tflag)
  238. d.mtime = mtime;
  239. d.mode = mode;
  240. Bflush(b);
  241. if(dirfwstat(Bfildes(b), &d) < 0)
  242. warn("can't set modes for %q: %r", name);
  243. if(uflag||Tflag){
  244. if((nd = dirfstat(Bfildes(b))) == nil)
  245. warn("can't reread modes for %q: %r", name);
  246. else{
  247. if(Tflag && nd->mtime != mtime)
  248. warn("%q: time mismatch %lu %lu\n",
  249. name, mtime, nd->mtime);
  250. if(uflag && strcmp(uid, nd->uid))
  251. warn("%q: uid mismatch %q %q",
  252. name, uid, nd->uid);
  253. if(uflag && strcmp(gid, nd->gid))
  254. warn("%q: gid mismatch %q %q",
  255. name, gid, nd->gid);
  256. free(nd);
  257. }
  258. }
  259. Bterm(b);
  260. }
  261. void
  262. seekpast(uint64_t bytes)
  263. {
  264. char buf[LEN];
  265. int32_t n;
  266. uint64_t tot;
  267. for(tot = 0; tot < bytes; tot += n){
  268. n = sizeof buf;
  269. if(tot + n > bytes)
  270. n = bytes - tot;
  271. n = Bread(&bin, buf, n);
  272. if(n < 0)
  273. error("premature eof");
  274. }
  275. }
  276. void
  277. error(char *fmt, ...)
  278. {
  279. char buf[1024];
  280. va_list arg;
  281. sprint(buf, "%q: ", argv0);
  282. va_start(arg, fmt);
  283. vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg);
  284. va_end(arg);
  285. fprint(2, "%s\n", buf);
  286. exits(0);
  287. }
  288. void
  289. warn(char *fmt, ...)
  290. {
  291. char buf[1024];
  292. va_list arg;
  293. sprint(buf, "%q: ", argv0);
  294. va_start(arg, fmt);
  295. vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg);
  296. va_end(arg);
  297. fprint(2, "%s\n", buf);
  298. }
  299. void
  300. usage(void)
  301. {
  302. fprint(2, "usage: mkext [-h] [-u] [-v] [-d dest-fs] [file ...]\n");
  303. exits("usage");
  304. }