mntgen.c (3755B)
1 #include <u.h> 2 #include <libc.h> 3 #include <fcall.h> 4 #include <thread.h> 5 #include <9p.h> 6 #include <mp.h> 7 #include <libsec.h> 8 9 static void 10 usage(void) 11 { 12 fprint(2, "mntgen [-s srvname] [mtpt]\n"); 13 threadexits("usage"); 14 } 15 16 ulong time0; 17 18 typedef struct Tab Tab; 19 struct Tab 20 { 21 char *name; 22 vlong qid; 23 ulong time; 24 int ref; 25 }; 26 27 Tab *tab; 28 int ntab; 29 int mtab; 30 31 static Tab* 32 findtab(vlong path) 33 { 34 int i; 35 36 for(i=0; i<ntab; i++) 37 if(tab[i].qid == path) 38 return &tab[i]; 39 return nil; 40 } 41 42 static vlong 43 hash(char *name) 44 { 45 vlong digest[MD5dlen / sizeof(vlong) + 1]; 46 md5((uchar *)name, strlen(name), (uchar *)digest, nil); 47 return digest[0] & ((1ULL<<48)-1); 48 } 49 50 static void 51 fsopen(Req *r) 52 { 53 if(r->ifcall.mode != OREAD) 54 respond(r, "permission denied"); 55 else 56 respond(r, nil); 57 } 58 59 static int 60 dirgen(int i, Dir *d, void* v) 61 { 62 USED(v); 63 64 if(i >= ntab) 65 return -1; 66 memset(d, 0, sizeof *d); 67 d->qid.type = QTDIR; 68 d->uid = estrdup9p("sys"); 69 d->gid = estrdup9p("sys"); 70 d->mode = DMDIR|0555; 71 d->length = 0; 72 if(i == -1){ 73 d->name = estrdup9p("/"); 74 d->atime = d->mtime = time0; 75 }else{ 76 d->qid.path = tab[i].qid; 77 d->name = estrdup9p(tab[i].name); 78 d->atime = d->mtime = tab[i].time; 79 } 80 return 0; 81 } 82 83 static void 84 fsread(Req *r) 85 { 86 if(r->fid->qid.path == 0) 87 dirread9p(r, dirgen, nil); 88 else 89 r->ofcall.count = 0; 90 respond(r, nil); 91 } 92 93 static void 94 fsstat(Req *r) 95 { 96 Tab *t; 97 vlong qid; 98 99 qid = r->fid->qid.path; 100 if(qid == 0) 101 dirgen(-1, &r->d, nil); 102 else{ 103 if((t = findtab(qid)) == nil){ 104 respond(r, "path not found ( ??? )"); 105 return; 106 } 107 dirgen(t-tab, &r->d, nil); 108 } 109 respond(r, nil); 110 } 111 112 static char* 113 fswalk1(Fid *fid, char *name, void* v) 114 { 115 int i; 116 Tab *t; 117 vlong h; 118 119 USED(v); 120 121 if(fid->qid.path != 0){ 122 /* nothing in child directory */ 123 if(strcmp(name, "..") == 0){ 124 if((t = findtab(fid->qid.path)) != nil) 125 t->ref--; 126 fid->qid.path = 0; 127 return nil; 128 } 129 return "path not found"; 130 } 131 /* root */ 132 if(strcmp(name, "..") == 0) 133 return nil; 134 for(i=0; i<ntab; i++) 135 if(strcmp(tab[i].name, name) == 0){ 136 tab[i].ref++; 137 fid->qid.path = tab[i].qid; 138 return nil; 139 } 140 h = hash(name); 141 if(findtab(h) != nil) 142 return "hash collision"; 143 144 /* create it */ 145 if(ntab == mtab){ 146 if(mtab == 0) 147 mtab = 16; 148 else 149 mtab *= 2; 150 tab = erealloc9p(tab, sizeof(tab[0])*mtab); 151 } 152 tab[ntab].qid = h; 153 fid->qid.path = tab[ntab].qid; 154 tab[ntab].name = estrdup9p(name); 155 tab[ntab].time = time(0); 156 tab[ntab].ref = 1; 157 ntab++; 158 159 return nil; 160 } 161 162 static char* 163 fsclone(Fid *fid, Fid* v, void* w) 164 { 165 USED(v); 166 USED(w); 167 168 Tab *t; 169 170 if((t = findtab(fid->qid.path)) != nil) 171 t->ref++; 172 return nil; 173 } 174 175 static void 176 fswalk(Req *r) 177 { 178 walkandclone(r, fswalk1, fsclone, nil); 179 } 180 181 static void 182 fsclunk(Fid *fid) 183 { 184 Tab *t; 185 vlong qid; 186 187 qid = fid->qid.path; 188 if(qid == 0) 189 return; 190 if((t = findtab(qid)) == nil){ 191 fprint(2, "warning: cannot find %llux\n", qid); 192 return; 193 } 194 if(--t->ref == 0){ 195 free(t->name); 196 tab[t-tab] = tab[--ntab]; 197 }else if(t->ref < 0) 198 fprint(2, "warning: negative ref count for %s\n", t->name); 199 } 200 201 static void 202 fsattach(Req *r) 203 { 204 char *spec; 205 206 spec = r->ifcall.aname; 207 if(spec && spec[0]){ 208 respond(r, "invalid attach specifier"); 209 return; 210 } 211 212 r->ofcall.qid = (Qid){0, 0, QTDIR}; 213 r->fid->qid = r->ofcall.qid; 214 respond(r, nil); 215 } 216 217 Srv fs= 218 { 219 .attach= fsattach, 220 .open= fsopen, 221 .read= fsread, 222 .stat= fsstat, 223 .walk= fswalk, 224 .destroyfid= fsclunk 225 }; 226 227 int 228 threadmaybackground(void) 229 { 230 return 1; 231 } 232 233 void 234 threadmain(int argc, char *argv[]) 235 { 236 char *service; 237 238 time0 = time(0); 239 service = nil; 240 ARGBEGIN{ 241 case 'D': 242 chatty9p++; 243 break; 244 case 's': 245 service = EARGF(usage()); 246 break; 247 default: 248 usage(); 249 }ARGEND 250 251 if(argc > 1) 252 usage(); 253 threadpostmountsrv(&fs, service, argc ? argv[0] : "/n", MAFTER); 254 threadexits(nil); 255 } 256