windows-nt/Source/XPSP1/NT/base/fs/hsm/wsb/wsbvol.cpp
2020-09-26 16:20:57 +08:00

284 lines
7.8 KiB
C++

/*++
Copyright (c) 1999 Microsoft Corporation
Module Name:
wsbvol.cpp
Abstract:
Definitions for volume support routines
Author:
Ran Kalach [rankala] 27, January 2000
Revision History:
--*/
#include <stdafx.h>
#include <wsbvol.h>
// Internal functions
static HRESULT FindMountPoint(IN PWSTR enumName, IN PWSTR volumeName, OUT PWSTR firstMountPoint, IN ULONG maxSize);
HRESULT
WsbGetFirstMountPoint(
IN PWSTR volumeName,
OUT PWSTR firstMountPoint,
IN ULONG maxSize
)
/*++
Routine Description:
Find one Mount Point path (if exists) for the given volume
Arguments:
volumeName - The volume name to search mount path for.
It should have the \\?\volume{GUID}\ format
firstMountPoint - Buffer for the output mount point path
maxSize - Buffer size
Return Value:
S_OK - If at least one Mount Point is found
--*/
{
HRESULT hr = S_FALSE;
WCHAR name[10];
UCHAR driveLetter;
WCHAR tempName[MAX_PATH];
WCHAR driveName[10];
FILE_FS_DEVICE_INFORMATION DeviceInfo;
IO_STATUS_BLOCK StatusBlock;
HANDLE hDrive = NULL ;
NTSTATUS status;
WsbTraceIn(OLESTR("WsbGetFirstMountPoint"), OLESTR("volume name = <%ls>"), volumeName);
name[1] = ':';
name[2] = '\\';
name[3] = 0;
driveName[0] = '\\';
driveName[1] = '\\';
driveName[2] = '.';
driveName[3] = '\\';
driveName[5] = ':';
driveName[6] = 0;
for (driveLetter = L'C'; driveLetter <= L'Z'; driveLetter++) {
name[0] = driveLetter;
// Exclude network drives
if (! GetVolumeNameForVolumeMountPoint(name, tempName, MAX_PATH)) {
continue;
}
// Verify that the drive is not removable or floppy,
// this is required to avoid popups when the drive is empty
driveName[4] = driveLetter;
hDrive = CreateFile(driveName,
FILE_READ_ATTRIBUTES | SYNCHRONIZE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
0,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0);
if (hDrive == INVALID_HANDLE_VALUE) {
// Can't open it - won't search on it
WsbTrace(OLESTR("WsbGetFirstMountPoint: Could not open volume %ls, status = %lu - Skipping it!\n"), driveName, GetLastError());
continue;
}
status = NtQueryVolumeInformationFile(hDrive,
&StatusBlock,
(PVOID) &DeviceInfo,
sizeof(FILE_FS_DEVICE_INFORMATION),
FileFsDeviceInformation);
if (!NT_SUCCESS(status)) {
// Can't query it - won't search on it
WsbTrace(OLESTR("WsbGetFirstMountPoint: Could not query information for volume %ls, status = %ld - Skipping it!\n"), driveName, (LONG)status);
CloseHandle(hDrive);
continue;
}
if ((DeviceInfo.Characteristics & FILE_FLOPPY_DISKETTE) || (DeviceInfo.Characteristics & FILE_REMOVABLE_MEDIA)) {
// Skip removable/floppy drives
WsbTrace(OLESTR("WsbGetFirstMountPoint: Skipping removable/floppy volume %ls\n"), driveName);
CloseHandle(hDrive);
continue;
}
CloseHandle(hDrive);
WsbTrace(OLESTR("WsbGetFirstMountPoint: Checking mount points on volume %ls\n"), driveName);
// Check mount points on drive
hr = FindMountPoint(name, volumeName, firstMountPoint, maxSize);
if (S_OK == hr) {
// Looking for only one mount point
break;
}
}
WsbTraceOut(OLESTR("WsbGetFirstMountPoint"), OLESTR("hr = <%ls> mount point = <%ls>"), WsbHrAsString(hr), firstMountPoint);
return hr;
}
HRESULT
FindMountPoint(
IN PWSTR enumName,
IN PWSTR volumeName,
OUT PWSTR firstMountPoint,
IN ULONG maxSize
)
/*++
Routine Description:
Find one Mount Point path (if exists) for the given volume on the given enumeration-volume
Arguments:
enumName - Volume to enumerate, i.e. search for a mount point on it
which corresponds to the given volume
volumeName - The volume name to search mount path for.
It should have the \\?\volume{GUID}\ format
firstMountPoint - Buffer for the output mount point path
maxSize - Buffer size
Comments:
Avoid the standard HSM try-catch paradigm for performance, especially since this
function is recursive
Return Value:
S_OK - if at least one Mount Point is found
S_FALSE - Otherwise
--*/
{
HANDLE hEnum;
WCHAR *enumVolumeName = NULL;
WCHAR *volumeMountPoint = NULL;
WCHAR *mountPointPath = NULL;
WCHAR c1, c2;
WCHAR *linkName1 = NULL;
WCHAR *linkName2 = NULL;
HRESULT hr = S_OK;
enumVolumeName = (WCHAR*)WsbAlloc(MAX_PATH * sizeof(WCHAR));
if (NULL == enumVolumeName) {
hr = E_OUTOFMEMORY;
goto exit;
}
volumeMountPoint = (WCHAR*)WsbAlloc(maxSize * sizeof(WCHAR));
if (NULL == volumeMountPoint) {
hr = E_OUTOFMEMORY;
goto exit;
}
mountPointPath = (WCHAR*)WsbAlloc((maxSize + wcslen(enumName)) * sizeof(WCHAR));
if (NULL == mountPointPath) {
hr = E_OUTOFMEMORY;
goto exit;
}
if (! GetVolumeNameForVolumeMountPoint(enumName, enumVolumeName, MAX_PATH)) {
DWORD dwErr = GetLastError();
hr = HRESULT_FROM_WIN32(dwErr);
goto exit;
}
if (!wcscmp(enumVolumeName, volumeName)) {
// The volume to enumerate on is the one we are looking for
wcscpy(firstMountPoint, enumName);
hr = S_OK;
goto exit;
} else {
linkName1 = (WCHAR*)WsbAlloc((maxSize * 2) * sizeof(WCHAR));
if (NULL == linkName1) {
hr = E_OUTOFMEMORY;
goto exit;
}
linkName2 = (WCHAR*)WsbAlloc((maxSize * 2) * sizeof(WCHAR));
if (NULL == linkName1) {
hr = E_OUTOFMEMORY;
goto exit;
}
c1 = enumVolumeName[48];
c2 = volumeName[48];
enumVolumeName[48] = 0;
volumeName[48] = 0;
if (QueryDosDevice(&enumVolumeName[4], linkName1, maxSize*2) &&
QueryDosDevice(&volumeName[4], linkName2, maxSize*2)) {
if (!wcscmp(linkName1, linkName2)) {
wcscpy(firstMountPoint, enumName);
enumVolumeName[48] = c1;
volumeName[48] = c2;
hr = S_OK;
goto exit;
}
}
enumVolumeName[48] = c1;
volumeName[48] = c2;
}
hEnum = FindFirstVolumeMountPoint(enumVolumeName, volumeMountPoint, maxSize);
if (hEnum == INVALID_HANDLE_VALUE) {
hr = S_FALSE;
goto exit;
}
for (;;) {
wcscpy(mountPointPath, enumName);
wcscat(mountPointPath, volumeMountPoint);
// Enumerate on the mount path we found
hr = FindMountPoint(mountPointPath, volumeName, firstMountPoint, maxSize);
if (S_OK == hr) {
// Found one mount point path, no need to continue
FindVolumeMountPointClose(hEnum);
goto exit;
}
if (! FindNextVolumeMountPoint(hEnum, volumeMountPoint, maxSize)) {
FindVolumeMountPointClose(hEnum);
hr = S_FALSE;
goto exit;
}
}
exit:
if (enumVolumeName) {
WsbFree(enumVolumeName);
}
if (volumeMountPoint) {
WsbFree(volumeMountPoint);
}
if (mountPointPath) {
WsbFree(mountPointPath);
}
if (linkName1) {
WsbFree(linkName1);
}
if (linkName2) {
WsbFree(linkName2);
}
return hr;
}