📄 fatlite.c
字号:
#ifndef FL_READ_ONLY
/*----------------------------------------------------------------------*/
/* 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) >> (FL_SECTOR_SIZE_BITS + 1);
else
#endif
fatSectorNo += cluster >> (FL_SECTOR_SIZE_BITS - 1);
checkStatus(updateSector(&vol,fatSectorNo,TRUE));
fat16Sector = (LEushort *) vol.volBuffer.flData;
#ifdef FAT_12BIT
if (vol.flags & VOLUME_12BIT_FAT) {
FLByte *fat12Sector = (FLByte *) vol.volBuffer.flData;
unsigned halfByteOffset = (cluster * 3) & (FL_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 >= FL_SECTOR_SIZE * 2) {
/* Entry continues on the next sector. What a mess */
halfByteOffset -= FL_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 & (FL_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;
unsigned fatEntry;
DirectoryEntry *dirEntry;
if (file->flags & FL_FILE_READ_ONLY)
return flNoWriteAccess;
/* Look for a free cluster. Start at the allocation rover */
originalRover = vol.allocationRover;
do {
vol.allocationRover++;
if (vol.allocationRover >= FL_LAST_VALID_CLUSTER )
vol.allocationRover = FL_FIRST_VALID_CLUSTER; /* wraparound to start of volume */
if (vol.allocationRover == originalRover)
{
if( originalRover != FL_FIRST_VALID_CLUSTER )
return flNoSpaceInVolume;
else
{
fatEntry = vol.allocationRover;
checkStatus(getFATentry(&vol,&fatEntry));
if( fatEntry != FAT_FREE )
return flNoSpaceInVolume;
else
break;
}
}
fatEntry = vol.allocationRover;
checkStatus(getFATentry(&vol,&fatEntry));
} while ( fatEntry!= FAT_FREE);
/* Mark previous cluster or directory to point to it */
if (file->currentCluster == 0) {
checkStatus(getDirEntryForUpdate(file,&dirEntry));
toLE2(dirEntry->startingCluster,vol.allocationRover);
setCurrentDateTime(dirEntry);
}
#ifndef FL_NO_SURE_FS_SUPPORT
if (file->flags & FL_FILE_IS_DIRECTORY) {
checkStatus(getDirEntryForUpdate(file,&dirEntry));
checkStatus( setAttentionFlag( &vol, dirEntry, ATTR_SUREFS_GEN_ATTENTION_FLAG));
}
else {
/* For extending file set attantion flag only once */
FLByte flag;
const DirectoryEntry FAR0 *entry;
entry = getDirEntry(file);
if(entry==NULL)
return flSectorNotFound;
if(entry==(const DirectoryEntry FAR0 *)dataErrorToken)
return flDataError;
getAttentionFlag( entry, &flag);
if (flag == 0) {
checkStatus(getDirEntryForUpdate(file, &dirEntry));
checkStatus( setAttentionFlag( &vol, dirEntry, ATTR_SUREFS_GEN_ATTENTION_FLAG));
}
}
#endif /* FL_NO_SURE_FS_SUPPORT */
if (file->currentCluster)
checkStatus(setFATentry(&vol,file->currentCluster,vol.allocationRover));
/* Mark found free cluster as an end of chain */
checkStatus(setFATentry(&vol,vol.allocationRover,FAT_LAST_CLUSTER));
/* Set our new current cluster */
file->currentCluster = vol.allocationRover;
return flOK;
}
#endif /* FL_READ_ONLY */
/*----------------------------------------------------------------------*/
/* 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 (file->flags & FL_FILE_IS_ROOT_DIR)
{
if (file->currentPosition >= file->fileSize)
return flRootDirectoryFull;
}
if (offsetInCluster == 0) { /* This cluster is finished. Get next */
if (!(file->flags & FL_FILE_IS_ROOT_DIR)) {
if (((file->currentPosition >= file->fileSize) && (file->currentPosition>0))||((file->fileSize==0)&&!(file->flags & FL_FILE_IS_DIRECTORY))) {
#ifndef FL_READ_ONLY
checkStatus(allocateCluster(file));
#else
return flSectorNotFound;
#endif
}
else {
unsigned nextCluster;
if (file->currentCluster == 0) {
const DirectoryEntry FAR0 *dirEntry;
dirEntry = getDirEntry(file);
if(dirEntry==NULL)
return flSectorNotFound;
if(dirEntry==(const DirectoryEntry FAR0 *)dataErrorToken)
return flDataError;
nextCluster = LE2(dirEntry->startingCluster);
}
else {
nextCluster = file->currentCluster;
checkStatus(getFATentry(&vol,&nextCluster));
}
if( IsValidCluster(nextCluster) == FALSE )
/* We have a bad file size, or the FAT is bad */
return flInvalidFATchain;
file->currentCluster = nextCluster;
}
}
}
*offsetInSector = offsetInCluster & (FL_SECTOR_SIZE - 1);
if (file->flags & FL_FILE_IS_ROOT_DIR)
*sectorNo = vol.rootDirectorySectorNo +
(SectorNo) (file->currentPosition >> FL_SECTOR_SIZE_BITS);
else
*sectorNo = firstSectorOfCluster(&vol,file->currentCluster) +
(SectorNo) (offsetInCluster >> FL_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. */
/* */
/* Returns: */
/* FLStatus : 0 on success, otherwise failed */
/*----------------------------------------------------------------------*/
FLStatus closeFile(File *file)
{
#ifndef FL_READ_ONLY
DirectoryEntry *dirEntry;
if ((file->flags & FL_FILE_MODIFIED) && !(file->flags & FL_FILE_IS_ROOT_DIR)) {
checkStatus(getDirEntryForUpdate(file,&dirEntry));
dirEntry->attributes |= FL_ATTR_ARCHIVE;
if (!(file->flags & FL_FILE_IS_DIRECTORY))
toLE4(dirEntry->fileSize,file->fileSize);
setCurrentDateTime(dirEntry);
#ifndef FL_NO_SURE_FS_SUPPORT
checkStatus( setAttentionFlag( file->fileVol, dirEntry, 0)); /* reset attention flag */
#endif /* FL_NO_SURE_FS_SUPPORT */
}
#endif /* FL_READ_ONLY */
if(!(file->flags & FL_FILE_IS_ROOT_DIR))
file->flags = 0; /* no longer open */
else
file->flags = FL_FILE_IS_ROOT_DIR;
return flOK;
}
/*----------------------------------------------------------------------*/
/* f l u s h F i l e */
/* */
/* Records file size and dates in directory but does not release */
/* file handle. */
/* */
/* Parameters: */
/* vol : Pointer identifying drive */
/* file : File to close. */
/* */
/* Returns: */
/* FLStatus : 0 on success, otherwise failed */
/*----------------------------------------------------------------------*/
FLStatus flushFile(File *file)
{
#ifndef FL_READ_ONLY
Volume vol = file->fileVol;
if ((file->flags & FILE_MODIFIED) && !(file->flags & FL_FILE_IS_ROOT_DIR)) {
DirectoryEntry *dirEntry;
checkStatus(getDirEntryForUpdate(file,&dirEntry));
dirEntry->attributes |= FL_ATTR_ARCHIVE;
if (!(file->flags & FL_FILE_IS_DIRECTORY))
toLE4(dirEntry->fileSize,file->fileSize);
setCurrentDateTime(dirEntry);
#ifndef FL_NO_SURE_FS_SUPPORT
checkStatus( setAttentionFlag( file->fileVol, dirEntry, 0)); /* reset attention flag */
#endif /* FL_NO_SURE_FS_SUPPORT */
vol.volBuffer.dirty = TRUE;
checkStatus(flushBuffer(&vol));
file->flags &= ~FILE_MODIFIED;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -