⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fat.c

📁 WinCE 3.0 BSP, 包含Inter SA1110, Intel_815E, Advantech_PCM9574 等
💻 C
字号:
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Copyright (c) 1995-2000  Microsoft Corporation

Module Name: fat.c

Abstract: Boot loader FAT file system support routines.
	
Functions:

    init_fat         - Get/save FAT partition information.
    clust_to_lba     - Convert a FAT cluster number to an LBA sector address.
    build_clust_list - Build a full cluster list for a file.
    file_open        - Open a file for reading.
    file_read        - Read contents of file.
    file_close       - Close file.

Notes:

    These support routines aid in finding and loading a binary image from disk
    to memory.  The design doesn't support multiple simultaneous file 
    operations (though serial operations are cool).

    The design of these routines assumes they'll be used on a FAT16 formatted 
    disk partition.

--*/


#include <windows.h>
#include "bootarg.h"
#include "fat.h"
#include "bldr.h"

// Preprocessor definitions.
//
#define CLUST_LIST_START	ETHDMA_BUFF_BASE	// Start of file cluster list

// External variables.
//
extern UCHAR g_bsect[SECTOR_SIZE];

// Function prototypes.
//
int read_sector(ULONG lba, UCHAR *pbuf);

// Global variables.
//
FILEINFO g_fileinfo;

// Type definitions.
//
// FAT partition information.
struct
{
    UCHAR sectspclust;      // Number of sectors per cluster
    USHORT numrootentry;    // Number of root directory entries
    ULONG fatlba;           // LBA start of FAT (first)
    ULONG apartlba;         // LBA start of active partition
    ULONG apartlen;         // Length of active partition
    ULONG rootdirlba;       // LBA start of root directory
    ULONG cluststlba;       // LBA start of data area
} g_fatparms;


int init_fat(void)
{
    UCHAR bsect[SECTOR_SIZE];
    PPARTTE pptbl = NULL;
    PBSECTHDR psecthdr = NULL;
    UCHAR i = 0;

    // Locate and verify single active partition in MBR.
    memset (&bsect[0], 0, SECTOR_SIZE);
    if (read_sector(0, &bsect[0]))
    {
        RETAILMSG(1, (TEXT("ERROR: Couldn't read MBR.\r\n")));
        return(-1);
    }

    // TODO - look for more than one occurrance of active partition.
    // Walk partition table looking for active partition
    pptbl = (PPARTTE)((UCHAR *)&bsect[0] + SECTOR_SIZE - PARTSIG_SIZE - PARTTBL_SIZE);
    for(i=0 ; i < MAX_PARTITIONS && pptbl->actvflg != PARTACTV_FLAG; i++)
        ++pptbl;

    if (i == MAX_PARTITIONS)
    {
        RETAILMSG(1, (TEXT("ERROR: Didn't find an active partition.\r\n")));
        return(-1);
    }

    // Save FAT info for active boot partition
    g_fatparms.apartlba = pptbl->slba;
    g_fatparms.apartlen = pptbl->size;

    DEBUGMSG(ZONE_INFO, (TEXT("Active boot partition found (LBA=0x%x  Length=0x%x)\r\n"), g_fatparms.apartlba, g_fatparms.apartlen));

    // Compute and store root directory LBA - to do this, get the boot sector
    // from the active partition, look at the disk parameter block contents
    // to determine number of reserved and hidden sectors, then compute.
    memset (&bsect[0], 0, SECTOR_SIZE);
    if (read_sector(g_fatparms.apartlba, &bsect[0]))
    {
        RETAILMSG(1, (TEXT("ERROR: Couldn't load active boot sector.\r\n")));
        return(-1);
    }
  
    psecthdr = (PBSECTHDR)&bsect[0]; 
    g_fatparms.rootdirlba = g_fatparms.apartlba + (psecthdr->numfats * psecthdr->sectspfat) + psecthdr->numrsvdsects;
    g_fatparms.fatlba = g_fatparms.apartlba + psecthdr->numrsvdsects;

    DEBUGMSG(ZONE_INFO, (TEXT("Root dir location (LBA=0x%x)\r\n"), g_fatparms.rootdirlba));
    DEBUGMSG(ZONE_INFO, (TEXT("  - Number of FATs = 0x%x)\r\n"), psecthdr->numfats));
    DEBUGMSG(ZONE_INFO, (TEXT("  - Number of Sectors Per FATs = 0x%x)\r\n"), psecthdr->sectspfat));
    DEBUGMSG(ZONE_INFO, (TEXT("  - Number of Hidden Sectors = 0x%x)\r\n"), psecthdr->numhdnsects));
    DEBUGMSG(ZONE_INFO, (TEXT("  - Number of Reserved Sectors = 0x%x)\r\n"), psecthdr->numrsvdsects));


    // Save data start LBA
    g_fatparms.cluststlba = g_fatparms.rootdirlba + ((sizeof(DIRENTRY) * psecthdr->numrootentry) / psecthdr->bytespsect);
    if ((sizeof(DIRENTRY) * psecthdr->numrootentry) % psecthdr->bytespsect)
        ++g_fatparms.cluststlba;

    // Save number of sectors per cluster
    g_fatparms.sectspclust = psecthdr->sectspclust;
    g_fatparms.numrootentry = psecthdr->numrootentry;

    return(0); 
}


