1c2c66affSColin Finck /* 2c2c66affSColin Finck * COPYRIGHT: See COPYING in the top level directory 3c2c66affSColin Finck * PROJECT: ReactOS system libraries 4c2c66affSColin Finck * FILE: dll/win32/kernel32/client/dosdev.c 5c2c66affSColin Finck * PURPOSE: Dos device functions 6c2c66affSColin Finck * PROGRAMMER: Ariadne (ariadne@xs4all.nl) 7*5d20d512SPierre Schweitzer * Pierre Schweitzer 8c2c66affSColin Finck * UPDATE HISTORY: 9c2c66affSColin Finck * Created 01/11/98 10c2c66affSColin Finck */ 11c2c66affSColin Finck 12c2c66affSColin Finck /* INCLUDES ******************************************************************/ 13c2c66affSColin Finck 14c2c66affSColin Finck #include <k32.h> 15c2c66affSColin Finck 16c2c66affSColin Finck #define NDEBUG 17c2c66affSColin Finck #include <debug.h> 18c2c66affSColin Finck #include <dbt.h> 19c2c66affSColin Finck DEBUG_CHANNEL(kernel32file); 20c2c66affSColin Finck 21c2c66affSColin Finck /* FUNCTIONS *****************************************************************/ 22c2c66affSColin Finck 23c2c66affSColin Finck /* 24c2c66affSColin Finck * @implemented 25c2c66affSColin Finck */ 26*5d20d512SPierre Schweitzer NTSTATUS 27*5d20d512SPierre Schweitzer IsGlobalDeviceMap( 28*5d20d512SPierre Schweitzer HANDLE DirectoryHandle, 29*5d20d512SPierre Schweitzer PBOOLEAN IsGlobal) 30*5d20d512SPierre Schweitzer { 31*5d20d512SPierre Schweitzer NTSTATUS Status; 32*5d20d512SPierre Schweitzer DWORD ReturnLength; 33*5d20d512SPierre Schweitzer UNICODE_STRING GlobalString; 34*5d20d512SPierre Schweitzer OBJECT_NAME_INFORMATION NameInfo, *PNameInfo; 35*5d20d512SPierre Schweitzer 36*5d20d512SPierre Schweitzer /* We need both parameters */ 37*5d20d512SPierre Schweitzer if (DirectoryHandle == 0 || IsGlobal == NULL) 38*5d20d512SPierre Schweitzer { 39*5d20d512SPierre Schweitzer return STATUS_INVALID_PARAMETER; 40*5d20d512SPierre Schweitzer } 41*5d20d512SPierre Schweitzer 42*5d20d512SPierre Schweitzer PNameInfo = NULL; 43*5d20d512SPierre Schweitzer _SEH2_TRY 44*5d20d512SPierre Schweitzer { 45*5d20d512SPierre Schweitzer /* Query handle information */ 46*5d20d512SPierre Schweitzer Status = NtQueryObject(DirectoryHandle, 47*5d20d512SPierre Schweitzer ObjectNameInformation, 48*5d20d512SPierre Schweitzer &NameInfo, 49*5d20d512SPierre Schweitzer 0, 50*5d20d512SPierre Schweitzer &ReturnLength); 51*5d20d512SPierre Schweitzer /* Only failure we tolerate is length mismatch */ 52*5d20d512SPierre Schweitzer if (NT_SUCCESS(Status) || Status == STATUS_INFO_LENGTH_MISMATCH) 53*5d20d512SPierre Schweitzer { 54*5d20d512SPierre Schweitzer /* Allocate big enough buffer */ 55*5d20d512SPierre Schweitzer PNameInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, ReturnLength); 56*5d20d512SPierre Schweitzer if (PNameInfo == NULL) 57*5d20d512SPierre Schweitzer { 58*5d20d512SPierre Schweitzer Status = STATUS_NO_MEMORY; 59*5d20d512SPierre Schweitzer _SEH2_LEAVE; 60*5d20d512SPierre Schweitzer } 61*5d20d512SPierre Schweitzer 62*5d20d512SPierre Schweitzer /* Query again handle information */ 63*5d20d512SPierre Schweitzer Status = NtQueryObject(DirectoryHandle, 64*5d20d512SPierre Schweitzer ObjectNameInformation, 65*5d20d512SPierre Schweitzer PNameInfo, 66*5d20d512SPierre Schweitzer ReturnLength, 67*5d20d512SPierre Schweitzer &ReturnLength); 68*5d20d512SPierre Schweitzer 69*5d20d512SPierre Schweitzer /* 70*5d20d512SPierre Schweitzer * If it succeed, check we have Global?? 71*5d20d512SPierre Schweitzer * If so, return success 72*5d20d512SPierre Schweitzer */ 73*5d20d512SPierre Schweitzer if (NT_SUCCESS(Status)) 74*5d20d512SPierre Schweitzer { 75*5d20d512SPierre Schweitzer RtlInitUnicodeString(&GlobalString, L"\\GLOBAL??"); 76*5d20d512SPierre Schweitzer *IsGlobal = RtlEqualUnicodeString(&GlobalString, &PNameInfo->Name, FALSE); 77*5d20d512SPierre Schweitzer Status = STATUS_SUCCESS; 78*5d20d512SPierre Schweitzer } 79*5d20d512SPierre Schweitzer 80*5d20d512SPierre Schweitzer 81*5d20d512SPierre Schweitzer } 82*5d20d512SPierre Schweitzer } 83*5d20d512SPierre Schweitzer _SEH2_FINALLY 84*5d20d512SPierre Schweitzer { 85*5d20d512SPierre Schweitzer if (PNameInfo != NULL) 86*5d20d512SPierre Schweitzer { 87*5d20d512SPierre Schweitzer RtlFreeHeap(RtlGetProcessHeap(), 0, PNameInfo); 88*5d20d512SPierre Schweitzer } 89*5d20d512SPierre Schweitzer } 90*5d20d512SPierre Schweitzer _SEH2_END; 91*5d20d512SPierre Schweitzer 92*5d20d512SPierre Schweitzer return Status; 93*5d20d512SPierre Schweitzer } 94*5d20d512SPierre Schweitzer 95*5d20d512SPierre Schweitzer /* 96*5d20d512SPierre Schweitzer * @implemented 97*5d20d512SPierre Schweitzer */ 98*5d20d512SPierre Schweitzer DWORD 99*5d20d512SPierre Schweitzer FindSymbolicLinkEntry( 100*5d20d512SPierre Schweitzer PWSTR NameToFind, 101*5d20d512SPierre Schweitzer PWSTR NamesList, 102*5d20d512SPierre Schweitzer DWORD TotalEntries, 103*5d20d512SPierre Schweitzer PBOOLEAN Found) 104*5d20d512SPierre Schweitzer { 105*5d20d512SPierre Schweitzer WCHAR Current; 106*5d20d512SPierre Schweitzer DWORD Entries; 107*5d20d512SPierre Schweitzer PWSTR PartialNamesList; 108*5d20d512SPierre Schweitzer 109*5d20d512SPierre Schweitzer /* We need all parameters to be set */ 110*5d20d512SPierre Schweitzer if (NameToFind == NULL || NamesList == NULL || Found == NULL) 111*5d20d512SPierre Schweitzer { 112*5d20d512SPierre Schweitzer return ERROR_INVALID_PARAMETER; 113*5d20d512SPierre Schweitzer } 114*5d20d512SPierre Schweitzer 115*5d20d512SPierre Schweitzer /* Assume failure */ 116*5d20d512SPierre Schweitzer *Found = FALSE; 117*5d20d512SPierre Schweitzer 118*5d20d512SPierre Schweitzer /* If no entries, job done, nothing found */ 119*5d20d512SPierre Schweitzer if (TotalEntries == 0) 120*5d20d512SPierre Schweitzer { 121*5d20d512SPierre Schweitzer return ERROR_SUCCESS; 122*5d20d512SPierre Schweitzer } 123*5d20d512SPierre Schweitzer 124*5d20d512SPierre Schweitzer /* Start browsing the names list */ 125*5d20d512SPierre Schweitzer Entries = 0; 126*5d20d512SPierre Schweitzer PartialNamesList = NamesList; 127*5d20d512SPierre Schweitzer /* As long as we didn't find the name... */ 128*5d20d512SPierre Schweitzer while (wcscmp(NameToFind, PartialNamesList) != 0) 129*5d20d512SPierre Schweitzer { 130*5d20d512SPierre Schweitzer /* We chomped an entry! */ 131*5d20d512SPierre Schweitzer ++Entries; 132*5d20d512SPierre Schweitzer 133*5d20d512SPierre Schweitzer /* We're out of entries, bail out not to overrun */ 134*5d20d512SPierre Schweitzer if (Entries > TotalEntries) 135*5d20d512SPierre Schweitzer { 136*5d20d512SPierre Schweitzer /* 137*5d20d512SPierre Schweitzer * Even though we found nothing, 138*5d20d512SPierre Schweitzer * the function ran fine 139*5d20d512SPierre Schweitzer */ 140*5d20d512SPierre Schweitzer return ERROR_SUCCESS; 141*5d20d512SPierre Schweitzer } 142*5d20d512SPierre Schweitzer 143*5d20d512SPierre Schweitzer /* Jump to the next string */ 144*5d20d512SPierre Schweitzer do 145*5d20d512SPierre Schweitzer { 146*5d20d512SPierre Schweitzer Current = *PartialNamesList; 147*5d20d512SPierre Schweitzer ++PartialNamesList; 148*5d20d512SPierre Schweitzer } while (Current != UNICODE_NULL); 149*5d20d512SPierre Schweitzer } 150*5d20d512SPierre Schweitzer 151*5d20d512SPierre Schweitzer /* 152*5d20d512SPierre Schweitzer * We're here because the loop stopped: 153*5d20d512SPierre Schweitzer * it means we found the name in the list 154*5d20d512SPierre Schweitzer */ 155*5d20d512SPierre Schweitzer *Found = TRUE; 156*5d20d512SPierre Schweitzer return ERROR_SUCCESS; 157*5d20d512SPierre Schweitzer } 158*5d20d512SPierre Schweitzer 159*5d20d512SPierre Schweitzer /* 160*5d20d512SPierre Schweitzer * @implemented 161*5d20d512SPierre Schweitzer */ 162c2c66affSColin Finck BOOL 163c2c66affSColin Finck WINAPI 164c2c66affSColin Finck DefineDosDeviceA( 165c2c66affSColin Finck DWORD dwFlags, 166c2c66affSColin Finck LPCSTR lpDeviceName, 167c2c66affSColin Finck LPCSTR lpTargetPath 168c2c66affSColin Finck ) 169c2c66affSColin Finck { 170c2c66affSColin Finck BOOL Result; 1711ed7f274SPierre Schweitzer NTSTATUS Status; 1721ed7f274SPierre Schweitzer ANSI_STRING AnsiString; 1731ed7f274SPierre Schweitzer PWSTR TargetPathBuffer; 1741ed7f274SPierre Schweitzer UNICODE_STRING TargetPathU; 1751ed7f274SPierre Schweitzer PUNICODE_STRING DeviceNameU; 176c2c66affSColin Finck 1771ed7f274SPierre Schweitzer /* Convert DeviceName using static unicode string */ 1781ed7f274SPierre Schweitzer RtlInitAnsiString(&AnsiString, lpDeviceName); 1791ed7f274SPierre Schweitzer DeviceNameU = &NtCurrentTeb()->StaticUnicodeString; 1801ed7f274SPierre Schweitzer Status = RtlAnsiStringToUnicodeString(DeviceNameU, &AnsiString, FALSE); 1811ed7f274SPierre Schweitzer if (!NT_SUCCESS(Status)) 182c2c66affSColin Finck { 1831ed7f274SPierre Schweitzer /* 1841ed7f274SPierre Schweitzer * If the static unicode string is too small, 1851ed7f274SPierre Schweitzer * it's because the name is too long... 1861ed7f274SPierre Schweitzer * so, return appropriate status! 1871ed7f274SPierre Schweitzer */ 1881ed7f274SPierre Schweitzer if (Status == STATUS_BUFFER_OVERFLOW) 1891ed7f274SPierre Schweitzer { 1901ed7f274SPierre Schweitzer SetLastError(ERROR_FILENAME_EXCED_RANGE); 1911ed7f274SPierre Schweitzer return FALSE; 192c2c66affSColin Finck } 193c2c66affSColin Finck 1941ed7f274SPierre Schweitzer BaseSetLastNTError(Status); 1951ed7f274SPierre Schweitzer return FALSE; 196c2c66affSColin Finck } 197c2c66affSColin Finck 1981ed7f274SPierre Schweitzer /* Convert target path if existing */ 1991ed7f274SPierre Schweitzer if (lpTargetPath != NULL) 2001ed7f274SPierre Schweitzer { 2011ed7f274SPierre Schweitzer RtlInitAnsiString(&AnsiString, lpTargetPath); 2021ed7f274SPierre Schweitzer Status = RtlAnsiStringToUnicodeString(&TargetPathU, &AnsiString, TRUE); 2031ed7f274SPierre Schweitzer if (!NT_SUCCESS(Status)) 2041ed7f274SPierre Schweitzer { 2051ed7f274SPierre Schweitzer BaseSetLastNTError(Status); 2061ed7f274SPierre Schweitzer return FALSE; 2071ed7f274SPierre Schweitzer } 208c2c66affSColin Finck 2091ed7f274SPierre Schweitzer TargetPathBuffer = TargetPathU.Buffer; 2101ed7f274SPierre Schweitzer } 2111ed7f274SPierre Schweitzer else 2121ed7f274SPierre Schweitzer { 2131ed7f274SPierre Schweitzer TargetPathBuffer = NULL; 2141ed7f274SPierre Schweitzer } 2151ed7f274SPierre Schweitzer 2161ed7f274SPierre Schweitzer /* Call W */ 2171ed7f274SPierre Schweitzer Result = DefineDosDeviceW(dwFlags, DeviceNameU->Buffer, TargetPathBuffer); 2181ed7f274SPierre Schweitzer 2191ed7f274SPierre Schweitzer /* Free target path if allocated */ 2201ed7f274SPierre Schweitzer if (TargetPathBuffer != NULL) 221c2c66affSColin Finck { 222c2c66affSColin Finck RtlFreeUnicodeString(&TargetPathU); 223c2c66affSColin Finck } 224c2c66affSColin Finck 225c2c66affSColin Finck return Result; 226c2c66affSColin Finck } 227c2c66affSColin Finck 228c2c66affSColin Finck 229c2c66affSColin Finck /* 230c2c66affSColin Finck * @implemented 231c2c66affSColin Finck */ 232c2c66affSColin Finck BOOL 233c2c66affSColin Finck WINAPI 234c2c66affSColin Finck DefineDosDeviceW( 235c2c66affSColin Finck DWORD dwFlags, 236c2c66affSColin Finck LPCWSTR lpDeviceName, 237c2c66affSColin Finck LPCWSTR lpTargetPath 238c2c66affSColin Finck ) 239c2c66affSColin Finck { 240c2c66affSColin Finck ULONG ArgumentCount; 241c2c66affSColin Finck ULONG BufferSize; 242c2c66affSColin Finck BASE_API_MESSAGE ApiMessage; 243c2c66affSColin Finck PBASE_DEFINE_DOS_DEVICE DefineDosDeviceRequest = &ApiMessage.Data.DefineDosDeviceRequest; 244c2c66affSColin Finck PCSR_CAPTURE_BUFFER CaptureBuffer; 245c2c66affSColin Finck UNICODE_STRING NtTargetPathU; 246c2c66affSColin Finck UNICODE_STRING DeviceNameU; 247c2c66affSColin Finck UNICODE_STRING DeviceUpcaseNameU; 248c2c66affSColin Finck HANDLE hUser32; 249c2c66affSColin Finck DEV_BROADCAST_VOLUME dbcv; 250c2c66affSColin Finck BOOL Result = TRUE; 251c2c66affSColin Finck DWORD dwRecipients; 252c2c66affSColin Finck typedef long (WINAPI *BSM_type)(DWORD, LPDWORD, UINT, WPARAM, LPARAM); 253c2c66affSColin Finck BSM_type BSM_ptr; 254c2c66affSColin Finck 255c2c66affSColin Finck if ( (dwFlags & 0xFFFFFFF0) || 256c2c66affSColin Finck ((dwFlags & DDD_EXACT_MATCH_ON_REMOVE) && 257c2c66affSColin Finck ! (dwFlags & DDD_REMOVE_DEFINITION)) ) 258c2c66affSColin Finck { 259c2c66affSColin Finck SetLastError(ERROR_INVALID_PARAMETER); 260c2c66affSColin Finck return FALSE; 261c2c66affSColin Finck } 262c2c66affSColin Finck 263c2c66affSColin Finck ArgumentCount = 1; 264c2c66affSColin Finck BufferSize = 0; 265c2c66affSColin Finck if (!lpTargetPath) 266c2c66affSColin Finck { 267c2c66affSColin Finck RtlInitUnicodeString(&NtTargetPathU, 268c2c66affSColin Finck NULL); 269c2c66affSColin Finck } 270c2c66affSColin Finck else 271c2c66affSColin Finck { 272c2c66affSColin Finck if (dwFlags & DDD_RAW_TARGET_PATH) 273c2c66affSColin Finck { 274c2c66affSColin Finck RtlInitUnicodeString(&NtTargetPathU, 275c2c66affSColin Finck lpTargetPath); 276c2c66affSColin Finck } 277c2c66affSColin Finck else 278c2c66affSColin Finck { 279c2c66affSColin Finck if (!RtlDosPathNameToNtPathName_U(lpTargetPath, 280c2c66affSColin Finck &NtTargetPathU, 281c2c66affSColin Finck NULL, 282c2c66affSColin Finck NULL)) 283c2c66affSColin Finck { 284c2c66affSColin Finck WARN("RtlDosPathNameToNtPathName_U() failed\n"); 285c2c66affSColin Finck BaseSetLastNTError(STATUS_OBJECT_NAME_INVALID); 286c2c66affSColin Finck return FALSE; 287c2c66affSColin Finck } 288c2c66affSColin Finck } 289c2c66affSColin Finck ArgumentCount = 2; 290c2c66affSColin Finck BufferSize += NtTargetPathU.Length; 291c2c66affSColin Finck } 292c2c66affSColin Finck 293c2c66affSColin Finck RtlInitUnicodeString(&DeviceNameU, 294c2c66affSColin Finck lpDeviceName); 295c2c66affSColin Finck RtlUpcaseUnicodeString(&DeviceUpcaseNameU, 296c2c66affSColin Finck &DeviceNameU, 297c2c66affSColin Finck TRUE); 298c2c66affSColin Finck BufferSize += DeviceUpcaseNameU.Length; 299c2c66affSColin Finck 300c2c66affSColin Finck CaptureBuffer = CsrAllocateCaptureBuffer(ArgumentCount, 301c2c66affSColin Finck BufferSize); 302c2c66affSColin Finck if (!CaptureBuffer) 303c2c66affSColin Finck { 304c2c66affSColin Finck SetLastError(ERROR_NOT_ENOUGH_MEMORY); 305c2c66affSColin Finck Result = FALSE; 306c2c66affSColin Finck } 307c2c66affSColin Finck else 308c2c66affSColin Finck { 309c2c66affSColin Finck DefineDosDeviceRequest->Flags = dwFlags; 310c2c66affSColin Finck 311c2c66affSColin Finck CsrCaptureMessageBuffer(CaptureBuffer, 312c2c66affSColin Finck DeviceUpcaseNameU.Buffer, 313c2c66affSColin Finck DeviceUpcaseNameU.Length, 314c2c66affSColin Finck (PVOID*)&DefineDosDeviceRequest->DeviceName.Buffer); 315c2c66affSColin Finck 316c2c66affSColin Finck DefineDosDeviceRequest->DeviceName.Length = 317c2c66affSColin Finck DeviceUpcaseNameU.Length; 318c2c66affSColin Finck DefineDosDeviceRequest->DeviceName.MaximumLength = 319c2c66affSColin Finck DeviceUpcaseNameU.Length; 320c2c66affSColin Finck 321c2c66affSColin Finck if (NtTargetPathU.Buffer) 322c2c66affSColin Finck { 323c2c66affSColin Finck CsrCaptureMessageBuffer(CaptureBuffer, 324c2c66affSColin Finck NtTargetPathU.Buffer, 325c2c66affSColin Finck NtTargetPathU.Length, 326c2c66affSColin Finck (PVOID*)&DefineDosDeviceRequest->TargetPath.Buffer); 327c2c66affSColin Finck } 328c2c66affSColin Finck DefineDosDeviceRequest->TargetPath.Length = 329c2c66affSColin Finck NtTargetPathU.Length; 330c2c66affSColin Finck DefineDosDeviceRequest->TargetPath.MaximumLength = 331c2c66affSColin Finck NtTargetPathU.Length; 332c2c66affSColin Finck 333c2c66affSColin Finck CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage, 334c2c66affSColin Finck CaptureBuffer, 335c2c66affSColin Finck CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepDefineDosDevice), 336c2c66affSColin Finck sizeof(*DefineDosDeviceRequest)); 337c2c66affSColin Finck CsrFreeCaptureBuffer(CaptureBuffer); 338c2c66affSColin Finck 339c2c66affSColin Finck if (!NT_SUCCESS(ApiMessage.Status)) 340c2c66affSColin Finck { 341c2c66affSColin Finck WARN("CsrClientCallServer() failed (Status %lx)\n", ApiMessage.Status); 342c2c66affSColin Finck BaseSetLastNTError(ApiMessage.Status); 343c2c66affSColin Finck Result = FALSE; 344c2c66affSColin Finck } 345c2c66affSColin Finck else 346c2c66affSColin Finck { 347c2c66affSColin Finck if (! (dwFlags & DDD_NO_BROADCAST_SYSTEM) && 348c2c66affSColin Finck DeviceUpcaseNameU.Length == 2 * sizeof(WCHAR) && 349c2c66affSColin Finck DeviceUpcaseNameU.Buffer[1] == L':' && 350c2c66affSColin Finck ( (DeviceUpcaseNameU.Buffer[0] - L'A') < 26 )) 351c2c66affSColin Finck { 352c2c66affSColin Finck hUser32 = LoadLibraryA("user32.dll"); 353c2c66affSColin Finck if (hUser32) 354c2c66affSColin Finck { 355c2c66affSColin Finck BSM_ptr = (BSM_type) 356c2c66affSColin Finck GetProcAddress(hUser32, "BroadcastSystemMessageW"); 357c2c66affSColin Finck if (BSM_ptr) 358c2c66affSColin Finck { 359c2c66affSColin Finck dwRecipients = BSM_APPLICATIONS; 360c2c66affSColin Finck dbcv.dbcv_size = sizeof(DEV_BROADCAST_VOLUME); 361c2c66affSColin Finck dbcv.dbcv_devicetype = DBT_DEVTYP_VOLUME; 362c2c66affSColin Finck dbcv.dbcv_reserved = 0; 363c2c66affSColin Finck dbcv.dbcv_unitmask |= 364c2c66affSColin Finck (1 << (DeviceUpcaseNameU.Buffer[0] - L'A')); 365c2c66affSColin Finck dbcv.dbcv_flags = DBTF_NET; 366c2c66affSColin Finck (void) BSM_ptr(BSF_SENDNOTIFYMESSAGE | BSF_FLUSHDISK, 367c2c66affSColin Finck &dwRecipients, 368c2c66affSColin Finck WM_DEVICECHANGE, 369c2c66affSColin Finck (WPARAM)DBT_DEVICEARRIVAL, 370c2c66affSColin Finck (LPARAM)&dbcv); 371c2c66affSColin Finck } 372c2c66affSColin Finck FreeLibrary(hUser32); 373c2c66affSColin Finck } 374c2c66affSColin Finck } 375c2c66affSColin Finck } 376c2c66affSColin Finck } 377c2c66affSColin Finck 378c2c66affSColin Finck if (NtTargetPathU.Buffer && 379c2c66affSColin Finck NtTargetPathU.Buffer != lpTargetPath) 380c2c66affSColin Finck { 381c2c66affSColin Finck RtlFreeHeap(RtlGetProcessHeap(), 382c2c66affSColin Finck 0, 383c2c66affSColin Finck NtTargetPathU.Buffer); 384c2c66affSColin Finck } 385c2c66affSColin Finck RtlFreeUnicodeString(&DeviceUpcaseNameU); 386c2c66affSColin Finck return Result; 387c2c66affSColin Finck } 388c2c66affSColin Finck 389c2c66affSColin Finck 390c2c66affSColin Finck /* 391c2c66affSColin Finck * @implemented 392c2c66affSColin Finck */ 393c2c66affSColin Finck DWORD 394c2c66affSColin Finck WINAPI 395c2c66affSColin Finck QueryDosDeviceA( 396c2c66affSColin Finck LPCSTR lpDeviceName, 397c2c66affSColin Finck LPSTR lpTargetPath, 398c2c66affSColin Finck DWORD ucchMax 399c2c66affSColin Finck ) 400c2c66affSColin Finck { 4018d128aa4SPierre Schweitzer NTSTATUS Status; 4028d128aa4SPierre Schweitzer USHORT CurrentPosition; 4038d128aa4SPierre Schweitzer ANSI_STRING AnsiString; 404c2c66affSColin Finck UNICODE_STRING TargetPathU; 4058d128aa4SPierre Schweitzer PUNICODE_STRING DeviceNameU; 4068d128aa4SPierre Schweitzer DWORD RetLength, CurrentLength, Length; 4078d128aa4SPierre Schweitzer PWSTR DeviceNameBuffer, TargetPathBuffer; 408c2c66affSColin Finck 4098d128aa4SPierre Schweitzer /* If we want a specific device name, convert it */ 4108d128aa4SPierre Schweitzer if (lpDeviceName != NULL) 411c2c66affSColin Finck { 4128d128aa4SPierre Schweitzer /* Convert DeviceName using static unicode string */ 4138d128aa4SPierre Schweitzer RtlInitAnsiString(&AnsiString, lpDeviceName); 4148d128aa4SPierre Schweitzer DeviceNameU = &NtCurrentTeb()->StaticUnicodeString; 4158d128aa4SPierre Schweitzer Status = RtlAnsiStringToUnicodeString(DeviceNameU, &AnsiString, FALSE); 4168d128aa4SPierre Schweitzer if (!NT_SUCCESS(Status)) 4178d128aa4SPierre Schweitzer { 4188d128aa4SPierre Schweitzer /* 4198d128aa4SPierre Schweitzer * If the static unicode string is too small, 4208d128aa4SPierre Schweitzer * it's because the name is too long... 4218d128aa4SPierre Schweitzer * so, return appropriate status! 4228d128aa4SPierre Schweitzer */ 4238d128aa4SPierre Schweitzer if (Status == STATUS_BUFFER_OVERFLOW) 4248d128aa4SPierre Schweitzer { 4258d128aa4SPierre Schweitzer SetLastError(ERROR_FILENAME_EXCED_RANGE); 4268d128aa4SPierre Schweitzer return FALSE; 4278d128aa4SPierre Schweitzer } 4288d128aa4SPierre Schweitzer 4298d128aa4SPierre Schweitzer BaseSetLastNTError(Status); 4308d128aa4SPierre Schweitzer return FALSE; 4318d128aa4SPierre Schweitzer } 4328d128aa4SPierre Schweitzer 4338d128aa4SPierre Schweitzer DeviceNameBuffer = DeviceNameU->Buffer; 4348d128aa4SPierre Schweitzer } 4358d128aa4SPierre Schweitzer else 4368d128aa4SPierre Schweitzer { 4378d128aa4SPierre Schweitzer DeviceNameBuffer = NULL; 4388d128aa4SPierre Schweitzer } 4398d128aa4SPierre Schweitzer 4408d128aa4SPierre Schweitzer /* Allocate the output buffer for W call */ 4418d128aa4SPierre Schweitzer TargetPathBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, ucchMax * sizeof(WCHAR)); 4428d128aa4SPierre Schweitzer if (TargetPathBuffer == NULL) 443c2c66affSColin Finck { 444c2c66affSColin Finck SetLastError(ERROR_NOT_ENOUGH_MEMORY); 445c2c66affSColin Finck return 0; 446c2c66affSColin Finck } 4478d128aa4SPierre Schweitzer 4488d128aa4SPierre Schweitzer /* Call W */ 4498d128aa4SPierre Schweitzer Length = QueryDosDeviceW(DeviceNameBuffer, TargetPathBuffer, ucchMax); 4508d128aa4SPierre Schweitzer /* We'll return that length in case of a success */ 4518d128aa4SPierre Schweitzer RetLength = Length; 4528d128aa4SPierre Schweitzer 4538d128aa4SPierre Schweitzer /* Handle the case where we would fill output buffer completly */ 4548d128aa4SPierre Schweitzer if (Length != 0 && Length == ucchMax) 455c2c66affSColin Finck { 4568d128aa4SPierre Schweitzer /* This will be our work length (but not the one we return) */ 4578d128aa4SPierre Schweitzer --Length; 4588d128aa4SPierre Schweitzer /* Already 0 the last char */ 4598d128aa4SPierre Schweitzer lpTargetPath[Length] = ANSI_NULL; 460c2c66affSColin Finck } 461c2c66affSColin Finck 4628d128aa4SPierre Schweitzer /* If we had an output, start the convert loop */ 463c2c66affSColin Finck if (Length != 0) 464c2c66affSColin Finck { 4658d128aa4SPierre Schweitzer /* 4668d128aa4SPierre Schweitzer * We'll have to loop because TargetPathBuffer may contain 4678d128aa4SPierre Schweitzer * several strings (NULL separated) 4688d128aa4SPierre Schweitzer * We'll start at position 0 4698d128aa4SPierre Schweitzer */ 4708d128aa4SPierre Schweitzer CurrentPosition = 0; 4718d128aa4SPierre Schweitzer while (CurrentPosition < Length) 472c2c66affSColin Finck { 4738d128aa4SPierre Schweitzer /* Get the maximum length */ 4748d128aa4SPierre Schweitzer CurrentLength = min(Length - CurrentPosition, MAXUSHORT / 2); 475c2c66affSColin Finck 4768d128aa4SPierre Schweitzer /* Initialize our output string */ 4778d128aa4SPierre Schweitzer AnsiString.Length = 0; 4788d128aa4SPierre Schweitzer AnsiString.MaximumLength = CurrentLength + sizeof(ANSI_NULL); 4798d128aa4SPierre Schweitzer AnsiString.Buffer = &lpTargetPath[CurrentPosition]; 480c2c66affSColin Finck 4818d128aa4SPierre Schweitzer /* Initialize input string that will be converted */ 4828d128aa4SPierre Schweitzer TargetPathU.Length = CurrentLength * sizeof(WCHAR); 4838d128aa4SPierre Schweitzer TargetPathU.MaximumLength = CurrentLength * sizeof(WCHAR) + sizeof(UNICODE_NULL); 4848d128aa4SPierre Schweitzer TargetPathU.Buffer = &TargetPathBuffer[CurrentPosition]; 485c2c66affSColin Finck 4868d128aa4SPierre Schweitzer /* Convert to ANSI */ 4878d128aa4SPierre Schweitzer Status = RtlUnicodeStringToAnsiString(&AnsiString, &TargetPathU, FALSE); 4888d128aa4SPierre Schweitzer if (!NT_SUCCESS(Status)) 489c2c66affSColin Finck { 4908d128aa4SPierre Schweitzer BaseSetLastNTError(Status); 4918d128aa4SPierre Schweitzer /* In case of a failure, forget about everything */ 4928d128aa4SPierre Schweitzer RetLength = 0; 4938d128aa4SPierre Schweitzer 4948d128aa4SPierre Schweitzer goto Leave; 495c2c66affSColin Finck } 4968d128aa4SPierre Schweitzer 4978d128aa4SPierre Schweitzer /* Move to the next string */ 4988d128aa4SPierre Schweitzer CurrentPosition += CurrentLength; 4998d128aa4SPierre Schweitzer } 5008d128aa4SPierre Schweitzer } 5018d128aa4SPierre Schweitzer 5028d128aa4SPierre Schweitzer Leave: 5038d128aa4SPierre Schweitzer /* Free our intermediate buffer and leave */ 5048d128aa4SPierre Schweitzer RtlFreeHeap(RtlGetProcessHeap(), 0, TargetPathBuffer); 5058d128aa4SPierre Schweitzer 5068d128aa4SPierre Schweitzer return RetLength; 507c2c66affSColin Finck } 508c2c66affSColin Finck 509c2c66affSColin Finck 510c2c66affSColin Finck /* 511c2c66affSColin Finck * @implemented 512c2c66affSColin Finck */ 513c2c66affSColin Finck DWORD 514c2c66affSColin Finck WINAPI 515c2c66affSColin Finck QueryDosDeviceW( 516c2c66affSColin Finck LPCWSTR lpDeviceName, 517c2c66affSColin Finck LPWSTR lpTargetPath, 518c2c66affSColin Finck DWORD ucchMax 519c2c66affSColin Finck ) 520c2c66affSColin Finck { 521c2c66affSColin Finck PWSTR Ptr; 522*5d20d512SPierre Schweitzer PVOID Buffer; 523*5d20d512SPierre Schweitzer NTSTATUS Status; 524*5d20d512SPierre Schweitzer USHORT i, TotalEntries; 525*5d20d512SPierre Schweitzer UNICODE_STRING UnicodeString; 526*5d20d512SPierre Schweitzer OBJECT_ATTRIBUTES ObjectAttributes; 527*5d20d512SPierre Schweitzer HANDLE DirectoryHandle, DeviceHandle; 528*5d20d512SPierre Schweitzer BOOLEAN IsGlobal, GlobalNeeded, Found; 529*5d20d512SPierre Schweitzer POBJECT_DIRECTORY_INFORMATION DirInfo; 530*5d20d512SPierre Schweitzer OBJECT_DIRECTORY_INFORMATION NullEntry = {{0}}; 531*5d20d512SPierre Schweitzer ULONG ReturnLength, NameLength, Length, Context, BufferLength; 532c2c66affSColin Finck 533c2c66affSColin Finck /* Open the '\??' directory */ 534c2c66affSColin Finck RtlInitUnicodeString(&UnicodeString, L"\\??"); 535c2c66affSColin Finck InitializeObjectAttributes(&ObjectAttributes, 536c2c66affSColin Finck &UnicodeString, 537c2c66affSColin Finck OBJ_CASE_INSENSITIVE, 538c2c66affSColin Finck NULL, 539c2c66affSColin Finck NULL); 540c2c66affSColin Finck Status = NtOpenDirectoryObject(&DirectoryHandle, 541c2c66affSColin Finck DIRECTORY_QUERY, 542c2c66affSColin Finck &ObjectAttributes); 543c2c66affSColin Finck if (!NT_SUCCESS(Status)) 544c2c66affSColin Finck { 545c2c66affSColin Finck WARN("NtOpenDirectoryObject() failed (Status %lx)\n", Status); 546c2c66affSColin Finck BaseSetLastNTError(Status); 547c2c66affSColin Finck return 0; 548c2c66affSColin Finck } 549c2c66affSColin Finck 550*5d20d512SPierre Schweitzer Buffer = NULL; 551*5d20d512SPierre Schweitzer _SEH2_TRY 552*5d20d512SPierre Schweitzer { 553c2c66affSColin Finck if (lpDeviceName != NULL) 554c2c66affSColin Finck { 555c2c66affSColin Finck /* Open the lpDeviceName link object */ 556*5d20d512SPierre Schweitzer RtlInitUnicodeString(&UnicodeString, lpDeviceName); 557c2c66affSColin Finck InitializeObjectAttributes(&ObjectAttributes, 558c2c66affSColin Finck &UnicodeString, 559c2c66affSColin Finck OBJ_CASE_INSENSITIVE, 560c2c66affSColin Finck DirectoryHandle, 561c2c66affSColin Finck NULL); 562c2c66affSColin Finck Status = NtOpenSymbolicLinkObject(&DeviceHandle, 563c2c66affSColin Finck SYMBOLIC_LINK_QUERY, 564c2c66affSColin Finck &ObjectAttributes); 565c2c66affSColin Finck if (!NT_SUCCESS(Status)) 566c2c66affSColin Finck { 567c2c66affSColin Finck WARN("NtOpenSymbolicLinkObject() failed (Status %lx)\n", Status); 568*5d20d512SPierre Schweitzer _SEH2_LEAVE; 569c2c66affSColin Finck } 570c2c66affSColin Finck 571*5d20d512SPierre Schweitzer /* 572*5d20d512SPierre Schweitzer * Make sure we don't overrun the output buffer, so convert our DWORD 573*5d20d512SPierre Schweitzer * size to USHORT size properly 574*5d20d512SPierre Schweitzer */ 575*5d20d512SPierre Schweitzer Length = (ucchMax <= MAXULONG / sizeof(WCHAR)) ? (ucchMax * sizeof(WCHAR)) : MAXULONG; 576*5d20d512SPierre Schweitzer 577c2c66affSColin Finck /* Query link target */ 578c2c66affSColin Finck UnicodeString.Length = 0; 579*5d20d512SPierre Schweitzer UnicodeString.MaximumLength = Length <= MAXUSHORT ? Length : MAXUSHORT; 580c2c66affSColin Finck UnicodeString.Buffer = lpTargetPath; 581c2c66affSColin Finck 582c2c66affSColin Finck ReturnLength = 0; 583c2c66affSColin Finck Status = NtQuerySymbolicLinkObject(DeviceHandle, 584c2c66affSColin Finck &UnicodeString, 585c2c66affSColin Finck &ReturnLength); 586c2c66affSColin Finck NtClose(DeviceHandle); 587c2c66affSColin Finck if (!NT_SUCCESS(Status)) 588c2c66affSColin Finck { 589c2c66affSColin Finck WARN("NtQuerySymbolicLinkObject() failed (Status %lx)\n", Status); 590*5d20d512SPierre Schweitzer _SEH2_LEAVE; 591c2c66affSColin Finck } 592c2c66affSColin Finck 593c2c66affSColin Finck TRACE("ReturnLength: %lu\n", ReturnLength); 594c2c66affSColin Finck TRACE("TargetLength: %hu\n", UnicodeString.Length); 595c2c66affSColin Finck TRACE("Target: '%wZ'\n", &UnicodeString); 596c2c66affSColin Finck 597*5d20d512SPierre Schweitzer Length = ReturnLength / sizeof(WCHAR); 598*5d20d512SPierre Schweitzer /* Make sure we null terminate output buffer */ 599*5d20d512SPierre Schweitzer if (Length == 0 || lpTargetPath[Length - 1] != UNICODE_NULL) 600*5d20d512SPierre Schweitzer { 601*5d20d512SPierre Schweitzer if (Length >= ucchMax) 602*5d20d512SPierre Schweitzer { 603*5d20d512SPierre Schweitzer TRACE("Buffer is too small\n"); 604*5d20d512SPierre Schweitzer Status = STATUS_BUFFER_TOO_SMALL; 605*5d20d512SPierre Schweitzer _SEH2_LEAVE; 606*5d20d512SPierre Schweitzer } 607*5d20d512SPierre Schweitzer 608*5d20d512SPierre Schweitzer /* Append null-character */ 609*5d20d512SPierre Schweitzer lpTargetPath[Length] = UNICODE_NULL; 610*5d20d512SPierre Schweitzer Length++; 611*5d20d512SPierre Schweitzer } 612*5d20d512SPierre Schweitzer 613c2c66affSColin Finck if (Length < ucchMax) 614c2c66affSColin Finck { 615c2c66affSColin Finck /* Append null-character */ 616c2c66affSColin Finck lpTargetPath[Length] = UNICODE_NULL; 617c2c66affSColin Finck Length++; 618c2c66affSColin Finck } 619c2c66affSColin Finck 620*5d20d512SPierre Schweitzer _SEH2_LEAVE; 621*5d20d512SPierre Schweitzer } 622*5d20d512SPierre Schweitzer 623*5d20d512SPierre Schweitzer /* 624*5d20d512SPierre Schweitzer * If LUID device maps are enabled, 625*5d20d512SPierre Schweitzer * ?? may not point to BaseNamedObjects 626*5d20d512SPierre Schweitzer * It may only be local DOS namespace. 627*5d20d512SPierre Schweitzer * And thus, it might be required to browse 628*5d20d512SPierre Schweitzer * Global?? for global devices 629*5d20d512SPierre Schweitzer */ 630*5d20d512SPierre Schweitzer GlobalNeeded = FALSE; 631*5d20d512SPierre Schweitzer if (BaseStaticServerData->LUIDDeviceMapsEnabled) 632c2c66affSColin Finck { 633*5d20d512SPierre Schweitzer /* Assume ?? == Global?? */ 634*5d20d512SPierre Schweitzer IsGlobal = TRUE; 635*5d20d512SPierre Schweitzer /* Check if it's the case */ 636*5d20d512SPierre Schweitzer Status = IsGlobalDeviceMap(DirectoryHandle, &IsGlobal); 637*5d20d512SPierre Schweitzer if (NT_SUCCESS(Status) && !IsGlobal) 638*5d20d512SPierre Schweitzer { 639*5d20d512SPierre Schweitzer /* It's not, we'll have to browse Global?? too! */ 640*5d20d512SPierre Schweitzer GlobalNeeded = TRUE; 641*5d20d512SPierre Schweitzer } 642*5d20d512SPierre Schweitzer } 643*5d20d512SPierre Schweitzer 644*5d20d512SPierre Schweitzer /* 645*5d20d512SPierre Schweitzer * Make sure we don't overrun the output buffer, so convert our DWORD 646*5d20d512SPierre Schweitzer * size to USHORT size properly 647*5d20d512SPierre Schweitzer */ 648*5d20d512SPierre Schweitzer BufferLength = (ucchMax <= MAXULONG / sizeof(WCHAR)) ? (ucchMax * sizeof(WCHAR)) : MAXULONG; 649*5d20d512SPierre Schweitzer Length = 0; 650*5d20d512SPierre Schweitzer Ptr = lpTargetPath; 651*5d20d512SPierre Schweitzer 652*5d20d512SPierre Schweitzer Context = 0; 653*5d20d512SPierre Schweitzer TotalEntries = 0; 654*5d20d512SPierre Schweitzer 655*5d20d512SPierre Schweitzer /* 656*5d20d512SPierre Schweitzer * We'll query all entries at once, with a rather big buffer 657*5d20d512SPierre Schweitzer * If it's too small, we'll grow it by 2. 658*5d20d512SPierre Schweitzer * Limit the number of attempts to 3. 659*5d20d512SPierre Schweitzer */ 660*5d20d512SPierre Schweitzer for (i = 0; i < 3; ++i) 661*5d20d512SPierre Schweitzer { 662*5d20d512SPierre Schweitzer /* Allocate the query buffer */ 663*5d20d512SPierre Schweitzer Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength); 664*5d20d512SPierre Schweitzer if (Buffer == NULL) 665*5d20d512SPierre Schweitzer { 666*5d20d512SPierre Schweitzer Status = STATUS_INSUFFICIENT_RESOURCES; 667*5d20d512SPierre Schweitzer _SEH2_LEAVE; 668*5d20d512SPierre Schweitzer } 669*5d20d512SPierre Schweitzer 670*5d20d512SPierre Schweitzer /* Perform the query */ 671c2c66affSColin Finck Status = NtQueryDirectoryObject(DirectoryHandle, 672c2c66affSColin Finck Buffer, 673*5d20d512SPierre Schweitzer BufferLength, 674*5d20d512SPierre Schweitzer FALSE, 675c2c66affSColin Finck TRUE, 676c2c66affSColin Finck &Context, 677c2c66affSColin Finck &ReturnLength); 678*5d20d512SPierre Schweitzer /* Only failure accepted is: no more entries */ 679c2c66affSColin Finck if (!NT_SUCCESS(Status)) 680c2c66affSColin Finck { 681*5d20d512SPierre Schweitzer if (Status != STATUS_NO_MORE_ENTRIES) 682c2c66affSColin Finck { 683*5d20d512SPierre Schweitzer _SEH2_LEAVE; 684*5d20d512SPierre Schweitzer } 685c2c66affSColin Finck 686*5d20d512SPierre Schweitzer /* 687*5d20d512SPierre Schweitzer * Which is a success! But break out, 688*5d20d512SPierre Schweitzer * it means our query returned no results 689*5d20d512SPierre Schweitzer * so, nothing to parse. 690*5d20d512SPierre Schweitzer */ 691c2c66affSColin Finck Status = STATUS_SUCCESS; 692c2c66affSColin Finck break; 693c2c66affSColin Finck } 694c2c66affSColin Finck 695*5d20d512SPierre Schweitzer /* In case we had them all, start browsing for devices */ 696*5d20d512SPierre Schweitzer if (Status != STATUS_MORE_ENTRIES) 697*5d20d512SPierre Schweitzer { 698*5d20d512SPierre Schweitzer DirInfo = Buffer; 699*5d20d512SPierre Schweitzer 700*5d20d512SPierre Schweitzer /* Loop until we find the nul entry (terminating entry) */ 701*5d20d512SPierre Schweitzer while (TRUE) 702*5d20d512SPierre Schweitzer { 703*5d20d512SPierre Schweitzer /* It's an entry full of zeroes */ 704*5d20d512SPierre Schweitzer if (RtlCompareMemory(&NullEntry, DirInfo, sizeof(NullEntry)) == sizeof(NullEntry)) 705*5d20d512SPierre Schweitzer { 706*5d20d512SPierre Schweitzer break; 707*5d20d512SPierre Schweitzer } 708*5d20d512SPierre Schweitzer 709*5d20d512SPierre Schweitzer /* Only handle symlinks */ 710c2c66affSColin Finck if (!wcscmp(DirInfo->TypeName.Buffer, L"SymbolicLink")) 711c2c66affSColin Finck { 712c2c66affSColin Finck TRACE("Name: '%wZ'\n", &DirInfo->Name); 713c2c66affSColin Finck 714*5d20d512SPierre Schweitzer /* Get name length in chars to only comparisons */ 715c2c66affSColin Finck NameLength = DirInfo->Name.Length / sizeof(WCHAR); 716*5d20d512SPierre Schweitzer 717*5d20d512SPierre Schweitzer /* Make sure we don't overrun output buffer */ 718*5d20d512SPierre Schweitzer if (Length > ucchMax || 719*5d20d512SPierre Schweitzer NameLength > ucchMax - Length || 720*5d20d512SPierre Schweitzer ucchMax - NameLength - Length < sizeof(WCHAR)) 721c2c66affSColin Finck { 722*5d20d512SPierre Schweitzer Status = STATUS_BUFFER_TOO_SMALL; 723*5d20d512SPierre Schweitzer _SEH2_LEAVE; 724*5d20d512SPierre Schweitzer } 725*5d20d512SPierre Schweitzer 726*5d20d512SPierre Schweitzer /* Copy and NULL terminate string */ 727*5d20d512SPierre Schweitzer memcpy(Ptr, DirInfo->Name.Buffer, DirInfo->Name.Length); 728*5d20d512SPierre Schweitzer Ptr[NameLength] = UNICODE_NULL; 729*5d20d512SPierre Schweitzer 730*5d20d512SPierre Schweitzer Ptr += (NameLength + 1); 731*5d20d512SPierre Schweitzer Length += (NameLength + 1); 732*5d20d512SPierre Schweitzer 733*5d20d512SPierre Schweitzer /* 734*5d20d512SPierre Schweitzer * Keep the entries count, in case we would have to 735*5d20d512SPierre Schweitzer * handle GLOBAL?? too 736*5d20d512SPierre Schweitzer */ 737*5d20d512SPierre Schweitzer ++TotalEntries; 738*5d20d512SPierre Schweitzer } 739*5d20d512SPierre Schweitzer 740*5d20d512SPierre Schweitzer /* Move to the next entry */ 741*5d20d512SPierre Schweitzer ++DirInfo; 742*5d20d512SPierre Schweitzer } 743*5d20d512SPierre Schweitzer 744*5d20d512SPierre Schweitzer /* 745*5d20d512SPierre Schweitzer * No need to loop again here, we got all the entries 746*5d20d512SPierre Schweitzer * Note: we don't free the buffer here, because we may 747*5d20d512SPierre Schweitzer * need it for GLOBAL??, so we save a few cycles here. 748*5d20d512SPierre Schweitzer */ 749c2c66affSColin Finck break; 750c2c66affSColin Finck } 751c2c66affSColin Finck 752*5d20d512SPierre Schweitzer /* Failure path here, we'll need bigger buffer */ 753*5d20d512SPierre Schweitzer RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); 754*5d20d512SPierre Schweitzer Buffer = NULL; 755*5d20d512SPierre Schweitzer 756*5d20d512SPierre Schweitzer /* We can't have bigger than that one, so leave */ 757*5d20d512SPierre Schweitzer if (BufferLength == MAXULONG) 758*5d20d512SPierre Schweitzer { 759*5d20d512SPierre Schweitzer break; 760*5d20d512SPierre Schweitzer } 761*5d20d512SPierre Schweitzer 762*5d20d512SPierre Schweitzer /* Prevent any overflow while computing new size */ 763*5d20d512SPierre Schweitzer if (MAXULONG - BufferLength < BufferLength) 764*5d20d512SPierre Schweitzer { 765*5d20d512SPierre Schweitzer BufferLength = MAXULONG; 766*5d20d512SPierre Schweitzer } 767*5d20d512SPierre Schweitzer else 768*5d20d512SPierre Schweitzer { 769*5d20d512SPierre Schweitzer BufferLength *= 2; 770*5d20d512SPierre Schweitzer } 771*5d20d512SPierre Schweitzer } 772*5d20d512SPierre Schweitzer 773*5d20d512SPierre Schweitzer /* 774*5d20d512SPierre Schweitzer * Out of the hot loop, but with more entries left? 775*5d20d512SPierre Schweitzer * that's an error case, leave here! 776*5d20d512SPierre Schweitzer */ 777*5d20d512SPierre Schweitzer if (Status == STATUS_MORE_ENTRIES) 778*5d20d512SPierre Schweitzer { 779*5d20d512SPierre Schweitzer Status = STATUS_BUFFER_TOO_SMALL; 780*5d20d512SPierre Schweitzer _SEH2_LEAVE; 781*5d20d512SPierre Schweitzer } 782*5d20d512SPierre Schweitzer 783*5d20d512SPierre Schweitzer /* Now, if we had to handle GLOBAL??, go for it! */ 784*5d20d512SPierre Schweitzer if (BaseStaticServerData->LUIDDeviceMapsEnabled && NT_SUCCESS(Status) && GlobalNeeded) 785*5d20d512SPierre Schweitzer { 786*5d20d512SPierre Schweitzer NtClose(DirectoryHandle); 787*5d20d512SPierre Schweitzer DirectoryHandle = 0; 788*5d20d512SPierre Schweitzer 789*5d20d512SPierre Schweitzer RtlInitUnicodeString(&UnicodeString, L"\\GLOBAL??"); 790*5d20d512SPierre Schweitzer InitializeObjectAttributes(&ObjectAttributes, 791*5d20d512SPierre Schweitzer &UnicodeString, 792*5d20d512SPierre Schweitzer OBJ_CASE_INSENSITIVE, 793*5d20d512SPierre Schweitzer NULL, 794*5d20d512SPierre Schweitzer NULL); 795*5d20d512SPierre Schweitzer Status = NtOpenDirectoryObject(&DirectoryHandle, 796*5d20d512SPierre Schweitzer DIRECTORY_QUERY, 797*5d20d512SPierre Schweitzer &ObjectAttributes); 798*5d20d512SPierre Schweitzer if (!NT_SUCCESS(Status)) 799*5d20d512SPierre Schweitzer { 800*5d20d512SPierre Schweitzer WARN("NtOpenDirectoryObject() failed (Status %lx)\n", Status); 801*5d20d512SPierre Schweitzer _SEH2_LEAVE; 802*5d20d512SPierre Schweitzer } 803*5d20d512SPierre Schweitzer 804*5d20d512SPierre Schweitzer /* 805*5d20d512SPierre Schweitzer * We'll query all entries at once, with a rather big buffer 806*5d20d512SPierre Schweitzer * If it's too small, we'll grow it by 2. 807*5d20d512SPierre Schweitzer * Limit the number of attempts to 3. 808*5d20d512SPierre Schweitzer */ 809*5d20d512SPierre Schweitzer for (i = 0; i < 3; ++i) 810*5d20d512SPierre Schweitzer { 811*5d20d512SPierre Schweitzer /* If we had no buffer from previous attempt, allocate one */ 812*5d20d512SPierre Schweitzer if (Buffer == NULL) 813*5d20d512SPierre Schweitzer { 814*5d20d512SPierre Schweitzer Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength); 815*5d20d512SPierre Schweitzer if (Buffer == NULL) 816*5d20d512SPierre Schweitzer { 817*5d20d512SPierre Schweitzer Status = STATUS_INSUFFICIENT_RESOURCES; 818*5d20d512SPierre Schweitzer _SEH2_LEAVE; 819*5d20d512SPierre Schweitzer } 820*5d20d512SPierre Schweitzer } 821*5d20d512SPierre Schweitzer 822*5d20d512SPierre Schweitzer /* Perform the query */ 823*5d20d512SPierre Schweitzer Status = NtQueryDirectoryObject(DirectoryHandle, 824*5d20d512SPierre Schweitzer Buffer, 825*5d20d512SPierre Schweitzer BufferLength, 826*5d20d512SPierre Schweitzer FALSE, 827*5d20d512SPierre Schweitzer TRUE, 828*5d20d512SPierre Schweitzer &Context, 829*5d20d512SPierre Schweitzer &ReturnLength); 830*5d20d512SPierre Schweitzer /* Only failure accepted is: no more entries */ 831*5d20d512SPierre Schweitzer if (!NT_SUCCESS(Status)) 832*5d20d512SPierre Schweitzer { 833*5d20d512SPierre Schweitzer if (Status != STATUS_NO_MORE_ENTRIES) 834*5d20d512SPierre Schweitzer { 835*5d20d512SPierre Schweitzer _SEH2_LEAVE; 836*5d20d512SPierre Schweitzer } 837*5d20d512SPierre Schweitzer 838*5d20d512SPierre Schweitzer /* 839*5d20d512SPierre Schweitzer * Which is a success! But break out, 840*5d20d512SPierre Schweitzer * it means our query returned no results 841*5d20d512SPierre Schweitzer * so, nothing to parse. 842*5d20d512SPierre Schweitzer */ 843*5d20d512SPierre Schweitzer Status = STATUS_SUCCESS; 844*5d20d512SPierre Schweitzer break; 845*5d20d512SPierre Schweitzer } 846*5d20d512SPierre Schweitzer 847*5d20d512SPierre Schweitzer /* In case we had them all, start browsing for devices */ 848*5d20d512SPierre Schweitzer if (Status != STATUS_MORE_ENTRIES) 849*5d20d512SPierre Schweitzer { 850*5d20d512SPierre Schweitzer DirInfo = Buffer; 851*5d20d512SPierre Schweitzer 852*5d20d512SPierre Schweitzer /* Loop until we find the nul entry (terminating entry) */ 853*5d20d512SPierre Schweitzer while (TRUE) 854*5d20d512SPierre Schweitzer { 855*5d20d512SPierre Schweitzer /* It's an entry full of zeroes */ 856*5d20d512SPierre Schweitzer if (RtlCompareMemory(&NullEntry, DirInfo, sizeof(NullEntry)) == sizeof(NullEntry)) 857*5d20d512SPierre Schweitzer { 858*5d20d512SPierre Schweitzer break; 859*5d20d512SPierre Schweitzer } 860*5d20d512SPierre Schweitzer 861*5d20d512SPierre Schweitzer /* Only handle symlinks */ 862*5d20d512SPierre Schweitzer if (!wcscmp(DirInfo->TypeName.Buffer, L"SymbolicLink")) 863*5d20d512SPierre Schweitzer { 864*5d20d512SPierre Schweitzer TRACE("Name: '%wZ'\n", &DirInfo->Name); 865*5d20d512SPierre Schweitzer 866*5d20d512SPierre Schweitzer /* 867*5d20d512SPierre Schweitzer * Now, we previously already browsed ??, and we 868*5d20d512SPierre Schweitzer * don't want to devices twice, so we'll check 869*5d20d512SPierre Schweitzer * the output buffer for duplicates. 870*5d20d512SPierre Schweitzer * We'll add our entry only if we don't have already 871*5d20d512SPierre Schweitzer * returned it. 872*5d20d512SPierre Schweitzer */ 873*5d20d512SPierre Schweitzer if (FindSymbolicLinkEntry(DirInfo->Name.Buffer, 874*5d20d512SPierre Schweitzer lpTargetPath, 875*5d20d512SPierre Schweitzer TotalEntries, 876*5d20d512SPierre Schweitzer &Found) == ERROR_SUCCESS && 877*5d20d512SPierre Schweitzer !Found) 878*5d20d512SPierre Schweitzer { 879*5d20d512SPierre Schweitzer /* Get name length in chars to only comparisons */ 880*5d20d512SPierre Schweitzer NameLength = DirInfo->Name.Length / sizeof(WCHAR); 881*5d20d512SPierre Schweitzer 882*5d20d512SPierre Schweitzer /* Make sure we don't overrun output buffer */ 883*5d20d512SPierre Schweitzer if (Length > ucchMax || 884*5d20d512SPierre Schweitzer NameLength > ucchMax - Length || 885*5d20d512SPierre Schweitzer ucchMax - NameLength - Length < sizeof(WCHAR)) 886*5d20d512SPierre Schweitzer { 887*5d20d512SPierre Schweitzer RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); 888*5d20d512SPierre Schweitzer NtClose(DirectoryHandle); 889*5d20d512SPierre Schweitzer BaseSetLastNTError(STATUS_BUFFER_TOO_SMALL); 890*5d20d512SPierre Schweitzer return 0; 891*5d20d512SPierre Schweitzer } 892*5d20d512SPierre Schweitzer 893*5d20d512SPierre Schweitzer /* Copy and NULL terminate string */ 894c2c66affSColin Finck memcpy(Ptr, DirInfo->Name.Buffer, DirInfo->Name.Length); 895*5d20d512SPierre Schweitzer Ptr[NameLength] = UNICODE_NULL; 896*5d20d512SPierre Schweitzer 897*5d20d512SPierre Schweitzer Ptr += (NameLength + 1); 898*5d20d512SPierre Schweitzer Length += (NameLength + 1); 899*5d20d512SPierre Schweitzer } 900*5d20d512SPierre Schweitzer } 901*5d20d512SPierre Schweitzer 902*5d20d512SPierre Schweitzer /* Move to the next entry */ 903*5d20d512SPierre Schweitzer ++DirInfo; 904*5d20d512SPierre Schweitzer } 905*5d20d512SPierre Schweitzer 906*5d20d512SPierre Schweitzer /* No need to loop again here, we got all the entries */ 907*5d20d512SPierre Schweitzer break; 908*5d20d512SPierre Schweitzer } 909*5d20d512SPierre Schweitzer 910*5d20d512SPierre Schweitzer /* Failure path here, we'll need bigger buffer */ 911*5d20d512SPierre Schweitzer RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); 912*5d20d512SPierre Schweitzer Buffer = NULL; 913*5d20d512SPierre Schweitzer 914*5d20d512SPierre Schweitzer /* We can't have bigger than that one, so leave */ 915*5d20d512SPierre Schweitzer if (BufferLength == MAXULONG) 916*5d20d512SPierre Schweitzer { 917*5d20d512SPierre Schweitzer break; 918*5d20d512SPierre Schweitzer } 919*5d20d512SPierre Schweitzer 920*5d20d512SPierre Schweitzer /* Prevent any overflow while computing new size */ 921*5d20d512SPierre Schweitzer if (MAXULONG - BufferLength < BufferLength) 922*5d20d512SPierre Schweitzer { 923*5d20d512SPierre Schweitzer BufferLength = MAXULONG; 924*5d20d512SPierre Schweitzer } 925*5d20d512SPierre Schweitzer else 926*5d20d512SPierre Schweitzer { 927*5d20d512SPierre Schweitzer BufferLength *= 2; 928*5d20d512SPierre Schweitzer } 929*5d20d512SPierre Schweitzer } 930*5d20d512SPierre Schweitzer 931*5d20d512SPierre Schweitzer /* 932*5d20d512SPierre Schweitzer * Out of the hot loop, but with more entries left? 933*5d20d512SPierre Schweitzer * that's an error case, leave here! 934*5d20d512SPierre Schweitzer */ 935*5d20d512SPierre Schweitzer if (Status == STATUS_MORE_ENTRIES) 936*5d20d512SPierre Schweitzer { 937*5d20d512SPierre Schweitzer Status = STATUS_BUFFER_TOO_SMALL; 938*5d20d512SPierre Schweitzer _SEH2_LEAVE; 939*5d20d512SPierre Schweitzer } 940*5d20d512SPierre Schweitzer } 941*5d20d512SPierre Schweitzer 942*5d20d512SPierre Schweitzer /* If we failed somewhere, just leave */ 943*5d20d512SPierre Schweitzer if (!NT_SUCCESS(Status)) 944*5d20d512SPierre Schweitzer { 945*5d20d512SPierre Schweitzer _SEH2_LEAVE; 946*5d20d512SPierre Schweitzer } 947*5d20d512SPierre Schweitzer 948*5d20d512SPierre Schweitzer /* If we returned no entries, time to write the empty string */ 949*5d20d512SPierre Schweitzer if (Length == 0) 950*5d20d512SPierre Schweitzer { 951*5d20d512SPierre Schweitzer /* Unless output buffer is too small! */ 952*5d20d512SPierre Schweitzer if (ucchMax <= 0) 953*5d20d512SPierre Schweitzer { 954*5d20d512SPierre Schweitzer Status = STATUS_BUFFER_TOO_SMALL; 955*5d20d512SPierre Schweitzer _SEH2_LEAVE; 956*5d20d512SPierre Schweitzer } 957*5d20d512SPierre Schweitzer 958*5d20d512SPierre Schweitzer /* Emptry string is one char (terminator!) */ 959c2c66affSColin Finck *Ptr = UNICODE_NULL; 960*5d20d512SPierre Schweitzer ++Ptr; 961*5d20d512SPierre Schweitzer Length = 1; 962c2c66affSColin Finck } 963c2c66affSColin Finck 964*5d20d512SPierre Schweitzer /* 965*5d20d512SPierre Schweitzer * If we have enough room, we need to double terminate the buffer: 966*5d20d512SPierre Schweitzer * that's a MULTI_SZ buffer, its end is marked by double NULL. 967*5d20d512SPierre Schweitzer * One was already added during the "copy string" process. 968*5d20d512SPierre Schweitzer * If we don't have enough room: that's a failure case. 969*5d20d512SPierre Schweitzer */ 970*5d20d512SPierre Schweitzer if (Length < ucchMax) 971*5d20d512SPierre Schweitzer { 972*5d20d512SPierre Schweitzer *Ptr = UNICODE_NULL; 973*5d20d512SPierre Schweitzer ++Ptr; 974c2c66affSColin Finck } 975*5d20d512SPierre Schweitzer else 976*5d20d512SPierre Schweitzer { 977*5d20d512SPierre Schweitzer Status = STATUS_BUFFER_TOO_SMALL; 978*5d20d512SPierre Schweitzer } 979*5d20d512SPierre Schweitzer } 980*5d20d512SPierre Schweitzer _SEH2_FINALLY 981*5d20d512SPierre Schweitzer { 982*5d20d512SPierre Schweitzer if (DirectoryHandle != 0) 983*5d20d512SPierre Schweitzer { 984c2c66affSColin Finck NtClose(DirectoryHandle); 985c2c66affSColin Finck } 986c2c66affSColin Finck 987*5d20d512SPierre Schweitzer if (Buffer != NULL) 988*5d20d512SPierre Schweitzer { 989*5d20d512SPierre Schweitzer RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); 990*5d20d512SPierre Schweitzer } 991*5d20d512SPierre Schweitzer 992*5d20d512SPierre Schweitzer if (!NT_SUCCESS(Status)) 993*5d20d512SPierre Schweitzer { 994*5d20d512SPierre Schweitzer Length = 0; 995*5d20d512SPierre Schweitzer BaseSetLastNTError(Status); 996*5d20d512SPierre Schweitzer } 997*5d20d512SPierre Schweitzer } 998*5d20d512SPierre Schweitzer _SEH2_END; 999*5d20d512SPierre Schweitzer 1000c2c66affSColin Finck return Length; 1001c2c66affSColin Finck } 1002c2c66affSColin Finck 1003c2c66affSColin Finck /* EOF */ 1004