638 lines
16 KiB
C++
638 lines
16 KiB
C++
/*++
|
||
|
||
Copyright (c) 1999 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
wsbfmt.cpp
|
||
|
||
Abstract:
|
||
|
||
This module implements file-system formatting support routines
|
||
|
||
Author:
|
||
|
||
Ravisankar Pudipeddi [ravisp] 19, January 2000
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
|
||
#include <stdafx.h>
|
||
extern "C" {
|
||
#include <ntdddisk.h>
|
||
#include <fmifs.h>
|
||
}
|
||
#include <wsbfmt.h>
|
||
|
||
|
||
#define MAX_FS_NAME_SIZE 256
|
||
#define MAX_PARAMS 20
|
||
#define INVALID_KEY 0
|
||
|
||
typedef struct _FORMAT_PARAMS {
|
||
PWSTR volumeSpec;
|
||
PWSTR label;
|
||
PWSTR fsName;
|
||
LONG fsType;
|
||
ULONG fsflags;
|
||
ULONG allocationUnitSize; // Cluster size in Bytes
|
||
HRESULT result;
|
||
ULONG threadId;
|
||
PFMIFS_ENABLECOMP_ROUTINE compressRoutine;
|
||
PFMIFS_FORMAT_ROUTINE formatRoutine;
|
||
PFMIFS_FORMATEX2_ROUTINE formatRoutineEx;
|
||
BOOLEAN quick;
|
||
BOOLEAN force;
|
||
BOOLEAN cancel;
|
||
} FORMAT_PARAMS, *PFORMAT_PARAMS;
|
||
|
||
typedef struct _FM_ENTRY {
|
||
ULONG key;
|
||
PFORMAT_PARAMS val;
|
||
} FM_ENTRY, *PFM_ENTRY;
|
||
|
||
static FM_ENTRY formatParamsTable[MAX_PARAMS];
|
||
static PFMIFS_FORMATEX2_ROUTINE FormatRoutineEx = NULL;
|
||
static PFMIFS_FORMAT_ROUTINE FormatRoutine = NULL;
|
||
static PFMIFS_SETLABEL_ROUTINE LabelRoutine = NULL;
|
||
static PFMIFS_ENABLECOMP_ROUTINE CompressRoutine = NULL;
|
||
static HINSTANCE IfsDllHandle = NULL;
|
||
|
||
void MountFileSystem(PWSTR volumeSpec);
|
||
|
||
|
||
HRESULT GetFormatParam(IN ULONG key, OUT PFORMAT_PARAMS *fp)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Returns the format parameter structure indexed by the
|
||
supplied key
|
||
|
||
Arguments:
|
||
|
||
key - key indexing the format params
|
||
fp - pointer to format params returned in this var.
|
||
|
||
Return Value:
|
||
S_OK if found
|
||
S_FALSE if not
|
||
|
||
--*/
|
||
{
|
||
HRESULT hr = S_FALSE;
|
||
ULONG i;
|
||
|
||
WsbTraceIn(OLESTR("GetFormatParam"), OLESTR(""));
|
||
|
||
for (i = 0; i < MAX_PARAMS; i++) {
|
||
if (formatParamsTable[i].key == key) {
|
||
hr = S_OK;
|
||
*fp = formatParamsTable[i].val;
|
||
break;
|
||
}
|
||
}
|
||
|
||
WsbTraceOut(OLESTR("GetFormatParam"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
|
||
return hr;
|
||
}
|
||
|
||
|
||
HRESULT SetFormatParam(IN ULONG key, IN PFORMAT_PARAMS fp)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Finds a free slot and stores the supplied format params,
|
||
indexed by the key
|
||
|
||
Arguments:
|
||
key - key indexing the format params
|
||
fp - pointer to format params
|
||
|
||
Return Value:
|
||
|
||
S_OK - Found a slot and stored the format params
|
||
E_OUTOFMEMORY - Couldn't find a slot: too many formats in progress
|
||
|
||
--*/
|
||
{
|
||
HRESULT hr = E_OUTOFMEMORY;
|
||
ULONG i;
|
||
|
||
WsbTraceIn(OLESTR("SetFormatParam"), OLESTR(""));
|
||
for (i = 0; i < MAX_PARAMS; i++) {
|
||
if (formatParamsTable[i].key == INVALID_KEY) {
|
||
hr = S_OK;
|
||
formatParamsTable[i].val = fp;
|
||
formatParamsTable[i].key = key;
|
||
break;
|
||
}
|
||
}
|
||
|
||
WsbTraceOut(OLESTR("SetFormatParam"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
|
||
return hr;
|
||
}
|
||
|
||
|
||
HRESULT DeleteFormatParam(IN ULONG key)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Locates the format params indexed by the key, deletes all allocated structures
|
||
and frees up the slot
|
||
|
||
Arguments:
|
||
|
||
key - key indexing the format params
|
||
|
||
Return Value:
|
||
|
||
|
||
S_OK - if format params found and deleted
|
||
E_FAIL - if not
|
||
--*/
|
||
{
|
||
PFORMAT_PARAMS formatParams;
|
||
HRESULT hr = E_FAIL;
|
||
ULONG i;
|
||
|
||
WsbTraceIn(OLESTR("DeleteFormatParam"), OLESTR(""));
|
||
for (i = 0; i < MAX_PARAMS; i++) {
|
||
if (formatParamsTable[i].key == key) {
|
||
hr = S_OK;
|
||
formatParams = formatParamsTable[i].val;
|
||
if (formatParams) {
|
||
if (formatParams->volumeSpec) {
|
||
delete [] formatParams->volumeSpec;
|
||
}
|
||
if (formatParams->label) {
|
||
delete [] formatParams->label;
|
||
}
|
||
if (formatParams->fsName) {
|
||
delete [] formatParams->fsName;
|
||
}
|
||
}
|
||
formatParamsTable[i].key = INVALID_KEY;
|
||
formatParamsTable[i].val = NULL;
|
||
break;
|
||
}
|
||
}
|
||
|
||
WsbTraceOut(OLESTR("DeleteFormatParam"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
|
||
return hr;
|
||
}
|
||
|
||
|
||
|
||
BOOL
|
||
LoadIfsDll(void)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Loads the FMIFS DLL and stores the handle to it in IfsDllHandle
|
||
Also sets the FormatXXX, LabelXXX, CompressXXX routines
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Value:
|
||
|
||
TRUE if dll was loaded successfully
|
||
FALSE if not
|
||
|
||
--*/
|
||
{
|
||
BOOL retVal = TRUE;
|
||
|
||
WsbTraceIn(OLESTR("LoadIfsDll"), OLESTR(""));
|
||
|
||
if (IfsDllHandle != NULL) {
|
||
|
||
// Library is already loaded and the routines needed
|
||
// have been located.
|
||
|
||
retVal = TRUE;
|
||
goto exit;
|
||
}
|
||
|
||
IfsDllHandle = LoadLibrary(L"fmifs.dll");
|
||
if (IfsDllHandle == (HANDLE)NULL) {
|
||
// FMIFS not available.
|
||
retVal = FALSE;
|
||
goto exit;
|
||
}
|
||
|
||
// Library is loaded. Locate the two routines needed
|
||
|
||
FormatRoutineEx = (PFMIFS_FORMATEX2_ROUTINE) GetProcAddress(IfsDllHandle, "FormatEx2");
|
||
FormatRoutine = (PFMIFS_FORMAT_ROUTINE) GetProcAddress(IfsDllHandle, "Format");
|
||
LabelRoutine = (PFMIFS_SETLABEL_ROUTINE) GetProcAddress(IfsDllHandle, "SetLabel");
|
||
CompressRoutine = (PFMIFS_ENABLECOMP_ROUTINE) GetProcAddress(IfsDllHandle,
|
||
"EnableVolumeCompression");
|
||
if (!FormatRoutine || !LabelRoutine || !FormatRoutineEx) {
|
||
|
||
// Couldn't find something, so shut down all access
|
||
// to the library by ensuring FormatRoutine is NULL
|
||
FreeLibrary(IfsDllHandle);
|
||
FormatRoutine = NULL;
|
||
FormatRoutineEx = NULL;
|
||
LabelRoutine = NULL;
|
||
retVal = FALSE;
|
||
}
|
||
|
||
exit:
|
||
|
||
WsbTraceOut(OLESTR("LoadIfsDll"), OLESTR("result = <%ls>"), WsbBoolAsString(retVal));
|
||
|
||
return retVal;
|
||
}
|
||
|
||
|
||
|
||
void
|
||
UnloadIfsDll(void)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Unloads the FMIFS dll
|
||
|
||
Arguments:
|
||
|
||
none
|
||
|
||
Return Value:
|
||
|
||
TRUE if unloaded
|
||
|
||
--*/
|
||
{
|
||
WsbTraceIn(OLESTR("UnloadIfsDll"), OLESTR(""));
|
||
if (IfsDllHandle != (HANDLE) NULL) {
|
||
FreeLibrary(IfsDllHandle);
|
||
FormatRoutine = NULL;
|
||
FormatRoutineEx = NULL;
|
||
IfsDllHandle = NULL;
|
||
LabelRoutine = NULL;
|
||
}
|
||
WsbTraceOut(OLESTR("UnloadIfsDll"), OLESTR(""));
|
||
}
|
||
|
||
BOOL
|
||
FmIfsCallback(IN FMIFS_PACKET_TYPE PacketType,
|
||
IN ULONG PacketLength,
|
||
IN PVOID PacketData)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine gets callbacks from fmifs.dll regarding
|
||
progress and status of the ongoing format
|
||
|
||
Arguments:
|
||
|
||
[PacketType] -- an fmifs packet type
|
||
[PacketLength] -- length of the packet data
|
||
[PacketData] -- data associated with the packet
|
||
|
||
Return Value:
|
||
|
||
TRUE if the fmifs activity should continue, FALSE if the
|
||
activity should halt immediately.
|
||
|
||
--*/
|
||
{
|
||
BOOL ret = TRUE;
|
||
WCHAR driveName[256];
|
||
PFORMAT_PARAMS formatParams;
|
||
|
||
UNREFERENCED_PARAMETER(PacketLength);
|
||
|
||
WsbTraceIn(OLESTR("FmIfsCallback"), OLESTR(""));
|
||
|
||
if (GetFormatParam(GetCurrentThreadId(), &formatParams) != S_OK) {
|
||
formatParams->result = E_FAIL;
|
||
goto exit;
|
||
}
|
||
//
|
||
// Cancel if needed
|
||
//
|
||
if (formatParams->cancel) {
|
||
formatParams->result = E_ABORT;
|
||
} else {
|
||
|
||
switch (PacketType) {
|
||
case FmIfsPercentCompleted:
|
||
if (((PFMIFS_PERCENT_COMPLETE_INFORMATION)
|
||
PacketData)->PercentCompleted % 10 == 0) {
|
||
WsbTrace(L"FmIfsPercentCompleted: %d%%\n",
|
||
((PFMIFS_PERCENT_COMPLETE_INFORMATION)
|
||
PacketData)->PercentCompleted);
|
||
}
|
||
break;
|
||
|
||
case FmIfsFormatReport:
|
||
WsbTrace(OLESTR("Format total kB: %d available kB %d\n"),
|
||
((PFMIFS_FORMAT_REPORT_INFORMATION)PacketData)->KiloBytesTotalDiskSpace,
|
||
((PFMIFS_FORMAT_REPORT_INFORMATION)PacketData)->KiloBytesAvailable);
|
||
break;
|
||
|
||
case FmIfsIncompatibleFileSystem:
|
||
formatParams->result = WSB_E_INCOMPATIBLE_FILE_SYSTEM;
|
||
break;
|
||
|
||
case FmIfsInsertDisk:
|
||
break;
|
||
|
||
case FmIfsFormattingDestination:
|
||
break;
|
||
|
||
case FmIfsIncompatibleMedia:
|
||
formatParams->result = WSB_E_BAD_MEDIA;
|
||
break;
|
||
|
||
case FmIfsAccessDenied:
|
||
formatParams->result = E_ACCESSDENIED;
|
||
break;
|
||
|
||
case FmIfsMediaWriteProtected:
|
||
formatParams->result = WSB_E_WRITE_PROTECTED;
|
||
break;
|
||
|
||
case FmIfsCantLock:
|
||
formatParams->result = WSB_E_CANT_LOCK;
|
||
break;
|
||
|
||
case FmIfsBadLabel:
|
||
formatParams->result = WSB_E_BAD_LABEL;
|
||
break;
|
||
|
||
case FmIfsCantQuickFormat:
|
||
formatParams->result = WSB_E_CANT_QUICK_FORMAT;
|
||
break;
|
||
|
||
case FmIfsIoError:
|
||
formatParams->result = WSB_E_IO_ERROR;
|
||
break;
|
||
|
||
case FmIfsVolumeTooSmall:
|
||
formatParams->result = WSB_E_VOLUME_TOO_SMALL;
|
||
break;
|
||
|
||
case FmIfsVolumeTooBig:
|
||
formatParams->result = WSB_E_VOLUME_TOO_BIG;
|
||
break;
|
||
|
||
case FmIfsClusterSizeTooSmall:
|
||
formatParams->result = E_FAIL;
|
||
break;
|
||
|
||
case FmIfsClusterSizeTooBig:
|
||
formatParams->result = E_FAIL;
|
||
break;
|
||
|
||
case FmIfsClustersCountBeyond32bits:
|
||
formatParams->result = E_FAIL;
|
||
break;
|
||
|
||
case FmIfsFinished:
|
||
|
||
if (formatParams->result == S_OK) {
|
||
ret = ((PFMIFS_FINISHED_INFORMATION) PacketData)->Success;
|
||
if (ret) {
|
||
MountFileSystem(formatParams->volumeSpec);
|
||
WsbTrace(OLESTR("Format finished for %S filesystem on %S label %S\n"),
|
||
formatParams->fsName, formatParams->volumeSpec, formatParams->label );
|
||
if ((formatParams->compressRoutine != NULL) && !wcscmp(formatParams->fsName , L"NTFS") && (formatParams->fsflags & WSBFMT_ENABLE_VOLUME_COMPRESSION)) {
|
||
swprintf(driveName, L"%s\\", formatParams->volumeSpec);
|
||
(formatParams->compressRoutine)(driveName, COMPRESSION_FORMAT_DEFAULT);
|
||
}
|
||
} else {
|
||
WsbTrace(OLESTR("Format finished failure with ret = %d\n"),ret);
|
||
formatParams->result = WSB_E_FORMAT_FAILED;
|
||
}
|
||
ret = FALSE;
|
||
}
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
exit:
|
||
|
||
if (formatParams->result != S_OK) {
|
||
ret = FALSE;
|
||
}
|
||
|
||
WsbTraceOut(OLESTR("FmIfsCallback"), OLESTR("result = <%ls>"), WsbBoolAsString(ret));
|
||
return ret;
|
||
}
|
||
|
||
|
||
|
||
void
|
||
MountFileSystem(PWSTR mountPoint)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Ensures a filesystem is mounted at the given root:
|
||
a) Opens the mount point and closes it.
|
||
b) Does a FindFirstFile on the mount point
|
||
|
||
The latter may sound redundant but is not because if we create the first
|
||
FAT32 filesystem then just opening and closing is not enough
|
||
|
||
|
||
Arguments:
|
||
|
||
mountPoint - path name to the root of filesystem to be mounted
|
||
|
||
Return Value:
|
||
|
||
none
|
||
|
||
--*/
|
||
{
|
||
WCHAR buffer[1024];
|
||
HANDLE handle;
|
||
WIN32_FIND_DATA fileData;
|
||
|
||
WsbTraceIn(OLESTR("MountFileSystem"), OLESTR(""));
|
||
|
||
handle = CreateFile(mountPoint, GENERIC_READ | GENERIC_WRITE,
|
||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||
0, OPEN_EXISTING, 0, 0);
|
||
if (handle != INVALID_HANDLE_VALUE)
|
||
CloseHandle(handle);
|
||
swprintf(buffer,L"%s\\*.*",mountPoint);
|
||
/*
|
||
* Go ahead and try to find the first file, this will make sure that
|
||
* the file system is mounted
|
||
*/
|
||
handle = FindFirstFile(buffer, &fileData);
|
||
if (handle != INVALID_HANDLE_VALUE) {
|
||
FindClose(handle);
|
||
}
|
||
WsbTraceOut(OLESTR("MountFileSystem"), OLESTR(""));
|
||
}
|
||
|
||
|
||
void
|
||
FormatVolume(IN PFORMAT_PARAMS params)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine format the volume described by params
|
||
|
||
Arguments:
|
||
|
||
params - pointer to the FORMAT_PARAMS describing the volume,
|
||
file system to be formatted to, quick/force etc.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
params->result contains the result of this operation
|
||
|
||
--*/
|
||
{
|
||
FMIFS_FORMATEX2_PARAM exParam;
|
||
HRESULT hr = S_OK;
|
||
|
||
WsbTraceIn(OLESTR("FormatVolume"), OLESTR(""));
|
||
/*
|
||
* Get the object corresponding to the storage Id and
|
||
* and notify all clients that the region has changed
|
||
* i.e. there is a format in progress on that region
|
||
*/
|
||
memset(&exParam, 0, sizeof(exParam));
|
||
exParam.Major = 1;
|
||
exParam.Minor = 0;
|
||
if (params->quick) {
|
||
exParam.Flags |= FMIFS_FORMAT_QUICK;
|
||
}
|
||
if (params->force) {
|
||
exParam.Flags |= FMIFS_FORMAT_FORCE;
|
||
}
|
||
exParam.LabelString = params->label;
|
||
exParam.ClusterSize = params->allocationUnitSize;
|
||
(params->formatRoutineEx)(params->volumeSpec,
|
||
FmMediaUnknown,
|
||
params->fsName,
|
||
&exParam,
|
||
(FMIFS_CALLBACK)&FmIfsCallback);
|
||
|
||
if (params->result == NULL) {
|
||
/* Format is successful so we lock unlock the filesystem */
|
||
MountFileSystem(params->volumeSpec);
|
||
}
|
||
DeleteFormatParam(params->threadId);
|
||
WsbTraceOut(OLESTR("FormatVolume"), OLESTR(""));
|
||
}
|
||
|
||
|
||
HRESULT
|
||
FormatPartition(IN PWSTR volumeSpec,
|
||
IN LONG fsType,
|
||
IN PWSTR label,
|
||
IN ULONG fsflags,
|
||
IN BOOLEAN quick,
|
||
IN BOOLEAN force,
|
||
IN ULONG allocationUnitSize)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Entry point for formatting a volume.
|
||
No defaults are assumed and all parameters need to be supplied
|
||
|
||
Arguments:
|
||
|
||
volumeSpec - Drive letter or name of volume
|
||
fsType - One of FSTYPE_FAT, FSTYPE_FAT32, FSTYE_NTFS
|
||
label - Volume label to be assigned to the partition/volume
|
||
fsflags - Flags describing desired characteristics
|
||
quick - If TRUE, a quick format is attempted
|
||
force - If TRUE a force format is done
|
||
allocationUnitSize -
|
||
cluster size
|
||
|
||
Return Value:
|
||
|
||
Result of the operation
|
||
|
||
--*/
|
||
{
|
||
FORMAT_PARAMS params;
|
||
|
||
WsbTraceIn(OLESTR("FormatPartition"), OLESTR(""));
|
||
|
||
if (fsType > 0 && !LoadIfsDll()) // fsType is +ve for FAT, FAT32 and NTFS which are supported by fmifs
|
||
{
|
||
// could not load the Dll
|
||
WsbTrace(OLESTR("Can't load fmifs.dll\n"));
|
||
return E_FAIL;
|
||
}
|
||
|
||
params.volumeSpec = new WCHAR[wcslen(volumeSpec) + 1];
|
||
if (params.volumeSpec == NULL) {
|
||
return E_INVALIDARG;
|
||
}
|
||
|
||
params.label = new WCHAR[wcslen(label) + 1];
|
||
if (params.label == NULL) {
|
||
delete [] params.volumeSpec;
|
||
return E_INVALIDARG;
|
||
}
|
||
params.fsName = new WCHAR[MAX_FS_NAME_SIZE];
|
||
if (params.fsName == NULL) {
|
||
delete [] params.volumeSpec;
|
||
delete [] params.label;
|
||
return E_INVALIDARG;
|
||
}
|
||
|
||
if (fsType > 0) {
|
||
wcscpy(params.fsName, (fsType == FSTYPE_FAT ? L"FAT" :
|
||
(fsType == FSTYPE_FAT32 ? L"FAT32" : L"NTFS")));
|
||
}
|
||
|
||
wcscpy(params.volumeSpec, volumeSpec);
|
||
wcscpy(params.label, label);
|
||
params.fsType = fsType;
|
||
params.fsflags = fsflags;
|
||
params.allocationUnitSize = allocationUnitSize;
|
||
params.quick = quick;
|
||
params.force = force;
|
||
params.result = S_OK;
|
||
params.cancel = FALSE;
|
||
params.formatRoutine = FormatRoutine;
|
||
params.formatRoutineEx = FormatRoutineEx;
|
||
params.compressRoutine = CompressRoutine;
|
||
params.threadId = GetCurrentThreadId();
|
||
|
||
if (SetFormatParam(params.threadId, ¶ms) != S_OK) {
|
||
delete [] params.label;
|
||
delete [] params.volumeSpec;
|
||
delete [] params.fsName;
|
||
return E_OUTOFMEMORY;
|
||
};
|
||
|
||
FormatVolume(¶ms);
|
||
|
||
WsbTraceOut(OLESTR("FormatPartition"), OLESTR("result = <%ls>"), WsbHrAsString(params.result));
|
||
return params.result;
|
||
}
|