fatlite.c
来自「cpc-1631的BSP包for VxWorks操作系统」· C语言 代码 · 共 1,760 行 · 第 1/5 页
C
1,760 行
if (!buffer.dirty) {
long sectorsNeeded = 20;
checkStatus(vol.tl.defragment(vol.tl.rec,§orsNeeded));
}
if (sectorNo != buffer.sectorNo || &vol != buffer.owner) {
const void FAR0 *mappedSector;
#endif
buffer.sectorNo = sectorNo;
buffer.owner = &vol;
if (read) {
mappedSector = vol.tl.mapSector(vol.tl.rec,sectorNo);
if (mappedSector)
tffscpy(buffer.data,mappedSector,SECTOR_SIZE);
else
return flSectorNotFound;
}
else
tffsset(buffer.data,0,SECTOR_SIZE);
}
buffer.dirty = TRUE;
return flOK;
}
/*----------------------------------------------------------------------*/
/* f i r s t S e c t o r O f C l u s t e r */
/* */
/* Get sector no. corresponding to cluster no. */
/* */
/* Parameters: */
/* vol : Pointer identifying drive */
/* cluster : Cluster no. */
/* */
/* Returns: */
/* first sector no. of cluster */
/*----------------------------------------------------------------------*/
static SectorNo firstSectorOfCluster(Volume vol, unsigned cluster)
{
return (SectorNo) (cluster - 2) * vol.sectorsPerCluster +
vol.firstDataSectorNo;
}
/*----------------------------------------------------------------------*/
/* g e t D i r E n t r y */
/* */
/* Get a read-only copy of a directory entry. */
/* */
/* Parameters: */
/* vol : Pointer identifying drive */
/* file : File belonging to directory entry */
/* */
/* Returns: */
/* dirEntry : Pointer to directory entry */
/*----------------------------------------------------------------------*/
static const DirectoryEntry FAR0 *getDirEntry(File *file)
{
return (DirectoryEntry FAR0 *) findSector(file->fileVol,file->directorySector) +
file->directoryIndex;
}
/*----------------------------------------------------------------------*/
/* g e t D i r E n t r y F o r U p d a t e */
/* */
/* Read a directory sector into the sector buffer and point to an */
/* entry, with the intention of modifying it. */
/* The buffer will be flushed on operation exit. */
/* */
/* Parameters: */
/* vol : Pointer identifying drive */
/* file : File belonging to directory entry */
/* */
/* Returns: */
/* FLStatus : 0 on success, otherwise failed */
/* dirEntry : Pointer to directory entry in buffer */
/*----------------------------------------------------------------------*/
static FLStatus getDirEntryForUpdate(File *file, DirectoryEntry * *dirEntry)
{
Volume vol = file->fileVol;
checkStatus(updateSector(file->fileVol,file->directorySector,TRUE));
*dirEntry = directory + file->directoryIndex;
buffer.checkPoint = TRUE;
return flOK;
}
/*----------------------------------------------------------------------*/
/* s e t C u r r e n t D a t e T i m e */
/* */
/* Set current time/date in directory entry */
/* */
/* Parameters: */
/* dirEntry : Pointer to directory entry */
/* */
/*----------------------------------------------------------------------*/
static void setCurrentDateTime(DirectoryEntry *dirEntry)
{
toLE2(dirEntry->updateTime,flCurrentTime());
toLE2(dirEntry->updateDate,flCurrentDate());
}
/*----------------------------------------------------------------------*/
/* g e t F A T e n t r y */
/* */
/* Get an entry from the FAT. The 1st FAT copy is used. */
/* */
/* Parameters: */
/* vol : Pointer identifying drive */
/* cluster : Cluster no. of enrty. */
/* */
/* Returns: */
/* Value of FAT entry. */
/*----------------------------------------------------------------------*/
static unsigned getFATentry(Volume vol, unsigned cluster)
{
LEushort FAR0 *fat16Sector;
unsigned fatSectorNo = vol.firstFATSectorNo;
#ifdef FAT_12BIT
if (vol.flags & VOLUME_12BIT_FAT)
fatSectorNo += (cluster * 3) >> (SECTOR_SIZE_BITS + 1);
else
#endif
fatSectorNo += cluster >> (SECTOR_SIZE_BITS - 1);
#ifndef SINGLE_BUFFER
if (!buffer.dirty) {
/* If the buffer is free, use it to store this FAT sector */
updateSector(&vol,fatSectorNo,TRUE);
buffer.dirty = FALSE;
}
#endif
fat16Sector = (LEushort FAR0 *) findSector(&vol,fatSectorNo);
#ifdef FAT_12BIT
if (vol.flags & VOLUME_12BIT_FAT) {
unsigned char FAR0 *fat12Sector = (unsigned char FAR0 *) fat16Sector;
unsigned halfByteOffset = (cluster * 3) & (SECTOR_SIZE * 2 - 1);
unsigned char firstByte = fat12Sector[halfByteOffset / 2];
halfByteOffset += 2;
if (halfByteOffset >= SECTOR_SIZE * 2) {
/* Entry continues on the next sector. What a mess */
halfByteOffset -= SECTOR_SIZE * 2;
fat12Sector = (unsigned char FAR0 *) findSector(&vol,fatSectorNo + 1);
}
if (halfByteOffset & 1)
return ((firstByte & 0xf0) >> 4) + (fat12Sector[halfByteOffset / 2] << 4);
else
return firstByte + ((fat12Sector[halfByteOffset / 2] & 0xf) << 8);
}
else
#endif
return LE2(fat16Sector[cluster & (SECTOR_SIZE / 2 - 1)]);
}
/*----------------------------------------------------------------------*/
/* s e t F A T e n t r y */
/* */
/* Writes a new value to a given FAT cluster entry. */
/* */
/* Parameters: */
/* vol : Pointer identifying drive */
/* cluster : Cluster no. of enrty. */
/* entry : New value of FAT entry. */
/* */
/* Returns: */
/* FLStatus : 0 on success, otherwise failed */
/*----------------------------------------------------------------------*/
static FLStatus setFATentry(Volume vol, unsigned cluster, unsigned entry)
{
LEushort *fat16Sector;
unsigned fatSectorNo = vol.firstFATSectorNo;
#ifdef FAT_12BIT
if (vol.flags & VOLUME_12BIT_FAT)
fatSectorNo += (cluster * 3) >> (SECTOR_SIZE_BITS + 1);
else
#endif
fatSectorNo += cluster >> (SECTOR_SIZE_BITS - 1);
checkStatus(updateSector(&vol,fatSectorNo,TRUE));
fat16Sector = (LEushort *) buffer.data;
#ifdef FAT_12BIT
if (vol.flags & VOLUME_12BIT_FAT) {
unsigned char *fat12Sector = (unsigned char *) buffer.data;
unsigned halfByteOffset = (cluster * 3) & (SECTOR_SIZE * 2 - 1);
if (halfByteOffset & 1) {
fat12Sector[halfByteOffset / 2] &= 0xf;
fat12Sector[halfByteOffset / 2] |= (entry & 0xf) << 4;
}
else
fat12Sector[halfByteOffset / 2] = entry;
halfByteOffset += 2;
if (halfByteOffset >= SECTOR_SIZE * 2) {
/* Entry continues on the next sector. What a mess */
halfByteOffset -= SECTOR_SIZE * 2;
fatSectorNo++;
checkStatus(updateSector(&vol,fatSectorNo,TRUE));
}
if (halfByteOffset & 1)
fat12Sector[halfByteOffset / 2] = entry >> 4;
else {
fat12Sector[halfByteOffset / 2] &= 0xf0;
fat12Sector[halfByteOffset / 2] |= (entry & 0x0f00) >> 8;
}
}
else
#endif
toLE2(fat16Sector[cluster & (SECTOR_SIZE / 2 - 1)],entry);
return flOK;
}
/*----------------------------------------------------------------------*/
/* a l l o c a t e C l u s t e r */
/* */
/* Allocates a new cluster for a file and adds it to a FAT chain or */
/* marks it in a directory entry. */
/* */
/* Parameters: */
/* vol : Pointer identifying drive */
/* file : File to extend. It should be positioned at */
/* end-of-file. */
/* */
/* Returns: */
/* FLStatus : 0 on success, otherwise failed */
/*----------------------------------------------------------------------*/
static FLStatus allocateCluster(File *file)
{
Volume vol = file->fileVol;
unsigned originalRover;
if (file->flags & FILE_READ_ONLY)
return flNoWriteAccess;
/* Look for a free cluster. Start at the allocation rover */
originalRover = vol.allocationRover;
do {
vol.allocationRover++;
if (vol.allocationRover > vol.maxCluster)
vol.allocationRover = 2; /* wraparound to start of volume */
if (vol.allocationRover == originalRover)
return flNoSpaceInVolume;
} while (getFATentry(&vol,vol.allocationRover) != FAT_FREE);
/* Found a free cluster. Mark it as an end of chain */
checkStatus(setFATentry(&vol,vol.allocationRover,FAT_LAST_CLUSTER));
/* Mark previous cluster or directory to point to it */
if (file->currentCluster == 0) {
DirectoryEntry *dirEntry;
checkStatus(getDirEntryForUpdate(file,&dirEntry));
toLE2(dirEntry->startingCluster,vol.allocationRover);
setCurrentDateTime(dirEntry);
}
else
checkStatus(setFATentry(&vol,file->currentCluster,vol.allocationRover));
/* Set our new current cluster */
file->currentCluster = vol.allocationRover;
return flOK;
}
/*----------------------------------------------------------------------*/
/* g e t S e c t o r A n d O f f s e t */
/* */
/* Based on the current position of a file, gets a sector number and */
/* offset in the sector that marks the file's current position. */
/* If the position is at the end-of-file, and the file is opened for */
/* write, this routine will extend the file by allocating a new cluster.*/
/* */
/* Parameters: */
/* vol : Pointer identifying drive */
/* */
/* Returns: */
/* FLStatus : 0 on success, otherwise failed */
/*----------------------------------------------------------------------*/
static FLStatus getSectorAndOffset(File *file,
SectorNo *sectorNo,
unsigned *offsetInSector)
{
Volume vol = file->fileVol;
unsigned offsetInCluster =
(unsigned) file->currentPosition & (vol.bytesPerCluster - 1);
if (offsetInCluster == 0) { /* This cluster is finished. Get next */
if (file->flags & FILE_IS_ROOT_DIR) {
if (file->currentPosition >= file->fileSize)
return flRootDirectoryFull;
}
else {
if (file->currentPosition >= file->fileSize) {
checkStatus(allocateCluster(file));
}
else {
unsigned nextCluster;
if (file->currentCluster == 0)
nextCluster = LE2(getDirEntry(file)->startingCluster);
else
nextCluster = getFATentry(&vol,file->currentCluster);
if (nextCluster < 2 || nextCluster > vol.maxCluster)
/* We have a bad file size, or the FAT is bad */
return flInvalidFATchain;
file->currentCluster = nextCluster;
}
}
}
*offsetInSector = offsetInCluster & (SECTOR_SIZE - 1);
if (file->flags & FILE_IS_ROOT_DIR)
*sectorNo = vol.rootDirectorySectorNo +
(SectorNo) (file->currentPosition >> SECTOR_SIZE_BITS);
else
*sectorNo = firstSectorOfCluster(&vol,file->currentCluster) +
(SectorNo) (offsetInCluster >> SECTOR_SIZE_BITS);
return flOK;
}
/*----------------------------------------------------------------------*/
/* c l o s e F i l e */
/* */
/* Closes an open file, records file size and dates in directory and */
/* releases file handle. */
/* */
/* Parameters: */
/* vol : Pointer identifying drive */
/* file : File to close. */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?