You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
637 lines
16 KiB
637 lines
16 KiB
/*++
|
|
|
|
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_OUTOFMEMORY;
|
|
}
|
|
|
|
params.label = new WCHAR[wcslen(label) + 1];
|
|
if (params.label == NULL) {
|
|
delete [] params.volumeSpec;
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
params.fsName = new WCHAR[MAX_FS_NAME_SIZE];
|
|
if (params.fsName == NULL) {
|
|
delete [] params.volumeSpec;
|
|
delete [] params.label;
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
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;
|
|
}
|