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
usage(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*
findtab(vlong path)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
hash(char * name)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
fsopen(Req * r)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
dirgen(int i,Dir * d,void *)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
fsread(Req * r)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
fsstat(Req * r)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*
fswalk1(Fid * fid,char * name,void *)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*
fsclone(Fid * fid,Fid *,void *)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
fswalk(Req * r)169 fswalk(Req *r)
170 {
171 walkandclone(r, fswalk1, fsclone, nil);
172 }
173
174 static void
fsclunk(Fid * fid)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
fsattach(Req * r)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
main(int argc,char ** argv)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