archfs.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. /*
  2. * archfs - mount mkfs style archives
  3. */
  4. #include <u.h>
  5. #include <libc.h>
  6. #include <bio.h>
  7. #include <auth.h>
  8. #include <fcall.h>
  9. #include <thread.h>
  10. #include <9p.h>
  11. Tree *archtree;
  12. Biobuf *b;
  13. int verbose;
  14. typedef struct Ahdr Ahdr;
  15. struct Ahdr {
  16. char *name;
  17. Dir;
  18. };
  19. typedef struct Arch Arch;
  20. struct Arch {
  21. vlong off;
  22. vlong length;
  23. };
  24. static void*
  25. emalloc(long sz)
  26. {
  27. void *v;
  28. v = malloc(sz);
  29. if(v == nil)
  30. sysfatal("malloc %lud fails\n", sz);
  31. memset(v, 0, sz);
  32. return v;
  33. }
  34. static char*
  35. estrdup(char *s)
  36. {
  37. s = strdup(s);
  38. if(s == nil)
  39. sysfatal("strdup (%.10s) fails\n", s);
  40. return s;
  41. }
  42. static char*
  43. Bgetline(Biobuf *b)
  44. {
  45. char *p;
  46. if(p = Brdline(b, '\n'))
  47. p[Blinelen(b)-1] = '\0';
  48. return p;
  49. }
  50. Ahdr*
  51. gethdr(Biobuf *b)
  52. {
  53. Ahdr *a;
  54. char *p, *f[10];
  55. if((p = Bgetline(b)) == nil)
  56. return nil;
  57. if(strcmp(p, "end of archive") == 0) {
  58. werrstr("");
  59. return nil;
  60. }
  61. if(tokenize(p, f, nelem(f)) != 6) {
  62. werrstr("bad format");
  63. return nil;
  64. }
  65. a = emalloc(sizeof(*a));
  66. a->name = estrdup(f[0]);
  67. a->mode = strtoul(f[1], 0, 8);
  68. a->uid = estrdup(f[2]);
  69. a->gid = estrdup(f[3]);
  70. a->mtime = strtoll(f[4], 0, 10);
  71. a->length = strtoll(f[5], 0, 10);
  72. return a;
  73. }
  74. static Arch*
  75. newarch(vlong off, vlong length)
  76. {
  77. static Arch *abuf;
  78. static int nabuf;
  79. if(nabuf == 0) {
  80. nabuf = 256;
  81. abuf = emalloc(sizeof(Arch)*nabuf);
  82. }
  83. nabuf--;
  84. abuf->off = off;
  85. abuf->length = length;
  86. return abuf++;
  87. }
  88. static File*
  89. createpath(File *f, char *name, char *u, ulong m)
  90. {
  91. char *p;
  92. File *nf;
  93. if(verbose)
  94. fprint(2, "createpath %s\n", name);
  95. incref(f);
  96. while(f && (p = strchr(name, '/'))) {
  97. *p = '\0';
  98. if(strcmp(name, "") != 0 && strcmp(name, ".") != 0){
  99. /* this would be a race if we were multithreaded */
  100. incref(f); /* so walk doesn't kill it immediately on failure */
  101. if((nf = walkfile(f, name)) == nil)
  102. nf = createfile(f, name, u, DMDIR|0777, nil);
  103. decref(f);
  104. f = nf;
  105. }
  106. *p = '/';
  107. name = p+1;
  108. }
  109. if(f == nil)
  110. return nil;
  111. incref(f);
  112. if((nf = walkfile(f, name)) == nil)
  113. nf = createfile(f, name, u, m, nil);
  114. decref(f);
  115. return nf;
  116. }
  117. static void
  118. archcreatefile(char *name, Arch *arch, Dir *d)
  119. {
  120. File *f;
  121. f = createpath(archtree->root, name, d->uid, d->mode);
  122. if(f == nil)
  123. sysfatal("creating %s: %r", name);
  124. free(f->gid);
  125. f->gid = estrdup9p(d->gid);
  126. f->aux = arch;
  127. f->mtime = d->mtime;
  128. f->length = d->length;
  129. decref(f);
  130. }
  131. static void
  132. fsread(Req *r)
  133. {
  134. Arch *a;
  135. char err[ERRMAX];
  136. int n;
  137. a = r->fid->file->aux;
  138. if(a->length <= r->ifcall.offset)
  139. r->ifcall.count = 0;
  140. else if(a->length <= r->ifcall.offset+r->ifcall.count)
  141. r->ifcall.count = a->length - r->ifcall.offset;
  142. werrstr("unknown error");
  143. if(Bseek(b, a->off+r->ifcall.offset, 0) < 0
  144. || (n = Bread(b, r->ofcall.data, r->ifcall.count)) < 0) {
  145. err[0] = '\0';
  146. errstr(err, sizeof err);
  147. respond(r, err);
  148. } else {
  149. r->ofcall.count = n;
  150. respond(r, nil);
  151. }
  152. }
  153. Srv fs = {
  154. .read= fsread,
  155. };
  156. static void
  157. usage(void)
  158. {
  159. fprint(2, "usage: archfs [-abcC] [-m mtpt] archfile\n");
  160. exits("usage");
  161. }
  162. void
  163. main(int argc, char **argv)
  164. {
  165. Ahdr *a;
  166. ulong flag;
  167. char *mtpt;
  168. char err[ERRMAX];
  169. flag = 0;
  170. mtpt = "/mnt/arch";
  171. ARGBEGIN{
  172. case 'D':
  173. chatty9p++;
  174. break;
  175. case 'a':
  176. flag |= MAFTER;
  177. break;
  178. case 'b':
  179. flag |= MBEFORE;
  180. break;
  181. case 'c':
  182. flag |= MCREATE;
  183. break;
  184. case 'C':
  185. flag |= MCACHE;
  186. break;
  187. case 'm':
  188. mtpt = ARGF();
  189. break;
  190. default:
  191. usage();
  192. break;
  193. }ARGEND;
  194. if(argc != 1)
  195. usage();
  196. if((b = Bopen(argv[0], OREAD)) == nil)
  197. sysfatal("open '%s': %r", argv[0]);
  198. archtree = fs.tree = alloctree("sys", "sys", DMDIR|0775, nil);
  199. while(a = gethdr(b)) {
  200. archcreatefile(a->name, newarch(Boffset(b), a->length), a);
  201. Bseek(b, a->length, 1);
  202. }
  203. err[0] = '\0';
  204. errstr(err, sizeof err);
  205. if(err[0])
  206. sysfatal("reading archive: %s", err);
  207. postmountsrv(&fs, nil, mtpt, flag);
  208. exits(0);
  209. }