mirror of https://github.com/tongzx/nt5src
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.
2464 lines
71 KiB
2464 lines
71 KiB
/*++
|
|
|
|
Copyright (c) 1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
volmount.c
|
|
|
|
Abstract:
|
|
|
|
This file contains the implementation for the Volume Mount Point API.
|
|
|
|
Author:
|
|
|
|
Norbert P. Kusters (norbertk) 22-Dec-1997
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "basedll.h"
|
|
#include "initguid.h"
|
|
#include "mountmgr.h"
|
|
|
|
// NOTE, this structure is here because it was not defined in NTIOAPI.H.
|
|
// This should be taken out in the future.
|
|
// This is stolen from NTFS.H
|
|
|
|
typedef struct _REPARSE_INDEX_KEY {
|
|
|
|
//
|
|
// The tag of the reparse point.
|
|
//
|
|
|
|
ULONG FileReparseTag;
|
|
|
|
//
|
|
// The file record Id where the reparse point is set.
|
|
//
|
|
|
|
LARGE_INTEGER FileId;
|
|
|
|
} REPARSE_INDEX_KEY, *PREPARSE_INDEX_KEY;
|
|
|
|
HANDLE
|
|
WINAPI
|
|
FindFirstVolumeA(
|
|
LPSTR lpszVolumeName,
|
|
DWORD cchBufferLength
|
|
)
|
|
|
|
{
|
|
ANSI_STRING ansiVolumeName;
|
|
UNICODE_STRING unicodeVolumeName;
|
|
HANDLE h;
|
|
NTSTATUS status;
|
|
|
|
ansiVolumeName.Buffer = lpszVolumeName;
|
|
ansiVolumeName.MaximumLength = (USHORT) (cchBufferLength - 1);
|
|
unicodeVolumeName.Buffer = NULL;
|
|
unicodeVolumeName.MaximumLength = 0;
|
|
|
|
try {
|
|
|
|
unicodeVolumeName.MaximumLength = (ansiVolumeName.MaximumLength + 1)*
|
|
sizeof(WCHAR);
|
|
unicodeVolumeName.Buffer =
|
|
RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
|
|
unicodeVolumeName.MaximumLength);
|
|
if (!unicodeVolumeName.Buffer) {
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
h = FindFirstVolumeW(unicodeVolumeName.Buffer, cchBufferLength);
|
|
|
|
if (h != INVALID_HANDLE_VALUE) {
|
|
|
|
RtlInitUnicodeString(&unicodeVolumeName, unicodeVolumeName.Buffer);
|
|
|
|
status = BasepUnicodeStringTo8BitString(&ansiVolumeName,
|
|
&unicodeVolumeName, FALSE);
|
|
if (!NT_SUCCESS(status)) {
|
|
BaseSetLastNTError(status);
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
ansiVolumeName.Buffer[ansiVolumeName.Length] = 0;
|
|
}
|
|
|
|
} finally {
|
|
|
|
if (unicodeVolumeName.Buffer) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, unicodeVolumeName.Buffer);
|
|
}
|
|
}
|
|
|
|
return h;
|
|
}
|
|
|
|
HANDLE
|
|
WINAPI
|
|
FindFirstVolumeW(
|
|
LPWSTR lpszVolumeName,
|
|
DWORD cchBufferLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine kicks off the enumeration of all volumes in the system.
|
|
|
|
Arguments:
|
|
|
|
lpszVolumeName - Returns the first volume name in the system.
|
|
|
|
cchBufferLength - Supplies the size of the preceeding buffer.
|
|
|
|
Return Value:
|
|
|
|
A valid handle or INVALID_HANDLE_VALUE.
|
|
|
|
--*/
|
|
|
|
{
|
|
HANDLE h;
|
|
MOUNTMGR_MOUNT_POINT point;
|
|
PMOUNTMGR_MOUNT_POINTS points;
|
|
BOOL b;
|
|
DWORD bytes;
|
|
|
|
h = CreateFileW(MOUNTMGR_DOS_DEVICE_NAME, 0,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
|
|
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
|
|
INVALID_HANDLE_VALUE);
|
|
if (h == INVALID_HANDLE_VALUE) {
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
RtlZeroMemory(&point, sizeof(point));
|
|
|
|
points = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
|
|
sizeof(MOUNTMGR_MOUNT_POINTS));
|
|
if (!points) {
|
|
CloseHandle(h);
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
b = DeviceIoControl(h, IOCTL_MOUNTMGR_QUERY_POINTS, &point, sizeof(point),
|
|
points, sizeof(MOUNTMGR_MOUNT_POINTS), &bytes, NULL);
|
|
while (!b && GetLastError() == ERROR_MORE_DATA) {
|
|
bytes = points->Size;
|
|
RtlFreeHeap(RtlProcessHeap(), 0, points);
|
|
points = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG), bytes);
|
|
if (!points) {
|
|
CloseHandle(h);
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
b = DeviceIoControl(h, IOCTL_MOUNTMGR_QUERY_POINTS, &point,
|
|
sizeof(point), points, bytes, &bytes, NULL);
|
|
}
|
|
|
|
CloseHandle(h);
|
|
|
|
if (!b) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, points);
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
b = FindNextVolumeW((HANDLE) points, lpszVolumeName, cchBufferLength);
|
|
if (!b) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, points);
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
return (HANDLE) points;
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
FindNextVolumeA(
|
|
HANDLE hFindVolume,
|
|
LPSTR lpszVolumeName,
|
|
DWORD cchBufferLength
|
|
)
|
|
|
|
{
|
|
ANSI_STRING ansiVolumeName;
|
|
UNICODE_STRING unicodeVolumeName;
|
|
BOOL b;
|
|
NTSTATUS status;
|
|
|
|
ansiVolumeName.Buffer = lpszVolumeName;
|
|
ansiVolumeName.MaximumLength = (USHORT) (cchBufferLength - 1);
|
|
unicodeVolumeName.Buffer = NULL;
|
|
unicodeVolumeName.MaximumLength = 0;
|
|
|
|
try {
|
|
|
|
unicodeVolumeName.MaximumLength = (ansiVolumeName.MaximumLength + 1)*
|
|
sizeof(WCHAR);
|
|
unicodeVolumeName.Buffer =
|
|
RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
|
|
unicodeVolumeName.MaximumLength);
|
|
if (!unicodeVolumeName.Buffer) {
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
|
|
b = FindNextVolumeW(hFindVolume, unicodeVolumeName.Buffer,
|
|
cchBufferLength);
|
|
|
|
if (b) {
|
|
|
|
RtlInitUnicodeString(&unicodeVolumeName, unicodeVolumeName.Buffer);
|
|
|
|
status = BasepUnicodeStringTo8BitString(&ansiVolumeName,
|
|
&unicodeVolumeName, FALSE);
|
|
if (!NT_SUCCESS(status)) {
|
|
BaseSetLastNTError(status);
|
|
return FALSE;
|
|
}
|
|
|
|
ansiVolumeName.Buffer[ansiVolumeName.Length] = 0;
|
|
}
|
|
|
|
} finally {
|
|
|
|
if (unicodeVolumeName.Buffer) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, unicodeVolumeName.Buffer);
|
|
}
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
FindNextVolumeW(
|
|
HANDLE hFindVolume,
|
|
LPWSTR lpszVolumeName,
|
|
DWORD cchBufferLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine continues the enumeration of all volumes in the system.
|
|
|
|
Arguments:
|
|
|
|
hFindVolume - Supplies the find volume handle.
|
|
|
|
lpszVolumeName - Returns the first volume name in the system.
|
|
|
|
cchBufferLength - Supplies the size of the preceeding buffer.
|
|
|
|
Return Value:
|
|
|
|
FALSE - Failure. The error code is returned in GetLastError().
|
|
|
|
TRUE - Success.
|
|
|
|
--*/
|
|
|
|
{
|
|
PMOUNTMGR_MOUNT_POINTS points = hFindVolume;
|
|
DWORD i, j;
|
|
PMOUNTMGR_MOUNT_POINT point, point2;
|
|
UNICODE_STRING symName, symName2, devName, devName2;
|
|
|
|
for (i = 0; i < points->NumberOfMountPoints; i++) {
|
|
|
|
point = &points->MountPoints[i];
|
|
if (!point->SymbolicLinkNameOffset) {
|
|
continue;
|
|
}
|
|
|
|
symName.Length = symName.MaximumLength = point->SymbolicLinkNameLength;
|
|
symName.Buffer = (PWSTR) ((PCHAR) points +
|
|
point->SymbolicLinkNameOffset);
|
|
|
|
if (!MOUNTMGR_IS_NT_VOLUME_NAME(&symName)) {
|
|
point->SymbolicLinkNameOffset = 0;
|
|
continue;
|
|
}
|
|
|
|
devName.Length = devName.MaximumLength = point->DeviceNameLength;
|
|
devName.Buffer = (PWSTR) ((PCHAR) points +
|
|
point->DeviceNameOffset);
|
|
|
|
for (j = i + 1; j < points->NumberOfMountPoints; j++) {
|
|
|
|
point2 = &points->MountPoints[j];
|
|
if (!point2->SymbolicLinkNameOffset) {
|
|
continue;
|
|
}
|
|
|
|
symName2.Length = symName2.MaximumLength =
|
|
point2->SymbolicLinkNameLength;
|
|
symName2.Buffer = (PWSTR) ((PCHAR) points +
|
|
point2->SymbolicLinkNameOffset);
|
|
|
|
if (!MOUNTMGR_IS_NT_VOLUME_NAME(&symName2)) {
|
|
point2->SymbolicLinkNameOffset = 0;
|
|
continue;
|
|
}
|
|
|
|
devName2.Length = devName2.MaximumLength =
|
|
point2->DeviceNameLength;
|
|
devName2.Buffer = (PWSTR) ((PCHAR) points +
|
|
point2->DeviceNameOffset);
|
|
|
|
if (RtlEqualUnicodeString(&devName, &devName2, TRUE)) {
|
|
point2->SymbolicLinkNameOffset = 0;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
if (i == points->NumberOfMountPoints) {
|
|
SetLastError(ERROR_NO_MORE_FILES);
|
|
return FALSE;
|
|
}
|
|
|
|
if (cchBufferLength*sizeof(WCHAR) < point->SymbolicLinkNameLength +
|
|
2*sizeof(WCHAR)) {
|
|
|
|
SetLastError(ERROR_FILENAME_EXCED_RANGE);
|
|
return FALSE;
|
|
}
|
|
|
|
RtlCopyMemory(lpszVolumeName, (PCHAR) points +
|
|
point->SymbolicLinkNameOffset,
|
|
point->SymbolicLinkNameLength);
|
|
lpszVolumeName[1] = '\\';
|
|
lpszVolumeName[point->SymbolicLinkNameLength/sizeof(WCHAR)] = '\\';
|
|
lpszVolumeName[point->SymbolicLinkNameLength/sizeof(WCHAR) + 1] = 0;
|
|
|
|
point->SymbolicLinkNameOffset = 0;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
FindVolumeClose(
|
|
HANDLE hFindVolume
|
|
)
|
|
|
|
{
|
|
RtlFreeHeap(RtlProcessHeap(), 0, hFindVolume);
|
|
return TRUE;
|
|
}
|
|
|
|
HANDLE
|
|
WINAPI
|
|
FindFirstVolumeMountPointA(
|
|
LPCSTR lpszRootPathName,
|
|
LPSTR lpszVolumeMountPoint,
|
|
DWORD cchBufferLength
|
|
)
|
|
|
|
{
|
|
PUNICODE_STRING unicodeRootPathName;
|
|
ANSI_STRING ansiVolumeMountPoint;
|
|
UNICODE_STRING unicodeVolumeMountPoint;
|
|
HANDLE h;
|
|
NTSTATUS status;
|
|
|
|
unicodeRootPathName =
|
|
Basep8BitStringToStaticUnicodeString(lpszRootPathName);
|
|
if (!unicodeRootPathName) {
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
ansiVolumeMountPoint.Buffer = lpszVolumeMountPoint;
|
|
ansiVolumeMountPoint.MaximumLength = (USHORT) (cchBufferLength - 1);
|
|
unicodeVolumeMountPoint.Buffer = NULL;
|
|
unicodeVolumeMountPoint.MaximumLength = 0;
|
|
|
|
try {
|
|
|
|
unicodeVolumeMountPoint.MaximumLength =
|
|
(ansiVolumeMountPoint.MaximumLength + 1)*sizeof(WCHAR);
|
|
unicodeVolumeMountPoint.Buffer =
|
|
RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
|
|
unicodeVolumeMountPoint.MaximumLength);
|
|
if (!unicodeVolumeMountPoint.Buffer) {
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
h = FindFirstVolumeMountPointW(unicodeRootPathName->Buffer,
|
|
unicodeVolumeMountPoint.Buffer,
|
|
cchBufferLength);
|
|
|
|
if (h != INVALID_HANDLE_VALUE) {
|
|
|
|
RtlInitUnicodeString(&unicodeVolumeMountPoint,
|
|
unicodeVolumeMountPoint.Buffer);
|
|
|
|
status = BasepUnicodeStringTo8BitString(&ansiVolumeMountPoint,
|
|
&unicodeVolumeMountPoint,
|
|
FALSE);
|
|
if (!NT_SUCCESS(status)) {
|
|
BaseSetLastNTError(status);
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
ansiVolumeMountPoint.Buffer[ansiVolumeMountPoint.Length] = 0;
|
|
}
|
|
|
|
} finally {
|
|
|
|
if (unicodeVolumeMountPoint.Buffer) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, unicodeVolumeMountPoint.Buffer);
|
|
}
|
|
}
|
|
|
|
return h;
|
|
}
|
|
|
|
BOOL
|
|
FindNextVolumeMountPointHelper(
|
|
HANDLE hFindVolumeMountPoint,
|
|
LPWSTR lpszVolumeMountPoint,
|
|
DWORD cchBufferLength,
|
|
BOOL FirstTimeCalled
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine continues the enumeration of all volume mount point on the
|
|
given volume.
|
|
|
|
Arguments:
|
|
|
|
hFindVolumeMountPoint - Supplies the handle for the enumeration.
|
|
|
|
lpszVolumeMountPoint - Returns the volume mount point.
|
|
|
|
cchBufferLength - Supplies the volume mount point buffer length.
|
|
|
|
FirstTimeCalled - Supplies whether or not this is being called
|
|
from FindFirst or from FindNext.
|
|
|
|
Return Value:
|
|
|
|
FALSE - Failure.
|
|
|
|
TRUE - Success.
|
|
|
|
--*/
|
|
|
|
{
|
|
REPARSE_INDEX_KEY reparseKey;
|
|
UNICODE_STRING reparseName;
|
|
NTSTATUS status;
|
|
IO_STATUS_BLOCK ioStatus;
|
|
FILE_REPARSE_POINT_INFORMATION reparseInfo;
|
|
UNICODE_STRING fileId;
|
|
OBJECT_ATTRIBUTES oa;
|
|
HANDLE h;
|
|
PREPARSE_DATA_BUFFER reparse;
|
|
BOOL b;
|
|
DWORD bytes;
|
|
UNICODE_STRING mountName;
|
|
DWORD nameInfoSize;
|
|
PFILE_NAME_INFORMATION nameInfo;
|
|
|
|
for (;;) {
|
|
|
|
if (FirstTimeCalled) {
|
|
FirstTimeCalled = FALSE;
|
|
RtlZeroMemory(&reparseKey, sizeof(reparseKey));
|
|
reparseKey.FileReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
|
|
reparseName.Length = reparseName.MaximumLength = sizeof(reparseKey);
|
|
reparseName.Buffer = (PWCHAR) &reparseKey;
|
|
status = NtQueryDirectoryFile(hFindVolumeMountPoint,
|
|
NULL, NULL, NULL, &ioStatus,
|
|
&reparseInfo, sizeof(reparseInfo),
|
|
FileReparsePointInformation, TRUE,
|
|
&reparseName, FALSE);
|
|
} else {
|
|
status = NtQueryDirectoryFile(hFindVolumeMountPoint,
|
|
NULL, NULL, NULL, &ioStatus,
|
|
&reparseInfo, sizeof(reparseInfo),
|
|
FileReparsePointInformation, TRUE,
|
|
NULL, FALSE);
|
|
}
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
BaseSetLastNTError(status);
|
|
return FALSE;
|
|
}
|
|
|
|
if (reparseInfo.Tag != IO_REPARSE_TAG_MOUNT_POINT) {
|
|
SetLastError(ERROR_NO_MORE_FILES);
|
|
return FALSE;
|
|
}
|
|
|
|
fileId.Length = sizeof(reparseInfo.FileReference);
|
|
fileId.MaximumLength = fileId.Length;
|
|
fileId.Buffer = (PWSTR) &reparseInfo.FileReference;
|
|
|
|
InitializeObjectAttributes(&oa, &fileId, 0, hFindVolumeMountPoint,
|
|
NULL);
|
|
|
|
status = NtOpenFile(&h, FILE_GENERIC_READ, &oa, &ioStatus,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_OPEN_BY_FILE_ID | FILE_OPEN_REPARSE_POINT);
|
|
if (!NT_SUCCESS(status)) {
|
|
BaseSetLastNTError(status);
|
|
return FALSE;
|
|
}
|
|
|
|
reparse = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
|
|
MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
|
|
if (!reparse) {
|
|
CloseHandle(h);
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
|
|
b = DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, NULL, 0, reparse,
|
|
MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &bytes, NULL);
|
|
|
|
if (!b || reparse->ReparseTag != IO_REPARSE_TAG_MOUNT_POINT) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, reparse);
|
|
CloseHandle(h);
|
|
return FALSE;
|
|
}
|
|
|
|
mountName.Length = mountName.MaximumLength =
|
|
reparse->MountPointReparseBuffer.SubstituteNameLength;
|
|
mountName.Buffer = (PWSTR)
|
|
((PCHAR) reparse->MountPointReparseBuffer.PathBuffer +
|
|
reparse->MountPointReparseBuffer.SubstituteNameOffset);
|
|
|
|
if (!MOUNTMGR_IS_NT_VOLUME_NAME_WB(&mountName)) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, reparse);
|
|
CloseHandle(h);
|
|
continue;
|
|
}
|
|
|
|
RtlFreeHeap(RtlProcessHeap(), 0, reparse);
|
|
|
|
nameInfoSize = FIELD_OFFSET(FILE_NAME_INFORMATION, FileName) +
|
|
(cchBufferLength - 1)*sizeof(WCHAR);
|
|
nameInfo = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
|
|
nameInfoSize);
|
|
if (!nameInfo) {
|
|
CloseHandle(h);
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
|
|
status = NtQueryInformationFile(h, &ioStatus, nameInfo, nameInfoSize,
|
|
FileNameInformation);
|
|
if (!NT_SUCCESS(status)) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, nameInfo);
|
|
CloseHandle(h);
|
|
BaseSetLastNTError(status);
|
|
return FALSE;
|
|
}
|
|
|
|
RtlCopyMemory(lpszVolumeMountPoint, &nameInfo->FileName[1],
|
|
nameInfo->FileNameLength - sizeof(WCHAR));
|
|
lpszVolumeMountPoint[nameInfo->FileNameLength/sizeof(WCHAR) - 1] = '\\';
|
|
lpszVolumeMountPoint[nameInfo->FileNameLength/sizeof(WCHAR)] = 0;
|
|
|
|
RtlFreeHeap(RtlProcessHeap(), 0, nameInfo);
|
|
CloseHandle(h);
|
|
break;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
HANDLE
|
|
WINAPI
|
|
FindFirstVolumeMountPointW(
|
|
LPCWSTR lpszRootPathName,
|
|
LPWSTR lpszVolumeMountPoint,
|
|
DWORD cchBufferLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine kicks off the enumeration of all volume mount point on the
|
|
given volume.
|
|
|
|
Arguments:
|
|
|
|
lpszRootPathName - Supplies the root path name.
|
|
|
|
lpszVolumeMountPoint - Returns the volume mount point.
|
|
|
|
cchBufferLength - Supplies the volume mount point buffer length.
|
|
|
|
Return Value:
|
|
|
|
A handle or INVALID_HANDLE_VALUE.
|
|
|
|
--*/
|
|
|
|
{
|
|
UNICODE_STRING unicodeRootPathName;
|
|
UNICODE_STRING reparseSuffix, reparseName;
|
|
HANDLE h;
|
|
BOOL b;
|
|
|
|
RtlInitUnicodeString(&unicodeRootPathName, lpszRootPathName);
|
|
if (unicodeRootPathName.Buffer[
|
|
unicodeRootPathName.Length/sizeof(WCHAR) - 1] != '\\') {
|
|
|
|
BaseSetLastNTError(STATUS_OBJECT_NAME_INVALID);
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
RtlInitUnicodeString(&reparseSuffix,
|
|
L"$Extend\\$Reparse:$R:$INDEX_ALLOCATION");
|
|
|
|
reparseName.MaximumLength = unicodeRootPathName.Length +
|
|
reparseSuffix.Length + sizeof(WCHAR);
|
|
reparseName.Length = 0;
|
|
reparseName.Buffer = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
|
|
reparseName.MaximumLength);
|
|
if (!reparseName.Buffer) {
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
RtlCopyUnicodeString(&reparseName, &unicodeRootPathName);
|
|
RtlAppendUnicodeStringToString(&reparseName, &reparseSuffix);
|
|
reparseName.Buffer[reparseName.Length/sizeof(WCHAR)] = 0;
|
|
|
|
h = CreateFileW(reparseName.Buffer, GENERIC_READ, FILE_SHARE_READ, NULL,
|
|
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS |
|
|
SECURITY_IMPERSONATION, NULL);
|
|
|
|
RtlFreeHeap(RtlProcessHeap(), 0, reparseName.Buffer);
|
|
|
|
if (h == INVALID_HANDLE_VALUE) {
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
b = FindNextVolumeMountPointHelper(h, lpszVolumeMountPoint,
|
|
cchBufferLength, TRUE);
|
|
if (!b) {
|
|
CloseHandle(h);
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
return h;
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
FindNextVolumeMountPointA(
|
|
HANDLE hFindVolumeMountPoint,
|
|
LPSTR lpszVolumeMountPoint,
|
|
DWORD cchBufferLength
|
|
)
|
|
|
|
{
|
|
ANSI_STRING ansiVolumeMountPoint;
|
|
UNICODE_STRING unicodeVolumeMountPoint;
|
|
BOOL b;
|
|
NTSTATUS status;
|
|
|
|
ansiVolumeMountPoint.Buffer = lpszVolumeMountPoint;
|
|
ansiVolumeMountPoint.MaximumLength = (USHORT) (cchBufferLength - 1);
|
|
unicodeVolumeMountPoint.Buffer = NULL;
|
|
unicodeVolumeMountPoint.MaximumLength = 0;
|
|
|
|
try {
|
|
|
|
unicodeVolumeMountPoint.MaximumLength =
|
|
(ansiVolumeMountPoint.MaximumLength + 1)*sizeof(WCHAR);
|
|
unicodeVolumeMountPoint.Buffer =
|
|
RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
|
|
unicodeVolumeMountPoint.MaximumLength);
|
|
if (!unicodeVolumeMountPoint.Buffer) {
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
|
|
b = FindNextVolumeMountPointW(hFindVolumeMountPoint,
|
|
unicodeVolumeMountPoint.Buffer,
|
|
cchBufferLength);
|
|
|
|
if (b) {
|
|
|
|
RtlInitUnicodeString(&unicodeVolumeMountPoint,
|
|
unicodeVolumeMountPoint.Buffer);
|
|
|
|
status = BasepUnicodeStringTo8BitString(&ansiVolumeMountPoint,
|
|
&unicodeVolumeMountPoint,
|
|
FALSE);
|
|
if (!NT_SUCCESS(status)) {
|
|
BaseSetLastNTError(status);
|
|
return FALSE;
|
|
}
|
|
|
|
ansiVolumeMountPoint.Buffer[ansiVolumeMountPoint.Length] = 0;
|
|
}
|
|
|
|
} finally {
|
|
|
|
if (unicodeVolumeMountPoint.Buffer) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, unicodeVolumeMountPoint.Buffer);
|
|
}
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
BOOL
|
|
IsThisAVolumeName(
|
|
LPCWSTR Name,
|
|
PBOOLEAN IsVolume
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine takes the given NT name and determines whether or not
|
|
the name points to a volume.
|
|
|
|
Arguments:
|
|
|
|
Name - Supplies the name.
|
|
|
|
IsVolume - Returns whether or not the given name is a volume.
|
|
|
|
Return Value:
|
|
|
|
FALSE - Failure.
|
|
|
|
TRUE - Success.
|
|
|
|
--*/
|
|
|
|
{
|
|
UNICODE_STRING name;
|
|
PMOUNTMGR_MOUNT_POINT point;
|
|
MOUNTMGR_MOUNT_POINTS points;
|
|
HANDLE h;
|
|
BOOL b;
|
|
DWORD bytes;
|
|
|
|
RtlInitUnicodeString(&name, Name);
|
|
if (name.Buffer[name.Length/sizeof(WCHAR) - 1] == '\\') {
|
|
name.Length -= sizeof(WCHAR);
|
|
}
|
|
point = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
|
|
name.Length + sizeof(MOUNTMGR_MOUNT_POINT));
|
|
if (!point) {
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
|
|
RtlZeroMemory(point, sizeof(MOUNTMGR_MOUNT_POINT));
|
|
point->DeviceNameOffset = sizeof(MOUNTMGR_MOUNT_POINT);
|
|
point->DeviceNameLength = name.Length;
|
|
RtlCopyMemory((PCHAR) point + point->DeviceNameOffset, name.Buffer,
|
|
point->DeviceNameLength);
|
|
|
|
if (name.Length >= 4 && name.Buffer[1] == '\\') {
|
|
((PWSTR) ((PCHAR) point + point->DeviceNameOffset))[1] = '?';
|
|
}
|
|
|
|
h = CreateFileW(MOUNTMGR_DOS_DEVICE_NAME, 0, FILE_SHARE_READ |
|
|
FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE);
|
|
if (h == INVALID_HANDLE_VALUE) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, point);
|
|
return FALSE;
|
|
}
|
|
|
|
b = DeviceIoControl(h, IOCTL_MOUNTMGR_QUERY_POINTS, point,
|
|
name.Length + sizeof(MOUNTMGR_MOUNT_POINT),
|
|
&points, sizeof(MOUNTMGR_MOUNT_POINTS), &bytes, NULL);
|
|
if (b) {
|
|
if (points.NumberOfMountPoints) {
|
|
*IsVolume = TRUE;
|
|
} else {
|
|
*IsVolume = FALSE;
|
|
}
|
|
} else {
|
|
if (GetLastError() == ERROR_MORE_DATA) {
|
|
*IsVolume = TRUE;
|
|
} else {
|
|
*IsVolume = FALSE;
|
|
}
|
|
}
|
|
|
|
CloseHandle(h);
|
|
RtlFreeHeap(RtlProcessHeap(), 0, point);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
FindNextVolumeMountPointW(
|
|
HANDLE hFindVolumeMountPoint,
|
|
LPWSTR lpszVolumeMountPoint,
|
|
DWORD cchBufferLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine continues the enumeration of all volume mount point on the
|
|
given volume.
|
|
|
|
Arguments:
|
|
|
|
hFindVolumeMountPoint - Supplies the handle for the enumeration.
|
|
|
|
lpszVolumeMountPoint - Returns the volume mount point.
|
|
|
|
cchBufferLength - Supplies the volume mount point buffer length.
|
|
|
|
Return Value:
|
|
|
|
FALSE - Failure.
|
|
|
|
TRUE - Success.
|
|
|
|
--*/
|
|
|
|
{
|
|
return FindNextVolumeMountPointHelper(hFindVolumeMountPoint,
|
|
lpszVolumeMountPoint,
|
|
cchBufferLength, FALSE);
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
FindVolumeMountPointClose(
|
|
HANDLE hFindVolumeMountPoint
|
|
)
|
|
|
|
{
|
|
return CloseHandle(hFindVolumeMountPoint);
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
GetVolumeNameForVolumeMountPointA(
|
|
LPCSTR lpszVolumeMountPoint,
|
|
LPSTR lpszVolumeName,
|
|
DWORD cchBufferLength
|
|
)
|
|
|
|
{
|
|
PUNICODE_STRING unicodeVolumeMountPoint;
|
|
ANSI_STRING ansiVolumeName;
|
|
UNICODE_STRING unicodeVolumeName;
|
|
BOOL b;
|
|
NTSTATUS status;
|
|
|
|
unicodeVolumeMountPoint =
|
|
Basep8BitStringToStaticUnicodeString(lpszVolumeMountPoint);
|
|
if (!unicodeVolumeMountPoint) {
|
|
return FALSE;
|
|
}
|
|
|
|
ansiVolumeName.Buffer = lpszVolumeName;
|
|
ansiVolumeName.MaximumLength = (USHORT) (cchBufferLength - 1);
|
|
unicodeVolumeName.Buffer = NULL;
|
|
unicodeVolumeName.MaximumLength = 0;
|
|
|
|
try {
|
|
|
|
unicodeVolumeName.MaximumLength =
|
|
(ansiVolumeName.MaximumLength + 1)*sizeof(WCHAR);
|
|
unicodeVolumeName.Buffer =
|
|
RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
|
|
unicodeVolumeName.MaximumLength);
|
|
if (!unicodeVolumeName.Buffer) {
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
|
|
b = GetVolumeNameForVolumeMountPointW(unicodeVolumeMountPoint->Buffer,
|
|
unicodeVolumeName.Buffer,
|
|
cchBufferLength);
|
|
|
|
if (b) {
|
|
|
|
RtlInitUnicodeString(&unicodeVolumeName,
|
|
unicodeVolumeName.Buffer);
|
|
|
|
status = BasepUnicodeStringTo8BitString(&ansiVolumeName,
|
|
&unicodeVolumeName,
|
|
FALSE);
|
|
if (!NT_SUCCESS(status)) {
|
|
BaseSetLastNTError(status);
|
|
return FALSE;
|
|
}
|
|
|
|
ansiVolumeName.Buffer[ansiVolumeName.Length] = 0;
|
|
}
|
|
|
|
} finally {
|
|
|
|
if (unicodeVolumeName.Buffer) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, unicodeVolumeName.Buffer);
|
|
}
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
BOOL
|
|
GetVolumeNameForRoot(
|
|
LPCWSTR DeviceName,
|
|
LPWSTR lpszVolumeName,
|
|
DWORD cchBufferLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine queries the volume name for the given NT device name.
|
|
|
|
Arguments:
|
|
|
|
DeviceName - Supplies a DOS device name terminated by a '\'.
|
|
|
|
lpszVolumeName - Returns the volume name pointed to by the DOS
|
|
device name.
|
|
|
|
cchBufferLength - Supplies the size of the preceeding buffer.
|
|
|
|
Return Value:
|
|
|
|
FALSE - Failure. The error code is returned in GetLastError().
|
|
|
|
TRUE - Success.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
UNICODE_STRING devicePath, symName;
|
|
OBJECT_ATTRIBUTES oa;
|
|
HANDLE h;
|
|
IO_STATUS_BLOCK ioStatus;
|
|
WCHAR buffer[MAX_PATH];
|
|
PMOUNTDEV_NAME name;
|
|
BOOL b;
|
|
DWORD bytes, i;
|
|
PMOUNTMGR_MOUNT_POINT point;
|
|
PMOUNTMGR_MOUNT_POINTS points;
|
|
|
|
if (GetDriveTypeW(DeviceName) == DRIVE_REMOTE) {
|
|
SetLastError(ERROR_PATH_NOT_FOUND);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!RtlDosPathNameToNtPathName_U(DeviceName, &devicePath, NULL, NULL)) {
|
|
SetLastError(ERROR_PATH_NOT_FOUND);
|
|
return FALSE;
|
|
}
|
|
|
|
if (devicePath.Buffer[devicePath.Length/sizeof(WCHAR) - 1] == '\\') {
|
|
devicePath.Buffer[devicePath.Length/sizeof(WCHAR) - 1] = 0;
|
|
devicePath.Length -= sizeof(WCHAR);
|
|
}
|
|
|
|
if (devicePath.Length >= 2*sizeof(WCHAR) &&
|
|
devicePath.Buffer[devicePath.Length/sizeof(WCHAR) - 1] == ':') {
|
|
|
|
devicePath.Buffer[devicePath.Length/sizeof(WCHAR) - 2] = (WCHAR)
|
|
toupper(devicePath.Buffer[devicePath.Length/sizeof(WCHAR) - 2]);
|
|
}
|
|
|
|
InitializeObjectAttributes(&oa, &devicePath, OBJ_CASE_INSENSITIVE,
|
|
NULL, NULL);
|
|
|
|
status = NtOpenFile(&h, FILE_READ_ATTRIBUTES | SYNCHRONIZE, &oa,
|
|
&ioStatus, FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_SYNCHRONOUS_IO_ALERT);
|
|
if (!NT_SUCCESS(status)) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, devicePath.Buffer);
|
|
SetLastError(RtlNtStatusToDosError(status));
|
|
return FALSE;
|
|
}
|
|
|
|
name = (PMOUNTDEV_NAME) buffer;
|
|
b = DeviceIoControl(h, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, NULL, 0, name,
|
|
MAX_PATH*sizeof(WCHAR), &bytes, NULL);
|
|
NtClose(h);
|
|
|
|
if (!b) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, devicePath.Buffer);
|
|
return FALSE;
|
|
}
|
|
|
|
RtlFreeHeap(RtlProcessHeap(), 0, devicePath.Buffer);
|
|
|
|
devicePath.Length = name->NameLength;
|
|
devicePath.MaximumLength = devicePath.Length + sizeof(WCHAR);
|
|
|
|
devicePath.Buffer = RtlAllocateHeap(RtlProcessHeap(),
|
|
MAKE_TAG(TMP_TAG),
|
|
devicePath.MaximumLength);
|
|
if (!devicePath.Buffer) {
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
|
|
RtlCopyMemory(devicePath.Buffer, name->Name, name->NameLength);
|
|
devicePath.Buffer[devicePath.Length/sizeof(WCHAR)] = 0;
|
|
|
|
point = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
|
|
devicePath.Length + sizeof(MOUNTMGR_MOUNT_POINT));
|
|
if (!point) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, devicePath.Buffer);
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
|
|
RtlZeroMemory(point, sizeof(MOUNTMGR_MOUNT_POINT));
|
|
point->DeviceNameOffset = sizeof(MOUNTMGR_MOUNT_POINT);
|
|
point->DeviceNameLength = devicePath.Length;
|
|
RtlCopyMemory((PCHAR) point + point->DeviceNameOffset,
|
|
devicePath.Buffer, point->DeviceNameLength);
|
|
|
|
RtlFreeHeap(RtlProcessHeap(), 0, devicePath.Buffer);
|
|
|
|
points = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
|
|
sizeof(MOUNTMGR_MOUNT_POINTS));
|
|
if (!points) {
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
RtlFreeHeap(RtlProcessHeap(), 0, point);
|
|
return FALSE;
|
|
}
|
|
|
|
h = CreateFileW(MOUNTMGR_DOS_DEVICE_NAME, 0,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
|
|
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
|
|
INVALID_HANDLE_VALUE);
|
|
if (h == INVALID_HANDLE_VALUE) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, points);
|
|
RtlFreeHeap(RtlProcessHeap(), 0, point);
|
|
return FALSE;
|
|
}
|
|
|
|
b = DeviceIoControl(h, IOCTL_MOUNTMGR_QUERY_POINTS, point,
|
|
devicePath.Length + sizeof(MOUNTMGR_MOUNT_POINT),
|
|
points, sizeof(MOUNTMGR_MOUNT_POINTS), &bytes, NULL);
|
|
while (!b && GetLastError() == ERROR_MORE_DATA) {
|
|
bytes = points->Size;
|
|
RtlFreeHeap(RtlProcessHeap(), 0, points);
|
|
points = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG), bytes);
|
|
if (!points) {
|
|
CloseHandle(h);
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
RtlFreeHeap(RtlProcessHeap(), 0, point);
|
|
return FALSE;
|
|
}
|
|
|
|
b = DeviceIoControl(h, IOCTL_MOUNTMGR_QUERY_POINTS, point,
|
|
devicePath.Length + sizeof(MOUNTMGR_MOUNT_POINT),
|
|
points, bytes, &bytes, NULL);
|
|
}
|
|
|
|
CloseHandle(h);
|
|
RtlFreeHeap(RtlProcessHeap(), 0, point);
|
|
|
|
if (!b) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, points);
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
for (i = 0; i < points->NumberOfMountPoints; i++) {
|
|
|
|
symName.Length = symName.MaximumLength =
|
|
points->MountPoints[i].SymbolicLinkNameLength;
|
|
symName.Buffer = (PWSTR) ((PCHAR) points +
|
|
points->MountPoints[i].SymbolicLinkNameOffset);
|
|
|
|
if (MOUNTMGR_IS_NT_VOLUME_NAME(&symName)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i == points->NumberOfMountPoints) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, points);
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
if (cchBufferLength*sizeof(WCHAR) < symName.Length + 2*sizeof(WCHAR)) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, points);
|
|
SetLastError(ERROR_FILENAME_EXCED_RANGE);
|
|
return FALSE;
|
|
}
|
|
|
|
RtlCopyMemory(lpszVolumeName, symName.Buffer, symName.Length);
|
|
lpszVolumeName[1] = '\\';
|
|
lpszVolumeName[symName.Length/sizeof(WCHAR)] = '\\';
|
|
lpszVolumeName[symName.Length/sizeof(WCHAR) + 1] = 0;
|
|
|
|
RtlFreeHeap(RtlProcessHeap(), 0, points);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
BasepGetVolumeNameFromReparsePoint(
|
|
LPCWSTR lpszVolumeMountPoint,
|
|
LPWSTR lpszVolumeName,
|
|
DWORD cchBufferLength,
|
|
PBOOL ResultOfOpen
|
|
)
|
|
|
|
{
|
|
HANDLE h;
|
|
PREPARSE_DATA_BUFFER reparse;
|
|
BOOL b;
|
|
DWORD bytes;
|
|
UNICODE_STRING mountName;
|
|
WCHAR c;
|
|
|
|
h = CreateFileW(lpszVolumeMountPoint, 0, FILE_SHARE_READ |
|
|
FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OPEN_REPARSE_POINT |
|
|
FILE_FLAG_BACKUP_SEMANTICS, INVALID_HANDLE_VALUE);
|
|
if (h == INVALID_HANDLE_VALUE) {
|
|
if (ResultOfOpen) {
|
|
*ResultOfOpen = FALSE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
if (ResultOfOpen) {
|
|
*ResultOfOpen = TRUE;
|
|
}
|
|
|
|
reparse = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
|
|
MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
|
|
if (!reparse) {
|
|
CloseHandle(h);
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
|
|
b = DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, NULL, 0, reparse,
|
|
MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &bytes, NULL);
|
|
CloseHandle(h);
|
|
|
|
if (!b || reparse->ReparseTag != IO_REPARSE_TAG_MOUNT_POINT) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, reparse);
|
|
return FALSE;
|
|
}
|
|
|
|
if (cchBufferLength*sizeof(WCHAR) <
|
|
reparse->MountPointReparseBuffer.SubstituteNameLength + sizeof(WCHAR)) {
|
|
|
|
RtlFreeHeap(RtlProcessHeap(), 0, reparse);
|
|
SetLastError(ERROR_FILENAME_EXCED_RANGE);
|
|
return FALSE;
|
|
}
|
|
|
|
RtlCopyMemory(lpszVolumeName,
|
|
(PCHAR) reparse->MountPointReparseBuffer.PathBuffer +
|
|
reparse->MountPointReparseBuffer.SubstituteNameOffset,
|
|
reparse->MountPointReparseBuffer.SubstituteNameLength);
|
|
|
|
c = lpszVolumeName[1];
|
|
lpszVolumeName[1] = '\\';
|
|
lpszVolumeName[reparse->MountPointReparseBuffer.SubstituteNameLength/
|
|
sizeof(WCHAR)] = 0;
|
|
|
|
mountName.Length = mountName.MaximumLength =
|
|
reparse->MountPointReparseBuffer.SubstituteNameLength;
|
|
mountName.Buffer = lpszVolumeName;
|
|
|
|
RtlFreeHeap(RtlProcessHeap(), 0, reparse);
|
|
|
|
if (!MOUNTMGR_IS_DOS_VOLUME_NAME_WB(&mountName)) {
|
|
lpszVolumeName[1] = c;
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
BasepGetVolumeNameForVolumeMountPoint(
|
|
LPCWSTR lpszVolumeMountPoint,
|
|
LPWSTR lpszVolumeName,
|
|
DWORD cchBufferLength,
|
|
PBOOL ResultOfOpen
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns the volume name for a given volume mount point.
|
|
|
|
Arguments:
|
|
|
|
lpszVolumeMountPoint - Supplies the volume mount point.
|
|
|
|
lpszVolumeName - Returns the volume name.
|
|
|
|
cchBufferLength - Supplies the size of the volume name buffer.
|
|
|
|
Return Value:
|
|
|
|
FALSE - Failure.
|
|
|
|
TRUE - Success.
|
|
|
|
--*/
|
|
|
|
{
|
|
UNICODE_STRING unicodeVolumeMountPoint;
|
|
BOOL b;
|
|
|
|
if (ResultOfOpen) {
|
|
*ResultOfOpen = TRUE;
|
|
}
|
|
|
|
RtlInitUnicodeString(&unicodeVolumeMountPoint, lpszVolumeMountPoint);
|
|
if (unicodeVolumeMountPoint.Buffer[
|
|
unicodeVolumeMountPoint.Length/sizeof(WCHAR) - 1] != '\\') {
|
|
|
|
BaseSetLastNTError(STATUS_OBJECT_NAME_INVALID);
|
|
if (lpszVolumeName && cchBufferLength >= 1) {
|
|
*lpszVolumeName = 0;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
if (unicodeVolumeMountPoint.Length == 6 &&
|
|
unicodeVolumeMountPoint.Buffer[1] == ':') {
|
|
|
|
b = GetVolumeNameForRoot(lpszVolumeMountPoint, lpszVolumeName,
|
|
cchBufferLength);
|
|
if (!b && lpszVolumeName && cchBufferLength >= 1) {
|
|
*lpszVolumeName = 0;
|
|
}
|
|
return b;
|
|
}
|
|
|
|
if (unicodeVolumeMountPoint.Length == 14 &&
|
|
unicodeVolumeMountPoint.Buffer[0] == '\\' &&
|
|
unicodeVolumeMountPoint.Buffer[1] == '\\' &&
|
|
(unicodeVolumeMountPoint.Buffer[2] == '.' ||
|
|
unicodeVolumeMountPoint.Buffer[2] == '?') &&
|
|
unicodeVolumeMountPoint.Buffer[3] == '\\' &&
|
|
unicodeVolumeMountPoint.Buffer[5] == ':') {
|
|
|
|
b = GetVolumeNameForRoot(lpszVolumeMountPoint + 4,
|
|
lpszVolumeName, cchBufferLength);
|
|
if (!b && lpszVolumeName && cchBufferLength >= 1) {
|
|
*lpszVolumeName = 0;
|
|
}
|
|
return b;
|
|
}
|
|
|
|
if (GetVolumeNameForRoot(lpszVolumeMountPoint, lpszVolumeName,
|
|
cchBufferLength)) {
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
b = BasepGetVolumeNameFromReparsePoint(lpszVolumeMountPoint,
|
|
lpszVolumeName, cchBufferLength,
|
|
ResultOfOpen);
|
|
if (!b && lpszVolumeName && cchBufferLength >= 1) {
|
|
*lpszVolumeName = 0;
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
GetVolumeNameForVolumeMountPointW(
|
|
LPCWSTR lpszVolumeMountPoint,
|
|
LPWSTR lpszVolumeName,
|
|
DWORD cchBufferLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns the volume name for a given volume mount point.
|
|
|
|
Arguments:
|
|
|
|
lpszVolumeMountPoint - Supplies the volume mount point.
|
|
|
|
lpszVolumeName - Returns the volume name.
|
|
|
|
cchBufferLength - Supplies the size of the volume name buffer.
|
|
|
|
Return Value:
|
|
|
|
FALSE - Failure.
|
|
|
|
TRUE - Success.
|
|
|
|
--*/
|
|
|
|
{
|
|
return BasepGetVolumeNameForVolumeMountPoint(lpszVolumeMountPoint,
|
|
lpszVolumeName,
|
|
cchBufferLength, NULL);
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
SetVolumeMountPointA(
|
|
LPCSTR lpszVolumeMountPoint,
|
|
LPCSTR lpszVolumeName
|
|
)
|
|
|
|
{
|
|
PUNICODE_STRING unicodeVolumeMountPoint;
|
|
UNICODE_STRING unicodeVolumeName;
|
|
BOOL b;
|
|
|
|
unicodeVolumeMountPoint = Basep8BitStringToStaticUnicodeString(
|
|
lpszVolumeMountPoint);
|
|
if (!unicodeVolumeMountPoint) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (!Basep8BitStringToDynamicUnicodeString(&unicodeVolumeName,
|
|
lpszVolumeName)) {
|
|
return FALSE;
|
|
}
|
|
|
|
b = SetVolumeMountPointW(unicodeVolumeMountPoint->Buffer,
|
|
unicodeVolumeName.Buffer);
|
|
|
|
RtlFreeUnicodeString(&unicodeVolumeName);
|
|
|
|
return b;
|
|
}
|
|
|
|
BOOL
|
|
SetVolumeNameForRoot(
|
|
LPCWSTR DeviceName,
|
|
LPCWSTR lpszVolumeName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets the volume name for the given DOS device name.
|
|
|
|
Arguments:
|
|
|
|
DeviceName - Supplies a DOS device name terminated by a '\'.
|
|
|
|
lpszVolumeName - Supplies the volume name that the DOS device name
|
|
will point to.
|
|
|
|
Return Value:
|
|
|
|
FALSE - Failure. The error code is returned in GetLastError().
|
|
|
|
TRUE - Success.
|
|
|
|
--*/
|
|
|
|
{
|
|
UNICODE_STRING devicePath, volumeName;
|
|
DWORD inputLength;
|
|
PMOUNTMGR_CREATE_POINT_INPUT input;
|
|
HANDLE h;
|
|
BOOL b;
|
|
DWORD bytes;
|
|
|
|
devicePath.Length = 28;
|
|
devicePath.MaximumLength = devicePath.Length + sizeof(WCHAR);
|
|
devicePath.Buffer = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
|
|
devicePath.MaximumLength);
|
|
if (!devicePath.Buffer) {
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
RtlCopyMemory(devicePath.Buffer, L"\\DosDevices\\", 24);
|
|
|
|
devicePath.Buffer[12] = (WCHAR)toupper(DeviceName[0]);
|
|
devicePath.Buffer[13] = ':';
|
|
devicePath.Buffer[14] = 0;
|
|
|
|
RtlInitUnicodeString(&volumeName, lpszVolumeName);
|
|
volumeName.Length -= sizeof(WCHAR);
|
|
|
|
inputLength = sizeof(MOUNTMGR_CREATE_POINT_INPUT) + devicePath.Length +
|
|
volumeName.Length;
|
|
input = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG), inputLength);
|
|
if (!input) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, devicePath.Buffer);
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
|
|
input->SymbolicLinkNameOffset = sizeof(MOUNTMGR_CREATE_POINT_INPUT);
|
|
input->SymbolicLinkNameLength = devicePath.Length;
|
|
input->DeviceNameOffset = input->SymbolicLinkNameOffset +
|
|
input->SymbolicLinkNameLength;
|
|
input->DeviceNameLength = volumeName.Length;
|
|
RtlCopyMemory((PCHAR) input + input->SymbolicLinkNameOffset,
|
|
devicePath.Buffer, input->SymbolicLinkNameLength);
|
|
RtlCopyMemory((PCHAR) input + input->DeviceNameOffset, volumeName.Buffer,
|
|
input->DeviceNameLength);
|
|
((PWSTR) ((PCHAR) input + input->DeviceNameOffset))[1] = '?';
|
|
|
|
RtlFreeHeap(RtlProcessHeap(), 0, devicePath.Buffer);
|
|
|
|
h = CreateFileW(MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE);
|
|
if (h == INVALID_HANDLE_VALUE) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, input);
|
|
return FALSE;
|
|
}
|
|
|
|
b = DeviceIoControl(h, IOCTL_MOUNTMGR_CREATE_POINT, input, inputLength,
|
|
NULL, 0, &bytes, NULL);
|
|
|
|
CloseHandle(h);
|
|
RtlFreeHeap(RtlProcessHeap(), 0, input);
|
|
|
|
return b;
|
|
}
|
|
|
|
VOID
|
|
NotifyMountMgr(
|
|
LPCWSTR lpszVolumeMountPoint,
|
|
LPCWSTR lpszVolumeName,
|
|
BOOL IsPointCreated
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine notifies the mount mgr that a volume mount point was
|
|
created or deleted so that the mount mgr can update the remote database on
|
|
the volume where the mount point was created or deleted.
|
|
|
|
Arguments:
|
|
|
|
lpszVolumeMountPoint - Supplies the directory where the volume mount
|
|
point resides.
|
|
|
|
lpszVolumeName - Supplies the volume name.
|
|
|
|
IsPointCreated - Supplies wheter or not the point was created or
|
|
deleted.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
UNICODE_STRING unicodeSourceVolumeName;
|
|
UNICODE_STRING unicodeTargetVolumeName;
|
|
DWORD inputSize;
|
|
PMOUNTMGR_VOLUME_MOUNT_POINT input;
|
|
HANDLE h;
|
|
DWORD ioControl, bytes;
|
|
|
|
if (!RtlDosPathNameToNtPathName_U(lpszVolumeMountPoint,
|
|
&unicodeSourceVolumeName, NULL, NULL)) {
|
|
|
|
return;
|
|
}
|
|
|
|
RtlInitUnicodeString(&unicodeTargetVolumeName, lpszVolumeName);
|
|
unicodeSourceVolumeName.Length -= sizeof(WCHAR);
|
|
unicodeTargetVolumeName.Length -= sizeof(WCHAR);
|
|
|
|
inputSize = sizeof(MOUNTMGR_VOLUME_MOUNT_POINT) +
|
|
unicodeSourceVolumeName.Length +
|
|
unicodeTargetVolumeName.Length;
|
|
input = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG), inputSize);
|
|
if (!input) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, unicodeSourceVolumeName.Buffer);
|
|
return;
|
|
}
|
|
|
|
input->SourceVolumeNameOffset = sizeof(MOUNTMGR_VOLUME_MOUNT_POINT);
|
|
input->SourceVolumeNameLength = unicodeSourceVolumeName.Length;
|
|
input->TargetVolumeNameOffset = input->SourceVolumeNameOffset +
|
|
input->SourceVolumeNameLength;
|
|
input->TargetVolumeNameLength = unicodeTargetVolumeName.Length;
|
|
|
|
RtlCopyMemory((PCHAR) input + input->SourceVolumeNameOffset,
|
|
unicodeSourceVolumeName.Buffer,
|
|
input->SourceVolumeNameLength);
|
|
|
|
RtlCopyMemory((PCHAR) input + input->TargetVolumeNameOffset,
|
|
unicodeTargetVolumeName.Buffer,
|
|
input->TargetVolumeNameLength);
|
|
|
|
((PWSTR) ((PCHAR) input + input->TargetVolumeNameOffset))[1] = '?';
|
|
|
|
h = CreateFileW(MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE);
|
|
if (h == INVALID_HANDLE_VALUE) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, input);
|
|
RtlFreeHeap(RtlProcessHeap(), 0, unicodeSourceVolumeName.Buffer);
|
|
return;
|
|
}
|
|
|
|
if (IsPointCreated) {
|
|
ioControl = IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_CREATED;
|
|
} else {
|
|
ioControl = IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_DELETED;
|
|
}
|
|
|
|
DeviceIoControl(h, ioControl, input, inputSize, NULL, 0, &bytes, NULL);
|
|
|
|
CloseHandle(h);
|
|
RtlFreeHeap(RtlProcessHeap(), 0, input);
|
|
RtlFreeHeap(RtlProcessHeap(), 0, unicodeSourceVolumeName.Buffer);
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
SetVolumeMountPointW(
|
|
LPCWSTR lpszVolumeMountPoint,
|
|
LPCWSTR lpszVolumeName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets a mount point on the given directory pointed to by
|
|
'VolumeMountPoint' which points to the volume given by 'VolumeName'.
|
|
In the case when 'VolumeMountPoint' is of the form "D:\", the drive
|
|
letter for the given volume is set to 'D:'.
|
|
|
|
Arguments:
|
|
|
|
lpszVolumeMountPoint - Supplies the directory where the volume mount
|
|
point will reside.
|
|
|
|
lpszVolumeName - Supplies the volume name.
|
|
|
|
Return Value:
|
|
|
|
FALSE - Failure.
|
|
|
|
TRUE - Success.
|
|
|
|
--*/
|
|
|
|
{
|
|
UNICODE_STRING unicodeVolumeMountPoint;
|
|
UNICODE_STRING unicodeVolumeName;
|
|
BOOLEAN isVolume;
|
|
BOOL b;
|
|
WCHAR volumeMountPointVolumePrefix[MAX_PATH];
|
|
HANDLE h;
|
|
PREPARSE_DATA_BUFFER reparse;
|
|
DWORD bytes;
|
|
|
|
if (GetVolumeNameForVolumeMountPointW(lpszVolumeMountPoint,
|
|
volumeMountPointVolumePrefix,
|
|
MAX_PATH) ||
|
|
GetLastError() == ERROR_FILENAME_EXCED_RANGE) {
|
|
|
|
SetLastError(ERROR_DIR_NOT_EMPTY);
|
|
return FALSE;
|
|
}
|
|
|
|
RtlInitUnicodeString(&unicodeVolumeMountPoint, lpszVolumeMountPoint);
|
|
RtlInitUnicodeString(&unicodeVolumeName, lpszVolumeName);
|
|
|
|
if (unicodeVolumeMountPoint.Length == 0 ||
|
|
unicodeVolumeName.Length == 0) {
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
if (unicodeVolumeMountPoint.Buffer[
|
|
unicodeVolumeMountPoint.Length/sizeof(WCHAR) - 1] != '\\' ||
|
|
unicodeVolumeName.Buffer[
|
|
unicodeVolumeName.Length/sizeof(WCHAR) - 1] != '\\') {
|
|
|
|
BaseSetLastNTError(STATUS_OBJECT_NAME_INVALID);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!MOUNTMGR_IS_DOS_VOLUME_NAME_WB(&unicodeVolumeName)) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!IsThisAVolumeName(lpszVolumeName, &isVolume)) {
|
|
return FALSE;
|
|
}
|
|
if (!isVolume) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
if (unicodeVolumeMountPoint.Length == 6 &&
|
|
unicodeVolumeMountPoint.Buffer[1] == ':') {
|
|
|
|
return SetVolumeNameForRoot(lpszVolumeMountPoint, lpszVolumeName);
|
|
}
|
|
|
|
if (unicodeVolumeMountPoint.Length == 14 &&
|
|
unicodeVolumeMountPoint.Buffer[0] == '\\' &&
|
|
unicodeVolumeMountPoint.Buffer[1] == '\\' &&
|
|
(unicodeVolumeMountPoint.Buffer[2] == '.' ||
|
|
unicodeVolumeMountPoint.Buffer[2] == '?') &&
|
|
unicodeVolumeMountPoint.Buffer[3] == '\\' &&
|
|
unicodeVolumeMountPoint.Buffer[5] == ':') {
|
|
|
|
return SetVolumeNameForRoot(lpszVolumeMountPoint + 4, lpszVolumeName);
|
|
}
|
|
|
|
if (GetDriveTypeW(lpszVolumeMountPoint) != DRIVE_FIXED) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
h = CreateFileW(MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE);
|
|
if (h == INVALID_HANDLE_VALUE) {
|
|
return FALSE;
|
|
}
|
|
|
|
CloseHandle(h);
|
|
|
|
h = CreateFileW(lpszVolumeMountPoint, GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OPEN_REPARSE_POINT |
|
|
FILE_FLAG_BACKUP_SEMANTICS, INVALID_HANDLE_VALUE);
|
|
if (h == INVALID_HANDLE_VALUE) {
|
|
return FALSE;
|
|
}
|
|
|
|
reparse = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
|
|
MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
|
|
if (!reparse) {
|
|
CloseHandle(h);
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
|
|
reparse->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
|
|
reparse->ReparseDataLength = (USHORT) (FIELD_OFFSET(REPARSE_DATA_BUFFER,
|
|
MountPointReparseBuffer.PathBuffer) -
|
|
REPARSE_DATA_BUFFER_HEADER_SIZE +
|
|
unicodeVolumeName.Length + 2*sizeof(WCHAR));
|
|
reparse->Reserved = 0;
|
|
reparse->MountPointReparseBuffer.SubstituteNameOffset = 0;
|
|
reparse->MountPointReparseBuffer.SubstituteNameLength = unicodeVolumeName.Length;
|
|
reparse->MountPointReparseBuffer.PrintNameOffset =
|
|
reparse->MountPointReparseBuffer.SubstituteNameLength +
|
|
sizeof(WCHAR);
|
|
reparse->MountPointReparseBuffer.PrintNameLength = 0;
|
|
|
|
CopyMemory(reparse->MountPointReparseBuffer.PathBuffer,
|
|
unicodeVolumeName.Buffer,
|
|
reparse->MountPointReparseBuffer.SubstituteNameLength);
|
|
|
|
reparse->MountPointReparseBuffer.PathBuffer[1] = '?';
|
|
reparse->MountPointReparseBuffer.PathBuffer[
|
|
unicodeVolumeName.Length/sizeof(WCHAR)] = 0;
|
|
reparse->MountPointReparseBuffer.PathBuffer[
|
|
unicodeVolumeName.Length/sizeof(WCHAR) + 1] = 0;
|
|
|
|
b = DeviceIoControl(h, FSCTL_SET_REPARSE_POINT, reparse,
|
|
REPARSE_DATA_BUFFER_HEADER_SIZE +
|
|
reparse->ReparseDataLength, NULL, 0, &bytes, NULL);
|
|
|
|
RtlFreeHeap(RtlProcessHeap(), 0, reparse);
|
|
CloseHandle(h);
|
|
|
|
if (b) {
|
|
NotifyMountMgr(lpszVolumeMountPoint, lpszVolumeName, TRUE);
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
DeleteVolumeMountPointA(
|
|
LPCSTR lpszVolumeMountPoint
|
|
)
|
|
|
|
{
|
|
PUNICODE_STRING unicodeVolumeMountPoint;
|
|
BOOL b;
|
|
|
|
unicodeVolumeMountPoint = Basep8BitStringToStaticUnicodeString(
|
|
lpszVolumeMountPoint);
|
|
if (!unicodeVolumeMountPoint) {
|
|
return FALSE;
|
|
}
|
|
|
|
b = DeleteVolumeMountPointW(unicodeVolumeMountPoint->Buffer);
|
|
|
|
return b;
|
|
}
|
|
|
|
BOOL
|
|
DeleteVolumeNameForRoot(
|
|
LPCWSTR DeviceName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine deletes the given DOS device name.
|
|
|
|
Arguments:
|
|
|
|
DeviceName - Supplies a DOS device name terminated by a '\'.
|
|
|
|
Return Value:
|
|
|
|
FALSE - Failure. The error code is returned in GetLastError().
|
|
|
|
TRUE - Success.
|
|
|
|
--*/
|
|
|
|
{
|
|
UNICODE_STRING devicePath;
|
|
DWORD inputLength;
|
|
PMOUNTMGR_MOUNT_POINT input;
|
|
DWORD outputLength;
|
|
PMOUNTMGR_MOUNT_POINTS output;
|
|
HANDLE h;
|
|
BOOL b;
|
|
DWORD bytes;
|
|
|
|
devicePath.Length = 28;
|
|
devicePath.MaximumLength = devicePath.Length + sizeof(WCHAR);
|
|
devicePath.Buffer = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
|
|
devicePath.MaximumLength);
|
|
if (!devicePath.Buffer) {
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
RtlCopyMemory(devicePath.Buffer, L"\\DosDevices\\", 24);
|
|
|
|
devicePath.Buffer[12] = (WCHAR)toupper(DeviceName[0]);
|
|
devicePath.Buffer[13] = ':';
|
|
devicePath.Buffer[14] = 0;
|
|
|
|
inputLength = sizeof(MOUNTMGR_MOUNT_POINT) + devicePath.Length;
|
|
input = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG), inputLength);
|
|
if (!input) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, devicePath.Buffer);
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
|
|
RtlZeroMemory(input, sizeof(MOUNTMGR_MOUNT_POINT));
|
|
input->SymbolicLinkNameOffset = sizeof(MOUNTMGR_MOUNT_POINT);
|
|
input->SymbolicLinkNameLength = devicePath.Length;
|
|
RtlCopyMemory((PCHAR) input + input->SymbolicLinkNameOffset,
|
|
devicePath.Buffer, input->SymbolicLinkNameLength);
|
|
|
|
RtlFreeHeap(RtlProcessHeap(), 0, devicePath.Buffer);
|
|
|
|
outputLength = sizeof(MOUNTMGR_MOUNT_POINTS) + 3*MAX_PATH*sizeof(WCHAR);
|
|
output = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
|
|
outputLength);
|
|
if (!output) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, input);
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
|
|
h = CreateFileW(MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE);
|
|
if (h == INVALID_HANDLE_VALUE) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, output);
|
|
RtlFreeHeap(RtlProcessHeap(), 0, input);
|
|
return FALSE;
|
|
}
|
|
|
|
b = DeviceIoControl(h, IOCTL_MOUNTMGR_DELETE_POINTS, input, inputLength,
|
|
output, outputLength, &bytes, NULL);
|
|
|
|
CloseHandle(h);
|
|
RtlFreeHeap(RtlProcessHeap(), 0, output);
|
|
RtlFreeHeap(RtlProcessHeap(), 0, input);
|
|
|
|
return b;
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
DeleteVolumeMountPointW(
|
|
LPCWSTR lpszVolumeMountPoint
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine removes the NTFS junction point from the given directory
|
|
or remove the drive letter symbolic link pointing to the given volume.
|
|
|
|
Arguments:
|
|
|
|
lpszVolumeMountPoint - Supplies the volume mount piont.
|
|
|
|
Return Value:
|
|
|
|
FALSE - Failure.
|
|
|
|
TRUE - Success.
|
|
|
|
--*/
|
|
|
|
{
|
|
UNICODE_STRING unicodeVolumeMountPoint;
|
|
HANDLE h;
|
|
PREPARSE_DATA_BUFFER reparse;
|
|
BOOL b;
|
|
DWORD bytes;
|
|
UNICODE_STRING substituteName;
|
|
|
|
RtlInitUnicodeString(&unicodeVolumeMountPoint, lpszVolumeMountPoint);
|
|
|
|
if (unicodeVolumeMountPoint.Buffer[
|
|
unicodeVolumeMountPoint.Length/sizeof(WCHAR) - 1] != '\\') {
|
|
|
|
BaseSetLastNTError(STATUS_OBJECT_NAME_INVALID);
|
|
return FALSE;
|
|
}
|
|
|
|
if (unicodeVolumeMountPoint.Length == 6 &&
|
|
unicodeVolumeMountPoint.Buffer[1] == ':') {
|
|
|
|
return DeleteVolumeNameForRoot(lpszVolumeMountPoint);
|
|
}
|
|
|
|
if (unicodeVolumeMountPoint.Length == 14 &&
|
|
unicodeVolumeMountPoint.Buffer[0] == '\\' &&
|
|
unicodeVolumeMountPoint.Buffer[1] == '\\' &&
|
|
(unicodeVolumeMountPoint.Buffer[2] == '.' ||
|
|
unicodeVolumeMountPoint.Buffer[2] == '?') &&
|
|
unicodeVolumeMountPoint.Buffer[3] == '\\' &&
|
|
unicodeVolumeMountPoint.Buffer[5] == ':') {
|
|
|
|
return DeleteVolumeNameForRoot(lpszVolumeMountPoint + 4);
|
|
}
|
|
|
|
h = CreateFileW(MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE);
|
|
if (h == INVALID_HANDLE_VALUE) {
|
|
return FALSE;
|
|
}
|
|
|
|
CloseHandle(h);
|
|
|
|
h = CreateFileW(lpszVolumeMountPoint, GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
|
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL |
|
|
FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
|
|
INVALID_HANDLE_VALUE);
|
|
if (h == INVALID_HANDLE_VALUE) {
|
|
return FALSE;
|
|
}
|
|
|
|
reparse = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
|
|
MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
|
|
if (!reparse) {
|
|
CloseHandle(h);
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
|
|
b = DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, NULL, 0, reparse,
|
|
MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &bytes, NULL);
|
|
|
|
if (!b || reparse->ReparseTag != IO_REPARSE_TAG_MOUNT_POINT) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, reparse);
|
|
CloseHandle(h);
|
|
return FALSE;
|
|
}
|
|
|
|
substituteName.MaximumLength = substituteName.Length =
|
|
reparse->MountPointReparseBuffer.SubstituteNameLength;
|
|
substituteName.Buffer = (PWSTR)
|
|
((PCHAR) reparse->MountPointReparseBuffer.PathBuffer +
|
|
reparse->MountPointReparseBuffer.SubstituteNameOffset);
|
|
|
|
if (!MOUNTMGR_IS_NT_VOLUME_NAME_WB(&substituteName)) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, reparse);
|
|
CloseHandle(h);
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
reparse->ReparseDataLength = 0;
|
|
|
|
b = DeviceIoControl(h, FSCTL_DELETE_REPARSE_POINT, reparse,
|
|
REPARSE_DATA_BUFFER_HEADER_SIZE, NULL, 0, &bytes,
|
|
NULL);
|
|
|
|
CloseHandle(h);
|
|
|
|
if (b) {
|
|
substituteName.Buffer[1] = '\\';
|
|
substituteName.Buffer[substituteName.Length/sizeof(WCHAR)] = 0;
|
|
NotifyMountMgr(lpszVolumeMountPoint, substituteName.Buffer,
|
|
FALSE);
|
|
}
|
|
|
|
RtlFreeHeap(RtlProcessHeap(), 0, reparse);
|
|
|
|
return b;
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
GetVolumePathNameA(
|
|
LPCSTR lpszFileName,
|
|
LPSTR lpszVolumePathName,
|
|
DWORD cchBufferLength
|
|
)
|
|
|
|
{
|
|
PUNICODE_STRING unicodeFileName;
|
|
ANSI_STRING ansiVolumePathName;
|
|
UNICODE_STRING unicodeVolumePathName;
|
|
BOOL b;
|
|
NTSTATUS status;
|
|
|
|
unicodeFileName = Basep8BitStringToStaticUnicodeString(lpszFileName);
|
|
if (!unicodeFileName) {
|
|
return FALSE;
|
|
}
|
|
|
|
ansiVolumePathName.Buffer = lpszVolumePathName;
|
|
ansiVolumePathName.MaximumLength = (USHORT) (cchBufferLength - 1);
|
|
unicodeVolumePathName.Buffer = NULL;
|
|
unicodeVolumePathName.MaximumLength = 0;
|
|
|
|
try {
|
|
|
|
unicodeVolumePathName.MaximumLength =
|
|
(ansiVolumePathName.MaximumLength + 1)*sizeof(WCHAR);
|
|
unicodeVolumePathName.Buffer =
|
|
RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
|
|
unicodeVolumePathName.MaximumLength);
|
|
if (!unicodeVolumePathName.Buffer) {
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
|
|
b = GetVolumePathNameW(unicodeFileName->Buffer,
|
|
unicodeVolumePathName.Buffer,
|
|
cchBufferLength);
|
|
|
|
if (b) {
|
|
|
|
RtlInitUnicodeString(&unicodeVolumePathName,
|
|
unicodeVolumePathName.Buffer);
|
|
|
|
status = BasepUnicodeStringTo8BitString(&ansiVolumePathName,
|
|
&unicodeVolumePathName,
|
|
FALSE);
|
|
if (!NT_SUCCESS(status)) {
|
|
BaseSetLastNTError(status);
|
|
return FALSE;
|
|
}
|
|
|
|
ansiVolumePathName.Buffer[ansiVolumePathName.Length] = 0;
|
|
}
|
|
|
|
} finally {
|
|
|
|
if (unicodeVolumePathName.Buffer) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, unicodeVolumePathName.Buffer);
|
|
}
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
GetVolumePathNameW(
|
|
LPCWSTR lpszFileName,
|
|
LPWSTR lpszVolumePathName,
|
|
DWORD cchBufferLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will return a full path whose prefix is the longest prefix
|
|
that represents a volume.
|
|
|
|
Arguments:
|
|
|
|
lpszFileName - Supplies the file name.
|
|
|
|
lpszVolumePathName - Returns the volume path name.
|
|
|
|
cchBufferLength - Supplies the volume path name buffer length.
|
|
|
|
Return Value:
|
|
|
|
FALSE - Failure.
|
|
|
|
TRUE - Success.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD fullPathLength;
|
|
PWSTR fullPath, p;
|
|
WCHAR c;
|
|
UNICODE_STRING name, dosName, prefix;
|
|
BOOL b, resultOfOpen;
|
|
PWSTR volumeName;
|
|
DWORD i;
|
|
|
|
fullPathLength = GetFullPathNameW(lpszFileName, 0, NULL, NULL);
|
|
if (!fullPathLength) {
|
|
return FALSE;
|
|
}
|
|
fullPathLength += 10;
|
|
|
|
fullPath = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
|
|
fullPathLength*sizeof(WCHAR));
|
|
if (!fullPath) {
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!GetFullPathNameW(lpszFileName, fullPathLength, fullPath, &p)) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, fullPath);
|
|
return FALSE;
|
|
}
|
|
|
|
RtlInitUnicodeString(&name, fullPath);
|
|
|
|
//
|
|
// Append a trailing backslash to start the search.
|
|
//
|
|
|
|
if (name.Buffer[(name.Length/sizeof(WCHAR)) - 1] != '\\') {
|
|
name.Length += sizeof(WCHAR);
|
|
name.Buffer[(name.Length/sizeof(WCHAR)) - 1] = '\\';
|
|
name.Buffer[name.Length/sizeof(WCHAR)] = 0;
|
|
}
|
|
|
|
volumeName = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
|
|
MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
|
|
if (!volumeName) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, fullPath);
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
|
|
p = NULL;
|
|
c = 0;
|
|
|
|
for (;;) {
|
|
|
|
b = BasepGetVolumeNameForVolumeMountPoint(
|
|
name.Buffer, volumeName, MAXIMUM_REPARSE_DATA_BUFFER_SIZE/
|
|
sizeof(WCHAR), &resultOfOpen);
|
|
if (b) {
|
|
break;
|
|
}
|
|
|
|
if (!resultOfOpen && GetLastError() == ERROR_ACCESS_DENIED) {
|
|
resultOfOpen = TRUE;
|
|
}
|
|
|
|
if (*volumeName) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, fullPath);
|
|
|
|
if (volumeName[0] == '\\' && volumeName[1] == '?' &&
|
|
volumeName[2] == '?' && volumeName[3] == '\\') {
|
|
|
|
if (volumeName[4] && volumeName[5] == ':') {
|
|
RtlInitUnicodeString(&name, volumeName);
|
|
MoveMemory(volumeName, volumeName + 4,
|
|
name.Length - 3*sizeof(WCHAR));
|
|
} else {
|
|
volumeName[1] = '\\';
|
|
}
|
|
|
|
b = GetVolumePathNameW(volumeName, lpszVolumePathName,
|
|
cchBufferLength);
|
|
|
|
} else {
|
|
|
|
RtlInitUnicodeString(&name, volumeName);
|
|
RtlInitUnicodeString(&prefix, L"\\\\?\\GLOBALROOT");
|
|
dosName.Length = name.Length + prefix.Length;
|
|
dosName.MaximumLength = dosName.Length + sizeof(WCHAR);
|
|
dosName.Buffer = RtlAllocateHeap(RtlProcessHeap(),
|
|
MAKE_TAG(TMP_TAG),
|
|
dosName.MaximumLength);
|
|
if (!dosName.Buffer) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, volumeName);
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
|
|
CopyMemory(dosName.Buffer, prefix.Buffer, prefix.Length);
|
|
CopyMemory((PCHAR) dosName.Buffer + prefix.Length,
|
|
name.Buffer, name.Length);
|
|
dosName.Buffer[dosName.Length/sizeof(WCHAR)] = 0;
|
|
|
|
b = GetVolumePathNameW(dosName.Buffer, lpszVolumePathName,
|
|
cchBufferLength);
|
|
|
|
RtlFreeHeap(RtlProcessHeap(), 0, dosName.Buffer);
|
|
}
|
|
|
|
RtlFreeHeap(RtlProcessHeap(), 0, volumeName);
|
|
|
|
return b;
|
|
}
|
|
|
|
if (!resultOfOpen && p) {
|
|
*p = c;
|
|
RtlInitUnicodeString(&name, fullPath);
|
|
break;
|
|
}
|
|
|
|
if (name.Length <= sizeof(WCHAR)) {
|
|
break;
|
|
}
|
|
|
|
for (i = name.Length/sizeof(WCHAR) - 2; i > 0; i--) {
|
|
if (name.Buffer[i] == '\\') {
|
|
break;
|
|
}
|
|
}
|
|
if (!i) {
|
|
break;
|
|
}
|
|
|
|
if (resultOfOpen) {
|
|
p = &name.Buffer[i + 1];
|
|
c = *p;
|
|
*p = 0;
|
|
} else {
|
|
name.Buffer[i + 1] = 0;
|
|
}
|
|
|
|
RtlInitUnicodeString(&name, fullPath);
|
|
}
|
|
|
|
RtlFreeHeap(RtlProcessHeap(), 0, volumeName);
|
|
|
|
if (!resultOfOpen && !p) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, fullPath);
|
|
return FALSE;
|
|
}
|
|
|
|
if (cchBufferLength*sizeof(WCHAR) < name.Length + sizeof(WCHAR)) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, fullPath);
|
|
SetLastError(ERROR_FILENAME_EXCED_RANGE);
|
|
return FALSE;
|
|
}
|
|
|
|
RtlCopyMemory(lpszVolumePathName, name.Buffer, name.Length);
|
|
lpszVolumePathName[name.Length/sizeof(WCHAR)] = 0;
|
|
RtlFreeHeap(RtlProcessHeap(), 0, fullPath);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
GetVolumePathNamesForVolumeNameA(
|
|
LPCSTR lpszVolumeName,
|
|
LPSTR lpszVolumePathNames,
|
|
DWORD cchBufferLength,
|
|
PDWORD lpcchReturnLength
|
|
)
|
|
|
|
{
|
|
PUNICODE_STRING unicodeVolumeName;
|
|
ANSI_STRING ansiVolumePathNames;
|
|
UNICODE_STRING unicodeVolumePathNames;
|
|
BOOL b;
|
|
NTSTATUS status;
|
|
DWORD len;
|
|
|
|
unicodeVolumeName = Basep8BitStringToStaticUnicodeString(lpszVolumeName);
|
|
if (!unicodeVolumeName) {
|
|
return FALSE;
|
|
}
|
|
|
|
ansiVolumePathNames.Buffer = lpszVolumePathNames;
|
|
ansiVolumePathNames.MaximumLength = (USHORT) cchBufferLength;
|
|
unicodeVolumePathNames.Buffer = NULL;
|
|
unicodeVolumePathNames.MaximumLength = 0;
|
|
|
|
try {
|
|
|
|
unicodeVolumePathNames.MaximumLength =
|
|
ansiVolumePathNames.MaximumLength*sizeof(WCHAR);
|
|
if (unicodeVolumePathNames.MaximumLength) {
|
|
unicodeVolumePathNames.Buffer =
|
|
RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
|
|
unicodeVolumePathNames.MaximumLength);
|
|
if (!unicodeVolumePathNames.Buffer) {
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
} else {
|
|
unicodeVolumePathNames.Buffer = NULL;
|
|
}
|
|
|
|
b = GetVolumePathNamesForVolumeNameW(unicodeVolumeName->Buffer,
|
|
unicodeVolumePathNames.Buffer,
|
|
cchBufferLength, &len);
|
|
|
|
if (b || GetLastError() == ERROR_MORE_DATA) {
|
|
|
|
if (b) {
|
|
unicodeVolumePathNames.Length = (USHORT) len*sizeof(WCHAR);
|
|
} else {
|
|
unicodeVolumePathNames.Length = (USHORT)
|
|
cchBufferLength*sizeof(WCHAR);
|
|
}
|
|
|
|
status = BasepUnicodeStringTo8BitString(&ansiVolumePathNames,
|
|
&unicodeVolumePathNames,
|
|
FALSE);
|
|
if (!NT_SUCCESS(status)) {
|
|
BaseSetLastNTError(status);
|
|
return FALSE;
|
|
}
|
|
|
|
if (lpcchReturnLength) {
|
|
if (b) {
|
|
*lpcchReturnLength = ansiVolumePathNames.Length/sizeof(WCHAR);
|
|
} else {
|
|
// Give an upper bound for the ANSI length since we
|
|
// don't actually know it.
|
|
*lpcchReturnLength = 2*len;
|
|
}
|
|
}
|
|
}
|
|
|
|
} finally {
|
|
|
|
if (unicodeVolumePathNames.Buffer) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, unicodeVolumePathNames.Buffer);
|
|
}
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
BOOL
|
|
GetVolumePathNamesForVolumeNameW(
|
|
LPCWSTR lpszVolumeName,
|
|
LPWSTR lpszVolumePathNames,
|
|
DWORD cchBufferLength,
|
|
PDWORD lpcchReturnLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns a Multi-Sz list of volume path names for the
|
|
given volume name. The returned 'lpcchReturnLength' will include the
|
|
extra tailing null characteristic of a Multi-Sz unless ERROR_MORE_DATA
|
|
is returned in which case the list returned is as long as possible
|
|
and may contain a part of a volume path.
|
|
|
|
Arguments:
|
|
|
|
lpszVolumeName - Supplies the volume name.
|
|
|
|
lpszVolumePathNames - Returns the volume path names.
|
|
|
|
cchBufferLength - Supplies the size of the return buffer.
|
|
|
|
lpcchReturnLength - Returns the number of characters copied back to the
|
|
return buffer on success or the total number
|
|
of characters necessary for the buffer on
|
|
ERROR_MORE_DATA.
|
|
|
|
Return Value:
|
|
|
|
FALSE - Failure.
|
|
|
|
TRUE - Success.
|
|
|
|
--*/
|
|
|
|
{
|
|
UNICODE_STRING unicodeVolumeName;
|
|
PMOUNTMGR_TARGET_NAME targetName;
|
|
HANDLE h;
|
|
BOOL b;
|
|
DWORD bytes, len, i, j, n;
|
|
PMOUNTMGR_VOLUME_PATHS volumePaths;
|
|
|
|
RtlInitUnicodeString(&unicodeVolumeName, lpszVolumeName);
|
|
if (unicodeVolumeName.Buffer[unicodeVolumeName.Length/sizeof(WCHAR) - 1] !=
|
|
'\\') {
|
|
|
|
BaseSetLastNTError(STATUS_OBJECT_NAME_INVALID);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!MOUNTMGR_IS_DOS_VOLUME_NAME_WB(&unicodeVolumeName)) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
targetName = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
|
|
MAX_PATH*sizeof(WCHAR));
|
|
if (!targetName) {
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
|
|
ZeroMemory(targetName, MAX_PATH*sizeof(WCHAR));
|
|
targetName->DeviceNameLength = unicodeVolumeName.Length - sizeof(WCHAR);
|
|
RtlCopyMemory(targetName->DeviceName, lpszVolumeName,
|
|
targetName->DeviceNameLength);
|
|
targetName->DeviceName[1] = '?';
|
|
|
|
h = CreateFileW(MOUNTMGR_DOS_DEVICE_NAME, 0, FILE_SHARE_READ |
|
|
FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE);
|
|
if (h == INVALID_HANDLE_VALUE) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, targetName);
|
|
return FALSE;
|
|
}
|
|
|
|
len = sizeof(MOUNTMGR_VOLUME_PATHS);
|
|
volumePaths = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG), len);
|
|
if (!volumePaths) {
|
|
CloseHandle(h);
|
|
RtlFreeHeap(RtlProcessHeap(), 0, targetName);
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
|
|
for (;;) {
|
|
|
|
b = DeviceIoControl(h, IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATHS,
|
|
targetName, MAX_PATH*sizeof(WCHAR), volumePaths,
|
|
len, &bytes, NULL);
|
|
if (b) {
|
|
break;
|
|
}
|
|
|
|
if (GetLastError() != ERROR_MORE_DATA) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, volumePaths);
|
|
RtlFreeHeap(RtlProcessHeap(), 0, targetName);
|
|
return FALSE;
|
|
}
|
|
|
|
len = sizeof(MOUNTMGR_VOLUME_PATHS) + volumePaths->MultiSzLength;
|
|
RtlFreeHeap(RtlProcessHeap(), 0, volumePaths);
|
|
volumePaths = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
|
|
len);
|
|
if (!volumePaths) {
|
|
CloseHandle(h);
|
|
RtlFreeHeap(RtlProcessHeap(), 0, targetName);
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
CloseHandle(h);
|
|
RtlFreeHeap(RtlProcessHeap(), 0, targetName);
|
|
|
|
n = 0;
|
|
for (i = 0, j = 0; i < cchBufferLength &&
|
|
j < volumePaths->MultiSzLength/sizeof(WCHAR) - 1; i++, j++) {
|
|
|
|
if (!volumePaths->MultiSz[j]) {
|
|
n++;
|
|
lpszVolumePathNames[i++] = '\\';
|
|
if (i == cchBufferLength) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
lpszVolumePathNames[i] = volumePaths->MultiSz[j];
|
|
}
|
|
|
|
for (; j < volumePaths->MultiSzLength/sizeof(WCHAR) - 1; j++) {
|
|
if (!volumePaths->MultiSz[j]) {
|
|
n++;
|
|
}
|
|
}
|
|
|
|
if (i < cchBufferLength) {
|
|
b = TRUE;
|
|
lpszVolumePathNames[i++] = 0;
|
|
if (lpcchReturnLength) {
|
|
*lpcchReturnLength = i;
|
|
}
|
|
} else {
|
|
b = FALSE;
|
|
SetLastError(ERROR_MORE_DATA);
|
|
if (lpcchReturnLength) {
|
|
*lpcchReturnLength = volumePaths->MultiSzLength/sizeof(WCHAR) + n;
|
|
}
|
|
}
|
|
|
|
RtlFreeHeap(RtlProcessHeap(), 0, volumePaths);
|
|
|
|
return b;
|
|
}
|