mkext.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  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. /*
  10. * bzip2-based file system.
  11. * the file system itself is just a bzipped2 xzipped mkfs archive
  12. * prefixed with "bzfilesystem\n" and suffixed with
  13. * a kilobyte of zeros.
  14. *
  15. * changes to the file system are only kept in
  16. * memory, not written back to the disk.
  17. *
  18. * this is intended for use on a floppy boot disk.
  19. * we assume the file is in the dos file system and
  20. * contiguous on the disk: finding it amounts to
  21. * looking at the beginning of each sector for
  22. * "bzfilesystem\n". then we pipe it through
  23. * bunzip2 and store the files in a file tree in memory.
  24. * things are slightly complicated by the fact that
  25. * devfloppy requires reads to be on a 512-byte
  26. * boundary and be a multiple of 512 bytes; we
  27. * fork a process to relieve bunzip2 of this restriction.
  28. */
  29. #include <u.h>
  30. #include <libc.h>
  31. #include <bio.h>
  32. #include <auth.h>
  33. #include <fcall.h>
  34. #include "bzfs.h"
  35. enum{
  36. LEN = 8*1024,
  37. NFLDS = 6, /* filename, modes, uid, gid, mtime, bytes */
  38. };
  39. void mkdirs(char*, char*);
  40. void mkdir(char*, uint32_t, uint32_t, char*, char*);
  41. void extract(char*, uint32_t, uint32_t, char*, char*, uint32_t);
  42. void seekpast(uint32_t);
  43. void error(char*, ...);
  44. void warn(char*, ...);
  45. void usage(void);
  46. char *mtpt;
  47. Biobufhdr bin;
  48. uchar binbuf[2*LEN];
  49. void
  50. usage(void)
  51. {
  52. fprint(2, "usage: bzfs [-m mtpt] [-s] [-f file] [-h]\n");
  53. exits("usage");
  54. }
  55. /*
  56. * floppy disks can only be read on 512-byte
  57. * boundaries and in 512 byte multiples.
  58. * feed one over a pipe to allow arbitrary reading.
  59. */
  60. char zero[512];
  61. int
  62. blockread(int in, char *first, int nfirst)
  63. {
  64. int p[2], out, n, rv;
  65. char blk[512];
  66. if(pipe(p) < 0)
  67. sysfatal("pipe: %r");
  68. rv = p[0];
  69. out = p[1];
  70. switch(rfork(RFPROC|RFNOTEG|RFFDG)){
  71. case -1:
  72. sysfatal("fork: %r");
  73. case 0:
  74. close(rv);
  75. break;
  76. default:
  77. close(in);
  78. close(out);
  79. return rv;
  80. }
  81. write(out, first, nfirst);
  82. while((n=read(in, blk, sizeof blk)) > 0){
  83. if(write(out, blk, n) != n)
  84. break;
  85. if(n == sizeof(blk) && memcmp(zero, blk, n) == n)
  86. break;
  87. }
  88. _exits(0);
  89. return -1;
  90. }
  91. enum { NAMELEN = 28 };
  92. void
  93. main(int argc, char **argv)
  94. {
  95. char *rargv[10];
  96. int rargc;
  97. char *fields[NFLDS], name[2*LEN], *p, *namep;
  98. char uid[NAMELEN], gid[NAMELEN];
  99. ulong mode, bytes, mtime;
  100. char *file;
  101. int i, n, stdin, fd, chatty;
  102. char blk[512];
  103. if(argc>1 && strcmp(argv[1], "RAMFS") == 0){
  104. argv[1] = argv[0];
  105. ramfsmain(argc-1, argv+1);
  106. exits(nil);
  107. }
  108. if(argc>1 && strcmp(argv[1], "BUNZIP") == 0){
  109. _unbzip(0, 1);
  110. exits(nil);
  111. }
  112. rfork(RFNOTEG);
  113. stdin = 0;
  114. file = nil;
  115. namep = name;
  116. mtpt = "/root";
  117. chatty = 0;
  118. ARGBEGIN{
  119. case 'd':
  120. chatty = !chatty;
  121. break;
  122. case 'f':
  123. file = ARGF();
  124. break;
  125. case 's':
  126. stdin++;
  127. break;
  128. case 'm':
  129. mtpt = ARGF();
  130. break;
  131. default:
  132. usage();
  133. }ARGEND
  134. if(argc != 0)
  135. usage();
  136. if(file == nil) {
  137. fprint(2, "must specify -f file\n");
  138. usage();
  139. }
  140. if((fd = open(file, OREAD)) < 0) {
  141. fprint(2, "cannot open \"%s\": %r\n", file);
  142. exits("open");
  143. }
  144. rargv[0] = "ramfs";
  145. rargc = 1;
  146. if(stdin)
  147. rargv[rargc++] = "-i";
  148. rargv[rargc++] = "-m";
  149. rargv[rargc++] = mtpt;
  150. rargv[rargc] = nil;
  151. ramfsmain(rargc, rargv);
  152. if(1 || strstr(file, "disk")) { /* search for archive on block boundary */
  153. if(chatty) fprint(2, "searching for bz\n");
  154. for(i=0;; i++){
  155. if((n = readn(fd, blk, sizeof blk)) != sizeof blk)
  156. sysfatal("read %d gets %d: %r\n", i, n);
  157. if(strncmp(blk, "bzfilesystem\n", 13) == 0)
  158. break;
  159. }
  160. if(chatty) fprint(2, "found at %d\n", i);
  161. }
  162. if(chdir(mtpt) < 0)
  163. error("chdir %s: %r", mtpt);
  164. fd = unbflz(unbzip(blockread(fd, blk+13, sizeof(blk)-13)));
  165. Binits(&bin, fd, OREAD, binbuf, sizeof binbuf);
  166. while(p = Brdline(&bin, '\n')){
  167. p[Blinelen(&bin)-1] = '\0';
  168. if(chatty) fprint(2, "%s\n", p);
  169. if(strcmp(p, "end of archive") == 0){
  170. _exits(0);
  171. }
  172. if(getfields(p, fields, NFLDS, 0, " \t") != NFLDS){
  173. warn("too few fields in file header");
  174. continue;
  175. }
  176. strcpy(namep, fields[0]);
  177. mode = strtoul(fields[1], 0, 8);
  178. mtime = strtoul(fields[4], 0, 10);
  179. bytes = strtoul(fields[5], 0, 10);
  180. strncpy(uid, fields[2], NAMELEN);
  181. strncpy(gid, fields[3], NAMELEN);
  182. if(mode & DMDIR)
  183. mkdir(name, mode, mtime, uid, gid);
  184. else
  185. extract(name, mode, mtime, uid, gid, bytes);
  186. }
  187. fprint(2, "premature end of archive\n");
  188. exits("premature end of archive");
  189. }
  190. char buf[8192];
  191. int
  192. ffcreate(char *name, uint32_t mode, char *uid, char *gid, uint32_t mtime,
  193. int length)
  194. {
  195. int fd, om;
  196. Dir nd;
  197. sprint(buf, "%s/%s", mtpt, name);
  198. om = ORDWR;
  199. if(mode&DMDIR)
  200. om = OREAD;
  201. if((fd = create(buf, om, (mode&DMDIR)|0666)) < 0)
  202. error("create %s: %r", buf);
  203. nulldir(&nd);
  204. nd.mode = mode;
  205. nd.uid = uid;
  206. nd.gid = gid;
  207. nd.mtime = mtime;
  208. if(length)
  209. nd.length = length;
  210. if(dirfwstat(fd, &nd) < 0)
  211. error("fwstat %s: %r", buf);
  212. return fd;
  213. }
  214. void
  215. mkdir(char *name, uint32_t mode, uint32_t mtime, char *uid, char *gid)
  216. {
  217. close(ffcreate(name, mode, uid, gid, mtime, 0));
  218. }
  219. void
  220. extract(char *name, uint32_t mode, uint32_t mtime, char *uid, char *gid,
  221. uint32_t bytes)
  222. {
  223. int fd, tot, n;
  224. fd = ffcreate(name, mode, uid, gid, mtime, bytes);
  225. for(tot = 0; tot < bytes; tot += n){
  226. n = sizeof buf;
  227. if(tot + n > bytes)
  228. n = bytes - tot;
  229. n = Bread(&bin, buf, n);
  230. if(n <= 0)
  231. error("premature eof reading %s", name);
  232. if(write(fd, buf, n) != n)
  233. error("short write writing %s", name);
  234. }
  235. close(fd);
  236. }
  237. void
  238. error(char *fmt, ...)
  239. {
  240. char buf[1024];
  241. va_list arg;
  242. sprint(buf, "%s: ", argv0);
  243. va_start(arg, fmt);
  244. vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg);
  245. va_end(arg);
  246. fprint(2, "%s\n", buf);
  247. exits(0);
  248. }
  249. void
  250. warn(char *fmt, ...)
  251. {
  252. char buf[1024];
  253. va_list arg;
  254. sprint(buf, "%s: ", argv0);
  255. va_start(arg, fmt);
  256. vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg);
  257. va_end(arg);
  258. fprint(2, "%s\n", buf);
  259. }
  260. int
  261. _efgfmt(Fmt*)
  262. {
  263. return -1;
  264. }