📄 format.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:
format.c
Abstract:
This file contains routines for formatting volumes.
Revision History:
--*/
#include "fatfs.h"
/* FormatVolume - Format a volume
*
* ENTRY
* pvol - pointer to VOLUME
* pfv - pointer to FMTVOLREQ structure (NULL if none)
*
* EXIT
* ERROR_SUCCESS if successful, error code if not
*
* NOTES
* Note that some of the values calculated by this function are arbitrary
* (eg, 256 root directory entries for SRAM cards vs. 512 root entries for
* ATA cards; no backup FATs unless specifically requested by the caller; etc).
* Which means the resulting volume may not exactly match what an MS-DOS or
* Win95 FORMAT utility would have created, but the volume should still be a
* legitimate FAT volume, and so hopefully all MS-DOS-based or Win95-based systems
* will have no problem mounting/reading it.
*/
DWORD FormatVolume(PVOLUME pvol, PFMTVOLREQ pfv)
{
DWORD dwFlags;
int iFAT, cLoops;
BYTE cFATs, bMediaDesc;
DWORD csecReserved, cRootEntries;
DWORD sec, csecHidden, csecClus;
DWORD csecFATs, csecFATsLast;
DWORD csecRoot, csecData, cclusData;
DEVPB devpb, volpb;
DWORD cbitsClus, secVolBias;
DWORD dwError = ERROR_SUCCESS;
BYTE abSector[DEFAULT_SECTOR_SIZE];
TCHAR szVolumeName[MAX_PATH];
dwFlags = FMTVOL_QUICK;
if (pfv)
dwFlags = pfv->fv_flags;
// All we support right now is "quick format"
if (!(dwFlags & FMTVOL_QUICK))
return ERROR_INVALID_FUNCTION;
// Now we can proceed with the "logical" formatting process...
QueryVolumeParameters(pvol, &volpb, TRUE);
QueryVolumeParameters(pvol, &devpb, FALSE);
if (devpb.DevPrm.OldDevPB.BPB.BPB_BytesPerSector != sizeof(abSector)) {
DEBUGMSG(ZONE_INIT || ZONE_ERRORS,(DBGTEXT("FATFS!FormatVolume: unsupported sector size (%d)\n"), devpb.DevPrm.OldDevPB.BPB.BPB_BytesPerSector));
return ERROR_GEN_FAILURE;
}
// Determine if we need to format the entire device or if the volume is already
// sufficiently well-defined. Don't bother with a backup FAT unless caller requests it.
cFATs = 1;
if (dwFlags & FMTVOL_BACKUP_FAT)
cFATs++;
cRootEntries = 256;
if (dwFlags & FMTVOL_ROOT_ENTRIES)
cRootEntries = pfv->fv_cRootEntries;
csecReserved = 1;
secVolBias = 0;
csecHidden = devpb.DevPrm.OldDevPB.BPB.BPB_HiddenSectors = 0;
// If there's partition information for this volume, use it; otherwise,
// rely on any existing volume information (for the case where we're being reformatted)
if (pvol->v_ppi) {
secVolBias = pvol->v_ppi->pi_secAbsolute;
devpb.DevPrm.OldDevPB.BPB.BPB_HiddenSectors = pvol->v_ppi->pi_secAbsolute;
if (pvol->v_ppi->pi_ppiParent)
devpb.DevPrm.OldDevPB.BPB.BPB_HiddenSectors -= pvol->v_ppi->pi_secPartTable;
devpb.DevPrm.OldDevPB.BPB.BPB_BigTotalSectors = pvol->v_ppi->pi_PartEntry.Part_TotalSectors;
}
else if (volpb.DevPrm.OldDevPB.BPB.BPB_BigTotalSectors != 0 && !(dwFlags & FMTVOL_DISK)) {
secVolBias = pvol->v_secVolBias;
devpb.DevPrm.OldDevPB.BPB.BPB_HiddenSectors = volpb.DevPrm.OldDevPB.BPB.BPB_HiddenSectors;
devpb.DevPrm.OldDevPB.BPB.BPB_BigTotalSectors = volpb.DevPrm.OldDevPB.BPB.BPB_BigTotalSectors;
}
// Compute new volume characteristics now
if (dwFlags & FMTVOL_VOLUME_SIZE) {
// But you can't make the volume *bigger* than it really is...
if (pfv->fv_csecVol > devpb.DevPrm.OldDevPB.BPB.BPB_BigTotalSectors)
return ERROR_INVALID_PARAMETER;
devpb.DevPrm.OldDevPB.BPB.BPB_BigTotalSectors = pfv->fv_csecVol;
}
// Determine if this is disk should be partitioned (and have hidden sectors)
if (devpb.DevPrm.OldDevPB.bMediaType == MEDIA_HD) {
// Partitioned disks typically reserve the entire first track,
// although only the first sector is used. Carry the tradition forward...
if (!(dwFlags & FMTVOL_ROOT_ENTRIES))
cRootEntries = 512;
if (secVolBias == 0)
csecHidden = devpb.DevPrm.OldDevPB.BPB.BPB_HiddenSectors = devpb.DevPrm.OldDevPB.BPB.BPB_SectorsPerTrack;
}
if (csecHidden || devpb.DevPrm.OldDevPB.BPB.BPB_HiddenSectors)
bMediaDesc = MEDIA_HD;
else
bMediaDesc = MEDIA_1440;
csecClus = 1;
if (dwFlags & FMTVOL_CLUSTER_SIZE) {
csecClus = pfv->fv_csecClus;
// Make sure the cluster size is valid, fits in a byte, and is a power of two...
if (csecClus == 0 || csecClus > 255 || (csecClus & (csecClus-1)))
return ERROR_INVALID_PARAMETER;
}
// Compute how many clusters will fit on the media, by first estimating
// how many sectors will be in the data area, then recomputing the number
// of clusters until we get a consistent answer.
restart:
do {
cLoops = 4;
csecFATs = csecRoot = 0;
do {
csecData = devpb.DevPrm.OldDevPB.BPB.BPB_BigTotalSectors -
csecHidden - csecReserved - csecFATs - csecRoot;
do {
cclusData = csecData / csecClus;
if (csecClus > (DWORD)(MAX_CLUS_SIZE/devpb.DevPrm.OldDevPB.BPB.BPB_BytesPerSector)) {
DEBUGMSG(ZONE_INIT || ZONE_ERRORS,(DBGTEXT("FATFS!FormatVolume: media too large (%d clusters at %d secs/clus)\n"), dwError, cclusData, csecClus));
// If a volume size has been specified, then we have to bail
if (dwFlags & FMTVOL_VOLUME_SIZE)
return ERROR_INVALID_PARAMETER;
dwFlags |= FMTVOL_VOLUME_SIZE;
#ifdef FAT32
devpb.DevPrm.OldDevPB.BPB.BPB_BigTotalSectors = (FAT32_BAD-1)*(MAX_CLUS_SIZE/devpb.DevPrm.OldDevPB.BPB.BPB_BytesPerSector);
#else
devpb.DevPrm.OldDevPB.BPB.BPB_BigTotalSectors = (FAT16_BAD-1)*(MAX_CLUS_SIZE/devpb.DevPrm.OldDevPB.BPB.BPB_BytesPerSector);
#endif
goto restart;
}
if (!(dwFlags & (FMTVOL_16BIT_FAT | FMTVOL_32BIT_FAT))) {
if (cclusData < FAT1216_THRESHOLD) {
cbitsClus = 12; // Should use a 12-bit FAT
break;
}
}
if (!(dwFlags & (FMTVOL_12BIT_FAT | FMTVOL_32BIT_FAT))) {
if (cclusData < FAT1632_THRESHOLD) {
cbitsClus = 16; // Should use a 16-bit FAT
break;
}
}
#ifndef FAT32
csecClus *= 2; // if no FAT32 support, no choice but to grow cluster size
#else
// So, at the current cluster size, a 32-bit FAT is the only answer;
// however, we won't settle on that as long as the cluster size is still small
// (less than 4K) AND the cluster was not explicitly selected by the caller.
if (!(dwFlags & (FMTVOL_CLUSTER_SIZE | FMTVOL_32BIT_FAT)) &&
csecClus < (DWORD)(4096/devpb.DevPrm.OldDevPB.BPB.BPB_BytesPerSector)) {
csecClus *= 2; // grow the cluster size
}
else {
// Bite the bullet and go with a 32-bit FAT; note that FAT32 also requires
// more than the usual number of reserved sectors, which we need to "reserve" now.
cbitsClus = 32;
csecReserved = 2; // why only 2? see "minimalist" comments below...
break;
}
#endif
} while (TRUE);
// NOTE: when computing csecFATs, we must add DATA_CLUSTER (2) to cclusData, because
// the first two entries in a FAT aren't real entries, but we must still account for them.
csecFATsLast = csecFATs;
csecFATs = (((cclusData+DATA_CLUSTER) * cbitsClus + 7)/8 + devpb.DevPrm.OldDevPB.BPB.BPB_BytesPerSector-1) / devpb.DevPrm.OldDevPB.BPB.BPB_BytesPerSector * cFATs;
#ifdef FAT32
if (cbitsClus == 32) // csecRoot comes into play only on non-FAT32 volumes
csecRoot = 0;
else
#endif
csecRoot = (sizeof(DIRENTRY) * cRootEntries + devpb.DevPrm.OldDevPB.BPB.BPB_BytesPerSector-1) / devpb.DevPrm.OldDevPB.BPB.BPB_BytesPerSector;
} while (csecFATs != csecFATsLast && --cLoops);
if (cLoops)
break;
// We couldn't get a consistent answer, so chop off one cluster
devpb.DevPrm.OldDevPB.BPB.BPB_BigTotalSectors -= csecClus;
} while (TRUE);
DEBUGMSG (ZONE_INIT,(DBGTEXT ("FATFS!FormatVolume:\n\n")));
DEBUGMSGW(ZONE_INIT,(DBGTEXTW("Disk type: %s\n"), csecHidden || devpb.DevPrm.OldDevPB.BPB.BPB_HiddenSectors? TEXTW("fixed") : TEXTW("removable")));
DEBUGMSG (ZONE_INIT,(DBGTEXT ("Sectors/FAT: %d (%d FATs)\n"), csecFATs/cFATs, cFATs));
DEBUGMSG (ZONE_INIT,(DBGTEXT ("New cluster size: %d (%d-bit FAT)\n"), csecClus * devpb.DevPrm.OldDevPB.BPB.BPB_BytesPerSector, cbitsClus));
DEBUGMSG (ZONE_INIT,(DBGTEXT ("New total clusters: %d\n"), cclusData));
DEBUGMSG (ZONE_INIT,(DBGTEXT ("Total available space: %d bytes\n\n"), cclusData * csecClus * devpb.DevPrm.OldDevPB.BPB.BPB_BytesPerSector));
// Now try to lock the volume in preparation for writing
dwError = LockVolume(pvol, VOLF_LOCKED);
if (dwError) {
DEBUGMSG(ZONE_INIT || ZONE_ERRORS,(DBGTEXT("FATFS!FormatVolume: cannot lock volume (%d)\n"), dwError));
goto abort;
}
// We will invalidate all buffers now, whether dirty or not, since we're about to rewrite
// the disk structure. Note that LockVolume is already supposed to insure that any threads
// that might have missed the locking transition have left FATFS, so there shouldn't be any
// risk of this invalidation being undone by another thread still modifying the disk state.
InvalidateBufferSet(pvol, TRUE);
pvol->v_flags |= VOLF_FORMATTING;
// Now write a new partition table if this is a partitioned disk and we're
// reformatting the whole disk...
if (csecHidden) {
PPARTENTRY ppe;
DWORD maxCyl =
devpb.DevPrm.OldDevPB.BPB.BPB_BigTotalSectors /
(devpb.DevPrm.OldDevPB.BPB.BPB_Heads * devpb.DevPrm.OldDevPB.BPB.BPB_SectorsPerTrack) - 1;
// The bulk of the partition sector needs to be zeroed.
memset(abSector, 0, devpb.DevPrm.OldDevPB.BPB.BPB_BytesPerSector);
abSector[0] = BS3BYTJMP;
abSector[1] = 0xfd;
abSector[2] = 0xff;
// Point to first partition table slot (the only one we're going to fill)
ppe = (PPARTENTRY)(abSector+PARTTABLE_OFFSET);
ppe->Part_BootInd = PART_BOOTABLE;
ppe->Part_FirstHead = 1;
ppe->Part_FirstSector = 1;
ppe->Part_FirstTrack = 0;
if (cbitsClus == 12) {
ppe->Part_FileSystem = PART_DOS2_FAT; // 12-bit FAT ID
} else {
#ifdef FAT32
if (cbitsClus == 32)
ppe->Part_FileSystem = PART_DOS32X13; // 32-bit FAT ID
else
#endif
if (devpb.DevPrm.OldDevPB.BPB.BPB_BigTotalSectors < 65536)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -