format.c 18 KB

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