part.cpp

来自「WinCE5.0部分核心源码」· C++ 代码 · 共 1,292 行 · 第 1/3 页

CPP
1,292
字号
//
// 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.
//

#include <windows.h>
#include <diskio.h>
#include <partdrv.h>
#include <fsdmgr.h>
#include "part.h"
#include "bpb.h"
#include "bootsec.h"
#include "drvdbg.h"

static DWORD LoadDiskInfo(PDriverState pState)
{
    DWORD dummy;
    
    // fail the open if we can't get params from the device driver
    if (!FSDMGR_DiskIoControl(pState->hDsk, DISK_IOCTL_GETINFO, &pState->diskInfo, sizeof(DISK_INFO), NULL, 0, &dummy, NULL))
    {
        return ERROR_GEN_FAILURE;
    }

    // simple check to verify the device is useful
    if (pState->diskInfo.di_bytes_per_sect == 0 || pState->diskInfo.di_total_sectors == 0)
    {
        return ERROR_GEN_FAILURE;
    }
    
    if (pState->diskInfo.di_heads == 0)
        pState->diskInfo.di_heads = 1;
        
    if (pState->diskInfo.di_cylinders == 0) 
        pState->diskInfo.di_cylinders = 1;

    if (pState->diskInfo.di_sectors == 0)
        pState->diskInfo.di_sectors = pState->diskInfo.di_total_sectors;
    
    return ERROR_SUCCESS;
}

/*****************************************************************************/


