Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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*, uchar*, long, long);
17
static long	iread(Xfile*, char*, vlong, long);
18
static long	iwrite(Xfile*, char*, vlong, 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(uchar*, int);
25
static char*	rdate(uchar*, int);
26
static int	getcontin(Xdata*, uchar*, uchar**);
27
static int	getdrec(Xfile*, void*);
28
static void	ungetdrec(Xfile*);
29
static int	opendotdot(Xfile*, Xfile*);
30
static int	showdrec(int, int, void*);
31
static long	gtime(uchar*);
32
static long	l16(void*);
33
static long	l32(void*);
34
static vlong	l64(void *);
35
static void	newdrec(Xfile*, Drec*);
36
static int	rzdir(Xfs*, Dir*, int, Drec*);
37
 
38
Xfsub	isosub =
39
{
40
	ireset, iattach, iclone, iwalkup, iwalk, iopen, icreate,
41
	ireaddir, iread, iwrite, iclunk, iremove, istat, iwstat
42
};
43
 
44
static vlong
45
fakemax(vlong len)
46
{
47
	if(len == (1UL << 31) - 1)	/* max. 9660 size? */
48
		len = (1ULL << 63) - 1;	/* pretend it's vast */
49
	return len;
50
}
51
 
52
static void
53
ireset(void)
54
{}
55
 
56
static int
57
iattach(Xfile *root)
58
{
59
	Xfs *cd = root->xf;
60
	Iobuf *p; Voldesc *v; Isofile *fp; Drec *dp;
61
	int fmt, blksize, i, n, l, haveplan9;
62
	Iobuf *dirp;
63
	uchar dbuf[256];
64
	Drec *rd = (Drec *)dbuf;
65
	uchar *q, *s;
66
 
67
	dirp = nil;
68
	blksize = 0;
69
	fmt = 0;
70
	dp = nil;
71
	haveplan9 = 0;
72
	for(i=VOLDESC;i<VOLDESC+100; i++){	/* +100 for sanity */
73
		p = getbuf(cd->d, i);
74
		v = (Voldesc*)(p->iobuf);
75
		if(memcmp(v->byte, "\01CD001\01", 7) == 0){		/* iso */
76
			if(dirp)
77
				putbuf(dirp);
78
			dirp = p;
79
			fmt = 'z';
80
			dp = (Drec*)v->z.desc.rootdir;
81
			blksize = l16(v->z.desc.blksize);
82
			chat("iso, blksize=%d...", blksize);
83
 
84
			v = (Voldesc*)(dirp->iobuf);
85
			haveplan9 = (strncmp((char*)v->z.boot.sysid, "PLAN 9", 6)==0);
86
			if(haveplan9){
87
				if(noplan9) {
88
					chat("ignoring plan9");
89
					haveplan9 = 0;
90
				} else {
91
					fmt = '9';
92
					chat("plan9 iso...");
93
				}
94
			}
95
			continue;
96
		}
97
 
98
		if(memcmp(&v->byte[8], "\01CDROM\01", 7) == 0){	/* high sierra */
99
			if(dirp)
100
				putbuf(dirp);
101
			dirp = p;
102
			fmt = 'r';
103
			dp = (Drec*)v->r.desc.rootdir;
104
			blksize = l16(v->r.desc.blksize);
105
			chat("high sierra, blksize=%d...", blksize);
106
			continue;
107
		}
108
 
109
		if(haveplan9==0 && !nojoliet
110
		&& memcmp(v->byte, "\02CD001\01", 7) == 0){
111
chat("%d %d\n", haveplan9, nojoliet);
112
			/*
113
			 * The right thing to do is walk the escape sequences looking
114
			 * for one of 25 2F 4[035], but Microsoft seems to not honor
115
			 * the format, which makes it hard to walk over.
116
			 */
117
			q = v->z.desc.escapes;
118
			if(q[0] == 0x25 && q[1] == 0x2F && (q[2] == 0x40 || q[2] == 0x43 || q[2] == 0x45)){	/* Joliet, it appears */
119
				if(dirp)
120
					putbuf(dirp);
121
				dirp = p;
122
				fmt = 'J';
123
				dp = (Drec*)v->z.desc.rootdir;
124
				if(blksize != l16(v->z.desc.blksize))
125
					fprint(2, "warning: suspicious Joliet blocksize\n");
126
				chat("joliet...");
127
				continue;
128
			}
129
		}
130
		putbuf(p);
131
		if(v->byte[0] == 0xFF)
132
			break;
133
	}
134
 
135
	if(fmt == 0){
136
		if(dirp)
137
			putbuf(dirp);
138
		return -1;
139
	}
140
	assert(dirp != nil);
141
 
142
	if(chatty)
143
		showdrec(2, fmt, dp);
144
	if(blksize > Sectorsize){
145
		chat("blksize too big...");
146
		putbuf(dirp);
147
		return -1;
148
	}
149
	if(waserror()){
150
		putbuf(dirp);
151
		nexterror();
152
	}
153
	root->len = sizeof(Isofile) - sizeof(Drec) + dp->reclen;
154
	root->ptr = fp = ealloc(root->len);
155
 
156
	if(haveplan9)
157
		root->xf->isplan9 = 1;
158
 
159
	fp->fmt = fmt;
160
	fp->blksize = blksize;
161
	fp->offset = 0;
162
	fp->doffset = 0;
163
	memmove(&fp->d, dp, dp->reclen);
164
	root->qid.path = l32(dp->addr);
165
	root->qid.type = QTDIR;
166
	putbuf(dirp);
167
	poperror();
168
	if(getdrec(root, rd) >= 0){
169
		n = rd->reclen-(34+rd->namelen);
170
		s = (uchar*)rd->name + rd->namelen;
171
		if((uintptr)s & 1){
172
			s++;
173
			n--;
174
		}
175
		if(n >= 7 && s[0] == 'S' && s[1] == 'P' && s[2] == 7 &&
176
		   s[3] == 1 && s[4] == 0xBE && s[5] == 0xEF){
177
			root->xf->issusp = 1;
178
			root->xf->suspoff = s[6];
179
			n -= root->xf->suspoff;
180
			s += root->xf->suspoff;
181
			for(; n >= 4; s += l, n -= l){
182
				l = s[2];
183
				if(s[0] == 'E' && s[1] == 'R'){
184
					if(!norock && s[4] == 10 && memcmp(s+8, "RRIP_1991A", 10) == 0)
185
						root->xf->isrock = 1;
186
					break;
187
				} else if(s[0] == 'C' && s[1] == 'E' && s[2] >= 28){
188
					n = getcontin(root->xf->d, s, &s);
189
					continue;
190
				} else if(s[0] == 'R' && s[1] == 'R'){
191
					if(!norock)
192
						root->xf->isrock = 1;
193
					break;
194
				} else if(s[0] == 'S' && s[1] == 'T')
195
					break;
196
			}
197
		}
198
	}
199
	if(root->xf->isrock)
200
		chat("Rock Ridge...");
201
	fp->offset = 0;
202
	fp->doffset = 0;
203
	return 0;
204
}
205
 
206
static void
207
iclone(Xfile *of, Xfile *nf)
208
{
209
	USED(of, nf);
210
}
211
 
212
static void
213
iwalkup(Xfile *f)
214
{
215
	vlong paddr;
216
	uchar dbuf[256];
217
	Drec *d = (Drec *)dbuf;
218
	Xfile pf, ppf;
219
	Isofile piso, ppiso;
220
 
221
	memset(&pf, 0, sizeof pf);
222
	memset(&ppf, 0, sizeof ppf);
223
	pf.ptr = &piso;
224
	ppf.ptr = &ppiso;
225
	if(opendotdot(f, &pf) < 0)
226
		error("can't open pf");
227
	paddr = l32(pf.ptr->d.addr);
228
	if(l32(f->ptr->d.addr) == paddr)
229
		return;
230
	if(opendotdot(&pf, &ppf) < 0)
231
		error("can't open ppf");
232
	while(getdrec(&ppf, d) >= 0){
233
		if(l32(d->addr) == paddr){
234
			newdrec(f, d);
235
			f->qid.path = paddr;
236
			f->qid.type = QTDIR;
237
			return;
238
		}
239
	}
240
	error("can't find addr of ..");
241
}
242
 
243
static int
244
casestrcmp(int isplan9, char *a, char *b)
245
{
246
	if(isplan9)
247
		return strcmp(a, b);
248
	return cistrcmp(a, b);
249
}
250
 
251
static void
252
iwalk(Xfile *f, char *name)
253
{
254
	Isofile *ip = f->ptr;
255
	uchar dbuf[256];
256
	char nbuf[4*Maxname];
257
	Drec *d = (Drec*)dbuf;
258
	Dir dir;
259
	char *p;
260
	int len, vers, dvers;
261
 
262
	vers = -1;
263
	if(p = strchr(name, ';')) {	/* assign = */
264
		len = p-name;
265
		if(len >= Maxname)
266
			len = Maxname-1;
267
		memmove(nbuf, name, len);
268
		vers = strtoul(p+1, 0, 10);
269
		name = nbuf;
270
	}
271
/*
272
	len = strlen(name);
273
	if(len >= Maxname){
274
		len = Maxname-1;
275
		if(name != nbuf){
276
			memmove(nbuf, name, len);
277
			name = nbuf;
278
		}
279
		name[len] = 0;
280
	}
281
*/
282
 
283
	chat("%d \"%s\"...", strlen(name), name);
284
	ip->offset = 0;
285
	setnames(&dir, nbuf);
286
	while(getdrec(f, d) >= 0) {
287
		dvers = rzdir(f->xf, &dir, ip->fmt, d);
288
		if(casestrcmp(f->xf->isplan9||f->xf->isrock, name, dir.name) != 0)
289
			continue;
290
		newdrec(f, d);
291
		f->qid.path = dir.qid.path;
292
		f->qid.type = dir.qid.type;
293
		USED(dvers);
294
		return;
295
	}
296
	USED(vers);
297
	error(Enonexist);
298
}
299
 
300
static void
301
iopen(Xfile *f, int mode)
302
{
303
	mode &= ~OCEXEC;
304
	if(mode != OREAD && mode != OEXEC)
305
		error(Eperm);
306
	f->ptr->offset = 0;
307
	f->ptr->doffset = 0;
308
}
309
 
310
static void
311
icreate(Xfile *f, char *name, long perm, int mode)
312
{
313
	USED(f, name, perm, mode);
314
	error(Eperm);
315
}
316
 
317
static long
318
ireaddir(Xfile *f, uchar *buf, long offset, long count)
319
{
320
	Isofile *ip = f->ptr;
321
	Dir d;
322
	char names[4*Maxname];
323
	uchar dbuf[256];
324
	Drec *drec = (Drec *)dbuf;
325
	int n, rcnt;
326
 
327
	if(offset==0){
328
		ip->offset = 0;
329
		ip->doffset = 0;
330
	}else if(offset != ip->doffset)
331
		error("seek in directory not allowed");
332
 
333
	rcnt = 0;
334
	setnames(&d, names);
335
	while(rcnt < count && getdrec(f, drec) >= 0){
336
		if(drec->namelen == 1){
337
			if(drec->name[0] == 0)
338
				continue;
339
			if(drec->name[0] == 1)
340
				continue;
341
		}
342
		rzdir(f->xf, &d, ip->fmt, drec);
343
		d.qid.vers = f->qid.vers;
344
		if((n = convD2M(&d, buf+rcnt, count-rcnt)) <= BIT16SZ){
345
			ungetdrec(f);
346
			break;
347
		}
348
		rcnt += n;
349
	}
350
	ip->doffset += rcnt;
351
	return rcnt;
352
}
353
 
354
static long
355
iread(Xfile *f, char *buf, vlong offset, long count)
356
{
357
	int n, o, rcnt = 0;
358
	vlong size, addr;
359
	Isofile *ip = f->ptr;
360
	Iobuf *p;
361
 
362
	size = fakemax(l32(ip->d.size));
363
	if(offset >= size)
364
		return 0;
365
	if(offset+count > size)
366
		count = size - offset;
367
	addr = ((vlong)l32(ip->d.addr) + ip->d.attrlen)*ip->blksize + offset;
368
	o = addr % Sectorsize;
369
	addr /= Sectorsize;
370
	/*chat("d.addr=%ld, addr=%lld, o=%d...", l32(ip->d.addr), addr, o);*/
371
	n = Sectorsize - o;
372
 
373
	while(count > 0){
374
		if(n > count)
375
			n = count;
376
		p = getbuf(f->xf->d, addr);
377
		memmove(&buf[rcnt], &p->iobuf[o], n);
378
		putbuf(p);
379
		count -= n;
380
		rcnt += n;
381
		++addr;
382
		o = 0;
383
		n = Sectorsize;
384
	}
385
	return rcnt;
386
}
387
 
388
static long
389
iwrite(Xfile *f, char *buf, vlong offset, long count)
390
{
391
	USED(f, buf, offset, count);
392
	error(Eperm);
393
	return 0;
394
}
395
 
396
static void
397
iclunk(Xfile *f)
398
{
399
	USED(f);
400
}
401
 
402
static void
403
iremove(Xfile *f)
404
{
405
	USED(f);
406
	error(Eperm);
407
}
408
 
409
static void
410
istat(Xfile *f, Dir *d)
411
{
412
	Isofile *ip = f->ptr;
413
 
414
	rzdir(f->xf, d, ip->fmt, &ip->d);
415
	d->qid.vers = f->qid.vers;
416
	if(d->qid.path==f->xf->rootqid.path){
417
		d->qid.path = 0;
418
		d->qid.type = QTDIR;
419
	}
420
}
421
 
422
static void
423
iwstat(Xfile *f, Dir *d)
424
{
425
	USED(f, d);
426
	error(Eperm);
427
}
428
 
429
static int
430
showdrec(int fd, int fmt, void *x)
431
{
432
	Drec *d = (Drec *)x;
433
	int namelen;
434
	int syslen;
435
 
436
	if(d->reclen == 0)
437
		return 0;
438
	fprint(fd, "%d %d %ld %ld ",
439
		d->reclen, d->attrlen, l32(d->addr), l32(d->size));
440
	fprint(fd, "%s 0x%2.2x %d %d %ld ",
441
		rdate(d->date, fmt), (fmt=='z' ? d->flags : d->r_flags),
442
		d->unitsize, d->gapsize, l16(d->vseqno));
443
	fprint(fd, "%d %s", d->namelen, nstr(d->name, d->namelen));
444
	if(fmt != 'J'){
445
		namelen = d->namelen + (1-(d->namelen&1));
446
		syslen = d->reclen - 33 - namelen;
447
		if(syslen != 0)
448
			fprint(fd, " %s", nstr(&d->name[namelen], syslen));
449
	}
450
	fprint(fd, "\n");
451
	return d->reclen + (d->reclen&1);
452
}
453
 
454
static void
455
newdrec(Xfile *f, Drec *dp)
456
{
457
	Isofile *x = f->ptr;
458
	Isofile *n;
459
	int len;
460
 
461
	len = sizeof(Isofile) - sizeof(Drec) + dp->reclen;
462
	n = ealloc(len);
463
	n->fmt = x->fmt;
464
	n->blksize = x->blksize;
465
	n->offset = 0;
466
	n->doffset = 0;
467
	memmove(&n->d, dp, dp->reclen);
468
	free(x);
469
	f->ptr = n;
470
	f->len = len;
471
}
472
 
473
static void
474
ungetdrec(Xfile *f)
475
{
476
	Isofile *ip = f->ptr;
477
 
478
	if(ip->offset >= ip->odelta){
479
		ip->offset -= ip->odelta;
480
		ip->odelta = 0;
481
	}
482
}
483
 
484
static int
485
getdrec(Xfile *f, void *buf)
486
{
487
	Isofile *ip = f->ptr;
488
	int len = 0, boff = 0;
489
	vlong addr;
490
	uvlong size;
491
	Iobuf *p = 0;
492
 
493
	if(!ip)
494
		return -1;
495
	size = fakemax(l32(ip->d.size));
496
	while(ip->offset < size){
497
		addr = ((vlong)l32(ip->d.addr)+ip->d.attrlen)*ip->blksize + ip->offset;
498
		boff = addr % Sectorsize;
499
		if(boff > Sectorsize-34){
500
			ip->offset += Sectorsize-boff;
501
			continue;
502
		}
503
		p = getbuf(f->xf->d, addr/Sectorsize);
504
		len = p->iobuf[boff];
505
		if(len >= 34)
506
			break;
507
		putbuf(p);
508
		p = 0;
509
		ip->offset += Sectorsize-boff;
510
	}
511
	if(p) {
512
		memmove(buf, &p->iobuf[boff], len);
513
		putbuf(p);
514
		ip->odelta = len + (len&1);
515
		ip->offset += ip->odelta;
516
		return 0;
517
	}
518
	return -1;
519
}
520
 
521
static int
522
opendotdot(Xfile *f, Xfile *pf)
523
{
524
	uchar dbuf[256];
525
	Drec *d = (Drec *)dbuf;
526
	Isofile *ip = f->ptr, *pip = pf->ptr;
527
 
528
	ip->offset = 0;
529
	if(getdrec(f, d) < 0){
530
		chat("opendotdot: getdrec(.) failed...");
531
		return -1;
532
	}
533
	if(d->namelen != 1 || d->name[0] != 0){
534
		chat("opendotdot: no . entry...");
535
		return -1;
536
	}
537
	if(l32(d->addr) != l32(ip->d.addr)){
538
		chat("opendotdot: bad . address...");
539
		return -1;
540
	}
541
	if(getdrec(f, d) < 0){
542
		chat("opendotdot: getdrec(..) failed...");
543
		return -1;
544
	}
545
	if(d->namelen != 1 || d->name[0] != 1){
546
		chat("opendotdot: no .. entry...");
547
		return -1;
548
	}
549
 
550
	pf->xf = f->xf;
551
	pip->fmt = ip->fmt;
552
	pip->blksize = ip->blksize;
553
	pip->offset = 0;
554
	pip->doffset = 0;
555
	pip->d = *d;
556
	return 0;
557
}
558
 
559
enum {
560
	Hname = 1,
561
	Hmode = 2,
562
};
563
 
564
static int
565
rzdir(Xfs *fs, Dir *d, int fmt, Drec *dp)
566
{
567
	int n, flags, i, j, lj, nl, vers, sysl, mode, l, have;
568
	uchar *s;
569
	char *p;
570
	char buf[Maxname+UTFmax+1];
571
	uchar *q;
572
	Rune r;
573
	enum { ONAMELEN = 28 };	/* old Plan 9 directory name length */
574
 
575
	have = 0;
576
	flags = 0;
577
	vers = -1;
578
	d->qid.path = l32(dp->addr);
579
	d->qid.type = 0;
580
	d->qid.vers = 0;
581
	n = dp->namelen;
582
	memset(d->name, 0, Maxname);
583
	if(n == 1) {
584
		switch(dp->name[0]){
585
		case 1:
586
			d->name[1] = '.';
587
			/* fall through */
588
		case 0:
589
			d->name[0] = '.';
590
			have = Hname;
591
			break;
592
		default:
593
			d->name[0] = tolower(dp->name[0]);
594
		}
595
	} else {
596
		if(fmt == 'J'){	/* Joliet, 16-bit Unicode */
597
			q = (uchar*)dp->name;
598
			for(i=j=lj=0; i<n && j<Maxname; i+=2){
599
				lj = j;
600
				r = (q[i]<<8)|q[i+1];
601
				j += runetochar(buf+j, &r);
602
			}
603
			if(j >= Maxname)
604
				j = lj;
605
			memmove(d->name, buf, j);
606
		}else{
607
			if(n >= Maxname)
608
				n = Maxname-1;
609
			for(i=0; i<n; i++)
610
				d->name[i] = tolower(dp->name[i]);
611
		}
612
	}
613
 
614
	sysl = dp->reclen-(34+dp->namelen);
615
	s = (uchar*)dp->name + dp->namelen;
616
	if(((uintptr)s) & 1) {
617
		s++;
618
		sysl--;
619
	}
620
	if(fs->isplan9 && sysl > 0) {
621
		/*
622
		 * get gid, uid, mode and possibly name
623
		 * from plan9 directory extension
624
		 */
625
		nl = *s;
626
		if(nl >= ONAMELEN)
627
			nl = ONAMELEN-1;
628
		if(nl) {
629
			memset(d->name, 0, ONAMELEN);
630
			memmove(d->name, s+1, nl);
631
		}
632
		s += 1 + *s;
633
		nl = *s;
634
		if(nl >= ONAMELEN)
635
			nl = ONAMELEN-1;
636
		memset(d->uid, 0, ONAMELEN);
637
		memmove(d->uid, s+1, nl);
638
		s += 1 + *s;
639
		nl = *s;
640
		if(nl >= ONAMELEN)
641
			nl = ONAMELEN-1;
642
		memset(d->gid, 0, ONAMELEN);
643
		memmove(d->gid, s+1, nl);
644
		s += 1 + *s;
645
		if(((uintptr)s) & 1)
646
			s++;
647
		d->mode = l32(s);
648
		if(d->mode & DMDIR)
649
			d->qid.type |= QTDIR;
650
	} else {
651
		d->mode = 0444;
652
		switch(fmt) {
653
		case 'z':
654
			if(fs->isrock)
655
				strcpy(d->gid, "ridge");
656
			else
657
				strcpy(d->gid, "iso9660");
658
			flags = dp->flags;
659
			break;
660
		case 'r':
661
			strcpy(d->gid, "sierra");
662
			flags = dp->r_flags;
663
			break;
664
		case 'J':
665
			strcpy(d->gid, "joliet");
666
			flags = dp->flags;
667
			break;
668
		case '9':
669
			strcpy(d->gid, "plan9");
670
			flags = dp->flags;
671
			break;
672
		}
673
		if(flags & 0x02){
674
			d->qid.type |= QTDIR;
675
			d->mode |= DMDIR|0111;
676
		}
677
		strcpy(d->uid, "cdrom");
678
		if(fmt!='9' && !(d->mode&DMDIR)){
679
			/*
680
			 * ISO 9660 actually requires that you always have a . and a ;,
681
			 * even if there is no version and no extension.  Very few writers
682
			 * do this.  If the version is present, we use it for qid.vers.
683
			 * If there is no extension but there is a dot, we strip it off.
684
			 * (VMS heads couldn't comprehend the dot as a file name character
685
			 * rather than as just a separator between name and extension.)
686
			 *
687
			 * We don't do this for directory names because directories are
688
			 * not allowed to have extensions and versions.
689
			 */
690
			if((p=strchr(d->name, ';')) != nil){
691
				vers = strtoul(p+1, 0, 0);
692
				d->qid.vers = vers;
693
				*p = '\0';
694
			}
695
			if((p=strchr(d->name, '.')) != nil && *(p+1)=='\0')
696
				*p = '\0';
697
		}
698
		if(fs->issusp){
699
			nl = 0;
700
			s += fs->suspoff;
701
			sysl -= fs->suspoff;
702
			for(; sysl >= 4 && have != (Hname|Hmode); sysl -= l, s += l){
703
				if(s[0] == 0 && ((uintptr)s & 1)){
704
					/* MacOS pads individual entries, contrary to spec */
705
					s++;
706
					sysl--;
707
				}
708
				l = s[2];
709
				if(s[0] == 'P' && s[1] == 'X' && s[3] == 1){
710
					/* posix file attributes */
711
					mode = l32(s+4);
712
					d->mode = mode & 0777;
713
					if((mode & 0170000) == 040000){
714
						d->mode |= DMDIR;
715
						d->qid.type |= QTDIR;
716
					}
717
					have |= Hmode;
718
				} else if(s[0] == 'N' && s[1] == 'M' && s[3] == 1){
719
					/* alternative name */
720
					if((s[4] & ~1) == 0){
721
						i = nl+l-5;
722
						if(i >= Maxname)
723
							i = Maxname-1;
724
						if((i -= nl) > 0){
725
							memmove(d->name+nl, s+5, i);
726
							nl += i;
727
						}
728
						if(s[4] == 0)
729
							have |= Hname;
730
					}
731
				} else if(s[0] == 'C' && s[1] == 'E' && s[2] >= 28){
732
					sysl = getcontin(fs->d, s, &s);
733
					continue;
734
				} else if(s[0] == 'S' && s[1] == 'T')
735
					break;
736
			}
737
		}
738
	}
739
	d->length = 0;
740
	if((d->mode & DMDIR) == 0)	
741
		d->length = fakemax(l32(dp->size));
742
	d->type = 0;
743
	d->dev = 0;
744
	d->atime = gtime(dp->date);
745
	d->mtime = d->atime;
746
	return vers;
747
}
748
 
749
static int
750
getcontin(Xdata *dev, uchar *p, uchar **s)
751
{
752
	vlong bn, off, len;
753
	Iobuf *b;
754
 
755
	bn = l32(p+4);
756
	off = l32(p+12);
757
	len = l32(p+20);
758
	chat("getcontin %lld...", bn);
759
	b = getbuf(dev, bn);
760
	if(b == 0){
761
		*s = 0;
762
		return 0;
763
	}
764
	*s = b->iobuf+off;
765
	putbuf(b);
766
	return len;
767
}
768
 
769
static char *
770
nstr(uchar *p, int n)
771
{
772
	static char buf[132];
773
	char *q = buf;
774
 
775
	while(--n >= 0){
776
		if(*p == '\\')
777
			*q++ = '\\';
778
		if(' ' <= *p && *p <= '~')
779
			*q++ = *p++;
780
		else
781
			q += sprint(q, "\\%2.2ux", *p++);
782
	}
783
	*q = 0;
784
	return buf;
785
}
786
 
787
static char *
788
rdate(uchar *p, int fmt)
789
{
790
	static char buf[64];
791
	int htz, s, n;
792
 
793
	n = sprint(buf, "%2.2d.%2.2d.%2.2d %2.2d:%2.2d:%2.2d",
794
		p[0], p[1], p[2], p[3], p[4], p[5]);
795
	if(fmt == 'z'){
796
		htz = p[6];
797
		if(htz >= 128){
798
			htz = 256-htz;
799
			s = '-';
800
		}else
801
			s = '+';
802
		sprint(&buf[n], " (%c%.1f)", s, (float)htz/2);
803
	}
804
	return buf;
805
}
806
 
807
static char
808
dmsize[12] =
809
{
810
	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
811
};
812
 
813
static int
814
dysize(int y)
815
{
816
 
817
	if((y%4) == 0)
818
		return 366;
819
	return 365;
820
}
821
 
822
static long
823
gtime(uchar *p)	/* yMdhmsz */
824
{
825
	long t;
826
	int i, y, M, d, h, m, s, tz;
827
 
828
	y=p[0]; M=p[1]; d=p[2];
829
	h=p[3]; m=p[4]; s=p[5]; tz=p[6];
830
	USED(tz);
831
	y += 1900;
832
	if (y < 1970)
833
		return 0;
834
	if (M < 1 || M > 12)
835
		return 0;
836
	if (d < 1 || d > dmsize[M-1])
837
		if (!(M == 2 && d == 29 && dysize(y) == 366))
838
			return 0;
839
	if (h > 23)
840
		return 0;
841
	if (m > 59)
842
		return 0;
843
	if (s > 59)
844
		return 0;
845
	t = 0;
846
	for(i=1970; i<y; i++)
847
		t += dysize(i);
848
	if (dysize(y)==366 && M >= 3)
849
		t++;
850
	while(--M)
851
		t += dmsize[M-1];
852
	t += d-1;
853
	t = 24*t + h;
854
	t = 60*t + m;
855
	t = 60*t + s;
856
	return t;
857
}
858
 
859
#define	p	((uchar*)arg)
860
 
861
static long
862
l16(void *arg)
863
{
864
	long v;
865
 
866
	v = ((long)p[1]<<8)|p[0];
867
	if (v >= 0x8000L)
868
		v -= 0x10000L;
869
	return v;
870
}
871
 
872
static long
873
l32(void *arg)
874
{
875
	return (((long)p[3]<<8 | p[2])<<8 | p[1])<<8 | p[0];
876
}
877
 
878
#undef	p
879
 
880
static vlong
881
l64(void *arg)
882
{
883
	uchar *p;
884
 
885
	p = arg;
886
	return (vlong)l32(p+4) << 32 | (ulong)l32(p);
887
}