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 exits("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*) 61 { 62 if(i >= ntab) 63 return -1; 64 memset(d, 0, sizeof *d); 65 d->qid.type = QTDIR; 66 d->uid = estrdup9p("sys"); 67 d->gid = estrdup9p("sys"); 68 d->mode = DMDIR|0555; 69 d->length = 0; 70 if(i == -1){ 71 d->name = estrdup9p("/"); 72 d->atime = d->mtime = time0; 73 }else{ 74 d->qid.path = tab[i].qid; 75 d->name = estrdup9p(tab[i].name); 76 d->atime = d->mtime = tab[i].time; 77 } 78 return 0; 79 } 80 81 static void 82 fsread(Req *r) 83 { 84 if(r->fid->qid.path == 0) 85 dirread9p(r, dirgen, nil); 86 else 87 r->ofcall.count = 0; 88 respond(r, nil); 89 } 90 91 static void 92 fsstat(Req *r) 93 { 94 Tab *t; 95 vlong qid; 96 97 qid = r->fid->qid.path; 98 if(qid == 0) 99 dirgen(-1, &r->d, nil); 100 else{ 101 if((t = findtab(qid)) == nil){ 102 respond(r, "path not found (???)"); 103 return; 104 } 105 dirgen(t-tab, &r->d, nil); 106 } 107 respond(r, nil); 108 } 109 110 static char* 111 fswalk1(Fid *fid, char *name, void*) 112 { 113 int i; 114 Tab *t; 115 vlong h; 116 117 if(fid->qid.path != 0){ 118 /* nothing in child directory */ 119 if(strcmp(name, "..") == 0){ 120 if((t = findtab(fid->qid.path)) != nil) 121 t->ref--; 122 fid->qid.path = 0; 123 return nil; 124 } 125 return "path not found"; 126 } 127 /* root */ 128 if(strcmp(name, "..") == 0) 129 return nil; 130 for(i=0; i<ntab; i++) 131 if(strcmp(tab[i].name, name) == 0){ 132 tab[i].ref++; 133 fid->qid.path = tab[i].qid; 134 return nil; 135 } 136 h = hash(name); 137 if(findtab(h) != nil) 138 return "hash collision"; 139 140 /* create it */ 141 if(ntab == mtab){ 142 if(mtab == 0) 143 mtab = 16; 144 else 145 mtab *= 2; 146 tab = erealloc9p(tab, sizeof(tab[0])*mtab); 147 } 148 tab[ntab].qid = h; 149 fid->qid.path = tab[ntab].qid; 150 tab[ntab].name = estrdup9p(name); 151 tab[ntab].time = time(0); 152 tab[ntab].ref = 1; 153 ntab++; 154 155 return nil; 156 } 157 158 static char* 159 fsclone(Fid *fid, Fid*, void*) 160 { 161 Tab *t; 162 163 if((t = findtab(fid->qid.path)) != nil) 164 t->ref++; 165 return nil; 166 } 167 168 static void 169 fswalk(Req *r) 170 { 171 walkandclone(r, fswalk1, fsclone, nil); 172 } 173 174 static void 175 fsclunk(Fid *fid) 176 { 177 Tab *t; 178 vlong qid; 179 180 qid = fid->qid.path; 181 if(qid == 0) 182 return; 183 if((t = findtab(qid)) == nil){ 184 fprint(2, "warning: cannot find %llux\n", qid); 185 return; 186 } 187 if(--t->ref == 0){ 188 free(t->name); 189 tab[t-tab] = tab[--ntab]; 190 }else if(t->ref < 0) 191 fprint(2, "warning: negative ref count for %s\n", t->name); 192 } 193 194 static void 195 fsattach(Req *r) 196 { 197 char *spec; 198 199 spec = r->ifcall.aname; 200 if(spec && spec[0]){ 201 respond(r, "invalid attach specifier"); 202 return; 203 } 204 205 r->ofcall.qid = (Qid){0, 0, QTDIR}; 206 r->fid->qid = r->ofcall.qid; 207 respond(r, nil); 208 } 209 210 Srv fs= 211 { 212 .attach= fsattach, 213 .open= fsopen, 214 .read= fsread, 215 .stat= fsstat, 216 .walk= fswalk, 217 .destroyfid= fsclunk 218 }; 219 220 void 221 main(int argc, char **argv) 222 { 223 char *service; 224 225 time0 = time(0); 226 service = nil; 227 ARGBEGIN{ 228 case 'D': 229 chatty9p++; 230 break; 231 case 's': 232 service = EARGF(usage()); 233 break; 234 default: 235 usage(); 236 }ARGEND 237 238 if(argc > 1) 239 usage(); 240 postmountsrv(&fs, service, argc ? argv[0] : "/n", MAFTER); 241 exits(nil); 242 } 243