DWORD PD_OpenStore(HANDLE hDisk, LPDWORD pdwStoreId)
{
    PPARTENTRY      tmpbuffer;
    PartState       *pPartState;
    DriverState     *pState;
    DWORD           dwError=ERROR_SUCCESS, lastUsedSector;
    SECTORNUM       snPartSector;
    PBYTE           buffer = NULL;
    int             i;
       
    *pdwStoreId = NULL;
    DEBUGMSG( ZONE_API, (L"MSPART!PD_OpenStore hDisk=%08X\r\n", hDisk));
    pState = (PDriverState)LocalAlloc(LMEM_ZEROINIT, sizeof(DriverState));
    if (!pState)
        return ERROR_OUTOFMEMORY;

    // convert the device handle to a store handle for FSDMGR_* helper functions
    pState->hDsk = FSDMGR_DeviceHandleToHDSK(hDisk);

    dwError = LoadDiskInfo(pState);
    if (ERROR_SUCCESS != dwError) 
    {
        LocalFree(pState);
        return dwError;
    }

    // Find out if we should create primary partitions
    DWORD dwRegValue;
    FSDMGR_GetRegistryValue( pState->hDsk, TEXT("PrimaryPart"), (PDWORD)&dwRegValue);
    if (dwRegValue)
        pState->dwFlags |= MSPART_CREATE_PRIMARY;

    FSDMGR_GetRegistryValue( pState->hDsk, TEXT("AlignCylinder"), (PDWORD)&dwRegValue);
    if (dwRegValue)
        pState->dwFlags |= MSPART_ALIGN_CYLINDER;

    FSDMGR_GetRegistryValue( pState->hDsk, TEXT("SkipSector1"), (PDWORD)&dwRegValue);
    if (dwRegValue)
        pState->dwFlags |= MSPART_SKIP_SECTOR1;
    
    pState->pPartState = NULL;
    pState->pSearchState = NULL;

    // assume this is unformatted for now
    pState->bFormatState = FALSE;

    if (!ReadSectors(pState, 0, 1, &buffer)) {
        if (!(pState->diskInfo.di_flags & DISK_INFO_FLAG_UNFORMATTED)) {
            dwError = ERROR_READ_FAULT;
        }    
        goto Exit;
    }


    pPartState = NULL;
    snPartSector = 0;

    // process the DOS partition tables and potentially extended partition tables
    dwError = GetDOSPartitions (pState, &pPartState, buffer, FALSE, &snPartSector);
    if (dwError) {
        // If the sector has a boot signature and it is a FAT volume, then we assume that it is a superfloppy
        if (IS_VALID_BOOTSEC(buffer) && 
            (((PBOOTSEC)buffer)->bsBPB.BPB_BigTotalSectors || ((PBOOTSEC)buffer)->bsBPB.BPB_TotalSectors) &&
            (((PBOOTSEC)buffer)->bsBPB.BPB_BigTotalSectors != 0xffffffff))
        {
            dwError = ERROR_DEVICE_NOT_PARTITIONED;
            goto Exit;
        } 
        else 
        {
            // in this case, we don't fail the call, but the store is not formatted
            if (dwError == ERROR_INVALID_DATA) {
                dwError = ERROR_SUCCESS;

                //  For primary partitions, if there is a valid bootsig, then it is formatted.
                if ((pState->dwFlags & MSPART_CREATE_PRIMARY) && IS_VALID_BOOTSEC(buffer))
                    pState->bFormatState = TRUE;
                
                goto Exit;
            }
        }    
        dwError = ERROR_READ_FAULT;
        goto Exit;
    }

    // this drive has a valid partition table - do a sanity check to adjust the diskInfo structure in case this drive
    //  was formatted through another OS - if that's the case, our CHS geometry should match the previously used CHS
    //  this involves three assumptions: 1 - that all partitions in the partition table are using the same CHS geometry
    //  2 - the CHS parameters fit within the legacy restrictions of 6 bits/sector 8 bits/heads and 10 bits/cylinders
    //  3 - the partitions all end on a cylinder boundary

    tmpbuffer = (PPARTENTRY)(buffer + PARTTABLE_OFFSET);

    // there's no extended partition, add one now to hold our data, and use the rest of the disk
    if (pState->snExtPartSector == 0) {
        lastUsedSector = 0;

        for (i=0, tmpbuffer = (PPARTENTRY)(buffer + PARTTABLE_OFFSET); i < 4; i++, tmpbuffer++) {
            if (tmpbuffer->Part_TotalSectors == 0)
                continue;

            lastUsedSector = tmpbuffer->Part_StartSector + tmpbuffer->Part_TotalSectors -1;

            // the extended partition starts on the next cylinder boundary, so adjust if needed
            if (pState->diskInfo.di_heads > 1)
                lastUsedSector += ((pState->diskInfo.di_heads - (tmpbuffer->Part_LastHead +1)) * pState->diskInfo.di_sectors) + pState->diskInfo.di_sectors - (tmpbuffer->Part_LastSector & 0x3f);
        }

        // create an extended partition only if there's room on the disk and in the MBR
#if 0
	    BOOL            bResult;
        if ((lastUsedSector < (pState->diskInfo.di_total_sectors -1)) &&
            ((i != 3) || (!tmpbuffer->Part_TotalSectors)))
        {

            // if this fails, it's not because there's no room for it
            bResult = WriteMBR(pState, lastUsedSector + 1, pState->diskInfo.di_total_sectors - lastUsedSector -1, PART_EXTENDED, FALSE);
            if (!bResult) {
                PD_CloseStore((DWORD)pState);
                dwError = ERROR_WRITE_FAULT;
                goto Exit;
            }

            // we added it successfully, update the pState structure so we know where it is
            pState->snExtPartSector = lastUsedSector + 1;
            pState->snExtPartEndSec = pState->diskInfo.di_total_sectors - 1;

        }
#endif
        
    }

    // we have a valid format
    pState->bFormatState = TRUE;

#if HIDDEN_PARTITIONS
    pState->bUseHiddenPartitions = TRUE;
    // process the hidden partition table to add in the extra partition data that we track
    if (pState->pHiddenPartState) {
        bResult = GetHiddenPartitions (pState);

        GeneratePartitionNames(pState);

        if (!bResult) {
            UpdateFileTime(pState, NULL, TRUE, FALSE);
            if (!WriteHiddenPartitionTable(pState)) {
                pState->bUseHiddenPartitions = FALSE;
            }
        }
    } else {
        // no hidden partition, try to add one now
        if (!AddHiddenPartition(pState)) {
            pState->bUseHiddenPartitions = FALSE;
        } 

        GeneratePartitionNames(pState);

        if (pState->bUseHiddenPartitions) {
            UpdateFileTime(pState, NULL, TRUE, FALSE);
            if (!WriteHiddenPartitionTable(pState)) {
                pState->bUseHiddenPartitions = FALSE;
            }
        }
    }
#else
        GeneratePartitionNames(pState);
#endif
Exit:
    if (buffer) {
        LocalFree( buffer);
    }
    *pdwStoreId = (DWORD)pState;
    return dwError;
}



