mkext.c 5.3 KB

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