reactos/dll/win32/kernel32/client/dosdev.c

466 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 */