dosfs.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858
  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. Devsize 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. Off addr;
  45. dos = p->dos;
  46. addr = (p->sector+dos->start)*dos->sectbytes;
  47. chat("writeclust @ %lld addr %lld...", (Wideoff)p->sector,
  48. (Wideoff)addr);
  49. if((*dos->seek)(dos->dev, addr) < 0)
  50. panic("writeclust: seek");
  51. if((*dos->write)(dos->dev, p->iobuf, p->size) != p->size)
  52. panic("writeclust: write");
  53. p->flags &= ~(MOD|IMMED);
  54. chat("OK\n");
  55. }
  56. /*
  57. * write any dirty buffers
  58. */
  59. static void
  60. syncclust(void)
  61. {
  62. Clustbuf *p;
  63. for(p = bio; p < &bio[Nbio]; p++){
  64. if(p->flags & LOCKED)
  65. panic("syncclust");
  66. if(p->flags & MOD)
  67. writeclust(p);
  68. }
  69. }
  70. /*
  71. * get an io buffer, possibly with valid data
  72. */
  73. static Clustbuf*
  74. getclust0(Dos *dos, Off sector)
  75. {
  76. Clustbuf *p, *oldest;
  77. chat("getclust0 @ %lld\n", (Wideoff)sector);
  78. /*
  79. * if we have it, just return it
  80. * otherwise, reuse the oldest unlocked entry
  81. */
  82. oldest = 0;
  83. for(p = bio; p < &bio[Nbio]; p++){
  84. if(sector == p->sector && dos == p->dos){
  85. if(p->flags & LOCKED)
  86. panic("getclust0 locked");
  87. chat("getclust0 %lld in cache\n", (Wideoff)sector);
  88. p->flags |= LOCKED;
  89. return p;
  90. }
  91. if(p->flags & LOCKED)
  92. continue;
  93. if(oldest == 0 || p->age <= oldest->age)
  94. oldest = p;
  95. }
  96. p = oldest;
  97. if(p == 0)
  98. panic("getclust0 all locked");
  99. p->flags |= LOCKED;
  100. if(p->flags & MOD)
  101. writeclust(p);
  102. /*
  103. * make sure the buffer is big enough
  104. */
  105. if(p->iobuf==0 || p->bufsize < dos->clustbytes){
  106. p->bufsize = dos->clustbytes;
  107. p->iobuf = ialloc(p->bufsize, 0);
  108. }
  109. if(sector >= dos->dataaddr)
  110. p->size = dos->clustbytes;
  111. else
  112. p->size = dos->sectbytes;
  113. p->dos = 0; /* make it invalid */
  114. return p;
  115. }
  116. /*
  117. * get an io block from an io buffer
  118. */
  119. static Clustbuf*
  120. getclust(Dos *dos, Off sector)
  121. {
  122. Clustbuf *p;
  123. Off addr;
  124. p = getclust0(dos, sector);
  125. if(p->dos){
  126. p->age = MACHP(0)->ticks;
  127. return p;
  128. }
  129. addr = (sector+dos->start)*dos->sectbytes;
  130. chat("getclust seek addr %lld\n", (Wideoff)addr);
  131. if((*dos->seek)(dos->dev, addr) < 0){
  132. chat("can't seek block\n");
  133. return 0;
  134. }
  135. chat("getclust read addr %lld\n", (Wideoff)addr);
  136. if((*dos->read)(dos->dev, p->iobuf, p->size) != p->size){
  137. chat("can't read block\n");
  138. return 0;
  139. }
  140. p->age = MACHP(0)->ticks;
  141. p->dos = dos;
  142. p->sector = sector;
  143. chat("getclust %lld read\n", (Wideoff)sector);
  144. return p;
  145. }
  146. /*
  147. * get an io block from an io buffer;
  148. * any current data is discarded.
  149. */
  150. static Clustbuf*
  151. getclustz(Dos *dos, Off sector)
  152. {
  153. Clustbuf *p;
  154. p = getclust0(dos, sector);
  155. p->age = MACHP(0)->ticks;
  156. p->dos = dos;
  157. p->sector = sector;
  158. memset(p->iobuf, 0, p->size);
  159. p->flags |= MOD;
  160. chat("getclustz %lld\n", (Wideoff)sector);
  161. return p;
  162. }
  163. /*
  164. * release an io buffer
  165. */
  166. static void
  167. putclust(Clustbuf *p)
  168. {
  169. if(!(p->flags & LOCKED))
  170. panic("putclust lock");
  171. if((p->flags & (MOD|IMMED)) == (MOD|IMMED))
  172. writeclust(p);
  173. p->flags &= ~LOCKED;
  174. chat("putclust @ sector %lld...", (Wideoff)p->sector);
  175. }
  176. /*
  177. * walk the fat one level ( n is a current cluster number ).
  178. * return the new cluster number or -1 if no more.
  179. */
  180. static long
  181. fatwalk(Dos *dos, int n)
  182. {
  183. ulong k, sect;
  184. Clustbuf *p;
  185. int o;
  186. chat("fatwalk %d\n", n);
  187. if(n < 2 || n >= dos->fatclusters)
  188. return -1;
  189. switch(dos->fatbits){
  190. case 12:
  191. k = (3*n)/2; break;
  192. case 16:
  193. k = 2*n; break;
  194. default:
  195. return -1;
  196. }
  197. if(k >= dos->fatbytes)
  198. panic("getfat");
  199. sect = k/dos->sectbytes + dos->fataddr;
  200. o = k%dos->sectbytes;
  201. p = getclust(dos, sect);
  202. k = p->iobuf[o++];
  203. if(o >= dos->sectbytes){
  204. putclust(p);
  205. p = getclust(dos, sect+1);
  206. o = 0;
  207. }
  208. k |= p->iobuf[o]<<8;
  209. putclust(p);
  210. if(dos->fatbits == 12){
  211. if(n&1)
  212. k >>= 4;
  213. else
  214. k &= 0xfff;
  215. if(k >= 0xff8)
  216. k |= 0xf000;
  217. }
  218. k = k < 0xfff8 ? k : -1;
  219. chat("fatwalk %d -> %lud\n", n, k);
  220. return k;
  221. }
  222. /*
  223. * write a value into each copy of the fat.
  224. */
  225. static void
  226. fatwrite(Dos *dos, int n, int val)
  227. {
  228. Off k, sect;
  229. Clustbuf *p;
  230. int i, o;
  231. chat("fatwrite %d %d...", n, val);
  232. if(n < 2 || n >= dos->fatclusters)
  233. panic("fatwrite n");
  234. switch(dos->fatbits){
  235. case 12:
  236. k = (3*n)/2; break;
  237. case 16:
  238. k = 2*n; break;
  239. default:
  240. panic("fatwrite fatbits");
  241. return;
  242. }
  243. if(k >= dos->fatbytes)
  244. panic("fatwrite k");
  245. for(i=0; i<dos->nfats; i++, k+=dos->fatbytes){
  246. sect = k/dos->sectbytes + dos->fataddr;
  247. o = k%dos->sectbytes;
  248. p = getclust(dos, sect);
  249. if(p == 0)
  250. panic("fatwrite getclust");
  251. switch(dos->fatbits){
  252. case 12:
  253. if(n&1){
  254. p->iobuf[o] &= 0x0f;
  255. p->iobuf[o++] |= val<<4;
  256. }else
  257. p->iobuf[o++] = val;
  258. if(o >= dos->sectbytes){
  259. p->flags |= MOD;
  260. putclust(p);
  261. p = getclust(dos, sect+1);
  262. if(p == 0)
  263. panic("fatwrite getclust");
  264. o = 0;
  265. }
  266. if(n&1)
  267. p->iobuf[o] = val>>4;
  268. else{
  269. p->iobuf[o] &= 0xf0;
  270. p->iobuf[o] |= (val>>8)&0x0f;
  271. }
  272. break;
  273. case 16:
  274. p->iobuf[o++] = val;
  275. p->iobuf[o] = val>>8;
  276. break;
  277. }
  278. p->flags |= MOD;
  279. putclust(p);
  280. }
  281. chat("OK\n");
  282. }
  283. /*
  284. * allocate a free cluster from the fat.
  285. */
  286. static int
  287. fatalloc(Dos *dos)
  288. {
  289. Clustbuf *p;
  290. int n;
  291. n = dos->freeptr;
  292. for(;;){
  293. if(fatwalk(dos, n) == 0)
  294. break;
  295. if(++n >= dos->fatclusters)
  296. n = 2;
  297. if(n == dos->freeptr)
  298. return -1;
  299. }
  300. dos->freeptr = n+1;
  301. if(dos->freeptr >= dos->fatclusters)
  302. dos->freeptr = 2;
  303. fatwrite(dos, n, 0xffff);
  304. p = getclustz(dos, dos->dataaddr + (n-2)*dos->clustsize);
  305. putclust(p);
  306. return n;
  307. }
  308. /*
  309. * map a file's logical sector address to a physical sector address
  310. */
  311. static long
  312. fileaddr(Dosfile *fp, Off ltarget, Clustbuf *pdir)
  313. {
  314. Dos *dos = fp->dos;
  315. Dosdir *dp;
  316. Off p;
  317. chat("fileaddr %8.8s %lld\n", fp->name, (Wideoff)ltarget);
  318. /*
  319. * root directory is contiguous and easy
  320. */
  321. if(fp->pdir == 0){
  322. if(ltarget*dos->sectbytes >= dos->rootsize*sizeof(Dosdir))
  323. return -1;
  324. p = dos->rootaddr + ltarget;
  325. chat("fileaddr %lld -> %lld\n", (Wideoff)ltarget, (Wideoff)p);
  326. return p;
  327. }
  328. if(fp->pstart == 0){ /* empty file */
  329. if(!pdir)
  330. return -1;
  331. p = fatalloc(dos);
  332. if(p <= 0)
  333. return -1;
  334. chat("fileaddr initial alloc %lld\n", (Wideoff)p);
  335. dp = (Dosdir *)(pdir->iobuf + fp->odir);
  336. puttime(dp);
  337. dp->start[0] = p;
  338. dp->start[1] = p>>8;
  339. pdir->flags |= MOD;
  340. fp->pstart = p;
  341. fp->pcurrent = p;
  342. fp->lcurrent = 0;
  343. }
  344. /*
  345. * anything else requires a walk through the fat
  346. * [lp]current will point to the last cluster if we run off the end
  347. */
  348. ltarget /= dos->clustsize;
  349. if(fp->pcurrent == 0 || fp->lcurrent > ltarget){
  350. /* go back to the beginning */
  351. fp->lcurrent = 0;
  352. fp->pcurrent = fp->pstart;
  353. }
  354. while(fp->lcurrent < ltarget){
  355. /* walk the fat */
  356. p = fatwalk(dos, fp->pcurrent);
  357. if(p < 0){
  358. if(!pdir)
  359. return -1;
  360. p = fatalloc(dos);
  361. if(p < 0){
  362. print("file system full\n");
  363. return -1;
  364. }
  365. fatwrite(dos, fp->pcurrent, p);
  366. }
  367. fp->pcurrent = p;
  368. ++fp->lcurrent;
  369. }
  370. /*
  371. * clusters start at 2 instead of 0 (why? - presotto)
  372. */
  373. p = dos->dataaddr + (fp->pcurrent-2)*dos->clustsize;
  374. chat("fileaddr %lld -> %lld\n", (Wideoff)ltarget, (Wideoff)p);
  375. return p;
  376. }
  377. /*
  378. * set up a dos file name
  379. */
  380. static void
  381. setname(char *name, char *ext, char *from)
  382. {
  383. char *to;
  384. memset(name, ' ', 8);
  385. memset(ext, ' ', 3);
  386. to = name;
  387. for(; *from && to-name < 8; from++, to++){
  388. if(*from == '.'){
  389. from++;
  390. break;
  391. }
  392. if(*from >= 'a' && *from <= 'z')
  393. *to = *from + 'A' - 'a';
  394. else
  395. *to = *from;
  396. }
  397. to = ext;
  398. for(; *from && to-ext < 3; from++, to++){
  399. if(*from >= 'a' && *from <= 'z')
  400. *to = *from + 'A' - 'a';
  401. else
  402. *to = *from;
  403. }
  404. chat("name is %8.8s %3.3s\n", name, ext);
  405. }
  406. /*
  407. * walk a directory returns
  408. * -1 if something went wrong
  409. * 0 if not found
  410. * 1 if found
  411. */
  412. static int
  413. doswalk(Dosfile *fp, char *name)
  414. {
  415. char dname[8], dext[3];
  416. Clustbuf *p;
  417. Dosdir *dp;
  418. Off o, addr;
  419. if((fp->attr & DOSDIR) == 0){
  420. chat("walking non-directory!\n");
  421. return -1;
  422. }
  423. setname(dname, dext, name);
  424. fp->offset = 0; /* start at the beginning */
  425. for(;;){
  426. addr = fileaddr(fp, fp->offset/fp->dos->sectbytes, 0);
  427. if(addr < 0)
  428. return 0;
  429. p = getclust(fp->dos, addr);
  430. if(p == 0)
  431. return -1;
  432. for(o=0; o<p->size; o += sizeof(Dosdir)){
  433. dp = (Dosdir *)(p->iobuf + o);
  434. chat("comparing to %8.8s.%3.3s\n", (char*)dp->name, (char*)dp->ext);
  435. if(memcmp(dname, dp->name, sizeof(dp->name)) != 0)
  436. continue;
  437. if(memcmp(dext, dp->ext, sizeof(dp->ext)) == 0)
  438. goto Found;
  439. }
  440. fp->offset += p->size;
  441. putclust(p);
  442. }
  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.lcurrent = 0;
  583. dos->root.pcurrent = 0;
  584. dos->root.offset = 0;
  585. syncclust();
  586. return 0;
  587. }
  588. static char *
  589. nextelem(char *path, char *elem)
  590. {
  591. int i;
  592. while(*path == '/')
  593. path++;
  594. if(*path==0 || *path==' ')
  595. return 0;
  596. for(i=0; *path && *path != '/' && *path != ' '; i++){
  597. if(i >= NAMELEN){
  598. print("name component too long\n");
  599. return 0;
  600. }
  601. *elem++ = *path++;
  602. }
  603. *elem = 0;
  604. return path;
  605. }
  606. static void
  607. puttime(Dosdir *d)
  608. {
  609. Timet secs;
  610. Rtc rtc;
  611. ushort x;
  612. secs = rtctime();
  613. sec2rtc(secs, &rtc);
  614. x = (rtc.hour<<11) | (rtc.min<<5) | (rtc.sec>>1);
  615. d->time[0] = x;
  616. d->time[1] = x>>8;
  617. x = ((rtc.year-80)<<9) | ((rtc.mon+1)<<5) | rtc.mday;
  618. d->date[0] = x;
  619. d->date[1] = x>>8;
  620. }
  621. Dosfile*
  622. dosopen(Dos *dos, char *path, Dosfile *fp)
  623. {
  624. char element[NAMELEN];
  625. *fp = dos->root;
  626. while(path = nextelem(path, element)){
  627. switch(doswalk(fp, element)){
  628. case -1:
  629. print("error walking to %s\n", element);
  630. return 0;
  631. case 0:
  632. print("%s not found\n", element);
  633. return 0;
  634. case 1:
  635. print("found %s attr 0x%ux start 0x%llux len %lld\n",
  636. element, fp->attr, (Wideoff)fp->pstart,
  637. (Wideoff)fp->length);
  638. break;
  639. }
  640. }
  641. syncclust();
  642. return fp;
  643. }
  644. /*
  645. * read from a dos file
  646. */
  647. long
  648. dosread(Dosfile *fp, void *a, long n)
  649. {
  650. Off addr, k, o;
  651. Clustbuf *p;
  652. uchar *to;
  653. if((fp->attr & DOSDIR) == 0){
  654. if(fp->offset >= fp->length)
  655. return 0;
  656. if(fp->offset+n > fp->length)
  657. n = fp->length - fp->offset;
  658. }
  659. to = a;
  660. while(n > 0){
  661. /*
  662. * read the data; sectors below dos->dataaddr
  663. * are read one at a time.
  664. */
  665. addr = fileaddr(fp, fp->offset/fp->dos->sectbytes, 0);
  666. if(addr < 0)
  667. return -1;
  668. p = getclust(fp->dos, addr);
  669. if(p == 0)
  670. return -1;
  671. /*
  672. * copy the bytes we need
  673. */
  674. o = fp->offset % p->size;
  675. k = p->size - o;
  676. if(k > n)
  677. k = n;
  678. memmove(to, p->iobuf+o, k);
  679. putclust(p);
  680. to += k;
  681. fp->offset += k;
  682. n -= k;
  683. }
  684. syncclust();
  685. return to - (uchar *)a;
  686. }
  687. /*
  688. * write to a dos file
  689. */
  690. long
  691. doswrite(Dosfile *fp, void *a, long n)
  692. {
  693. Off blksize, addr, k, o;
  694. Clustbuf *p, *pdir;
  695. Dosdir *dp;
  696. uchar *from;
  697. if(fp->attr & DOSDIR){
  698. print("write dir\n");
  699. return -1;
  700. }
  701. if(fp->pdir){
  702. pdir = getclust(fp->dos, fp->pdir);
  703. /*
  704. * should do consistency check if
  705. * concurrent access is possible.
  706. */
  707. if(pdir == 0)
  708. panic("doswrite");
  709. }else
  710. pdir = 0;
  711. blksize = pdir ? fp->dos->clustbytes : fp->dos->sectbytes;
  712. from = a;
  713. while(n > 0){
  714. addr = fileaddr(fp, fp->offset/fp->dos->sectbytes, pdir);
  715. if(addr < 0)
  716. return -1;
  717. o = fp->offset % blksize;
  718. if(o == 0 && n >= blksize)
  719. p = getclustz(fp->dos, addr);
  720. else
  721. p = getclust(fp->dos, addr);
  722. if(p == 0)
  723. return -1;
  724. /*
  725. * copy the bytes we need
  726. */
  727. k = p->size - o;
  728. if(k > n)
  729. k = n;
  730. memmove(p->iobuf+o, from, k);
  731. p->flags |= MOD;
  732. putclust(p);
  733. from += k;
  734. fp->offset += k;
  735. n -= k;
  736. }
  737. if(pdir){
  738. dp = (Dosdir *)(pdir->iobuf + fp->odir);
  739. puttime(dp);
  740. if(fp->offset > fp->length){
  741. fp->length = fp->offset;
  742. dp->length[0] = fp->length;
  743. dp->length[1] = fp->length>>8;
  744. dp->length[2] = fp->length>>16;
  745. dp->length[3] = fp->length>>24;
  746. }
  747. pdir->flags |= MOD;
  748. putclust(pdir);
  749. }
  750. syncclust();
  751. return from - (uchar *)a;
  752. }
  753. /*
  754. * truncate a dos file to zero length
  755. */
  756. int
  757. dostrunc(Dosfile *fp)
  758. {
  759. Clustbuf *pdir;
  760. Dosdir *dp;
  761. Off p, np;
  762. if(fp->attr & DOSDIR){
  763. print("trunc dir\n");
  764. return -1;
  765. }
  766. pdir = getclust(fp->dos, fp->pdir);
  767. if(pdir == 0)
  768. panic("dostrunc");
  769. p = fatwalk(fp->dos, fp->pstart);
  770. fatwrite(fp->dos, fp->pstart, 0xffff);
  771. while(p >= 0){
  772. np = fatwalk(fp->dos, p);
  773. fatwrite(fp->dos, p, 0);
  774. p = np;
  775. }
  776. fp->length = 0;
  777. dp = (Dosdir *)(pdir->iobuf + fp->odir);
  778. puttime(dp);
  779. dp->length[0] = 0;
  780. dp->length[1] = 0;
  781. dp->length[2] = 0;
  782. dp->length[3] = 0;
  783. pdir->flags |= MOD;
  784. putclust(pdir);
  785. syncclust();
  786. return 0;
  787. }