1 #include <u.h>
2 #include <libc.h>
3 #include <ctype.h>
4 #include <disk.h>
5
6 /*
7 * disk types (all MFM encoding)
8 */
9 typedef struct Type Type;
10 struct Type
11 {
12 char *name;
13 int bytes; /* bytes/sector */
14 int sectors; /* sectors/track */
15 int heads; /* number of heads */
16 int tracks; /* tracks/disk */
17 int media; /* media descriptor byte */
18 int cluster; /* default cluster size */
19 };
20 Type floppytype[] =
21 {
22 { "3½HD", 512, 18, 2, 80, 0xf0, 1, },
23 { "3½DD", 512, 9, 2, 80, 0xf9, 2, },
24 { "3½QD", 512, 36, 2, 80, 0xf9, 2, }, /* invented */
25 { "5¼HD", 512, 15, 2, 80, 0xf9, 1, },
26 { "5¼DD", 512, 9, 2, 40, 0xfd, 2, },
27 { "hard", 512, 0, 0, 0, 0xf8, 4, },
28 };
29
30 #define NTYPES (sizeof(floppytype)/sizeof(Type))
31
32 typedef struct Dosboot Dosboot;
33 struct Dosboot{
34 uchar magic[3]; /* really an x86 JMP instruction */
35 uchar version[8];
36 uchar sectsize[2];
37 uchar clustsize;
38 uchar nresrv[2];
39 uchar nfats;
40 uchar rootsize[2];
41 uchar volsize[2];
42 uchar mediadesc;
43 uchar fatsize[2];
44 uchar trksize[2];
45 uchar nheads[2];
46 uchar nhidden[4];
47 uchar bigvolsize[4];
48 uchar driveno;
49 uchar reserved0;
50 uchar bootsig;
51 uchar volid[4];
52 uchar label[11];
53 uchar type[8];
54 };
55 #define PUTSHORT(p, v) { (p)[1] = (v)>>8; (p)[0] = (v); }
56 #define PUTLONG(p, v) { PUTSHORT((p), (v)); PUTSHORT((p)+2, (v)>>16); }
57 #define GETSHORT(p) (((p)[1]<<8)|(p)[0])
58 #define GETLONG(p) (((ulong)GETSHORT(p+2)<<16)|(ulong)GETSHORT(p))
59
60 typedef struct Dosdir Dosdir;
61 struct Dosdir
62 {
63 uchar name[8];
64 uchar ext[3];
65 uchar attr;
66 uchar reserved[10];
67 uchar time[2];
68 uchar date[2];
69 uchar start[2];
70 uchar length[4];
71 };
72
73 #define DRONLY 0x01
74 #define DHIDDEN 0x02
75 #define DSYSTEM 0x04
76 #define DVLABEL 0x08
77 #define DDIR 0x10
78 #define DARCH 0x20
79
80 /*
81 * the boot program for the boot sector.
82 */
83 int nbootprog = 188; /* no. of bytes of boot program, including the first 0x3E */
84 uchar bootprog[512] =
85 {
86 [0x000] 0xEB, 0x3C, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00,
87 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
88 [0x03E] 0xFA, 0xFC, 0x8C, 0xC8, 0x8E, 0xD8, 0x8E, 0xD0,
89 0xBC, 0x00, 0x7C, 0xBE, 0x77, 0x7C, 0xE8, 0x19,
90 0x00, 0x33, 0xC0, 0xCD, 0x16, 0xBB, 0x40, 0x00,
91 0x8E, 0xC3, 0xBB, 0x72, 0x00, 0xB8, 0x34, 0x12,
92 0x26, 0x89, 0x07, 0xEA, 0x00, 0x00, 0xFF, 0xFF,
93 0xEB, 0xD6, 0xAC, 0x0A, 0xC0, 0x74, 0x09, 0xB4,
94 0x0E, 0xBB, 0x07, 0x00, 0xCD, 0x10, 0xEB, 0xF2,
95 0xC3, 'N', 'o', 't', ' ', 'a', ' ', 'b',
96 'o', 'o', 't', 'a', 'b', 'l', 'e', ' ',
97 'd', 'i', 's', 'c', ' ', 'o', 'r', ' ',
98 'd', 'i', 's', 'c', ' ', 'e', 'r', 'r',
99 'o', 'r', '\r', '\n', 'P', 'r', 'e', 's',
100 's', ' ', 'a', 'l', 'm', 'o', 's', 't',
101 ' ', 'a', 'n', 'y', ' ', 'k', 'e', 'y',
102 ' ', 't', 'o', ' ', 'r', 'e', 'b', 'o',
103 'o', 't', '.', '.', '.', 0x00, 0x00, 0x00,
104 [0x1F0] 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
105 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xAA,
106 };
107
108 char *dev;
109 int clustersize;
110 uchar *fat; /* the fat */
111 int fatbits;
112 int fatsecs;
113 int fatlast; /* last cluster allocated */
114 int clusters;
115 int fatsecs;
116 vlong volsecs;
117 uchar *root; /* first block of root */
118 int rootsecs;
119 int rootfiles;
120 int rootnext;
121 int nresrv = 1;
122 int chatty;
123 vlong length;
124 Type *t;
125 int fflag;
126 int hflag;
127 int xflag;
128 char *file;
129 char *pbs;
130 char *type;
131 char *bootfile;
132 int dos;
133
134 enum
135 {
136 Sof = 1, /* start of file */
137 Eof = 2, /* end of file */
138 };
139
140 void dosfs(int, int, Disk*, char*, int, char*[], int);
141 ulong clustalloc(int);
142 void addrname(uchar*, Dir*, char*, ulong);
143 void sanitycheck(Disk*);
144
145 void
usage(void)146 usage(void)
147 {
148 fprint(2, "usage: disk/format [-df] [-b bootblock] [-c csize] "
149 "[-l label] [-r nresrv] [-t type] disk [files ...]\n");
150 exits("usage");
151 }
152
153 void
fatal(char * fmt,...)154 fatal(char *fmt, ...)
155 {
156 char err[128];
157 va_list arg;
158
159 va_start(arg, fmt);
160 vsnprint(err, sizeof(err), fmt, arg);
161 va_end(arg);
162 fprint(2, "format: %s\n", err);
163 if(fflag && file)
164 remove(file);
165 exits(err);
166 }
167
168 void
main(int argc,char ** argv)169 main(int argc, char **argv)
170 {
171 int fd, n, writepbs;
172 char buf[512], label[11];
173 char *a;
174 Disk *disk;
175
176 dos = 0;
177 type = nil;
178 clustersize = 0;
179 writepbs = 0;
180 memmove(label, "CYLINDRICAL", sizeof(label));
181 ARGBEGIN {
182 case 'b':
183 pbs = EARGF(usage());
184 writepbs = 1;
185 break;
186 case 'c':
187 clustersize = atoi(EARGF(usage()));
188 break;
189 case 'd':
190 dos = 1;
191 writepbs = 1;
192 break;
193 case 'f':
194 fflag = 1;
195 break;
196 case 'l':
197 a = EARGF(usage());
198 n = strlen(a);
199 if(n > sizeof(label))
200 n = sizeof(label);
201 memmove(label, a, n);
202 while(n < sizeof(label))
203 label[n++] = ' ';
204 break;
205 case 'r':
206 nresrv = atoi(EARGF(usage()));
207 break;
208 case 't':
209 type = EARGF(usage());
210 break;
211 case 'v':
212 chatty++;
213 break;
214 case 'x':
215 xflag = 1;
216 break;
217 default:
218 usage();
219 } ARGEND
220
221 if(argc < 1)
222 usage();
223
224 disk = opendisk(argv[0], 0, 0);
225 if(disk == nil) {
226 if(fflag) {
227 if((fd = create(argv[0], ORDWR, 0666)) >= 0) {
228 file = argv[0];
229 close(fd);
230 disk = opendisk(argv[0], 0, 0);
231 }
232 }
233 }
234 if(disk == nil)
235 fatal("opendisk: %r");
236
237 if(disk->type == Tfile)
238 fflag = 1;
239
240 if(type == nil) {
241 switch(disk->type){
242 case Tfile:
243 type = "3½HD";
244 break;
245 case Tfloppy:
246 seek(disk->ctlfd, 0, 0);
247 n = read(disk->ctlfd, buf, 10);
248 if(n <= 0 || n >= 10)
249 fatal("reading floppy type");
250 buf[n] = 0;
251 type = strdup(buf);
252 if(type == nil)
253 fatal("out of memory");
254 break;
255 case Tsd:
256 type = "hard";
257 break;
258 default:
259 type = "unknown";
260 break;
261 }
262 }
263
264 if(!fflag && disk->type == Tfloppy)
265 if(fprint(disk->ctlfd, "format %s", type) < 0)
266 fatal("formatting floppy as %s: %r", type);
267
268 if(disk->type != Tfloppy)
269 sanitycheck(disk);
270
271 /* check that everything will succeed */
272 dosfs(dos, writepbs, disk, label, argc-1, argv+1, 0);
273
274 /* commit */
275 dosfs(dos, writepbs, disk, label, argc-1, argv+1, 1);
276
277 print("used %lld bytes\n", fatlast*clustersize*disk->secsize);
278 exits(0);
279 }
280
281 /*
282 * Look for a partition table on sector 1, as would be the
283 * case if we were erroneously formatting 9fat without -r 2.
284 * If it's there and nresrv is not big enough, complain and exit.
285 * I've blown away my partition table too many times.
286 */
287 void
sanitycheck(Disk * disk)288 sanitycheck(Disk *disk)
289 {
290 char buf[512];
291 int bad;
292
293 if(xflag)
294 return;
295
296 bad = 0;
297 if(dos && nresrv < 2 && seek(disk->fd, disk->secsize, 0) == disk->secsize
298 && read(disk->fd, buf, sizeof(buf)) >= 5 && strncmp(buf, "part ", 5) == 0) {
299 fprint(2,
300 "there's a plan9 partition on the disk\n"
301 "and you didn't specify -r 2 (or greater).\n"
302 "either specify -r 2 or -x to disable this check.\n");
303 bad = 1;
304 }
305
306 if(disk->type == Tsd && disk->offset == 0LL) {
307 fprint(2,
308 "you're attempting to format your disk (/dev/sdXX/data)\n"
309 "rather than a partition like /dev/sdXX/9fat;\n"
310 "this is likely a mistake. specify -x to disable this check.\n");
311 bad = 1;
312 }
313
314 if(bad)
315 exits("failed disk sanity check");
316 }
317
318 /*
319 * Return the BIOS drive number for the disk.
320 * 0x80 is the first fixed disk, 0x81 the next, etc.
321 * We map sdC0=0x80, sdC1=0x81, sdD0=0x82, sdD1=0x83
322 */
323 int
getdriveno(Disk * disk)324 getdriveno(Disk *disk)
325 {
326 char buf[64], *p;
327
328 if(disk->type != Tsd)
329 return 0x80; /* first hard disk */
330
331 if(fd2path(disk->fd, buf, sizeof(buf)) < 0)
332 return 0x80;
333
334 /*
335 * The name is of the format #SsdC0/foo
336 * or /dev/sdC0/foo.
337 * So that we can just look for /sdC0, turn
338 * #SsdC0/foo into #/sdC0/foo.
339 */
340 if(buf[0] == '#' && buf[1] == 'S')
341 buf[1] = '/';
342
343 for(p=buf; *p; p++)
344 if(p[0] == 's' && p[1] == 'd' && (p[2]=='C' || p[2]=='D') &&
345 (p[3]=='0' || p[3]=='1'))
346 return 0x80 + (p[2]-'C')*2 + (p[3]-'0');
347
348 return 0x80;
349 }
350
351 long
writen(int fd,void * buf,long n)352 writen(int fd, void *buf, long n)
353 {
354 long m, tot;
355
356 /* write 8k at a time, to be nice to the disk subsystem */
357 for(tot=0; tot<n; tot+=m){
358 m = n - tot;
359 if(m > 8192)
360 m = 8192;
361 if(write(fd, (uchar*)buf+tot, m) != m)
362 break;
363 }
364 return tot;
365 }
366
367 void
dosfs(int dofat,int dopbs,Disk * disk,char * label,int argc,char * argv[],int commit)368 dosfs(int dofat, int dopbs, Disk *disk, char *label, int argc, char *argv[], int commit)
369 {
370 char r[16];
371 Dosboot *b;
372 uchar *buf, *pbsbuf, *p;
373 Dir *d;
374 int i, data, newclusters, npbs, n, sysfd;
375 ulong x;
376 vlong length, secsize;
377
378 if(dofat == 0 && dopbs == 0)
379 return;
380
381 for(t = floppytype; t < &floppytype[NTYPES]; t++)
382 if(strcmp(type, t->name) == 0)
383 break;
384 if(t == &floppytype[NTYPES])
385 fatal("unknown floppy type %s", type);
386
387 if(t->sectors == 0 && strcmp(type, "hard") == 0) {
388 t->sectors = disk->s;
389 t->heads = disk->h;
390 t->tracks = disk->c;
391 }
392
393 if(t->sectors == 0 && dofat)
394 fatal("cannot format fat with type %s: geometry unknown\n", type);
395
396 if(fflag){
397 disk->size = t->bytes*t->sectors*t->heads*t->tracks;
398 disk->secsize = t->bytes;
399 disk->secs = disk->size / disk->secsize;
400 }
401
402 secsize = disk->secsize;
403 length = disk->size;
404
405 buf = malloc(secsize);
406 if(buf == 0)
407 fatal("out of memory");
408
409 /*
410 * Make disk full size if a file.
411 */
412 if(fflag && disk->type == Tfile){
413 if((d = dirfstat(disk->wfd)) == nil)
414 fatal("fstat disk: %r");
415 if(commit && d->length < disk->size) {
416 if(seek(disk->wfd, disk->size-1, 0) < 0)
417 fatal("seek to 9: %r");
418 if(write(disk->wfd, "9", 1) < 0)
419 fatal("writing 9: @%lld %r", seek(disk->wfd, 0LL, 1));
420 }
421 free(d);
422 }
423
424 /*
425 * Start with initial sector from disk
426 */
427 if(seek(disk->fd, 0, 0) < 0)
428 fatal("seek to boot sector: %r\n");
429 if(commit && read(disk->fd, buf, secsize) != secsize)
430 fatal("reading boot sector: %r");
431
432 if(dofat)
433 memset(buf, 0, sizeof(Dosboot));
434
435 /*
436 * Jump instruction and OEM name.
437 */
438 b = (Dosboot*)buf;
439 b->magic[0] = 0xEB;
440 b->magic[1] = 0x3C;
441 b->magic[2] = 0x90;
442 memmove(b->version, "Plan9.00", sizeof(b->version));
443
444 /*
445 * Add bootstrapping code; assume it starts
446 * at 0x3E (the destination of the jump we just
447 * wrote to b->magic).
448 */
449 if(dopbs) {
450 pbsbuf = malloc(secsize);
451 if(pbsbuf == 0)
452 fatal("out of memory");
453
454 if(pbs){
455 if((sysfd = open(pbs, OREAD)) < 0)
456 fatal("open %s: %r", pbs);
457 if((npbs = read(sysfd, pbsbuf, secsize)) < 0)
458 fatal("read %s: %r", pbs);
459
460 if(npbs > secsize-2)
461 fatal("boot block too large");
462
463 close(sysfd);
464 }
465 else {
466 memmove(pbsbuf, bootprog, sizeof(bootprog));
467 npbs = nbootprog;
468 }
469 if(npbs <= 0x3E)
470 fprint(2, "warning: pbs too small\n");
471 else
472 memmove(buf+0x3E, pbsbuf+0x3E, npbs-0x3E);
473
474 free(pbsbuf);
475 }
476
477 /*
478 * Add FAT BIOS parameter block.
479 */
480 if(dofat) {
481 if(commit) {
482 print("Initializing FAT file system\n");
483 print("type %s, %d tracks, %d heads, %d sectors/track, %lld bytes/sec\n",
484 t->name, t->tracks, t->heads, t->sectors, secsize);
485 }
486
487 if(clustersize == 0)
488 clustersize = t->cluster;
489 /*
490 * the number of fat bits depends on how much disk is left
491 * over after you subtract out the space taken up by the fat tables.
492 * try both. what a crock.
493 */
494 fatbits = 12;
495 Tryagain:
496 volsecs = length/secsize;
497 /*
498 * here's a crock inside a crock. even having fixed fatbits,
499 * the number of fat sectors depends on the number of clusters,
500 * but of course we don't know yet. maybe iterating will get us there.
501 * or maybe it will cycle.
502 */
503 clusters = 0;
504 for(i=0;; i++){
505 fatsecs = (fatbits*clusters + 8*secsize - 1)/(8*secsize);
506 rootsecs = volsecs/200;
507 rootfiles = rootsecs * (secsize/sizeof(Dosdir));
508 if(rootfiles > 512){
509 rootfiles = 512;
510 rootsecs = rootfiles/(secsize/sizeof(Dosdir));
511 }
512 data = nresrv + 2*fatsecs + (rootfiles*sizeof(Dosdir) + secsize-1)/secsize;
513 newclusters = 2 + (volsecs - data)/clustersize;
514 if(newclusters == clusters)
515 break;
516 clusters = newclusters;
517 if(i > 10)
518 fatal("can't decide how many clusters to use (%d? %d?)", clusters, newclusters);
519 if(chatty) print("clusters %d\n", clusters);
520 }
521
522 if(chatty) print("try %d fatbits => %d clusters of %d\n", fatbits, clusters, clustersize);
523 switch(fatbits){
524 case 12:
525 if(clusters >= 4087){
526 fatbits = 16;
527 goto Tryagain;
528 }
529 break;
530 case 16:
531 if(clusters >= 65527)
532 fatal("disk too big; implement fat32");
533 break;
534 }
535 PUTSHORT(b->sectsize, secsize);
536 b->clustsize = clustersize;
537 PUTSHORT(b->nresrv, nresrv);
538 b->nfats = 2;
539 PUTSHORT(b->rootsize, rootfiles);
540 if(volsecs < (1<<16))
541 PUTSHORT(b->volsize, volsecs);
542 b->mediadesc = t->media;
543 PUTSHORT(b->fatsize, fatsecs);
544 PUTSHORT(b->trksize, t->sectors);
545 PUTSHORT(b->nheads, t->heads);
546 PUTLONG(b->nhidden, disk->offset);
547 PUTLONG(b->bigvolsize, volsecs);
548
549 /*
550 * Extended BIOS Parameter Block.
551 */
552 if(t->media == 0xF8)
553 b->driveno = getdriveno(disk);
554 else
555 b->driveno = 0;
556 if(chatty) print("driveno = %ux\n", b->driveno);
557
558 b->bootsig = 0x29;
559 x = disk->offset + b->nfats*fatsecs + nresrv;
560 PUTLONG(b->volid, x);
561 if(chatty) print("volid = %lux %lux\n", x, GETLONG(b->volid));
562 memmove(b->label, label, sizeof(b->label));
563 sprint(r, "FAT%d ", fatbits);
564 memmove(b->type, r, sizeof(b->type));
565 }
566
567 buf[secsize-2] = 0x55;
568 buf[secsize-1] = 0xAA;
569
570 if(commit) {
571 if(seek(disk->wfd, 0, 0) < 0)
572 fatal("seek to boot sector: %r\n");
573 if(write(disk->wfd, buf, secsize) != secsize)
574 fatal("writing boot sector: %r");
575 }
576
577 free(buf);
578
579 /*
580 * If we were only called to write the PBS, leave now.
581 */
582 if(dofat == 0)
583 return;
584
585 /*
586 * allocate an in memory fat
587 */
588 if(seek(disk->wfd, nresrv*secsize, 0) < 0)
589 fatal("seek to fat: %r\n");
590 if(chatty) print("fat @%lluX\n", seek(disk->wfd, 0, 1));
591 fat = malloc(fatsecs*secsize);
592 if(fat == 0)
593 fatal("out of memory");
594 memset(fat, 0, fatsecs*secsize);
595 fat[0] = t->media;
596 fat[1] = 0xff;
597 fat[2] = 0xff;
598 if(fatbits == 16)
599 fat[3] = 0xff;
600 fatlast = 1;
601 if(seek(disk->wfd, 2*fatsecs*secsize, 1) < 0) /* 2 fats */
602 fatal("seek to root: %r");
603 if(chatty) print("root @%lluX\n", seek(disk->wfd, 0LL, 1));
604
605 /*
606 * allocate an in memory root
607 */
608 root = malloc(rootsecs*secsize);
609 if(root == 0)
610 fatal("out of memory");
611 memset(root, 0, rootsecs*secsize);
612 if(seek(disk->wfd, rootsecs*secsize, 1) < 0) /* rootsecs */
613 fatal("seek to files: %r");
614 if(chatty) print("files @%lluX\n", seek(disk->wfd, 0LL, 1));
615
616 /*
617 * Now positioned at the Files Area.
618 * If we have any arguments, process
619 * them and write out.
620 */
621 for(p = root; argc > 0; argc--, argv++, p += sizeof(Dosdir)){
622 if(p >= (root+(rootsecs*secsize)))
623 fatal("too many files in root");
624 /*
625 * Open the file and get its length.
626 */
627 if((sysfd = open(*argv, OREAD)) < 0)
628 fatal("open %s: %r", *argv);
629 if((d = dirfstat(sysfd)) == nil)
630 fatal("stat %s: %r", *argv);
631 if(d->length > 0xFFFFFFFFU)
632 fatal("file %s too big\n", *argv, d->length);
633 if(commit)
634 print("Adding file %s, length %lld\n", *argv, d->length);
635
636 length = d->length;
637 if(length){
638 /*
639 * Allocate a buffer to read the entire file into.
640 * This must be rounded up to a cluster boundary.
641 *
642 * Read the file and write it out to the Files Area.
643 */
644 length += secsize*clustersize - 1;
645 length /= secsize*clustersize;
646 length *= secsize*clustersize;
647 if((buf = malloc(length)) == 0)
648 fatal("out of memory");
649
650 if(readn(sysfd, buf, d->length) != d->length)
651 fatal("read %s: %r", *argv);
652 memset(buf+d->length, 0, length-d->length);
653 if(chatty) print("%s @%lluX\n", d->name, seek(disk->wfd, 0LL, 1));
654 if(commit && writen(disk->wfd, buf, length) != length)
655 fatal("write %s: %r", *argv);
656 free(buf);
657
658 close(sysfd);
659
660 /*
661 * Allocate the FAT clusters.
662 * We're assuming here that where we
663 * wrote the file is in sync with
664 * the cluster allocation.
665 * Save the starting cluster.
666 */
667 length /= secsize*clustersize;
668 x = clustalloc(Sof);
669 for(n = 0; n < length-1; n++)
670 clustalloc(0);
671 clustalloc(Eof);
672 }
673 else
674 x = 0;
675
676 /*
677 * Add the filename to the root.
678 */
679 fprint(2, "add %s at clust %lux\n", d->name, x);
680 addrname(p, d, *argv, x);
681 free(d);
682 }
683
684 /*
685 * write the fats and root
686 */
687 if(commit) {
688 if(seek(disk->wfd, nresrv*secsize, 0) < 0)
689 fatal("seek to fat #1: %r");
690 if(write(disk->wfd, fat, fatsecs*secsize) < 0)
691 fatal("writing fat #1: %r");
692 if(write(disk->wfd, fat, fatsecs*secsize) < 0)
693 fatal("writing fat #2: %r");
694 if(write(disk->wfd, root, rootsecs*secsize) < 0)
695 fatal("writing root: %r");
696 }
697
698 free(fat);
699 free(root);
700 }
701
702 /*
703 * allocate a cluster
704 */
705 ulong
clustalloc(int flag)706 clustalloc(int flag)
707 {
708 ulong o, x;
709
710 if(flag != Sof){
711 x = (flag == Eof) ? 0xffff : (fatlast+1);
712 if(fatbits == 12){
713 x &= 0xfff;
714 o = (3*fatlast)/2;
715 if(fatlast & 1){
716 fat[o] = (fat[o]&0x0f) | (x<<4);
717 fat[o+1] = (x>>4);
718 } else {
719 fat[o] = x;
720 fat[o+1] = (fat[o+1]&0xf0) | ((x>>8) & 0x0F);
721 }
722 } else {
723 o = 2*fatlast;
724 fat[o] = x;
725 fat[o+1] = x>>8;
726 }
727 }
728
729 if(flag == Eof)
730 return 0;
731 else{
732 ++fatlast;
733 if(fatlast >= clusters)
734 sysfatal("data does not fit on disk (%d %d)", fatlast, clusters);
735 return fatlast;
736 }
737 }
738
739 void
putname(char * p,Dosdir * d)740 putname(char *p, Dosdir *d)
741 {
742 int i;
743
744 memset(d->name, ' ', sizeof d->name+sizeof d->ext);
745 for(i = 0; i< sizeof(d->name); i++){
746 if(*p == 0 || *p == '.')
747 break;
748 d->name[i] = toupper(*p++);
749 }
750 p = strrchr(p, '.');
751 if(p){
752 for(i = 0; i < sizeof d->ext; i++){
753 if(*++p == 0)
754 break;
755 d->ext[i] = toupper(*p);
756 }
757 }
758 }
759
760 void
puttime(Dosdir * d)761 puttime(Dosdir *d)
762 {
763 Tm *t = localtime(time(0));
764 ushort x;
765
766 x = (t->hour<<11) | (t->min<<5) | (t->sec>>1);
767 d->time[0] = x;
768 d->time[1] = x>>8;
769 x = ((t->year-80)<<9) | ((t->mon+1)<<5) | t->mday;
770 d->date[0] = x;
771 d->date[1] = x>>8;
772 }
773
774 void
addrname(uchar * entry,Dir * dir,char * name,ulong start)775 addrname(uchar *entry, Dir *dir, char *name, ulong start)
776 {
777 char *s;
778 Dosdir *d;
779
780 s = strrchr(name, '/');
781 if(s)
782 s++;
783 else
784 s = name;
785
786 d = (Dosdir*)entry;
787 putname(s, d);
788 if(strcmp(s, "9load") == 0)
789 d->attr = DSYSTEM;
790 else
791 d->attr = 0;
792 puttime(d);
793 d->start[0] = start;
794 d->start[1] = start>>8;
795 d->length[0] = dir->length;
796 d->length[1] = dir->length>>8;
797 d->length[2] = dir->length>>16;
798 d->length[3] = dir->length>>24;
799 }
800