📄 fat.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 + -