GUI: Fix Tomato RAF theme for all builds. Compilation typo.
[tomato.git] / release / src-rt-6.x.4708 / cfe / cfe / main / cfe_fatfs.c
blob93aa5f4b474480be9904e1dbdab5d0744475f5f8
1 /* *********************************************************************
2 * Broadcom Common Firmware Environment (CFE)
3 *
4 * FAT file system File: cfe_fatfs.c
5 *
6 * This module knows how to read files from a FAT formatted
7 * file system (12 or 16 bit fats only for now)
9 * Eventually, we'll also include support for the FAT Translation
10 * Layer (FTL) on PCMCIA flash file systems.
12 * Author: Mitch Lichtenberg (mpl@broadcom.com)
14 *********************************************************************
16 * Copyright 2000,2001,2002,2003
17 * Broadcom Corporation. All rights reserved.
19 * This software is furnished under license and may be used and
20 * copied only in accordance with the following terms and
21 * conditions. Subject to these conditions, you may download,
22 * copy, install, use, modify and distribute modified or unmodified
23 * copies of this software in source and/or binary form. No title
24 * or ownership is transferred hereby.
26 * 1) Any source code used, modified or distributed must reproduce
27 * and retain this copyright notice and list of conditions
28 * as they appear in the source file.
30 * 2) No right is granted to use any trade name, trademark, or
31 * logo of Broadcom Corporation. The "Broadcom Corporation"
32 * name may not be used to endorse or promote products derived
33 * from this software without the prior written permission of
34 * Broadcom Corporation.
36 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
37 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
38 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
39 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
40 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
41 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
42 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
43 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
44 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
45 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
46 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
47 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
48 * THE POSSIBILITY OF SUCH DAMAGE.
49 ********************************************************************* */
52 #include "lib_types.h"
53 #include "lib_string.h"
54 #include "lib_queue.h"
55 #include "lib_malloc.h"
56 #include "lib_printf.h"
58 #include "cfe_error.h"
59 #include "cfe_fileops.h"
60 #include "cfe_iocb.h"
61 #include "cfe_devfuncs.h"
63 #include "cfe_loader.h"
65 #include "cfe.h"
68 /* *********************************************************************
69 * Constants
70 ********************************************************************* */
72 #define SECTORSIZE 512
73 #define DIRENTRYSIZE 32
74 #define DIRPERSECTOR (SECTORSIZE/DIRENTRYSIZE)
76 /*#define _FATFS_DEBUG_*/
79 * Bios Parameter Block offsets and values
82 #define BPB_JMPINSTR 0x00
83 #define BPB_JMPINSTR_VALUE 0xEB
84 #define BPB_JMPINSTR_VALUE2 0xE9
85 #define BPB_SEAL 0x1FE
86 #define BPB_SEAL_VALUE 0xAA55
88 #define BPB_BYTESPERSECTOR 0x0B
89 #define BPB_SECTORSPERCLUSTER 0x0D
90 #define BPB_RESERVEDSECTORS 0x0E
91 #define BPB_NUMFATS 0x10
92 #define BPB_MAXROOTDIR 0x11
93 #define BPB_TOTALSECTORS 0x13
94 #define BPB_SECTORSPERFAT 0x16
95 #define BPB_SECTORSPERTRACK 0x18
96 #define BPB_NUMHEADS 0x1A
97 #define BPB_HIDDENSECTORS 0x1C
98 #define BPB_SYSTEMID 54
99 #define BPB_MEDIADESCRIPTOR 21
100 #define BPB_SIGNATURE 38
101 #define BPB_SIGNATURE_VALUE1 0x28
102 #define BPB_SIGNATURE_VALUE2 0x29
105 * Partition types
108 #define PARTTYPE_EMPTY 0
109 #define PARTTYPE_FAT12 1
110 #define PARTTYPE_FAT16 4
111 #define PARTTYPE_FAT16BIG 6
112 #define PARTTYPE_FAT32 0x0B
115 * Partition table offsets
117 #define PTABLE_STATUS 0
118 #define PTABLE_STARTHEAD 1
119 #define PTABLE_STARTSECCYL 2 /* 2 bytes */
120 #define PTABLE_TYPE 4
121 #define PTABLE_ENDHEAD 5
122 #define PTABLE_ENDSECCYL 6 /* 2 bytes */
123 #define PTABLE_BOOTSECTOR 8 /* 4 bytes */
124 #define PTABLE_NUMSECTORS 12 /* 4 bytes */
126 #define PTABLE_SIZE 16
127 #define PTABLE_COUNT 4
128 #define PTABLE_OFFSET (512-2-(PTABLE_COUNT*PTABLE_SIZE))
130 #define PTABLE_STATUS_ACTIVE 0x80
133 * Directory attributes
136 #define ATTRIB_NORMAL 0x00
137 #define ATTRIB_READONLY 0x01
138 #define ATTRIB_HIDDEN 0x02
139 #define ATTRIB_SYSTEM 0x04
140 #define ATTRIB_LABEL 0x08
141 #define ATTRIB_DIR 0x10
142 #define ATTRIB_ARCHIVE 0x20
144 #define ATTRIB_LFN 0x0F
147 * Macros to read fields in directory & BPB entries
150 #define READWORD(buffer,x) (((unsigned int) (buffer)[(x)]) | \
151 (((unsigned int) (buffer)[(x)+1]) << 8))
153 #define READWORD32(buffer,x) (READWORD(buffer,(x)) | (READWORD(buffer,(x)+2) << 16))
155 #define READBYTE(buffer,x) ((unsigned int) (buffer)[(x)])
158 * Directory entry offsets and values
161 #define DIR_CHECKSUM 13
162 #define DIR_FILELENGTH 28
163 #define DIR_STARTCLUSTER 26
164 #define DIR_ATTRIB 11
165 #define DIR_NAMEOFFSET 0
166 #define DIR_NAMELEN 8
167 #define DIR_EXTOFFSET 8
168 #define DIR_EXTLEN 3
170 #define DIRENTRY_CHECKSUM(e) READBYTE(e,DIR_CHECKSUM)
171 #define DIRENTRY_FILELENGTH(e) READWORD32(e,DIR_FILELENGTH)
172 #define DIRENTRY_STARTCLUSTER(e) READWORD(e,DIR_STARTCLUSTER)
173 #define DIRENTRY_ATTRIB(e) READBYTE(e,DIR_ATTRIB)
175 #define DIRENTRY_LAST 0
176 #define DIRENTRY_DELETED 0xE5
177 #define DIRENTRY_PARENTDIR 0x2E
179 #define DIRENTRY_LFNIDX(e) READBYTE(e,0)
180 #define LFNIDX_MASK 0x1F
181 #define LFNIDX_END 0x40
182 #define LFNIDX_MAX 20
184 /* *********************************************************************
185 * Types
186 ********************************************************************* */
189 * Internalized BPB
192 typedef struct bpb_s {
193 unsigned int bpb_bytespersector;
194 unsigned int bpb_sectorspercluster;
195 unsigned int bpb_reservedsectors;
196 unsigned int bpb_numfats;
197 unsigned int bpb_maxrootdir;
198 unsigned int bpb_totalsectors;
199 unsigned int bpb_sectorsperfat;
200 unsigned int bpb_sectorspertrack;
201 unsigned int bpb_numheads;
202 unsigned int bpb_hiddensectors;
203 } bpb_t;
206 * FAT Filesystem descriptor - contains working information
207 * about an "open" file system
210 typedef struct fatfs_s {
211 int fat_fh;
212 int fat_refcnt;
213 bpb_t fat_bpb;
214 int fat_twelvebit;
215 int fat_partstart;
216 uint8_t fat_dirsector[SECTORSIZE];
217 int fat_dirsecnum;
218 uint8_t fat_fatsector[SECTORSIZE];
219 int fat_fatsecnum;
220 } fatfs_t;
223 * FAT Chain - describes a series of FAT entries
226 typedef struct fatchain_s {
227 int fat_start;
228 uint16_t *fat_entries;
229 int fat_count;
230 } fatchain_t;
233 * FAT File descriptor - contains working information
234 * about an open file (including the filesystem info)
237 typedef struct fatfile_s {
238 fatfs_t *ff_fat;
239 int ff_filelength;
240 fatchain_t ff_chain;
241 int ff_curpos;
242 int ff_cursector;
243 uint8_t ff_sector[SECTORSIZE];
244 } fatfile_t;
246 /* *********************************************************************
247 * Prototypes
248 ********************************************************************* */
250 static int fatfs_fileop_xinit(void **fsctx,void *filename);
251 static int fatfs_fileop_pinit(void **fsctx,void *filename);
252 static int fatfs_fileop_open(void **ref,void *fsctx,char *filename,int mode);
253 static int fatfs_fileop_read(void *ref,uint8_t *buf,int len);
254 static int fatfs_fileop_write(void *ref,uint8_t *buf,int len);
255 static int fatfs_fileop_seek(void *ref,int offset,int how);
256 static void fatfs_fileop_close(void *ref);
257 static void fatfs_fileop_uninit(void *fsctx);
259 static int fatfs_check_for_partition_table(fatfs_t *fatfs);
261 /* *********************************************************************
262 * FAT fileio dispatch table
263 ********************************************************************* */
266 * Raw FAT (no partition table) - used only on floppies
269 const fileio_dispatch_t fatfs_fileops = {
270 "rfat",
271 LOADFLG_NOBB,
272 fatfs_fileop_xinit,
273 fatfs_fileop_open,
274 fatfs_fileop_read,
275 fatfs_fileop_write,
276 fatfs_fileop_seek,
277 fatfs_fileop_close,
278 fatfs_fileop_uninit
282 * Partitioned FAT - used on Zip disks, removable hard disks,
283 * hard disks, flash cards, etc.
286 const fileio_dispatch_t pfatfs_fileops = {
287 "fat",
288 LOADFLG_NOBB,
289 fatfs_fileop_pinit,
290 fatfs_fileop_open,
291 fatfs_fileop_read,
292 fatfs_fileop_write,
293 fatfs_fileop_seek,
294 fatfs_fileop_close,
295 fatfs_fileop_uninit
299 /* *********************************************************************
300 * fat_readsector(fatfs,sector,numsec,buffer)
302 * Read one or more sectors from the disk into memory
304 * Input parameters:
305 * fatfs - fat filesystem descriptor
306 * sector - sector number
307 * numsec - number of sectors to read
308 * buffer - buffer to read sectors into
310 * Return value:
311 * 0 if ok
312 * else error code
313 ********************************************************************* */
315 static int fat_readsector(fatfs_t *fatfs,int sector,int numsec,uint8_t *buffer)
317 int res;
319 res = cfe_readblk(fatfs->fat_fh,(sector+fatfs->fat_partstart)*SECTORSIZE,
320 buffer,numsec*SECTORSIZE);
322 if (res != numsec*SECTORSIZE) return CFE_ERR_IOERR;
324 return 0;
328 /* *********************************************************************
329 * fat_dumpbpb(bpb)
331 * Debug function; display fields in a BPB
333 * Input parameters:
334 * bpb - BIOS parameter block structure
336 * Return value:
337 * nothing
338 ********************************************************************* */
340 #ifdef _FATFS_DEBUG_
341 static void fat_dumpbpb(bpb_t *bpb)
343 xprintf("Bytes per sector %d\n",bpb->bpb_bytespersector);
344 xprintf("Sectors per cluster %d\n",bpb->bpb_sectorspercluster);
345 xprintf("Reserved sectors %d\n",bpb->bpb_reservedsectors);
346 xprintf("Number of FATs %d\n",bpb->bpb_numfats);
347 xprintf("Root dir entries %d\n",bpb->bpb_maxrootdir);
348 xprintf("Total sectors %d\n",bpb->bpb_totalsectors);
349 xprintf("Sectors per FAT %d\n",bpb->bpb_sectorsperfat);
350 xprintf("Sectors per track %d\n",bpb->bpb_sectorspertrack);
351 xprintf("Number of heads %d\n",bpb->bpb_numheads);
352 xprintf("Hidden sectors %d\n",bpb->bpb_hiddensectors);
354 #endif
356 /* *********************************************************************
357 * fat_findpart(fatfs)
359 * For partitioned disks, locate the active partition
360 * and set "fat_partstart" accordingly
362 * Input parameters:
363 * fatfs - FAT filesystem descriptor
365 * Return value:
366 * 0 if we found a valid partition table; else error code
367 ********************************************************************* */
369 static int fat_findpart(fatfs_t *fatfs)
371 uint8_t buffer[SECTORSIZE];
372 uint8_t *part;
373 int res;
374 int idx;
376 fatfs->fat_partstart = 0; /* make sure we get real boot sector */
377 res = fat_readsector(fatfs,0,1,buffer);
378 if (res < 0) return res;
381 * Normally you're supposed to check for a JMP instruction.
382 * At least that's what many people do. Flash MBRs don't start
383 * with JMP instructions, so just look for the seal.
386 * if (READBYTE(buffer,BPB_JMPINSTR) != BPB_JMPINSTR_VALUE) {
387 * return CFE_ERR_BADFILESYS;
392 * Check the seal at the end of th sector
395 if (READWORD(buffer,BPB_SEAL) != BPB_SEAL_VALUE) return CFE_ERR_BADFILESYS;
398 * Look for an active FAT partition. The partition we want must
399 * be the active one. We do not deal with extended partitions
400 * here. Hey, this is supposed to be boot code!
403 part = &buffer[PTABLE_OFFSET];
404 for (idx = 0; idx < PTABLE_COUNT; idx++) {
405 if ((part[PTABLE_STATUS] == PTABLE_STATUS_ACTIVE) &&
406 ((part[PTABLE_TYPE] == PARTTYPE_FAT12) ||
407 (part[PTABLE_TYPE] == PARTTYPE_FAT16) ||
408 (part[PTABLE_TYPE] == PARTTYPE_FAT16BIG))) {
409 break;
412 part += PTABLE_SIZE;
415 if (idx == PTABLE_COUNT) return CFE_ERR_BADFILESYS;
418 * The info we want is really just the pointer to the
419 * boot (BPB) sector. Get that and we'll use it for an
420 * offset into the disk later.
423 fatfs->fat_partstart = READWORD32(part,PTABLE_BOOTSECTOR);
425 return 0;
429 /* *********************************************************************
430 * fat_readbpb(fatfs)
432 * Read and internalize the BIOS Parameter Block
434 * Input parameters:
435 * fatfs - FAT filesystem descriptor
437 * Return value:
438 * 0 if ok
439 * else error code (usually, BPB is not valid)
440 ********************************************************************* */
442 static int fat_readbpb(fatfs_t *fatfs)
444 uint8_t buffer[SECTORSIZE];
445 int res;
447 res = fat_readsector(fatfs,0,1,buffer);
448 if (res < 0) return res;
450 if (READBYTE(buffer,BPB_JMPINSTR) != BPB_JMPINSTR_VALUE) return CFE_ERR_BADFILESYS;
451 if (READWORD(buffer,BPB_SEAL) != BPB_SEAL_VALUE) return CFE_ERR_BADFILESYS;
453 fatfs->fat_bpb.bpb_bytespersector = READWORD(buffer,BPB_BYTESPERSECTOR);
454 fatfs->fat_bpb.bpb_sectorspercluster = READBYTE(buffer,BPB_SECTORSPERCLUSTER);
455 fatfs->fat_bpb.bpb_reservedsectors = READWORD(buffer,BPB_RESERVEDSECTORS);
456 fatfs->fat_bpb.bpb_numfats = READBYTE(buffer,BPB_NUMFATS);
457 fatfs->fat_bpb.bpb_maxrootdir = READWORD(buffer,BPB_MAXROOTDIR);
458 fatfs->fat_bpb.bpb_totalsectors = READWORD(buffer,BPB_TOTALSECTORS);
459 fatfs->fat_bpb.bpb_sectorsperfat = READWORD(buffer,BPB_SECTORSPERFAT);
460 fatfs->fat_bpb.bpb_sectorspertrack = READWORD(buffer,BPB_SECTORSPERTRACK);
461 fatfs->fat_bpb.bpb_numheads = READWORD(buffer,BPB_NUMHEADS);
462 fatfs->fat_bpb.bpb_hiddensectors = READWORD(buffer,BPB_HIDDENSECTORS);
464 fatfs->fat_twelvebit = 1;
465 if (memcmp(&buffer[0x36],"FAT16 ",8) == 0) fatfs->fat_twelvebit = 0;
467 if (fatfs->fat_bpb.bpb_bytespersector != SECTORSIZE) return CFE_ERR_BADFILESYS;
468 if (fatfs->fat_bpb.bpb_numfats > 2) return CFE_ERR_BADFILESYS;
471 #ifdef _FATFS_DEBUG_
472 fat_dumpbpb(&(fatfs->fat_bpb));
473 #endif
475 return 0;
480 /* *********************************************************************
481 * fat_getentry(fatfs,entry)
483 * Read a FAT entry. This is more involved than you'd think,
484 * since we have to deal with 12 and 16 (and someday 32) bit FATs,
485 * and the nasty case where a 12-bit FAT entry crosses a sector
486 * boundary.
488 * Input parameters:
489 * fatfs - FAT filesystem descriptor
490 * entry - index of FAT entry
492 * Return value:
493 * FAT entry, or <0 if an error occured
494 ********************************************************************* */
496 static int fat_getfatentry(fatfs_t *fatfs,int entry)
498 int fatsect;
499 int byteoffset;
500 int fatstart;
501 int fatoffset;
502 uint8_t b1,b2,b3;
503 int res;
505 fatstart = fatfs->fat_bpb.bpb_reservedsectors;
507 if (fatfs->fat_twelvebit) {
508 int odd;
509 odd = entry & 1;
510 byteoffset = ((entry & ~1) * 3) / 2;
511 fatsect = byteoffset / SECTORSIZE;
512 fatoffset = byteoffset % SECTORSIZE;
514 if (fatfs->fat_fatsecnum != fatsect) {
515 res = fat_readsector(fatfs,fatsect+fatstart,1,fatfs->fat_fatsector);
516 if (res < 0) {
517 return res;
519 fatfs->fat_fatsecnum = fatsect;
522 b1 = fatfs->fat_fatsector[fatoffset];
524 if ((fatoffset+1) >= SECTORSIZE) {
525 res = fat_readsector(fatfs,fatsect+1+fatstart,1,fatfs->fat_fatsector);
526 if (res < 0) {
527 return res;
529 fatfs->fat_fatsecnum = fatsect+1;
530 fatoffset -= SECTORSIZE;
533 b2 = fatfs->fat_fatsector[fatoffset+1];
535 if ((fatoffset+2) >= SECTORSIZE) {
536 res = fat_readsector(fatfs,fatsect+1+fatstart,1,fatfs->fat_fatsector);
537 if (res < 0) {
538 return res;
540 fatfs->fat_fatsecnum = fatsect+1;
541 fatoffset -= SECTORSIZE;
544 b3 = fatfs->fat_fatsector[fatoffset+2];
546 if (odd) {
547 return ((unsigned int) b3 << 4) + ((unsigned int) (b2 & 0xF0) >> 4);
549 else {
550 return ((unsigned int) (b2 & 0x0F) << 8) + ((unsigned int) b1);
554 else {
555 byteoffset = entry * 2;
556 fatsect = byteoffset / SECTORSIZE;
557 fatoffset = byteoffset % SECTORSIZE;
559 if (fatfs->fat_fatsecnum != fatsect) {
560 res = fat_readsector(fatfs,fatsect+fatstart,1,fatfs->fat_fatsector);
561 if (res < 0) {
562 return res;
564 fatfs->fat_fatsecnum = fatsect;
567 b1 = fatfs->fat_fatsector[fatoffset];
568 b2 = fatfs->fat_fatsector[fatoffset+1];
569 return ((unsigned int) b1) + (((unsigned int) b2) << 8);
573 /* *********************************************************************
574 * fat_getrootdirentry(fatfs,entryidx,entry)
576 * Read a root directory entry. The FAT12/16 root directory
577 * is a contiguous group of sectors, whose size is specified in
578 * the BPB. This routine just digs out an entry from there
580 * Input parameters:
581 * fatfs - FAT filesystem descriptor
582 * entryidx - 0-based entry index to read
583 * entry - pointer to directory entry (32 bytes)
585 * Return value:
586 * 0 if ok
587 * <0 if error occured
588 ********************************************************************* */
590 static int fat_getrootdirentry(fatfs_t *fatfs,int entryidx,uint8_t *entry)
592 int rootdirstart;
593 int rootdirsize;
594 int dirsecnum;
595 int res;
597 if (entryidx >= fatfs->fat_bpb.bpb_maxrootdir) {
598 memset(entry,0,DIRENTRYSIZE);
599 return CFE_ERR_INV_PARAM;
602 rootdirstart = fatfs->fat_bpb.bpb_reservedsectors +
603 fatfs->fat_bpb.bpb_numfats * fatfs->fat_bpb.bpb_sectorsperfat;
605 rootdirsize = fatfs->fat_bpb.bpb_maxrootdir / DIRENTRYSIZE;
607 dirsecnum = rootdirstart + entryidx / DIRPERSECTOR;
609 if (fatfs->fat_dirsecnum != dirsecnum) {
610 res = fat_readsector(fatfs,dirsecnum,1,fatfs->fat_dirsector);
611 if (res < 0) {
612 return res;
614 fatfs->fat_dirsecnum = dirsecnum;
617 memcpy(entry,&(fatfs->fat_dirsector[(entryidx % DIRPERSECTOR)*DIRENTRYSIZE]),
618 DIRENTRYSIZE);
620 return 0;
623 /* *********************************************************************
624 * fat_checksumname(name)
626 * Calculate the "long filename" checksum for a given short name.
627 * All LFN directory entries associated with the short name are
628 * given the same checksum byte, to help keep the long name
629 * consistent.
631 * Input parameters:
632 * name - pointer to 32-byte directory entry
634 * Return value:
635 * checksum value
636 ********************************************************************* */
638 static uint8_t fat_checksumname(uint8_t *name)
640 uint8_t sum = 0;
641 uint8_t newbit;
642 int idx;
644 for (idx = 0; idx < 11; idx++) {
645 newbit = (sum & 1) ? 0x80 : 0x00;
646 sum >>= 1;
647 sum |= newbit;
648 sum += name[idx];
651 return sum;
654 #ifdef _FATFS_DEBUG_
655 void fat_dumpdirentry(uint8_t *entry);
656 void fat_dumpdirentry(uint8_t *entry)
658 uint8_t name[32];
659 int idx;
661 if (entry[11] != ATTRIB_LFN) {
662 memcpy(name,entry,11);
663 name[11] = 0;
664 xprintf("%s %02X %04X %d\n",
665 name,DIRENTRY_ATTRIB(entry),
666 DIRENTRY_STARTCLUSTER(entry),
667 DIRENTRY_FILELENGTH(entry));
669 else {
670 for (idx = 0; idx < 5; idx++) {
671 name[idx] = entry[(idx*2)+1];
673 for (idx = 0; idx < 6; idx++) {
674 name[idx+5] = entry[(idx*2)+14];
676 for (idx = 0; idx < 2; idx++) {
677 name[idx+11] = entry[(idx*2)+28];
679 name[13] = '\0';
680 xprintf("%02X: %s %04X cksum %02X\n",entry[0],
681 name,READWORD(entry,0x1A),entry[13]);
684 #endif
687 /* *********************************************************************
688 * fat_walkfatchain(fat,start,arg,func)
690 * Walk a FAT chain, calling a callback routine for each entry
691 * we find along the way.
693 * Input parameters:
694 * fat - FAT filesystem descriptor
695 * start - starting FAT entry (from the directory, usually)
696 * arg - argument to pass to callback routine
697 * func - function to call for each FAT entry
699 * Return value:
700 * 0 if all elements processed
701 * <0 if error occured
702 * >0 if callback routine returned a nonzero value
703 ********************************************************************* */
705 static int fat_walkfatchain(fatfs_t *fat,int start,
706 void *arg,
707 int (*func)(fatfs_t *fat,
708 int e,
709 int prev_e,
710 void *arg))
712 int prev_e = 0;
713 int ending_e;
714 int e;
715 int res = 0;
717 e = start;
719 /* Note: ending FAT entry can be 0x(F)FF8..0x(F)FFF. We assume that the
720 'getfatentry' call won't return values above that. */
721 if (fat->fat_twelvebit) {
722 ending_e = 0xFF8;
724 else {
725 ending_e = 0xFFF8;
728 while (e < ending_e) {
729 res = (*func)(fat,e,prev_e,arg);
730 if (res) break;
731 prev_e = e;
732 e = fat_getfatentry(fat,e);
733 if (e < 0) return e;
736 return res;
739 /* *********************************************************************
740 * fat_getwalkfunc(fat,e,prev_e,arg)
742 * Callback routien to collect all of the FAT entries into
743 * a FAT chain descriptor
745 * Input parameters:
746 * fat - FAT filesystem descriptor
747 * e - current entry
748 * prev_e - previous entry (0 if first entry)
749 * arg - argument passed to fat_walkfatchain
751 * Return value:
752 * 0 to keep walking
753 * else value to return from fat_walkfatchain
754 ********************************************************************* */
756 static int fat_getwalkfunc(fatfs_t *fat,int e,
757 int prev_e,void *arg)
759 fatchain_t *chain = arg;
761 if (chain->fat_entries) {
762 chain->fat_entries[chain->fat_count] = (uint16_t) e;
765 chain->fat_count++;
767 return 0;
770 /* *********************************************************************
771 * fat_getchain(fat,start,chain)
773 * Walk an entire FAT chain and remember the chain in a
774 * FAT chain descriptor
776 * Input parameters:
777 * fat - FAT filesystem descriptor
778 * start - starting FAT entry
779 * chain - chain descriptor
781 * Return value:
782 * 0 if ok
783 * else error code
784 ********************************************************************* */
786 static int fat_getchain(fatfs_t *fat,int start,fatchain_t *chain)
788 int res;
790 chain->fat_entries = NULL;
791 chain->fat_count = 0;
792 chain->fat_start = start;
795 * walk once to count the entries.
797 * For regular files, you probably don't have to do this
798 * since you can predict exactly how many FAT entries
799 * there are given the file length.
802 res = fat_walkfatchain(fat,start,chain,fat_getwalkfunc);
803 if (res < 0) return res;
806 * allocate space for the entries. Include one extra
807 * slot for the first entry, since the first entry
808 * does not actually appear in the FAT (the fat is
809 * only the 'next' pointers).
812 if (chain->fat_count == 0) return 0;
813 chain->fat_entries = KMALLOC((chain->fat_count+1)*sizeof(uint16_t),0);
814 chain->fat_count = 0;
817 * walk again to collect entries
819 res = fat_walkfatchain(fat,start,chain,fat_getwalkfunc);
820 if (res < 0) return res;
822 return chain->fat_count;
826 /* *********************************************************************
827 * fat_freechain(chain)
829 * Free memory associated with a FAT chain
831 * Input parameters:
832 * chain - chain descriptor
834 * Return value:
835 * nothing
836 ********************************************************************* */
838 static void fat_freechain(fatchain_t *chain)
840 if (chain->fat_entries) {
841 KFREE(chain->fat_entries);
842 chain->fat_entries = NULL;
844 chain->fat_count = 0;
847 /* *********************************************************************
848 * fat_clusteridx(fat,chain,idx)
850 * Index into a FAT chain and return the nth cluster number
851 * from the chain
853 * Input parameters:
854 * fat - fat filesystem descriptor
855 * chain - chain descriptor
856 * idx - index into FAT chain
858 * Return value:
859 * FAT entry at the nth index, or
860 * <0 if an error occured
861 ********************************************************************* */
862 static int fat_clusteridx(fatfs_t *fat,fatchain_t *chain,int idx)
864 if (idx >= chain->fat_count) return CFE_ERR_INV_PARAM; /* error! */
865 return (int) (unsigned int) chain->fat_entries[idx];
868 /* *********************************************************************
869 * fat_sectoridx(fat,chain,idx)
871 * Return the sector nunber of the nth sector in a given
872 * FAT chain. This routine knows how to translate cluster
873 * numbers into sector numbers.
875 * Input parameters:
876 * fat - FAT filesystem descriptor
877 * chain - FAT chain
878 * idx - index of which sector to find
880 * Return value:
881 * sector number
882 * <0 if an error occured
883 ********************************************************************* */
884 static int fat_sectoridx(fatfs_t *fat,fatchain_t *chain,int idx)
886 int clusteridx;
887 int sectoridx;
888 int sector;
889 int fatentry;
891 clusteridx = idx / fat->fat_bpb.bpb_sectorspercluster;
892 sectoridx = idx % fat->fat_bpb.bpb_sectorspercluster;
894 fatentry = fat_clusteridx(fat,chain,clusteridx);
896 if (fatentry < 0) xprintf("ran off end of fat chain!\n");
897 if (fatentry < 2) xprintf("fat entries should be >= 2\n");
899 sector = fat->fat_bpb.bpb_reservedsectors +
900 (fat->fat_bpb.bpb_maxrootdir * DIRENTRYSIZE)/SECTORSIZE +
901 (fat->fat_bpb.bpb_numfats * fat->fat_bpb.bpb_sectorsperfat) +
902 (fatentry - 2) * fat->fat_bpb.bpb_sectorspercluster +
903 sectoridx;
905 return sector;
908 /* *********************************************************************
909 * fat_getsubdirentry(fat,chain,idx,direntry)
911 * This routine is similar to fat_getrootdirentry except it
912 * works on a subdirectory. FAT subdirectories are like files
913 * containing directory entries, so we use the "get nth sector
914 * in chain" routines to walk the chains of sectors reading directory
915 * entries.
917 * Input parameters:
918 * fat - FAT filesystem descriptor
919 * chain - FAT chain
920 * idx - index of entry to read
921 * direntry - place to put directory entry we read
923 * Return value:
924 * 0 if ok
925 * else error code
926 ********************************************************************* */
928 static int fat_getsubdirentry(fatfs_t *fat,fatchain_t *chain,
929 int idx,uint8_t *direntry)
931 int sector;
932 int res;
934 sector = fat_sectoridx(fat,chain,idx/DIRPERSECTOR);
936 if (sector < 0) return sector;
938 if (fat->fat_dirsecnum != sector) {
939 res = fat_readsector(fat,sector,1,fat->fat_dirsector);
940 if (res < 0) {
941 return res;
943 fat->fat_dirsecnum = sector;
946 memcpy(direntry,&(fat->fat_dirsector[(idx % DIRPERSECTOR)*DIRENTRYSIZE]),
947 DIRENTRYSIZE);
949 return 0;
952 /* *********************************************************************
953 * fat_getshortname(direntry,name)
955 * Read the short filename from a directory entry, converting
956 * it into its classic 8.3 form
958 * Input parameters:
959 * direntry - directory entry
960 * name - place to put 8.3 name
962 * Return value:
963 * nothing
964 ********************************************************************* */
966 static void fat_getshortname(uint8_t *direntry,char *name)
968 int idx;
971 * Collect the base file name
974 for (idx = DIR_NAMEOFFSET; idx < (DIR_NAMEOFFSET+DIR_NAMELEN); idx++) {
975 if (direntry[idx] == ' ') break;
976 *name++ = direntry[idx];
980 * Put in the dot for the extension only if there
981 * is an extension.
984 if (direntry[DIR_EXTOFFSET] != ' ') *name++ = '.';
987 * Collect the extension
990 for (idx = DIR_EXTOFFSET; idx < (DIR_EXTOFFSET+DIR_EXTLEN); idx++) {
991 if (direntry[idx] == ' ') break;
992 *name++ = direntry[idx];
995 *name = '\0';
999 /* *********************************************************************
1000 * fat_getlongname(fat,chain,diridx,shortentry,longname)
1002 * Look backwards in the directory to locate the long file name
1003 * that corresponds to the short file name passed in 'shortentry'
1005 * Input parameters:
1006 * fat - FAT filesystem descriptor
1007 * chain - chain describing current directory, or NULL
1008 * if the current directory is the root directory
1009 * diridx - index of the short file name
1010 * shortentry - points to the short directory entry
1011 * longname - buffer to receive long file name (up to 261 chars)
1013 * Return value:
1014 * 0 if ok
1015 * else error code
1016 ********************************************************************* */
1018 static int fat_getlongname(fatfs_t *fat,fatchain_t *chain,int diridx,
1019 uint8_t *shortentry,char *longname)
1021 int lfnidx = 1;
1022 uint8_t checksum;
1023 uint8_t direntry[DIRENTRYSIZE];
1024 int idx;
1025 char *lfnptr;
1026 int badlfn = 0;
1028 *longname = '\0';
1031 * idx is the entry # of the short name
1034 checksum = fat_checksumname(shortentry);
1037 * Start working backwards from current entry
1038 * and collect pieces of the lfn
1041 lfnptr = longname;
1042 diridx--;
1044 while (diridx > 0) {
1047 * Read previous entry
1050 if (chain) {
1051 fat_getsubdirentry(fat,chain,diridx,direntry);
1053 else {
1054 fat_getrootdirentry(fat,diridx,direntry);
1058 * Checksum must match, it must have the right entry index,
1059 * and it must have the LFN attribute
1062 if (DIRENTRY_CHECKSUM(direntry) != checksum) {
1063 badlfn = 1;
1064 break;
1066 if ((DIRENTRY_LFNIDX(direntry) & LFNIDX_MASK) != lfnidx) {
1067 badlfn = 1;
1068 break;
1071 if (DIRENTRY_ATTRIB(direntry) != ATTRIB_LFN) {
1072 badlfn = 1;
1073 break;
1077 * Collect the chars from the filename. Note we
1078 * don't deal well with real unicode chars here.
1081 for (idx = 0; idx < 5; idx++) {
1082 *lfnptr++ = direntry[(idx*2)+1];
1084 for (idx = 0; idx < 6; idx++) {
1085 *lfnptr++ = direntry[(idx*2)+14];
1087 for (idx = 0; idx < 2; idx++) {
1088 *lfnptr++ = direntry[(idx*2)+28];
1092 * Don't go too far
1095 if (DIRENTRY_LFNIDX(direntry) & LFNIDX_END) break;
1096 lfnidx++;
1097 if (lfnidx > LFNIDX_MAX) {
1098 badlfn = 1;
1099 break;
1102 diridx--;
1106 * Null terminate the lfn
1109 *lfnptr = 0;
1111 if (badlfn) {
1112 longname[0] = 0;
1113 return CFE_ERR_FILENOTFOUND;
1116 return 0;
1120 /* *********************************************************************
1121 * fat_scandir(fat,chain,name,direntry)
1123 * Scan a single directory looking for a file name
1125 * Input parameters:
1126 * fat - FAT filesystem descriptor
1127 * chain - FAT chain for directory or NULL for root directory
1128 * name - name of file to look for (short or long name)
1129 * direntry - place to put directory entry if we find one
1131 * Return value:
1132 * 1 if name was found
1133 * 0 if name was not found
1134 * else <0 is error code
1135 ********************************************************************* */
1138 static int fat_scandir(fatfs_t *fat,fatchain_t *chain,
1139 char *name,uint8_t *direntry)
1141 int idx;
1142 int count;
1143 char shortname[16];
1144 char longname[280];
1147 * Get directory size
1150 if (chain) {
1151 count = (chain->fat_count * fat->fat_bpb.bpb_sectorspercluster) * DIRPERSECTOR;
1153 else {
1154 count = (int) fat->fat_bpb.bpb_maxrootdir;
1158 * Scan whole directory
1161 for (idx = 0; idx < count; idx++) {
1164 * Get entry by root or chain depending...
1167 if (chain) {
1168 fat_getsubdirentry(fat,chain,idx,direntry);
1170 else {
1171 fat_getrootdirentry(fat,idx,direntry);
1175 * Ignore stuff we don't want to see
1178 if (direntry[0] == DIRENTRY_LAST) break; /* stop if at end of dir */
1179 if (direntry[0] == DIRENTRY_DELETED) continue; /* skip deleted entries */
1180 if (direntry[0] == DIRENTRY_PARENTDIR) continue; /* skip ./.. entries */
1182 if (DIRENTRY_ATTRIB(direntry) == ATTRIB_LFN) continue; /* skip LFNs */
1183 if (DIRENTRY_ATTRIB(direntry) & ATTRIB_LABEL) continue; /* skip volume labels */
1186 * Get actual file names from directory
1189 fat_getshortname(direntry,shortname);
1190 fat_getlongname(fat,chain,idx,direntry,longname);
1193 if (name) {
1194 if (strcmpi(name,shortname) == 0) return 1;
1195 if (longname[0] && (strcmpi(name,longname) == 0)) return 1;
1197 else {
1198 xprintf("%-30s",longname[0] ? longname : shortname);
1199 // xprintf(" Clus=%04X",DIRENTRY_STARTCLUSTER(direntry));
1200 // xprintf(" Attrib=%02X",DIRENTRY_ATTRIB(direntry));
1201 // xprintf(" Size=%d",DIRENTRY_FILELENGTH(direntry));
1202 xprintf("%d",DIRENTRY_FILELENGTH(direntry));
1203 xprintf("\n");
1207 return 0;
1210 /* *********************************************************************
1211 * fat_findfile(fat,name,direntry)
1213 * Locate a directory entry given a complete path name
1215 * Input parameters:
1216 * fat - FAT filesystem descriptor
1217 * name - name of file to locate (forward or reverse slashses ok)
1218 * direntry - place to put directory entry we find
1220 * Return value:
1221 * 0 if file not found
1222 * 1 if file was found
1223 * <0 if error occurs
1224 ********************************************************************* */
1226 static int fat_findfile(fatfs_t *fat,char *name,uint8_t *direntry)
1228 char *namecopy;
1229 char *namepart;
1230 char *ptr;
1231 fatchain_t chain;
1232 int res;
1233 int e;
1236 * Copy the name, we're going to hack it up
1239 namecopy = strdup(name);
1242 * Chew off the first piece up to the first slash. Remove
1243 * a leading slash if it is there.
1246 ptr = namecopy;
1248 if ((*ptr == '/') || (*ptr == '\\')) ptr++;
1250 namepart = ptr;
1251 while (*ptr && (*ptr != '/') && (*ptr != '\\')) ptr++;
1252 if (*ptr) *ptr++ = '\0';
1255 * Scan the root directory looking for the first piece
1258 res = fat_scandir(fat,NULL,namepart,direntry);
1259 if (res == 0) {
1260 KFREE(namecopy);
1261 return 0; /* file not found */
1266 * Start scanning subdirectories until we run out
1267 * of directory components.
1270 namepart = ptr;
1271 while (*ptr && (*ptr != '/') && (*ptr != '\\')) ptr++;
1272 if (*ptr) *ptr++ = '\0';
1273 if (!*namepart) namepart = NULL;
1276 while (namepart) {
1279 * Scan the subdirectory
1282 e = DIRENTRY_STARTCLUSTER(direntry);
1283 memset(&chain,0,sizeof(chain));
1284 fat_getchain(fat,e,&chain);
1285 res = fat_scandir(fat,&chain,namepart,direntry);
1286 if (res == 0) {
1287 break;
1289 fat_freechain(&chain);
1292 * Advance to the next piece
1295 namepart = ptr;
1296 while (*ptr && (*ptr != '/') && (*ptr != '\\')) ptr++;
1297 if (*ptr) *ptr++ = '\0';
1298 if (!*namepart) namepart = NULL;
1301 * If there's more to go and we hit something that
1302 * is not a directory, stop here.
1305 if (namepart && !(DIRENTRY_ATTRIB(direntry) & ATTRIB_DIR)) {
1306 res = 0;
1310 KFREE(namecopy);
1313 * The last piece we enumerate has to be a file.
1316 if ((res > 0) &&
1317 (DIRENTRY_ATTRIB(direntry) & ATTRIB_DIR)) {
1318 return 0;
1321 return res;
1325 /* *********************************************************************
1326 * fat_init(fat,name)
1328 * Create the filesystem descriptor and attach to the hardware
1329 * device.
1331 * Input parameters:
1332 * fat - filesystem descriptor
1333 * name - hardware device name
1334 * part - true to look for partition tables
1336 * Return value:
1337 * 0 if ok
1338 * else error code
1339 ********************************************************************* */
1341 static int fat_init(fatfs_t *fat,char *name,int part)
1343 int res;
1345 memset(fat,0,sizeof(fatfs_t));
1346 fat->fat_dirsecnum = -1;
1347 fat->fat_fatsecnum = -1;
1349 fat->fat_fh = cfe_open(name);
1351 if (fat->fat_fh < 0) return fat->fat_fh;
1353 res = fatfs_check_for_partition_table(fat);
1354 /* If we were able to figure it out, use that as the default */
1355 if (res >= 0) part = res;
1357 if (part) {
1358 res = fat_findpart(fat);
1359 if (res < 0) {
1360 cfe_close(fat->fat_fh);
1361 fat->fat_fh = -1;
1362 return res;
1366 res = fat_readbpb(fat);
1367 if (res != 0) {
1368 cfe_close(fat->fat_fh);
1369 fat->fat_fh = -1;
1370 return res;
1373 return 0;
1376 /* *********************************************************************
1377 * fat_uninit(fat)
1379 * Uninit the filesystem descriptor and release any resources
1380 * we allocated.
1382 * Input parameters:
1383 * fat - filesystem descriptor
1385 * Return value:
1386 * nothing
1387 ********************************************************************* */
1389 static void fat_uninit(fatfs_t *fat)
1391 if (fat->fat_fh >= 0) cfe_close(fat->fat_fh);
1392 fat->fat_fh = -1;
1395 int fatfs_fileop_dir(void *fsctx);
1396 int fatfs_fileop_dir(void *fsctx)
1398 fatfs_t *fatfs = fsctx;
1399 uint8_t direntry[32];
1401 fat_scandir(fatfs,NULL,NULL,direntry);
1403 return 0;
1406 /* *********************************************************************
1407 * fatfs_fileop_init(fsctx,devname)
1409 * Create a FAT filesystem context and open the associated
1410 * block device.
1412 * Input parameters:
1413 * fsctx - file system context (return pointer)
1414 * devname - device name to open
1415 * part - true to look for a partition table
1417 * Return value:
1418 * 0 if ok, else error
1419 ********************************************************************* */
1421 static int fatfs_fileop_init(void **fsctx,char *devname,int part)
1423 int res;
1424 fatfs_t *fatfs;
1427 * Allocate a file system context
1430 fatfs = (fatfs_t *) KMALLOC(sizeof(fatfs_t),0);
1431 if (!fatfs) return CFE_ERR_NOMEM;
1434 * Open a handle to the underlying device
1437 res = fat_init(fatfs,devname,part);
1438 if (res != 0) {
1439 KFREE(fatfs);
1440 return res;
1443 *fsctx = fatfs;
1445 return 0;
1448 /* *********************************************************************
1449 * fatfs_check_for_partition_table(fatfs)
1451 * This routine attempts to determine if the disk contains a
1452 * partition table or if it contains a standard MS-DOS boot recod.
1453 * We try to find both, and return what we find, or an error
1454 * if it is still unclear.
1456 * Input parameters:
1457 * fatfs - fat filesystem context
1459 * Return value:
1460 * 0 if no partition table
1461 * 1 if partition table
1462 * <0 = error occured, could not tell or I/O error
1463 ********************************************************************* */
1465 static int fatfs_check_for_partition_table(fatfs_t *fatfs)
1467 int res;
1468 uint8_t buffer[SECTORSIZE];
1469 uint8_t *part;
1470 int idx;
1471 int foundit = 0;
1474 * Read sector 0
1477 fatfs->fat_partstart = 0;
1478 res = fat_readsector(fatfs,0,1,buffer);
1479 if (res < 0) return res;
1482 * Check the seal at the end of th sector. Both
1483 * boot sector and MBR should contain this seal.
1485 if (READWORD(buffer,BPB_SEAL) != BPB_SEAL_VALUE) {
1486 res = CFE_ERR_BADFILESYS;
1487 return res;
1491 * See Microsoft Knowledgebase article # Q140418, it contains
1492 * a good description of the boot sector format.
1494 * If the extended information is present, and SystemID is "FAT"
1495 * and the "bytes per sector" is 512, assume it's a regular boot block
1498 if (((buffer[BPB_SIGNATURE] == BPB_SIGNATURE_VALUE1) ||
1499 (buffer[BPB_SIGNATURE] == BPB_SIGNATURE_VALUE2)) &&
1500 (memcmp(&buffer[BPB_SYSTEMID],"FAT",3) == 0) &&
1501 (READWORD(buffer,BPB_BYTESPERSECTOR) == 512)) {
1502 /* Not partitioned */
1503 res = 0;
1504 return res;
1507 /* If no extended information is present, check a few other key values. */
1509 if ((READWORD(buffer,BPB_BYTESPERSECTOR) == 512) &&
1510 (READWORD(buffer,BPB_RESERVEDSECTORS) >= 1) &&
1511 ((READWORD(buffer,BPB_MEDIADESCRIPTOR) & 0xF0) == 0xF0)) {
1512 res = 0;
1513 return res;
1517 * If we're still confused, look for a partition table with a valid FAT
1518 * partition on it. We might not detect a partition table that has
1519 * only non-FAT partitions on it, like a disk with all Linux partitions,
1520 * but that is fine here in the FATFS module, since we only want to
1521 * find FAT partitions anyway.
1523 part = &buffer[PTABLE_OFFSET];
1524 for (idx = 0; idx < PTABLE_COUNT; idx++) {
1526 if (((part[PTABLE_STATUS] == PTABLE_STATUS_ACTIVE) ||
1527 (part[PTABLE_STATUS] == 0x00)) &&
1528 ((part[PTABLE_TYPE] == PARTTYPE_FAT12) ||
1529 (part[PTABLE_TYPE] == PARTTYPE_FAT16) ||
1530 (part[PTABLE_TYPE] == PARTTYPE_FAT16BIG))) {
1531 foundit = 1;
1532 res = 1; /*Partition table present*/
1533 break;
1535 part += PTABLE_SIZE;
1539 * If at this point we did not find what we were looking for,
1540 * return an error.
1542 if (foundit) {
1543 res = 1; /*Partition table is present.*/
1545 else {
1546 /*Error! We can't decide if partition table exists or not*/
1547 res = CFE_ERR_BADFILESYS;
1550 return res;
1553 static int fatfs_fileop_xinit(void **fsctx,void *dev)
1555 char *devname = (char *) dev;
1557 return fatfs_fileop_init(fsctx,devname,0);
1560 static int fatfs_fileop_pinit(void **fsctx,void *dev)
1562 char *devname = (char *) dev;
1564 return fatfs_fileop_init(fsctx,devname,1);
1569 /* *********************************************************************
1570 * fatfs_fileop_open(ref,name)
1572 * Open a file on the FAT device.
1574 * Input parameters:
1575 * ref - place to store pointer to fileinfo
1576 * fsctx - filesystem context
1577 * name - name of file to open
1579 * Return value:
1580 * 0 if ok
1581 * else error code
1582 ********************************************************************* */
1584 static int fatfs_fileop_open(void **ref,void *fsctx,char *name,int mode)
1586 int res;
1587 uint8_t direntry[DIRENTRYSIZE];
1588 fatfile_t *ff;
1589 fatfs_t *fatfs;
1591 if (mode != FILE_MODE_READ) return CFE_ERR_UNSUPPORTED;
1593 fatfs = (fatfs_t *) fsctx;
1595 ff = (fatfile_t *) KMALLOC(sizeof(fatfile_t),0);
1596 if (ff == NULL) return CFE_ERR_NOMEM;
1598 memset(ff,0,sizeof(fatfile_t));
1600 ff->ff_fat = fatfs;
1602 res = fat_findfile(ff->ff_fat,name,direntry);
1603 if (res <= 0) {
1604 return CFE_ERR_FILENOTFOUND; /* not found */
1608 * Okay, the file was found. Enumerate the FAT chain
1609 * associated with this file.
1612 ff->ff_filelength = DIRENTRY_FILELENGTH(direntry);
1614 ff->ff_curpos = 0;
1615 ff->ff_cursector = -1;
1617 res = fat_getchain(ff->ff_fat,
1618 DIRENTRY_STARTCLUSTER(direntry),
1619 &(ff->ff_chain));
1621 if (res < 0) {
1622 KFREE(ff);
1623 return res;
1627 * Return the file handle
1631 fatfs->fat_refcnt++;
1632 *ref = (void *) ff;
1633 return 0;
1637 /* *********************************************************************
1638 * fatfs_fileop_close(ref)
1640 * Close the file.
1642 * Input parameters:
1643 * ref - pointer to open file information
1645 * Return value:
1646 * nothing
1647 ********************************************************************* */
1649 static void fatfs_fileop_close(void *ref)
1651 fatfile_t *file = (fatfile_t *) ref;
1652 fatfs_t *fatctx = file->ff_fat;
1654 fatctx->fat_refcnt--;
1656 fat_freechain(&(file->ff_chain));
1657 KFREE(file);
1661 /* *********************************************************************
1662 * fatfs_fileop_uninit(ref)
1664 * Uninitialize the file system.
1666 * Input parameters:
1667 * fsctx - filesystem context
1669 * Return value:
1670 * nothing
1671 ********************************************************************* */
1672 static void fatfs_fileop_uninit(void *fsctx)
1674 fatfs_t *fatctx = (fatfs_t *) fsctx;
1676 if (fatctx->fat_refcnt) {
1677 xprintf("fatfs_fileop_unint: warning: refcnt should be zero\n");
1680 fat_uninit(fatctx);
1682 KFREE(fatctx);
1686 /* *********************************************************************
1687 * fatfs_fileop_seek(ref,offset,how)
1689 * Move the file pointer within the file
1691 * Input parameters:
1692 * ref - pointer to open file information
1693 * offset - new file location or distance to move
1694 * how - method for moving
1696 * Return value:
1697 * new file offset
1698 * <0 if error occured
1699 ********************************************************************* */
1701 static int fatfs_fileop_seek(void *ref,int offset,int how)
1703 fatfile_t *file = (fatfile_t *) ref;
1705 switch (how) {
1706 case FILE_SEEK_BEGINNING:
1707 file->ff_curpos = offset;
1708 break;
1709 case FILE_SEEK_CURRENT:
1710 file->ff_curpos += offset;
1711 break;
1712 default:
1713 break;
1716 if (file->ff_curpos >= file->ff_filelength) {
1717 file->ff_curpos = file->ff_filelength;
1720 return file->ff_curpos;
1724 /* *********************************************************************
1725 * fatfs_fileop_read(ref,buf,len)
1727 * Read data from the file.
1729 * Input parameters:
1730 * ref - pointer to open file information
1731 * buf - buffer to read data into
1732 * len - number of bytes to read
1734 * Return value:
1735 * number of bytes read
1736 * <0 if error occured
1737 * 0 means eof
1738 ********************************************************************* */
1740 static int fatfs_fileop_read(void *ref,uint8_t *buf,int len)
1742 fatfile_t *file = (fatfile_t *) ref;
1743 int amtcopy;
1744 int ttlcopy = 0;
1745 int offset;
1746 int sector;
1747 int secidx;
1748 int origpos;
1749 int res;
1750 uint8_t temp_buf[SECTORSIZE];
1753 * Remember orig position in case we have an error
1756 origpos = file->ff_curpos;
1759 * bounds check the length based on the file length
1762 if ((file->ff_curpos + len) > file->ff_filelength) {
1763 len = file->ff_filelength - file->ff_curpos;
1766 res = 0;
1769 * while ther is still data to be transferred
1773 while (len) {
1776 * Calculate the sector offset and index in the sector
1779 offset = file->ff_curpos % SECTORSIZE;
1780 secidx = file->ff_curpos / SECTORSIZE;
1782 sector = fat_sectoridx(file->ff_fat,&(file->ff_chain),secidx);
1784 if (sector < 0) {
1785 xprintf("should not happen, sector = -1!\n");
1786 return sector;
1790 * first transfer up to the sector boundary
1793 amtcopy = len;
1794 if (amtcopy > (SECTORSIZE-offset)) {
1795 amtcopy = (SECTORSIZE-offset);
1799 * If transferring exactly a sector, on a sector
1800 * boundary, read the data directly into the user buffer
1802 * Extra credit: See if we can transfer more than one
1803 * sector at a time, by determining if we can read a run of
1804 * contiguous sectors (very likely)
1806 * Otherwise: read into the sector buffer and
1807 * transfer the data to user memory.
1810 if ((offset == 0) && (amtcopy == SECTORSIZE)) {
1811 res = fat_readsector(file->ff_fat,sector,1,temp_buf);
1812 if (res < 0) {
1813 xprintf("I/O error!\n");
1814 break;
1816 memcpy(buf,temp_buf,amtcopy);
1818 else {
1819 if (file->ff_cursector != sector) {
1820 res = fat_readsector(file->ff_fat,sector,1,file->ff_sector);
1821 if (res < 0) {
1822 break;
1824 file->ff_cursector = sector;
1826 memcpy(buf,&(file->ff_sector[offset]),amtcopy);
1830 * Adjust/update all our pointers.
1833 buf += amtcopy;
1834 file->ff_curpos += amtcopy;
1835 ttlcopy += amtcopy;
1836 len -= amtcopy;
1839 * see if we ran off the end of the file. Should not
1840 * be necessary.
1843 if (file->ff_curpos >= file->ff_filelength) {
1844 /* should not be necessary */
1845 break;
1850 * If an error occured, get out now.
1853 if (res < 0) {
1854 file->ff_curpos = origpos;
1855 return res;
1858 return ttlcopy;
1862 static int fatfs_fileop_write(void *ref,uint8_t *buf,int len)
1864 return CFE_ERR_UNSUPPORTED;