archfs.c 4.3 KB

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