xref: /reactos/dll/win32/kernel32/client/dosdev.c (revision 204bfa85)
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