878 lines
28 KiB
C
878 lines
28 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1992 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
dosdev.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
This file contains the implementation of the DefineDosDevice API
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Steve Wood (stevewo) 13-Dec-1992
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "basedll.h"
|
||
|
|
||
|
#define USHORT_MAX ((USHORT)(-1))
|
||
|
#define DWORD_MAX ((DWORD)(-1))
|
||
|
#define CH_COUNT_MAX ( DWORD_MAX / sizeof( WCHAR ) )
|
||
|
|
||
|
BOOL
|
||
|
WINAPI
|
||
|
DefineDosDeviceA(
|
||
|
DWORD dwFlags,
|
||
|
LPCSTR lpDeviceName,
|
||
|
LPCSTR lpTargetPath
|
||
|
)
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
BOOL Result;
|
||
|
ANSI_STRING AnsiString;
|
||
|
PUNICODE_STRING DeviceName;
|
||
|
UNICODE_STRING TargetPath;
|
||
|
PCWSTR lpDeviceNameW;
|
||
|
PCWSTR lpTargetPathW;
|
||
|
|
||
|
RtlInitAnsiString( &AnsiString, lpDeviceName );
|
||
|
DeviceName = &NtCurrentTeb()->StaticUnicodeString;
|
||
|
Status = RtlAnsiStringToUnicodeString( DeviceName, &AnsiString, FALSE );
|
||
|
if (!NT_SUCCESS( Status )) {
|
||
|
if ( Status == STATUS_BUFFER_OVERFLOW ) {
|
||
|
SetLastError( ERROR_FILENAME_EXCED_RANGE );
|
||
|
}
|
||
|
else {
|
||
|
BaseSetLastNTError( Status );
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
else {
|
||
|
lpDeviceNameW = DeviceName->Buffer;
|
||
|
}
|
||
|
|
||
|
if (ARGUMENT_PRESENT( lpTargetPath )) {
|
||
|
RtlInitAnsiString( &AnsiString, lpTargetPath );
|
||
|
Status = RtlAnsiStringToUnicodeString( &TargetPath, &AnsiString, TRUE );
|
||
|
if (!NT_SUCCESS( Status )) {
|
||
|
BaseSetLastNTError( Status );
|
||
|
return FALSE;
|
||
|
}
|
||
|
else {
|
||
|
lpTargetPathW = TargetPath.Buffer;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
lpTargetPathW = NULL;
|
||
|
}
|
||
|
|
||
|
Result = DefineDosDeviceW( dwFlags,
|
||
|
lpDeviceNameW,
|
||
|
lpTargetPathW
|
||
|
);
|
||
|
|
||
|
if (lpTargetPathW != NULL) {
|
||
|
RtlFreeUnicodeString( &TargetPath );
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
|
||
|
typedef
|
||
|
long
|
||
|
(WINAPI *PBROADCASTSYSTEMMESSAGEW)( DWORD, LPDWORD, UINT, WPARAM, LPARAM );
|
||
|
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
WINAPI
|
||
|
DefineDosDeviceW(
|
||
|
DWORD dwFlags,
|
||
|
PCWSTR lpDeviceName,
|
||
|
PCWSTR lpTargetPath
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This function provides the capability to define new DOS device names or
|
||
|
redefine or delete existing DOS device names. DOS Device names are stored
|
||
|
as symbolic links in the NT object name space. The code that converts
|
||
|
a DOS path into a corresponding NT path uses these symbolic links to
|
||
|
handle mapping of DOS devices and drive letters. This API provides a
|
||
|
mechanism for a Win32 Application to modify the symbolic links used
|
||
|
to implement the DOS Device namespace. Use the QueryDosDevice API
|
||
|
to query the current mapping for a DOS device name.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
dwFlags - Supplies additional flags that control the creation
|
||
|
of the DOS device.
|
||
|
|
||
|
dwFlags Flags:
|
||
|
|
||
|
DDD_PUSH_POP_DEFINITION - If lpTargetPath is not NULL, then push
|
||
|
the new target path in front of any existing target path.
|
||
|
If lpTargetPath is NULL, then delete the existing target path
|
||
|
and pop the most recent one pushed. If nothing left to pop
|
||
|
then the device name will be deleted.
|
||
|
|
||
|
DDD_RAW_TARGET_PATH - Do not convert the lpTargetPath string from
|
||
|
a DOS path to an NT path, but take it as is.
|
||
|
|
||
|
lpDeviceName - Points to the DOS device name being defined, redefined or deleted.
|
||
|
It must NOT have a trailing colon unless it is a drive letter being defined,
|
||
|
redefined or deleted.
|
||
|
|
||
|
lpTargetPath - Points to the DOS path that will implement this device. If the
|
||
|
ADD_RAW_TARGET_PATH flag is specified, then this parameter points to an
|
||
|
NT path string. If this parameter is NULL, then the device name is being
|
||
|
deleted or restored if the ADD_PUSH_POP_DEFINITION flag is specified.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
TRUE - The operation was successful
|
||
|
|
||
|
FALSE/NULL - The operation failed. Extended error status is available
|
||
|
using GetLastError.
|
||
|
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
#if !defined(BUILD_WOW6432)
|
||
|
BASE_API_MSG m;
|
||
|
PBASE_DEFINEDOSDEVICE_MSG a = (PBASE_DEFINEDOSDEVICE_MSG)&m.u.DefineDosDeviceApi;
|
||
|
PCSR_CAPTURE_HEADER p;
|
||
|
ULONG PointerCount, n;
|
||
|
#endif
|
||
|
UNICODE_STRING DeviceName;
|
||
|
UNICODE_STRING TargetPath;
|
||
|
DWORD iDrive;
|
||
|
DEV_BROADCAST_VOLUME dbv;
|
||
|
DWORD dwRec = BSM_APPLICATIONS;
|
||
|
BOOLEAN LuidDevMapsEnabled = BaseStaticServerData->LUIDDeviceMapsEnabled;
|
||
|
|
||
|
#if defined(BUILD_WOW6432)
|
||
|
NTSTATUS Status;
|
||
|
#endif
|
||
|
|
||
|
if (dwFlags & ~(DDD_RAW_TARGET_PATH |
|
||
|
DDD_REMOVE_DEFINITION |
|
||
|
DDD_EXACT_MATCH_ON_REMOVE |
|
||
|
DDD_NO_BROADCAST_SYSTEM |
|
||
|
DDD_LUID_BROADCAST_DRIVE
|
||
|
) ||
|
||
|
((dwFlags & DDD_EXACT_MATCH_ON_REMOVE) &&
|
||
|
(!(dwFlags & DDD_REMOVE_DEFINITION))
|
||
|
) ||
|
||
|
((!ARGUMENT_PRESENT( lpTargetPath )) &&
|
||
|
(!(dwFlags & (DDD_REMOVE_DEFINITION | DDD_LUID_BROADCAST_DRIVE)))
|
||
|
) ||
|
||
|
((dwFlags & DDD_LUID_BROADCAST_DRIVE) &&
|
||
|
((!ARGUMENT_PRESENT( lpDeviceName )) ||
|
||
|
ARGUMENT_PRESENT( lpTargetPath ) ||
|
||
|
(dwFlags & (DDD_RAW_TARGET_PATH | DDD_EXACT_MATCH_ON_REMOVE | DDD_NO_BROADCAST_SYSTEM)) ||
|
||
|
(LuidDevMapsEnabled == FALSE)
|
||
|
)
|
||
|
)
|
||
|
) {
|
||
|
SetLastError( ERROR_INVALID_PARAMETER );
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
RtlInitUnicodeString( &DeviceName, lpDeviceName );
|
||
|
#if !defined(BUILD_WOW6432)
|
||
|
PointerCount = 1;
|
||
|
n = DeviceName.MaximumLength;
|
||
|
#endif
|
||
|
if (ARGUMENT_PRESENT( lpTargetPath )) {
|
||
|
if (!(dwFlags & DDD_RAW_TARGET_PATH)) {
|
||
|
if (!RtlDosPathNameToNtPathName_U( lpTargetPath,
|
||
|
&TargetPath,
|
||
|
NULL,
|
||
|
NULL
|
||
|
)
|
||
|
) {
|
||
|
BaseSetLastNTError( STATUS_OBJECT_NAME_INVALID );
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
RtlInitUnicodeString( &TargetPath, lpTargetPath );
|
||
|
}
|
||
|
#if !defined(BUILD_WOW6432)
|
||
|
PointerCount += 1;
|
||
|
n += TargetPath.MaximumLength;
|
||
|
#endif
|
||
|
}
|
||
|
else {
|
||
|
RtlInitUnicodeString( &TargetPath, NULL );
|
||
|
}
|
||
|
|
||
|
#if defined(BUILD_WOW6432)
|
||
|
Status = CsrBasepDefineDosDevice(dwFlags, &DeviceName, &TargetPath);
|
||
|
|
||
|
if (TargetPath.Length != 0 && !(dwFlags & DDD_RAW_TARGET_PATH)) {
|
||
|
RtlFreeUnicodeString( &TargetPath );
|
||
|
}
|
||
|
#else
|
||
|
p = CsrAllocateCaptureBuffer( PointerCount, n );
|
||
|
if (p == NULL) {
|
||
|
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
a->Flags = dwFlags;
|
||
|
a->DeviceName.MaximumLength =
|
||
|
(USHORT)CsrAllocateMessagePointer( p,
|
||
|
DeviceName.MaximumLength,
|
||
|
(PVOID *)&a->DeviceName.Buffer
|
||
|
);
|
||
|
RtlUpcaseUnicodeString( &a->DeviceName, &DeviceName, FALSE );
|
||
|
if (TargetPath.Length != 0) {
|
||
|
a->TargetPath.MaximumLength =
|
||
|
(USHORT)CsrAllocateMessagePointer( p,
|
||
|
TargetPath.MaximumLength,
|
||
|
(PVOID *)&a->TargetPath.Buffer
|
||
|
);
|
||
|
RtlCopyUnicodeString( &a->TargetPath, &TargetPath );
|
||
|
if (!(dwFlags & DDD_RAW_TARGET_PATH)) {
|
||
|
RtlFreeUnicodeString( &TargetPath );
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
RtlInitUnicodeString( &a->TargetPath, NULL );
|
||
|
}
|
||
|
|
||
|
CsrClientCallServer( (PCSR_API_MSG)&m,
|
||
|
p,
|
||
|
CSR_MAKE_API_NUMBER( BASESRV_SERVERDLL_INDEX,
|
||
|
BasepDefineDosDevice
|
||
|
),
|
||
|
sizeof( *a )
|
||
|
);
|
||
|
CsrFreeCaptureBuffer( p );
|
||
|
#endif
|
||
|
|
||
|
#if defined(BUILD_WOW6432)
|
||
|
if (NT_SUCCESS( Status )) {
|
||
|
#else
|
||
|
if (NT_SUCCESS( (NTSTATUS)m.ReturnValue )) {
|
||
|
#endif
|
||
|
HMODULE hUser32Dll;
|
||
|
PBROADCASTSYSTEMMESSAGEW pBroadCastSystemMessageW;
|
||
|
|
||
|
|
||
|
if (!(dwFlags & DDD_NO_BROADCAST_SYSTEM) &&
|
||
|
DeviceName.Length == (2 * sizeof( WCHAR )) &&
|
||
|
DeviceName.Buffer[ 1 ] == L':' &&
|
||
|
(iDrive = RtlUpcaseUnicodeChar( DeviceName.Buffer[ 0 ] ) - L'A') < 26 &&
|
||
|
LuidDevMapsEnabled == FALSE
|
||
|
) {
|
||
|
dbv.dbcv_size = sizeof( dbv );
|
||
|
dbv.dbcv_devicetype = DBT_DEVTYP_VOLUME;
|
||
|
dbv.dbcv_reserved = 0;
|
||
|
dbv.dbcv_unitmask = (1 << iDrive);
|
||
|
dbv.dbcv_flags = DBTF_NET;
|
||
|
|
||
|
hUser32Dll = LoadLibraryW( L"USER32.DLL" );
|
||
|
|
||
|
if (hUser32Dll != NULL) {
|
||
|
pBroadCastSystemMessageW = (PBROADCASTSYSTEMMESSAGEW)
|
||
|
GetProcAddress( hUser32Dll, "BroadcastSystemMessageW" );
|
||
|
|
||
|
// broadcast to all windows!
|
||
|
if (pBroadCastSystemMessageW != NULL) {
|
||
|
(*pBroadCastSystemMessageW)( BSF_FORCEIFHUNG |
|
||
|
BSF_NOHANG |
|
||
|
BSF_NOTIMEOUTIFNOTHUNG,
|
||
|
&dwRec,
|
||
|
WM_DEVICECHANGE,
|
||
|
(WPARAM)((dwFlags & DDD_REMOVE_DEFINITION) ?
|
||
|
DBT_DEVICEREMOVECOMPLETE :
|
||
|
DBT_DEVICEARRIVAL
|
||
|
),
|
||
|
(LPARAM)(DEV_BROADCAST_HDR *)&dbv
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
FreeLibrary (hUser32Dll);
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
else {
|
||
|
#if defined(BUILD_WOW6432)
|
||
|
BaseSetLastNTError( Status );
|
||
|
#else
|
||
|
BaseSetLastNTError( (NTSTATUS)m.ReturnValue );
|
||
|
#endif
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
IsGlobalDeviceMap(
|
||
|
IN HANDLE hDirObject,
|
||
|
OUT PBOOLEAN pbGlobalDeviceMap
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Determine whether a directory object is the global device map
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
hDirObject - Supplies a handle to the directory object.
|
||
|
|
||
|
pbGlobalDeviceMap - Points to a variable that will receive the result of
|
||
|
"Is this directory object the global device map?"
|
||
|
TRUE - directory object is the global device map
|
||
|
FALSE - directory object is not the global device map
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
STATUS_SUCCESS - operations successful, did not encounter any errors,
|
||
|
the result in pbGlobalDeviceMap is only valid for this
|
||
|
status code
|
||
|
|
||
|
STATUS_INVALID_PARAMETER - pbGlobalDeviceMap or hDirObject is NULL
|
||
|
|
||
|
STATUS_NO_MEMORY - could not allocate memory to read the directory object's
|
||
|
name
|
||
|
|
||
|
STATUS_INFO_LENGTH_MISMATCH - did not allocate enough memory for the
|
||
|
directory object's name
|
||
|
|
||
|
STATUS_UNSUCCESSFUL - an unexpected error encountered
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
UNICODE_STRING ObjectName;
|
||
|
UNICODE_STRING GlobalDeviceMapName;
|
||
|
PWSTR NameBuffer = NULL;
|
||
|
ULONG ReturnedLength;
|
||
|
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
||
|
|
||
|
if( ( pbGlobalDeviceMap == NULL ) || ( hDirObject == NULL ) ) {
|
||
|
return( STATUS_INVALID_PARAMETER );
|
||
|
}
|
||
|
|
||
|
try {
|
||
|
ObjectName.Length = 0;
|
||
|
ObjectName.MaximumLength = 0;
|
||
|
ObjectName.Buffer = NULL;
|
||
|
ReturnedLength = 0;
|
||
|
|
||
|
//
|
||
|
// Determine the length of the directory object's name
|
||
|
//
|
||
|
Status = NtQueryObject( hDirObject,
|
||
|
ObjectNameInformation,
|
||
|
(PVOID) &ObjectName,
|
||
|
0,
|
||
|
&ReturnedLength
|
||
|
);
|
||
|
|
||
|
if( !NT_SUCCESS( Status ) && (Status != STATUS_INFO_LENGTH_MISMATCH) ) {
|
||
|
leave;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// allocate memory for the directory object's name
|
||
|
//
|
||
|
NameBuffer = RtlAllocateHeap( RtlProcessHeap(),
|
||
|
MAKE_TAG( TMP_TAG ),
|
||
|
ReturnedLength
|
||
|
);
|
||
|
|
||
|
if( NameBuffer == NULL ) {
|
||
|
Status = STATUS_NO_MEMORY;
|
||
|
leave;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// get the full name of the directory object
|
||
|
//
|
||
|
Status = NtQueryObject( hDirObject,
|
||
|
ObjectNameInformation,
|
||
|
NameBuffer,
|
||
|
ReturnedLength,
|
||
|
&ReturnedLength
|
||
|
);
|
||
|
|
||
|
if( !NT_SUCCESS( Status )) {
|
||
|
leave;
|
||
|
}
|
||
|
|
||
|
RtlInitUnicodeString ( &GlobalDeviceMapName, L"\\GLOBAL??" );
|
||
|
|
||
|
//
|
||
|
// Check if the directory object is the global device map
|
||
|
//
|
||
|
*pbGlobalDeviceMap = RtlEqualUnicodeString( &GlobalDeviceMapName,
|
||
|
(PUNICODE_STRING)NameBuffer,
|
||
|
FALSE);
|
||
|
|
||
|
Status = STATUS_SUCCESS;
|
||
|
}
|
||
|
finally {
|
||
|
if( NameBuffer != NULL ) {
|
||
|
RtlFreeHeap( RtlProcessHeap(), 0, NameBuffer );
|
||
|
NameBuffer = NULL;
|
||
|
}
|
||
|
}
|
||
|
return ( Status );
|
||
|
}
|
||
|
|
||
|
DWORD
|
||
|
FindSymbolicLinkEntry(
|
||
|
IN PWSTR lpKey,
|
||
|
IN PWSTR lpBuffer,
|
||
|
IN ULONG nElements,
|
||
|
OUT PBOOLEAN pbResult
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Determine whether a symbolic link's name exists in a buffer of symbolic
|
||
|
link names.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
lpKey - Points to the symbolic link's name to search for
|
||
|
|
||
|
lpBuffer - contains symbolic link names, where names are separated by a
|
||
|
UNICODE_NULL
|
||
|
|
||
|
nElements - the number of name elements to search
|
||
|
|
||
|
pbResult - Points to a variable that will receive the result of
|
||
|
"Does symbolic link name exist in the buffer?"
|
||
|
TRUE - symbolic link name found in the buffer
|
||
|
FALSE - symbolic link name not found in the buffer
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NO_ERROR - operations successful, did not encounter any errors,
|
||
|
the result in pbResult is only valid for this status code
|
||
|
|
||
|
ERROR_INVALID_PARAMETER - lpKey, lpBuffer, or pbResult is a NULL pointer
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
ULONG i = 0;
|
||
|
|
||
|
//
|
||
|
// Check for invalid parameters
|
||
|
//
|
||
|
if( (lpKey == NULL) || (lpBuffer == NULL) || (pbResult == NULL) ) {
|
||
|
return( ERROR_INVALID_PARAMETER );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Assume the symbolic link's name is not in the buffer
|
||
|
//
|
||
|
*pbResult = FALSE;
|
||
|
|
||
|
//
|
||
|
// Search for the number of names specified
|
||
|
//
|
||
|
while( i < nElements ) {
|
||
|
if( !wcscmp( lpKey, lpBuffer ) ) {
|
||
|
//
|
||
|
// Found the name, can stop searching & pass back the result
|
||
|
//
|
||
|
*pbResult = TRUE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
i++;
|
||
|
|
||
|
//
|
||
|
// Get the next name
|
||
|
//
|
||
|
while (*lpBuffer++);
|
||
|
}
|
||
|
return( NO_ERROR );
|
||
|
}
|
||
|
|
||
|
DWORD
|
||
|
WINAPI
|
||
|
QueryDosDeviceA(
|
||
|
LPCSTR lpDeviceName,
|
||
|
LPSTR lpTargetPath,
|
||
|
DWORD ucchMax
|
||
|
)
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
DWORD Result;
|
||
|
ANSI_STRING AnsiString;
|
||
|
PUNICODE_STRING DeviceName;
|
||
|
UNICODE_STRING TargetPath;
|
||
|
PCWSTR lpDeviceNameW;
|
||
|
PWSTR lpTargetPathW;
|
||
|
|
||
|
if (ARGUMENT_PRESENT( lpDeviceName )) {
|
||
|
RtlInitAnsiString( &AnsiString, lpDeviceName );
|
||
|
DeviceName = &NtCurrentTeb()->StaticUnicodeString;
|
||
|
Status = RtlAnsiStringToUnicodeString( DeviceName, &AnsiString, FALSE );
|
||
|
if (!NT_SUCCESS( Status )) {
|
||
|
if ( Status == STATUS_BUFFER_OVERFLOW ) {
|
||
|
SetLastError( ERROR_FILENAME_EXCED_RANGE );
|
||
|
}
|
||
|
else {
|
||
|
BaseSetLastNTError( Status );
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
else {
|
||
|
lpDeviceNameW = DeviceName->Buffer;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
lpDeviceNameW = NULL;
|
||
|
}
|
||
|
|
||
|
lpTargetPathW = RtlAllocateHeap( RtlProcessHeap(),
|
||
|
MAKE_TAG( TMP_TAG ),
|
||
|
ucchMax * sizeof( WCHAR )
|
||
|
);
|
||
|
if (lpTargetPathW == NULL) {
|
||
|
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
Result = QueryDosDeviceW( lpDeviceNameW,
|
||
|
lpTargetPathW,
|
||
|
ucchMax
|
||
|
);
|
||
|
|
||
|
if (Result != 0) {
|
||
|
TargetPath.Buffer = lpTargetPathW;
|
||
|
TargetPath.Length = (USHORT)(Result * sizeof( WCHAR ));
|
||
|
TargetPath.MaximumLength = (USHORT)(TargetPath.Length + 1);
|
||
|
|
||
|
AnsiString.Buffer = lpTargetPath;
|
||
|
AnsiString.Length = 0;
|
||
|
AnsiString.MaximumLength = (USHORT)ucchMax;
|
||
|
|
||
|
Status = RtlUnicodeStringToAnsiString( &AnsiString,
|
||
|
&TargetPath,
|
||
|
FALSE
|
||
|
);
|
||
|
if (!NT_SUCCESS( Status )) {
|
||
|
BaseSetLastNTError( Status );
|
||
|
Result = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
RtlFreeHeap( RtlProcessHeap(), 0, lpTargetPathW );
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
|
||
|
DWORD
|
||
|
WINAPI
|
||
|
QueryDosDeviceW(
|
||
|
PCWSTR lpDeviceName,
|
||
|
PWSTR lpTargetPath,
|
||
|
DWORD ucchMax
|
||
|
)
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
UNICODE_STRING UnicodeString;
|
||
|
OBJECT_ATTRIBUTES Attributes;
|
||
|
HANDLE DirectoryHandle = NULL;
|
||
|
HANDLE LinkHandle;
|
||
|
POBJECT_DIRECTORY_INFORMATION DirInfo;
|
||
|
BOOLEAN RestartScan;
|
||
|
UCHAR DirInfoBuffer[ 512 ];
|
||
|
CLONG Count = 0;
|
||
|
ULONG Context = 0;
|
||
|
ULONG ReturnedLength;
|
||
|
DWORD ucchName, ucchReturned;
|
||
|
BOOLEAN ScanGlobalDeviceMap = FALSE;
|
||
|
ULONG nElements = 0;
|
||
|
BOOLEAN DuplicateEntry;
|
||
|
PWSTR lpBuffer = lpTargetPath;
|
||
|
DWORD Result, BufferSize;
|
||
|
|
||
|
RtlInitUnicodeString( &UnicodeString, L"\\??" );
|
||
|
|
||
|
InitializeObjectAttributes( &Attributes,
|
||
|
&UnicodeString,
|
||
|
OBJ_CASE_INSENSITIVE,
|
||
|
NULL,
|
||
|
NULL
|
||
|
);
|
||
|
Status = NtOpenDirectoryObject( &DirectoryHandle,
|
||
|
DIRECTORY_QUERY,
|
||
|
&Attributes
|
||
|
);
|
||
|
|
||
|
if (!NT_SUCCESS( Status )) {
|
||
|
BaseSetLastNTError( Status );
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
ucchReturned = 0;
|
||
|
try {
|
||
|
if (ARGUMENT_PRESENT( lpDeviceName )) {
|
||
|
RtlInitUnicodeString( &UnicodeString, lpDeviceName );
|
||
|
InitializeObjectAttributes( &Attributes,
|
||
|
&UnicodeString,
|
||
|
OBJ_CASE_INSENSITIVE,
|
||
|
DirectoryHandle,
|
||
|
NULL
|
||
|
);
|
||
|
Status = NtOpenSymbolicLinkObject( &LinkHandle,
|
||
|
SYMBOLIC_LINK_QUERY,
|
||
|
&Attributes
|
||
|
);
|
||
|
if (NT_SUCCESS( Status )) {
|
||
|
UnicodeString.Buffer = lpTargetPath;
|
||
|
UnicodeString.Length = 0;
|
||
|
|
||
|
//
|
||
|
// Check for possible overflow of a DWORD
|
||
|
//
|
||
|
if (ucchMax > CH_COUNT_MAX) {
|
||
|
BufferSize = DWORD_MAX;
|
||
|
} else {
|
||
|
BufferSize = ucchMax * sizeof( WCHAR );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Check for possible overflow of a USHORT
|
||
|
//
|
||
|
if (BufferSize > (DWORD)(USHORT_MAX)) {
|
||
|
UnicodeString.MaximumLength = USHORT_MAX;
|
||
|
} else {
|
||
|
UnicodeString.MaximumLength = (USHORT)(BufferSize);
|
||
|
}
|
||
|
|
||
|
ReturnedLength = 0;
|
||
|
Status = NtQuerySymbolicLinkObject( LinkHandle,
|
||
|
&UnicodeString,
|
||
|
&ReturnedLength
|
||
|
);
|
||
|
NtClose( LinkHandle );
|
||
|
if (NT_SUCCESS( Status )) {
|
||
|
ucchReturned = ReturnedLength / sizeof( WCHAR );
|
||
|
|
||
|
if ( ( (ucchReturned == 0) ||
|
||
|
( (ucchReturned > 0) &&
|
||
|
(lpTargetPath[ ucchReturned - 1 ] != UNICODE_NULL)
|
||
|
)
|
||
|
) &&
|
||
|
(ucchReturned < ucchMax)
|
||
|
) {
|
||
|
|
||
|
lpTargetPath[ ucchReturned ] = UNICODE_NULL;
|
||
|
ucchReturned++;
|
||
|
}
|
||
|
|
||
|
if (ucchReturned < ucchMax) {
|
||
|
lpTargetPath[ ucchReturned++ ] = UNICODE_NULL;
|
||
|
} else {
|
||
|
ucchReturned = 0;
|
||
|
Status = STATUS_BUFFER_TOO_SMALL;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
//
|
||
|
// Dump all the symbolic links in the device map's directory
|
||
|
// With LUID device maps enabled, we must search two directories
|
||
|
// because the LUID device map is transparent on top of the
|
||
|
// global device map
|
||
|
//
|
||
|
|
||
|
if (BaseStaticServerData->LUIDDeviceMapsEnabled == TRUE) {
|
||
|
BOOLEAN GlobalDeviceMap = TRUE;
|
||
|
|
||
|
//
|
||
|
// Determine if directory is the global directory
|
||
|
//
|
||
|
Status = IsGlobalDeviceMap( DirectoryHandle,
|
||
|
&GlobalDeviceMap );
|
||
|
|
||
|
//
|
||
|
// if !global, set second directory search flag
|
||
|
//
|
||
|
if( (NT_SUCCESS( Status )) &&
|
||
|
(GlobalDeviceMap == FALSE) ) {
|
||
|
ScanGlobalDeviceMap = TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
nElements = 0;
|
||
|
RestartScan = TRUE;
|
||
|
DirInfo = (POBJECT_DIRECTORY_INFORMATION)&DirInfoBuffer;
|
||
|
while (TRUE) {
|
||
|
Status = NtQueryDirectoryObject( DirectoryHandle,
|
||
|
(PVOID)DirInfo,
|
||
|
sizeof( DirInfoBuffer ),
|
||
|
TRUE,
|
||
|
RestartScan,
|
||
|
&Context,
|
||
|
&ReturnedLength
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// Check the status of the operation.
|
||
|
//
|
||
|
|
||
|
if (!NT_SUCCESS( Status )) {
|
||
|
if (Status == STATUS_NO_MORE_ENTRIES) {
|
||
|
Status = STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (!wcscmp( DirInfo->TypeName.Buffer, L"SymbolicLink" )) {
|
||
|
ucchName = DirInfo->Name.Length / sizeof( WCHAR );
|
||
|
if ((ucchReturned + ucchName + 1 + 1) > ucchMax) {
|
||
|
ucchReturned = 0;
|
||
|
Status = STATUS_BUFFER_TOO_SMALL;
|
||
|
break;
|
||
|
}
|
||
|
RtlMoveMemory( lpTargetPath,
|
||
|
DirInfo->Name.Buffer,
|
||
|
DirInfo->Name.Length
|
||
|
);
|
||
|
lpTargetPath += ucchName;
|
||
|
*lpTargetPath++ = UNICODE_NULL;
|
||
|
ucchReturned += ucchName + 1;
|
||
|
nElements++;
|
||
|
}
|
||
|
|
||
|
RestartScan = FALSE;
|
||
|
}
|
||
|
|
||
|
if ( (BaseStaticServerData->LUIDDeviceMapsEnabled == TRUE) &&
|
||
|
(NT_SUCCESS( Status )) &&
|
||
|
ScanGlobalDeviceMap == TRUE) {
|
||
|
//
|
||
|
// need to perform a second scan for the
|
||
|
// global device map because the first scan only
|
||
|
// searches the LUID device map
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// close DirectoryHandle, set to NULL
|
||
|
//
|
||
|
if( DirectoryHandle != NULL ) {
|
||
|
NtClose( DirectoryHandle );
|
||
|
DirectoryHandle = NULL;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// open the global device map
|
||
|
//
|
||
|
RtlInitUnicodeString( &UnicodeString, L"\\GLOBAL??" );
|
||
|
|
||
|
InitializeObjectAttributes( &Attributes,
|
||
|
&UnicodeString,
|
||
|
OBJ_CASE_INSENSITIVE,
|
||
|
NULL,
|
||
|
NULL
|
||
|
);
|
||
|
Status = NtOpenDirectoryObject( &DirectoryHandle,
|
||
|
DIRECTORY_QUERY,
|
||
|
&Attributes
|
||
|
);
|
||
|
|
||
|
if (!NT_SUCCESS( Status )) {
|
||
|
DirectoryHandle = NULL;
|
||
|
leave;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// perform the second scan
|
||
|
// scan the global device map
|
||
|
//
|
||
|
RestartScan = TRUE;
|
||
|
while (TRUE) {
|
||
|
Status = NtQueryDirectoryObject( DirectoryHandle,
|
||
|
(PVOID)DirInfo,
|
||
|
sizeof( DirInfoBuffer ),
|
||
|
TRUE,
|
||
|
RestartScan,
|
||
|
&Context,
|
||
|
&ReturnedLength
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// Check the status of the operation.
|
||
|
//
|
||
|
|
||
|
if (!NT_SUCCESS( Status )) {
|
||
|
if (Status == STATUS_NO_MORE_ENTRIES) {
|
||
|
Status = STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (!wcscmp( DirInfo->TypeName.Buffer, L"SymbolicLink" )) {
|
||
|
Result = FindSymbolicLinkEntry(
|
||
|
DirInfo->Name.Buffer,
|
||
|
lpBuffer,
|
||
|
nElements,
|
||
|
&DuplicateEntry);
|
||
|
|
||
|
if ((Result == NO_ERROR) && (DuplicateEntry == FALSE)) {
|
||
|
ucchName = DirInfo->Name.Length / sizeof( WCHAR );
|
||
|
if ((ucchReturned + ucchName + 1 + 1) > ucchMax) {
|
||
|
ucchReturned = 0;
|
||
|
Status = STATUS_BUFFER_TOO_SMALL;
|
||
|
break;
|
||
|
}
|
||
|
RtlMoveMemory( lpTargetPath,
|
||
|
DirInfo->Name.Buffer,
|
||
|
DirInfo->Name.Length
|
||
|
);
|
||
|
lpTargetPath += ucchName;
|
||
|
*lpTargetPath++ = UNICODE_NULL;
|
||
|
ucchReturned += ucchName + 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
RestartScan = FALSE;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
if (NT_SUCCESS( Status )) {
|
||
|
*lpTargetPath++ = UNICODE_NULL;
|
||
|
ucchReturned++;
|
||
|
}
|
||
|
}
|
||
|
} finally {
|
||
|
if( DirectoryHandle != NULL ) {
|
||
|
NtClose( DirectoryHandle );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!NT_SUCCESS( Status )) {
|
||
|
ucchReturned = 0;
|
||
|
BaseSetLastNTError( Status );
|
||
|
}
|
||
|
|
||
|
return ucchReturned;
|
||
|
}
|