mkext.c 5.6 KB

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