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