int clust_to_lba(USHORT clust)
{
    return(g_fatparms.cluststlba + (clust - 2) * g_fatparms.sectspclust);
}


int file_read(UCHAR *pbuf, ULONG len)
{
    UCHAR *ptmp = pbuf;
    ULONG bytestoread = len;
    ULONG sectstoread = 0;

    // TODO - handle EOF mid-cluster.
    while (bytestoread)
    {
        if (g_fileinfo.bytesreminsect == 0)	// Buffer isn't filled...
        {
            // EOF?
            if (g_fileinfo.curclust >= 0xfff8 && g_fileinfo.curclust <= 0xffff)
                return(FAT_EOF);

            memset(&g_bsect[0], 0, SECTOR_SIZE);
            if (read_sector(g_fileinfo.cursect, &g_bsect[0]))
            {
                RETAILMSG(1, (TEXT("ERROR: Couldn't read data sector.\r\n")));
                return(-1);
            }

	        // jump to next cluster if we've read all the sectors in the current
            g_fileinfo.sectreminclust--;
            g_fileinfo.cursect++;
            if (g_fileinfo.sectreminclust == 0)
            {
                ++g_fileinfo.clusttlbofst;
                g_fileinfo.sectreminclust = g_fatparms.sectspclust;
                g_fileinfo.curclust = *((USHORT *)CLUST_LIST_START + g_fileinfo.clusttlbofst);
                g_fileinfo.cursect = clust_to_lba(g_fileinfo.curclust);
            }
            
            g_fileinfo.bytesreminsect = SECTOR_SIZE;
            g_fileinfo.byteofst = 0;
        }

        // If data in read buffer has all the data the caller needs...
        if (bytestoread <= g_fileinfo.bytesreminsect)
        {
            memcpy(ptmp, (UCHAR *)&g_bsect[g_fileinfo.byteofst], bytestoread);
            g_fileinfo.bytesreminsect -= (USHORT)bytestoread;
	    g_fileinfo.byteofst += (USHORT)bytestoread;
            return(0);
        }

        // Caller wants more data than is in the global buffer - first
	    // deplete the global buffer contents
        memcpy(ptmp, (UCHAR *)&g_bsect[g_fileinfo.byteofst], g_fileinfo.bytesreminsect);
	    bytestoread -= g_fileinfo.bytesreminsect;
	    ptmp += g_fileinfo.bytesreminsect;
	    g_fileinfo.bytesreminsect = 0;

        // If remaining bytes are less than a sector in size - don't need to
	    // optimize for multi-sector reads - do a partial sector read
	    if ((bytestoread / SECTOR_SIZE) == 0)
	        continue;
      
        // TODO - can optimize reads here by avoiding intermediate buffer copy...
        // Otherwise - read full sectors into buffer
	    sectstoread = bytestoread / SECTOR_SIZE;
	    bytestoread = bytestoread % SECTOR_SIZE;

        while (sectstoread)
        {
            // EOF?
            if (g_fileinfo.curclust >= 0xfff8 && g_fileinfo.curclust <= 0xffff)
                return(FAT_EOF);

            memset(&g_bsect[0], 0, SECTOR_SIZE);
            if (read_sector(g_fileinfo.cursect, &g_bsect[0]))
            {
                RETAILMSG(1, (TEXT("ERROR: Couldn't read data sector\r\n")));
                return(-1);
            }

            // jump to next cluster if we've read all the sectors in the current
            g_fileinfo.sectreminclust--;
            g_fileinfo.cursect++;
            if (g_fileinfo.sectreminclust == 0)
            {
                ++g_fileinfo.clusttlbofst;
                g_fileinfo.sectreminclust = g_fatparms.sectspclust;
                g_fileinfo.curclust = *((USHORT *)CLUST_LIST_START + g_fileinfo.clusttlbofst);
                g_fileinfo.cursect = clust_to_lba(g_fileinfo.curclust);
            }

	    memcpy(ptmp, &g_bsect[0], SECTOR_SIZE);
	    ptmp += SECTOR_SIZE;
	    g_fileinfo.bytesreminsect = 0;
	    --sectstoread;
        }
    }

    return(0);
}


