📄 fat_misc.c
字号:
/*
**********************************************************************
* Micrium, Inc.
* 949 Crestview Circle
* Weston, FL 33327-1848
*
* uC/FS
*
* (c) Copyright 2001 - 2003, Micrium, Inc.
* All rights reserved.
*
***********************************************************************
----------------------------------------------------------------------
File : fat_misc.c
Purpose : File system's FAT File System Layer misc routines
----------------------------------------------------------------------
Known problems or limitations with current version
----------------------------------------------------------------------
None.
---------------------------END-OF-HEADER------------------------------
*/
/*********************************************************************
*
* #include Section
*
**********************************************************************
*/
#include "fs_conf.h"
#include "fs_port.h"
#include "fs_dev.h"
#include "fs_api.h"
#include "fs_fsl.h"
#include "fs_int.h"
#include "fs_os.h"
#include "fs_lbl.h"
#include "fs_fat.h"
#include "fs_clib.h"
/*********************************************************************
*
* #define constants
*
**********************************************************************
*/
#ifndef FS_FAT_NOFAT32
#define FS_FAT_NOFAT32 0
#endif /* FS_FAT_NOFAT32 */
#ifndef FS_DIR_MAXOPEN
#define FS_DIR_MAXOPEN 0
#endif /* FS_DIR_MAXOPEN */
#define FS_MEMBLOCK_NUM (FS_MAXOPEN+FS_DIR_MAXOPEN)*2
/*********************************************************************
*
* Local data types
*
**********************************************************************
*/
typedef struct {
int status;
char memory[FS_FAT_SEC_SIZE];
} _FS_FAT_block_type;
/*********************************************************************
*
* Local Variables
*
**********************************************************************
*/
static _FS_FAT_block_type _FS_memblock[FS_MEMBLOCK_NUM];
/*********************************************************************
*
* Local functions section
*
**********************************************************************
*/
/*********************************************************************
*
* _FS_ReadBPB
*
Description:
FS internal function. Read Bios-Parameter-Block from a device and
copy the relevant data to FS__FAT_aBPBUnit.
Parameters:
Idx - Index of device in the device information table
referred by FS__pDevInfo.
Unit - Unit number.
Return value:
==0 - BPB successfully read.
<0 - An error has occured.
*/
static int _FS_ReadBPB(int Idx, FS_u32 Unit) {
int err;
unsigned char *buffer;
buffer = (unsigned char*)FS__fat_malloc(FS_FAT_SEC_SIZE);
if (!buffer) {
return -1;
}
err = FS__lb_read(FS__pDevInfo[Idx].devdriver, Unit, 0, (void*)buffer);
if (err < 0) {
FS__fat_free(buffer);
return -1;
}
/* Assign FS__FAT_aBPBUnit */
FS__FAT_aBPBUnit[Idx][Unit].BytesPerSec = buffer[11] + 256 * buffer[12]; /* _512_,1024,2048,4096 */
FS__FAT_aBPBUnit[Idx][Unit].SecPerClus = buffer[13]; /* sec in allocation unit */
FS__FAT_aBPBUnit[Idx][Unit].RsvdSecCnt = buffer[14] + 256 * buffer[15]; /* 1 for FAT12 & FAT16 */
FS__FAT_aBPBUnit[Idx][Unit].NumFATs = buffer[16]; /* 2 */
FS__FAT_aBPBUnit[Idx][Unit].RootEntCnt = buffer[17] + 256 * buffer[18]; /* number of root dir entries */
FS__FAT_aBPBUnit[Idx][Unit].TotSec16 = buffer[19] + 256 * buffer[20]; /* RSVD + FAT + ROOT + FATA (<64k) */
FS__FAT_aBPBUnit[Idx][Unit].FATSz16 = buffer[22] + 256 * buffer[23]; /* number of FAT sectors */
FS__FAT_aBPBUnit[Idx][Unit].TotSec32 = buffer[32] + 0x100UL * buffer[33] /* RSVD + FAT + ROOT + FATA (>=64k) */
+ 0x10000UL * buffer[34]
+ 0x1000000UL * buffer[35];
if (FS__FAT_aBPBUnit[Idx][Unit].FATSz16 == 0) {
FS__FAT_aBPBUnit[Idx][Unit].FATSz32 = buffer[36] + 0x100UL * buffer[37] /* number of FAT sectors */
+ 0x10000UL * buffer[38]
+ 0x1000000UL * buffer[39];
FS__FAT_aBPBUnit[Idx][Unit].ExtFlags = buffer[40] + 256 * buffer[41]; /* mirroring info */
FS__FAT_aBPBUnit[Idx][Unit].RootClus = buffer[44] + 0x100UL * buffer[45] /* root dir clus for FAT32 */
+ 0x10000UL * buffer[46]
+ 0x1000000UL * buffer[47];
FS__FAT_aBPBUnit[Idx][Unit].FSInfo = buffer[48] + 256 * buffer[49]; /* position of FSInfo structure */
}
else {
FS__FAT_aBPBUnit[Idx][Unit].FATSz32 = 0;
FS__FAT_aBPBUnit[Idx][Unit].ExtFlags = 0;
FS__FAT_aBPBUnit[Idx][Unit].RootClus = 0;
FS__FAT_aBPBUnit[Idx][Unit].FSInfo = 0;
}
FS__FAT_aBPBUnit[Idx][Unit].Signature = buffer[FS_FAT_SEC_SIZE-2]
+ 256 * buffer[FS_FAT_SEC_SIZE-1];
FS__fat_free(buffer);
return err;
}
/*********************************************************************
*
* _FS__fat_FindFreeCluster
*
Description:
FS internal function. Find the next free entry in the FAT.
Parameters:
Idx - Index of device in the device information table
referred by FS__pDevInfo.
Unit - Unit number.
pFATSector - Returns the sector number of the free entry.
pLastSector - Returns the sector number of the sector in pBuffer.
pFATOffset - Returns the offset of the free FAT entry within the
sector pFATSector.
LastClust - Cluster, which will be used to link the new allocated
cluster to. Here it is used at hint for where to start
in the FAT.
pBuffer - Pointer to a sector buffer.
FSysType - ==1 => FAT12
==0 => FAT16
==2 => FAT32
FATSize - Size of one FAT ind sectors.
BytesPerSec - Number of bytes in each sector.
Return value:
>=0 - Number of the free cluster.
<0 - An error has occured.
*/
static FS_i32 _FS__fat_FindFreeCluster(int Idx, FS_u32 Unit, FS_i32 *pFATSector,
FS_i32 *pLastSector, FS_i32 *pFATOffset,
FS_i32 LastClust, unsigned char *pBuffer,
int FSysType, FS_u32 FATSize, FS_i32 BytesPerSec) {
FS_u32 totclst;
FS_u32 rootdirsize;
FS_i32 curclst;
FS_i32 fatindex;
int err;
int scan;
unsigned char fatentry;
unsigned char a;
unsigned char b;
#if (FS_FAT_NOFAT32==0)
unsigned char c;
unsigned char d;
#endif
if (LastClust > 0) {
curclst = LastClust + 1; /* Start scan after the previous allocated sector */
}
else {
curclst = 0; /* Start scan at the beginning of the media */
}
scan = 0;
*pFATSector = 0;
*pLastSector = -1;
fatentry = 0xff;
/* Calculate total number of data clusters on the media */
totclst = (FS_u32)FS__FAT_aBPBUnit[Idx][Unit].TotSec16;
if (totclst == 0) {
totclst = FS__FAT_aBPBUnit[Idx][Unit].TotSec32;
}
rootdirsize = ((FS_u32)((FS_u32)FS__FAT_aBPBUnit[Idx][Unit].RootEntCnt) * FS_FAT_DENTRY_SIZE) / BytesPerSec;
totclst = totclst - (FS__FAT_aBPBUnit[Idx][Unit].RsvdSecCnt + FS__FAT_aBPBUnit[Idx][Unit].NumFATs * FATSize + rootdirsize);
totclst /= FS__FAT_aBPBUnit[Idx][Unit].SecPerClus;
while (1) {
if (curclst >= (FS_i32)totclst) {
scan++;
if (scan > 1) {
break; /* End of clusters reached after 2nd scan */
}
if (LastClust <= 0) {
break; /* 1st scan started already at zero */
}
curclst = 0; /* Try again starting at the beginning of the FAT */
fatentry = 0xff;
}
if (fatentry == 0) {
break; /* Free entry found */
}
if (FSysType == 1) {
fatindex = curclst + (curclst / 2); /* FAT12 */
}
else if (FSysType == 2) {
fatindex = curclst * 4; /* FAT32 */
}
else {
fatindex = curclst * 2; /* FAT16 */
}
*pFATSector = FS__FAT_aBPBUnit[Idx][Unit].RsvdSecCnt + (fatindex / BytesPerSec);
*pFATOffset = fatindex % BytesPerSec;
if (*pFATSector != *pLastSector) {
err = FS__lb_read(FS__pDevInfo[Idx].devdriver, Unit, *pFATSector, (void*)pBuffer);
if (err < 0) {
err = FS__lb_read(FS__pDevInfo[Idx].devdriver, Unit, FATSize + *pFATSector, (void*)pBuffer);
if (err < 0) {
return -1;
}
/* Try to repair original FAT sector with contents of copy */
FS__lb_write(FS__pDevInfo[Idx].devdriver, Unit, *pFATSector, (void*)pBuffer);
}
*pLastSector = *pFATSector;
}
if (FSysType == 1) {
if (*pFATOffset == (BytesPerSec - 1)) {
a = pBuffer[*pFATOffset];
err = FS__lb_read(FS__pDevInfo[Idx].devdriver, Unit, *pFATSector + 1, (void*)pBuffer);
if (err < 0) {
err = FS__lb_read(FS__pDevInfo[Idx].devdriver, Unit, FATSize + *pFATSector + 1, (void*)pBuffer);
if (err < 0) {
return -1;
}
/* Try to repair original FAT sector with contents of copy */
FS__lb_write(FS__pDevInfo[Idx].devdriver, Unit, *pFATSector + 1, (void*)pBuffer);
}
*pLastSector = *pFATSector + 1;
b = pBuffer[0];
}
else {
a = pBuffer[*pFATOffset];
b = pBuffer[*pFATOffset + 1];
}
if (curclst & 1) {
fatentry = ((a & 0xf0) >> 4 ) | b;
}
else {
fatentry = a | (b & 0x0f);
}
}
#if (FS_FAT_NOFAT32==0)
else if (FSysType == 2) {
a = pBuffer[*pFATOffset];
b = pBuffer[*pFATOffset + 1];
c = pBuffer[*pFATOffset + 2];
d = pBuffer[*pFATOffset + 3];
fatentry = a | b | c | d;
}
#endif /* FS_FAT_NOFAT32==0 */
else {
a = pBuffer[*pFATOffset];
b = pBuffer[*pFATOffset + 1];
fatentry = a | b;
}
if (fatentry != 0) {
curclst++; /* Cluster is in use or defect, so try the next one */
}
}
if (fatentry == 0) {
return curclst; /* Free cluster found */
}
return -1;
}
/*********************************************************************
*
* _FS__fat_SetEOFMark
*
Description:
FS internal function. Set the EOF mark in the FAT for a cluster.
The function does not write the FAT sector. An exception is FAT12,
if the FAT entry is in two sectors.
Parameters:
Idx - Index of device in the device information table
referred by FS__pDevInfo.
Unit - Unit number.
FATSector - FAT sector, where the cluster is located.
pLastSector - Pointer to an FS_i32, which contains the number of the
sector in pBuffer.
FATOffset - Offset of the cluster in the FAT sector.
Cluster - Cluster number, where to set the EOF mark.
pBuffer - Pointer to a sector buffer.
FSysType - ==1 => FAT12
==0 => FAT16
==2 => FAT32
FATSize - Size of one FAT ind sectors.
BytesPerSec - Number of bytes in each sector.
Return value:
>=0 - EOF mark set.
<0 - An error has occured.
*/
static int _FS__fat_SetEOFMark(int Idx, FS_u32 Unit, FS_i32 FATSector,
FS_i32 *pLastSector, FS_i32 FATOffset,
FS_i32 Cluster, unsigned char *pBuffer,
int FSysType, FS_u32 FATSize, FS_i32 BytesPerSec) {
int err1;
int err2;
int lexp;
if (FSysType == 1) {
if (FATOffset == (BytesPerSec - 1)) {
/* Entry in 2 sectors (we have 2nd sector in buffer) */
if (Cluster & 1) {
pBuffer[0] = (char)0xff;
}
else {
pBuffer[0] |= (char)0x0f;
}
err1 = FS__lb_write(FS__pDevInfo[Idx].devdriver, Unit, FATSector + 1, (void*)pBuffer);
err2 = FS__lb_write(FS__pDevInfo[Idx].devdriver, Unit, FATSize + FATSector + 1, (void*)pBuffer);
lexp = (err1 < 0);
lexp = lexp || (err2 < 0);
if (lexp) {
return -1;
}
err1 = FS__lb_read(FS__pDevInfo[Idx].devdriver, Unit, FATSector, (void*)pBuffer);
if (err1 < 0) {
err1 = FS__lb_read(FS__pDevInfo[Idx].devdriver, Unit, FATSize + FATSector, (void*)pBuffer);
if (err1 < 0) {
return -1;
}
/* Try to repair original FAT sector with contents of copy */
FS__lb_write(FS__pDevInfo[Idx].devdriver, Unit, FATSector, (void*)pBuffer);
}
*pLastSector = FATSector;
if (Cluster & 1) {
pBuffer[FATOffset] |= (char)0xf0;
}
else {
pBuffer[FATOffset] = (char)0xff;
}
}
else {
if (Cluster & 1) {
pBuffer[FATOffset] |= (char)0xf0;
pBuffer[FATOffset+1] = (char)0xff;
}
else {
pBuffer[FATOffset] = (char)0xff;
pBuffer[FATOffset+1] |= (char)0x0f;
}
}
}
#if (FS_FAT_NOFAT32==0)
else if (FSysType == 2) { /* FAT32 */
pBuffer[FATOffset] = (char)0xff;
pBuffer[FATOffset + 1] = (char)0xff;
pBuffer[FATOffset + 2] = (char)0xff;
pBuffer[FATOffset + 3] = (char)0x0f;
}
#endif /* FS_FAT_NOFAT32==0 */
else { /* FAT16 */
pBuffer[FATOffset] = (char)0xff;
pBuffer[FATOffset + 1] = (char)0xff;
}
return 0;
}
/*********************************************************************
*
* _FS__fat_LinkCluster
*
Description:
FS internal function. Link the new cluster with the EOF mark to the
cluster list.
Parameters:
Idx - Index of device in the device information table
referred by FS__pDevInfo.
Unit - Unit number.
pLastSector - Pointer to an FS_i32, which contains the number of the
sector in pBuffer.
Cluster - Cluster number of the new cluster with the EOF mark.
LastClust - Number of cluster, to which the new allocated cluster
is linked to.
pBuffer - Pointer to a sector buffer.
FSysType - ==1 => FAT12
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -