📄 fat.c
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// This source code is licensed under Microsoft Shared Source License
// Version 1.0 for Windows CE.
// For a copy of the license visit http://go.microsoft.com/fwlink/?LinkId=3223.
//
/*++
Module Name:
fat.c
Abstract:
This file contains routines for manipulating the FAT.
Revision History:
--*/
#include "fatfs.h"
/* LockFAT - Wrapper around EnterCriticalSection for FAT streams
*
* ENTRY
* pvol - pointer to VOLUME
*
* EXIT
* None.
*/
void LockFAT(PVOLUME pvol)
{
EnterCriticalSection(&pvol->v_pstmFAT->s_cs);
}
/* GetFAT - Wrapper around ReadStreamBuffer for FAT streams
*
* ENTRY
* pvol - pointer to VOLUME
* dwOffset - offset within FAT stream to read
* ppvEntry - address of pointer to first byte of buffered data
* ppvEntryEnd - address of pointer to last byte of buffered data
*
* EXIT
* ERROR_SUCCESS or other error code (same as ReadStreamBuffer)
*/
DWORD GetFAT(PVOLUME pvol, DWORD dwOffset, PVOID *ppvEntry, PVOID *ppvEntryEnd)
{
DWORD dwError;
PDSTREAM pstmFAT = pvol->v_pstmFAT;
DWORD cbBuf = pvol->v_pdsk->d_diActive.di_bytes_per_sect;
// However, releasing the FAT CS here isn't very feasible, because other
// threads could arrive and change the FAT stream's current buffer info
// without our knowledge. BUT, we can get away with this for now, because
// we know that the set of drivers that support demand-paging also acquire
// their own critical sections, and by so doing, are obligated to avoid
// making any kernel call that could block them. So the fact that we still
// hold some of our own critical sections does not make matters any worse. -JTP
ASSERT(OWNCRITICALSECTION(&pvol->v_pstmFAT->s_cs));
if (pstmFAT->s_flags & STF_BUFCURHELD) {
DWORD off = dwOffset - pstmFAT->s_offbufCur;
if (off < cbBuf) {
*ppvEntry = pstmFAT->s_pbufCur->b_pdata + off;
if (ppvEntryEnd)
*ppvEntryEnd = pstmFAT->s_pbufCur->b_pdata + cbBuf;
return ERROR_SUCCESS;
}
}
dwError = ReadStreamBuffer(pstmFAT, dwOffset, 0, ppvEntry, ppvEntryEnd);
if (dwError) {
ASSERT(!(pstmFAT->s_flags & STF_BUFCURHELD));
}
else {
// Use the FAT stream's s_offbufCur field to record the offset
// that corresponds to the start of the FAT stream's current buffer.
pstmFAT->s_offbufCur = dwOffset - ((PBYTE)*ppvEntry - pstmFAT->s_pbufCur->b_pdata);
}
return dwError;
}
/* UnlockFAT - Wrapper around LeaveCriticalSection for FAT streams
*
* ENTRY
* pvol - pointer to VOLUME
*
* EXIT
* None. Nested calls to LockFAT/UnlockFAT are perfectly
* legitimate, because the critical section maintains a count;
* however, ReleaseStreamBuffer does not keep a count with respect
* to the buffer, so since the buffer could get reused now, we need
* to clear the current buffer pointer, so that we don't use it
* as a hint.
*/
void UnlockFAT(PVOLUME pvol)
{
ASSERT(OWNCRITICALSECTION(&pvol->v_pstmFAT->s_cs));
ReleaseStreamBuffer(pvol->v_pstmFAT, FALSE);
LeaveCriticalSection(&pvol->v_pstmFAT->s_cs);
}
/* Unpack12 - Unpack 12-bit FAT entries
*
* ENTRY
* pvol - pointer to VOLUME
* clusIndex - cluster index to unpack (to obtain next cluster)
* pclusData - pointer to returned cluster (UNKNOWN_CLUSTER if error)
*
* EXIT
* ERROR_SUCCESS if successful, or an error code (eg, ERROR_INVALID_DATA)
*/
DWORD Unpack12(PVOLUME pvol, DWORD clusIndex, PDWORD pclusData)
{
DWORD dwError;
DWORD dwOffset, clusData;
PBYTE pEntry, pEntryEnd;
ASSERT(OWNCRITICALSECTION(&pvol->v_pstmFAT->s_cs));
DEBUGMSG(ZONE_FATIO,(DBGTEXT("FATFS!Unpack12: unpacking cluster %d\r\n"), clusIndex));
*pclusData = UNKNOWN_CLUSTER;
if (clusIndex > pvol->v_clusMax) {
DEBUGMSG(ZONE_FATIO|ZONE_ERRORS,(DBGTEXT("FATFS!Unpack12: invalid cluster index: %d\r\n"), clusIndex));
return ERROR_INVALID_DATA;
}
// The address of the first byte of a given cluster's data is the
// cluster # times 1.5.
dwOffset = clusIndex + (clusIndex>>1);
dwError = GetFAT(pvol, dwOffset, &pEntry, &pEntryEnd);
if (dwError)
return dwError;
if (pEntryEnd - pEntry > 1)
clusData = *(UNALIGNED WORD *)pEntry;
else {
// We must dereference pEntry before calling GetFAT again,
// because without an explicit hold on the current buffer, the
// ReadStreamBuffer call that GetFAT makes could choose to reuse it.
clusData = *pEntry; // get low byte
dwError = GetFAT(pvol, dwOffset+1, &pEntryEnd, NULL);
if (dwError)
return dwError;
clusData |= *pEntryEnd << 8; // get high byte
}
if (clusIndex & 1)
clusData >>= 4; // adjust odd cluster value
*pclusData = clusData & FAT12_EOF_MAX;
return dwError;
}
/* Pack12 - Pack 12-bit FAT entries
*
* ENTRY
* pvol - pointer to VOLUME
* clusIndex - cluster index to pack
* clusData - cluster data to pack at clusIndex
* pclusOld - pointer to old cluster data at clusIndex, NULL if not needed
*
* EXIT
* ERROR_SUCCESS if successful, or an error code (eg, ERROR_INVALID_DATA)
*/
DWORD Pack12(PVOLUME pvol, DWORD clusIndex, DWORD clusData, PDWORD pclusOld)
{
WORD wMask;
DWORD dwError;
DWORD clusOrig = clusData;
DWORD dwOffset, clusCur, clusOld, clusNew;
PBYTE pEntry, pEntryEnd;
ASSERT(OWNCRITICALSECTION(&pvol->v_pstmFAT->s_cs));
DEBUGMSG(ZONE_FATIO,(DBGTEXT("FATFS!Pack12: packing cluster %d\r\n"), clusIndex));
if (clusIndex > pvol->v_clusMax) {
DEBUGMSG(ZONE_FATIO|ZONE_ERRORS,(DBGTEXT("FATFS!Pack12: invalid cluster index: %d\r\n"), clusIndex));
return ERROR_INVALID_DATA;
}
// The address of the first byte of a given cluster's data is the
// cluster # times 1.5.
dwOffset = clusIndex + (clusIndex>>1);
dwError = GetFAT(pvol, dwOffset, &pEntry, &pEntryEnd);
if (dwError)
return dwError;
if (pEntryEnd - pEntry > 1) {
clusCur = clusOld = *(UNALIGNED WORD *)pEntry;
// get combined bytes
wMask = FAT12_EOF_MAX;
if (clusIndex & 1) {
clusData <<= 4; // adjust odd cluster value
wMask = FAT12_EOF_MAX << 4;
clusOld >>= 4; // fix the return value
}
clusNew = (clusCur & ~wMask) | (clusData & wMask);
if (clusNew != clusCur) { // if the cluster entry is changing...
if (ModifyStreamBuffer(pvol->v_pstmFAT, pEntry, 2) == ERROR_SUCCESS) {
*(UNALIGNED WORD *)pEntry = (WORD)clusNew;
}
}
}
else {
PBUF pbuf = pvol->v_pstmFAT->s_pbufCur;
// Because GetFAT does an implicit unhold on the current
// FAT buffer, we need to explicitly hold the first buffer.
HoldBuffer(pbuf);
clusOld = *pEntry; // get low byte
dwError = GetFAT(pvol, dwOffset+1, &pEntryEnd, NULL);
if (dwError) {
UnholdBuffer(pbuf);
return dwError;
}
clusOld |= *pEntryEnd << 8; // get high byte
clusCur = clusOld; // get combined bytes
wMask = FAT12_EOF_MAX;
if (clusIndex & 1) {
clusData <<= 4; // adjust odd cluster value
wMask = FAT12_EOF_MAX << 4;
clusOld >>= 4; // fix the return value
}
clusNew = (clusCur & ~wMask) | (clusData & wMask);
if (clusNew != clusCur) { // if the cluster entry is changing...
if (ModifyBuffer(pbuf, pEntry, 1) == ERROR_SUCCESS) {
*pEntry = (BYTE)clusNew;
if (ModifyStreamBuffer(pvol->v_pstmFAT, pEntryEnd, 1) == ERROR_SUCCESS) {
*pEntryEnd = (BYTE)(clusNew >> 8);
}
}
}
UnholdBuffer(pbuf);
}
clusOld &= FAT12_EOF_MAX;
if (clusNew != clusCur) {
if (pvol->v_cclusFree != UNKNOWN_CLUSTER) {
if (clusOrig == FREE_CLUSTER)
pvol->v_cclusFree++;
else if (clusOld == FREE_CLUSTER)
pvol->v_cclusFree--;
}
}
if (pclusOld)
*pclusOld = clusOld;
return dwError;
}
/* Unpack16 - Unpack 16-bit FAT entries
*
* ENTRY
* pvol - pointer to VOLUME
* clusIndex - cluster index to unpack (to obtain next cluster)
* pclusData - pointer to returned cluster (UNKNOWN_CLUSTER if error)
*
* EXIT
* ERROR_SUCCESS if successful, or an error code (eg, ERROR_INVALID_DATA)
*/
DWORD Unpack16(PVOLUME pvol, DWORD clusIndex, PDWORD pclusData)
{
PWORD pEntry;
DWORD dwError;
ASSERT(OWNCRITICALSECTION(&pvol->v_pstmFAT->s_cs));
DEBUGMSG(ZONE_FATIO,(DBGTEXT("FATFS!Unpack16: unpacking cluster %d\r\n"), clusIndex));
*pclusData = UNKNOWN_CLUSTER;
if (clusIndex > pvol->v_clusMax) {
DEBUGMSG(ZONE_FATIO|ZONE_ERRORS,(DBGTEXT("FATFS!Unpack16: invalid cluster index: %d\r\n"), clusIndex));
return ERROR_INVALID_DATA;
}
dwError = GetFAT(pvol, clusIndex*2, &pEntry, NULL);
if (!dwError)
*pclusData = *pEntry & FAT16_EOF_MAX;
return dwError;
}
/* Pack16 - Pack 16-bit FAT entries
*
* ENTRY
* pvol - pointer to VOLUME
* clusIndex - cluster index to pack
* clusData - cluster data to pack at clusIndex
* pclusOld - pointer to old cluster data at clusIndex, NULL if not needed
*
* EXIT
* ERROR_SUCCESS if successful, or an error code (eg, ERROR_INVALID_DATA)
*/
DWORD Pack16(PVOLUME pvol, DWORD clusIndex, DWORD clusData, PDWORD pclusOld)
{
PWORD pEntry;
DWORD clusOld, dwError;
ASSERT(OWNCRITICALSECTION(&pvol->v_pstmFAT->s_cs));
DEBUGMSG(ZONE_FATIO,(DBGTEXT("FATFS!Pack16: packing cluster %d\r\n"), clusIndex));
if (clusIndex > pvol->v_clusMax) {
DEBUGMSG(ZONE_FATIO|ZONE_ERRORS,(DBGTEXT("FATFS!Pack16: invalid cluster index: %d\r\n"), clusIndex));
return ERROR_INVALID_DATA;
}
dwError = GetFAT(pvol, clusIndex*2, &pEntry, NULL);
if (dwError)
return dwError;
clusData &= FAT16_EOF_MAX;
clusOld = *pEntry & FAT16_EOF_MAX;
if (clusOld != clusData) {
if (ModifyStreamBuffer(pvol->v_pstmFAT, pEntry, 2) == ERROR_SUCCESS) {
*pEntry = (WORD)clusData;
}
if (pvol->v_cclusFree != UNKNOWN_CLUSTER) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -