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