413 lines
11 KiB
C
413 lines
11 KiB
C
|
/*++
|
||
|
Copyright (c) 1993 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
spdrmmgr.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
Revision History:
|
||
|
Initial Code Michael Peterson (v-michpe) 13.Dec.1997
|
||
|
Code cleanup and changes Guhan Suriyanarayanan (guhans) 21.Aug.1999
|
||
|
|
||
|
--*/
|
||
|
#include "spprecmp.h"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#define THIS_MODULE L"spdrmmgr.c"
|
||
|
#define THIS_MODULE_CODE L"M"
|
||
|
|
||
|
#define DOS_DEVICES L"\\DosDevices\\?:"
|
||
|
#define DOS_DEVICES_DRV_LTR_POS 12
|
||
|
|
||
|
typedef struct _NAMETABLE {
|
||
|
ULONG Elements;
|
||
|
PWSTR SymbolicName[1];
|
||
|
} NAMETABLE, *PNAMETABLE;
|
||
|
|
||
|
|
||
|
// Imported from sppartit.c
|
||
|
extern WCHAR
|
||
|
SpDeleteDriveLetter(IN PWSTR DeviceName);
|
||
|
|
||
|
|
||
|
NTSTATUS
|
||
|
SpAsrOpenMountManager(
|
||
|
OUT HANDLE *Handle
|
||
|
)
|
||
|
{
|
||
|
NTSTATUS status = STATUS_SUCCESS;
|
||
|
IO_STATUS_BLOCK ioStatusBlock;
|
||
|
OBJECT_ATTRIBUTES objectAttributes;
|
||
|
UNICODE_STRING unicodeString;
|
||
|
|
||
|
INIT_OBJA(&objectAttributes, &unicodeString, MOUNTMGR_DEVICE_NAME);
|
||
|
status = ZwOpenFile(Handle,
|
||
|
(ACCESS_MASK)(FILE_GENERIC_READ),
|
||
|
&objectAttributes,
|
||
|
&ioStatusBlock,
|
||
|
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE ,
|
||
|
FILE_NON_DIRECTORY_FILE
|
||
|
);
|
||
|
|
||
|
if (!NT_SUCCESS(status)) {
|
||
|
DbgErrorMesg((_asrerr, "Could not open the mount manager (0x%x). \n", status));
|
||
|
ASSERT(0 && L"Could not open mount manager");
|
||
|
}
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
SpAsrAllocateMountPointForCreate(
|
||
|
IN PWSTR PartitionDeviceName,
|
||
|
IN PWSTR MountPointNameString,
|
||
|
OUT PMOUNTMGR_CREATE_POINT_INPUT *pMpt,
|
||
|
OUT ULONG *MountPointSize
|
||
|
)
|
||
|
{
|
||
|
PMOUNTMGR_CREATE_POINT_INPUT pMountPoint = NULL;
|
||
|
|
||
|
*pMpt = NULL;
|
||
|
*MountPointSize = sizeof(MOUNTMGR_CREATE_POINT_INPUT) +
|
||
|
(wcslen(PartitionDeviceName) + wcslen(MountPointNameString)) * sizeof(WCHAR);
|
||
|
|
||
|
pMountPoint = (PMOUNTMGR_CREATE_POINT_INPUT) SpAsrMemAlloc(*MountPointSize, TRUE); // does not return on failure
|
||
|
|
||
|
pMountPoint->SymbolicLinkNameOffset = sizeof(MOUNTMGR_CREATE_POINT_INPUT);
|
||
|
pMountPoint->SymbolicLinkNameLength = wcslen(MountPointNameString) * sizeof(WCHAR);
|
||
|
RtlCopyMemory(((PCHAR) pMountPoint + pMountPoint->SymbolicLinkNameOffset),
|
||
|
MountPointNameString,
|
||
|
pMountPoint->SymbolicLinkNameLength
|
||
|
);
|
||
|
|
||
|
pMountPoint->DeviceNameLength = (USHORT) (wcslen(PartitionDeviceName) * sizeof(WCHAR));
|
||
|
pMountPoint->DeviceNameOffset = (USHORT) pMountPoint->SymbolicLinkNameOffset +
|
||
|
pMountPoint->SymbolicLinkNameLength;
|
||
|
RtlCopyMemory(((PCHAR)pMountPoint + pMountPoint->DeviceNameOffset),
|
||
|
PartitionDeviceName,
|
||
|
pMountPoint->DeviceNameLength
|
||
|
);
|
||
|
|
||
|
*pMpt = pMountPoint;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
NTSTATUS
|
||
|
SpAsrCreateMountPoint(
|
||
|
IN PWSTR PartitionDeviceName,
|
||
|
IN PWSTR MountPointNameString
|
||
|
)
|
||
|
/*++
|
||
|
Description:
|
||
|
|
||
|
Creates the specified mount point for the specified partition region.
|
||
|
These strings will usually be in the form of a symbolic names, such as:
|
||
|
|
||
|
"\DosDevices\?:"
|
||
|
|
||
|
Where ? can be any supported drive letter,
|
||
|
or,
|
||
|
a GUID string in the form of, for example:
|
||
|
|
||
|
"\??\Volume{1234abcd-1234-5678-abcd-000000000000}"
|
||
|
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
PartitionDeviceName Specifies the partitioned region portion of the
|
||
|
mount point.
|
||
|
|
||
|
MountPointNameString Specifies the symbolic name to be associated with
|
||
|
the specified partition.
|
||
|
|
||
|
Returns:
|
||
|
|
||
|
NTSTATUS
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
NTSTATUS status = STATUS_SUCCESS;
|
||
|
IO_STATUS_BLOCK ioStatusBlock;
|
||
|
HANDLE handle = NULL;
|
||
|
ULONG mountPointSize = 0;
|
||
|
PMOUNTMGR_CREATE_POINT_INPUT pMountPoint = NULL;
|
||
|
|
||
|
//
|
||
|
// Create the input structure.
|
||
|
//
|
||
|
SpAsrAllocateMountPointForCreate(PartitionDeviceName,
|
||
|
MountPointNameString,
|
||
|
&pMountPoint,
|
||
|
&mountPointSize
|
||
|
);
|
||
|
|
||
|
status = SpAsrOpenMountManager(&handle);
|
||
|
if (!NT_SUCCESS(status)) {
|
||
|
|
||
|
DbgFatalMesg((_asrerr, "SpAsrCreateMountPoint([%ws],[%ws]). SpAsrOpenMountManager failed (0x%x). mountPointSize:%lu handle:0x%x.\n",
|
||
|
PartitionDeviceName,
|
||
|
MountPointNameString,
|
||
|
status,
|
||
|
mountPointSize,
|
||
|
handle
|
||
|
));
|
||
|
|
||
|
SpMemFree(pMountPoint);
|
||
|
//
|
||
|
// There's nothing the user can do in this case.
|
||
|
//
|
||
|
INTERNAL_ERROR(L"SpAsrOpenMountManager() Failed"); // ok
|
||
|
// does not return
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// IOCTL_CREATE_POINT
|
||
|
//
|
||
|
status = ZwDeviceIoControlFile(handle,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
&ioStatusBlock,
|
||
|
IOCTL_MOUNTMGR_CREATE_POINT,
|
||
|
pMountPoint,
|
||
|
mountPointSize,
|
||
|
NULL,
|
||
|
0
|
||
|
);
|
||
|
|
||
|
if (!NT_SUCCESS(status)) {
|
||
|
//
|
||
|
// We couldn't restore the volume guid for this volume. This is expected if the
|
||
|
// volume is on a non-critical disk--we only recreate critical disks in textmode
|
||
|
// Setup.
|
||
|
//
|
||
|
DbgErrorMesg((_asrwarn, "SpAsrCreateMountPoint([%ws], [%ws]). ZwDeviceIoControlFile(IOCTL_MOUNTMGR_CREATE_POINT) failed (0x%x). handle:0x%x, pMountPoint:0x%x, mountPointSize:0x%x\n",
|
||
|
PartitionDeviceName,
|
||
|
MountPointNameString,
|
||
|
status,
|
||
|
handle,
|
||
|
pMountPoint,
|
||
|
mountPointSize
|
||
|
));
|
||
|
}
|
||
|
|
||
|
SpMemFree(pMountPoint);
|
||
|
ZwClose(handle);
|
||
|
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
// EXPORTED FUNCTIONS //
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
|
||
|
NTSTATUS
|
||
|
SpAsrSetPartitionDriveLetter(
|
||
|
IN PDISK_REGION pRegion,
|
||
|
IN WCHAR NewDriveLetter
|
||
|
)
|
||
|
/*++
|
||
|
Description:
|
||
|
|
||
|
Checks whether a drive letter exists for the specified partitioned region.
|
||
|
If one does, then if the existing drive letter is the same as the
|
||
|
specified drive letter, return STATUS_SUCCESS. If the existing drive
|
||
|
letter is different from that specified by the caller, delete and recreate
|
||
|
the region's mount point using the symbolic name built from the drive letter
|
||
|
parameter.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
pRegion A pointer to a partitioned region descriptor.
|
||
|
|
||
|
NewDriveLetter Specifies the drive letter to be assigned to the region.
|
||
|
|
||
|
Returns:
|
||
|
|
||
|
NTSTATUS
|
||
|
--*/
|
||
|
{
|
||
|
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
||
|
WCHAR existingDriveLetter = 0;
|
||
|
PWSTR partitionDeviceName = NULL;
|
||
|
PWSTR symbolicName = NULL;
|
||
|
|
||
|
//
|
||
|
// Check input parameters: these better be valid
|
||
|
//
|
||
|
if (!pRegion || !SPPT_IS_REGION_PARTITIONED(pRegion)) {
|
||
|
DbgErrorMesg((_asrwarn,
|
||
|
"SpAsrSetPartitionDriveLetter. Invalid Parameter, pRegion %p is NULL or not partitioned.\n",
|
||
|
pRegion
|
||
|
));
|
||
|
ASSERT(0 && L"Invalid Parameter, pRegion is NULL or not partitioned."); // debug
|
||
|
return STATUS_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
if (NewDriveLetter < ((!IsNEC_98) ? L'C' : L'A') || NewDriveLetter > L'Z') {
|
||
|
DbgErrorMesg((_asrwarn, "SpAsrSetPartitionDriveLetter. Invalid Parameter, NewDriveLetter [%wc].\n", NewDriveLetter));
|
||
|
ASSERT(0 && L"Invalid Parameter, NewDriveLetter"); // debug
|
||
|
return STATUS_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Check if the drive letter already exists
|
||
|
//
|
||
|
partitionDeviceName = SpAsrGetRegionName(pRegion);
|
||
|
existingDriveLetter = SpGetDriveLetter(partitionDeviceName, NULL);
|
||
|
|
||
|
if (NewDriveLetter == existingDriveLetter) {
|
||
|
|
||
|
DbgStatusMesg((_asrinfo,
|
||
|
"SpAsrSetPartitionDriveLetter. Ptn [%ws] already has drv letter %wc.\n",
|
||
|
partitionDeviceName,
|
||
|
NewDriveLetter
|
||
|
));
|
||
|
|
||
|
SpMemFree(partitionDeviceName);
|
||
|
return STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// The existing drive letter does not match. Delete it.
|
||
|
//
|
||
|
if (existingDriveLetter) {
|
||
|
|
||
|
DbgStatusMesg((_asrinfo,
|
||
|
"SpAsrSetPartitionDriveLetter. [%ws] has driveLetter %wc, deleting.\n",
|
||
|
partitionDeviceName,
|
||
|
existingDriveLetter
|
||
|
));
|
||
|
|
||
|
SpDeleteDriveLetter(partitionDeviceName);
|
||
|
}
|
||
|
|
||
|
symbolicName = SpDupStringW(DOS_DEVICES);
|
||
|
pRegion->DriveLetter = symbolicName[DOS_DEVICES_DRV_LTR_POS] = NewDriveLetter;
|
||
|
|
||
|
//
|
||
|
// Create the mount point with the correct drive letter
|
||
|
//
|
||
|
status = SpAsrCreateMountPoint(partitionDeviceName, symbolicName);
|
||
|
|
||
|
if (NT_SUCCESS(status)) {
|
||
|
|
||
|
DbgStatusMesg((_asrinfo,
|
||
|
"SpAsrSetPartitionDriveLetter. [%ws] is drive %wc.\n",
|
||
|
partitionDeviceName,
|
||
|
NewDriveLetter
|
||
|
));
|
||
|
|
||
|
}
|
||
|
else {
|
||
|
|
||
|
DbgErrorMesg((_asrwarn,
|
||
|
"SpAsrSetPartitionDriveLetter. SpAsrCreateMountPoint([%ws],[%ws]) failed (0x%x). Drive letter %wc not assigned to [%ws].\n",
|
||
|
partitionDeviceName,
|
||
|
symbolicName,
|
||
|
status,
|
||
|
NewDriveLetter,
|
||
|
partitionDeviceName
|
||
|
));
|
||
|
}
|
||
|
|
||
|
SpMemFree(partitionDeviceName);
|
||
|
SpMemFree(symbolicName);
|
||
|
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
|
||
|
NTSTATUS
|
||
|
SpAsrDeleteMountPoint(IN PWSTR PartitionDevicePath)
|
||
|
{
|
||
|
//
|
||
|
// Check the DevicePath: it better not be NULL.
|
||
|
//
|
||
|
if (!PartitionDevicePath) {
|
||
|
|
||
|
DbgErrorMesg((_asrwarn,
|
||
|
"SpAsrDeleteMountPoint. Invalid Parameter, ParititionDevicePath is NULL.\n"
|
||
|
));
|
||
|
|
||
|
ASSERT(0 && L"Invalid Parameter, ParititionDevicePath is NULL."); // debug
|
||
|
return STATUS_INVALID_PARAMETER;
|
||
|
|
||
|
}
|
||
|
|
||
|
DbgStatusMesg((_asrinfo,
|
||
|
"SpAsrDeleteMountPoint. Deleting drive letter for [%ws]\n",
|
||
|
PartitionDevicePath
|
||
|
));
|
||
|
|
||
|
SpDeleteDriveLetter(PartitionDevicePath);
|
||
|
return STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
|
||
|
NTSTATUS
|
||
|
SpAsrSetVolumeGuid(
|
||
|
IN PDISK_REGION pRegion,
|
||
|
IN PWSTR VolumeGuid
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Description:
|
||
|
Delete and recreate the region's mount point using the passed-in symbolic
|
||
|
name GUID parameter.
|
||
|
|
||
|
Arguments:
|
||
|
pRegion A pointer to a partitioned region descriptor.
|
||
|
VolumeGuid Specifies the GUID string to be assigned to the region.
|
||
|
DeleteDriveLetter Specifies if the existing drive letter for the volume
|
||
|
should be deleted. This should be TRUE for all volumes
|
||
|
except the boot volume.
|
||
|
|
||
|
Returns:
|
||
|
NTSTATUS
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
||
|
PWSTR partitionDeviceName = NULL;
|
||
|
|
||
|
//
|
||
|
// Check input parameters
|
||
|
//
|
||
|
if (!pRegion || !SPPT_IS_REGION_PARTITIONED(pRegion)) {
|
||
|
|
||
|
DbgErrorMesg((_asrwarn,
|
||
|
"SpAsrSetVolumeGuid. Invalid Param: pRegion (%p) NULL/not partitioned\n",
|
||
|
pRegion
|
||
|
));
|
||
|
|
||
|
return STATUS_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
if (!VolumeGuid || !wcslen(VolumeGuid)) {
|
||
|
|
||
|
DbgErrorMesg((_asrwarn,
|
||
|
"SpAsrSetVolumeGuid. Invalid Param: VolumeGuid (%p) NULL/blank.\n",
|
||
|
VolumeGuid
|
||
|
));
|
||
|
|
||
|
return STATUS_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
partitionDeviceName = SpAsrGetRegionName(pRegion);
|
||
|
|
||
|
//
|
||
|
// Create the mount point with the correct Guid string.
|
||
|
//
|
||
|
status = SpAsrCreateMountPoint(partitionDeviceName, VolumeGuid);
|
||
|
|
||
|
SpMemFree(partitionDeviceName);
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
|