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 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 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 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 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 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 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 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 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 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 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 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