xref: /plan9-contrib/sys/src/cmd/dossrv/dosfs.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1 #include <u.h>
2 #include <libc.h>
3 #include <auth.h>
4 #include <fcall.h>
5 #include "iotrack.h"
6 #include "dat.h"
7 #include "fns.h"
8 
9 extern Fcall	thdr;
10 extern Fcall	rhdr;
11 extern char	data[sizeof(Fcall)+MAXFDATA];
12 extern char	fdata[MAXFDATA];
13 extern int	errno;
14 
15 void
16 rnop(void)
17 {
18 	chat("nop...");
19 }
20 void
21 rsession(void)
22 {
23 	memset(thdr.authid, 0, sizeof(thdr.authid));
24 	memset(thdr.authdom, 0, sizeof(thdr.authdom));
25 	memset(thdr.chal, 0, sizeof(thdr.chal));
26 	chat("session...");
27 }
28 void
29 rflush(void)
30 {
31 	chat("flush...");
32 }
33 void
34 rattach(void)
35 {
36 	Xfs *xf;
37 	Xfile *root;
38 	Dosptr *dp;
39 
40 	chat("attach(fid=%d,uname=\"%s\",aname=\"%s\",auth=\"%s\")...",
41 		thdr.fid, thdr.uname, thdr.aname, thdr.auth);
42 
43 	root = xfile(thdr.fid, Clean);
44 	if(!root){
45 		errno = Enomem;
46 		goto error;
47 	}
48 	root->xf = xf = getxfs(thdr.aname);
49 	if(!xf)
50 		goto error;
51 	if(xf->fmt==0 && dosfs(xf)<0){
52 		errno = Eformat;
53 		goto error;
54 	}
55 	root->qid.path = CHDIR;
56 	root->qid.vers = 0;
57 	root->xf->rootqid = root->qid;
58 	dp = malloc(sizeof(Dosptr));
59 	memset(dp, 0, sizeof(Dosptr));
60 	root->ptr = dp;
61 	rhdr.qid = root->qid;
62 	return;
63 error:
64 	if(root)
65 		xfile(thdr.fid, Clunk);
66 	return;
67 }
68 void
69 rclone(void)
70 {
71 	Xfile *of = xfile(thdr.fid, Asis);
72 	Xfile *nf = xfile(thdr.newfid, Clean);
73 
74 	chat("clone(fid=%d,newfid=%d)...", thdr.fid, thdr.newfid);
75 	if(!of)
76 		errno = Eio;
77 	else if(!nf)
78 		errno = Enomem;
79 	else{
80 		Xfile *next = nf->next;
81 		Dosptr *dp = malloc(sizeof(Dosptr));
82 		*nf = *of;
83 		nf->next = next;
84 		nf->fid = thdr.newfid;
85 		nf->ptr = dp;
86 		refxfs(nf->xf, 1);
87 		memmove(dp, of->ptr, sizeof(Dosptr));
88 		dp->p = 0;
89 		dp->d = 0;
90 	}
91 }
92 void
93 rwalk(void)
94 {
95 	Xfile *f=xfile(thdr.fid, Asis);
96 	Dosptr dp[1];
97 	int r;
98 
99 	chat("walk(fid=%d,name=\"%s\")...", thdr.fid, thdr.name);
100 	if(!f){
101 		chat("no xfile...");
102 		goto error;
103 	}
104 	if(!(f->qid.path & CHDIR)){
105 		chat("qid.path=0x%x...", f->qid.path);
106 		goto error;
107 	}
108 	if(strcmp(thdr.name, ".")==0){
109 		rhdr.qid = f->qid;
110 		return;
111 	}else if(strcmp(thdr.name, "..")==0){
112 		if(f->qid.path==f->xf->rootqid.path){
113 			chat("walkup from root...");
114 			rhdr.qid = f->qid;
115 			return;
116 		}
117 		r = walkup(f, dp);
118 		if(r < 0)
119 			goto error;
120 		memmove(f->ptr, dp, sizeof(Dosptr));
121 		if(dp->addr == 0)
122 			f->qid.path = f->xf->rootqid.path;
123 		else{
124 			Iosect *p; Dosdir *xd;
125 			p = getsect(f->xf, dp->addr);
126 			if(p == 0)
127 				goto error;
128 			xd = (Dosdir *)&p->iobuf[dp->offset];
129 			f->qid.path = CHDIR | GSHORT(xd->start);
130 			putsect(p);
131 		}
132 	}else{
133 		if(getfile(f) < 0)
134 			goto error;
135 		r = searchdir(f, thdr.name, dp, 0);
136 		putfile(f);
137 		if(r < 0)
138 			goto error;
139 		memmove(f->ptr, dp, sizeof(Dosptr));
140 		f->qid.path = GSHORT(dp->d->start);
141 		if(f->qid.path == 0)
142 			f->qid.path = f->xf->rootqid.path;
143 		else if(dp->d->attr & DDIR)
144 			f->qid.path |= CHDIR;
145 		putfile(f);
146 	}
147 	rhdr.qid = f->qid;
148 	return;
149 error:
150 	errno = Enonexist;
151 	return;
152 }
153 void
154 ropen(void)
155 {
156 	Xfile *f;
157 	Dosptr *dp;
158 	int attr, omode=0;
159 
160 	chat("open(fid=%d,mode=%d)...", thdr.fid, thdr.mode);
161 	f = xfile(thdr.fid, Asis);
162 	if(!f || (f->flags&Omodes)){
163 		errno = Eio;
164 		return;
165 	}
166 	dp = f->ptr;
167 	if(dp->paddr && (thdr.mode & ORCLOSE)){
168 		/*
169 		 * check on parent directory of file to be deleted
170 		 */
171 		Iosect *p = getsect(f->xf, dp->paddr);
172 		if(p == 0){
173 			errno = Eio;
174 			return;
175 		}
176 		attr = ((Dosdir *)&p->iobuf[dp->poffset])->attr;
177 		putsect(p);
178 		if(attr & DRONLY){
179 			errno = Eperm;
180 			return;
181 		}
182 		omode |= Orclose;
183 	}else if(thdr.mode & ORCLOSE)
184 		omode |= Orclose;
185 	if(getfile(f) < 0){
186 		errno = Enonexist;
187 		return;
188 	}
189 	if(dp->addr)
190 		attr = dp->d->attr;
191 	else
192 		attr = DDIR;
193 	switch(thdr.mode & 7){
194 	case OREAD:
195 	case OEXEC:
196 		omode |= Oread;
197 		break;
198 	case ORDWR:
199 		omode |= Oread;
200 		/* fall through */
201 	case OWRITE:
202 		omode |= Owrite;
203 		if(attr & DRONLY){
204 			errno = Eperm;
205 			goto out;
206 		}
207 		break;
208 	default:
209 		errno = Eio;
210 		goto out;
211 	}
212 	if(thdr.mode & OTRUNC){
213 		if(attr & DDIR || attr & DRONLY){
214 			errno = Eperm;
215 			goto out;
216 		}
217 		if(truncfile(f, 0) < 0){
218 			errno = Eio;
219 			goto out;
220 		}
221 	}
222 	f->flags |= omode;
223 	chat("f->qid=0x%8.8lux...", f->qid.path);
224 	rhdr.qid = f->qid;
225 out:
226 	putfile(f);
227 }
228 void
229 rcreate(void)
230 {
231 	Dosbpb *bp;
232 	Xfile *f;
233 	Dosptr *pdp, *ndp;
234 	Iosect *xp;
235 	Dosdir *pd, *nd, *xd;
236 	int attr, omode=0, start;
237 
238 	chat("create(fid=%d,name=\"%s\",perm=%uo,mode=%d)...",
239 		thdr.fid, thdr.name, thdr.perm, thdr.mode);
240 	f = xfile(thdr.fid, Asis);
241 	if(!f || (f->flags&Omodes) || getfile(f)<0){
242 		errno = Eio;
243 		return;
244 	}
245 	ndp = malloc(sizeof(Dosptr));
246 	pdp = f->ptr;
247 	pd = pdp->addr ? pdp->d : 0;
248 	attr = pd ? pd->attr : DDIR;
249 	if(!(attr & DDIR) || (attr & DRONLY)){
250 badperm:
251 		if(ndp)
252 			free(ndp);
253 		putfile(f);
254 		errno = Eperm;
255 		return;
256 	}
257 	if(thdr.mode & ORCLOSE)
258 		omode |= Orclose;
259 	switch(thdr.mode & 7){
260 	case OREAD:
261 	case OEXEC:
262 		omode |= Oread;
263 		break;
264 	case ORDWR:
265 		omode |= Oread;
266 		/* fall through */
267 	case OWRITE:
268 		omode |= Owrite;
269 		if(thdr.perm & CHDIR)
270 			goto badperm;
271 		break;
272 	default:
273 		goto badperm;
274 	}
275 	if(strcmp(thdr.name, ".") == 0 || strcmp(thdr.name, "..") == 0)
276 		goto badperm;
277 	if(searchdir(f, thdr.name, ndp, 1) < 0)
278 		goto badperm;
279 	bp = f->xf->ptr;
280 	lock(bp);
281 	start = falloc(f->xf);
282 	unlock(bp);
283 	if(start <= 0){
284 		if(ndp)
285 			free(ndp);
286 		putfile(f);
287 		errno = Eio;
288 		return;
289 	}
290 	/*
291 	 * now we're committed
292 	 */
293 	if(pd){
294 		puttime(pd, 0);
295 		pdp->p->flags |= BMOD;
296 	}
297 	f->ptr = ndp;
298 	f->qid.path = start;
299 	ndp->p = getsect(f->xf, ndp->addr);
300 	if(ndp->p == 0)
301 		goto badio;
302 	ndp->d = (Dosdir *)&ndp->p->iobuf[ndp->offset];
303 	nd = ndp->d;
304 	memset(nd, 0, sizeof(Dosdir));
305 	putname(thdr.name, nd);
306 	if((thdr.perm & 0222) == 0)
307 		nd->attr |= DRONLY;
308 	puttime(nd, 0);
309 	nd->start[0] = start;
310 	nd->start[1] = start>>8;
311 	if(thdr.perm & CHDIR){
312 		nd->attr |= DDIR;
313 		f->qid.path |= CHDIR;
314 		xp = getsect(f->xf, bp->dataaddr+(start-2)*bp->clustsize);
315 		if(xp == 0)
316 			goto badio;
317 		xd = (Dosdir *)&xp->iobuf[0];
318 		memmove(xd, nd, sizeof(Dosdir));
319 		memset(xd->name, ' ', sizeof xd->name+sizeof xd->ext);
320 		xd->name[0] = '.';
321 		xd = (Dosdir *)&xp->iobuf[sizeof(Dosdir)];
322 		if(pd)
323 			memmove(xd, pd, sizeof(Dosdir));
324 		else{
325 			memset(xd, 0, sizeof(Dosdir));
326 			puttime(xd, 0);
327 			xd->attr = DDIR;
328 		}
329 		memset(xd->name, ' ', sizeof xd->name+sizeof xd->ext);
330 		xd->name[0] = '.';
331 		xd->name[1] = '.';
332 		xp->flags |= BMOD;
333 		putsect(xp);
334 	}
335 	ndp->p->flags |= BMOD;
336 	putfile(f);
337 	putsect(pdp->p);
338 	free(pdp);
339 	f->flags |= omode;
340 	chat("f->qid=0x%8.8lux...", f->qid.path);
341 	rhdr.qid = f->qid;
342 	return;
343 badio:
344 	if(ndp->p)
345 		putfile(f);
346 	putsect(pdp->p);
347 	free(pdp);
348 	errno = Eio;
349 }
350 void
351 rread(void)
352 {
353 	Xfile *f; int r;
354 
355 	chat("read(fid=%d,offset=%d,count=%d)...",
356 		thdr.fid, thdr.offset, thdr.count);
357 	if (!(f=xfile(thdr.fid, Asis)) || !(f->flags&Oread))
358 		goto error;
359 	if(f->qid.path & CHDIR){
360 		thdr.count = (thdr.count/DIRLEN)*DIRLEN;
361 		if(thdr.count<DIRLEN || thdr.offset%DIRLEN){
362 			chat("count=%d,offset=%d,DIRLEN=%d...",
363 				thdr.count, thdr.offset, DIRLEN);
364 			goto error;
365 		}
366 		if(getfile(f) < 0)
367 			goto error;
368 		r = readdir(f, fdata, thdr.offset, thdr.count);
369 	}else{
370 		if(getfile(f) < 0)
371 			goto error;
372 		r = readfile(f, fdata, thdr.offset, thdr.count);
373 	}
374 	putfile(f);
375 	if(r < 0){
376 error:
377 		errno = Eio;
378 	}else{
379 		rhdr.count = r;
380 		rhdr.data = fdata;
381 		chat("rcnt=%d...", r);
382 	}
383 }
384 void
385 rwrite(void)
386 {
387 	Xfile *f; int r;
388 
389 	chat("write(fid=%d,offset=%d,count=%d)...",
390 		thdr.fid, thdr.offset, thdr.count);
391 	if (!(f=xfile(thdr.fid, Asis)) || !(f->flags&Owrite))
392 		goto error;
393 	if(getfile(f) < 0)
394 		goto error;
395 	r = writefile(f, thdr.data, thdr.offset, thdr.count);
396 	putfile(f);
397 	if(r < 0){
398 error:
399 		errno = Eio;
400 	}else{
401 		rhdr.count = r;
402 		chat("rcnt=%d...", r);
403 	}
404 }
405 void
406 rclunk(void)
407 {
408 	chat("clunk(fid=%d)...", thdr.fid);
409 	xfile(thdr.fid, Clunk);
410 	sync();
411 }
412 void
413 rremove(void)
414 {
415 	Xfile *f=xfile(thdr.fid, Asis);
416 	Dosptr *dp;
417 	Iosect *parp; Dosdir *pard;
418 
419 	chat("remove(fid=%d,name=\"%s\")...", thdr.fid, thdr.name);
420 	if(!f){
421 		errno = Eio;
422 		goto out;
423 	}
424 	dp = f->ptr;
425 	if(!dp->addr){
426 		chat("root...");
427 		errno = Eperm;
428 		goto out;
429 	}
430 	/*
431 	 * check on parent directory of file to be deleted
432 	 */
433 	parp = getsect(f->xf, dp->paddr);
434 	if(parp == 0){
435 		errno = Eio;
436 		goto out;
437 	}
438 	pard = (Dosdir *)&parp->iobuf[dp->poffset];
439 	if(dp->paddr && (pard->attr & DRONLY)){
440 		chat("parent read-only...");
441 		putsect(parp);
442 		errno = Eperm;
443 		goto out;
444 	}
445 	if(getfile(f) < 0){
446 		chat("getfile failed...");
447 		putsect(parp);
448 		errno = Eio;
449 		goto out;
450 	}
451 	if((dp->d->attr & DDIR) && emptydir(f) < 0){
452 		chat("non-empty dir...");
453 		putfile(f);
454 		putsect(parp);
455 		errno = Eperm;
456 		goto out;
457 	}
458 	if(dp->paddr == 0 && (dp->d->attr&DRONLY)){
459 		chat("read-only file in root directory...");
460 		putfile(f);
461 		putsect(parp);
462 		errno = Eperm;
463 		goto out;
464 	}
465 	if(dp->paddr){
466 		puttime(pard, 0);
467 		parp->flags |= BMOD;
468 	}
469 	putsect(parp);
470 	if(truncfile(f, 1) < 0)
471 		errno = Eio;
472 	dp->d->name[0] = 0xe5;
473 	dp->p->flags |= BMOD;
474 	putfile(f);
475 out:
476 	xfile(thdr.fid, Clunk);
477 	sync();
478 }
479 void
480 rstat(void)
481 {
482 	Dir dir;
483 	Xfile *f=xfile(thdr.fid, Asis);
484 	Dosptr *dp = f->ptr;
485 
486 	chat("stat(fid=%d)...", thdr.fid);
487 	if(!f || getfile(f)< 0)
488 		errno = Eio;
489 	else{
490 		getdir(&dir, dp->addr ? dp->d : 0);
491 		convD2M(&dir, rhdr.stat);
492 		putfile(f);
493 	}
494 }
495 
496 static char isfrog[256]={
497 	/*NUL*/	1, 1, 1, 1, 1, 1, 1, 1,
498 	/*BKS*/	1, 1, 1, 1, 1, 1, 1, 1,
499 	/*DLE*/	1, 1, 1, 1, 1, 1, 1, 1,
500 	/*CAN*/	1, 1, 1, 1, 1, 1, 1, 1,
501 	[' ']	1,
502 	['/']	1,
503 	[0x7f]	1,
504 };
505 
506 static int
507 nameok(char *elem)
508 {
509 	char *eelem;
510 
511 	eelem = elem+NAMELEN;
512 	while(*elem){
513 		if(isfrog[*(uchar*)elem])
514 			return -1;
515 		elem++;
516 		if(elem >= eelem)
517 			return -1;
518 	}
519 	return 0;
520 }
521 
522 void
523 rwstat(void)
524 {
525 	errno = Eperm;
526 }
527