]> git.ipfire.org Git - thirdparty/u-boot.git/blame - fs/fat/fat.c
fs/fat: Avoid corruption of sectors following the FAT
[thirdparty/u-boot.git] / fs / fat / fat.c
CommitLineData
71f95118
WD
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 *
1a459660 9 * SPDX-License-Identifier: GPL-2.0+
71f95118
WD
10 */
11
12#include <common.h>
2a981dc2 13#include <blk.h>
71f95118 14#include <config.h>
ac497771 15#include <exports.h>
71f95118
WD
16#include <fat.h>
17#include <asm/byteorder.h>
7205e407 18#include <part.h>
9a800ac7 19#include <malloc.h>
cf92e05c 20#include <memalign.h>
9a800ac7 21#include <linux/compiler.h>
fb7e16cc 22#include <linux/ctype.h>
71f95118 23
cb940c7e
RG
24#ifdef CONFIG_SUPPORT_VFAT
25static const int vfat_enabled = 1;
26#else
27static const int vfat_enabled = 0;
28#endif
29
71f95118
WD
30/*
31 * Convert a string to lowercase.
32 */
9795e07b 33static void downcase(char *str)
71f95118
WD
34{
35 while (*str != '\0') {
fb7e16cc 36 *str = tolower(*str);
71f95118
WD
37 str++;
38 }
39}
40
4101f687 41static struct blk_desc *cur_dev;
9813b750 42static disk_partition_t cur_part_info;
7385c28e 43
9813b750 44#define DOS_BOOT_MAGIC_OFFSET 0x1fe
7205e407 45#define DOS_FS_TYPE_OFFSET 0x36
66c2d73c 46#define DOS_FS32_TYPE_OFFSET 0x52
71f95118 47
9813b750 48static int disk_read(__u32 block, __u32 nr_blocks, void *buf)
71f95118 49{
0a04ed86
ŁM
50 ulong ret;
51
2a981dc2 52 if (!cur_dev)
7205e407 53 return -1;
7385c28e 54
2a981dc2 55 ret = blk_dread(cur_dev, cur_part_info.start + block, nr_blocks, buf);
0a04ed86
ŁM
56
57 if (nr_blocks && ret == 0)
58 return -1;
59
60 return ret;
71f95118
WD
61}
62
4101f687 63int fat_set_blk_dev(struct blk_desc *dev_desc, disk_partition_t *info)
71f95118 64{
9a800ac7 65 ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, dev_desc->blksz);
7205e407 66
5e8f9831
SW
67 cur_dev = dev_desc;
68 cur_part_info = *info;
9813b750
KM
69
70 /* Make sure it has a valid FAT header */
71 if (disk_read(0, 1, buffer) != 1) {
72 cur_dev = NULL;
73 return -1;
bf1060ea 74 }
9813b750
KM
75
76 /* Check if it's actually a DOS volume */
77 if (memcmp(buffer + DOS_BOOT_MAGIC_OFFSET, "\x55\xAA", 2)) {
78 cur_dev = NULL;
79 return -1;
80 }
81
82 /* Check for FAT12/FAT16/FAT32 filesystem */
83 if (!memcmp(buffer + DOS_FS_TYPE_OFFSET, "FAT", 3))
84 return 0;
85 if (!memcmp(buffer + DOS_FS32_TYPE_OFFSET, "FAT32", 5))
86 return 0;
87
88 cur_dev = NULL;
89 return -1;
71f95118
WD
90}
91
4101f687 92int fat_register_device(struct blk_desc *dev_desc, int part_no)
5e8f9831
SW
93{
94 disk_partition_t info;
95
96 /* First close any currently found FAT filesystem */
97 cur_dev = NULL;
98
99 /* Read the partition table, if present */
3e8bd469 100 if (part_get_info(dev_desc, part_no, &info)) {
5e8f9831
SW
101 if (part_no != 0) {
102 printf("** Partition %d not valid on device %d **\n",
bcce53d0 103 part_no, dev_desc->devnum);
5e8f9831
SW
104 return -1;
105 }
106
107 info.start = 0;
108 info.size = dev_desc->lba;
109 info.blksz = dev_desc->blksz;
110 info.name[0] = 0;
111 info.type[0] = 0;
112 info.bootable = 0;
113#ifdef CONFIG_PARTITION_UUIDS
114 info.uuid[0] = 0;
115#endif
116 }
117
118 return fat_set_blk_dev(dev_desc, &info);
119}
9813b750 120
71f95118
WD
121/*
122 * Get the first occurence of a directory delimiter ('/' or '\') in a string.
123 * Return index into string if found, -1 otherwise.
124 */
9795e07b 125static int dirdelim(char *str)
71f95118
WD
126{
127 char *start = str;
128
129 while (*str != '\0') {
7385c28e
WD
130 if (ISDIRDELIM(*str))
131 return str - start;
71f95118
WD
132 str++;
133 }
134 return -1;
135}
136
71f95118
WD
137/*
138 * Extract zero terminated short name from a directory entry.
139 */
9795e07b 140static void get_name(dir_entry *dirent, char *s_name)
71f95118
WD
141{
142 char *ptr;
143
7385c28e 144 memcpy(s_name, dirent->name, 8);
71f95118
WD
145 s_name[8] = '\0';
146 ptr = s_name;
147 while (*ptr && *ptr != ' ')
148 ptr++;
149 if (dirent->ext[0] && dirent->ext[0] != ' ') {
150 *ptr = '.';
151 ptr++;
7385c28e 152 memcpy(ptr, dirent->ext, 3);
71f95118
WD
153 ptr[3] = '\0';
154 while (*ptr && *ptr != ' ')
155 ptr++;
156 }
157 *ptr = '\0';
158 if (*s_name == DELETED_FLAG)
159 *s_name = '\0';
160 else if (*s_name == aRING)
3c2c2f42 161 *s_name = DELETED_FLAG;
7385c28e 162 downcase(s_name);
71f95118
WD
163}
164
165/*
166 * Get the entry at index 'entry' in a FAT (12/16/32) table.
167 * On failure 0x00 is returned.
168 */
9795e07b 169static __u32 get_fatent(fsdata *mydata, __u32 entry)
71f95118
WD
170{
171 __u32 bufnum;
7385c28e 172 __u32 off16, offset;
71f95118 173 __u32 ret = 0x00;
7385c28e 174 __u16 val1, val2;
71f95118
WD
175
176 switch (mydata->fatsize) {
177 case 32:
178 bufnum = entry / FAT32BUFSIZE;
179 offset = entry - bufnum * FAT32BUFSIZE;
180 break;
181 case 16:
182 bufnum = entry / FAT16BUFSIZE;
183 offset = entry - bufnum * FAT16BUFSIZE;
184 break;
185 case 12:
186 bufnum = entry / FAT12BUFSIZE;
187 offset = entry - bufnum * FAT12BUFSIZE;
188 break;
189
190 default:
191 /* Unsupported FAT size */
192 return ret;
193 }
194
7385c28e
WD
195 debug("FAT%d: entry: 0x%04x = %d, offset: 0x%04x = %d\n",
196 mydata->fatsize, entry, entry, offset, offset);
2aa98c66 197
71f95118
WD
198 /* Read a new block of FAT entries into the cache. */
199 if (bufnum != mydata->fatbufnum) {
60b36f0f 200 __u32 getsize = FATBUFBLOCKS;
71f95118
WD
201 __u8 *bufptr = mydata->fatbuf;
202 __u32 fatlength = mydata->fatlength;
203 __u32 startblock = bufnum * FATBUFBLOCKS;
204
6c1a8080 205 /* Cap length if fatlength is not a multiple of FATBUFBLOCKS */
8006dd2e
BT
206 if (startblock + getsize > fatlength)
207 getsize = fatlength - startblock;
60b36f0f 208
71f95118
WD
209 startblock += mydata->fat_sect; /* Offset from start of disk */
210
71f95118 211 if (disk_read(startblock, getsize, bufptr) < 0) {
7385c28e 212 debug("Error reading FAT blocks\n");
71f95118
WD
213 return ret;
214 }
215 mydata->fatbufnum = bufnum;
216 }
217
218 /* Get the actual entry from the table */
219 switch (mydata->fatsize) {
220 case 32:
7385c28e 221 ret = FAT2CPU32(((__u32 *) mydata->fatbuf)[offset]);
71f95118
WD
222 break;
223 case 16:
7385c28e 224 ret = FAT2CPU16(((__u16 *) mydata->fatbuf)[offset]);
71f95118 225 break;
7385c28e
WD
226 case 12:
227 off16 = (offset * 3) / 4;
71f95118
WD
228
229 switch (offset & 0x3) {
230 case 0:
7385c28e 231 ret = FAT2CPU16(((__u16 *) mydata->fatbuf)[off16]);
71f95118
WD
232 ret &= 0xfff;
233 break;
234 case 1:
7385c28e 235 val1 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16]);
71f95118 236 val1 &= 0xf000;
7385c28e 237 val2 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16 + 1]);
71f95118
WD
238 val2 &= 0x00ff;
239 ret = (val2 << 4) | (val1 >> 12);
240 break;
241 case 2:
7385c28e 242 val1 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16]);
71f95118 243 val1 &= 0xff00;
7385c28e 244 val2 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16 + 1]);
71f95118
WD
245 val2 &= 0x000f;
246 ret = (val2 << 8) | (val1 >> 8);
247 break;
248 case 3:
7385c28e 249 ret = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16]);
71f95118
WD
250 ret = (ret & 0xfff0) >> 4;
251 break;
252 default:
253 break;
254 }
7385c28e 255 break;
71f95118 256 }
7385c28e
WD
257 debug("FAT%d: ret: %08x, offset: %04x\n",
258 mydata->fatsize, ret, offset);
71f95118
WD
259
260 return ret;
261}
262
71f95118
WD
263/*
264 * Read at most 'size' bytes from the specified cluster into 'buffer'.
265 * Return 0 on success, -1 otherwise.
266 */
267static int
9795e07b 268get_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer, unsigned long size)
71f95118 269{
3f270f42 270 __u32 idx = 0;
71f95118 271 __u32 startsect;
46236b14 272 int ret;
71f95118
WD
273
274 if (clustnum > 0) {
7385c28e
WD
275 startsect = mydata->data_begin +
276 clustnum * mydata->clust_size;
71f95118
WD
277 } else {
278 startsect = mydata->rootdir_sect;
279 }
280
7385c28e
WD
281 debug("gc - clustnum: %d, startsect: %d\n", clustnum, startsect);
282
cc63b25e 283 if ((unsigned long)buffer & (ARCH_DMA_MINALIGN - 1)) {
9a800ac7 284 ALLOC_CACHE_ALIGN_BUFFER(__u8, tmpbuf, mydata->sect_size);
7385c28e 285
cc63b25e
BT
286 printf("FAT: Misaligned buffer address (%p)\n", buffer);
287
288 while (size >= mydata->sect_size) {
289 ret = disk_read(startsect++, 1, tmpbuf);
290 if (ret != 1) {
291 debug("Error reading data (got %d)\n", ret);
292 return -1;
293 }
294
295 memcpy(buffer, tmpbuf, mydata->sect_size);
296 buffer += mydata->sect_size;
297 size -= mydata->sect_size;
298 }
299 } else {
ac497771 300 idx = size / mydata->sect_size;
cc63b25e
BT
301 ret = disk_read(startsect, idx, buffer);
302 if (ret != idx) {
303 debug("Error reading data (got %d)\n", ret);
304 return -1;
305 }
306 startsect += idx;
307 idx *= mydata->sect_size;
308 buffer += idx;
309 size -= idx;
310 }
311 if (size) {
312 ALLOC_CACHE_ALIGN_BUFFER(__u8, tmpbuf, mydata->sect_size);
313
314 ret = disk_read(startsect, 1, tmpbuf);
46236b14
KM
315 if (ret != 1) {
316 debug("Error reading data (got %d)\n", ret);
7205e407 317 return -1;
71f95118 318 }
7205e407 319
cc63b25e 320 memcpy(buffer, tmpbuf, size);
71f95118
WD
321 }
322
323 return 0;
324}
325
71f95118 326/*
1170e634 327 * Read at most 'maxsize' bytes from 'pos' in the file associated with 'dentptr'
71f95118 328 * into 'buffer'.
1ad0b98a 329 * Update the number of bytes read in *gotsize or return -1 on fatal errors.
71f95118 330 */
1170e634
BT
331__u8 get_contents_vfatname_block[MAX_CLUSTSIZE]
332 __aligned(ARCH_DMA_MINALIGN);
333
1ad0b98a
SR
334static int get_contents(fsdata *mydata, dir_entry *dentptr, loff_t pos,
335 __u8 *buffer, loff_t maxsize, loff_t *gotsize)
71f95118 336{
1ad0b98a 337 loff_t filesize = FAT2CPU32(dentptr->size);
ac497771 338 unsigned int bytesperclust = mydata->clust_size * mydata->sect_size;
71f95118 339 __u32 curclust = START(dentptr);
7205e407 340 __u32 endclust, newclust;
1ad0b98a 341 loff_t actsize;
71f95118 342
1ad0b98a
SR
343 *gotsize = 0;
344 debug("Filesize: %llu bytes\n", filesize);
71f95118 345
1170e634 346 if (pos >= filesize) {
1ad0b98a
SR
347 debug("Read position past EOF: %llu\n", pos);
348 return 0;
1170e634
BT
349 }
350
351 if (maxsize > 0 && filesize > pos + maxsize)
352 filesize = pos + maxsize;
71f95118 353
1ad0b98a 354 debug("%llu bytes\n", filesize);
7385c28e 355
1170e634
BT
356 actsize = bytesperclust;
357
358 /* go to cluster at pos */
359 while (actsize <= pos) {
360 curclust = get_fatent(mydata, curclust);
361 if (CHECK_CLUST(curclust, mydata->fatsize)) {
362 debug("curclust: 0x%x\n", curclust);
363 debug("Invalid FAT entry\n");
1ad0b98a 364 return 0;
1170e634
BT
365 }
366 actsize += bytesperclust;
367 }
368
369 /* actsize > pos */
370 actsize -= bytesperclust;
371 filesize -= actsize;
372 pos -= actsize;
373
374 /* align to beginning of next cluster if any */
375 if (pos) {
1ad0b98a 376 actsize = min(filesize, (loff_t)bytesperclust);
1170e634
BT
377 if (get_cluster(mydata, curclust, get_contents_vfatname_block,
378 (int)actsize) != 0) {
379 printf("Error reading cluster\n");
380 return -1;
381 }
382 filesize -= actsize;
383 actsize -= pos;
384 memcpy(buffer, get_contents_vfatname_block + pos, actsize);
1ad0b98a 385 *gotsize += actsize;
1170e634 386 if (!filesize)
1ad0b98a 387 return 0;
1170e634
BT
388 buffer += actsize;
389
390 curclust = get_fatent(mydata, curclust);
391 if (CHECK_CLUST(curclust, mydata->fatsize)) {
392 debug("curclust: 0x%x\n", curclust);
393 debug("Invalid FAT entry\n");
1ad0b98a 394 return 0;
1170e634
BT
395 }
396 }
397
7385c28e
WD
398 actsize = bytesperclust;
399 endclust = curclust;
71f95118
WD
400
401 do {
7205e407 402 /* search for consecutive clusters */
7385c28e 403 while (actsize < filesize) {
7205e407 404 newclust = get_fatent(mydata, endclust);
7385c28e 405 if ((newclust - 1) != endclust)
7205e407 406 goto getit;
8ce4e5c2 407 if (CHECK_CLUST(newclust, mydata->fatsize)) {
7385c28e
WD
408 debug("curclust: 0x%x\n", newclust);
409 debug("Invalid FAT entry\n");
1ad0b98a 410 return 0;
7205e407 411 }
7385c28e
WD
412 endclust = newclust;
413 actsize += bytesperclust;
7205e407 414 }
7385c28e 415
7205e407 416 /* get remaining bytes */
7385c28e 417 actsize = filesize;
0880e5bb 418 if (get_cluster(mydata, curclust, buffer, (int)actsize) != 0) {
7385c28e 419 printf("Error reading cluster\n");
7205e407
WD
420 return -1;
421 }
1ad0b98a
SR
422 *gotsize += actsize;
423 return 0;
7205e407
WD
424getit:
425 if (get_cluster(mydata, curclust, buffer, (int)actsize) != 0) {
7385c28e 426 printf("Error reading cluster\n");
7205e407
WD
427 return -1;
428 }
1ad0b98a 429 *gotsize += (int)actsize;
7205e407
WD
430 filesize -= actsize;
431 buffer += actsize;
7385c28e 432
7205e407 433 curclust = get_fatent(mydata, endclust);
8ce4e5c2 434 if (CHECK_CLUST(curclust, mydata->fatsize)) {
7385c28e
WD
435 debug("curclust: 0x%x\n", curclust);
436 printf("Invalid FAT entry\n");
1ad0b98a 437 return 0;
71f95118 438 }
7385c28e
WD
439 actsize = bytesperclust;
440 endclust = curclust;
71f95118
WD
441 } while (1);
442}
443
71f95118
WD
444/*
445 * Extract the file name information from 'slotptr' into 'l_name',
446 * starting at l_name[*idx].
447 * Return 1 if terminator (zero byte) is found, 0 otherwise.
448 */
9795e07b 449static int slot2str(dir_slot *slotptr, char *l_name, int *idx)
71f95118
WD
450{
451 int j;
452
453 for (j = 0; j <= 8; j += 2) {
454 l_name[*idx] = slotptr->name0_4[j];
7385c28e
WD
455 if (l_name[*idx] == 0x00)
456 return 1;
71f95118
WD
457 (*idx)++;
458 }
459 for (j = 0; j <= 10; j += 2) {
460 l_name[*idx] = slotptr->name5_10[j];
7385c28e
WD
461 if (l_name[*idx] == 0x00)
462 return 1;
71f95118
WD
463 (*idx)++;
464 }
465 for (j = 0; j <= 2; j += 2) {
466 l_name[*idx] = slotptr->name11_12[j];
7385c28e
WD
467 if (l_name[*idx] == 0x00)
468 return 1;
71f95118
WD
469 (*idx)++;
470 }
471
472 return 0;
473}
474
71f95118
WD
475/*
476 * Extract the full long filename starting at 'retdent' (which is really
477 * a slot) into 'l_name'. If successful also copy the real directory entry
478 * into 'retdent'
479 * Return 0 on success, -1 otherwise.
480 */
481static int
9795e07b
BT
482get_vfatname(fsdata *mydata, int curclust, __u8 *cluster,
483 dir_entry *retdent, char *l_name)
71f95118
WD
484{
485 dir_entry *realdent;
7385c28e 486 dir_slot *slotptr = (dir_slot *)retdent;
025421ea
SS
487 __u8 *buflimit = cluster + mydata->sect_size * ((curclust == 0) ?
488 PREFETCH_BLOCKS :
489 mydata->clust_size);
7385c28e 490 __u8 counter = (slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff;
71f95118
WD
491 int idx = 0;
492
3831530d
MZ
493 if (counter > VFAT_MAXSEQ) {
494 debug("Error: VFAT name is too long\n");
495 return -1;
496 }
497
498 while ((__u8 *)slotptr < buflimit) {
7385c28e
WD
499 if (counter == 0)
500 break;
2d1a537d
WD
501 if (((slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff) != counter)
502 return -1;
71f95118
WD
503 slotptr++;
504 counter--;
505 }
506
3831530d 507 if ((__u8 *)slotptr >= buflimit) {
71f95118
WD
508 dir_slot *slotptr2;
509
3831530d
MZ
510 if (curclust == 0)
511 return -1;
71f95118 512 curclust = get_fatent(mydata, curclust);
8ce4e5c2 513 if (CHECK_CLUST(curclust, mydata->fatsize)) {
7385c28e
WD
514 debug("curclust: 0x%x\n", curclust);
515 printf("Invalid FAT entry\n");
71f95118
WD
516 return -1;
517 }
7385c28e 518
1170e634 519 if (get_cluster(mydata, curclust, get_contents_vfatname_block,
ac497771 520 mydata->clust_size * mydata->sect_size) != 0) {
7385c28e 521 debug("Error: reading directory block\n");
71f95118
WD
522 return -1;
523 }
7385c28e 524
1170e634 525 slotptr2 = (dir_slot *)get_contents_vfatname_block;
3831530d
MZ
526 while (counter > 0) {
527 if (((slotptr2->id & ~LAST_LONG_ENTRY_MASK)
528 & 0xff) != counter)
529 return -1;
71f95118 530 slotptr2++;
3831530d
MZ
531 counter--;
532 }
7385c28e 533
71f95118 534 /* Save the real directory entry */
3831530d 535 realdent = (dir_entry *)slotptr2;
1170e634 536 while ((__u8 *)slotptr2 > get_contents_vfatname_block) {
71f95118 537 slotptr2--;
3831530d 538 slot2str(slotptr2, l_name, &idx);
71f95118
WD
539 }
540 } else {
541 /* Save the real directory entry */
7385c28e 542 realdent = (dir_entry *)slotptr;
71f95118
WD
543 }
544
545 do {
546 slotptr--;
7385c28e
WD
547 if (slot2str(slotptr, l_name, &idx))
548 break;
2d1a537d 549 } while (!(slotptr->id & LAST_LONG_ENTRY_MASK));
71f95118
WD
550
551 l_name[idx] = '\0';
7385c28e
WD
552 if (*l_name == DELETED_FLAG)
553 *l_name = '\0';
554 else if (*l_name == aRING)
555 *l_name = DELETED_FLAG;
71f95118
WD
556 downcase(l_name);
557
558 /* Return the real directory entry */
559 memcpy(retdent, realdent, sizeof(dir_entry));
560
561 return 0;
562}
563
71f95118 564/* Calculate short name checksum */
ff04f6d1 565static __u8 mkcksum(const char name[8], const char ext[3])
71f95118
WD
566{
567 int i;
7385c28e 568
71f95118
WD
569 __u8 ret = 0;
570
6ad77d88 571 for (i = 0; i < 8; i++)
ff04f6d1 572 ret = (((ret & 1) << 7) | ((ret & 0xfe) >> 1)) + name[i];
6ad77d88 573 for (i = 0; i < 3; i++)
ff04f6d1 574 ret = (((ret & 1) << 7) | ((ret & 0xfe) >> 1)) + ext[i];
71f95118
WD
575
576 return ret;
577}
71f95118
WD
578
579/*
580 * Get the directory entry associated with 'filename' from the directory
581 * starting at 'startsect'
582 */
9a800ac7
EN
583__u8 get_dentfromdir_block[MAX_CLUSTSIZE]
584 __aligned(ARCH_DMA_MINALIGN);
7385c28e 585
9795e07b
BT
586static dir_entry *get_dentfromdir(fsdata *mydata, int startsect,
587 char *filename, dir_entry *retdent,
588 int dols)
71f95118 589{
7385c28e
WD
590 __u16 prevcksum = 0xffff;
591 __u32 curclust = START(retdent);
592 int files = 0, dirs = 0;
71f95118 593
7385c28e 594 debug("get_dentfromdir: %s\n", filename);
71f95118 595
7385c28e
WD
596 while (1) {
597 dir_entry *dentptr;
598
599 int i;
600
601 if (get_cluster(mydata, curclust, get_dentfromdir_block,
ac497771 602 mydata->clust_size * mydata->sect_size) != 0) {
7385c28e
WD
603 debug("Error: reading directory block\n");
604 return NULL;
605 }
606
607 dentptr = (dir_entry *)get_dentfromdir_block;
608
609 for (i = 0; i < DIRENTSPERCLUST; i++) {
3831530d 610 char s_name[14], l_name[VFAT_MAXLEN_BYTES];
7385c28e
WD
611
612 l_name[0] = '\0';
613 if (dentptr->name[0] == DELETED_FLAG) {
614 dentptr++;
615 continue;
616 }
617 if ((dentptr->attr & ATTR_VOLUME)) {
cb940c7e
RG
618 if (vfat_enabled &&
619 (dentptr->attr & ATTR_VFAT) == ATTR_VFAT &&
206d68fd 620 (dentptr->name[0] & LAST_LONG_ENTRY_MASK)) {
7385c28e
WD
621 prevcksum = ((dir_slot *)dentptr)->alias_checksum;
622 get_vfatname(mydata, curclust,
623 get_dentfromdir_block,
624 dentptr, l_name);
625 if (dols) {
626 int isdir;
627 char dirc;
628 int doit = 0;
629
630 isdir = (dentptr->attr & ATTR_DIR);
631
632 if (isdir) {
633 dirs++;
634 dirc = '/';
635 doit = 1;
636 } else {
637 dirc = ' ';
638 if (l_name[0] != 0) {
639 files++;
640 doit = 1;
641 }
642 }
643 if (doit) {
644 if (dirc == ' ') {
1ad0b98a
SR
645 printf(" %8u %s%c\n",
646 FAT2CPU32(dentptr->size),
7385c28e
WD
647 l_name,
648 dirc);
649 } else {
650 printf(" %s%c\n",
651 l_name,
652 dirc);
653 }
654 }
655 dentptr++;
656 continue;
657 }
658 debug("vfatname: |%s|\n", l_name);
cb940c7e 659 } else {
7385c28e
WD
660 /* Volume label or VFAT entry */
661 dentptr++;
662 continue;
663 }
71f95118 664 }
7385c28e
WD
665 if (dentptr->name[0] == 0) {
666 if (dols) {
667 printf("\n%d file(s), %d dir(s)\n\n",
668 files, dirs);
669 }
670 debug("Dentname == NULL - %d\n", i);
671 return NULL;
71f95118 672 }
cb940c7e
RG
673 if (vfat_enabled) {
674 __u8 csum = mkcksum(dentptr->name, dentptr->ext);
675 if (dols && csum == prevcksum) {
676 prevcksum = 0xffff;
677 dentptr++;
678 continue;
679 }
7385c28e 680 }
cb940c7e 681
7385c28e
WD
682 get_name(dentptr, s_name);
683 if (dols) {
684 int isdir = (dentptr->attr & ATTR_DIR);
685 char dirc;
686 int doit = 0;
687
688 if (isdir) {
689 dirs++;
690 dirc = '/';
691 doit = 1;
692 } else {
693 dirc = ' ';
694 if (s_name[0] != 0) {
695 files++;
696 doit = 1;
697 }
698 }
699
700 if (doit) {
701 if (dirc == ' ') {
1ad0b98a
SR
702 printf(" %8u %s%c\n",
703 FAT2CPU32(dentptr->size),
7385c28e
WD
704 s_name, dirc);
705 } else {
706 printf(" %s%c\n",
707 s_name, dirc);
708 }
709 }
710
711 dentptr++;
712 continue;
713 }
714
715 if (strcmp(filename, s_name)
716 && strcmp(filename, l_name)) {
717 debug("Mismatch: |%s|%s|\n", s_name, l_name);
718 dentptr++;
719 continue;
720 }
721
722 memcpy(retdent, dentptr, sizeof(dir_entry));
723
724 debug("DentName: %s", s_name);
725 debug(", start: 0x%x", START(dentptr));
726 debug(", size: 0x%x %s\n",
727 FAT2CPU32(dentptr->size),
728 (dentptr->attr & ATTR_DIR) ? "(DIR)" : "");
729
730 return retdent;
71f95118 731 }
7385c28e
WD
732
733 curclust = get_fatent(mydata, curclust);
734 if (CHECK_CLUST(curclust, mydata->fatsize)) {
735 debug("curclust: 0x%x\n", curclust);
736 printf("Invalid FAT entry\n");
737 return NULL;
71f95118 738 }
71f95118 739 }
71f95118 740
7385c28e 741 return NULL;
71f95118
WD
742}
743
71f95118
WD
744/*
745 * Read boot sector and volume info from a FAT filesystem
746 */
747static int
9795e07b 748read_bootsectandvi(boot_sector *bs, volume_info *volinfo, int *fatsize)
71f95118 749{
ac497771 750 __u8 *block;
71f95118 751 volume_info *vistart;
ac497771
SS
752 int ret = 0;
753
754 if (cur_dev == NULL) {
755 debug("Error: no device selected\n");
756 return -1;
757 }
758
9a800ac7 759 block = memalign(ARCH_DMA_MINALIGN, cur_dev->blksz);
ac497771
SS
760 if (block == NULL) {
761 debug("Error: allocating block\n");
762 return -1;
763 }
71f95118 764
9795e07b 765 if (disk_read(0, 1, block) < 0) {
7385c28e 766 debug("Error: reading block\n");
ac497771 767 goto fail;
71f95118
WD
768 }
769
770 memcpy(bs, block, sizeof(boot_sector));
7385c28e
WD
771 bs->reserved = FAT2CPU16(bs->reserved);
772 bs->fat_length = FAT2CPU16(bs->fat_length);
773 bs->secs_track = FAT2CPU16(bs->secs_track);
774 bs->heads = FAT2CPU16(bs->heads);
775 bs->total_sect = FAT2CPU32(bs->total_sect);
71f95118
WD
776
777 /* FAT32 entries */
778 if (bs->fat_length == 0) {
779 /* Assume FAT32 */
780 bs->fat32_length = FAT2CPU32(bs->fat32_length);
7385c28e 781 bs->flags = FAT2CPU16(bs->flags);
71f95118 782 bs->root_cluster = FAT2CPU32(bs->root_cluster);
7385c28e
WD
783 bs->info_sector = FAT2CPU16(bs->info_sector);
784 bs->backup_boot = FAT2CPU16(bs->backup_boot);
785 vistart = (volume_info *)(block + sizeof(boot_sector));
71f95118
WD
786 *fatsize = 32;
787 } else {
7385c28e 788 vistart = (volume_info *)&(bs->fat32_length);
71f95118
WD
789 *fatsize = 0;
790 }
791 memcpy(volinfo, vistart, sizeof(volume_info));
792
71f95118 793 if (*fatsize == 32) {
7385c28e 794 if (strncmp(FAT32_SIGN, vistart->fs_type, SIGNLEN) == 0)
ac497771 795 goto exit;
71f95118 796 } else {
651351fe 797 if (strncmp(FAT12_SIGN, vistart->fs_type, SIGNLEN) == 0) {
71f95118 798 *fatsize = 12;
ac497771 799 goto exit;
71f95118 800 }
651351fe 801 if (strncmp(FAT16_SIGN, vistart->fs_type, SIGNLEN) == 0) {
71f95118 802 *fatsize = 16;
ac497771 803 goto exit;
71f95118
WD
804 }
805 }
806
7385c28e 807 debug("Error: broken fs_type sign\n");
ac497771
SS
808fail:
809 ret = -1;
810exit:
811 free(block);
812 return ret;
71f95118
WD
813}
814
1170e634 815__u8 do_fat_read_at_block[MAX_CLUSTSIZE]
9a800ac7 816 __aligned(ARCH_DMA_MINALIGN);
7385c28e 817
1ad0b98a
SR
818int do_fat_read_at(const char *filename, loff_t pos, void *buffer,
819 loff_t maxsize, int dols, int dogetsize, loff_t *size)
71f95118 820{
7385c28e
WD
821 char fnamecopy[2048];
822 boot_sector bs;
823 volume_info volinfo;
824 fsdata datablock;
825 fsdata *mydata = &datablock;
cd1b042c 826 dir_entry *dentptr = NULL;
7385c28e
WD
827 __u16 prevcksum = 0xffff;
828 char *subname = "";
3f270f42 829 __u32 cursect;
7385c28e
WD
830 int idx, isdir = 0;
831 int files = 0, dirs = 0;
1ad0b98a 832 int ret = -1;
7385c28e 833 int firsttime;
40e21916 834 __u32 root_cluster = 0;
64f65e1e 835 __u32 read_blk;
3f270f42 836 int rootdir_size = 0;
64f65e1e
PM
837 int buffer_blk_cnt;
838 int do_read;
839 __u8 *dir_ptr;
7385c28e
WD
840
841 if (read_bootsectandvi(&bs, &volinfo, &mydata->fatsize)) {
842 debug("Error: reading boot sector\n");
843 return -1;
844 }
845
40e21916
SS
846 if (mydata->fatsize == 32) {
847 root_cluster = bs.root_cluster;
7385c28e 848 mydata->fatlength = bs.fat32_length;
40e21916 849 } else {
7385c28e 850 mydata->fatlength = bs.fat_length;
40e21916 851 }
7385c28e
WD
852
853 mydata->fat_sect = bs.reserved;
854
855 cursect = mydata->rootdir_sect
856 = mydata->fat_sect + mydata->fatlength * bs.fats;
857
ac497771 858 mydata->sect_size = (bs.sector_size[1] << 8) + bs.sector_size[0];
7385c28e 859 mydata->clust_size = bs.cluster_size;
46236b14
KM
860 if (mydata->sect_size != cur_part_info.blksz) {
861 printf("Error: FAT sector size mismatch (fs=%hu, dev=%lu)\n",
862 mydata->sect_size, cur_part_info.blksz);
863 return -1;
864 }
7385c28e
WD
865
866 if (mydata->fatsize == 32) {
867 mydata->data_begin = mydata->rootdir_sect -
868 (mydata->clust_size * 2);
869 } else {
7385c28e
WD
870 rootdir_size = ((bs.dir_entries[1] * (int)256 +
871 bs.dir_entries[0]) *
872 sizeof(dir_entry)) /
ac497771 873 mydata->sect_size;
7385c28e
WD
874 mydata->data_begin = mydata->rootdir_sect +
875 rootdir_size -
876 (mydata->clust_size * 2);
877 }
878
879 mydata->fatbufnum = -1;
3c0ed9c3 880 mydata->fat_dirty = 0;
9a800ac7 881 mydata->fatbuf = memalign(ARCH_DMA_MINALIGN, FATBUFSIZE);
ac497771
SS
882 if (mydata->fatbuf == NULL) {
883 debug("Error: allocating memory\n");
884 return -1;
885 }
71f95118 886
cb940c7e
RG
887 if (vfat_enabled)
888 debug("VFAT Support enabled\n");
889
7385c28e
WD
890 debug("FAT%d, fat_sect: %d, fatlength: %d\n",
891 mydata->fatsize, mydata->fat_sect, mydata->fatlength);
892 debug("Rootdir begins at cluster: %d, sector: %d, offset: %x\n"
893 "Data begins at: %d\n",
894 root_cluster,
895 mydata->rootdir_sect,
ac497771
SS
896 mydata->rootdir_sect * mydata->sect_size, mydata->data_begin);
897 debug("Sector size: %d, cluster size: %d\n", mydata->sect_size,
898 mydata->clust_size);
7385c28e
WD
899
900 /* "cwd" is always the root... */
901 while (ISDIRDELIM(*filename))
902 filename++;
903
904 /* Make a copy of the filename and convert it to lowercase */
905 strcpy(fnamecopy, filename);
906 downcase(fnamecopy);
907
18a10d46 908root_reparse:
7385c28e
WD
909 if (*fnamecopy == '\0') {
910 if (!dols)
ac497771 911 goto exit;
71f95118 912
7385c28e
WD
913 dols = LS_ROOT;
914 } else if ((idx = dirdelim(fnamecopy)) >= 0) {
915 isdir = 1;
916 fnamecopy[idx] = '\0';
917 subname = fnamecopy + idx + 1;
918
919 /* Handle multiple delimiters */
920 while (ISDIRDELIM(*subname))
921 subname++;
922 } else if (dols) {
923 isdir = 1;
71f95118 924 }
71f95118 925
64f65e1e
PM
926 buffer_blk_cnt = 0;
927 firsttime = 1;
7385c28e
WD
928 while (1) {
929 int i;
930
64f65e1e
PM
931 if (mydata->fatsize == 32 || firsttime) {
932 dir_ptr = do_fat_read_at_block;
933 firsttime = 0;
934 } else {
935 /**
936 * FAT16 sector buffer modification:
937 * Each loop, the second buffered block is moved to
938 * the buffer begin, and two next sectors are read
939 * next to the previously moved one. So the sector
940 * buffer keeps always 3 sectors for fat16.
941 * And the current sector is the buffer second sector
942 * beside the "firsttime" read, when it is the first one.
943 *
944 * PREFETCH_BLOCKS is 2 for FAT16 == loop[0:1]
945 * n = computed root dir sector
946 * loop | cursect-1 | cursect | cursect+1 |
947 * 0 | sector n+0 | sector n+1 | none |
948 * 1 | none | sector n+0 | sector n+1 |
949 * 0 | sector n+1 | sector n+2 | sector n+3 |
950 * 1 | sector n+3 | ...
951 */
952 dir_ptr = (do_fat_read_at_block + mydata->sect_size);
953 memcpy(do_fat_read_at_block, dir_ptr, mydata->sect_size);
954 }
955
956 do_read = 1;
957
958 if (mydata->fatsize == 32 && buffer_blk_cnt)
959 do_read = 0;
960
961 if (do_read) {
962 read_blk = (mydata->fatsize == 32) ?
963 mydata->clust_size : PREFETCH_BLOCKS;
964
965 debug("FAT read(sect=%d, cnt:%d), clust_size=%d, DIRENTSPERBLOCK=%zd\n",
966 cursect, read_blk, mydata->clust_size, DIRENTSPERBLOCK);
7385c28e 967
64f65e1e 968 if (disk_read(cursect, read_blk, dir_ptr) < 0) {
cd1b042c
BT
969 debug("Error: reading rootdir block\n");
970 goto exit;
971 }
7385c28e 972
64f65e1e 973 dentptr = (dir_entry *)dir_ptr;
cd1b042c 974 }
7385c28e
WD
975
976 for (i = 0; i < DIRENTSPERBLOCK; i++) {
3831530d 977 char s_name[14], l_name[VFAT_MAXLEN_BYTES];
ff04f6d1 978 __u8 csum;
7385c28e
WD
979
980 l_name[0] = '\0';
3831530d
MZ
981 if (dentptr->name[0] == DELETED_FLAG) {
982 dentptr++;
983 continue;
984 }
ff04f6d1 985
cb940c7e
RG
986 if (vfat_enabled)
987 csum = mkcksum(dentptr->name, dentptr->ext);
988
ff04f6d1 989 if (dentptr->attr & ATTR_VOLUME) {
cb940c7e
RG
990 if (vfat_enabled &&
991 (dentptr->attr & ATTR_VFAT) == ATTR_VFAT &&
7385c28e
WD
992 (dentptr->name[0] & LAST_LONG_ENTRY_MASK)) {
993 prevcksum =
994 ((dir_slot *)dentptr)->alias_checksum;
995
3831530d 996 get_vfatname(mydata,
40e21916 997 root_cluster,
64f65e1e 998 dir_ptr,
7385c28e
WD
999 dentptr, l_name);
1000
1001 if (dols == LS_ROOT) {
1002 char dirc;
1003 int doit = 0;
1004 int isdir =
1005 (dentptr->attr & ATTR_DIR);
1006
1007 if (isdir) {
1008 dirs++;
1009 dirc = '/';
1010 doit = 1;
1011 } else {
1012 dirc = ' ';
1013 if (l_name[0] != 0) {
1014 files++;
1015 doit = 1;
1016 }
1017 }
1018 if (doit) {
1019 if (dirc == ' ') {
1ad0b98a
SR
1020 printf(" %8u %s%c\n",
1021 FAT2CPU32(dentptr->size),
7385c28e
WD
1022 l_name,
1023 dirc);
1024 } else {
1025 printf(" %s%c\n",
1026 l_name,
1027 dirc);
1028 }
1029 }
1030 dentptr++;
1031 continue;
1032 }
1033 debug("Rootvfatname: |%s|\n",
1034 l_name);
cb940c7e 1035 } else {
7385c28e
WD
1036 /* Volume label or VFAT entry */
1037 dentptr++;
1038 continue;
1039 }
1040 } else if (dentptr->name[0] == 0) {
1041 debug("RootDentname == NULL - %d\n", i);
1042 if (dols == LS_ROOT) {
1043 printf("\n%d file(s), %d dir(s)\n\n",
1044 files, dirs);
ac497771 1045 ret = 0;
7385c28e 1046 }
ac497771 1047 goto exit;
71f95118 1048 }
cb940c7e
RG
1049 else if (vfat_enabled &&
1050 dols == LS_ROOT && csum == prevcksum) {
bf34e7d9 1051 prevcksum = 0xffff;
7385c28e
WD
1052 dentptr++;
1053 continue;
71f95118 1054 }
cb940c7e 1055
7385c28e
WD
1056 get_name(dentptr, s_name);
1057
1058 if (dols == LS_ROOT) {
1059 int isdir = (dentptr->attr & ATTR_DIR);
1060 char dirc;
1061 int doit = 0;
1062
1063 if (isdir) {
1064 dirc = '/';
1065 if (s_name[0] != 0) {
1066 dirs++;
1067 doit = 1;
1068 }
1069 } else {
1070 dirc = ' ';
1071 if (s_name[0] != 0) {
1072 files++;
1073 doit = 1;
1074 }
1075 }
1076 if (doit) {
1077 if (dirc == ' ') {
1ad0b98a
SR
1078 printf(" %8u %s%c\n",
1079 FAT2CPU32(dentptr->size),
7385c28e
WD
1080 s_name, dirc);
1081 } else {
1082 printf(" %s%c\n",
1083 s_name, dirc);
1084 }
1085 }
1086 dentptr++;
1087 continue;
1088 }
1089
1090 if (strcmp(fnamecopy, s_name)
1091 && strcmp(fnamecopy, l_name)) {
1092 debug("RootMismatch: |%s|%s|\n", s_name,
1093 l_name);
1094 dentptr++;
1095 continue;
1096 }
1097
1098 if (isdir && !(dentptr->attr & ATTR_DIR))
ac497771 1099 goto exit;
7385c28e
WD
1100
1101 debug("RootName: %s", s_name);
1102 debug(", start: 0x%x", START(dentptr));
1103 debug(", size: 0x%x %s\n",
1104 FAT2CPU32(dentptr->size),
1105 isdir ? "(DIR)" : "");
1106
1107 goto rootdir_done; /* We got a match */
71f95118 1108 }
64f65e1e 1109 debug("END LOOP: buffer_blk_cnt=%d clust_size=%d\n", buffer_blk_cnt,
7385c28e
WD
1110 mydata->clust_size);
1111
1112 /*
1113 * On FAT32 we must fetch the FAT entries for the next
1114 * root directory clusters when a cluster has been
1115 * completely processed.
1116 */
64f65e1e 1117 ++buffer_blk_cnt;
cd1b042c
BT
1118 int rootdir_end = 0;
1119 if (mydata->fatsize == 32) {
64f65e1e 1120 if (buffer_blk_cnt == mydata->clust_size) {
cd1b042c
BT
1121 int nxtsect = 0;
1122 int nxt_clust = 0;
7385c28e 1123
cd1b042c
BT
1124 nxt_clust = get_fatent(mydata, root_cluster);
1125 rootdir_end = CHECK_CLUST(nxt_clust, 32);
7385c28e 1126
cd1b042c
BT
1127 nxtsect = mydata->data_begin +
1128 (nxt_clust * mydata->clust_size);
7385c28e 1129
cd1b042c 1130 root_cluster = nxt_clust;
7385c28e 1131
cd1b042c 1132 cursect = nxtsect;
64f65e1e 1133 buffer_blk_cnt = 0;
cd1b042c 1134 }
71f95118 1135 } else {
64f65e1e
PM
1136 if (buffer_blk_cnt == PREFETCH_BLOCKS)
1137 buffer_blk_cnt = 0;
cd1b042c
BT
1138
1139 rootdir_end = (++cursect - mydata->rootdir_sect >=
1140 rootdir_size);
71f95118 1141 }
3f270f42
EH
1142
1143 /* If end of rootdir reached */
cd1b042c 1144 if (rootdir_end) {
3f270f42
EH
1145 if (dols == LS_ROOT) {
1146 printf("\n%d file(s), %d dir(s)\n\n",
1147 files, dirs);
1ad0b98a 1148 *size = 0;
3f270f42 1149 }
ac497771 1150 goto exit;
3f270f42 1151 }
7385c28e
WD
1152 }
1153rootdir_done:
71f95118 1154
7385c28e 1155 firsttime = 1;
71f95118 1156
7385c28e
WD
1157 while (isdir) {
1158 int startsect = mydata->data_begin
1159 + START(dentptr) * mydata->clust_size;
1160 dir_entry dent;
1161 char *nextname = NULL;
71f95118 1162
7385c28e
WD
1163 dent = *dentptr;
1164 dentptr = &dent;
71f95118 1165
7385c28e
WD
1166 idx = dirdelim(subname);
1167
1168 if (idx >= 0) {
1169 subname[idx] = '\0';
1170 nextname = subname + idx + 1;
1171 /* Handle multiple delimiters */
1172 while (ISDIRDELIM(*nextname))
1173 nextname++;
1174 if (dols && *nextname == '\0')
1175 firsttime = 0;
1176 } else {
1177 if (dols && firsttime) {
1178 firsttime = 0;
1179 } else {
1180 isdir = 0;
1181 }
1182 }
1183
1184 if (get_dentfromdir(mydata, startsect, subname, dentptr,
1185 isdir ? 0 : dols) == NULL) {
1186 if (dols && !isdir)
1ad0b98a 1187 *size = 0;
ac497771 1188 goto exit;
7385c28e
WD
1189 }
1190
7ee46ceb
BT
1191 if (isdir && !(dentptr->attr & ATTR_DIR))
1192 goto exit;
1193
18a10d46
SW
1194 /*
1195 * If we are looking for a directory, and found a directory
1196 * type entry, and the entry is for the root directory (as
1197 * denoted by a cluster number of 0), jump back to the start
1198 * of the function, since at least on FAT12/16, the root dir
1199 * lives in a hard-coded location and needs special handling
1200 * to parse, rather than simply following the cluster linked
1201 * list in the FAT, like other directories.
1202 */
1203 if (isdir && (dentptr->attr & ATTR_DIR) && !START(dentptr)) {
1204 /*
1205 * Modify the filename to remove the prefix that gets
1206 * back to the root directory, so the initial root dir
1207 * parsing code can continue from where we are without
1208 * confusion.
1209 */
1210 strcpy(fnamecopy, nextname ?: "");
1211 /*
1212 * Set up state the same way as the function does when
1213 * first started. This is required for the root dir
1214 * parsing code operates in its expected environment.
1215 */
1216 subname = "";
1217 cursect = mydata->rootdir_sect;
1218 isdir = 0;
1219 goto root_reparse;
1220 }
1221
7ee46ceb 1222 if (idx >= 0)
7385c28e 1223 subname = nextname;
71f95118 1224 }
71f95118 1225
1ad0b98a
SR
1226 if (dogetsize) {
1227 *size = FAT2CPU32(dentptr->size);
1228 ret = 0;
1229 } else {
1230 ret = get_contents(mydata, dentptr, pos, buffer, maxsize, size);
1231 }
1232 debug("Size: %u, got: %llu\n", FAT2CPU32(dentptr->size), *size);
71f95118 1233
ac497771
SS
1234exit:
1235 free(mydata->fatbuf);
7385c28e
WD
1236 return ret;
1237}
71f95118 1238
1ad0b98a
SR
1239int do_fat_read(const char *filename, void *buffer, loff_t maxsize, int dols,
1240 loff_t *actread)
1170e634 1241{
1ad0b98a 1242 return do_fat_read_at(filename, 0, buffer, maxsize, dols, 0, actread);
1170e634
BT
1243}
1244
9795e07b 1245int file_fat_detectfs(void)
71f95118 1246{
7385c28e
WD
1247 boot_sector bs;
1248 volume_info volinfo;
1249 int fatsize;
1250 char vol_label[12];
71f95118 1251
7385c28e 1252 if (cur_dev == NULL) {
7205e407
WD
1253 printf("No current device\n");
1254 return 1;
1255 }
7385c28e 1256
dd60d122 1257#if defined(CONFIG_CMD_IDE) || \
8c5170a7 1258 defined(CONFIG_CMD_SATA) || \
c649e3c9 1259 defined(CONFIG_SCSI) || \
dd60d122 1260 defined(CONFIG_CMD_USB) || \
21f6f963 1261 defined(CONFIG_MMC)
7205e407 1262 printf("Interface: ");
7385c28e
WD
1263 switch (cur_dev->if_type) {
1264 case IF_TYPE_IDE:
1265 printf("IDE");
1266 break;
1267 case IF_TYPE_SATA:
1268 printf("SATA");
1269 break;
1270 case IF_TYPE_SCSI:
1271 printf("SCSI");
1272 break;
1273 case IF_TYPE_ATAPI:
1274 printf("ATAPI");
1275 break;
1276 case IF_TYPE_USB:
1277 printf("USB");
1278 break;
1279 case IF_TYPE_DOC:
1280 printf("DOC");
1281 break;
1282 case IF_TYPE_MMC:
1283 printf("MMC");
1284 break;
1285 default:
1286 printf("Unknown");
7205e407 1287 }
7385c28e 1288
bcce53d0 1289 printf("\n Device %d: ", cur_dev->devnum);
7205e407
WD
1290 dev_print(cur_dev);
1291#endif
7385c28e
WD
1292
1293 if (read_bootsectandvi(&bs, &volinfo, &fatsize)) {
7205e407
WD
1294 printf("\nNo valid FAT fs found\n");
1295 return 1;
1296 }
7385c28e
WD
1297
1298 memcpy(vol_label, volinfo.volume_label, 11);
7205e407 1299 vol_label[11] = '\0';
7385c28e
WD
1300 volinfo.fs_type[5] = '\0';
1301
461f86e6 1302 printf("Filesystem: %s \"%s\"\n", volinfo.fs_type, vol_label);
7385c28e 1303
7205e407 1304 return 0;
71f95118
WD
1305}
1306
9795e07b 1307int file_fat_ls(const char *dir)
71f95118 1308{
1ad0b98a
SR
1309 loff_t size;
1310
1311 return do_fat_read(dir, NULL, 0, LS_YES, &size);
71f95118
WD
1312}
1313
b7b5f319
SW
1314int fat_exists(const char *filename)
1315{
1ad0b98a
SR
1316 int ret;
1317 loff_t size;
1318
1319 ret = do_fat_read_at(filename, 0, NULL, 0, LS_NO, 1, &size);
1320 return ret == 0;
b7b5f319
SW
1321}
1322
d455d878 1323int fat_size(const char *filename, loff_t *size)
cf659819 1324{
d455d878 1325 return do_fat_read_at(filename, 0, NULL, 0, LS_NO, 1, size);
cf659819
SW
1326}
1327
1ad0b98a
SR
1328int file_fat_read_at(const char *filename, loff_t pos, void *buffer,
1329 loff_t maxsize, loff_t *actread)
71f95118 1330{
7385c28e 1331 printf("reading %s\n", filename);
1ad0b98a
SR
1332 return do_fat_read_at(filename, pos, buffer, maxsize, LS_NO, 0,
1333 actread);
1170e634
BT
1334}
1335
1ad0b98a 1336int file_fat_read(const char *filename, void *buffer, int maxsize)
1170e634 1337{
1ad0b98a
SR
1338 loff_t actread;
1339 int ret;
1340
1341 ret = file_fat_read_at(filename, 0, buffer, maxsize, &actread);
1342 if (ret)
1343 return ret;
1344 else
1345 return actread;
71f95118 1346}
e6d52415 1347
d455d878
SR
1348int fat_read_file(const char *filename, void *buf, loff_t offset, loff_t len,
1349 loff_t *actread)
e6d52415 1350{
1ad0b98a 1351 int ret;
e6d52415 1352
d455d878
SR
1353 ret = file_fat_read_at(filename, offset, buf, len, actread);
1354 if (ret)
e6d52415 1355 printf("** Unable to read file %s **\n", filename);
e6d52415 1356
d455d878 1357 return ret;
e6d52415
SG
1358}
1359
1360void fat_close(void)
1361{
1362}