mirror of
https://github.com/reactos/reactos.git
synced 2024-08-20 18:35:32 +00:00
467 lines
13 KiB
C
467 lines
13 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS system libraries
|
|
* FILE: dll/win32/kernel32/client/dosdev.c
|
|
* PURPOSE: Dos device functions
|
|
* PROGRAMMER: Ariadne (ariadne@xs4all.nl)
|
|
* UPDATE HISTORY:
|
|
* Created 01/11/98
|
|
*/
|
|
|
|
/* INCLUDES ******************************************************************/
|
|
|
|
#include <k32.h>
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
#include <dbt.h>
|
|
DEBUG_CHANNEL(kernel32file);
|
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
DefineDosDeviceA(
|
|
DWORD dwFlags,
|
|
LPCSTR lpDeviceName,
|
|
LPCSTR lpTargetPath
|
|
)
|
|
{
|
|
UNICODE_STRING DeviceNameU = {0};
|
|
UNICODE_STRING TargetPathU = {0};
|
|
BOOL Result;
|
|
|
|
if (lpDeviceName &&
|
|
!RtlCreateUnicodeStringFromAsciiz(&DeviceNameU, lpDeviceName))
|
|
{
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return 0;
|
|
}
|
|
|
|
if (lpTargetPath &&
|
|
!RtlCreateUnicodeStringFromAsciiz(&TargetPathU, lpTargetPath))
|
|
{
|
|
if (DeviceNameU.Buffer)
|
|
{
|
|
RtlFreeUnicodeString(&DeviceNameU);
|
|
}
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return 0;
|
|
}
|
|
|
|
Result = DefineDosDeviceW(dwFlags,
|
|
DeviceNameU.Buffer,
|
|
TargetPathU.Buffer);
|
|
|
|
if (TargetPathU.Buffer)
|
|
{
|
|
RtlFreeUnicodeString(&TargetPathU);
|
|
}
|
|
|
|
if (DeviceNameU.Buffer)
|
|
{
|
|
RtlFreeUnicodeString(&DeviceNameU);
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
DefineDosDeviceW(
|
|
DWORD dwFlags,
|
|
LPCWSTR lpDeviceName,
|
|
LPCWSTR lpTargetPath
|
|
)
|
|
{
|
|
ULONG ArgumentCount;
|
|
ULONG BufferSize;
|
|
BASE_API_MESSAGE ApiMessage;
|
|
PBASE_DEFINE_DOS_DEVICE DefineDosDeviceRequest = &ApiMessage.Data.DefineDosDeviceRequest;
|
|
PCSR_CAPTURE_BUFFER CaptureBuffer;
|
|
UNICODE_STRING NtTargetPathU;
|
|
UNICODE_STRING DeviceNameU;
|
|
UNICODE_STRING DeviceUpcaseNameU;
|
|
HANDLE hUser32;
|
|
DEV_BROADCAST_VOLUME dbcv;
|
|
BOOL Result = TRUE;
|
|
DWORD dwRecipients;
|
|
typedef long (WINAPI *BSM_type)(DWORD, LPDWORD, UINT, WPARAM, LPARAM);
|
|
BSM_type BSM_ptr;
|
|
|
|
if ( (dwFlags & 0xFFFFFFF0) ||
|
|
((dwFlags & DDD_EXACT_MATCH_ON_REMOVE) &&
|
|
! (dwFlags & DDD_REMOVE_DEFINITION)) )
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
ArgumentCount = 1;
|
|
BufferSize = 0;
|
|
if (!lpTargetPath)
|
|
{
|
|
RtlInitUnicodeString(&NtTargetPathU,
|
|
NULL);
|
|
}
|
|
else
|
|
{
|
|
if (dwFlags & DDD_RAW_TARGET_PATH)
|
|
{
|
|
RtlInitUnicodeString(&NtTargetPathU,
|
|
lpTargetPath);
|
|
}
|
|
else
|
|
{
|
|
if (!RtlDosPathNameToNtPathName_U(lpTargetPath,
|
|
&NtTargetPathU,
|
|
NULL,
|
|
NULL))
|
|
{
|
|
WARN("RtlDosPathNameToNtPathName_U() failed\n");
|
|
BaseSetLastNTError(STATUS_OBJECT_NAME_INVALID);
|
|
return FALSE;
|
|
}
|
|
}
|
|
ArgumentCount = 2;
|
|
BufferSize += NtTargetPathU.Length;
|
|
}
|
|
|
|
RtlInitUnicodeString(&DeviceNameU,
|
|
lpDeviceName);
|
|
RtlUpcaseUnicodeString(&DeviceUpcaseNameU,
|
|
&DeviceNameU,
|
|
TRUE);
|
|
BufferSize += DeviceUpcaseNameU.Length;
|
|
|
|
CaptureBuffer = CsrAllocateCaptureBuffer(ArgumentCount,
|
|
BufferSize);
|
|
if (!CaptureBuffer)
|
|
{
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
Result = FALSE;
|
|
}
|
|
else
|
|
{
|
|
DefineDosDeviceRequest->Flags = dwFlags;
|
|
|
|
CsrCaptureMessageBuffer(CaptureBuffer,
|
|
DeviceUpcaseNameU.Buffer,
|
|
DeviceUpcaseNameU.Length,
|
|
(PVOID*)&DefineDosDeviceRequest->DeviceName.Buffer);
|
|
|
|
DefineDosDeviceRequest->DeviceName.Length =
|
|
DeviceUpcaseNameU.Length;
|
|
DefineDosDeviceRequest->DeviceName.MaximumLength =
|
|
DeviceUpcaseNameU.Length;
|
|
|
|
if (NtTargetPathU.Buffer)
|
|
{
|
|
CsrCaptureMessageBuffer(CaptureBuffer,
|
|
NtTargetPathU.Buffer,
|
|
NtTargetPathU.Length,
|
|
(PVOID*)&DefineDosDeviceRequest->TargetPath.Buffer);
|
|
}
|
|
DefineDosDeviceRequest->TargetPath.Length =
|
|
NtTargetPathU.Length;
|
|
DefineDosDeviceRequest->TargetPath.MaximumLength =
|
|
NtTargetPathU.Length;
|
|
|
|
CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
|
|
CaptureBuffer,
|
|
CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepDefineDosDevice),
|
|
sizeof(*DefineDosDeviceRequest));
|
|
CsrFreeCaptureBuffer(CaptureBuffer);
|
|
|
|
if (!NT_SUCCESS(ApiMessage.Status))
|
|
{
|
|
WARN("CsrClientCallServer() failed (Status %lx)\n", ApiMessage.Status);
|
|
BaseSetLastNTError(ApiMessage.Status);
|
|
Result = FALSE;
|
|
}
|
|
else
|
|
{
|
|
if (! (dwFlags & DDD_NO_BROADCAST_SYSTEM) &&
|
|
DeviceUpcaseNameU.Length == 2 * sizeof(WCHAR) &&
|
|
DeviceUpcaseNameU.Buffer[1] == L':' &&
|
|
( (DeviceUpcaseNameU.Buffer[0] - L'A') < 26 ))
|
|
{
|
|
hUser32 = LoadLibraryA("user32.dll");
|
|
if (hUser32)
|
|
{
|
|
BSM_ptr = (BSM_type)
|
|
GetProcAddress(hUser32, "BroadcastSystemMessageW");
|
|
if (BSM_ptr)
|
|
{
|
|
dwRecipients = BSM_APPLICATIONS;
|
|
dbcv.dbcv_size = sizeof(DEV_BROADCAST_VOLUME);
|
|
dbcv.dbcv_devicetype = DBT_DEVTYP_VOLUME;
|
|
dbcv.dbcv_reserved = 0;
|
|
dbcv.dbcv_unitmask |=
|
|
(1 << (DeviceUpcaseNameU.Buffer[0] - L'A'));
|
|
dbcv.dbcv_flags = DBTF_NET;
|
|
(void) BSM_ptr(BSF_SENDNOTIFYMESSAGE | BSF_FLUSHDISK,
|
|
&dwRecipients,
|
|
WM_DEVICECHANGE,
|
|
(WPARAM)DBT_DEVICEARRIVAL,
|
|
(LPARAM)&dbcv);
|
|
}
|
|
FreeLibrary(hUser32);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (NtTargetPathU.Buffer &&
|
|
NtTargetPathU.Buffer != lpTargetPath)
|
|
{
|
|
RtlFreeHeap(RtlGetProcessHeap(),
|
|
0,
|
|
NtTargetPathU.Buffer);
|
|
}
|
|
RtlFreeUnicodeString(&DeviceUpcaseNameU);
|
|
return Result;
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
DWORD
|
|
WINAPI
|
|
QueryDosDeviceA(
|
|
LPCSTR lpDeviceName,
|
|
LPSTR lpTargetPath,
|
|
DWORD ucchMax
|
|
)
|
|
{
|
|
UNICODE_STRING DeviceNameU;
|
|
UNICODE_STRING TargetPathU;
|
|
ANSI_STRING TargetPathA;
|
|
DWORD Length;
|
|
DWORD CurrentLength;
|
|
PWCHAR Buffer;
|
|
|
|
if (lpDeviceName)
|
|
{
|
|
if (!RtlCreateUnicodeStringFromAsciiz(&DeviceNameU,
|
|
(LPSTR)lpDeviceName))
|
|
{
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return 0;
|
|
}
|
|
}
|
|
Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, ucchMax * sizeof(WCHAR));
|
|
if (Buffer == NULL)
|
|
{
|
|
if (lpDeviceName)
|
|
{
|
|
RtlFreeHeap(RtlGetProcessHeap(), 0, DeviceNameU.Buffer);
|
|
}
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return 0;
|
|
}
|
|
|
|
Length = QueryDosDeviceW(lpDeviceName ? DeviceNameU.Buffer : NULL,
|
|
Buffer, ucchMax);
|
|
if (Length != 0)
|
|
{
|
|
TargetPathA.Buffer = lpTargetPath;
|
|
TargetPathU.Buffer = Buffer;
|
|
ucchMax = Length;
|
|
|
|
while (ucchMax)
|
|
{
|
|
CurrentLength = min(ucchMax, MAXUSHORT / 2);
|
|
TargetPathU.MaximumLength = TargetPathU.Length = (USHORT)CurrentLength * sizeof(WCHAR);
|
|
|
|
TargetPathA.Length = 0;
|
|
TargetPathA.MaximumLength = (USHORT)CurrentLength;
|
|
|
|
RtlUnicodeStringToAnsiString(&TargetPathA, &TargetPathU, FALSE);
|
|
ucchMax -= CurrentLength;
|
|
TargetPathA.Buffer += TargetPathA.Length;
|
|
TargetPathU.Buffer += TargetPathU.Length / sizeof(WCHAR);
|
|
}
|
|
}
|
|
|
|
RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
|
|
if (lpDeviceName)
|
|
{
|
|
RtlFreeHeap(RtlGetProcessHeap(), 0, DeviceNameU.Buffer);
|
|
}
|
|
return Length;
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
DWORD
|
|
WINAPI
|
|
QueryDosDeviceW(
|
|
LPCWSTR lpDeviceName,
|
|
LPWSTR lpTargetPath,
|
|
DWORD ucchMax
|
|
)
|
|
{
|
|
POBJECT_DIRECTORY_INFORMATION DirInfo;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
UNICODE_STRING UnicodeString;
|
|
HANDLE DirectoryHandle;
|
|
HANDLE DeviceHandle;
|
|
ULONG ReturnLength;
|
|
ULONG NameLength;
|
|
ULONG Length;
|
|
ULONG Context;
|
|
BOOLEAN RestartScan;
|
|
NTSTATUS Status;
|
|
UCHAR Buffer[512];
|
|
PWSTR Ptr;
|
|
|
|
/* Open the '\??' directory */
|
|
RtlInitUnicodeString(&UnicodeString, L"\\??");
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&UnicodeString,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL);
|
|
Status = NtOpenDirectoryObject(&DirectoryHandle,
|
|
DIRECTORY_QUERY,
|
|
&ObjectAttributes);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
WARN("NtOpenDirectoryObject() failed (Status %lx)\n", Status);
|
|
BaseSetLastNTError(Status);
|
|
return 0;
|
|
}
|
|
|
|
Length = 0;
|
|
|
|
if (lpDeviceName != NULL)
|
|
{
|
|
/* Open the lpDeviceName link object */
|
|
RtlInitUnicodeString(&UnicodeString, (PWSTR)lpDeviceName);
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&UnicodeString,
|
|
OBJ_CASE_INSENSITIVE,
|
|
DirectoryHandle,
|
|
NULL);
|
|
Status = NtOpenSymbolicLinkObject(&DeviceHandle,
|
|
SYMBOLIC_LINK_QUERY,
|
|
&ObjectAttributes);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
WARN("NtOpenSymbolicLinkObject() failed (Status %lx)\n", Status);
|
|
NtClose(DirectoryHandle);
|
|
BaseSetLastNTError(Status);
|
|
return 0;
|
|
}
|
|
|
|
/* Query link target */
|
|
UnicodeString.Length = 0;
|
|
UnicodeString.MaximumLength = (USHORT)ucchMax * sizeof(WCHAR);
|
|
UnicodeString.Buffer = lpTargetPath;
|
|
|
|
ReturnLength = 0;
|
|
Status = NtQuerySymbolicLinkObject(DeviceHandle,
|
|
&UnicodeString,
|
|
&ReturnLength);
|
|
NtClose(DeviceHandle);
|
|
NtClose(DirectoryHandle);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
WARN("NtQuerySymbolicLinkObject() failed (Status %lx)\n", Status);
|
|
BaseSetLastNTError(Status);
|
|
return 0;
|
|
}
|
|
|
|
TRACE("ReturnLength: %lu\n", ReturnLength);
|
|
TRACE("TargetLength: %hu\n", UnicodeString.Length);
|
|
TRACE("Target: '%wZ'\n", &UnicodeString);
|
|
|
|
Length = UnicodeString.Length / sizeof(WCHAR);
|
|
if (Length < ucchMax)
|
|
{
|
|
/* Append null-character */
|
|
lpTargetPath[Length] = UNICODE_NULL;
|
|
Length++;
|
|
}
|
|
else
|
|
{
|
|
TRACE("Buffer is too small\n");
|
|
BaseSetLastNTError(STATUS_BUFFER_TOO_SMALL);
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RestartScan = TRUE;
|
|
Context = 0;
|
|
Ptr = lpTargetPath;
|
|
DirInfo = (POBJECT_DIRECTORY_INFORMATION)Buffer;
|
|
|
|
while (TRUE)
|
|
{
|
|
Status = NtQueryDirectoryObject(DirectoryHandle,
|
|
Buffer,
|
|
sizeof(Buffer),
|
|
TRUE,
|
|
RestartScan,
|
|
&Context,
|
|
&ReturnLength);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
if (Status == STATUS_NO_MORE_ENTRIES)
|
|
{
|
|
/* Terminate the buffer */
|
|
*Ptr = UNICODE_NULL;
|
|
Length++;
|
|
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
Length = 0;
|
|
}
|
|
BaseSetLastNTError(Status);
|
|
break;
|
|
}
|
|
|
|
if (!wcscmp(DirInfo->TypeName.Buffer, L"SymbolicLink"))
|
|
{
|
|
TRACE("Name: '%wZ'\n", &DirInfo->Name);
|
|
|
|
NameLength = DirInfo->Name.Length / sizeof(WCHAR);
|
|
if (Length + NameLength + 1 >= ucchMax)
|
|
{
|
|
Length = 0;
|
|
BaseSetLastNTError(STATUS_BUFFER_TOO_SMALL);
|
|
break;
|
|
}
|
|
|
|
memcpy(Ptr, DirInfo->Name.Buffer, DirInfo->Name.Length);
|
|
Ptr += NameLength;
|
|
Length += NameLength;
|
|
*Ptr = UNICODE_NULL;
|
|
Ptr++;
|
|
Length++;
|
|
}
|
|
|
|
RestartScan = FALSE;
|
|
}
|
|
|
|
NtClose(DirectoryHandle);
|
|
}
|
|
|
|
return Length;
|
|
}
|
|
|
|
/* EOF */
|