int file_open(UCHAR *pfname)
{
    USHORT i = 0;
    USHORT j = 0;
    UCHAR fname[11] = {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
    UCHAR bsect[SECTOR_SIZE];
    PDIRENTRY pdirentry = NULL;
    ULONG dirlba = 0;
    UCHAR found = 0;

    if (pfname == NULL)
        return(-1);

    for (i = 0 ; i < 8 && *(pfname + i) != '\0' && *(pfname + i) != '.' ; i++)
        fname[i] = TO_UPPER(*(pfname + i));
    if (*(pfname + i) == '.')
    {
        i++;
        for (j=0 ; i < 12 && *(pfname + i) != '\0' ; i++, j++)
        fname[8 + j] = TO_UPPER(*(pfname + i));
    }

    // Look for filename in directory list
    for (found=0, i=0, dirlba=g_fatparms.rootdirlba ; !found && i < g_fatparms.numrootentry ; dirlba++)
    {
        memset(&bsect[0], 0, SECTOR_SIZE);

        DEBUGMSG(ZONE_INFO, (TEXT("INFO: Reading root dir sector (LBA=0x%x).\r\n"), dirlba));

        if (read_sector(dirlba, &bsect[0]))
        {
            RETAILMSG(1, (TEXT("ERROR: Couldn't read root dir sector.\r\n")));
            return(-1);
        }

        for (pdirentry = (PDIRENTRY)&bsect[0], j=0 ; j < (SECTOR_SIZE / sizeof(DIRENTRY)) && i < g_fatparms.numrootentry ; j++, i++, pdirentry++)
        {
            DEBUGMSG(ZONE_INFO, (TEXT("INFO: %d: fname '%s' fsize = 0x%x.\r\n"), j, &(pdirentry->fname[0]), pdirentry->fsize));

            if (!memcmp(&fname[0], &(pdirentry->fname[0]), 11))
            {
                found=1;
                break;
            }
        }
    } 


    if (!found)
    {
        RETAILMSG(1, (TEXT("ERROR: Couldn't find file '%s'.\r\n"), pfname)); 
        return(-1);
    }
    else
    {
        DEBUGMSG(ZONE_INFO, (TEXT("INFO: Found file '%s' (start clust = 0x%x size = 0x%x).\r\n"), pfname, pdirentry->fclust, pdirentry->fsize)); 
    }
   
    // Save file parameters
    g_fileinfo.curclust = pdirentry->fclust;
    g_fileinfo.cursect = clust_to_lba(g_fileinfo.curclust);
    g_fileinfo.fsize = pdirentry->fsize;
    g_fileinfo.bytesreminsect = 0;
    g_fileinfo.clusttlbofst  = 0;
    g_fileinfo.sectreminclust = g_fatparms.sectspclust;
    g_fileinfo.byteofst = 0;

    // Build cluster list from FAT for file
    if (build_clust_list())
    {
        RETAILMSG(1, (TEXT("ERROR: Couldn't build cluster list for '%s'.\r\n"), pfname)); 
        return(-1);
    }
 
    return(0);
}


int file_close(void)
{
    USHORT *pclustlist = (USHORT *)CLUST_LIST_START;

    *pclustlist = 0xffff;

    memset(&g_fileinfo, 0, sizeof(g_fileinfo));

    return(0);
}


int build_clust_list(void)
{
    USHORT curclust = g_fileinfo.curclust;
    USHORT cnt = 0; 
    USHORT *pclustlist = (USHORT *)CLUST_LIST_START;
    ULONG curlba = 0;
    UCHAR bsect[SECTOR_SIZE];
    ULONG tmp = 0;
    USHORT byteofst = 0;

    // While we point at a valid cluster value, walk the list and build a 
    // linear summary...
    while (curclust >= 0x2 && curclust <= 0xffef)
    {
        // Save cluster value
        *(pclustlist + cnt) = curclust;
        ++cnt;

        // Determine FAT LBA address and byte offset into sector for lookup
        tmp = curclust * sizeof(USHORT);
        byteofst = (USHORT)tmp % SECTOR_SIZE;
        tmp /= SECTOR_SIZE;
        tmp += g_fatparms.fatlba;

        // We haven't read needed sector yet - do it.
        if (tmp != curlba)
        {
            memset(&bsect[0], 0, SECTOR_SIZE);
            if (read_sector(tmp, &bsect[0]))
            {
                RETAILMSG(1, (TEXT("ERROR: Couldn't read FAT.\r\n")));
                return(-1);
            }
            curlba = tmp; 
        }

        // Look up next cluster in list
        curclust = *((USHORT *)(&bsect[0] + byteofst));
    }

    // Done - set end of list cluster tag.
    if (curclust >= 0xfff8 && curclust <= 0xffff)
    {
        *(pclustlist + cnt) = curclust;
        ++cnt;
    }
    else
    {
        RETAILMSG(1, (TEXT("ERROR: Failed to build cluster list.\r\n")));
        return(-1);
    }

    DEBUGMSG(ZONE_INFO, (TEXT("INFO: Built cluster list (size = 0x%x).\r\n"), cnt));

    return(0);    
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -