fat.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191
  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 <exports.h>
  30. #include <fat.h>
  31. #include <asm/byteorder.h>
  32. #include <part.h>
  33. #include <malloc.h>
  34. #include <linux/compiler.h>
  35. /*
  36. * Convert a string to lowercase.
  37. */
  38. static void downcase (char *str)
  39. {
  40. while (*str != '\0') {
  41. TOLOWER(*str);
  42. str++;
  43. }
  44. }
  45. static block_dev_desc_t *cur_dev;
  46. static unsigned int cur_part_nr;
  47. static disk_partition_t cur_part_info;
  48. #define DOS_BOOT_MAGIC_OFFSET 0x1fe
  49. #define DOS_FS_TYPE_OFFSET 0x36
  50. #define DOS_FS32_TYPE_OFFSET 0x52
  51. static int disk_read(__u32 block, __u32 nr_blocks, void *buf)
  52. {
  53. if (!cur_dev || !cur_dev->block_read)
  54. return -1;
  55. return cur_dev->block_read(cur_dev->dev,
  56. cur_part_info.start + block, nr_blocks, buf);
  57. }
  58. int fat_register_device (block_dev_desc_t * dev_desc, int part_no)
  59. {
  60. ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, dev_desc->blksz);
  61. /* First close any currently found FAT filesystem */
  62. cur_dev = NULL;
  63. #if (defined(CONFIG_CMD_IDE) || \
  64. defined(CONFIG_CMD_MG_DISK) || \
  65. defined(CONFIG_CMD_SATA) || \
  66. defined(CONFIG_CMD_SCSI) || \
  67. defined(CONFIG_CMD_USB) || \
  68. defined(CONFIG_MMC) || \
  69. defined(CONFIG_SYSTEMACE) )
  70. /* Read the partition table, if present */
  71. if (!get_partition_info(dev_desc, part_no, &cur_part_info)) {
  72. cur_dev = dev_desc;
  73. cur_part_nr = part_no;
  74. }
  75. #endif
  76. /* Otherwise it might be a superfloppy (whole-disk FAT filesystem) */
  77. if (!cur_dev) {
  78. if (part_no != 1) {
  79. printf("** Partition %d not valid on device %d **\n",
  80. part_no, dev_desc->dev);
  81. return -1;
  82. }
  83. cur_dev = dev_desc;
  84. cur_part_nr = 1;
  85. cur_part_info.start = 0;
  86. cur_part_info.size = dev_desc->lba;
  87. cur_part_info.blksz = dev_desc->blksz;
  88. memset(cur_part_info.name, 0, sizeof(cur_part_info.name));
  89. memset(cur_part_info.type, 0, sizeof(cur_part_info.type));
  90. }
  91. /* Make sure it has a valid FAT header */
  92. if (disk_read(0, 1, buffer) != 1) {
  93. cur_dev = NULL;
  94. return -1;
  95. }
  96. /* Check if it's actually a DOS volume */
  97. if (memcmp(buffer + DOS_BOOT_MAGIC_OFFSET, "\x55\xAA", 2)) {
  98. cur_dev = NULL;
  99. return -1;
  100. }
  101. /* Check for FAT12/FAT16/FAT32 filesystem */
  102. if (!memcmp(buffer + DOS_FS_TYPE_OFFSET, "FAT", 3))
  103. return 0;
  104. if (!memcmp(buffer + DOS_FS32_TYPE_OFFSET, "FAT32", 5))
  105. return 0;
  106. cur_dev = NULL;
  107. return -1;
  108. }
  109. /*
  110. * Get the first occurence of a directory delimiter ('/' or '\') in a string.
  111. * Return index into string if found, -1 otherwise.
  112. */
  113. static int dirdelim (char *str)
  114. {
  115. char *start = str;
  116. while (*str != '\0') {
  117. if (ISDIRDELIM(*str))
  118. return str - start;
  119. str++;
  120. }
  121. return -1;
  122. }
  123. /*
  124. * Extract zero terminated short name from a directory entry.
  125. */
  126. static void get_name (dir_entry *dirent, char *s_name)
  127. {
  128. char *ptr;
  129. memcpy(s_name, dirent->name, 8);
  130. s_name[8] = '\0';
  131. ptr = s_name;
  132. while (*ptr && *ptr != ' ')
  133. ptr++;
  134. if (dirent->ext[0] && dirent->ext[0] != ' ') {
  135. *ptr = '.';
  136. ptr++;
  137. memcpy(ptr, dirent->ext, 3);
  138. ptr[3] = '\0';
  139. while (*ptr && *ptr != ' ')
  140. ptr++;
  141. }
  142. *ptr = '\0';
  143. if (*s_name == DELETED_FLAG)
  144. *s_name = '\0';
  145. else if (*s_name == aRING)
  146. *s_name = DELETED_FLAG;
  147. downcase(s_name);
  148. }
  149. /*
  150. * Get the entry at index 'entry' in a FAT (12/16/32) table.
  151. * On failure 0x00 is returned.
  152. */
  153. static __u32 get_fatent (fsdata *mydata, __u32 entry)
  154. {
  155. __u32 bufnum;
  156. __u32 off16, offset;
  157. __u32 ret = 0x00;
  158. __u16 val1, val2;
  159. switch (mydata->fatsize) {
  160. case 32:
  161. bufnum = entry / FAT32BUFSIZE;
  162. offset = entry - bufnum * FAT32BUFSIZE;
  163. break;
  164. case 16:
  165. bufnum = entry / FAT16BUFSIZE;
  166. offset = entry - bufnum * FAT16BUFSIZE;
  167. break;
  168. case 12:
  169. bufnum = entry / FAT12BUFSIZE;
  170. offset = entry - bufnum * FAT12BUFSIZE;
  171. break;
  172. default:
  173. /* Unsupported FAT size */
  174. return ret;
  175. }
  176. debug("FAT%d: entry: 0x%04x = %d, offset: 0x%04x = %d\n",
  177. mydata->fatsize, entry, entry, offset, offset);
  178. /* Read a new block of FAT entries into the cache. */
  179. if (bufnum != mydata->fatbufnum) {
  180. __u32 getsize = FATBUFBLOCKS;
  181. __u8 *bufptr = mydata->fatbuf;
  182. __u32 fatlength = mydata->fatlength;
  183. __u32 startblock = bufnum * FATBUFBLOCKS;
  184. if (getsize > fatlength)
  185. getsize = fatlength;
  186. fatlength *= mydata->sect_size; /* We want it in bytes now */
  187. startblock += mydata->fat_sect; /* Offset from start of disk */
  188. if (disk_read(startblock, getsize, bufptr) < 0) {
  189. debug("Error reading FAT blocks\n");
  190. return ret;
  191. }
  192. mydata->fatbufnum = bufnum;
  193. }
  194. /* Get the actual entry from the table */
  195. switch (mydata->fatsize) {
  196. case 32:
  197. ret = FAT2CPU32(((__u32 *) mydata->fatbuf)[offset]);
  198. break;
  199. case 16:
  200. ret = FAT2CPU16(((__u16 *) mydata->fatbuf)[offset]);
  201. break;
  202. case 12:
  203. off16 = (offset * 3) / 4;
  204. switch (offset & 0x3) {
  205. case 0:
  206. ret = FAT2CPU16(((__u16 *) mydata->fatbuf)[off16]);
  207. ret &= 0xfff;
  208. break;
  209. case 1:
  210. val1 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16]);
  211. val1 &= 0xf000;
  212. val2 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16 + 1]);
  213. val2 &= 0x00ff;
  214. ret = (val2 << 4) | (val1 >> 12);
  215. break;
  216. case 2:
  217. val1 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16]);
  218. val1 &= 0xff00;
  219. val2 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16 + 1]);
  220. val2 &= 0x000f;
  221. ret = (val2 << 8) | (val1 >> 8);
  222. break;
  223. case 3:
  224. ret = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16]);
  225. ret = (ret & 0xfff0) >> 4;
  226. break;
  227. default:
  228. break;
  229. }
  230. break;
  231. }
  232. debug("FAT%d: ret: %08x, offset: %04x\n",
  233. mydata->fatsize, ret, offset);
  234. return ret;
  235. }
  236. /*
  237. * Read at most 'size' bytes from the specified cluster into 'buffer'.
  238. * Return 0 on success, -1 otherwise.
  239. */
  240. static int
  241. get_cluster (fsdata *mydata, __u32 clustnum, __u8 *buffer,
  242. unsigned long size)
  243. {
  244. __u32 idx = 0;
  245. __u32 startsect;
  246. __u32 nr_sect;
  247. int ret;
  248. if (clustnum > 0) {
  249. startsect = mydata->data_begin +
  250. clustnum * mydata->clust_size;
  251. } else {
  252. startsect = mydata->rootdir_sect;
  253. }
  254. debug("gc - clustnum: %d, startsect: %d\n", clustnum, startsect);
  255. nr_sect = size / mydata->sect_size;
  256. ret = disk_read(startsect, nr_sect, buffer);
  257. if (ret != nr_sect) {
  258. debug("Error reading data (got %d)\n", ret);
  259. return -1;
  260. }
  261. if (size % mydata->sect_size) {
  262. ALLOC_CACHE_ALIGN_BUFFER(__u8, tmpbuf, mydata->sect_size);
  263. idx = size / mydata->sect_size;
  264. ret = disk_read(startsect + idx, 1, tmpbuf);
  265. if (ret != 1) {
  266. debug("Error reading data (got %d)\n", ret);
  267. return -1;
  268. }
  269. buffer += idx * mydata->sect_size;
  270. memcpy(buffer, tmpbuf, size % mydata->sect_size);
  271. return 0;
  272. }
  273. return 0;
  274. }
  275. /*
  276. * Read at most 'maxsize' bytes from the file associated with 'dentptr'
  277. * into 'buffer'.
  278. * Return the number of bytes read or -1 on fatal errors.
  279. */
  280. static long
  281. get_contents (fsdata *mydata, dir_entry *dentptr, __u8 *buffer,
  282. unsigned long maxsize)
  283. {
  284. unsigned long filesize = FAT2CPU32(dentptr->size), gotsize = 0;
  285. unsigned int bytesperclust = mydata->clust_size * mydata->sect_size;
  286. __u32 curclust = START(dentptr);
  287. __u32 endclust, newclust;
  288. unsigned long actsize;
  289. debug("Filesize: %ld bytes\n", filesize);
  290. if (maxsize > 0 && filesize > maxsize)
  291. filesize = maxsize;
  292. debug("%ld bytes\n", filesize);
  293. actsize = bytesperclust;
  294. endclust = curclust;
  295. do {
  296. /* search for consecutive clusters */
  297. while (actsize < filesize) {
  298. newclust = get_fatent(mydata, endclust);
  299. if ((newclust - 1) != endclust)
  300. goto getit;
  301. if (CHECK_CLUST(newclust, mydata->fatsize)) {
  302. debug("curclust: 0x%x\n", newclust);
  303. debug("Invalid FAT entry\n");
  304. return gotsize;
  305. }
  306. endclust = newclust;
  307. actsize += bytesperclust;
  308. }
  309. /* actsize >= file size */
  310. actsize -= bytesperclust;
  311. /* get remaining clusters */
  312. if (get_cluster(mydata, curclust, buffer, (int)actsize) != 0) {
  313. printf("Error reading cluster\n");
  314. return -1;
  315. }
  316. /* get remaining bytes */
  317. gotsize += (int)actsize;
  318. filesize -= actsize;
  319. buffer += actsize;
  320. actsize = filesize;
  321. if (get_cluster(mydata, endclust, buffer, (int)actsize) != 0) {
  322. printf("Error reading cluster\n");
  323. return -1;
  324. }
  325. gotsize += actsize;
  326. return gotsize;
  327. getit:
  328. if (get_cluster(mydata, curclust, buffer, (int)actsize) != 0) {
  329. printf("Error reading cluster\n");
  330. return -1;
  331. }
  332. gotsize += (int)actsize;
  333. filesize -= actsize;
  334. buffer += actsize;
  335. curclust = get_fatent(mydata, endclust);
  336. if (CHECK_CLUST(curclust, mydata->fatsize)) {
  337. debug("curclust: 0x%x\n", curclust);
  338. printf("Invalid FAT entry\n");
  339. return gotsize;
  340. }
  341. actsize = bytesperclust;
  342. endclust = curclust;
  343. } while (1);
  344. }
  345. #ifdef CONFIG_SUPPORT_VFAT
  346. /*
  347. * Extract the file name information from 'slotptr' into 'l_name',
  348. * starting at l_name[*idx].
  349. * Return 1 if terminator (zero byte) is found, 0 otherwise.
  350. */
  351. static int slot2str (dir_slot *slotptr, char *l_name, int *idx)
  352. {
  353. int j;
  354. for (j = 0; j <= 8; j += 2) {
  355. l_name[*idx] = slotptr->name0_4[j];
  356. if (l_name[*idx] == 0x00)
  357. return 1;
  358. (*idx)++;
  359. }
  360. for (j = 0; j <= 10; j += 2) {
  361. l_name[*idx] = slotptr->name5_10[j];
  362. if (l_name[*idx] == 0x00)
  363. return 1;
  364. (*idx)++;
  365. }
  366. for (j = 0; j <= 2; j += 2) {
  367. l_name[*idx] = slotptr->name11_12[j];
  368. if (l_name[*idx] == 0x00)
  369. return 1;
  370. (*idx)++;
  371. }
  372. return 0;
  373. }
  374. /*
  375. * Extract the full long filename starting at 'retdent' (which is really
  376. * a slot) into 'l_name'. If successful also copy the real directory entry
  377. * into 'retdent'
  378. * Return 0 on success, -1 otherwise.
  379. */
  380. __u8 get_vfatname_block[MAX_CLUSTSIZE]
  381. __aligned(ARCH_DMA_MINALIGN);
  382. static int
  383. get_vfatname (fsdata *mydata, int curclust, __u8 *cluster,
  384. dir_entry *retdent, char *l_name)
  385. {
  386. dir_entry *realdent;
  387. dir_slot *slotptr = (dir_slot *)retdent;
  388. __u8 *buflimit = cluster + mydata->sect_size * ((curclust == 0) ?
  389. PREFETCH_BLOCKS :
  390. mydata->clust_size);
  391. __u8 counter = (slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff;
  392. int idx = 0;
  393. if (counter > VFAT_MAXSEQ) {
  394. debug("Error: VFAT name is too long\n");
  395. return -1;
  396. }
  397. while ((__u8 *)slotptr < buflimit) {
  398. if (counter == 0)
  399. break;
  400. if (((slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff) != counter)
  401. return -1;
  402. slotptr++;
  403. counter--;
  404. }
  405. if ((__u8 *)slotptr >= buflimit) {
  406. dir_slot *slotptr2;
  407. if (curclust == 0)
  408. return -1;
  409. curclust = get_fatent(mydata, curclust);
  410. if (CHECK_CLUST(curclust, mydata->fatsize)) {
  411. debug("curclust: 0x%x\n", curclust);
  412. printf("Invalid FAT entry\n");
  413. return -1;
  414. }
  415. if (get_cluster(mydata, curclust, get_vfatname_block,
  416. mydata->clust_size * mydata->sect_size) != 0) {
  417. debug("Error: reading directory block\n");
  418. return -1;
  419. }
  420. slotptr2 = (dir_slot *)get_vfatname_block;
  421. while (counter > 0) {
  422. if (((slotptr2->id & ~LAST_LONG_ENTRY_MASK)
  423. & 0xff) != counter)
  424. return -1;
  425. slotptr2++;
  426. counter--;
  427. }
  428. /* Save the real directory entry */
  429. realdent = (dir_entry *)slotptr2;
  430. while ((__u8 *)slotptr2 > get_vfatname_block) {
  431. slotptr2--;
  432. slot2str(slotptr2, l_name, &idx);
  433. }
  434. } else {
  435. /* Save the real directory entry */
  436. realdent = (dir_entry *)slotptr;
  437. }
  438. do {
  439. slotptr--;
  440. if (slot2str(slotptr, l_name, &idx))
  441. break;
  442. } while (!(slotptr->id & LAST_LONG_ENTRY_MASK));
  443. l_name[idx] = '\0';
  444. if (*l_name == DELETED_FLAG)
  445. *l_name = '\0';
  446. else if (*l_name == aRING)
  447. *l_name = DELETED_FLAG;
  448. downcase(l_name);
  449. /* Return the real directory entry */
  450. memcpy(retdent, realdent, sizeof(dir_entry));
  451. return 0;
  452. }
  453. /* Calculate short name checksum */
  454. static __u8 mkcksum (const char *str)
  455. {
  456. int i;
  457. __u8 ret = 0;
  458. for (i = 0; i < 11; i++) {
  459. ret = (((ret & 1) << 7) | ((ret & 0xfe) >> 1)) + str[i];
  460. }
  461. return ret;
  462. }
  463. #endif /* CONFIG_SUPPORT_VFAT */
  464. /*
  465. * Get the directory entry associated with 'filename' from the directory
  466. * starting at 'startsect'
  467. */
  468. __u8 get_dentfromdir_block[MAX_CLUSTSIZE]
  469. __aligned(ARCH_DMA_MINALIGN);
  470. static dir_entry *get_dentfromdir (fsdata *mydata, int startsect,
  471. char *filename, dir_entry *retdent,
  472. int dols)
  473. {
  474. __u16 prevcksum = 0xffff;
  475. __u32 curclust = START(retdent);
  476. int files = 0, dirs = 0;
  477. debug("get_dentfromdir: %s\n", filename);
  478. while (1) {
  479. dir_entry *dentptr;
  480. int i;
  481. if (get_cluster(mydata, curclust, get_dentfromdir_block,
  482. mydata->clust_size * mydata->sect_size) != 0) {
  483. debug("Error: reading directory block\n");
  484. return NULL;
  485. }
  486. dentptr = (dir_entry *)get_dentfromdir_block;
  487. for (i = 0; i < DIRENTSPERCLUST; i++) {
  488. char s_name[14], l_name[VFAT_MAXLEN_BYTES];
  489. l_name[0] = '\0';
  490. if (dentptr->name[0] == DELETED_FLAG) {
  491. dentptr++;
  492. continue;
  493. }
  494. if ((dentptr->attr & ATTR_VOLUME)) {
  495. #ifdef CONFIG_SUPPORT_VFAT
  496. if ((dentptr->attr & ATTR_VFAT) == ATTR_VFAT &&
  497. (dentptr->name[0] & LAST_LONG_ENTRY_MASK)) {
  498. prevcksum = ((dir_slot *)dentptr)->alias_checksum;
  499. get_vfatname(mydata, curclust,
  500. get_dentfromdir_block,
  501. dentptr, l_name);
  502. if (dols) {
  503. int isdir;
  504. char dirc;
  505. int doit = 0;
  506. isdir = (dentptr->attr & ATTR_DIR);
  507. if (isdir) {
  508. dirs++;
  509. dirc = '/';
  510. doit = 1;
  511. } else {
  512. dirc = ' ';
  513. if (l_name[0] != 0) {
  514. files++;
  515. doit = 1;
  516. }
  517. }
  518. if (doit) {
  519. if (dirc == ' ') {
  520. printf(" %8ld %s%c\n",
  521. (long)FAT2CPU32(dentptr->size),
  522. l_name,
  523. dirc);
  524. } else {
  525. printf(" %s%c\n",
  526. l_name,
  527. dirc);
  528. }
  529. }
  530. dentptr++;
  531. continue;
  532. }
  533. debug("vfatname: |%s|\n", l_name);
  534. } else
  535. #endif
  536. {
  537. /* Volume label or VFAT entry */
  538. dentptr++;
  539. continue;
  540. }
  541. }
  542. if (dentptr->name[0] == 0) {
  543. if (dols) {
  544. printf("\n%d file(s), %d dir(s)\n\n",
  545. files, dirs);
  546. }
  547. debug("Dentname == NULL - %d\n", i);
  548. return NULL;
  549. }
  550. #ifdef CONFIG_SUPPORT_VFAT
  551. if (dols && mkcksum(dentptr->name) == prevcksum) {
  552. prevcksum = 0xffff;
  553. dentptr++;
  554. continue;
  555. }
  556. #endif
  557. get_name(dentptr, s_name);
  558. if (dols) {
  559. int isdir = (dentptr->attr & ATTR_DIR);
  560. char dirc;
  561. int doit = 0;
  562. if (isdir) {
  563. dirs++;
  564. dirc = '/';
  565. doit = 1;
  566. } else {
  567. dirc = ' ';
  568. if (s_name[0] != 0) {
  569. files++;
  570. doit = 1;
  571. }
  572. }
  573. if (doit) {
  574. if (dirc == ' ') {
  575. printf(" %8ld %s%c\n",
  576. (long)FAT2CPU32(dentptr->size),
  577. s_name, dirc);
  578. } else {
  579. printf(" %s%c\n",
  580. s_name, dirc);
  581. }
  582. }
  583. dentptr++;
  584. continue;
  585. }
  586. if (strcmp(filename, s_name)
  587. && strcmp(filename, l_name)) {
  588. debug("Mismatch: |%s|%s|\n", s_name, l_name);
  589. dentptr++;
  590. continue;
  591. }
  592. memcpy(retdent, dentptr, sizeof(dir_entry));
  593. debug("DentName: %s", s_name);
  594. debug(", start: 0x%x", START(dentptr));
  595. debug(", size: 0x%x %s\n",
  596. FAT2CPU32(dentptr->size),
  597. (dentptr->attr & ATTR_DIR) ? "(DIR)" : "");
  598. return retdent;
  599. }
  600. curclust = get_fatent(mydata, curclust);
  601. if (CHECK_CLUST(curclust, mydata->fatsize)) {
  602. debug("curclust: 0x%x\n", curclust);
  603. printf("Invalid FAT entry\n");
  604. return NULL;
  605. }
  606. }
  607. return NULL;
  608. }
  609. /*
  610. * Read boot sector and volume info from a FAT filesystem
  611. */
  612. static int
  613. read_bootsectandvi (boot_sector *bs, volume_info *volinfo, int *fatsize)
  614. {
  615. __u8 *block;
  616. volume_info *vistart;
  617. int ret = 0;
  618. if (cur_dev == NULL) {
  619. debug("Error: no device selected\n");
  620. return -1;
  621. }
  622. block = memalign(ARCH_DMA_MINALIGN, cur_dev->blksz);
  623. if (block == NULL) {
  624. debug("Error: allocating block\n");
  625. return -1;
  626. }
  627. if (disk_read (0, 1, block) < 0) {
  628. debug("Error: reading block\n");
  629. goto fail;
  630. }
  631. memcpy(bs, block, sizeof(boot_sector));
  632. bs->reserved = FAT2CPU16(bs->reserved);
  633. bs->fat_length = FAT2CPU16(bs->fat_length);
  634. bs->secs_track = FAT2CPU16(bs->secs_track);
  635. bs->heads = FAT2CPU16(bs->heads);
  636. bs->total_sect = FAT2CPU32(bs->total_sect);
  637. /* FAT32 entries */
  638. if (bs->fat_length == 0) {
  639. /* Assume FAT32 */
  640. bs->fat32_length = FAT2CPU32(bs->fat32_length);
  641. bs->flags = FAT2CPU16(bs->flags);
  642. bs->root_cluster = FAT2CPU32(bs->root_cluster);
  643. bs->info_sector = FAT2CPU16(bs->info_sector);
  644. bs->backup_boot = FAT2CPU16(bs->backup_boot);
  645. vistart = (volume_info *)(block + sizeof(boot_sector));
  646. *fatsize = 32;
  647. } else {
  648. vistart = (volume_info *)&(bs->fat32_length);
  649. *fatsize = 0;
  650. }
  651. memcpy(volinfo, vistart, sizeof(volume_info));
  652. if (*fatsize == 32) {
  653. if (strncmp(FAT32_SIGN, vistart->fs_type, SIGNLEN) == 0)
  654. goto exit;
  655. } else {
  656. if (strncmp(FAT12_SIGN, vistart->fs_type, SIGNLEN) == 0) {
  657. *fatsize = 12;
  658. goto exit;
  659. }
  660. if (strncmp(FAT16_SIGN, vistart->fs_type, SIGNLEN) == 0) {
  661. *fatsize = 16;
  662. goto exit;
  663. }
  664. }
  665. debug("Error: broken fs_type sign\n");
  666. fail:
  667. ret = -1;
  668. exit:
  669. free(block);
  670. return ret;
  671. }
  672. __u8 do_fat_read_block[MAX_CLUSTSIZE]
  673. __aligned(ARCH_DMA_MINALIGN);
  674. long
  675. do_fat_read (const char *filename, void *buffer, unsigned long maxsize,
  676. int dols)
  677. {
  678. char fnamecopy[2048];
  679. boot_sector bs;
  680. volume_info volinfo;
  681. fsdata datablock;
  682. fsdata *mydata = &datablock;
  683. dir_entry *dentptr;
  684. __u16 prevcksum = 0xffff;
  685. char *subname = "";
  686. __u32 cursect;
  687. int idx, isdir = 0;
  688. int files = 0, dirs = 0;
  689. long ret = -1;
  690. int firsttime;
  691. __u32 root_cluster = 0;
  692. int rootdir_size = 0;
  693. int j;
  694. if (read_bootsectandvi(&bs, &volinfo, &mydata->fatsize)) {
  695. debug("Error: reading boot sector\n");
  696. return -1;
  697. }
  698. if (mydata->fatsize == 32) {
  699. root_cluster = bs.root_cluster;
  700. mydata->fatlength = bs.fat32_length;
  701. } else {
  702. mydata->fatlength = bs.fat_length;
  703. }
  704. mydata->fat_sect = bs.reserved;
  705. cursect = mydata->rootdir_sect
  706. = mydata->fat_sect + mydata->fatlength * bs.fats;
  707. mydata->sect_size = (bs.sector_size[1] << 8) + bs.sector_size[0];
  708. mydata->clust_size = bs.cluster_size;
  709. if (mydata->sect_size != cur_part_info.blksz) {
  710. printf("Error: FAT sector size mismatch (fs=%hu, dev=%lu)\n",
  711. mydata->sect_size, cur_part_info.blksz);
  712. return -1;
  713. }
  714. if (mydata->fatsize == 32) {
  715. mydata->data_begin = mydata->rootdir_sect -
  716. (mydata->clust_size * 2);
  717. } else {
  718. rootdir_size = ((bs.dir_entries[1] * (int)256 +
  719. bs.dir_entries[0]) *
  720. sizeof(dir_entry)) /
  721. mydata->sect_size;
  722. mydata->data_begin = mydata->rootdir_sect +
  723. rootdir_size -
  724. (mydata->clust_size * 2);
  725. }
  726. mydata->fatbufnum = -1;
  727. mydata->fatbuf = memalign(ARCH_DMA_MINALIGN, FATBUFSIZE);
  728. if (mydata->fatbuf == NULL) {
  729. debug("Error: allocating memory\n");
  730. return -1;
  731. }
  732. #ifdef CONFIG_SUPPORT_VFAT
  733. debug("VFAT Support enabled\n");
  734. #endif
  735. debug("FAT%d, fat_sect: %d, fatlength: %d\n",
  736. mydata->fatsize, mydata->fat_sect, mydata->fatlength);
  737. debug("Rootdir begins at cluster: %d, sector: %d, offset: %x\n"
  738. "Data begins at: %d\n",
  739. root_cluster,
  740. mydata->rootdir_sect,
  741. mydata->rootdir_sect * mydata->sect_size, mydata->data_begin);
  742. debug("Sector size: %d, cluster size: %d\n", mydata->sect_size,
  743. mydata->clust_size);
  744. /* "cwd" is always the root... */
  745. while (ISDIRDELIM(*filename))
  746. filename++;
  747. /* Make a copy of the filename and convert it to lowercase */
  748. strcpy(fnamecopy, filename);
  749. downcase(fnamecopy);
  750. if (*fnamecopy == '\0') {
  751. if (!dols)
  752. goto exit;
  753. dols = LS_ROOT;
  754. } else if ((idx = dirdelim(fnamecopy)) >= 0) {
  755. isdir = 1;
  756. fnamecopy[idx] = '\0';
  757. subname = fnamecopy + idx + 1;
  758. /* Handle multiple delimiters */
  759. while (ISDIRDELIM(*subname))
  760. subname++;
  761. } else if (dols) {
  762. isdir = 1;
  763. }
  764. j = 0;
  765. while (1) {
  766. int i;
  767. debug("FAT read sect=%d, clust_size=%d, DIRENTSPERBLOCK=%zd\n",
  768. cursect, mydata->clust_size, DIRENTSPERBLOCK);
  769. if (disk_read(cursect,
  770. (mydata->fatsize == 32) ?
  771. (mydata->clust_size) :
  772. PREFETCH_BLOCKS,
  773. do_fat_read_block) < 0) {
  774. debug("Error: reading rootdir block\n");
  775. goto exit;
  776. }
  777. dentptr = (dir_entry *) do_fat_read_block;
  778. for (i = 0; i < DIRENTSPERBLOCK; i++) {
  779. char s_name[14], l_name[VFAT_MAXLEN_BYTES];
  780. l_name[0] = '\0';
  781. if (dentptr->name[0] == DELETED_FLAG) {
  782. dentptr++;
  783. continue;
  784. }
  785. if ((dentptr->attr & ATTR_VOLUME)) {
  786. #ifdef CONFIG_SUPPORT_VFAT
  787. if ((dentptr->attr & ATTR_VFAT) == ATTR_VFAT &&
  788. (dentptr->name[0] & LAST_LONG_ENTRY_MASK)) {
  789. prevcksum =
  790. ((dir_slot *)dentptr)->alias_checksum;
  791. get_vfatname(mydata,
  792. root_cluster,
  793. do_fat_read_block,
  794. dentptr, l_name);
  795. if (dols == LS_ROOT) {
  796. char dirc;
  797. int doit = 0;
  798. int isdir =
  799. (dentptr->attr & ATTR_DIR);
  800. if (isdir) {
  801. dirs++;
  802. dirc = '/';
  803. doit = 1;
  804. } else {
  805. dirc = ' ';
  806. if (l_name[0] != 0) {
  807. files++;
  808. doit = 1;
  809. }
  810. }
  811. if (doit) {
  812. if (dirc == ' ') {
  813. printf(" %8ld %s%c\n",
  814. (long)FAT2CPU32(dentptr->size),
  815. l_name,
  816. dirc);
  817. } else {
  818. printf(" %s%c\n",
  819. l_name,
  820. dirc);
  821. }
  822. }
  823. dentptr++;
  824. continue;
  825. }
  826. debug("Rootvfatname: |%s|\n",
  827. l_name);
  828. } else
  829. #endif
  830. {
  831. /* Volume label or VFAT entry */
  832. dentptr++;
  833. continue;
  834. }
  835. } else if (dentptr->name[0] == 0) {
  836. debug("RootDentname == NULL - %d\n", i);
  837. if (dols == LS_ROOT) {
  838. printf("\n%d file(s), %d dir(s)\n\n",
  839. files, dirs);
  840. ret = 0;
  841. }
  842. goto exit;
  843. }
  844. #ifdef CONFIG_SUPPORT_VFAT
  845. else if (dols == LS_ROOT &&
  846. mkcksum(dentptr->name) == prevcksum) {
  847. prevcksum = 0xffff;
  848. dentptr++;
  849. continue;
  850. }
  851. #endif
  852. get_name(dentptr, s_name);
  853. if (dols == LS_ROOT) {
  854. int isdir = (dentptr->attr & ATTR_DIR);
  855. char dirc;
  856. int doit = 0;
  857. if (isdir) {
  858. dirc = '/';
  859. if (s_name[0] != 0) {
  860. dirs++;
  861. doit = 1;
  862. }
  863. } else {
  864. dirc = ' ';
  865. if (s_name[0] != 0) {
  866. files++;
  867. doit = 1;
  868. }
  869. }
  870. if (doit) {
  871. if (dirc == ' ') {
  872. printf(" %8ld %s%c\n",
  873. (long)FAT2CPU32(dentptr->size),
  874. s_name, dirc);
  875. } else {
  876. printf(" %s%c\n",
  877. s_name, dirc);
  878. }
  879. }
  880. dentptr++;
  881. continue;
  882. }
  883. if (strcmp(fnamecopy, s_name)
  884. && strcmp(fnamecopy, l_name)) {
  885. debug("RootMismatch: |%s|%s|\n", s_name,
  886. l_name);
  887. dentptr++;
  888. continue;
  889. }
  890. if (isdir && !(dentptr->attr & ATTR_DIR))
  891. goto exit;
  892. debug("RootName: %s", s_name);
  893. debug(", start: 0x%x", START(dentptr));
  894. debug(", size: 0x%x %s\n",
  895. FAT2CPU32(dentptr->size),
  896. isdir ? "(DIR)" : "");
  897. goto rootdir_done; /* We got a match */
  898. }
  899. debug("END LOOP: j=%d clust_size=%d\n", j,
  900. mydata->clust_size);
  901. /*
  902. * On FAT32 we must fetch the FAT entries for the next
  903. * root directory clusters when a cluster has been
  904. * completely processed.
  905. */
  906. ++j;
  907. int fat32_end = 0;
  908. if ((mydata->fatsize == 32) && (j == mydata->clust_size)) {
  909. int nxtsect = 0;
  910. int nxt_clust = 0;
  911. nxt_clust = get_fatent(mydata, root_cluster);
  912. fat32_end = CHECK_CLUST(nxt_clust, 32);
  913. nxtsect = mydata->data_begin +
  914. (nxt_clust * mydata->clust_size);
  915. root_cluster = nxt_clust;
  916. cursect = nxtsect;
  917. j = 0;
  918. } else {
  919. cursect++;
  920. }
  921. /* If end of rootdir reached */
  922. if ((mydata->fatsize == 32 && fat32_end) ||
  923. (mydata->fatsize != 32 && j == rootdir_size)) {
  924. if (dols == LS_ROOT) {
  925. printf("\n%d file(s), %d dir(s)\n\n",
  926. files, dirs);
  927. ret = 0;
  928. }
  929. goto exit;
  930. }
  931. }
  932. rootdir_done:
  933. firsttime = 1;
  934. while (isdir) {
  935. int startsect = mydata->data_begin
  936. + START(dentptr) * mydata->clust_size;
  937. dir_entry dent;
  938. char *nextname = NULL;
  939. dent = *dentptr;
  940. dentptr = &dent;
  941. idx = dirdelim(subname);
  942. if (idx >= 0) {
  943. subname[idx] = '\0';
  944. nextname = subname + idx + 1;
  945. /* Handle multiple delimiters */
  946. while (ISDIRDELIM(*nextname))
  947. nextname++;
  948. if (dols && *nextname == '\0')
  949. firsttime = 0;
  950. } else {
  951. if (dols && firsttime) {
  952. firsttime = 0;
  953. } else {
  954. isdir = 0;
  955. }
  956. }
  957. if (get_dentfromdir(mydata, startsect, subname, dentptr,
  958. isdir ? 0 : dols) == NULL) {
  959. if (dols && !isdir)
  960. ret = 0;
  961. goto exit;
  962. }
  963. if (idx >= 0) {
  964. if (!(dentptr->attr & ATTR_DIR))
  965. goto exit;
  966. subname = nextname;
  967. }
  968. }
  969. ret = get_contents(mydata, dentptr, buffer, maxsize);
  970. debug("Size: %d, got: %ld\n", FAT2CPU32(dentptr->size), ret);
  971. exit:
  972. free(mydata->fatbuf);
  973. return ret;
  974. }
  975. int file_fat_detectfs (void)
  976. {
  977. boot_sector bs;
  978. volume_info volinfo;
  979. int fatsize;
  980. char vol_label[12];
  981. if (cur_dev == NULL) {
  982. printf("No current device\n");
  983. return 1;
  984. }
  985. #if defined(CONFIG_CMD_IDE) || \
  986. defined(CONFIG_CMD_MG_DISK) || \
  987. defined(CONFIG_CMD_SATA) || \
  988. defined(CONFIG_CMD_SCSI) || \
  989. defined(CONFIG_CMD_USB) || \
  990. defined(CONFIG_MMC)
  991. printf("Interface: ");
  992. switch (cur_dev->if_type) {
  993. case IF_TYPE_IDE:
  994. printf("IDE");
  995. break;
  996. case IF_TYPE_SATA:
  997. printf("SATA");
  998. break;
  999. case IF_TYPE_SCSI:
  1000. printf("SCSI");
  1001. break;
  1002. case IF_TYPE_ATAPI:
  1003. printf("ATAPI");
  1004. break;
  1005. case IF_TYPE_USB:
  1006. printf("USB");
  1007. break;
  1008. case IF_TYPE_DOC:
  1009. printf("DOC");
  1010. break;
  1011. case IF_TYPE_MMC:
  1012. printf("MMC");
  1013. break;
  1014. default:
  1015. printf("Unknown");
  1016. }
  1017. printf("\n Device %d: ", cur_dev->dev);
  1018. dev_print(cur_dev);
  1019. #endif
  1020. if (read_bootsectandvi(&bs, &volinfo, &fatsize)) {
  1021. printf("\nNo valid FAT fs found\n");
  1022. return 1;
  1023. }
  1024. memcpy(vol_label, volinfo.volume_label, 11);
  1025. vol_label[11] = '\0';
  1026. volinfo.fs_type[5] = '\0';
  1027. printf("Partition %d: Filesystem: %s \"%s\"\n", cur_part_nr,
  1028. volinfo.fs_type, vol_label);
  1029. return 0;
  1030. }
  1031. int file_fat_ls (const char *dir)
  1032. {
  1033. return do_fat_read(dir, NULL, 0, LS_YES);
  1034. }
  1035. long file_fat_read (const char *filename, void *buffer, unsigned long maxsize)
  1036. {
  1037. printf("reading %s\n", filename);
  1038. return do_fat_read(filename, buffer, maxsize, LS_NO);
  1039. }