?? volume.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:
volume.c
Abstract:
This file contains routines for mounting volumes, direct volume access, etc.
Revision History:
--*/
#include "fatfs.h"
#if defined(UNDER_WIN95) && !defined(INCLUDE_FATFS)
#include <pcmd.h> // for interacting with ReadVolume/WriteVolume
#endif
ERRFALSE(offsetof(BOOTSEC, bsBPB) == offsetof(BIGFATBOOTSEC, bgbsBPB));
/* ReadVolume
*
* Like ReadWriteDisk, except it takes a PVOLUME, and it works with
* volume-relative BLOCKS instead of disk-relative SECTORS.
*
* For now, the caller must specify a block number that starts on a sector
* boundary, and the number of blocks must map to a whole number of sectors.
*
* Entry:
* pvol address of VOLUME structure
* block 0-based block number
* cBlocks number of blocks to read
* pvBuffer address of buffer to read sectors into
*
* Exit:
* ERROR_SUCCESS if successful, else GetLastError() from the FSDMGR_DiskIoControl call issued
*/
DWORD ReadVolume(PVOLUME pvol, DWORD block, int cBlocks, PVOID pvBuffer)
{
#ifdef UNDER_WIN95
if (ZONE_BUFFERS && ZONE_PROMPTS) {
WCHAR wsBuf[10];
DBGPRINTFW(TEXTW("Read: block %d, total %d; allow (Y/N)? "), block, cBlocks);
DBGSCANFW(wsBuf, ARRAYSIZE(wsBuf));
if (TOLOWER(wsBuf[0]) == 'n')
return ERROR_BAD_UNIT;
}
#endif
// Assert that the shifted bits in both block and cBlocks are zero
ASSERT(pvol->v_log2cblkSec<=0? 1 : (((block | cBlocks) & ((1 << pvol->v_log2cblkSec) - 1)) == 0));
if (pvol->v_flags & VOLF_FROZEN) {
DEBUGMSG(ZONE_INIT || ZONE_ERRORS,(DBGTEXT("FATFS!ReadVolume: frozen volume, cannot read block %d!\n"), block));
return ERROR_DEV_NOT_EXIST;
}
// NOTE that all sectors computed in this function are relative to
// block 0, and that before they are passed to ReadWriteDisk, they are
// adjusted by v_secBlkBias (the sector bias for block 0). Thus, it is
// impossible for this function to read from any of the volume's reserved
// sectors (eg, the boot sector and BPB) or hidden sectors, because they
// precede block 0.
//
// See the code in IOCTL_DISK_READ_SECTORS and IOCTL_DISK_WRITE_SECTORS
// to access sectors outside the normal block range.
return ReadWriteDisk(pvol, pvol->v_pdsk->d_hdsk, DISK_IOCTL_READ, &pvol->v_pdsk->d_diActive, pvol->v_secBlkBias + (block>>pvol->v_log2cblkSec), (cBlocks>>pvol->v_log2cblkSec), pvBuffer);
}
/* WriteVolume
*
* Like ReadWriteDisk, except it takes a PVOLUME, and it works with
* volume-relative BLOCKS instead of disk-relative SECTORS.
*
* For now, the caller must specify a block number that starts on a sector
* boundary, and the number of blocks must map to a whole number of sectors.
*
* Entry:
* pvol address of VOLUME structure
* block 0-based block number
* cBlocks number of blocks to write
* pvBuffer address of buffer to write sectors from
*
* Exit:
* ERROR_SUCCESS if successful, else GetLastError() from the FSDMGR_DiskIoControl call issued
*/
DWORD WriteVolume(PVOLUME pvol, DWORD block, int cBlocks, PVOID pvBuffer)
{
DWORD sec, csec, secEnd, secBackup;
#ifdef UNDER_WIN95
if (ZONE_BUFFERS && ZONE_PROMPTS) {
WCHAR wsBuf[10];
DBGPRINTFW(TEXTW("Write: block %d, total %d; allow (Y/N)? "), block, cBlocks);
DBGSCANFW(wsBuf, ARRAYSIZE(wsBuf));
if (TOLOWER(wsBuf[0]) == 'n')
return ERROR_BAD_UNIT;
}
#endif
// Assert that the shifted bits in both block and cBlocks are zero
ASSERT(pvol->v_log2cblkSec<=0? 1 : (((block | cBlocks) & ((1 << pvol->v_log2cblkSec) - 1)) == 0));
if (pvol->v_flags & VOLF_FROZEN) {
DEBUGMSG(ZONE_INIT || ZONE_ERRORS,(DBGTEXT("FATFS!WriteVolume: frozen volume, cannot write block %d!\n"), block));
return ERROR_DEV_NOT_EXIST;
}
// NOTE that all sectors computed in this function are relative to
// block 0, and that before they are passed to ReadWriteDisk, they are
// adjusted by v_secBlkBias (the sector bias for block 0). Thus, it is
// impossible for this function to write to any of the volume's reserved
// sectors (eg, the boot sector and BPB) or hidden sectors, because they
// precede block 0.
//
// See the code in IOCTL_DISK_READ_SECTORS and IOCTL_DISK_WRITE_SECTORS
// to access sectors outside the normal block range.
sec = block >> pvol->v_log2cblkSec;
csec = cBlocks >> pvol->v_log2cblkSec;
// If we have multiple FATs, and we're writing to the FAT region,
// adjust and/or mirror the write appropriately.
if ((pvol->v_flags & VOLF_BACKUP_FAT) && sec < pvol->v_secEndAllFATs) {
secEnd = sec + csec;
// Check for write to root directory area that starts inside
// a backup FAT. Backup FATs are not buffered, hence any buffered
// data inside the range of the backup FAT could be stale and
// must NOT be written.
if (sec >= pvol->v_secEndFAT) {
ASSERT(secEnd > pvol->v_secEndAllFATs);
csec = secEnd - pvol->v_secEndAllFATs;
sec = pvol->v_secEndAllFATs;
goto write;
}
// Check for write to end of the active FAT that ends inside
// a backup FAT. Backup FATs are not buffered, hence any buffered
// data inside the range of the backup FAT could be stale and
// must NOT be written.
secBackup = sec;
if (secEnd > pvol->v_secEndFAT) {
DWORD csecFATWrite;
csecFATWrite = pvol->v_secEndFAT - sec;
if (secEnd < pvol->v_secEndAllFATs) {
csec = csecFATWrite;
}
else {
DWORD cbFATWrite;
PBYTE pFAT, pFATBackup;
// The current buffer spans all the FATs, so we need to
// copy the FAT data to the backup FAT location(s) instead of
// doing extra writes.
pFAT = (PBYTE)pvBuffer;
pFATBackup = pFAT + (pvol->v_csecFAT << pvol->v_log2cbSec);
cbFATWrite = (csecFATWrite << pvol->v_log2cbSec);
while ((secBackup += pvol->v_csecFAT) < pvol->v_secEndAllFATs) {
memcpy(pFATBackup, pFAT, cbFATWrite);
pFATBackup += pvol->v_csecFAT << pvol->v_log2cbSec;
}
goto write;
}
}
// If we're still here, we've got a FAT write that's been restricted
// to the just the sectors within the active FAT. Start cycling through
// the backup FATs now.
while ((secBackup += pvol->v_csecFAT) < pvol->v_secEndAllFATs) {
DEBUGMSG(ZONE_FATIO,(DBGTEXT("FATFS!WriteVolume: mirroring %d FAT sectors at %d to %d\n"), csec, sec, secBackup));
ASSERT(secBackup + csec <= pvol->v_secEndAllFATs);
// We ignore any error here, on the assumption that perhaps the
// backup FAT has simply gone bad.
ReadWriteDisk(pvol, pvol->v_pdsk->d_hdsk, DISK_IOCTL_WRITE, &pvol->v_pdsk->d_diActive, pvol->v_secBlkBias + secBackup, csec, pvBuffer);
}
}
write:
return ReadWriteDisk(pvol, pvol->v_pdsk->d_hdsk, DISK_IOCTL_WRITE, &pvol->v_pdsk->d_diActive, pvol->v_secBlkBias + sec, csec, pvBuffer);
}
/* InitVolume - Initialize a VOLUME structure
*
* ENTRY
* pvol - pointer to VOLUME
* pbgbs - pointer to PBR (partition boot record) for volume
*
* EXIT
* TRUE if VOLUME structure successfully initialized, FALSE if not
*/
BOOL InitVolume(PVOLUME pvol, PBIGFATBOOTSEC pbgbs)
{
DWORD cmaxClus;
PBIGFATBPB pbpb;
PDSTREAM pstmFAT;
PDSTREAM pstmRoot;
ASSERT(OWNCRITICALSECTION(&pvol->v_cs));
pvol->v_flags &= ~(VOLF_INVALID | VOLF_12BIT_FAT | VOLF_16BIT_FAT | VOLF_32BIT_FAT | VOLF_BACKUP_FAT);
// Allocate special DSTREAMs for the FAT and the root directory,
// using PSEUDO cluster numbers 0 and 1. Root directories of FAT32
// volumes do have a REAL cluster number, and if we're in a nested init
// path, we need to use it, but otherwise we'll just use ROOT_PSEUDO_CLUSTER
// and record the real cluster number when we figure it out, in the
// FAT32-specific code farther down...
pstmFAT = OpenStream(pvol, FAT_PSEUDO_CLUSTER, NULL, NULL, NULL, OPENSTREAM_CREATE);
ASSERT(pvol->v_pstmFAT == NULL || pvol->v_pstmFAT == pstmFAT);
pstmRoot = OpenStream(pvol, pvol->v_pstmRoot? pvol->v_pstmRoot->s_clusFirst : ROOT_PSEUDO_CLUSTER, NULL, NULL, NULL, OPENSTREAM_CREATE);
ASSERT(pvol->v_pstmRoot == NULL || pvol->v_pstmRoot == pstmRoot);
if (!pstmFAT || !pstmRoot)
goto exit;
// Add extra refs to these special streams to make them stick around;
// we only want to do this if the current open is their only reference,
// because if they've been resurrected, then they still have their original
// extra refs.
if (pstmFAT->s_refs == 1) {
pstmFAT->s_refs++;
}
if (pstmRoot->s_refs == 1) {
pstmRoot->s_refs++;
}
pvol->v_pstmFAT = pstmFAT;
pvol->v_pstmRoot = pstmRoot;
pstmRoot->s_attr = ATTR_DIRECTORY;
// We have completed the required stream initialization for this
// volume. Now perform boot sector verification and BPB validation.
if (pvol->v_pdsk->d_diActive.di_flags & DISK_INFO_FLAG_UNFORMATTED) {
RETAILMSG(TRUE,(DBGTEXT("FATFS!InitVolume: driver has set 'unformatted' bit, marking volume invalid\n")));
pvol->v_flags |= VOLF_INVALID;
}
if (!(pvol->v_flags & VOLF_INVALID)) {
if (pbgbs->bgbsJump[0] != BSNOP &&
pbgbs->bgbsJump[0] != BS2BYTJMP &&
pbgbs->bgbsJump[0] != BS3BYTJMP) {
RETAILMSG(TRUE,(DBGTEXT("FATFS!InitVolume: sector 0 byte 0 suspicious (0x%x)\n"), pbgbs->bgbsJump[0]));
}
if (pbgbs->bgbsBPB.oldBPB.BPB_BytesPerSector < DEFAULT_SECTOR_SIZE ||
Log2(pbgbs->bgbsBPB.oldBPB.BPB_BytesPerSector) == -1 ||
pbgbs->bgbsBPB.oldBPB.BPB_NumberOfFATs < 1 ||
*(PWORD)((PBYTE)pbgbs+DEFAULT_SECTOR_SIZE-2) != BOOTSECTRAILSIGH) {
DEBUGMSG(ZONE_INIT || ZONE_ERRORS,(DBGTEXT("FATFS!InitVolume: invalid BPB, volume deemed invalid\n")));
pvol->v_flags |= VOLF_INVALID;
}
}
pbpb = &pbgbs->bgbsBPB;
// Preliminary FAT32 detection: if FAT32 support is disabled, then ALWAYS
// set VOLF_INVALID; otherwise, do it only if there is a version mismatch.
if (!(pvol->v_flags & VOLF_INVALID) && pbpb->oldBPB.BPB_SectorsPerFAT == 0) {
#ifdef FAT32
if (pbpb->BGBPB_FS_Version > FAT32_Curr_FS_Version) {
RETAILMSG(TRUE,(TEXT("FATFS!InitVolume: FAT32 volume version unsupported (%d > %d)\n"),
pbpb->BGBPB_FS_Version, FAT32_Curr_FS_Version));
#else
RETAILMSG(TRUE,(TEXT("FATFS!InitVolume: FAT32 volumes not supported in this build\n")));
#endif
pvol->v_flags |= VOLF_INVALID;
#ifdef FAT32
}
if (!(pvol->v_flags & VOLF_INVALID)) {
pvol->v_flags |= VOLF_32BIT_FAT;
pvol->v_secFSInfo = pbpb->BGBPB_FSInfoSec;
}
#endif
}
if (pvol->v_flags & VOLF_INVALID) {
memset(&pvol->v_bMediaDesc, 0, offsetof(VOLUME, v_pstmFAT) - offsetof(VOLUME, v_bMediaDesc));
memset(&pstmFAT->s_run, 0, sizeof(pstmFAT->s_run));
memset(&pstmRoot->s_run, 0, sizeof(pstmRoot->s_run));
goto exit;
}
// Now compute volume dimensions, etc, from BPB data
pvol->v_bMediaDesc = pbpb->oldBPB.BPB_MediaDescriptor;
if (pbpb->oldBPB.BPB_NumberOfFATs > 1)
pvol->v_flags |= VOLF_BACKUP_FAT;
// Compute sector bias for volume (for sector-based I/O)
pvol->v_secVolBias = pbpb->oldBPB.BPB_HiddenSectors;
// Compute sector bias for block 0 (for block-based I/O only)
pvol->v_secBlkBias = pbpb->oldBPB.BPB_HiddenSectors + pbpb->oldBPB.BPB_ReservedSectors;
// Compute how many sectors are on the volume
pvol->v_csecTotal = pbpb->oldBPB.BPB_TotalSectors;
if (pvol->v_csecTotal == 0)
pvol->v_csecTotal = pbpb->oldBPB.BPB_BigTotalSectors;
if (pvol->v_csecTotal <= pbpb->oldBPB.BPB_ReservedSectors) {
DEBUGMSGBREAK(ZONE_INIT || ZONE_ERRORS,
(DBGTEXT("FATFS!InitVolume: total sectors (%d) is incorrect, adjusting to match driver\n"), pvol->v_csecTotal));
pvol->v_csecTotal = pvol->v_pdsk->d_diActive.di_total_sectors - pvol->v_secBlkBias;
}
else
pvol->v_csecTotal -= pbpb->oldBPB.BPB_ReservedSectors;
#ifdef DEBUG
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -