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) 75d20d512SPierre 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 */ 265d20d512SPierre Schweitzer NTSTATUS 275d20d512SPierre Schweitzer IsGlobalDeviceMap( 285d20d512SPierre Schweitzer HANDLE DirectoryHandle, 295d20d512SPierre Schweitzer PBOOLEAN IsGlobal) 305d20d512SPierre Schweitzer { 315d20d512SPierre Schweitzer NTSTATUS Status; 325d20d512SPierre Schweitzer DWORD ReturnLength; 335d20d512SPierre Schweitzer UNICODE_STRING GlobalString; 345d20d512SPierre Schweitzer OBJECT_NAME_INFORMATION NameInfo, *PNameInfo; 355d20d512SPierre Schweitzer 365d20d512SPierre Schweitzer /* We need both parameters */ 375d20d512SPierre Schweitzer if (DirectoryHandle == 0 || IsGlobal == NULL) 385d20d512SPierre Schweitzer { 395d20d512SPierre Schweitzer return STATUS_INVALID_PARAMETER; 405d20d512SPierre Schweitzer } 415d20d512SPierre Schweitzer 425d20d512SPierre Schweitzer PNameInfo = NULL; 435d20d512SPierre Schweitzer _SEH2_TRY 445d20d512SPierre Schweitzer { 455d20d512SPierre Schweitzer /* Query handle information */ 465d20d512SPierre Schweitzer Status = NtQueryObject(DirectoryHandle, 475d20d512SPierre Schweitzer ObjectNameInformation, 485d20d512SPierre Schweitzer &NameInfo, 495d20d512SPierre Schweitzer 0, 505d20d512SPierre Schweitzer &ReturnLength); 515d20d512SPierre Schweitzer /* Only failure we tolerate is length mismatch */ 525d20d512SPierre Schweitzer if (NT_SUCCESS(Status) || Status == STATUS_INFO_LENGTH_MISMATCH) 535d20d512SPierre Schweitzer { 545d20d512SPierre Schweitzer /* Allocate big enough buffer */ 555d20d512SPierre Schweitzer PNameInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, ReturnLength); 565d20d512SPierre Schweitzer if (PNameInfo == NULL) 575d20d512SPierre Schweitzer { 585d20d512SPierre Schweitzer Status = STATUS_NO_MEMORY; 595d20d512SPierre Schweitzer _SEH2_LEAVE; 605d20d512SPierre Schweitzer } 615d20d512SPierre Schweitzer 625d20d512SPierre Schweitzer /* Query again handle information */ 635d20d512SPierre Schweitzer Status = NtQueryObject(DirectoryHandle, 645d20d512SPierre Schweitzer ObjectNameInformation, 655d20d512SPierre Schweitzer PNameInfo, 665d20d512SPierre Schweitzer ReturnLength, 675d20d512SPierre Schweitzer &ReturnLength); 685d20d512SPierre Schweitzer 695d20d512SPierre Schweitzer /* 705d20d512SPierre Schweitzer * If it succeed, check we have Global?? 715d20d512SPierre Schweitzer * If so, return success 725d20d512SPierre Schweitzer */ 735d20d512SPierre Schweitzer if (NT_SUCCESS(Status)) 745d20d512SPierre Schweitzer { 755d20d512SPierre Schweitzer RtlInitUnicodeString(&GlobalString, L"\\GLOBAL??"); 765d20d512SPierre Schweitzer *IsGlobal = RtlEqualUnicodeString(&GlobalString, &PNameInfo->Name, FALSE); 775d20d512SPierre Schweitzer Status = STATUS_SUCCESS; 785d20d512SPierre Schweitzer } 795d20d512SPierre Schweitzer 805d20d512SPierre Schweitzer 815d20d512SPierre Schweitzer } 825d20d512SPierre Schweitzer } 835d20d512SPierre Schweitzer _SEH2_FINALLY 845d20d512SPierre Schweitzer { 855d20d512SPierre Schweitzer if (PNameInfo != NULL) 865d20d512SPierre Schweitzer { 875d20d512SPierre Schweitzer RtlFreeHeap(RtlGetProcessHeap(), 0, PNameInfo); 885d20d512SPierre Schweitzer } 895d20d512SPierre Schweitzer } 905d20d512SPierre Schweitzer _SEH2_END; 915d20d512SPierre Schweitzer 925d20d512SPierre Schweitzer return Status; 935d20d512SPierre Schweitzer } 945d20d512SPierre Schweitzer 955d20d512SPierre Schweitzer /* 965d20d512SPierre Schweitzer * @implemented 975d20d512SPierre Schweitzer */ 985d20d512SPierre Schweitzer DWORD 995d20d512SPierre Schweitzer FindSymbolicLinkEntry( 1005d20d512SPierre Schweitzer PWSTR NameToFind, 1015d20d512SPierre Schweitzer PWSTR NamesList, 1025d20d512SPierre Schweitzer DWORD TotalEntries, 1035d20d512SPierre Schweitzer PBOOLEAN Found) 1045d20d512SPierre Schweitzer { 1055d20d512SPierre Schweitzer WCHAR Current; 1065d20d512SPierre Schweitzer DWORD Entries; 1075d20d512SPierre Schweitzer PWSTR PartialNamesList; 1085d20d512SPierre Schweitzer 1095d20d512SPierre Schweitzer /* We need all parameters to be set */ 1105d20d512SPierre Schweitzer if (NameToFind == NULL || NamesList == NULL || Found == NULL) 1115d20d512SPierre Schweitzer { 1125d20d512SPierre Schweitzer return ERROR_INVALID_PARAMETER; 1135d20d512SPierre Schweitzer } 1145d20d512SPierre Schweitzer 1155d20d512SPierre Schweitzer /* Assume failure */ 1165d20d512SPierre Schweitzer *Found = FALSE; 1175d20d512SPierre Schweitzer 1185d20d512SPierre Schweitzer /* If no entries, job done, nothing found */ 1195d20d512SPierre Schweitzer if (TotalEntries == 0) 1205d20d512SPierre Schweitzer { 1215d20d512SPierre Schweitzer return ERROR_SUCCESS; 1225d20d512SPierre Schweitzer } 1235d20d512SPierre Schweitzer 1245d20d512SPierre Schweitzer /* Start browsing the names list */ 1255d20d512SPierre Schweitzer Entries = 0; 1265d20d512SPierre Schweitzer PartialNamesList = NamesList; 1275d20d512SPierre Schweitzer /* As long as we didn't find the name... */ 1285d20d512SPierre Schweitzer while (wcscmp(NameToFind, PartialNamesList) != 0) 1295d20d512SPierre Schweitzer { 1305d20d512SPierre Schweitzer /* We chomped an entry! */ 1315d20d512SPierre Schweitzer ++Entries; 1325d20d512SPierre Schweitzer 1335d20d512SPierre Schweitzer /* We're out of entries, bail out not to overrun */ 1345d20d512SPierre Schweitzer if (Entries > TotalEntries) 1355d20d512SPierre Schweitzer { 1365d20d512SPierre Schweitzer /* 1375d20d512SPierre Schweitzer * Even though we found nothing, 1385d20d512SPierre Schweitzer * the function ran fine 1395d20d512SPierre Schweitzer */ 1405d20d512SPierre Schweitzer return ERROR_SUCCESS; 1415d20d512SPierre Schweitzer } 1425d20d512SPierre Schweitzer 1435d20d512SPierre Schweitzer /* Jump to the next string */ 1445d20d512SPierre Schweitzer do 1455d20d512SPierre Schweitzer { 1465d20d512SPierre Schweitzer Current = *PartialNamesList; 1475d20d512SPierre Schweitzer ++PartialNamesList; 1485d20d512SPierre Schweitzer } while (Current != UNICODE_NULL); 1495d20d512SPierre Schweitzer } 1505d20d512SPierre Schweitzer 1515d20d512SPierre Schweitzer /* 1525d20d512SPierre Schweitzer * We're here because the loop stopped: 1535d20d512SPierre Schweitzer * it means we found the name in the list 1545d20d512SPierre Schweitzer */ 1555d20d512SPierre Schweitzer *Found = TRUE; 1565d20d512SPierre Schweitzer return ERROR_SUCCESS; 1575d20d512SPierre Schweitzer } 1585d20d512SPierre Schweitzer 1595d20d512SPierre Schweitzer /* 1605d20d512SPierre Schweitzer * @implemented 1615d20d512SPierre 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 HANDLE hUser32; 248c2c66affSColin Finck DEV_BROADCAST_VOLUME dbcv; 249c2c66affSColin Finck DWORD dwRecipients; 250c2c66affSColin Finck typedef long (WINAPI *BSM_type)(DWORD, LPDWORD, UINT, WPARAM, LPARAM); 251c2c66affSColin Finck BSM_type BSM_ptr; 252*204bfa85SPierre Schweitzer BOOLEAN LUIDDeviceMapsEnabled; 253*204bfa85SPierre Schweitzer WCHAR Letter; 254*204bfa85SPierre Schweitzer WPARAM wParam; 255c2c66affSColin Finck 256*204bfa85SPierre Schweitzer /* Get status about local device mapping */ 257*204bfa85SPierre Schweitzer LUIDDeviceMapsEnabled = BaseStaticServerData->LUIDDeviceMapsEnabled; 258*204bfa85SPierre Schweitzer 259*204bfa85SPierre Schweitzer /* Validate input & flags */ 260*204bfa85SPierre Schweitzer if ((dwFlags & 0xFFFFFFE0) || 261c2c66affSColin Finck ((dwFlags & DDD_EXACT_MATCH_ON_REMOVE) && 262*204bfa85SPierre Schweitzer !(dwFlags & DDD_REMOVE_DEFINITION)) || 263*204bfa85SPierre Schweitzer (lpTargetPath == NULL && !(dwFlags & (DDD_LUID_BROADCAST_DRIVE | DDD_REMOVE_DEFINITION))) || 264*204bfa85SPierre Schweitzer ((dwFlags & DDD_LUID_BROADCAST_DRIVE) && 265*204bfa85SPierre Schweitzer (lpDeviceName == NULL || lpTargetPath != NULL || dwFlags & (DDD_NO_BROADCAST_SYSTEM | DDD_EXACT_MATCH_ON_REMOVE | DDD_RAW_TARGET_PATH) || !LUIDDeviceMapsEnabled))) 266c2c66affSColin Finck { 267c2c66affSColin Finck SetLastError(ERROR_INVALID_PARAMETER); 268c2c66affSColin Finck return FALSE; 269c2c66affSColin Finck } 270c2c66affSColin Finck 271*204bfa85SPierre Schweitzer /* Initialize device unicode string to ease its use */ 272*204bfa85SPierre Schweitzer RtlInitUnicodeString(&DeviceNameU, lpDeviceName); 273*204bfa85SPierre Schweitzer 274*204bfa85SPierre Schweitzer /* The buffer for CSR call will contain it */ 275*204bfa85SPierre Schweitzer BufferSize = DeviceNameU.MaximumLength; 276c2c66affSColin Finck ArgumentCount = 1; 277*204bfa85SPierre Schweitzer 278*204bfa85SPierre Schweitzer /* If we don't have target path, use empty string */ 279*204bfa85SPierre Schweitzer if (lpTargetPath == NULL) 280c2c66affSColin Finck { 281*204bfa85SPierre Schweitzer RtlInitUnicodeString(&NtTargetPathU, NULL); 282c2c66affSColin Finck } 283c2c66affSColin Finck else 284c2c66affSColin Finck { 285*204bfa85SPierre Schweitzer /* Else, use it raw if asked to */ 286c2c66affSColin Finck if (dwFlags & DDD_RAW_TARGET_PATH) 287c2c66affSColin Finck { 288*204bfa85SPierre Schweitzer RtlInitUnicodeString(&NtTargetPathU, lpTargetPath); 289c2c66affSColin Finck } 290c2c66affSColin Finck else 291c2c66affSColin Finck { 292*204bfa85SPierre Schweitzer /* Otherwise, use it converted */ 293c2c66affSColin Finck if (!RtlDosPathNameToNtPathName_U(lpTargetPath, 294c2c66affSColin Finck &NtTargetPathU, 295c2c66affSColin Finck NULL, 296c2c66affSColin Finck NULL)) 297c2c66affSColin Finck { 298c2c66affSColin Finck WARN("RtlDosPathNameToNtPathName_U() failed\n"); 299c2c66affSColin Finck BaseSetLastNTError(STATUS_OBJECT_NAME_INVALID); 300c2c66affSColin Finck return FALSE; 301c2c66affSColin Finck } 302c2c66affSColin Finck } 303*204bfa85SPierre Schweitzer 304*204bfa85SPierre Schweitzer /* This target path will be the second arg */ 305c2c66affSColin Finck ArgumentCount = 2; 306*204bfa85SPierre Schweitzer BufferSize += NtTargetPathU.MaximumLength; 307c2c66affSColin Finck } 308c2c66affSColin Finck 309*204bfa85SPierre Schweitzer /* Allocate the capture buffer for our strings */ 310c2c66affSColin Finck CaptureBuffer = CsrAllocateCaptureBuffer(ArgumentCount, 311c2c66affSColin Finck BufferSize); 312*204bfa85SPierre Schweitzer if (CaptureBuffer == NULL) 313c2c66affSColin Finck { 314*204bfa85SPierre Schweitzer if (!(dwFlags & DDD_RAW_TARGET_PATH)) 315*204bfa85SPierre Schweitzer { 316*204bfa85SPierre Schweitzer RtlFreeUnicodeString(&NtTargetPathU); 317c2c66affSColin Finck } 318*204bfa85SPierre Schweitzer 319*204bfa85SPierre Schweitzer SetLastError(ERROR_NOT_ENOUGH_MEMORY); 320*204bfa85SPierre Schweitzer return FALSE; 321*204bfa85SPierre Schweitzer } 322*204bfa85SPierre Schweitzer 323*204bfa85SPierre Schweitzer /* Set the flags */ 324c2c66affSColin Finck DefineDosDeviceRequest->Flags = dwFlags; 325c2c66affSColin Finck 326*204bfa85SPierre Schweitzer /* Allocate a buffer for the device name */ 327*204bfa85SPierre Schweitzer DefineDosDeviceRequest->DeviceName.MaximumLength = CsrAllocateMessagePointer(CaptureBuffer, 328*204bfa85SPierre Schweitzer DeviceNameU.MaximumLength, 329c2c66affSColin Finck (PVOID*)&DefineDosDeviceRequest->DeviceName.Buffer); 330*204bfa85SPierre Schweitzer /* And copy it while upcasing it */ 331*204bfa85SPierre Schweitzer RtlUpcaseUnicodeString(&DefineDosDeviceRequest->DeviceName, &DeviceNameU, FALSE); 332c2c66affSColin Finck 333*204bfa85SPierre Schweitzer /* If we have a target path, copy it too, and free it if allocated */ 334*204bfa85SPierre Schweitzer if (NtTargetPathU.Length != 0) 335c2c66affSColin Finck { 336*204bfa85SPierre Schweitzer DefineDosDeviceRequest->TargetPath.MaximumLength = CsrAllocateMessagePointer(CaptureBuffer, 337*204bfa85SPierre Schweitzer NtTargetPathU.MaximumLength, 338c2c66affSColin Finck (PVOID*)&DefineDosDeviceRequest->TargetPath.Buffer); 339*204bfa85SPierre Schweitzer RtlCopyUnicodeString(&DefineDosDeviceRequest->TargetPath, &NtTargetPathU); 340c2c66affSColin Finck 341*204bfa85SPierre Schweitzer if (!(dwFlags & DDD_RAW_TARGET_PATH)) 342*204bfa85SPierre Schweitzer { 343*204bfa85SPierre Schweitzer RtlFreeUnicodeString(&NtTargetPathU); 344*204bfa85SPierre Schweitzer } 345*204bfa85SPierre Schweitzer } 346*204bfa85SPierre Schweitzer /* Otherwise, null initialize the string */ 347*204bfa85SPierre Schweitzer else 348*204bfa85SPierre Schweitzer { 349*204bfa85SPierre Schweitzer RtlInitUnicodeString(&DefineDosDeviceRequest->TargetPath, NULL); 350*204bfa85SPierre Schweitzer } 351*204bfa85SPierre Schweitzer 352*204bfa85SPierre Schweitzer /* Finally, call the server */ 353c2c66affSColin Finck CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage, 354c2c66affSColin Finck CaptureBuffer, 355c2c66affSColin Finck CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepDefineDosDevice), 356c2c66affSColin Finck sizeof(*DefineDosDeviceRequest)); 357c2c66affSColin Finck CsrFreeCaptureBuffer(CaptureBuffer); 358c2c66affSColin Finck 359*204bfa85SPierre Schweitzer /* Return failure if any */ 360c2c66affSColin Finck if (!NT_SUCCESS(ApiMessage.Status)) 361c2c66affSColin Finck { 362c2c66affSColin Finck WARN("CsrClientCallServer() failed (Status %lx)\n", ApiMessage.Status); 363c2c66affSColin Finck BaseSetLastNTError(ApiMessage.Status); 364*204bfa85SPierre Schweitzer return FALSE; 365c2c66affSColin Finck } 366*204bfa85SPierre Schweitzer 367*204bfa85SPierre Schweitzer /* Here is the success path, we will always return true */ 368*204bfa85SPierre Schweitzer 369*204bfa85SPierre Schweitzer /* Should broadcast the event? Only do if not denied and if drive letter */ 370c2c66affSColin Finck if (!(dwFlags & DDD_NO_BROADCAST_SYSTEM) && 371*204bfa85SPierre Schweitzer DeviceNameU.Length == 2 * sizeof(WCHAR) && 372*204bfa85SPierre Schweitzer DeviceNameU.Buffer[1] == L':') 373c2c66affSColin Finck { 374*204bfa85SPierre Schweitzer /* Make sure letter is valid and there are no local device mappings */ 375*204bfa85SPierre Schweitzer Letter = RtlUpcaseUnicodeChar(DeviceNameU.Buffer[0]) - L'A'; 376*204bfa85SPierre Schweitzer if (Letter < 26 && !LUIDDeviceMapsEnabled) 377c2c66affSColin Finck { 378*204bfa85SPierre Schweitzer /* Rely on user32 for broadcasting */ 379*204bfa85SPierre Schweitzer hUser32 = LoadLibraryW(L"user32.dll"); 380*204bfa85SPierre Schweitzer if (hUser32 != 0) 381*204bfa85SPierre Schweitzer { 382*204bfa85SPierre Schweitzer /* Get the function pointer */ 383*204bfa85SPierre Schweitzer BSM_ptr = (BSM_type)GetProcAddress(hUser32, "BroadcastSystemMessageW"); 384c2c66affSColin Finck if (BSM_ptr) 385c2c66affSColin Finck { 386*204bfa85SPierre Schweitzer /* Set our target */ 387c2c66affSColin Finck dwRecipients = BSM_APPLICATIONS; 388*204bfa85SPierre Schweitzer 389*204bfa85SPierre Schweitzer /* And initialize our structure */ 390c2c66affSColin Finck dbcv.dbcv_size = sizeof(DEV_BROADCAST_VOLUME); 391c2c66affSColin Finck dbcv.dbcv_devicetype = DBT_DEVTYP_VOLUME; 392c2c66affSColin Finck dbcv.dbcv_reserved = 0; 393*204bfa85SPierre Schweitzer 394*204bfa85SPierre Schweitzer /* Set the volume which had the event */ 395*204bfa85SPierre Schweitzer dbcv.dbcv_unitmask = 1 << Letter; 396c2c66affSColin Finck dbcv.dbcv_flags = DBTF_NET; 397*204bfa85SPierre Schweitzer 398*204bfa85SPierre Schweitzer /* And properly set the event (removal or arrival?) */ 399*204bfa85SPierre Schweitzer wParam = (dwFlags & DDD_REMOVE_DEFINITION) ? DBT_DEVICEREMOVECOMPLETE : DBT_DEVICEARRIVAL; 400*204bfa85SPierre Schweitzer 401*204bfa85SPierre Schweitzer /* And broadcast! */ 402*204bfa85SPierre Schweitzer BSM_ptr(BSF_SENDNOTIFYMESSAGE | BSF_FLUSHDISK, 403c2c66affSColin Finck &dwRecipients, 404c2c66affSColin Finck WM_DEVICECHANGE, 405*204bfa85SPierre Schweitzer wParam, 406c2c66affSColin Finck (LPARAM)&dbcv); 407c2c66affSColin Finck } 408*204bfa85SPierre Schweitzer 409*204bfa85SPierre Schweitzer /* We're done! */ 410c2c66affSColin Finck FreeLibrary(hUser32); 411c2c66affSColin Finck } 412c2c66affSColin Finck } 413c2c66affSColin Finck } 414c2c66affSColin Finck 415*204bfa85SPierre Schweitzer return TRUE; 416c2c66affSColin Finck } 417c2c66affSColin Finck 418c2c66affSColin Finck 419c2c66affSColin Finck /* 420c2c66affSColin Finck * @implemented 421c2c66affSColin Finck */ 422c2c66affSColin Finck DWORD 423c2c66affSColin Finck WINAPI 424c2c66affSColin Finck QueryDosDeviceA( 425c2c66affSColin Finck LPCSTR lpDeviceName, 426c2c66affSColin Finck LPSTR lpTargetPath, 427c2c66affSColin Finck DWORD ucchMax 428c2c66affSColin Finck ) 429c2c66affSColin Finck { 4308d128aa4SPierre Schweitzer NTSTATUS Status; 4318d128aa4SPierre Schweitzer USHORT CurrentPosition; 4328d128aa4SPierre Schweitzer ANSI_STRING AnsiString; 433c2c66affSColin Finck UNICODE_STRING TargetPathU; 4348d128aa4SPierre Schweitzer PUNICODE_STRING DeviceNameU; 4358d128aa4SPierre Schweitzer DWORD RetLength, CurrentLength, Length; 4368d128aa4SPierre Schweitzer PWSTR DeviceNameBuffer, TargetPathBuffer; 437c2c66affSColin Finck 4388d128aa4SPierre Schweitzer /* If we want a specific device name, convert it */ 4398d128aa4SPierre Schweitzer if (lpDeviceName != NULL) 440c2c66affSColin Finck { 4418d128aa4SPierre Schweitzer /* Convert DeviceName using static unicode string */ 4428d128aa4SPierre Schweitzer RtlInitAnsiString(&AnsiString, lpDeviceName); 4438d128aa4SPierre Schweitzer DeviceNameU = &NtCurrentTeb()->StaticUnicodeString; 4448d128aa4SPierre Schweitzer Status = RtlAnsiStringToUnicodeString(DeviceNameU, &AnsiString, FALSE); 4458d128aa4SPierre Schweitzer if (!NT_SUCCESS(Status)) 4468d128aa4SPierre Schweitzer { 4478d128aa4SPierre Schweitzer /* 4488d128aa4SPierre Schweitzer * If the static unicode string is too small, 4498d128aa4SPierre Schweitzer * it's because the name is too long... 4508d128aa4SPierre Schweitzer * so, return appropriate status! 4518d128aa4SPierre Schweitzer */ 4528d128aa4SPierre Schweitzer if (Status == STATUS_BUFFER_OVERFLOW) 4538d128aa4SPierre Schweitzer { 4548d128aa4SPierre Schweitzer SetLastError(ERROR_FILENAME_EXCED_RANGE); 4558d128aa4SPierre Schweitzer return FALSE; 4568d128aa4SPierre Schweitzer } 4578d128aa4SPierre Schweitzer 4588d128aa4SPierre Schweitzer BaseSetLastNTError(Status); 4598d128aa4SPierre Schweitzer return FALSE; 4608d128aa4SPierre Schweitzer } 4618d128aa4SPierre Schweitzer 4628d128aa4SPierre Schweitzer DeviceNameBuffer = DeviceNameU->Buffer; 4638d128aa4SPierre Schweitzer } 4648d128aa4SPierre Schweitzer else 4658d128aa4SPierre Schweitzer { 4668d128aa4SPierre Schweitzer DeviceNameBuffer = NULL; 4678d128aa4SPierre Schweitzer } 4688d128aa4SPierre Schweitzer 4698d128aa4SPierre Schweitzer /* Allocate the output buffer for W call */ 4708d128aa4SPierre Schweitzer TargetPathBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, ucchMax * sizeof(WCHAR)); 4718d128aa4SPierre Schweitzer if (TargetPathBuffer == NULL) 472c2c66affSColin Finck { 473c2c66affSColin Finck SetLastError(ERROR_NOT_ENOUGH_MEMORY); 474c2c66affSColin Finck return 0; 475c2c66affSColin Finck } 4768d128aa4SPierre Schweitzer 4778d128aa4SPierre Schweitzer /* Call W */ 4788d128aa4SPierre Schweitzer Length = QueryDosDeviceW(DeviceNameBuffer, TargetPathBuffer, ucchMax); 4798d128aa4SPierre Schweitzer /* We'll return that length in case of a success */ 4808d128aa4SPierre Schweitzer RetLength = Length; 4818d128aa4SPierre Schweitzer 4828d128aa4SPierre Schweitzer /* Handle the case where we would fill output buffer completly */ 4838d128aa4SPierre Schweitzer if (Length != 0 && Length == ucchMax) 484c2c66affSColin Finck { 4858d128aa4SPierre Schweitzer /* This will be our work length (but not the one we return) */ 4868d128aa4SPierre Schweitzer --Length; 4878d128aa4SPierre Schweitzer /* Already 0 the last char */ 4888d128aa4SPierre Schweitzer lpTargetPath[Length] = ANSI_NULL; 489c2c66affSColin Finck } 490c2c66affSColin Finck 4918d128aa4SPierre Schweitzer /* If we had an output, start the convert loop */ 492c2c66affSColin Finck if (Length != 0) 493c2c66affSColin Finck { 4948d128aa4SPierre Schweitzer /* 4958d128aa4SPierre Schweitzer * We'll have to loop because TargetPathBuffer may contain 4968d128aa4SPierre Schweitzer * several strings (NULL separated) 4978d128aa4SPierre Schweitzer * We'll start at position 0 4988d128aa4SPierre Schweitzer */ 4998d128aa4SPierre Schweitzer CurrentPosition = 0; 5008d128aa4SPierre Schweitzer while (CurrentPosition < Length) 501c2c66affSColin Finck { 5028d128aa4SPierre Schweitzer /* Get the maximum length */ 5038d128aa4SPierre Schweitzer CurrentLength = min(Length - CurrentPosition, MAXUSHORT / 2); 504c2c66affSColin Finck 5058d128aa4SPierre Schweitzer /* Initialize our output string */ 5068d128aa4SPierre Schweitzer AnsiString.Length = 0; 5078d128aa4SPierre Schweitzer AnsiString.MaximumLength = CurrentLength + sizeof(ANSI_NULL); 5088d128aa4SPierre Schweitzer AnsiString.Buffer = &lpTargetPath[CurrentPosition]; 509c2c66affSColin Finck 5108d128aa4SPierre Schweitzer /* Initialize input string that will be converted */ 5118d128aa4SPierre Schweitzer TargetPathU.Length = CurrentLength * sizeof(WCHAR); 5128d128aa4SPierre Schweitzer TargetPathU.MaximumLength = CurrentLength * sizeof(WCHAR) + sizeof(UNICODE_NULL); 5138d128aa4SPierre Schweitzer TargetPathU.Buffer = &TargetPathBuffer[CurrentPosition]; 514c2c66affSColin Finck 5158d128aa4SPierre Schweitzer /* Convert to ANSI */ 5168d128aa4SPierre Schweitzer Status = RtlUnicodeStringToAnsiString(&AnsiString, &TargetPathU, FALSE); 5178d128aa4SPierre Schweitzer if (!NT_SUCCESS(Status)) 518c2c66affSColin Finck { 5198d128aa4SPierre Schweitzer BaseSetLastNTError(Status); 5208d128aa4SPierre Schweitzer /* In case of a failure, forget about everything */ 5218d128aa4SPierre Schweitzer RetLength = 0; 5228d128aa4SPierre Schweitzer 5238d128aa4SPierre Schweitzer goto Leave; 524c2c66affSColin Finck } 5258d128aa4SPierre Schweitzer 5268d128aa4SPierre Schweitzer /* Move to the next string */ 5278d128aa4SPierre Schweitzer CurrentPosition += CurrentLength; 5288d128aa4SPierre Schweitzer } 5298d128aa4SPierre Schweitzer } 5308d128aa4SPierre Schweitzer 5318d128aa4SPierre Schweitzer Leave: 5328d128aa4SPierre Schweitzer /* Free our intermediate buffer and leave */ 5338d128aa4SPierre Schweitzer RtlFreeHeap(RtlGetProcessHeap(), 0, TargetPathBuffer); 5348d128aa4SPierre Schweitzer 5358d128aa4SPierre Schweitzer return RetLength; 536c2c66affSColin Finck } 537c2c66affSColin Finck 538c2c66affSColin Finck 539c2c66affSColin Finck /* 540c2c66affSColin Finck * @implemented 541c2c66affSColin Finck */ 542c2c66affSColin Finck DWORD 543c2c66affSColin Finck WINAPI 544c2c66affSColin Finck QueryDosDeviceW( 545c2c66affSColin Finck LPCWSTR lpDeviceName, 546c2c66affSColin Finck LPWSTR lpTargetPath, 547c2c66affSColin Finck DWORD ucchMax 548c2c66affSColin Finck ) 549c2c66affSColin Finck { 550c2c66affSColin Finck PWSTR Ptr; 5515d20d512SPierre Schweitzer PVOID Buffer; 5525d20d512SPierre Schweitzer NTSTATUS Status; 5535d20d512SPierre Schweitzer USHORT i, TotalEntries; 5545d20d512SPierre Schweitzer UNICODE_STRING UnicodeString; 5555d20d512SPierre Schweitzer OBJECT_ATTRIBUTES ObjectAttributes; 5565d20d512SPierre Schweitzer HANDLE DirectoryHandle, DeviceHandle; 5575d20d512SPierre Schweitzer BOOLEAN IsGlobal, GlobalNeeded, Found; 5585d20d512SPierre Schweitzer POBJECT_DIRECTORY_INFORMATION DirInfo; 5595d20d512SPierre Schweitzer OBJECT_DIRECTORY_INFORMATION NullEntry = {{0}}; 5605d20d512SPierre Schweitzer ULONG ReturnLength, NameLength, Length, Context, BufferLength; 561c2c66affSColin Finck 562c2c66affSColin Finck /* Open the '\??' directory */ 563c2c66affSColin Finck RtlInitUnicodeString(&UnicodeString, L"\\??"); 564c2c66affSColin Finck InitializeObjectAttributes(&ObjectAttributes, 565c2c66affSColin Finck &UnicodeString, 566c2c66affSColin Finck OBJ_CASE_INSENSITIVE, 567c2c66affSColin Finck NULL, 568c2c66affSColin Finck NULL); 569c2c66affSColin Finck Status = NtOpenDirectoryObject(&DirectoryHandle, 570c2c66affSColin Finck DIRECTORY_QUERY, 571c2c66affSColin Finck &ObjectAttributes); 572c2c66affSColin Finck if (!NT_SUCCESS(Status)) 573c2c66affSColin Finck { 574c2c66affSColin Finck WARN("NtOpenDirectoryObject() failed (Status %lx)\n", Status); 575c2c66affSColin Finck BaseSetLastNTError(Status); 576c2c66affSColin Finck return 0; 577c2c66affSColin Finck } 578c2c66affSColin Finck 5795d20d512SPierre Schweitzer Buffer = NULL; 5805d20d512SPierre Schweitzer _SEH2_TRY 5815d20d512SPierre Schweitzer { 582c2c66affSColin Finck if (lpDeviceName != NULL) 583c2c66affSColin Finck { 584c2c66affSColin Finck /* Open the lpDeviceName link object */ 5855d20d512SPierre Schweitzer RtlInitUnicodeString(&UnicodeString, lpDeviceName); 586c2c66affSColin Finck InitializeObjectAttributes(&ObjectAttributes, 587c2c66affSColin Finck &UnicodeString, 588c2c66affSColin Finck OBJ_CASE_INSENSITIVE, 589c2c66affSColin Finck DirectoryHandle, 590c2c66affSColin Finck NULL); 591c2c66affSColin Finck Status = NtOpenSymbolicLinkObject(&DeviceHandle, 592c2c66affSColin Finck SYMBOLIC_LINK_QUERY, 593c2c66affSColin Finck &ObjectAttributes); 594c2c66affSColin Finck if (!NT_SUCCESS(Status)) 595c2c66affSColin Finck { 596c2c66affSColin Finck WARN("NtOpenSymbolicLinkObject() failed (Status %lx)\n", Status); 5975d20d512SPierre Schweitzer _SEH2_LEAVE; 598c2c66affSColin Finck } 599c2c66affSColin Finck 6005d20d512SPierre Schweitzer /* 6015d20d512SPierre Schweitzer * Make sure we don't overrun the output buffer, so convert our DWORD 6025d20d512SPierre Schweitzer * size to USHORT size properly 6035d20d512SPierre Schweitzer */ 6045d20d512SPierre Schweitzer Length = (ucchMax <= MAXULONG / sizeof(WCHAR)) ? (ucchMax * sizeof(WCHAR)) : MAXULONG; 6055d20d512SPierre Schweitzer 606c2c66affSColin Finck /* Query link target */ 607c2c66affSColin Finck UnicodeString.Length = 0; 6085d20d512SPierre Schweitzer UnicodeString.MaximumLength = Length <= MAXUSHORT ? Length : MAXUSHORT; 609c2c66affSColin Finck UnicodeString.Buffer = lpTargetPath; 610c2c66affSColin Finck 611c2c66affSColin Finck ReturnLength = 0; 612c2c66affSColin Finck Status = NtQuerySymbolicLinkObject(DeviceHandle, 613c2c66affSColin Finck &UnicodeString, 614c2c66affSColin Finck &ReturnLength); 615c2c66affSColin Finck NtClose(DeviceHandle); 616c2c66affSColin Finck if (!NT_SUCCESS(Status)) 617c2c66affSColin Finck { 618c2c66affSColin Finck WARN("NtQuerySymbolicLinkObject() failed (Status %lx)\n", Status); 6195d20d512SPierre Schweitzer _SEH2_LEAVE; 620c2c66affSColin Finck } 621c2c66affSColin Finck 622c2c66affSColin Finck TRACE("ReturnLength: %lu\n", ReturnLength); 623c2c66affSColin Finck TRACE("TargetLength: %hu\n", UnicodeString.Length); 624c2c66affSColin Finck TRACE("Target: '%wZ'\n", &UnicodeString); 625c2c66affSColin Finck 6265d20d512SPierre Schweitzer Length = ReturnLength / sizeof(WCHAR); 6275d20d512SPierre Schweitzer /* Make sure we null terminate output buffer */ 6285d20d512SPierre Schweitzer if (Length == 0 || lpTargetPath[Length - 1] != UNICODE_NULL) 6295d20d512SPierre Schweitzer { 6305d20d512SPierre Schweitzer if (Length >= ucchMax) 6315d20d512SPierre Schweitzer { 6325d20d512SPierre Schweitzer TRACE("Buffer is too small\n"); 6335d20d512SPierre Schweitzer Status = STATUS_BUFFER_TOO_SMALL; 6345d20d512SPierre Schweitzer _SEH2_LEAVE; 6355d20d512SPierre Schweitzer } 6365d20d512SPierre Schweitzer 6375d20d512SPierre Schweitzer /* Append null-character */ 6385d20d512SPierre Schweitzer lpTargetPath[Length] = UNICODE_NULL; 6395d20d512SPierre Schweitzer Length++; 6405d20d512SPierre Schweitzer } 6415d20d512SPierre Schweitzer 642c2c66affSColin Finck if (Length < ucchMax) 643c2c66affSColin Finck { 644c2c66affSColin Finck /* Append null-character */ 645c2c66affSColin Finck lpTargetPath[Length] = UNICODE_NULL; 646c2c66affSColin Finck Length++; 647c2c66affSColin Finck } 648c2c66affSColin Finck 6495d20d512SPierre Schweitzer _SEH2_LEAVE; 6505d20d512SPierre Schweitzer } 6515d20d512SPierre Schweitzer 6525d20d512SPierre Schweitzer /* 6535d20d512SPierre Schweitzer * If LUID device maps are enabled, 6545d20d512SPierre Schweitzer * ?? may not point to BaseNamedObjects 6555d20d512SPierre Schweitzer * It may only be local DOS namespace. 6565d20d512SPierre Schweitzer * And thus, it might be required to browse 6575d20d512SPierre Schweitzer * Global?? for global devices 6585d20d512SPierre Schweitzer */ 6595d20d512SPierre Schweitzer GlobalNeeded = FALSE; 6605d20d512SPierre Schweitzer if (BaseStaticServerData->LUIDDeviceMapsEnabled) 661c2c66affSColin Finck { 6625d20d512SPierre Schweitzer /* Assume ?? == Global?? */ 6635d20d512SPierre Schweitzer IsGlobal = TRUE; 6645d20d512SPierre Schweitzer /* Check if it's the case */ 6655d20d512SPierre Schweitzer Status = IsGlobalDeviceMap(DirectoryHandle, &IsGlobal); 6665d20d512SPierre Schweitzer if (NT_SUCCESS(Status) && !IsGlobal) 6675d20d512SPierre Schweitzer { 6685d20d512SPierre Schweitzer /* It's not, we'll have to browse Global?? too! */ 6695d20d512SPierre Schweitzer GlobalNeeded = TRUE; 6705d20d512SPierre Schweitzer } 6715d20d512SPierre Schweitzer } 6725d20d512SPierre Schweitzer 6735d20d512SPierre Schweitzer /* 6745d20d512SPierre Schweitzer * Make sure we don't overrun the output buffer, so convert our DWORD 6755d20d512SPierre Schweitzer * size to USHORT size properly 6765d20d512SPierre Schweitzer */ 6775d20d512SPierre Schweitzer BufferLength = (ucchMax <= MAXULONG / sizeof(WCHAR)) ? (ucchMax * sizeof(WCHAR)) : MAXULONG; 6785d20d512SPierre Schweitzer Length = 0; 6795d20d512SPierre Schweitzer Ptr = lpTargetPath; 6805d20d512SPierre Schweitzer 6815d20d512SPierre Schweitzer Context = 0; 6825d20d512SPierre Schweitzer TotalEntries = 0; 6835d20d512SPierre Schweitzer 6845d20d512SPierre Schweitzer /* 6855d20d512SPierre Schweitzer * We'll query all entries at once, with a rather big buffer 6865d20d512SPierre Schweitzer * If it's too small, we'll grow it by 2. 6875d20d512SPierre Schweitzer * Limit the number of attempts to 3. 6885d20d512SPierre Schweitzer */ 6895d20d512SPierre Schweitzer for (i = 0; i < 3; ++i) 6905d20d512SPierre Schweitzer { 6915d20d512SPierre Schweitzer /* Allocate the query buffer */ 6925d20d512SPierre Schweitzer Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength); 6935d20d512SPierre Schweitzer if (Buffer == NULL) 6945d20d512SPierre Schweitzer { 6955d20d512SPierre Schweitzer Status = STATUS_INSUFFICIENT_RESOURCES; 6965d20d512SPierre Schweitzer _SEH2_LEAVE; 6975d20d512SPierre Schweitzer } 6985d20d512SPierre Schweitzer 6995d20d512SPierre Schweitzer /* Perform the query */ 700c2c66affSColin Finck Status = NtQueryDirectoryObject(DirectoryHandle, 701c2c66affSColin Finck Buffer, 7025d20d512SPierre Schweitzer BufferLength, 7035d20d512SPierre Schweitzer FALSE, 704c2c66affSColin Finck TRUE, 705c2c66affSColin Finck &Context, 706c2c66affSColin Finck &ReturnLength); 7075d20d512SPierre Schweitzer /* Only failure accepted is: no more entries */ 708c2c66affSColin Finck if (!NT_SUCCESS(Status)) 709c2c66affSColin Finck { 7105d20d512SPierre Schweitzer if (Status != STATUS_NO_MORE_ENTRIES) 711c2c66affSColin Finck { 7125d20d512SPierre Schweitzer _SEH2_LEAVE; 7135d20d512SPierre Schweitzer } 714c2c66affSColin Finck 7155d20d512SPierre Schweitzer /* 7165d20d512SPierre Schweitzer * Which is a success! But break out, 7175d20d512SPierre Schweitzer * it means our query returned no results 7185d20d512SPierre Schweitzer * so, nothing to parse. 7195d20d512SPierre Schweitzer */ 720c2c66affSColin Finck Status = STATUS_SUCCESS; 721c2c66affSColin Finck break; 722c2c66affSColin Finck } 723c2c66affSColin Finck 7245d20d512SPierre Schweitzer /* In case we had them all, start browsing for devices */ 7255d20d512SPierre Schweitzer if (Status != STATUS_MORE_ENTRIES) 7265d20d512SPierre Schweitzer { 7275d20d512SPierre Schweitzer DirInfo = Buffer; 7285d20d512SPierre Schweitzer 7295d20d512SPierre Schweitzer /* Loop until we find the nul entry (terminating entry) */ 7305d20d512SPierre Schweitzer while (TRUE) 7315d20d512SPierre Schweitzer { 7325d20d512SPierre Schweitzer /* It's an entry full of zeroes */ 7335d20d512SPierre Schweitzer if (RtlCompareMemory(&NullEntry, DirInfo, sizeof(NullEntry)) == sizeof(NullEntry)) 7345d20d512SPierre Schweitzer { 7355d20d512SPierre Schweitzer break; 7365d20d512SPierre Schweitzer } 7375d20d512SPierre Schweitzer 7385d20d512SPierre Schweitzer /* Only handle symlinks */ 739c2c66affSColin Finck if (!wcscmp(DirInfo->TypeName.Buffer, L"SymbolicLink")) 740c2c66affSColin Finck { 741c2c66affSColin Finck TRACE("Name: '%wZ'\n", &DirInfo->Name); 742c2c66affSColin Finck 7435d20d512SPierre Schweitzer /* Get name length in chars to only comparisons */ 744c2c66affSColin Finck NameLength = DirInfo->Name.Length / sizeof(WCHAR); 7455d20d512SPierre Schweitzer 7465d20d512SPierre Schweitzer /* Make sure we don't overrun output buffer */ 7475d20d512SPierre Schweitzer if (Length > ucchMax || 7485d20d512SPierre Schweitzer NameLength > ucchMax - Length || 7495d20d512SPierre Schweitzer ucchMax - NameLength - Length < sizeof(WCHAR)) 750c2c66affSColin Finck { 7515d20d512SPierre Schweitzer Status = STATUS_BUFFER_TOO_SMALL; 7525d20d512SPierre Schweitzer _SEH2_LEAVE; 7535d20d512SPierre Schweitzer } 7545d20d512SPierre Schweitzer 7555d20d512SPierre Schweitzer /* Copy and NULL terminate string */ 7565d20d512SPierre Schweitzer memcpy(Ptr, DirInfo->Name.Buffer, DirInfo->Name.Length); 7575d20d512SPierre Schweitzer Ptr[NameLength] = UNICODE_NULL; 7585d20d512SPierre Schweitzer 7595d20d512SPierre Schweitzer Ptr += (NameLength + 1); 7605d20d512SPierre Schweitzer Length += (NameLength + 1); 7615d20d512SPierre Schweitzer 7625d20d512SPierre Schweitzer /* 7635d20d512SPierre Schweitzer * Keep the entries count, in case we would have to 7645d20d512SPierre Schweitzer * handle GLOBAL?? too 7655d20d512SPierre Schweitzer */ 7665d20d512SPierre Schweitzer ++TotalEntries; 7675d20d512SPierre Schweitzer } 7685d20d512SPierre Schweitzer 7695d20d512SPierre Schweitzer /* Move to the next entry */ 7705d20d512SPierre Schweitzer ++DirInfo; 7715d20d512SPierre Schweitzer } 7725d20d512SPierre Schweitzer 7735d20d512SPierre Schweitzer /* 7745d20d512SPierre Schweitzer * No need to loop again here, we got all the entries 7755d20d512SPierre Schweitzer * Note: we don't free the buffer here, because we may 7765d20d512SPierre Schweitzer * need it for GLOBAL??, so we save a few cycles here. 7775d20d512SPierre Schweitzer */ 778c2c66affSColin Finck break; 779c2c66affSColin Finck } 780c2c66affSColin Finck 7815d20d512SPierre Schweitzer /* Failure path here, we'll need bigger buffer */ 7825d20d512SPierre Schweitzer RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); 7835d20d512SPierre Schweitzer Buffer = NULL; 7845d20d512SPierre Schweitzer 7855d20d512SPierre Schweitzer /* We can't have bigger than that one, so leave */ 7865d20d512SPierre Schweitzer if (BufferLength == MAXULONG) 7875d20d512SPierre Schweitzer { 7885d20d512SPierre Schweitzer break; 7895d20d512SPierre Schweitzer } 7905d20d512SPierre Schweitzer 7915d20d512SPierre Schweitzer /* Prevent any overflow while computing new size */ 7925d20d512SPierre Schweitzer if (MAXULONG - BufferLength < BufferLength) 7935d20d512SPierre Schweitzer { 7945d20d512SPierre Schweitzer BufferLength = MAXULONG; 7955d20d512SPierre Schweitzer } 7965d20d512SPierre Schweitzer else 7975d20d512SPierre Schweitzer { 7985d20d512SPierre Schweitzer BufferLength *= 2; 7995d20d512SPierre Schweitzer } 8005d20d512SPierre Schweitzer } 8015d20d512SPierre Schweitzer 8025d20d512SPierre Schweitzer /* 8035d20d512SPierre Schweitzer * Out of the hot loop, but with more entries left? 8045d20d512SPierre Schweitzer * that's an error case, leave here! 8055d20d512SPierre Schweitzer */ 8065d20d512SPierre Schweitzer if (Status == STATUS_MORE_ENTRIES) 8075d20d512SPierre Schweitzer { 8085d20d512SPierre Schweitzer Status = STATUS_BUFFER_TOO_SMALL; 8095d20d512SPierre Schweitzer _SEH2_LEAVE; 8105d20d512SPierre Schweitzer } 8115d20d512SPierre Schweitzer 8125d20d512SPierre Schweitzer /* Now, if we had to handle GLOBAL??, go for it! */ 8135d20d512SPierre Schweitzer if (BaseStaticServerData->LUIDDeviceMapsEnabled && NT_SUCCESS(Status) && GlobalNeeded) 8145d20d512SPierre Schweitzer { 8155d20d512SPierre Schweitzer NtClose(DirectoryHandle); 8165d20d512SPierre Schweitzer DirectoryHandle = 0; 8175d20d512SPierre Schweitzer 8185d20d512SPierre Schweitzer RtlInitUnicodeString(&UnicodeString, L"\\GLOBAL??"); 8195d20d512SPierre Schweitzer InitializeObjectAttributes(&ObjectAttributes, 8205d20d512SPierre Schweitzer &UnicodeString, 8215d20d512SPierre Schweitzer OBJ_CASE_INSENSITIVE, 8225d20d512SPierre Schweitzer NULL, 8235d20d512SPierre Schweitzer NULL); 8245d20d512SPierre Schweitzer Status = NtOpenDirectoryObject(&DirectoryHandle, 8255d20d512SPierre Schweitzer DIRECTORY_QUERY, 8265d20d512SPierre Schweitzer &ObjectAttributes); 8275d20d512SPierre Schweitzer if (!NT_SUCCESS(Status)) 8285d20d512SPierre Schweitzer { 8295d20d512SPierre Schweitzer WARN("NtOpenDirectoryObject() failed (Status %lx)\n", Status); 8305d20d512SPierre Schweitzer _SEH2_LEAVE; 8315d20d512SPierre Schweitzer } 8325d20d512SPierre Schweitzer 8335d20d512SPierre Schweitzer /* 8345d20d512SPierre Schweitzer * We'll query all entries at once, with a rather big buffer 8355d20d512SPierre Schweitzer * If it's too small, we'll grow it by 2. 8365d20d512SPierre Schweitzer * Limit the number of attempts to 3. 8375d20d512SPierre Schweitzer */ 8385d20d512SPierre Schweitzer for (i = 0; i < 3; ++i) 8395d20d512SPierre Schweitzer { 8405d20d512SPierre Schweitzer /* If we had no buffer from previous attempt, allocate one */ 8415d20d512SPierre Schweitzer if (Buffer == NULL) 8425d20d512SPierre Schweitzer { 8435d20d512SPierre Schweitzer Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength); 8445d20d512SPierre Schweitzer if (Buffer == NULL) 8455d20d512SPierre Schweitzer { 8465d20d512SPierre Schweitzer Status = STATUS_INSUFFICIENT_RESOURCES; 8475d20d512SPierre Schweitzer _SEH2_LEAVE; 8485d20d512SPierre Schweitzer } 8495d20d512SPierre Schweitzer } 8505d20d512SPierre Schweitzer 8515d20d512SPierre Schweitzer /* Perform the query */ 8525d20d512SPierre Schweitzer Status = NtQueryDirectoryObject(DirectoryHandle, 8535d20d512SPierre Schweitzer Buffer, 8545d20d512SPierre Schweitzer BufferLength, 8555d20d512SPierre Schweitzer FALSE, 8565d20d512SPierre Schweitzer TRUE, 8575d20d512SPierre Schweitzer &Context, 8585d20d512SPierre Schweitzer &ReturnLength); 8595d20d512SPierre Schweitzer /* Only failure accepted is: no more entries */ 8605d20d512SPierre Schweitzer if (!NT_SUCCESS(Status)) 8615d20d512SPierre Schweitzer { 8625d20d512SPierre Schweitzer if (Status != STATUS_NO_MORE_ENTRIES) 8635d20d512SPierre Schweitzer { 8645d20d512SPierre Schweitzer _SEH2_LEAVE; 8655d20d512SPierre Schweitzer } 8665d20d512SPierre Schweitzer 8675d20d512SPierre Schweitzer /* 8685d20d512SPierre Schweitzer * Which is a success! But break out, 8695d20d512SPierre Schweitzer * it means our query returned no results 8705d20d512SPierre Schweitzer * so, nothing to parse. 8715d20d512SPierre Schweitzer */ 8725d20d512SPierre Schweitzer Status = STATUS_SUCCESS; 8735d20d512SPierre Schweitzer break; 8745d20d512SPierre Schweitzer } 8755d20d512SPierre Schweitzer 8765d20d512SPierre Schweitzer /* In case we had them all, start browsing for devices */ 8775d20d512SPierre Schweitzer if (Status != STATUS_MORE_ENTRIES) 8785d20d512SPierre Schweitzer { 8795d20d512SPierre Schweitzer DirInfo = Buffer; 8805d20d512SPierre Schweitzer 8815d20d512SPierre Schweitzer /* Loop until we find the nul entry (terminating entry) */ 8825d20d512SPierre Schweitzer while (TRUE) 8835d20d512SPierre Schweitzer { 8845d20d512SPierre Schweitzer /* It's an entry full of zeroes */ 8855d20d512SPierre Schweitzer if (RtlCompareMemory(&NullEntry, DirInfo, sizeof(NullEntry)) == sizeof(NullEntry)) 8865d20d512SPierre Schweitzer { 8875d20d512SPierre Schweitzer break; 8885d20d512SPierre Schweitzer } 8895d20d512SPierre Schweitzer 8905d20d512SPierre Schweitzer /* Only handle symlinks */ 8915d20d512SPierre Schweitzer if (!wcscmp(DirInfo->TypeName.Buffer, L"SymbolicLink")) 8925d20d512SPierre Schweitzer { 8935d20d512SPierre Schweitzer TRACE("Name: '%wZ'\n", &DirInfo->Name); 8945d20d512SPierre Schweitzer 8955d20d512SPierre Schweitzer /* 8965d20d512SPierre Schweitzer * Now, we previously already browsed ??, and we 8975d20d512SPierre Schweitzer * don't want to devices twice, so we'll check 8985d20d512SPierre Schweitzer * the output buffer for duplicates. 8995d20d512SPierre Schweitzer * We'll add our entry only if we don't have already 9005d20d512SPierre Schweitzer * returned it. 9015d20d512SPierre Schweitzer */ 9025d20d512SPierre Schweitzer if (FindSymbolicLinkEntry(DirInfo->Name.Buffer, 9035d20d512SPierre Schweitzer lpTargetPath, 9045d20d512SPierre Schweitzer TotalEntries, 9055d20d512SPierre Schweitzer &Found) == ERROR_SUCCESS && 9065d20d512SPierre Schweitzer !Found) 9075d20d512SPierre Schweitzer { 9085d20d512SPierre Schweitzer /* Get name length in chars to only comparisons */ 9095d20d512SPierre Schweitzer NameLength = DirInfo->Name.Length / sizeof(WCHAR); 9105d20d512SPierre Schweitzer 9115d20d512SPierre Schweitzer /* Make sure we don't overrun output buffer */ 9125d20d512SPierre Schweitzer if (Length > ucchMax || 9135d20d512SPierre Schweitzer NameLength > ucchMax - Length || 9145d20d512SPierre Schweitzer ucchMax - NameLength - Length < sizeof(WCHAR)) 9155d20d512SPierre Schweitzer { 9165d20d512SPierre Schweitzer RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); 9175d20d512SPierre Schweitzer NtClose(DirectoryHandle); 9185d20d512SPierre Schweitzer BaseSetLastNTError(STATUS_BUFFER_TOO_SMALL); 9195d20d512SPierre Schweitzer return 0; 9205d20d512SPierre Schweitzer } 9215d20d512SPierre Schweitzer 9225d20d512SPierre Schweitzer /* Copy and NULL terminate string */ 923c2c66affSColin Finck memcpy(Ptr, DirInfo->Name.Buffer, DirInfo->Name.Length); 9245d20d512SPierre Schweitzer Ptr[NameLength] = UNICODE_NULL; 9255d20d512SPierre Schweitzer 9265d20d512SPierre Schweitzer Ptr += (NameLength + 1); 9275d20d512SPierre Schweitzer Length += (NameLength + 1); 9285d20d512SPierre Schweitzer } 9295d20d512SPierre Schweitzer } 9305d20d512SPierre Schweitzer 9315d20d512SPierre Schweitzer /* Move to the next entry */ 9325d20d512SPierre Schweitzer ++DirInfo; 9335d20d512SPierre Schweitzer } 9345d20d512SPierre Schweitzer 9355d20d512SPierre Schweitzer /* No need to loop again here, we got all the entries */ 9365d20d512SPierre Schweitzer break; 9375d20d512SPierre Schweitzer } 9385d20d512SPierre Schweitzer 9395d20d512SPierre Schweitzer /* Failure path here, we'll need bigger buffer */ 9405d20d512SPierre Schweitzer RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); 9415d20d512SPierre Schweitzer Buffer = NULL; 9425d20d512SPierre Schweitzer 9435d20d512SPierre Schweitzer /* We can't have bigger than that one, so leave */ 9445d20d512SPierre Schweitzer if (BufferLength == MAXULONG) 9455d20d512SPierre Schweitzer { 9465d20d512SPierre Schweitzer break; 9475d20d512SPierre Schweitzer } 9485d20d512SPierre Schweitzer 9495d20d512SPierre Schweitzer /* Prevent any overflow while computing new size */ 9505d20d512SPierre Schweitzer if (MAXULONG - BufferLength < BufferLength) 9515d20d512SPierre Schweitzer { 9525d20d512SPierre Schweitzer BufferLength = MAXULONG; 9535d20d512SPierre Schweitzer } 9545d20d512SPierre Schweitzer else 9555d20d512SPierre Schweitzer { 9565d20d512SPierre Schweitzer BufferLength *= 2; 9575d20d512SPierre Schweitzer } 9585d20d512SPierre Schweitzer } 9595d20d512SPierre Schweitzer 9605d20d512SPierre Schweitzer /* 9615d20d512SPierre Schweitzer * Out of the hot loop, but with more entries left? 9625d20d512SPierre Schweitzer * that's an error case, leave here! 9635d20d512SPierre Schweitzer */ 9645d20d512SPierre Schweitzer if (Status == STATUS_MORE_ENTRIES) 9655d20d512SPierre Schweitzer { 9665d20d512SPierre Schweitzer Status = STATUS_BUFFER_TOO_SMALL; 9675d20d512SPierre Schweitzer _SEH2_LEAVE; 9685d20d512SPierre Schweitzer } 9695d20d512SPierre Schweitzer } 9705d20d512SPierre Schweitzer 9715d20d512SPierre Schweitzer /* If we failed somewhere, just leave */ 9725d20d512SPierre Schweitzer if (!NT_SUCCESS(Status)) 9735d20d512SPierre Schweitzer { 9745d20d512SPierre Schweitzer _SEH2_LEAVE; 9755d20d512SPierre Schweitzer } 9765d20d512SPierre Schweitzer 9775d20d512SPierre Schweitzer /* If we returned no entries, time to write the empty string */ 9785d20d512SPierre Schweitzer if (Length == 0) 9795d20d512SPierre Schweitzer { 9805d20d512SPierre Schweitzer /* Unless output buffer is too small! */ 9815d20d512SPierre Schweitzer if (ucchMax <= 0) 9825d20d512SPierre Schweitzer { 9835d20d512SPierre Schweitzer Status = STATUS_BUFFER_TOO_SMALL; 9845d20d512SPierre Schweitzer _SEH2_LEAVE; 9855d20d512SPierre Schweitzer } 9865d20d512SPierre Schweitzer 9875d20d512SPierre Schweitzer /* Emptry string is one char (terminator!) */ 988c2c66affSColin Finck *Ptr = UNICODE_NULL; 9895d20d512SPierre Schweitzer ++Ptr; 9905d20d512SPierre Schweitzer Length = 1; 991c2c66affSColin Finck } 992c2c66affSColin Finck 9935d20d512SPierre Schweitzer /* 9945d20d512SPierre Schweitzer * If we have enough room, we need to double terminate the buffer: 9955d20d512SPierre Schweitzer * that's a MULTI_SZ buffer, its end is marked by double NULL. 9965d20d512SPierre Schweitzer * One was already added during the "copy string" process. 9975d20d512SPierre Schweitzer * If we don't have enough room: that's a failure case. 9985d20d512SPierre Schweitzer */ 9995d20d512SPierre Schweitzer if (Length < ucchMax) 10005d20d512SPierre Schweitzer { 10015d20d512SPierre Schweitzer *Ptr = UNICODE_NULL; 10025d20d512SPierre Schweitzer ++Ptr; 1003c2c66affSColin Finck } 10045d20d512SPierre Schweitzer else 10055d20d512SPierre Schweitzer { 10065d20d512SPierre Schweitzer Status = STATUS_BUFFER_TOO_SMALL; 10075d20d512SPierre Schweitzer } 10085d20d512SPierre Schweitzer } 10095d20d512SPierre Schweitzer _SEH2_FINALLY 10105d20d512SPierre Schweitzer { 10115d20d512SPierre Schweitzer if (DirectoryHandle != 0) 10125d20d512SPierre Schweitzer { 1013c2c66affSColin Finck NtClose(DirectoryHandle); 1014c2c66affSColin Finck } 1015c2c66affSColin Finck 10165d20d512SPierre Schweitzer if (Buffer != NULL) 10175d20d512SPierre Schweitzer { 10185d20d512SPierre Schweitzer RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); 10195d20d512SPierre Schweitzer } 10205d20d512SPierre Schweitzer 10215d20d512SPierre Schweitzer if (!NT_SUCCESS(Status)) 10225d20d512SPierre Schweitzer { 10235d20d512SPierre Schweitzer Length = 0; 10245d20d512SPierre Schweitzer BaseSetLastNTError(Status); 10255d20d512SPierre Schweitzer } 10265d20d512SPierre Schweitzer } 10275d20d512SPierre Schweitzer _SEH2_END; 10285d20d512SPierre Schweitzer 1029c2c66affSColin Finck return Length; 1030c2c66affSColin Finck } 1031c2c66affSColin Finck 1032c2c66affSColin Finck /* EOF */ 1033