format.c 17 KB

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