xref: /plan9-contrib/sys/src/cmd/9660srv/9660srv.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1 #include <u.h>
2 #include <libc.h>
3 #include <auth.h>
4 #include <fcall.h>
5 #include "dat.h"
6 #include "fns.h"
7 #include "iso9660.h"
8 
9 static void	ireset(void);
10 static int	iattach(Xfile*);
11 static void	iclone(Xfile*, Xfile*);
12 static void	iwalkup(Xfile*);
13 static void	iwalk(Xfile*, char*);
14 static void	iopen(Xfile*, int);
15 static void	icreate(Xfile*, char*, long, int);
16 static long	ireaddir(Xfile*, void*, long, long);
17 static long	iread(Xfile*, void*, long, long);
18 static long	iwrite(Xfile*, void*, long, long);
19 static void	iclunk(Xfile*);
20 static void	iremove(Xfile*);
21 static void	istat(Xfile*, Dir*);
22 static void	iwstat(Xfile*, Dir*);
23 
24 static char*	nstr(void*, int);
25 static char*	rdate(void*, int);
26 static int	getdrec(Xfile*, void*);
27 static int	opendotdot(Xfile*, Xfile*);
28 static int	showdrec(int, int, void*);
29 static long	gtime(void*);
30 static long	l16(void*);
31 static long	l32(void*);
32 static void	newdrec(Xfile*, Drec*);
33 static int	rzdir(int, Dir*, int, Drec*);
34 
35 Xfsub	isosub =
36 {
37 	ireset, iattach, iclone, iwalkup, iwalk, iopen, icreate,
38 	ireaddir, iread, iwrite, iclunk, iremove, istat, iwstat
39 };
40 
41 static void
42 ireset(void)
43 {}
44 
45 static int
46 iattach(Xfile *root)
47 {
48 	Xfs *cd = root->xf;
49 	Iobuf *p; Voldesc *v; Isofile *fp; Drec *dp;
50 	int fmt, blksize;
51 
52 	p = getbuf(cd->d, VOLDESC);
53 	v = (Voldesc*)(p->iobuf);
54 	if(memcmp(v->byte, "\01CD001\01", 7) == 0){		/* iso */
55 		fmt = 'z';
56 		dp = (Drec*)v->z.desc.rootdir;
57 		blksize = l16(v->z.desc.blksize);
58 		chat("iso, blksize=%d...", blksize);
59 	}else if(memcmp(&v->byte[8], "\01CDROM\01", 7) == 0){	/* high sierra */
60 		fmt = 'r';
61 		dp = (Drec*)v->r.desc.rootdir;
62 		blksize = l16(v->r.desc.blksize);
63 		chat("high sierra, blksize=%d...", blksize);
64 	}else{
65 		putbuf(p);
66 		return -1;
67 	}
68 	if(chatty)
69 		showdrec(2, fmt, dp);
70 	if(blksize > Sectorsize){
71 		chat("blksize too big...");
72 		putbuf(p);
73 		return -1;
74 	}
75 	if(waserror()){
76 		putbuf(p);
77 		nexterror();
78 	}
79 	root->len = sizeof(Isofile) - sizeof(Drec) + dp->reclen;
80 	root->ptr = fp = ealloc(root->len);
81 	root->xf->isplan9 = (strncmp((char*)v->z.boot.sysid, "PLAN 9", 6)==0);
82 	fp->fmt = fmt;
83 	fp->blksize = blksize;
84 	fp->offset = 0;
85 	fp->doffset = 0;
86 	memmove(&fp->d, dp, dp->reclen);
87 	root->qid.path = CHDIR|l32(dp->addr);
88 	putbuf(p);
89 	poperror();
90 	return 0;
91 }
92 
93 static void
94 iclone(Xfile *of, Xfile *nf)
95 {
96 	USED(of, nf);
97 }
98 
99 static void
100 iwalkup(Xfile *f)
101 {
102 	long paddr;
103 	uchar dbuf[256];
104 	Drec *d = (Drec *)dbuf;
105 	Xfile pf, ppf;
106 	Isofile piso, ppiso;
107 
108 	memset(&pf, 0, sizeof pf);
109 	memset(&ppf, 0, sizeof ppf);
110 	pf.ptr = &piso;
111 	ppf.ptr = &ppiso;
112 	if(opendotdot(f, &pf) < 0)
113 		error("can't open pf");
114 	paddr = l32(((Isofile *)pf.ptr)->d.addr);
115 	if(l32(((Isofile *)f->ptr)->d.addr) == paddr)
116 		return;
117 	if(opendotdot(&pf, &ppf) < 0)
118 		error("can't open ppf");
119 	while(getdrec(&ppf, d) >= 0){
120 		if(l32(d->addr) == paddr){
121 			newdrec(f, d);
122 			f->qid.path = paddr|CHDIR;
123 			return;
124 		}
125 	}
126 	error("can't find addr of ..");
127 }
128 
129 static void
130 iwalk(Xfile *f, char *name)
131 {
132 	Isofile *ip = f->ptr;
133 	uchar dbuf[256];
134 	char nbuf[NAMELEN];
135 	Drec *d = (Drec*)dbuf;
136 	Dir dir;
137 	char *p;
138 	int len, vers, dvers;
139 
140 	vers = -1;
141 	if(p = strchr(name, ';')) {	/* assign = */
142 		len = p-name;
143 		if(len >= NAMELEN)
144 			len = NAMELEN-1;
145 		memmove(nbuf, name, len);
146 		vers = strtoul(p+1, 0, 10);
147 		name = nbuf;
148 	}
149 	len = strlen(name);
150 	if(len >= NAMELEN)
151 		len = NAMELEN-1;
152 	name[len] = 0;
153 
154 	chat("%d \"%s\"...", len, name);
155 	ip->offset = 0;
156 	while(getdrec(f, d) >= 0) {
157 		dvers = rzdir(f->xf->isplan9, &dir, 'z', d);
158 		if(strcmp(name, dir.name) != 0)
159 			continue;
160 		newdrec(f, d);
161 		f->qid.path = dir.qid.path;
162 		USED(dvers);
163 		return;
164 	}
165 	USED(vers);
166 	error(Enonexist);
167 }
168 
169 static void
170 iopen(Xfile *f, int mode)
171 {
172 	mode &= ~OCEXEC;
173 	if(mode != OREAD && mode != OEXEC)
174 		error(Eperm);
175 	((Isofile*)f->ptr)->offset = 0;
176 	((Isofile*)f->ptr)->doffset = 0;
177 }
178 
179 static void
180 icreate(Xfile *f, char *name, long perm, int mode)
181 {
182 	USED(f, name, perm, mode);
183 	error(Eperm);
184 }
185 
186 static long
187 ireaddir(Xfile *f, char *buf, long offset, long count)
188 {
189 	Isofile *ip = f->ptr;
190 	Dir d;
191 	uchar dbuf[256];
192 	Drec *drec = (Drec *)dbuf;
193 	int rcnt = 0;
194 
195 	if(offset < ip->doffset){
196 		ip->offset = 0;
197 		ip->doffset = 0;
198 	}
199 	while(rcnt < count && getdrec(f, drec) >= 0){
200 		if(drec->namelen == 1){
201 			if(drec->name[0] == 0)
202 				continue;
203 			if(drec->name[0] == 1)
204 				continue;
205 		}
206 		if(ip->doffset < offset){
207 			ip->doffset += DIRLEN;
208 			continue;
209 		}
210 		rzdir(f->xf->isplan9, &d, ip->fmt, drec);
211 		d.qid.vers = f->qid.vers;
212 		rcnt += convD2M(&d, &buf[rcnt]);
213 	}
214 	ip->doffset += rcnt;
215 	return rcnt;
216 }
217 
218 static long
219 iread(Xfile *f, char *buf, long offset, long count)
220 {
221 	Isofile *ip = f->ptr;
222 	long size, addr, o, n;
223 	int rcnt = 0;
224 	Iobuf *p;
225 
226 	size = l32(ip->d.size);
227 	if(offset >= size)
228 		return 0;
229 	if(offset+count > size)
230 		count = size - offset;
231 	addr = (l32(ip->d.addr)+ip->d.attrlen)*ip->blksize + offset;
232 	o = addr % Sectorsize;
233 	addr /= Sectorsize;
234 	/*chat("d.addr=0x%x, addr=0x%x, o=0x%x...", l32(ip->d.addr), addr, o);*/
235 	n = Sectorsize - o;
236 
237 	while(count > 0){
238 		if(n > count)
239 			n = count;
240 		p = getbuf(f->xf->d, addr);
241 		memmove(&buf[rcnt], &p->iobuf[o], n);
242 		putbuf(p);
243 		count -= n;
244 		rcnt += n;
245 		++addr;
246 		o = 0;
247 		n = Sectorsize;
248 	}
249 	return rcnt;
250 }
251 
252 static long
253 iwrite(Xfile *f, uchar *buf, long offset, long count)
254 {
255 	USED(f, buf, offset, count);
256 	error(Eperm);
257 	return 0;
258 }
259 
260 static void
261 iclunk(Xfile *f)
262 {
263 	USED(f);
264 }
265 
266 static void
267 iremove(Xfile *f)
268 {
269 	USED(f);
270 	error(Eperm);
271 }
272 
273 static void
274 istat(Xfile *f, Dir *d)
275 {
276 	Isofile *ip = f->ptr;
277 
278 	rzdir(f->xf->isplan9, d, ip->fmt, &ip->d);
279 	d->qid.vers = f->qid.vers;
280 	if(d->qid.path==f->xf->rootqid.path)
281 		d->qid.path = CHDIR;
282 }
283 
284 static void
285 iwstat(Xfile *f, Dir *d)
286 {
287 	USED(f, d);
288 	error(Eperm);
289 }
290 
291 static int
292 showdrec(int fd, int fmt, void *x)
293 {
294 	Drec *d = (Drec *)x;
295 	int namelen, syslen;
296 
297 	if(d->reclen == 0)
298 		return 0;
299 	fprint(fd, "%d %d %d %d ",
300 		d->reclen, d->attrlen, l32(d->addr), l32(d->size));
301 	fprint(fd, "%s 0x%2.2x %d %d %d ",
302 		rdate(d->date, fmt), (fmt=='z' ? d->flags : d->r_flags),
303 		d->unitsize, d->gapsize, l16(d->vseqno));
304 	fprint(fd, "%d %s", d->namelen, nstr(d->name, d->namelen));
305 	namelen = d->namelen + (1-(d->namelen&1));
306 	syslen = d->reclen - 33 - namelen;
307 	if(syslen != 0)
308 		fprint(fd, " %s", nstr(&d->name[namelen], syslen));
309 	fprint(fd, "\n");
310 	return d->reclen + (d->reclen&1);
311 }
312 
313 static void
314 newdrec(Xfile *f, Drec *dp)
315 {
316 	Isofile *x = f->ptr;
317 	Isofile *n;
318 	int len;
319 
320 	len = sizeof(Isofile) - sizeof(Drec) + dp->reclen;
321 	n = ealloc(len);
322 	n->fmt = x->fmt;
323 	n->blksize = x->blksize;
324 	n->offset = 0;
325 	n->doffset = 0;
326 	memmove(&n->d, dp, dp->reclen);
327 	free(x);
328 	f->ptr = n;
329 	f->len = len;
330 }
331 
332 static int
333 getdrec(Xfile *f, void *buf)
334 {
335 	Isofile *ip = f->ptr;
336 	int len = 0, boff = 0;
337 	long size, addr;
338 	Iobuf *p = 0;
339 
340 	if(!ip)
341 		return -1;
342 	size = l32(ip->d.size);
343 	while(ip->offset<size){
344 		addr = (l32(ip->d.addr)+ip->d.attrlen)*ip->blksize + ip->offset;
345 		boff = addr % Sectorsize;
346 		if(boff > Sectorsize-34){
347 			ip->offset += Sectorsize-boff;
348 			continue;
349 		}
350 		p = getbuf(f->xf->d, addr/Sectorsize);
351 		len = p->iobuf[boff];
352 		if(len >= 34)
353 			break;
354 		putbuf(p);
355 		p = 0;
356 		ip->offset += Sectorsize-boff;
357 	}
358 	if(p) {
359 		memmove(buf, &p->iobuf[boff], len);
360 		putbuf(p);
361 		ip->offset += len + (len&1);
362 	}
363 	if(p)
364 		return 0;
365 	return -1;
366 }
367 
368 static int
369 opendotdot(Xfile *f, Xfile *pf)
370 {
371 	uchar dbuf[256];
372 	Drec *d = (Drec *)dbuf;
373 	Isofile *ip = f->ptr, *pip = pf->ptr;
374 
375 	ip->offset = 0;
376 	if(getdrec(f, d) < 0){
377 		chat("opendotdot: getdrec(.) failed...");
378 		return -1;
379 	}
380 	if(d->namelen != 1 || d->name[0] != 0){
381 		chat("opendotdot: no . entry...");
382 		return -1;
383 	}
384 	if(l32(d->addr) != l32(ip->d.addr)){
385 		chat("opendotdot: bad . address...");
386 		return -1;
387 	}
388 	if(getdrec(f, d) < 0){
389 		chat("opendotdot: getdrec(..) failed...");
390 		return -1;
391 	}
392 	if(d->namelen != 1 || d->name[0] != 1){
393 		chat("opendotdot: no .. entry...");
394 		return -1;
395 	}
396 
397 	pf->xf = f->xf;
398 	pip->fmt = ip->fmt;
399 	pip->blksize = ip->blksize;
400 	pip->offset = 0;
401 	pip->doffset = 0;
402 	pip->d = *d;
403 	return 0;
404 }
405 
406 static int
407 rzdir(int isplan9, Dir *d, int fmt, Drec *dp)
408 {
409 	int n, flags, i, nl, vers;
410 	uchar *s;
411 	char *p;
412 
413 	flags = 0;
414 	vers = -1;
415 	d->qid.path = l32(dp->addr);
416 	d->qid.vers = 0;
417 	n = dp->namelen;
418 	if(n >= NAMELEN)
419 		n = NAMELEN-1;
420 	memset(d->name, 0, NAMELEN);
421 	if(n == 1) {
422 		switch(dp->name[0]){
423 		case 1:
424 			d->name[1] = '.';
425 			/* fall through */
426 		case 0:
427 			d->name[0] = '.';
428 			break;
429 		default:
430 			d->name[0] = tolower(dp->name[0]);
431 		}
432 	} else {
433 		for(i=0; i<n; i++)
434 			d->name[i] = tolower(dp->name[i]);
435 	}
436 
437 	if(isplan9 && dp->reclen>34+dp->namelen) {
438 		/*
439 		 * get gid, uid, mode and possibly name
440 		 * from plan9 directory extension
441 		 */
442 		s = (uchar*)dp->name + dp->namelen;
443 		if(((ulong)s) & 1)
444 			s++;
445 		nl = *s;
446 		if(nl >= NAMELEN)
447 			nl = NAMELEN-1;
448 		if(nl) {
449 			memset(d->name, 0, NAMELEN);
450 			memmove(d->name, s+1, nl);
451 		}
452 		s += 1 + *s;
453 		nl = *s;
454 		if(nl >= NAMELEN)
455 			nl = NAMELEN-1;
456 		memset(d->uid, 0, NAMELEN);
457 		memmove(d->uid, s+1, nl);
458 		s += 1 + *s;
459 		nl = *s;
460 		if(nl >= NAMELEN)
461 			nl = NAMELEN-1;
462 		memset(d->gid, 0, NAMELEN);
463 		memmove(d->gid, s+1, nl);
464 		s += 1 + *s;
465 		if(((ulong)s) & 1)
466 			s++;
467 		d->mode = l32(s);
468 		if(d->mode & CHDIR)
469 			d->qid.path |= CHDIR;
470 	} else {
471 		d->mode = 0444;
472 		switch(fmt) {
473 		case 'z':
474 			strcpy(d->gid, "iso");
475 			flags = dp->flags;
476 			break;
477 		case 'r':
478 			strcpy(d->gid, "sierra");
479 			flags = dp->r_flags;
480 			break;
481 		}
482 		if(flags & 0x02){
483 			d->qid.path |= CHDIR;
484 			d->mode |= CHDIR|0111;
485 		}
486 		strcpy(d->uid, "cdrom");
487 		p = strchr(d->name, ';');
488 		if(p != 0) {
489 			vers = strtoul(p+1, 0, 10);
490 			memset(p, 0, NAMELEN-(p-d->name));
491 		}
492 	}
493 	d->length = 0;
494 	if((d->mode & CHDIR) == 0)
495 		d->length = l32(dp->size);
496 	d->type = 0;
497 	d->dev = 0;
498 	d->atime = gtime(dp->date);
499 	d->mtime = d->atime;
500 	return vers;
501 }
502 
503 static char *
504 nstr(uchar *p, int n)
505 {
506 	static char buf[132];
507 	char *q = buf;
508 
509 	while(--n >= 0){
510 		if(*p == '\\')
511 			*q++ = '\\';
512 		if(' ' <= *p && *p <= '~')
513 			*q++ = *p++;
514 		else
515 			q += sprint(q, "\\%2.2ux", *p++);
516 	}
517 	*q = 0;
518 	return buf;
519 }
520 
521 static char *
522 rdate(uchar *p, int fmt)
523 {
524 	static char buf[64];
525 	int htz, s, n;
526 
527 	n = sprint(buf, "%2.2d.%2.2d.%2.2d %2.2d:%2.2d:%2.2d",
528 		p[0], p[1], p[2], p[3], p[4], p[5]);
529 	if(fmt == 'z'){
530 		htz = p[6];
531 		if(htz >= 128){
532 			htz = 256-htz;
533 			s = '-';
534 		}else
535 			s = '+';
536 		sprint(&buf[n], " (%c%.1f)", s, (float)htz/2);
537 	}
538 	return buf;
539 }
540 
541 static char
542 dmsize[12] =
543 {
544 	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
545 };
546 
547 static int
548 dysize(int y)
549 {
550 
551 	if((y%4) == 0)
552 		return 366;
553 	return 365;
554 }
555 
556 static long
557 gtime(uchar *p)	/* yMdhmsz */
558 {
559 	long t;
560 	int i, y, M, d, h, m, s, tz;
561 	y=p[0]; M=p[1]; d=p[2];
562 	h=p[3]; m=p[4]; s=p[5]; tz=p[6];
563 	USED(tz);
564 	if (y < 70)
565 		return 0;
566 	if (M < 1 || M > 12)
567 		return 0;
568 	if (d < 1 || d > dmsize[M-1])
569 		return 0;
570 	if (h > 23)
571 		return 0;
572 	if (m > 59)
573 		return 0;
574 	if (s > 59)
575 		return 0;
576 	y += 1900;
577 	t = 0;
578 	for(i=1970; i<y; i++)
579 		t += dysize(i);
580 	if (dysize(y)==366 && M >= 3)
581 		t++;
582 	while(--M)
583 		t += dmsize[M-1];
584 	t += d-1;
585 	t = 24*t + h;
586 	t = 60*t + m;
587 	t = 60*t + s;
588 	return t;
589 }
590 
591 #define	p	((uchar*)arg)
592 
593 static long
594 l16(void *arg)
595 {
596 	long v;
597 
598 	v = ((long)p[1]<<8)|p[0];
599 	if (v >= 0x8000L)
600 		v -= 0x10000L;
601 	return v;
602 }
603 
604 static long
605 l32(void *arg)
606 {
607 	return ((((((long)p[3]<<8)|p[2])<<8)|p[1])<<8)|p[0];
608 }
609 
610 #undef	p
611