/*****************************************************************************/


DWORD PD_GetStoreInfo(DWORD dwStoreId, PPD_STOREINFO psi)
{

    BOOL    bResult;
    DriverState *pState = (PDriverState) dwStoreId;

    DEBUGMSG(ZONE_API, (L"MSPART!PD_GetStoreInfo: dwStoreId=%08X \r\n", dwStoreId));

    if (psi->cbSize != sizeof(PD_STOREINFO)) {
        return ERROR_INVALID_PARAMETER;
    }
    memset( psi, 0, sizeof(PD_STOREINFO));
    psi->cbSize = sizeof(PD_STOREINFO); 

    psi->ftCreated = pState->ftCreate;
    psi->ftLastModified = pState->ftAccess;
    psi->dwBytesPerSector = pState->diskInfo.di_bytes_per_sect;
    psi->snNumSectors = pState->diskInfo.di_total_sectors;

    bResult = CalculatePartitionSpace(pState, &psi->snFreeSectors, &psi->snBiggestPartCreatable);
    if (!bResult)
        return ERROR_GEN_FAILURE;

    if (!pState->bFormatState)
        psi->dwAttributes |= STORE_ATTRIBUTE_UNFORMATTED;
    
    return ERROR_SUCCESS;
}


/*****************************************************************************/


void PD_CloseStore(DWORD dwStoreId)
{
    DriverState *pState = (PDriverState)dwStoreId;
    ClearPartitionList(pState);
    LocalFree(pState);
}


/*****************************************************************************/


DWORD PD_FormatStore(DWORD dwStoreId)
{

    PBYTE           buffer = NULL;
    DWORD           bufferSize;
    DWORD           dummy;
    BOOL            bResult;
    DWORD           dwError;
    DriverState *pState = (PDriverState) dwStoreId;


    DEBUGMSG(ZONE_API, (L"PD_FormatStore: dwStoreId=%08X\n", dwStoreId));
    
    if (!FSDMGR_DiskIoControl(pState->hDsk, DISK_IOCTL_FORMAT_MEDIA, &(pState->diskInfo), sizeof(DISK_INFO), NULL, 0, &dummy, NULL)) {
        dwError= GetLastError();
        RETAILMSG(TRUE,(L"MSPART!FormatStore: Driver has failed low-level format request (%d)\n", dwError));
        return dwError? dwError : ERROR_GEN_FAILURE;
    }

    /* update the disk information structure */
    dwError = LoadDiskInfo(pState);
    if (ERROR_SUCCESS != dwError) {
        return dwError;
    }

    /* get an I/O buffer that is a multiple of the sector size */
    bufferSize = pState->diskInfo.di_bytes_per_sect * 8;
    buffer     = (PBYTE)LocalAlloc(LMEM_ZEROINIT, bufferSize);
    if (!buffer)
        return ERROR_OUTOFMEMORY;   

    if (pState->dwFlags & MSPART_CREATE_PRIMARY) {
        // add header and trailer info to the MBR.  Clear partition table.
        *(WORD *)(buffer + BOOT_SIGNATURE) = BOOTSECTRAILSIGH;
        buffer[0] = 0xE9;
        buffer[1] = 0xfd;
        buffer[2] = 0xff;
        memset (buffer + PARTTABLE_OFFSET, 0, MAX_PARTTABLE_ENTRIES * SIZE_PARTTABLE_ENTRIES);
    }     

    bResult = WriteSectors(pState, 0, bufferSize / pState->diskInfo.di_bytes_per_sect, buffer);

    LocalFree(buffer);

    if (!bResult)
        return ERROR_WRITE_FAULT;


    // if we are formatted a previously formatted store, we need to clear out the existing partition structures first
    if (pState->bFormatState)
        ClearPartitionList(pState);
    pState->dwNumParts = 0;

    if (!(pState->dwFlags & MSPART_CREATE_PRIMARY)) {

        // carve out the extended partition

        // skip to the next cylinder boundary        
        if (pState->diskInfo.di_heads > 1)
            pState->snExtPartSector = pState->diskInfo.di_sectors * pState->diskInfo.di_heads;
        else
            pState->snExtPartSector = 1;

        pState->snExtPartEndSec = pState->diskInfo.di_total_sectors - 1;

        bResult = WriteMBR(pState, pState->snExtPartSector, pState->diskInfo.di_total_sectors - pState->snExtPartSector, PART_EXTENDED, TRUE);
        if (!bResult)
            return ERROR_WRITE_FAULT;
    }
        
#if HIDDEN_PARTITIONS
    pState->bUseHiddenPartitions = TRUE;
    // next create a PBR for the hidden partition
    bResult = AddHiddenPartition(pState);
    if (!bResult) {
        pState->bUseHiddenPartitions = FALSE;
    } else {    
        UpdateFileTime(pState, NULL, TRUE, FALSE);
        WriteHiddenPartitionTable(pState);
    }    
#endif
    
    if (bResult)
        pState->bFormatState = TRUE;

    return bResult ? ERROR_SUCCESS : ERROR_GEN_FAILURE;
}

