fat.c 28 KB

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