fat.c 24 KB

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