dosfs.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855
  1. #include "all.h"
  2. #include "io.h"
  3. #include "mem.h"
  4. #include "dosfs.h"
  5. #define GSHORT(p) (((p)[1]<<8)|(p)[0])
  6. #define GLONG(p) ((GSHORT(p+2)<<16)|GSHORT(p))
  7. #define GLSHORT(p) (((p)[0]<<8)|(p)[1])
  8. #define GLLONG(p) ((GLSHORT(p)<<16)|GLSHORT(p+2))
  9. /*
  10. * debugging
  11. */
  12. #define chatty 0
  13. #define chat if(chatty)print
  14. /*
  15. * block io buffers
  16. */
  17. typedef struct Clustbuf Clustbuf;
  18. struct Clustbuf
  19. {
  20. int flags;
  21. int age;
  22. long sector;
  23. uchar * iobuf;
  24. Dos * dos;
  25. int size;
  26. int bufsize;
  27. };
  28. enum
  29. {
  30. Nbio= 16,
  31. LOCKED= 1,
  32. MOD= 2,
  33. IMMED= 4,
  34. };
  35. static void puttime(Dosdir*);
  36. static Clustbuf bio[Nbio];
  37. /*
  38. * write an io buffer and update its flags
  39. */
  40. static void
  41. writeclust(Clustbuf *p)
  42. {
  43. Dos *dos;
  44. int addr;
  45. dos = p->dos;
  46. addr = (p->sector+dos->start)*dos->sectbytes;
  47. chat("writeclust @ %ld addr %d...", p->sector, addr);
  48. if((*dos->seek)(dos->dev, addr) < 0)
  49. panic("writeclust: seek");
  50. if((*dos->write)(dos->dev, p->iobuf, p->size) != p->size)
  51. panic("writeclust: write");
  52. p->flags &= ~(MOD|IMMED);
  53. chat("OK\n");
  54. }
  55. /*
  56. * write any dirty buffers
  57. */
  58. static void
  59. syncclust(void)
  60. {
  61. Clustbuf *p;
  62. for(p = bio; p < &bio[Nbio]; p++){
  63. if(p->flags & LOCKED)
  64. panic("syncclust");
  65. if(p->flags & MOD)
  66. writeclust(p);
  67. }
  68. }
  69. /*
  70. * get an io buffer, possibly with valid data
  71. */
  72. static Clustbuf*
  73. getclust0(Dos *dos, long sector)
  74. {
  75. Clustbuf *p, *oldest;
  76. chat("getclust0 @ %ld\n", sector);
  77. /*
  78. * if we have it, just return it
  79. * otherwise, reuse the oldest unlocked entry
  80. */
  81. oldest = 0;
  82. for(p = bio; p < &bio[Nbio]; p++){
  83. if(sector == p->sector && dos == p->dos){
  84. if(p->flags & LOCKED)
  85. panic("getclust0 locked");
  86. chat("getclust0 %ld in cache\n", sector);
  87. p->flags |= LOCKED;
  88. return p;
  89. }
  90. if(p->flags & LOCKED)
  91. continue;
  92. if(oldest == 0 || p->age <= oldest->age)
  93. oldest = p;
  94. }
  95. p = oldest;
  96. if(p == 0)
  97. panic("getclust0 all locked");
  98. p->flags |= LOCKED;
  99. if(p->flags & MOD)
  100. writeclust(p);
  101. /*
  102. * make sure the buffer is big enough
  103. */
  104. if(p->iobuf==0 || p->bufsize < dos->clustbytes){
  105. p->bufsize = dos->clustbytes;
  106. p->iobuf = ialloc(p->bufsize, 0);
  107. }
  108. if(sector >= dos->dataaddr)
  109. p->size = dos->clustbytes;
  110. else
  111. p->size = dos->sectbytes;
  112. p->dos = 0; /* make it invalid */
  113. return p;
  114. }
  115. /*
  116. * get an io block from an io buffer
  117. */
  118. static Clustbuf*
  119. getclust(Dos *dos, long sector)
  120. {
  121. Clustbuf *p;
  122. int addr;
  123. p = getclust0(dos, sector);
  124. if(p->dos){
  125. p->age = MACHP(0)->ticks;
  126. return p;
  127. }
  128. addr = (sector+dos->start)*dos->sectbytes;
  129. chat("getclust seek addr %d\n", addr);
  130. if((*dos->seek)(dos->dev, addr) < 0){
  131. chat("can't seek block\n");
  132. return 0;
  133. }
  134. chat("getclust read addr %d\n", addr);
  135. if((*dos->read)(dos->dev, p->iobuf, p->size) != p->size){
  136. chat("can't read block\n");
  137. return 0;
  138. }
  139. p->age = MACHP(0)->ticks;
  140. p->dos = dos;
  141. p->sector = sector;
  142. chat("getclust %ld read\n", sector);
  143. return p;
  144. }
  145. /*
  146. * get an io block from an io buffer;
  147. * any current data is discarded.
  148. */
  149. static Clustbuf*
  150. getclustz(Dos *dos, long sector)
  151. {
  152. Clustbuf *p;
  153. p = getclust0(dos, sector);
  154. p->age = MACHP(0)->ticks;
  155. p->dos = dos;
  156. p->sector = sector;
  157. memset(p->iobuf, 0, p->size);
  158. p->flags |= MOD;
  159. chat("getclustz %ld\n", sector);
  160. return p;
  161. }
  162. /*
  163. * release an io buffer
  164. */
  165. static void
  166. putclust(Clustbuf *p)
  167. {
  168. if(!(p->flags & LOCKED))
  169. panic("putclust lock");
  170. if((p->flags & (MOD|IMMED)) == (MOD|IMMED))
  171. writeclust(p);
  172. p->flags &= ~LOCKED;
  173. chat("putclust @ sector %ld...", p->sector);
  174. }
  175. /*
  176. * walk the fat one level ( n is a current cluster number ).
  177. * return the new cluster number or -1 if no more.
  178. */
  179. static long
  180. fatwalk(Dos *dos, int n)
  181. {
  182. ulong k, sect;
  183. Clustbuf *p;
  184. int o;
  185. chat("fatwalk %d\n", n);
  186. if(n < 2 || n >= dos->fatclusters)
  187. return -1;
  188. switch(dos->fatbits){
  189. case 12:
  190. k = (3*n)/2; break;
  191. case 16:
  192. k = 2*n; break;
  193. default:
  194. return -1;
  195. }
  196. if(k >= dos->fatbytes)
  197. panic("getfat");
  198. sect = k/dos->sectbytes + dos->fataddr;
  199. o = k%dos->sectbytes;
  200. p = getclust(dos, sect);
  201. k = p->iobuf[o++];
  202. if(o >= dos->sectbytes){
  203. putclust(p);
  204. p = getclust(dos, sect+1);
  205. o = 0;
  206. }
  207. k |= p->iobuf[o]<<8;
  208. putclust(p);
  209. if(dos->fatbits == 12){
  210. if(n&1)
  211. k >>= 4;
  212. else
  213. k &= 0xfff;
  214. if(k >= 0xff8)
  215. k |= 0xf000;
  216. }
  217. k = k < 0xfff8 ? k : -1;
  218. chat("fatwalk %d -> %lud\n", n, k);
  219. return k;
  220. }
  221. /*
  222. * write a value into each copy of the fat.
  223. */
  224. static void
  225. fatwrite(Dos *dos, int n, int val)
  226. {
  227. ulong k, sect;
  228. Clustbuf *p;
  229. int i, o;
  230. chat("fatwrite %d %d...", n, val);
  231. if(n < 2 || n >= dos->fatclusters)
  232. panic("fatwrite n");
  233. switch(dos->fatbits){
  234. case 12:
  235. k = (3*n)/2; break;
  236. case 16:
  237. k = 2*n; break;
  238. default:
  239. panic("fatwrite fatbits");
  240. return;
  241. }
  242. if(k >= dos->fatbytes)
  243. panic("fatwrite k");
  244. for(i=0; i<dos->nfats; i++, k+=dos->fatbytes){
  245. sect = k/dos->sectbytes + dos->fataddr;
  246. o = k%dos->sectbytes;
  247. p = getclust(dos, sect);
  248. if(p == 0)
  249. panic("fatwrite getclust");
  250. switch(dos->fatbits){
  251. case 12:
  252. if(n&1){
  253. p->iobuf[o] &= 0x0f;
  254. p->iobuf[o++] |= val<<4;
  255. }else
  256. p->iobuf[o++] = val;
  257. if(o >= dos->sectbytes){
  258. p->flags |= MOD;
  259. putclust(p);
  260. p = getclust(dos, sect+1);
  261. if(p == 0)
  262. panic("fatwrite getclust");
  263. o = 0;
  264. }
  265. if(n&1)
  266. p->iobuf[o] = val>>4;
  267. else{
  268. p->iobuf[o] &= 0xf0;
  269. p->iobuf[o] |= (val>>8)&0x0f;
  270. }
  271. break;
  272. case 16:
  273. p->iobuf[o++] = val;
  274. p->iobuf[o] = val>>8;
  275. break;
  276. }
  277. p->flags |= MOD;
  278. putclust(p);
  279. }
  280. chat("OK\n");
  281. }
  282. /*
  283. * allocate a free cluster from the fat.
  284. */
  285. static int
  286. fatalloc(Dos *dos)
  287. {
  288. Clustbuf *p;
  289. int n;
  290. n = dos->freeptr;
  291. for(;;){
  292. if(fatwalk(dos, n) == 0)
  293. break;
  294. if(++n >= dos->fatclusters)
  295. n = 2;
  296. if(n == dos->freeptr)
  297. return -1;
  298. }
  299. dos->freeptr = n+1;
  300. if(dos->freeptr >= dos->fatclusters)
  301. dos->freeptr = 2;
  302. fatwrite(dos, n, 0xffff);
  303. p = getclustz(dos, dos->dataaddr + (n-2)*dos->clustsize);
  304. putclust(p);
  305. return n;
  306. }
  307. /*
  308. * map a file's logical sector address to a physical sector address
  309. */
  310. static long
  311. fileaddr(Dosfile *fp, long ltarget, Clustbuf *pdir)
  312. {
  313. Dos *dos = fp->dos;
  314. Dosdir *dp;
  315. long p;
  316. chat("fileaddr %8.8s %ld\n", fp->name, ltarget);
  317. /*
  318. * root directory is contiguous and easy
  319. */
  320. if(fp->pdir == 0){
  321. if(ltarget*dos->sectbytes >= dos->rootsize*sizeof(Dosdir))
  322. return -1;
  323. p = dos->rootaddr + ltarget;
  324. chat("fileaddr %ld -> %ld\n", ltarget, p);
  325. return p;
  326. }
  327. if(fp->pstart == 0){ /* empty file */
  328. if(!pdir)
  329. return -1;
  330. p = fatalloc(dos);
  331. if(p <= 0)
  332. return -1;
  333. chat("fileaddr initial alloc %ld\n", p);
  334. dp = (Dosdir *)(pdir->iobuf + fp->odir);
  335. puttime(dp);
  336. dp->start[0] = p;
  337. dp->start[1] = p>>8;
  338. pdir->flags |= MOD;
  339. fp->pstart = p;
  340. fp->pcurrent = p;
  341. fp->lcurrent = 0;
  342. }
  343. /*
  344. * anything else requires a walk through the fat
  345. * [lp]current will point to the last cluster if we run off the end
  346. */
  347. ltarget /= dos->clustsize;
  348. if(fp->pcurrent == 0 || fp->lcurrent > ltarget){
  349. /* go back to the beginning */
  350. fp->lcurrent = 0;
  351. fp->pcurrent = fp->pstart;
  352. }
  353. while(fp->lcurrent < ltarget){
  354. /* walk the fat */
  355. p = fatwalk(dos, fp->pcurrent);
  356. if(p < 0){
  357. if(!pdir)
  358. return -1;
  359. p = fatalloc(dos);
  360. if(p < 0){
  361. print("file system full\n");
  362. return -1;
  363. }
  364. fatwrite(dos, fp->pcurrent, p);
  365. }
  366. fp->pcurrent = p;
  367. ++fp->lcurrent;
  368. }
  369. /*
  370. * clusters start at 2 instead of 0 (why? - presotto)
  371. */
  372. p = dos->dataaddr + (fp->pcurrent-2)*dos->clustsize;
  373. chat("fileaddr %ld -> %ld\n", ltarget, p);
  374. return p;
  375. }
  376. /*
  377. * set up a dos file name
  378. */
  379. static void
  380. setname(char *name, char *ext, char *from)
  381. {
  382. char *to;
  383. memset(name, ' ', 8);
  384. memset(ext, ' ', 3);
  385. to = name;
  386. for(; *from && to-name < 8; from++, to++){
  387. if(*from == '.'){
  388. from++;
  389. break;
  390. }
  391. if(*from >= 'a' && *from <= 'z')
  392. *to = *from + 'A' - 'a';
  393. else
  394. *to = *from;
  395. }
  396. to = ext;
  397. for(; *from && to-ext < 3; from++, to++){
  398. if(*from >= 'a' && *from <= 'z')
  399. *to = *from + 'A' - 'a';
  400. else
  401. *to = *from;
  402. }
  403. chat("name is %8.8s %3.3s\n", name, ext);
  404. }
  405. /*
  406. * walk a directory returns
  407. * -1 if something went wrong
  408. * 0 if not found
  409. * 1 if found
  410. */
  411. static int
  412. doswalk(Dosfile *fp, char *name)
  413. {
  414. char dname[8], dext[3];
  415. Clustbuf *p;
  416. Dosdir *dp;
  417. long o, addr;
  418. if((fp->attr & DOSDIR) == 0){
  419. chat("walking non-directory!\n");
  420. return -1;
  421. }
  422. setname(dname, dext, name);
  423. fp->offset = 0; /* start at the beginning */
  424. for(;;){
  425. addr = fileaddr(fp, fp->offset/fp->dos->sectbytes, 0);
  426. if(addr < 0)
  427. return 0;
  428. p = getclust(fp->dos, addr);
  429. if(p == 0)
  430. return -1;
  431. for(o=0; o<p->size; o += sizeof(Dosdir)){
  432. dp = (Dosdir *)(p->iobuf + o);
  433. chat("comparing to %8.8s.%3.3s\n", (char*)dp->name, (char*)dp->ext);
  434. if(memcmp(dname, dp->name, sizeof(dp->name)) != 0)
  435. continue;
  436. if(memcmp(dext, dp->ext, sizeof(dp->ext)) == 0)
  437. goto Found;
  438. }
  439. fp->offset += p->size;
  440. putclust(p);
  441. }
  442. panic("doswalk");
  443. Found:
  444. fp->pdir = p->sector;
  445. fp->odir = o;
  446. putclust(p);
  447. memmove(fp->name, dname, sizeof(fp->name));
  448. memmove(fp->ext, dext, sizeof(fp->ext));
  449. fp->attr = dp->attr;
  450. fp->length = GLONG(dp->length);
  451. fp->pstart = GSHORT(dp->start);
  452. fp->pcurrent = 0;
  453. fp->lcurrent = 0;
  454. fp->offset = 0;
  455. return 1;
  456. }
  457. static void
  458. bootdump(Dosboot *b)
  459. {
  460. if(chatty == 0)
  461. return;
  462. print("magic: 0x%2.2x 0x%2.2x 0x%2.2x\n",
  463. b->magic[0], b->magic[1], b->magic[2]);
  464. print("version: \"%8.8s\"\n", (char*)b->version);
  465. print("sectbytes: %d\n", GSHORT(b->sectbytes));
  466. print("allocsize: %d\n", b->clustsize);
  467. print("nresrv: %d\n", GSHORT(b->nresrv));
  468. print("nfats: %d\n", b->nfats);
  469. print("rootsize: %d\n", GSHORT(b->rootsize));
  470. print("volsize: %d\n", GSHORT(b->volsize));
  471. print("mediadesc: 0x%2.2x\n", b->mediadesc);
  472. print("fatsize: %d\n", GSHORT(b->fatsize));
  473. print("trksize: %d\n", GSHORT(b->trksize));
  474. print("nheads: %d\n", GSHORT(b->nheads));
  475. print("nhidden: %d\n", GLONG(b->nhidden));
  476. print("bigvolsize: %d\n", GLONG(b->bigvolsize));
  477. print("driveno: %d\n", b->driveno);
  478. print("reserved0: 0x%2.2x\n", b->reserved0);
  479. print("bootsig: 0x%2.2x\n", b->bootsig);
  480. print("volid: 0x%8.8x\n", GLONG(b->volid));
  481. print("label: \"%11.11s\"\n", (char*)b->label);
  482. }
  483. /*
  484. * instructions that boot blocks can start with
  485. */
  486. #define JMPSHORT 0xeb
  487. #define JMPNEAR 0xe9
  488. /*
  489. * read dos file system properties
  490. */
  491. int
  492. dosinit(Dos *dos)
  493. {
  494. Clustbuf *p;
  495. Dospart *dp;
  496. Dosboot *b;
  497. int i;
  498. /* defaults till we know better */
  499. dos->start = 0;
  500. dos->sectbytes = 512;
  501. dos->clustsize = 1;
  502. dos->clustbytes = 512;
  503. /* get first sector */
  504. p = getclust(dos, 0);
  505. if(p == 0){
  506. chat("can't read boot block\n");
  507. return -1;
  508. }
  509. p->dos = 0;
  510. /* if a hard disk format, look for an active partition */
  511. b = (Dosboot *)p->iobuf;
  512. if(b->magic[0] != JMPNEAR && (b->magic[0] != JMPSHORT || b->magic[2] != 0x90)){
  513. if(p->iobuf[0x1fe] != 0x55 || p->iobuf[0x1ff] != 0xaa){
  514. print("no dos file system or partition table\n");
  515. putclust(p);
  516. return -1;
  517. }
  518. dp = (Dospart*)&p->iobuf[0x1be];
  519. for(i = 0; i < 4; i++, dp++)
  520. if(dp->type && dp->flag == 0x80)
  521. break;
  522. if(i == 4){
  523. putclust(p);
  524. return -1;
  525. }
  526. dos->start = GLONG(dp->start);
  527. putclust(p);
  528. p = getclust(dos, 0);
  529. if(p == 0){
  530. chat("can't read boot block\n");
  531. putclust(p);
  532. return -1;
  533. }
  534. p->dos = 0;
  535. }
  536. b = (Dosboot *)p->iobuf;
  537. if(b->magic[0] != JMPNEAR && (b->magic[0] != JMPSHORT || b->magic[2] != 0x90)){
  538. print("no dos file system\n");
  539. putclust(p);
  540. return -1;
  541. }
  542. if(chatty)
  543. bootdump(b);/**/
  544. /*
  545. * determine the systems' wondersous properties
  546. */
  547. dos->sectbytes = GSHORT(b->sectbytes);
  548. dos->clustsize = b->clustsize;
  549. dos->clustbytes = dos->sectbytes*dos->clustsize;
  550. dos->nresrv = GSHORT(b->nresrv);
  551. dos->nfats = b->nfats;
  552. dos->rootsize = GSHORT(b->rootsize);
  553. dos->volsize = GSHORT(b->volsize);
  554. if(dos->volsize == 0)
  555. dos->volsize = GLONG(b->bigvolsize);
  556. dos->mediadesc = b->mediadesc;
  557. dos->fatsize = GSHORT(b->fatsize);
  558. dos->fatbytes = dos->sectbytes*dos->fatsize;
  559. dos->fataddr = dos->nresrv;
  560. dos->rootaddr = dos->fataddr + dos->nfats*dos->fatsize;
  561. i = dos->rootsize*sizeof(Dosdir) + dos->sectbytes - 1;
  562. i = i/dos->sectbytes;
  563. dos->dataaddr = dos->rootaddr + i;
  564. dos->fatclusters = 2+(dos->volsize - dos->dataaddr)/dos->clustsize;
  565. if(dos->fatclusters < 4087)
  566. dos->fatbits = 12;
  567. else
  568. dos->fatbits = 16;
  569. dos->freeptr = 2;
  570. putclust(p);
  571. /*
  572. * set up the root
  573. */
  574. dos->root.dos = dos;
  575. dos->root.pdir = 0;
  576. dos->root.odir = 0;
  577. memmove(dos->root.name, "<root> ", 8);
  578. memmove(dos->root.ext, " ", 3);
  579. dos->root.attr = DOSDIR;
  580. dos->root.length = dos->rootsize*sizeof(Dosdir);
  581. dos->root.pstart = 0;
  582. dos->root.pcurrent = dos->root.lcurrent = 0;
  583. dos->root.offset = 0;
  584. syncclust();
  585. return 0;
  586. }
  587. static char *
  588. nextelem(char *path, char *elem)
  589. {
  590. int i;
  591. while(*path == '/')
  592. path++;
  593. if(*path==0 || *path==' ')
  594. return 0;
  595. for(i=0; *path && *path != '/' && *path != ' '; i++){
  596. if(i >= NAMELEN){
  597. print("name component too long\n");
  598. return 0;
  599. }
  600. *elem++ = *path++;
  601. }
  602. *elem = 0;
  603. return path;
  604. }
  605. static void
  606. puttime(Dosdir *d)
  607. {
  608. ulong secs;
  609. Rtc rtc;
  610. ushort x;
  611. secs = rtctime();
  612. sec2rtc(secs, &rtc);
  613. x = (rtc.hour<<11) | (rtc.min<<5) | (rtc.sec>>1);
  614. d->time[0] = x;
  615. d->time[1] = x>>8;
  616. x = ((rtc.year-80)<<9) | ((rtc.mon+1)<<5) | rtc.mday;
  617. d->date[0] = x;
  618. d->date[1] = x>>8;
  619. }
  620. Dosfile*
  621. dosopen(Dos *dos, char *path, Dosfile *fp)
  622. {
  623. char element[NAMELEN];
  624. *fp = dos->root;
  625. while(path = nextelem(path, element)){
  626. switch(doswalk(fp, element)){
  627. case -1:
  628. print("error walking to %s\n", element);
  629. return 0;
  630. case 0:
  631. print("%s not found\n", element);
  632. return 0;
  633. case 1:
  634. print("found %s attr 0x%ux start 0x%lux len %ld\n",
  635. element, fp->attr, fp->pstart, fp->length);
  636. break;
  637. }
  638. }
  639. syncclust();
  640. return fp;
  641. }
  642. /*
  643. * read from a dos file
  644. */
  645. long
  646. dosread(Dosfile *fp, void *a, long n)
  647. {
  648. long addr, k, o;
  649. Clustbuf *p;
  650. uchar *to;
  651. if((fp->attr & DOSDIR) == 0){
  652. if(fp->offset >= fp->length)
  653. return 0;
  654. if(fp->offset+n > fp->length)
  655. n = fp->length - fp->offset;
  656. }
  657. to = a;
  658. while(n > 0){
  659. /*
  660. * read the data; sectors below dos->dataaddr
  661. * are read one at a time.
  662. */
  663. addr = fileaddr(fp, fp->offset/fp->dos->sectbytes, 0);
  664. if(addr < 0)
  665. return -1;
  666. p = getclust(fp->dos, addr);
  667. if(p == 0)
  668. return -1;
  669. /*
  670. * copy the bytes we need
  671. */
  672. o = fp->offset % p->size;
  673. k = p->size - o;
  674. if(k > n)
  675. k = n;
  676. memmove(to, p->iobuf+o, k);
  677. putclust(p);
  678. to += k;
  679. fp->offset += k;
  680. n -= k;
  681. }
  682. syncclust();
  683. return to - (uchar *)a;
  684. }
  685. /*
  686. * write to a dos file
  687. */
  688. long
  689. doswrite(Dosfile *fp, void *a, long n)
  690. {
  691. long blksize, addr, k, o;
  692. Clustbuf *p, *pdir;
  693. Dosdir *dp;
  694. uchar *from;
  695. if(fp->attr & DOSDIR){
  696. print("write dir\n");
  697. return -1;
  698. }
  699. if(fp->pdir){
  700. pdir = getclust(fp->dos, fp->pdir);
  701. /*
  702. * should do consistency check if
  703. * concurrent access is possible.
  704. */
  705. if(pdir == 0)
  706. panic("doswrite");
  707. }else
  708. pdir = 0;
  709. blksize = pdir ? fp->dos->clustbytes : fp->dos->sectbytes;
  710. from = a;
  711. while(n > 0){
  712. addr = fileaddr(fp, fp->offset/fp->dos->sectbytes, pdir);
  713. if(addr < 0)
  714. return -1;
  715. o = fp->offset % blksize;
  716. if(o == 0 && n >= blksize)
  717. p = getclustz(fp->dos, addr);
  718. else
  719. p = getclust(fp->dos, addr);
  720. if(p == 0)
  721. return -1;
  722. /*
  723. * copy the bytes we need
  724. */
  725. k = p->size - o;
  726. if(k > n)
  727. k = n;
  728. memmove(p->iobuf+o, from, k);
  729. p->flags |= MOD;
  730. putclust(p);
  731. from += k;
  732. fp->offset += k;
  733. n -= k;
  734. }
  735. if(pdir){
  736. dp = (Dosdir *)(pdir->iobuf + fp->odir);
  737. puttime(dp);
  738. if(fp->offset > fp->length){
  739. fp->length = fp->offset;
  740. dp->length[0] = fp->length;
  741. dp->length[1] = fp->length>>8;
  742. dp->length[2] = fp->length>>16;
  743. dp->length[3] = fp->length>>24;
  744. }
  745. pdir->flags |= MOD;
  746. putclust(pdir);
  747. }
  748. syncclust();
  749. return from - (uchar *)a;
  750. }
  751. /*
  752. * truncate a dos file to zero length
  753. */
  754. int
  755. dostrunc(Dosfile *fp)
  756. {
  757. Clustbuf *pdir;
  758. Dosdir *dp;
  759. int p, np;
  760. if(fp->attr & DOSDIR){
  761. print("trunc dir\n");
  762. return -1;
  763. }
  764. pdir = getclust(fp->dos, fp->pdir);
  765. if(pdir == 0)
  766. panic("dostrunc");
  767. p = fatwalk(fp->dos, fp->pstart);
  768. fatwrite(fp->dos, fp->pstart, 0xffff);
  769. while(p >= 0){
  770. np = fatwalk(fp->dos, p);
  771. fatwrite(fp->dos, p, 0);
  772. p = np;
  773. }
  774. fp->length = 0;
  775. dp = (Dosdir *)(pdir->iobuf + fp->odir);
  776. puttime(dp);
  777. dp->length[0] = 0;
  778. dp->length[1] = 0;
  779. dp->length[2] = 0;
  780. dp->length[3] = 0;
  781. pdir->flags |= MOD;
  782. putclust(pdir);
  783. syncclust();
  784. return 0;
  785. }