fat.c 26 KB

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