/*****************************************************************************/


DWORD PD_IsStoreFormatted(DWORD dwStoreId)
{
    PDriverState pState = (PDriverState) dwStoreId;

    return pState->bFormatState ? ERROR_SUCCESS : ERROR_BAD_FORMAT;
}


/*****************************************************************************/

DWORD PD_CreatePartition(DWORD dwStoreId, LPCTSTR szPartitionName, BYTE bPartType, SECTORNUM snNumSectors, BOOL bAuto)
{
    PartState    *pNewPartState;
    PartState    *pTmpPartState;
    SearchState  *pSearchState;
    BOOL            bResult;
    SECTORNUM       snStartSector = 0;
    SECTORNUM       snNextPBRSector;
    SECTORNUM       snPrevPBRSector;
    SECTORNUM       snSectorCount;
    SECTORNUM       snPBRSector;
    DriverState     *pState = (PDriverState) dwStoreId;

    DEBUGMSG (ZONE_API,(L"MSPART!PD_CreatePartition: dwStoreId=%08X, PartName %s, PartType=%ld, NumSectors=%d Auto=%s\n", dwStoreId, szPartitionName, bPartType, (DWORD)snNumSectors, bAuto ? L"TRUE" : L"FALSE"));

    if (!pState->bFormatState) { 
        return ERROR_BAD_FORMAT;
    }

    if (!wcslen(szPartitionName)) {
        return ERROR_INVALID_NAME;
    }
    
    if ((!snNumSectors) || (snNumSectors > pState->diskInfo.di_total_sectors)) {
        return ERROR_DISK_FULL;
    }

    GetPartition(pState, &pTmpPartState, NULL, szPartitionName);

    // don't allow the create if the name is not unique
    if (pTmpPartState) {
        return ERROR_ALREADY_EXISTS;
    }

    // the number of partitions is historically limited to the # of drive letters available through the extended partition
    if (pState->dwNumParts == 24) {
        return ERROR_PARTITION_FAILURE;
    }

#if HIDDEN_PARTITIONS
    // if we don't have a hidden partition, we probably don't have room for this one either
    // but we'll try to create the hidden partition first and then if that works create the one requested
    if (pState->bUseHiddenPartitions) {
        UpdateFileTime(pState, NULL, TRUE, FALSE);
        if (!WriteHiddenPartitionTable(pState)) {
            pState->bUseHiddenPartitions = FALSE;
        }   
    }
#endif    

    bResult = GetPartLocation (pState, snNumSectors, bPartType, &pTmpPartState, &snStartSector, &snPBRSector, &snSectorCount);
    if (!bResult)
        return ERROR_PARTITION_FAILURE;

    pNewPartState = (PPartState)LocalAlloc(LMEM_ZEROINIT, sizeof(PartState));
    if (!pNewPartState)
        return ERROR_OUTOFMEMORY;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?