xref: /plan9-contrib/sys/src/cmd/dossrv/dossubs.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <auth.h>
5 #include <fcall.h>
6 #include "iotrack.h"
7 #include "dat.h"
8 #include "fns.h"
9 
10 int
11 dosfs(Xfs *xf)
12 {
13 	Iosect *p = 0;
14 	Dosboot *b = 0;
15 	Dosbpb *bp;
16 	Dospart *dp;
17 	int i, j; long offset;
18 
19 	for(i=2; i>0; i--){
20 		p = getsect(xf, 0);
21 		if(p == 0)
22 			return -1;
23 		b = (Dosboot *)p->iobuf;
24 		if(b->magic[0] == 0xe9)
25 			break;
26 		if(b->magic[0] == 0xeb && b->magic[2] == 0x90)
27 			break;
28 		if(i < 2 || p->iobuf[0x1fe] != 0x55 || p->iobuf[0x1ff] != 0xaa){
29 			i = 0;
30 			break;
31 		}
32 		dp = (Dospart *)&p->iobuf[0x1be];
33 		for(j=4; j>0; j--,dp++){
34 			chat("0x%2.2ux (%d,%d) 0x%2.2ux (%d,%d) %d %d...",
35 				dp->active, dp->hstart, GSHORT(dp->cylstart),
36 				dp->type, dp->hend, GSHORT(dp->cylend),
37 				GLONG(dp->start), GLONG(dp->length));
38 			if(dp->type)
39 				break;
40 		}
41 		if(j <= 0){
42 			chat("no active partition...");
43 			putsect(p);
44 			return -1;
45 		}
46 		offset = GLONG(dp->start)*Sectorsize;
47 		putsect(p);
48 		purgebuf(xf);
49 		xf->offset = offset;
50 	}
51 	if(i <= 0){
52 		chat("bad magic...");
53 		putsect(p);
54 		return -1;
55 	}
56 	if(chatty)
57 		bootdump(2, b);
58 
59 	bp = malloc(sizeof(Dosbpb));
60 	xf->ptr = bp;
61 	xf->fmt = 1;
62 
63 	bp->sectsize = GSHORT(b->sectsize);
64 	bp->clustsize = b->clustsize;
65 	bp->nresrv = GSHORT(b->nresrv);
66 	bp->nfats = b->nfats;
67 	bp->rootsize = GSHORT(b->rootsize);
68 	bp->volsize = GSHORT(b->volsize);
69 	if(bp->volsize == 0)
70 		bp->volsize = GLONG(b->bigvolsize);
71 	bp->mediadesc = b->mediadesc;
72 	bp->fatsize = GSHORT(b->fatsize);
73 
74 	bp->fataddr = bp->nresrv;
75 	bp->rootaddr = bp->fataddr + bp->nfats*bp->fatsize;
76 	i = bp->rootsize*sizeof(Dosdir) + bp->sectsize-1;
77 	i /= bp->sectsize;
78 	bp->dataaddr = bp->rootaddr + i;
79 	bp->fatclusters = 2+(bp->volsize - bp->dataaddr)/bp->clustsize;
80 	if(bp->fatclusters < 4087)
81 		bp->fatbits = 12;
82 	else
83 		bp->fatbits = 16;
84 	bp->freeptr = 2;
85 	chat("fatbits=%d (%d clusters)...", bp->fatbits, bp->fatclusters);
86 	for(i=0; i<b->nfats; i++)
87 		chat("fat %d: %d...", i, bp->fataddr+i*bp->fatsize);
88 	chat("root: %d...", bp->rootaddr);
89 	chat("data: %d...", bp->dataaddr);
90 	putsect(p);
91 	return 0;
92 }
93 
94 int
95 getfile(Xfile *f)
96 {
97 	Dosptr *dp = f->ptr;
98 	Iosect *p;
99 	Dosdir *d;
100 
101 	if(dp->p)
102 		panic("getfile");
103 	p = getsect(f->xf, dp->addr);
104 	if(p == 0)
105 		return -1;
106 	if(dp->addr != 0){
107 		d = (Dosdir *)&p->iobuf[dp->offset];
108 		if((f->qid.path & ~CHDIR) != GSHORT(d->start)){
109 			chat("qid mismatch f=0x%x d=0x%x...",
110 				f->qid.path, GSHORT(d->start));
111 			putsect(p);
112 			errno = Enonexist;
113 			return -1;
114 		}
115 		dp->d = d;
116 	}
117 	dp->p = p;
118 	return 0;
119 }
120 
121 void
122 putfile(Xfile *f)
123 {
124 	Dosptr *dp = f->ptr;
125 
126 	if(!dp->p)
127 		panic("putfile");
128 	putsect(dp->p);
129 	dp->p = 0;
130 	dp->d = 0;
131 }
132 
133 int
134 fileaddr(Xfile *f, int isect, int cflag)
135 {
136 	Dosbpb *bp = f->xf->ptr;
137 	Dosptr *dp = f->ptr;
138 	Dosdir *d = dp->d;
139 	int clust, iclust, nskip, next = 0;
140 
141 	if(dp->addr == 0){
142 		if(isect*bp->sectsize >= bp->rootsize*sizeof(Dosdir))
143 			return -1;
144 		return bp->rootaddr + isect;
145 	}
146 	iclust = isect/bp->clustsize;
147 	if(dp->clust == 0 || iclust < dp->iclust){
148 		clust = GSHORT(d->start);
149 		nskip = iclust;
150 	}else{
151 		clust = dp->clust;
152 		nskip = iclust - dp->iclust;
153 	}
154 	if(chatty > 1 && nskip > 0)
155 		chat("clust 0x%x, skip %d...", clust, nskip);
156 	if(clust <= 0)
157 		return -1;
158 	if(nskip > 0){
159 		lock(bp);
160 		while(--nskip >= 0){
161 			next = getfat(f->xf, clust);
162 			if(chatty > 1)
163 				chat("->0x%x", next);
164 			if(next > 0){
165 				clust = next;
166 				continue;
167 			}else if(!cflag)
168 				break;
169 			next = falloc(f->xf);
170 			if(next < 0)
171 				break;
172 			putfat(f->xf, clust, next);
173 			clust = next;
174 		}
175 		unlock(bp);
176 		if(next <= 0)
177 			return -1;
178 		dp->clust = clust;
179 		dp->iclust = iclust;
180 	}
181 	if(chatty > 1)
182 		chat(" clust(0x%x)=0x%x...", iclust, clust);
183 	return bp->dataaddr + (clust-2)*bp->clustsize + isect%bp->clustsize;
184 }
185 
186 int
187 searchdir(Xfile *f, char *name, Dosptr *dp, int cflag)
188 {
189 	Xfs *xf = f->xf;
190 	Dosbpb *bp = xf->ptr;
191 	char uname[16], buf[16];
192 	int isect, addr, o;
193 	int addr1 = 0, o1 = 0;
194 	Iosect *p;
195 	Dosdir *d, tmpdir;
196 
197 	putname(name, &tmpdir);
198 	getname(uname, &tmpdir);
199 	memset(dp, 0, sizeof(Dosptr));
200 	dp->paddr = ((Dosptr *)f->ptr)->addr;
201 	dp->poffset = ((Dosptr *)f->ptr)->offset;
202 
203 	for(isect=0;; isect++){
204 		addr = fileaddr(f, isect, cflag);
205 		if(addr < 0)
206 			break;
207 		p = getsect(xf, addr);
208 		if(p == 0)
209 			break;
210 		for(o=0; o<bp->sectsize; o+=sizeof(Dosdir)){
211 			d = (Dosdir *)&p->iobuf[o];
212 			if(d->name[0] == 0x00){
213 				chat("end dir(0)...");
214 				putsect(p);
215 				if(!cflag)
216 					return -1;
217 				if(addr1 == 0){
218 					addr1 = addr;
219 					o1 = o;
220 				}
221 				dp->addr = addr1;
222 				dp->offset = o1;
223 				return 0;
224 			}
225 			if(d->name[0] == 0xe5){
226 				if(addr1 == 0){
227 					addr1 = addr;
228 					o1 = o;
229 				}
230 				continue;
231 			}
232 			/*dirdump(d);*/
233 			if(d->attr&DVLABEL)
234 				continue;
235 			getname(buf, d);
236 			if(strcmp(buf, uname) != 0)
237 				continue;
238 			dirdump(d);
239 			if(cflag){
240 				putsect(p);
241 				return -1;
242 			}
243 			dp->addr = addr;
244 			dp->offset = o;
245 			dp->p = p;
246 			dp->d = d;
247 			return 0;
248 		}
249 		putsect(p);
250 	}
251 	chat("end dir(1)...");
252 	return -1;
253 }
254 
255 int
256 emptydir(Xfile *f)
257 {
258 	Xfs *xf = f->xf;
259 	Dosbpb *bp = xf->ptr;
260 	int isect, addr, o;
261 	Iosect *p;
262 	Dosdir *d;
263 
264 	for(isect=0;; isect++){
265 		addr = fileaddr(f, isect, 0);
266 		if(addr < 0)
267 			break;
268 		p = getsect(xf, addr);
269 		if(p == 0)
270 			return -1;
271 		for(o=0; o<bp->sectsize; o+=sizeof(Dosdir)){
272 			d = (Dosdir *)&p->iobuf[o];
273 			if(d->name[0] == 0x00){
274 				putsect(p);
275 				return 0;
276 			}
277 			if(d->name[0] == 0xe5)
278 				continue;
279 			if(d->name[0] == '.')
280 				continue;
281 			if(d->attr&DVLABEL)
282 				continue;
283 			putsect(p);
284 			return -1;
285 		}
286 		putsect(p);
287 	}
288 	return 0;
289 }
290 
291 long
292 readdir(Xfile *f, char *buf, long offset, long count)
293 {
294 	Xfs *xf = f->xf;
295 	Dosbpb *bp = xf->ptr;
296 	Dir dir;
297 	int isect, addr, o;
298 	Iosect *p;
299 	Dosdir *d;
300 	long rcnt = 0;
301 
302 	if(count <= 0)
303 		return 0;
304 	for(isect=0;; isect++){
305 		addr = fileaddr(f, isect, 0);
306 		if(addr < 0)
307 			break;
308 		p = getsect(xf, addr);
309 		if(p == 0)
310 			return -1;
311 		for(o=0; o<bp->sectsize; o+=sizeof(Dosdir)){
312 			d = (Dosdir *)&p->iobuf[o];
313 			if(d->name[0] == 0x00){
314 				putsect(p);
315 				return rcnt;
316 			}
317 			if(d->name[0] == 0xe5)
318 				continue;
319 			/*dirdump(d);*/
320 			if(d->name[0] == '.'){
321 				if(d->name[1] == ' ' || d->name[1] == 0)
322 					continue;
323 				if(d->name[1] == '.' &&
324 				  (d->name[2] == ' ' || d->name[2] == 0))
325 					continue;
326 			}
327 			if(d->attr&DVLABEL)
328 				continue;
329 			if(offset > 0){
330 				offset -= DIRLEN;
331 				continue;
332 			}
333 			getdir(&dir, d);
334 			rcnt += convD2M(&dir, &buf[rcnt]);
335 			if(rcnt >= count){
336 				putsect(p);
337 				return rcnt;
338 			}
339 		}
340 		putsect(p);
341 	}
342 	return rcnt;
343 }
344 
345 int
346 walkup(Xfile *f, Dosptr *ndp)
347 {
348 	Dosbpb *bp = f->xf->ptr;
349 	Dosptr *dp = f->ptr;
350 	Dosdir *xd;
351 	Iosect *p;
352 	int k, o, so, start, pstart, ppstart;
353 
354 	memset(ndp, 0, sizeof(Dosptr));
355 	ndp->addr = dp->paddr;
356 	ndp->offset = dp->poffset;
357 	chat("walkup: paddr=0x%x...", dp->paddr);
358 	if(dp->paddr == 0)
359 		return 0;
360 	p = getsect(f->xf, dp->paddr);
361 	if(p == 0)
362 		goto error;
363 	xd = (Dosdir *)&p->iobuf[dp->poffset];
364 	dirdump(xd);
365 	start = GSHORT(xd->start);
366 	chat("start=0x%x...", start);
367 	if(start == 0)
368 		goto error;
369 	putsect(p);
370 	p = getsect(f->xf, bp->dataaddr + (start-2)*bp->clustsize);
371 	if(p == 0)
372 		goto error;
373 	xd = (Dosdir *)p->iobuf;
374 	dirdump(xd);
375 	if(xd->name[0]!='.' || xd->name[1]!=' ' || start!=GSHORT(xd->start))
376 		goto error;
377 	xd++;
378 	dirdump(xd);
379 	if(xd->name[0] != '.' || xd->name[1] != '.')
380 		goto error;
381 	pstart = GSHORT(xd->start);
382 	putsect(p);
383 	if(pstart == 0)
384 		return 0;
385 	p = getsect(f->xf, bp->dataaddr + (pstart-2)*bp->clustsize);
386 	if(p == 0){
387 		chat("getsect %d failed\n", pstart);
388 		goto error;
389 	}
390 	xd = (Dosdir *)p->iobuf;
391 	dirdump(xd);
392 	if(xd->name[0]!='.' || xd->name[1]!=' ' || pstart!=GSHORT(xd->start))
393 		goto error;
394 	xd++;
395 	dirdump(xd);
396 	if(xd->name[0] != '.' || xd->name[1] != '.')
397 		goto error;
398 	ppstart = GSHORT(xd->start);
399 	putsect(p);
400 	k = ppstart ? (bp->dataaddr + (ppstart-2)*bp->clustsize) : bp->rootaddr;
401 	p = getsect(f->xf, k);
402 	if(p == 0){
403 		chat("getsect %d failed\n", k);
404 		goto error;
405 	}
406 	xd = (Dosdir *)p->iobuf;
407 	dirdump(xd);
408 	if(ppstart)
409 		if(xd->name[0]!='.' || xd->name[1]!=' ' || ppstart!=GSHORT(xd->start))
410 			goto error;
411 	for(so=1;; so++){
412 		for(o=0; o<bp->sectsize; o+=sizeof(Dosdir)){
413 			xd = (Dosdir *)&p->iobuf[o];
414 			if(xd->name[0] == 0x00){
415 				chat("end dir\n");
416 				goto error;
417 			}
418 			if(xd->name[0] == 0xe5)
419 				continue;
420 			if(GSHORT(xd->start) == pstart)
421 				goto out;
422 		}
423 		if(ppstart){
424 			if(so%bp->clustsize == 0){
425 				lock(bp);
426 				ppstart = getfat(f->xf, ppstart);
427 				unlock(bp);
428 				if(ppstart < 0){
429 					chat("getfat %d failed\n", ppstart);
430 					goto error;
431 				}
432 			}
433 			k = bp->dataaddr + (ppstart-2)*bp->clustsize +
434 				so%bp->clustsize;
435 		}else{
436 			if(so*bp->sectsize >= bp->rootsize*sizeof(Dosdir))
437 				goto error;
438 			k = bp->rootaddr + so;
439 		}
440 		putsect(p);
441 		p = getsect(f->xf, k);
442 		if(p == 0){
443 			chat("getsect %d failed\n", k);
444 			goto error;
445 		}
446 	}
447 out:
448 	putsect(p);
449 	ndp->paddr = k;
450 	ndp->poffset = o;
451 	return 0;
452 
453 error:
454 	if(p)
455 		putsect(p);
456 	return -1;
457 }
458 
459 long
460 readfile(Xfile *f, uchar *buf, long offset, long count)
461 {
462 	Xfs *xf = f->xf;
463 	Dosbpb *bp = xf->ptr;
464 	Dosptr *dp = f->ptr;
465 	Dosdir *d = dp->d;
466 	int isect, addr, o, c;
467 	Iosect *p;
468 	long length = GLONG(d->length), rcnt = 0;
469 
470 	if(offset >= length)
471 		return 0;
472 	if(offset+count >= length)
473 		count = length - offset;
474 	isect = offset/bp->sectsize;
475 	o = offset%bp->sectsize;
476 	while(count > 0){
477 		addr = fileaddr(f, isect++, 0);
478 		if(addr < 0)
479 			break;
480 		c = bp->sectsize - o;
481 		if(c > count)
482 			c = count;
483 		p = getsect(xf, addr);
484 		if(p == 0)
485 			return -1;
486 		memmove(&buf[rcnt], &p->iobuf[o], c);
487 		putsect(p);
488 		count -= c;
489 		rcnt += c;
490 		o = 0;
491 	}
492 	return rcnt;
493 }
494 
495 long
496 writefile(Xfile *f, uchar *buf, long offset, long count)
497 {
498 	Xfs *xf = f->xf;
499 	Dosbpb *bp = xf->ptr;
500 	Dosptr *dp = f->ptr;
501 	Dosdir *d = dp->d;
502 	int isect, addr = 0, o, c;
503 	Iosect *p;
504 	long length, rcnt = 0, dlen;
505 
506 	isect = offset/bp->sectsize;
507 	o = offset%bp->sectsize;
508 	while(count > 0){
509 		addr = fileaddr(f, isect++, 1);
510 		if(addr < 0)
511 			break;
512 		c = bp->sectsize - o;
513 		if(c > count)
514 			c = count;
515 		if(c == bp->sectsize){
516 			p = getosect(xf, addr);
517 			if(p == 0)
518 				return -1;
519 			p->flags = 0;
520 		}else{
521 			p = getsect(xf, addr);
522 			if(p == 0)
523 				return -1;
524 		}
525 		memmove(&p->iobuf[o], &buf[rcnt], c);
526 		p->flags |= BMOD;
527 		putsect(p);
528 		count -= c;
529 		rcnt += c;
530 		o = 0;
531 	}
532 	if(rcnt <= 0 && addr < 0)
533 		return -1;
534 	length = 0;
535 	dlen = GLONG(d->length);
536 	if(rcnt > 0)
537 		length = offset+rcnt;
538 	else if(dp->addr && dp->clust){
539 		c = bp->clustsize*bp->sectsize;
540 		if(dp->iclust > (dlen+c-1)/c)
541 			length = c*dp->iclust;
542 	}
543 	if(length > dlen){
544 		d->length[0] = length;
545 		d->length[1] = length>>8;
546 		d->length[2] = length>>16;
547 		d->length[3] = length>>24;
548 	}
549 	puttime(d, 0);
550 	dp->p->flags |= BMOD;
551 	return rcnt;
552 }
553 
554 int
555 truncfile(Xfile *f, int totally)
556 {
557 	Xfs *xf = f->xf;
558 	Dosbpb *bp = xf->ptr;
559 	Dosptr *dp = f->ptr;
560 	Dosdir *d = dp->d;
561 	int clust, next;
562 
563 	lock(bp);
564 	clust = GSHORT(d->start);
565 	if(totally){
566 		d->start[0] = 0;
567 		d->start[1] = 0;
568 	}else{
569 		next = getfat(xf, clust);
570 		putfat(xf, clust, 0xffff);
571 		clust = next;
572 	}
573 	while(clust >= 0){
574 		next = getfat(xf, clust);
575 		putfat(xf, clust, 0);
576 		clust = next;
577 	}
578 	unlock(bp);
579 	d->length[0] = 0;
580 	d->length[1] = 0;
581 	d->length[2] = 0;
582 	d->length[3] = 0;
583 	dp->iclust = 0;
584 	dp->clust = 0;
585 	dp->p->flags |= BMOD;
586 	return 0;
587 }
588 
589 void
590 getdir(Dir *dp, Dosdir *d)
591 {
592 	char *p;
593 
594 	memset(dp, 0, sizeof(Dir));
595 	if(d == 0){
596 		dp->name[0] = '/';
597 		dp->qid.path = CHDIR;
598 		dp->mode = CHDIR|0777;
599 	}else{
600 		getname(dp->name, d);
601 		for(p=dp->name; *p; p++)
602 			*p = tolower(*p);
603 		dp->qid.path = GSHORT(d->start);
604 		if(d->attr & DRONLY)
605 			dp->mode = 0444;
606 		else
607 			dp->mode = 0666;
608 		dp->atime = gtime(d);
609 		dp->mtime = dp->atime;
610 		if(d->attr & DDIR){
611 			dp->qid.path |= CHDIR;
612 			dp->mode |= CHDIR|0111;
613 		}else
614 			dp->length = GLONG(d->length);
615 		if(d->attr & DSYSTEM)
616 			dp->mode |= CHEXCL;
617 	}
618 	strcpy(dp->uid, "bill");
619 	strcpy(dp->gid, "trog");
620 }
621 
622 void
623 getname(char *p, Dosdir *d)
624 {
625 	int c, i;
626 
627 	for(i=0; i<8; i++){
628 		c = d->name[i];
629 		if(c == 0 || c == ' ')
630 			break;
631 		if(i == 0 && c == 0x05)
632 			c = 0xe5;
633 		*p++ = c;
634 	}
635 	for(i=0; i<3; i++){
636 		c = d->ext[i];
637 		if(c == 0 || c == ' ')
638 			break;
639 		if(i == 0)
640 			*p++ = '.';
641 		*p++ = c;
642 	}
643 	*p = 0;
644 }
645 
646 void
647 putname(char *p, Dosdir *d)
648 {
649 	int i;
650 
651 	memset(d->name, ' ', sizeof d->name+sizeof d->ext);
652 	for(i=0; i<sizeof d->name; i++){
653 		if(*p == 0 || *p == '.')
654 			break;
655 		d->name[i] = toupper(*p++);
656 	}
657 	p = strrchr(p, '.');
658 	if(p){
659 		for(i=0; i<sizeof d->ext; i++){
660 			if(*++p == 0)
661 				break;
662 			d->ext[i] = toupper(*p);
663 		}
664 	}
665 }
666 
667 int
668 getfat(Xfs *xf, int n)
669 {
670 	Dosbpb *bp = xf->ptr;
671 	ulong k = 0, sect; Iosect *p;
672 	int o;
673 
674 	if(n < 2 || n >= bp->fatclusters)
675 		return -1;
676 	switch(bp->fatbits){
677 	case 12:
678 		k = (3*n)/2; break;
679 	case 16:
680 		k = 2*n; break;
681 	}
682 	if(k >= bp->fatsize*bp->sectsize)
683 		panic("getfat");
684 	sect = k/bp->sectsize + bp->fataddr;
685 	o = k%bp->sectsize;
686 	p = getsect(xf, sect);
687 	if(p == 0)
688 		return -1;
689 	k = p->iobuf[o++];
690 	if(o >= bp->sectsize){
691 		putsect(p);
692 		p = getsect(xf, sect+1);
693 		if(p == 0)
694 			return -1;
695 		o = 0;
696 	}
697 	k |= p->iobuf[o]<<8;
698 	putsect(p);
699 	if(bp->fatbits == 12){
700 		if(n&1)
701 			k >>= 4;
702 		else
703 			k &= 0xfff;
704 		if(k >= 0xff8)
705 			k |= 0xf000;
706 	}
707 	if(chatty > 1)
708 		chat("fat(0x%x)=0x%x...", n, k);
709 	return k < 0xfff8 ? k : -1;
710 }
711 
712 void
713 putfat(Xfs *xf, int n, int val)
714 {
715 	Dosbpb *bp = xf->ptr;
716 	ulong k = 0, sect; Iosect *p;
717 	int o;
718 
719 	switch(bp->fatbits){
720 	case 12:
721 		k = (3*n)/2; break;
722 	case 16:
723 		k = 2*n; break;
724 	}
725 	if(k >= bp->fatsize*bp->sectsize)
726 		panic("putfat");
727 	sect = k/bp->sectsize + bp->fataddr;
728 	for(; sect<bp->rootaddr; sect+=bp->fatsize){
729 		o = k%bp->sectsize;
730 		p = getsect(xf, sect);
731 		if(p == 0)
732 			continue;
733 		switch(bp->fatbits){
734 		case 12:
735 			if(n&1){
736 				p->iobuf[o] &= 0x0f;
737 				p->iobuf[o++] |= val<<4;
738 				if(o >= bp->sectsize){
739 					p->flags |= BMOD;
740 					putsect(p);
741 					p = getsect(xf, sect+1);
742 					if(p == 0)
743 						continue;
744 					o = 0;
745 				}
746 				p->iobuf[o] = val>>4;
747 			}else{
748 				p->iobuf[o++] = val;
749 				if(o >= bp->sectsize){
750 					p->flags |= BMOD;
751 					putsect(p);
752 					p = getsect(xf, sect+1);
753 					if(p == 0)
754 						continue;
755 					o = 0;
756 				}
757 				p->iobuf[o] &= 0xf0;
758 				p->iobuf[o] |= (val>>8)&0x0f;
759 			}
760 			break;
761 		case 16:
762 			p->iobuf[o++] = val;
763 			p->iobuf[o] = val>>8;
764 			break;
765 		}
766 		p->flags |= BMOD;
767 		putsect(p);
768 	}
769 }
770 
771 int
772 falloc(Xfs *xf)
773 {
774 	Dosbpb *bp = xf->ptr;
775 	int n, i, k;
776 	Iosect *p;
777 
778 	n = bp->freeptr;
779 	for(;;){
780 		if(getfat(xf, n) == 0)
781 			break;
782 		if(++n >= bp->fatclusters)
783 			n = 2;
784 		if(n == bp->freeptr)
785 			return -1;
786 	}
787 	bp->freeptr = n+1;
788 	if(bp->freeptr >= bp->fatclusters)
789 		bp->freeptr = 2;
790 	putfat(xf, n, 0xffff);
791 	k = bp->dataaddr + (n-2)*bp->clustsize;
792 	for(i=0; i<bp->clustsize; i++){
793 		p = getosect(xf, k+i);
794 		if(p == 0)
795 			break;
796 		memset(p->iobuf, 0, bp->sectsize);
797 		p->flags = BMOD;
798 		putsect(p);
799 	}
800 	return n;
801 }
802 
803 void
804 bootdump(int fd, Dosboot *b)
805 {
806 	Biobuf *bp;
807 
808 	bp = malloc(sizeof(Biobuf));
809 	if(bp == 0)
810 		panic("malloc");
811 	Binit(bp, fd, OWRITE);
812 	Bprint(bp, "magic: 0x%2.2x 0x%2.2x 0x%2.2x\n",
813 		b->magic[0], b->magic[1], b->magic[2]);
814 	Bprint(bp, "version: \"%8.8s\"\n", b->version);
815 	Bprint(bp, "sectsize: %d\n", GSHORT(b->sectsize));
816 	Bprint(bp, "allocsize: %d\n", b->clustsize);
817 	Bprint(bp, "nresrv: %d\n", GSHORT(b->nresrv));
818 	Bprint(bp, "nfats: %d\n", b->nfats);
819 	Bprint(bp, "rootsize: %d\n", GSHORT(b->rootsize));
820 	Bprint(bp, "volsize: %d\n", GSHORT(b->volsize));
821 	Bprint(bp, "mediadesc: 0x%2.2x\n", b->mediadesc);
822 	Bprint(bp, "fatsize: %d\n", GSHORT(b->fatsize));
823 	Bprint(bp, "trksize: %d\n", GSHORT(b->trksize));
824 	Bprint(bp, "nheads: %d\n", GSHORT(b->nheads));
825 	Bprint(bp, "nhidden: %d\n", GLONG(b->nhidden));
826 	Bprint(bp, "bigvolsize: %d\n", GLONG(b->bigvolsize));
827 	Bprint(bp, "driveno: %d\n", b->driveno);
828 	Bprint(bp, "reserved0: 0x%2.2x\n", b->reserved0);
829 	Bprint(bp, "bootsig: 0x%2.2x\n", b->bootsig);
830 	Bprint(bp, "volid: 0x%8.8x\n", GLONG(b->volid));
831 	Bprint(bp, "label: \"%11.11s\"\n", b->label);
832 	Bterm(bp);
833 	free(bp);
834 }
835 
836 void
837 puttime(Dosdir *d, long s)
838 {
839 	Tm *t;
840 	ushort x;
841 
842 	if(s == 0)
843 		s = time(0);
844 	t = localtime(s);
845 
846 	x = (t->hour<<11) | (t->min<<5) | (t->sec>>1);
847 	d->time[0] = x;
848 	d->time[1] = x>>8;
849 	x = ((t->year-80)<<9) | ((t->mon+1)<<5) | t->mday;
850 	d->date[0] = x;
851 	d->date[1] = x>>8;
852 }
853 
854 static char	dmsize[12] = {
855 	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
856 };
857 static int
858 dysize(int y)
859 {
860 
861 	if((y%4) == 0)
862 		return 366;
863 	return 365;
864 }
865 long
866 gtime(Dosdir *dp)
867 {
868 	long t, noonGMT = 12*60*60;
869 	int i, y, M, d, h, m, s;
870 
871 	i = GSHORT(dp->time);
872 	h = i>>11; m = (i>>5)&63; s = (i&31)<<1;
873 	i = GSHORT(dp->date);
874 	y = 80+(i>>9); M = (i>>5)&15; d = i&31;
875 
876 	if (M < 1 || M > 12)
877 		return 0;
878 	if (d < 1 || d > dmsize[M-1])
879 		return 0;
880 	if (h > 23)
881 		return 0;
882 	if (m > 59)
883 		return 0;
884 	if (s > 59)
885 		return 0;
886 	y += 1900;
887 	t = 0;
888 	for(i=1970; i<y; i++)
889 		t += dysize(i);
890 	if (dysize(y)==366 && M >= 3)
891 		t++;
892 	while(--M)
893 		t += dmsize[M-1];
894 	t += d-1;
895 	noonGMT += 24*60*60*t;
896 	t = 24*t + h;
897 	t = 60*t + m;
898 	t = 60*t + s;
899 	t += (12-localtime(noonGMT)->hour)*60*60;
900 	return t;
901 }
902 
903 void
904 dirdump(void *dbuf)
905 {
906 	static char attrchar[] = "rhsvda67";
907 	char buf[72];
908 	Dosdir *d = dbuf;
909 	int i, n = 0;
910 	char *p;
911 
912 	if(!chatty)
913 		return;
914 	n += sprint(buf+n, "\"%.8s.%.3s\" ", d->name, d->ext);
915 	p = attrchar+7;
916 	for(i=0x80; i; i>>=1,p--)
917 		n += sprint(buf+n, "%c", d->attr&i ? *p : '-');
918 	i = GSHORT(d->time);
919 	n += sprint(buf+n, " %2.2d:%2.2d:%2.2d", i>>11, (i>>5)&63, (i&31)<<1);
920 	i = GSHORT(d->date);
921 	n += sprint(buf+n, " %2.2d.%2.2d.%2.2d", 80+(i>>9), (i>>5)&15, i&31);
922 	sprint(buf+n, " %d %d", GSHORT(d->start), GSHORT(d->length));
923 	chat("%s\n", buf);
924 }
925