fat.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901
  1. /*
  2. * fat.c
  3. *
  4. * R/O (V)FAT 12/16/32 filesystem implementation by Marcus Sundberg
  5. *
  6. * 2002-07-28 - rjones@nexus-tech.net - ported to ppcboot v1.1.6
  7. * 2003-03-10 - kharris@nexus-tech.net - ported to uboot
  8. *
  9. * See file CREDITS for list of people who contributed to this
  10. * project.
  11. *
  12. * This program is free software; you can redistribute it and/or
  13. * modify it under the terms of the GNU General Public License as
  14. * published by the Free Software Foundation; either version 2 of
  15. * the License, or (at your option) any later version.
  16. *
  17. * This program is distributed in the hope that it will be useful,
  18. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. * GNU General Public License for more details.
  21. *
  22. * You should have received a copy of the GNU General Public License
  23. * along with this program; if not, write to the Free Software
  24. * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  25. * MA 02111-1307 USA
  26. */
  27. #include <common.h>
  28. #include <config.h>
  29. #include <fat.h>
  30. #include <asm/byteorder.h>
  31. #if (CONFIG_COMMANDS & CFG_CMD_FAT)
  32. /*
  33. * Convert a string to lowercase.
  34. */
  35. static void
  36. downcase(char *str)
  37. {
  38. while (*str != '\0') {
  39. TOLOWER(*str);
  40. str++;
  41. }
  42. }
  43. int (*dev_block_read)(int device, __u32 blknr, __u32 blkcnt, __u8 *buffer) = 0;
  44. int disk_read (__u32 startblock, __u32 getsize, __u8 * bufptr)
  45. {
  46. /* FIXME we need to determine the start block of the
  47. * partition where the DOS FS resides
  48. */
  49. startblock += 32;
  50. if (dev_block_read) {
  51. return dev_block_read (0, startblock, getsize, bufptr);
  52. }
  53. return -1;
  54. }
  55. int
  56. fat_register_read (int (*block_read)(int, __u32, __u32, __u8 *))
  57. {
  58. dev_block_read = block_read;
  59. return 0;
  60. }
  61. /*
  62. * Get the first occurence of a directory delimiter ('/' or '\') in a string.
  63. * Return index into string if found, -1 otherwise.
  64. */
  65. static int
  66. dirdelim(char *str)
  67. {
  68. char *start = str;
  69. while (*str != '\0') {
  70. if (ISDIRDELIM(*str)) return str - start;
  71. str++;
  72. }
  73. return -1;
  74. }
  75. /*
  76. * Match volume_info fs_type strings.
  77. * Return 0 on match, -1 otherwise.
  78. */
  79. static int
  80. compare_sign(char *str1, char *str2)
  81. {
  82. char *end = str1+SIGNLEN;
  83. while (str1 != end) {
  84. if (*str1 != *str2) {
  85. return -1;
  86. }
  87. str1++;
  88. str2++;
  89. }
  90. return 0;
  91. }
  92. /*
  93. * Extract zero terminated short name from a directory entry.
  94. */
  95. static void get_name (dir_entry *dirent, char *s_name)
  96. {
  97. char *ptr;
  98. memcpy (s_name, dirent->name, 8);
  99. s_name[8] = '\0';
  100. ptr = s_name;
  101. while (*ptr && *ptr != ' ')
  102. ptr++;
  103. if (dirent->ext[0] && dirent->ext[0] != ' ') {
  104. *ptr = '.';
  105. ptr++;
  106. memcpy (ptr, dirent->ext, 3);
  107. ptr[3] = '\0';
  108. while (*ptr && *ptr != ' ')
  109. ptr++;
  110. }
  111. *ptr = '\0';
  112. if (*s_name == DELETED_FLAG)
  113. *s_name = '\0';
  114. else if (*s_name == aRING)
  115. *s_name = 'å';
  116. downcase (s_name);
  117. }
  118. /*
  119. * Get the entry at index 'entry' in a FAT (12/16/32) table.
  120. * On failure 0x00 is returned.
  121. */
  122. static __u32
  123. get_fatent(fsdata *mydata, __u32 entry)
  124. {
  125. __u32 bufnum;
  126. __u32 offset;
  127. __u32 ret = 0x00;
  128. switch (mydata->fatsize) {
  129. case 32:
  130. bufnum = entry / FAT32BUFSIZE;
  131. offset = entry - bufnum * FAT32BUFSIZE;
  132. break;
  133. case 16:
  134. bufnum = entry / FAT16BUFSIZE;
  135. offset = entry - bufnum * FAT16BUFSIZE;
  136. break;
  137. case 12:
  138. bufnum = entry / FAT12BUFSIZE;
  139. offset = entry - bufnum * FAT12BUFSIZE;
  140. break;
  141. default:
  142. /* Unsupported FAT size */
  143. return ret;
  144. }
  145. /* Read a new block of FAT entries into the cache. */
  146. if (bufnum != mydata->fatbufnum) {
  147. int getsize = FATBUFSIZE/FS_BLOCK_SIZE;
  148. __u8 *bufptr = mydata->fatbuf;
  149. __u32 fatlength = mydata->fatlength;
  150. __u32 startblock = bufnum * FATBUFBLOCKS;
  151. fatlength *= SECTOR_SIZE; /* We want it in bytes now */
  152. startblock += mydata->fat_sect; /* Offset from start of disk */
  153. if (getsize > fatlength) getsize = fatlength;
  154. if (disk_read(startblock, getsize, bufptr) < 0) {
  155. FAT_DPRINT("Error reading FAT blocks\n");
  156. return ret;
  157. }
  158. mydata->fatbufnum = bufnum;
  159. }
  160. /* Get the actual entry from the table */
  161. switch (mydata->fatsize) {
  162. case 32:
  163. ret = FAT2CPU32(((__u32*)mydata->fatbuf)[offset]);
  164. break;
  165. case 16:
  166. ret = FAT2CPU16(((__u16*)mydata->fatbuf)[offset]);
  167. break;
  168. case 12: {
  169. __u32 off16 = (offset*3)/4;
  170. __u16 val1, val2;
  171. switch (offset & 0x3) {
  172. case 0:
  173. ret = FAT2CPU16(((__u16*)mydata->fatbuf)[off16]);
  174. ret &= 0xfff;
  175. break;
  176. case 1:
  177. val1 = FAT2CPU16(((__u16*)mydata->fatbuf)[off16]);
  178. val1 &= 0xf000;
  179. val2 = FAT2CPU16(((__u16*)mydata->fatbuf)[off16+1]);
  180. val2 &= 0x00ff;
  181. ret = (val2 << 4) | (val1 >> 12);
  182. break;
  183. case 2:
  184. val1 = FAT2CPU16(((__u16*)mydata->fatbuf)[off16]);
  185. val1 &= 0xff00;
  186. val2 = FAT2CPU16(((__u16*)mydata->fatbuf)[off16+1]);
  187. val2 &= 0x000f;
  188. ret = (val2 << 8) | (val1 >> 8);
  189. break;
  190. case 3:
  191. ret = FAT2CPU16(((__u16*)mydata->fatbuf)[off16]);;
  192. ret = (ret & 0xfff0) >> 4;
  193. break;
  194. default:
  195. break;
  196. }
  197. }
  198. break;
  199. }
  200. FAT_DPRINT("ret: %d, offset: %d\n", ret, offset);
  201. return ret;
  202. }
  203. /*
  204. * Read at most 'size' bytes from the specified cluster into 'buffer'.
  205. * Return 0 on success, -1 otherwise.
  206. */
  207. static int
  208. get_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer, unsigned long size)
  209. {
  210. int idx = 0;
  211. __u32 startsect;
  212. if (clustnum > 0) {
  213. startsect = mydata->data_begin + clustnum*mydata->clust_size;
  214. } else {
  215. startsect = mydata->rootdir_sect;
  216. }
  217. FAT_DPRINT("gc - clustnum: %d, startsect: %d\n", clustnum, startsect);
  218. while (size > 0) {
  219. if (size >= FS_BLOCK_SIZE) {
  220. if (disk_read(startsect + idx, 1, buffer) < 0) {
  221. FAT_DPRINT("Error reading data\n");
  222. return -1;
  223. }
  224. } else {
  225. __u8 tmpbuf[FS_BLOCK_SIZE];
  226. if (disk_read(startsect + idx, 1, tmpbuf) < 0) {
  227. FAT_DPRINT("Error reading data\n");
  228. return -1;
  229. }
  230. memcpy(buffer, tmpbuf, size);
  231. return 0;
  232. }
  233. buffer += FS_BLOCK_SIZE;
  234. size -= FS_BLOCK_SIZE;
  235. idx++;
  236. }
  237. return 0;
  238. }
  239. /*
  240. * Read at most 'maxsize' bytes from the file associated with 'dentptr'
  241. * into 'buffer'.
  242. * Return the number of bytes read or -1 on fatal errors.
  243. */
  244. static long
  245. get_contents(fsdata *mydata, dir_entry *dentptr, __u8 *buffer,
  246. unsigned long maxsize)
  247. {
  248. unsigned long filesize = FAT2CPU32(dentptr->size), gotsize = 0;
  249. unsigned int bytesperclust = mydata->clust_size * SECTOR_SIZE;
  250. __u32 curclust = START(dentptr);
  251. FAT_DPRINT("Filesize: %ld bytes\n", filesize);
  252. if (maxsize > 0 && filesize > maxsize) filesize = maxsize;
  253. FAT_DPRINT("Reading: %ld bytes\n", filesize);
  254. do {
  255. int getsize = (filesize > bytesperclust) ? bytesperclust :
  256. filesize;
  257. if (get_cluster(mydata, curclust, buffer, getsize) != 0) {
  258. FAT_ERROR("Error reading cluster\n");
  259. return -1;
  260. }
  261. gotsize += getsize;
  262. filesize -= getsize;
  263. if (filesize <= 0) return gotsize;
  264. buffer += getsize;
  265. curclust = get_fatent(mydata, curclust);
  266. if (curclust <= 0x0001 || curclust >= 0xfff0) {
  267. FAT_DPRINT("curclust: 0x%x\n", curclust);
  268. FAT_ERROR("Invalid FAT entry\n");
  269. return gotsize;
  270. }
  271. } while (1);
  272. }
  273. #ifdef CONFIG_SUPPORT_VFAT
  274. /*
  275. * Extract the file name information from 'slotptr' into 'l_name',
  276. * starting at l_name[*idx].
  277. * Return 1 if terminator (zero byte) is found, 0 otherwise.
  278. */
  279. static int
  280. slot2str(dir_slot *slotptr, char *l_name, int *idx)
  281. {
  282. int j;
  283. for (j = 0; j <= 8; j += 2) {
  284. l_name[*idx] = slotptr->name0_4[j];
  285. if (l_name[*idx] == 0x00) return 1;
  286. (*idx)++;
  287. }
  288. for (j = 0; j <= 10; j += 2) {
  289. l_name[*idx] = slotptr->name5_10[j];
  290. if (l_name[*idx] == 0x00) return 1;
  291. (*idx)++;
  292. }
  293. for (j = 0; j <= 2; j += 2) {
  294. l_name[*idx] = slotptr->name11_12[j];
  295. if (l_name[*idx] == 0x00) return 1;
  296. (*idx)++;
  297. }
  298. return 0;
  299. }
  300. /*
  301. * Extract the full long filename starting at 'retdent' (which is really
  302. * a slot) into 'l_name'. If successful also copy the real directory entry
  303. * into 'retdent'
  304. * Return 0 on success, -1 otherwise.
  305. */
  306. static int
  307. get_vfatname(fsdata *mydata, int curclust, __u8 *cluster,
  308. dir_entry *retdent, char *l_name)
  309. {
  310. dir_entry *realdent;
  311. dir_slot *slotptr = (dir_slot*) retdent;
  312. __u8 *nextclust = cluster + mydata->clust_size * SECTOR_SIZE;
  313. __u8 counter = slotptr->id & 0xf;
  314. int idx = 0;
  315. while ((__u8*)slotptr < nextclust) {
  316. if (counter == 0) break;
  317. if ((slotptr->id & 0x0f) != counter) return -1;
  318. slotptr++;
  319. counter--;
  320. }
  321. if ((__u8*)slotptr >= nextclust) {
  322. __u8 block[MAX_CLUSTSIZE];
  323. dir_slot *slotptr2;
  324. slotptr--;
  325. curclust = get_fatent(mydata, curclust);
  326. if (curclust <= 0x0001 || curclust >= 0xfff0) {
  327. FAT_DPRINT("curclust: 0x%x\n", curclust);
  328. FAT_ERROR("Invalid FAT entry\n");
  329. return -1;
  330. }
  331. if (get_cluster(mydata, curclust, block,
  332. mydata->clust_size * SECTOR_SIZE) != 0) {
  333. FAT_DPRINT("Error: reading directory block\n");
  334. return -1;
  335. }
  336. slotptr2 = (dir_slot*) block;
  337. while (slotptr2->id > 0x01) {
  338. slotptr2++;
  339. }
  340. /* Save the real directory entry */
  341. realdent = (dir_entry*)slotptr2 + 1;
  342. while ((__u8*)slotptr2 >= block) {
  343. slot2str(slotptr2, l_name, &idx);
  344. slotptr2--;
  345. }
  346. } else {
  347. /* Save the real directory entry */
  348. realdent = (dir_entry*)slotptr;
  349. }
  350. do {
  351. slotptr--;
  352. if (slot2str(slotptr, l_name, &idx)) break;
  353. } while (!(slotptr->id & 0x40));
  354. l_name[idx] = '\0';
  355. if (*l_name == DELETED_FLAG) *l_name = '\0';
  356. else if (*l_name == aRING) *l_name = 'å';
  357. downcase(l_name);
  358. /* Return the real directory entry */
  359. memcpy(retdent, realdent, sizeof(dir_entry));
  360. return 0;
  361. }
  362. /* Calculate short name checksum */
  363. static __u8
  364. mkcksum(const char *str)
  365. {
  366. int i;
  367. __u8 ret = 0;
  368. for (i = 0; i < 11; i++) {
  369. ret = (((ret&1)<<7)|((ret&0xfe)>>1)) + str[i];
  370. }
  371. return ret;
  372. }
  373. #endif
  374. /*
  375. * Get the directory entry associated with 'filename' from the directory
  376. * starting at 'startsect'
  377. */
  378. static dir_entry *get_dentfromdir (fsdata * mydata, int startsect,
  379. char *filename, dir_entry * retdent,
  380. int dols)
  381. {
  382. __u16 prevcksum = 0xffff;
  383. __u8 block[MAX_CLUSTSIZE];
  384. __u32 curclust = START (retdent);
  385. int files = 0, dirs = 0;
  386. FAT_DPRINT ("get_dentfromdir: %s\n", filename);
  387. while (1) {
  388. dir_entry *dentptr;
  389. int i;
  390. if (get_cluster (mydata, curclust, block,
  391. mydata->clust_size * SECTOR_SIZE) != 0) {
  392. FAT_DPRINT ("Error: reading directory block\n");
  393. return NULL;
  394. }
  395. dentptr = (dir_entry *) block;
  396. for (i = 0; i < DIRENTSPERCLUST; i++) {
  397. char s_name[14], l_name[256];
  398. l_name[0] = '\0';
  399. if ((dentptr->attr & ATTR_VOLUME)) {
  400. #ifdef CONFIG_SUPPORT_VFAT
  401. if ((dentptr->attr & ATTR_VFAT) &&
  402. (dentptr->name[0] & 0x40)) {
  403. prevcksum = ((dir_slot *) dentptr)
  404. ->alias_checksum;
  405. get_vfatname (mydata, curclust, block,
  406. dentptr, l_name);
  407. if (dols) {
  408. int isdir = (dentptr->attr & ATTR_DIR);
  409. char dirc;
  410. int doit = 0;
  411. if (isdir) {
  412. dirs++;
  413. dirc = '/';
  414. doit = 1;
  415. } else {
  416. dirc = ' ';
  417. if (l_name[0] != 0) {
  418. files++;
  419. doit = 1;
  420. }
  421. }
  422. if (doit) {
  423. if (dirc == ' ') {
  424. printf (" %8ld %s%c\n",
  425. (long) FAT2CPU32 (dentptr->size),
  426. l_name, dirc);
  427. } else {
  428. printf (" %s%c\n", l_name, dirc);
  429. }
  430. }
  431. dentptr++;
  432. continue;
  433. }
  434. FAT_DPRINT ("vfatname: |%s|\n", l_name);
  435. } else
  436. #endif
  437. {
  438. /* Volume label or VFAT entry */
  439. dentptr++;
  440. continue;
  441. }
  442. }
  443. if (dentptr->name[0] == 0) {
  444. if (dols) {
  445. printf ("\n%d file(s), %d dir(s)\n\n", files, dirs);
  446. }
  447. FAT_DPRINT ("Dentname == NULL - %d\n", i);
  448. return NULL;
  449. }
  450. #ifdef CONFIG_SUPPORT_VFAT
  451. if (dols && mkcksum (dentptr->name) == prevcksum) {
  452. dentptr++;
  453. continue;
  454. }
  455. #endif
  456. get_name (dentptr, s_name);
  457. if (dols) {
  458. int isdir = (dentptr->attr & ATTR_DIR);
  459. char dirc;
  460. int doit = 0;
  461. if (isdir) {
  462. dirs++;
  463. dirc = '/';
  464. doit = 1;
  465. } else {
  466. dirc = ' ';
  467. if (s_name[0] != 0) {
  468. files++;
  469. doit = 1;
  470. }
  471. }
  472. if (doit) {
  473. if (dirc == ' ') {
  474. printf (" %8ld %s%c\n",
  475. (long) FAT2CPU32 (dentptr->size), s_name,
  476. dirc);
  477. } else {
  478. printf (" %s%c\n", s_name, dirc);
  479. }
  480. }
  481. dentptr++;
  482. continue;
  483. }
  484. if (strcmp (filename, s_name) && strcmp (filename, l_name)) {
  485. FAT_DPRINT ("Mismatch: |%s|%s|\n", s_name, l_name);
  486. dentptr++;
  487. continue;
  488. }
  489. memcpy (retdent, dentptr, sizeof (dir_entry));
  490. FAT_DPRINT ("DentName: %s", s_name);
  491. FAT_DPRINT (", start: 0x%x", START (dentptr));
  492. FAT_DPRINT (", size: 0x%x %s\n",
  493. FAT2CPU32 (dentptr->size),
  494. (dentptr->attr & ATTR_DIR) ? "(DIR)" : "");
  495. return retdent;
  496. }
  497. curclust = get_fatent (mydata, curclust);
  498. if (curclust <= 0x0001 || curclust >= 0xfff0) {
  499. FAT_DPRINT ("curclust: 0x%x\n", curclust);
  500. FAT_ERROR ("Invalid FAT entry\n");
  501. return NULL;
  502. }
  503. }
  504. return NULL;
  505. }
  506. /*
  507. * Read boot sector and volume info from a FAT filesystem
  508. */
  509. static int
  510. read_bootsectandvi(boot_sector *bs, volume_info *volinfo, int *fatsize)
  511. {
  512. __u8 block[FS_BLOCK_SIZE];
  513. volume_info *vistart;
  514. if (disk_read(0, 1, block) < 0) {
  515. FAT_DPRINT("Error: reading block\n");
  516. return -1;
  517. }
  518. memcpy(bs, block, sizeof(boot_sector));
  519. bs->reserved = FAT2CPU16(bs->reserved);
  520. bs->fat_length = FAT2CPU16(bs->fat_length);
  521. bs->secs_track = FAT2CPU16(bs->secs_track);
  522. bs->heads = FAT2CPU16(bs->heads);
  523. #if 0 /* UNUSED */
  524. bs->hidden = FAT2CPU32(bs->hidden);
  525. #endif
  526. bs->total_sect = FAT2CPU32(bs->total_sect);
  527. /* FAT32 entries */
  528. if (bs->fat_length == 0) {
  529. /* Assume FAT32 */
  530. bs->fat32_length = FAT2CPU32(bs->fat32_length);
  531. bs->flags = FAT2CPU16(bs->flags);
  532. bs->root_cluster = FAT2CPU32(bs->root_cluster);
  533. bs->info_sector = FAT2CPU16(bs->info_sector);
  534. bs->backup_boot = FAT2CPU16(bs->backup_boot);
  535. vistart = (volume_info*) (block + sizeof(boot_sector));
  536. *fatsize = 32;
  537. } else {
  538. vistart = (volume_info*) &(bs->fat32_length);
  539. *fatsize = 0;
  540. }
  541. memcpy(volinfo, vistart, sizeof(volume_info));
  542. /* Terminate fs_type string. Writing past the end of vistart
  543. is ok - it's just the buffer. */
  544. vistart->fs_type[8] = '\0';
  545. if (*fatsize == 32) {
  546. if (compare_sign(FAT32_SIGN, vistart->fs_type) == 0) {
  547. return 0;
  548. }
  549. } else {
  550. if (compare_sign(FAT12_SIGN, vistart->fs_type) == 0) {
  551. *fatsize = 12;
  552. return 0;
  553. }
  554. if (compare_sign(FAT16_SIGN, vistart->fs_type) == 0) {
  555. *fatsize = 16;
  556. return 0;
  557. }
  558. }
  559. FAT_DPRINT("Error: broken fs_type sign\n");
  560. return -1;
  561. }
  562. static long
  563. do_fat_read (const char *filename, void *buffer, unsigned long maxsize,
  564. int dols)
  565. {
  566. __u8 block[FS_BLOCK_SIZE]; /* Block buffer */
  567. char fnamecopy[2048];
  568. boot_sector bs;
  569. volume_info volinfo;
  570. fsdata datablock;
  571. fsdata *mydata = &datablock;
  572. dir_entry *dentptr;
  573. __u16 prevcksum = 0xffff;
  574. char *subname = "";
  575. int rootdir_size, cursect;
  576. int idx, isdir = 0;
  577. int files = 0, dirs = 0;
  578. long ret = 0;
  579. int firsttime;
  580. if (read_bootsectandvi (&bs, &volinfo, &mydata->fatsize)) {
  581. FAT_DPRINT ("Error: reading boot sector\n");
  582. return -1;
  583. }
  584. if (mydata->fatsize == 32) {
  585. mydata->fatlength = bs.fat32_length;
  586. } else {
  587. mydata->fatlength = bs.fat_length;
  588. }
  589. mydata->fat_sect = bs.reserved;
  590. cursect = mydata->rootdir_sect
  591. = mydata->fat_sect + mydata->fatlength * bs.fats;
  592. mydata->clust_size = bs.cluster_size;
  593. if (mydata->fatsize == 32) {
  594. rootdir_size = mydata->clust_size;
  595. mydata->data_begin = mydata->rootdir_sect /* + rootdir_size */
  596. - (mydata->clust_size * 2);
  597. } else {
  598. rootdir_size = ((bs.dir_entries[1] * (int) 256 + bs.dir_entries[0])
  599. * sizeof (dir_entry)) / SECTOR_SIZE;
  600. mydata->data_begin = mydata->rootdir_sect + rootdir_size
  601. - (mydata->clust_size * 2);
  602. }
  603. mydata->fatbufnum = -1;
  604. FAT_DPRINT ("FAT%d, fatlength: %d\n", mydata->fatsize,
  605. mydata->fatlength);
  606. FAT_DPRINT ("Rootdir begins at sector: %d, offset: %x, size: %d\n"
  607. "Data begins at: %d\n",
  608. mydata->rootdir_sect, mydata->rootdir_sect * SECTOR_SIZE,
  609. rootdir_size, mydata->data_begin);
  610. FAT_DPRINT ("Cluster size: %d\n", mydata->clust_size);
  611. /* "cwd" is always the root... */
  612. while (ISDIRDELIM (*filename))
  613. filename++;
  614. /* Make a copy of the filename and convert it to lowercase */
  615. strcpy (fnamecopy, filename);
  616. downcase (fnamecopy);
  617. if (*fnamecopy == '\0') {
  618. if (!dols)
  619. return -1;
  620. dols = LS_ROOT;
  621. } else if ((idx = dirdelim (fnamecopy)) >= 0) {
  622. isdir = 1;
  623. fnamecopy[idx] = '\0';
  624. subname = fnamecopy + idx + 1;
  625. /* Handle multiple delimiters */
  626. while (ISDIRDELIM (*subname))
  627. subname++;
  628. } else if (dols) {
  629. isdir = 1;
  630. }
  631. while (1) {
  632. int i;
  633. if (disk_read (cursect, 1, block) < 0) {
  634. FAT_DPRINT ("Error: reading rootdir block\n");
  635. return -1;
  636. }
  637. dentptr = (dir_entry *) block;
  638. for (i = 0; i < DIRENTSPERBLOCK; i++) {
  639. char s_name[14], l_name[256];
  640. l_name[0] = '\0';
  641. if ((dentptr->attr & ATTR_VOLUME)) {
  642. #ifdef CONFIG_SUPPORT_VFAT
  643. if ((dentptr->attr & ATTR_VFAT) &&
  644. (dentptr->name[0] & 0x40)) {
  645. prevcksum = ((dir_slot *) dentptr)->alias_checksum;
  646. get_vfatname (mydata, 0, block, dentptr, l_name);
  647. if (dols == LS_ROOT) {
  648. int isdir = (dentptr->attr & ATTR_DIR);
  649. char dirc;
  650. int doit = 0;
  651. if (isdir) {
  652. dirs++;
  653. dirc = '/';
  654. doit = 1;
  655. } else {
  656. dirc = ' ';
  657. if (l_name[0] != 0) {
  658. files++;
  659. doit = 1;
  660. }
  661. }
  662. if (doit) {
  663. if (dirc == ' ') {
  664. printf (" %8ld %s%c\n",
  665. (long) FAT2CPU32 (dentptr->size),
  666. l_name, dirc);
  667. } else {
  668. printf (" %s%c\n", l_name, dirc);
  669. }
  670. }
  671. dentptr++;
  672. continue;
  673. }
  674. FAT_DPRINT ("Rootvfatname: |%s|\n", l_name);
  675. } else
  676. #endif
  677. {
  678. /* Volume label or VFAT entry */
  679. dentptr++;
  680. continue;
  681. }
  682. } else if (dentptr->name[0] == 0) {
  683. FAT_DPRINT ("RootDentname == NULL - %d\n", i);
  684. if (dols == LS_ROOT) {
  685. printf ("\n%d file(s), %d dir(s)\n\n", files, dirs);
  686. return 0;
  687. }
  688. return -1;
  689. }
  690. #ifdef CONFIG_SUPPORT_VFAT
  691. else if (dols == LS_ROOT
  692. && mkcksum (dentptr->name) == prevcksum) {
  693. dentptr++;
  694. continue;
  695. }
  696. #endif
  697. get_name (dentptr, s_name);
  698. if (dols == LS_ROOT) {
  699. int isdir = (dentptr->attr & ATTR_DIR);
  700. char dirc;
  701. int doit = 0;
  702. if (isdir) {
  703. dirs++;
  704. dirc = '/';
  705. doit = 1;
  706. } else {
  707. dirc = ' ';
  708. if (s_name[0] != 0) {
  709. files++;
  710. doit = 1;
  711. }
  712. }
  713. if (doit) {
  714. if (dirc == ' ') {
  715. printf (" %8ld %s%c\n",
  716. (long) FAT2CPU32 (dentptr->size), s_name,
  717. dirc);
  718. } else {
  719. printf (" %s%c\n", s_name, dirc);
  720. }
  721. }
  722. dentptr++;
  723. continue;
  724. }
  725. if (strcmp (fnamecopy, s_name) && strcmp (fnamecopy, l_name)) {
  726. FAT_DPRINT ("RootMismatch: |%s|%s|\n", s_name, l_name);
  727. dentptr++;
  728. continue;
  729. }
  730. if (isdir && !(dentptr->attr & ATTR_DIR))
  731. return -1;
  732. FAT_DPRINT ("RootName: %s", s_name);
  733. FAT_DPRINT (", start: 0x%x", START (dentptr));
  734. FAT_DPRINT (", size: 0x%x %s\n",
  735. FAT2CPU32 (dentptr->size), isdir ? "(DIR)" : "");
  736. goto rootdir_done; /* We got a match */
  737. }
  738. cursect++;
  739. }
  740. rootdir_done:
  741. firsttime = 1;
  742. while (isdir) {
  743. int startsect = mydata->data_begin
  744. + START (dentptr) * mydata->clust_size;
  745. dir_entry dent;
  746. char *nextname = NULL;
  747. dent = *dentptr;
  748. dentptr = &dent;
  749. idx = dirdelim (subname);
  750. if (idx >= 0) {
  751. subname[idx] = '\0';
  752. nextname = subname + idx + 1;
  753. /* Handle multiple delimiters */
  754. while (ISDIRDELIM (*nextname))
  755. nextname++;
  756. if (dols && *nextname == '\0')
  757. firsttime = 0;
  758. } else {
  759. if (dols && firsttime) {
  760. firsttime = 0;
  761. } else {
  762. isdir = 0;
  763. }
  764. }
  765. if (get_dentfromdir (mydata, startsect, subname, dentptr,
  766. isdir ? 0 : dols) == NULL) {
  767. if (dols && !isdir)
  768. return 0;
  769. return -1;
  770. }
  771. if (idx >= 0) {
  772. if (!(dentptr->attr & ATTR_DIR))
  773. return -1;
  774. subname = nextname;
  775. }
  776. }
  777. ret = get_contents (mydata, dentptr, buffer, maxsize);
  778. FAT_DPRINT ("Size: %d, got: %ld\n", FAT2CPU32 (dentptr->size), ret);
  779. return ret;
  780. }
  781. int
  782. file_fat_detectfs(void)
  783. {
  784. boot_sector bs;
  785. volume_info volinfo;
  786. int fatsize;
  787. return read_bootsectandvi(&bs, &volinfo, &fatsize);
  788. }
  789. int
  790. file_fat_ls(const char *dir)
  791. {
  792. return do_fat_read(dir, NULL, 0, LS_YES);
  793. }
  794. long
  795. file_fat_read(const char *filename, void *buffer, unsigned long maxsize)
  796. {
  797. return do_fat_read(filename, buffer, maxsize, LS_NO);
  798. }
  799. #endif /* #if (CONFIG_COMMANDS & CFG_CMD_FAT) */