xref: /reactos/dll/win32/kernel32/client/dosdev.c (revision ea7aca8b)
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
IsGlobalDeviceMap(HANDLE DirectoryHandle,PBOOLEAN IsGlobal)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     _SEH2_FINALLY
825d20d512SPierre Schweitzer     {
835d20d512SPierre Schweitzer         if (PNameInfo != NULL)
845d20d512SPierre Schweitzer         {
855d20d512SPierre Schweitzer             RtlFreeHeap(RtlGetProcessHeap(), 0, PNameInfo);
865d20d512SPierre Schweitzer         }
875d20d512SPierre Schweitzer     }
885d20d512SPierre Schweitzer     _SEH2_END;
895d20d512SPierre Schweitzer 
905d20d512SPierre Schweitzer     return Status;
915d20d512SPierre Schweitzer }
925d20d512SPierre Schweitzer 
935d20d512SPierre Schweitzer /*
945d20d512SPierre Schweitzer  * @implemented
955d20d512SPierre Schweitzer  */
965d20d512SPierre Schweitzer DWORD
FindSymbolicLinkEntry(PWSTR NameToFind,PWSTR NamesList,DWORD TotalEntries,PBOOLEAN Found)975d20d512SPierre Schweitzer FindSymbolicLinkEntry(
985d20d512SPierre Schweitzer     PWSTR NameToFind,
995d20d512SPierre Schweitzer     PWSTR NamesList,
1005d20d512SPierre Schweitzer     DWORD TotalEntries,
1015d20d512SPierre Schweitzer     PBOOLEAN Found)
1025d20d512SPierre Schweitzer {
1035d20d512SPierre Schweitzer     WCHAR Current;
1045d20d512SPierre Schweitzer     DWORD Entries;
1055d20d512SPierre Schweitzer     PWSTR PartialNamesList;
1065d20d512SPierre Schweitzer 
1075d20d512SPierre Schweitzer     /* We need all parameters to be set */
1085d20d512SPierre Schweitzer     if (NameToFind == NULL || NamesList == NULL || Found == NULL)
1095d20d512SPierre Schweitzer     {
1105d20d512SPierre Schweitzer         return ERROR_INVALID_PARAMETER;
1115d20d512SPierre Schweitzer     }
1125d20d512SPierre Schweitzer 
1135d20d512SPierre Schweitzer     /* Assume failure */
1145d20d512SPierre Schweitzer     *Found = FALSE;
1155d20d512SPierre Schweitzer 
1165d20d512SPierre Schweitzer     /* If no entries, job done, nothing found */
1175d20d512SPierre Schweitzer     if (TotalEntries == 0)
1185d20d512SPierre Schweitzer     {
1195d20d512SPierre Schweitzer         return ERROR_SUCCESS;
1205d20d512SPierre Schweitzer     }
1215d20d512SPierre Schweitzer 
1225d20d512SPierre Schweitzer     /* Start browsing the names list */
1235d20d512SPierre Schweitzer     Entries = 0;
1245d20d512SPierre Schweitzer     PartialNamesList = NamesList;
1255d20d512SPierre Schweitzer     /* As long as we didn't find the name... */
1265d20d512SPierre Schweitzer     while (wcscmp(NameToFind, PartialNamesList) != 0)
1275d20d512SPierre Schweitzer     {
1285d20d512SPierre Schweitzer         /* We chomped an entry! */
1295d20d512SPierre Schweitzer         ++Entries;
1305d20d512SPierre Schweitzer 
1315d20d512SPierre Schweitzer         /* We're out of entries, bail out not to overrun */
1325d20d512SPierre Schweitzer         if (Entries > TotalEntries)
1335d20d512SPierre Schweitzer         {
1345d20d512SPierre Schweitzer             /*
1355d20d512SPierre Schweitzer              * Even though we found nothing,
1365d20d512SPierre Schweitzer              * the function ran fine
1375d20d512SPierre Schweitzer              */
1385d20d512SPierre Schweitzer             return ERROR_SUCCESS;
1395d20d512SPierre Schweitzer         }
1405d20d512SPierre Schweitzer 
1415d20d512SPierre Schweitzer         /* Jump to the next string */
1425d20d512SPierre Schweitzer         do
1435d20d512SPierre Schweitzer         {
1445d20d512SPierre Schweitzer             Current = *PartialNamesList;
1455d20d512SPierre Schweitzer             ++PartialNamesList;
1465d20d512SPierre Schweitzer         } while (Current != UNICODE_NULL);
1475d20d512SPierre Schweitzer     }
1485d20d512SPierre Schweitzer 
1495d20d512SPierre Schweitzer     /*
1505d20d512SPierre Schweitzer      * We're here because the loop stopped:
1515d20d512SPierre Schweitzer      * it means we found the name in the list
1525d20d512SPierre Schweitzer      */
1535d20d512SPierre Schweitzer     *Found = TRUE;
1545d20d512SPierre Schweitzer     return ERROR_SUCCESS;
1555d20d512SPierre Schweitzer }
1565d20d512SPierre Schweitzer 
1575d20d512SPierre Schweitzer /*
1585d20d512SPierre Schweitzer  * @implemented
1595d20d512SPierre Schweitzer  */
160c2c66affSColin Finck BOOL
161c2c66affSColin Finck WINAPI
DefineDosDeviceA(DWORD dwFlags,LPCSTR lpDeviceName,LPCSTR lpTargetPath)162c2c66affSColin Finck DefineDosDeviceA(
163c2c66affSColin Finck     DWORD dwFlags,
164c2c66affSColin Finck     LPCSTR lpDeviceName,
165c2c66affSColin Finck     LPCSTR lpTargetPath
166c2c66affSColin Finck     )
167c2c66affSColin Finck {
168c2c66affSColin Finck     BOOL Result;
1691ed7f274SPierre Schweitzer     NTSTATUS Status;
1701ed7f274SPierre Schweitzer     ANSI_STRING AnsiString;
1711ed7f274SPierre Schweitzer     PWSTR TargetPathBuffer;
1721ed7f274SPierre Schweitzer     UNICODE_STRING TargetPathU;
1731ed7f274SPierre Schweitzer     PUNICODE_STRING DeviceNameU;
174c2c66affSColin Finck 
1751ed7f274SPierre Schweitzer     /* Convert DeviceName using static unicode string */
1761ed7f274SPierre Schweitzer     RtlInitAnsiString(&AnsiString, lpDeviceName);
1771ed7f274SPierre Schweitzer     DeviceNameU = &NtCurrentTeb()->StaticUnicodeString;
1781ed7f274SPierre Schweitzer     Status = RtlAnsiStringToUnicodeString(DeviceNameU, &AnsiString, FALSE);
1791ed7f274SPierre Schweitzer     if (!NT_SUCCESS(Status))
180c2c66affSColin Finck     {
1811ed7f274SPierre Schweitzer         /*
1821ed7f274SPierre Schweitzer          * If the static unicode string is too small,
1831ed7f274SPierre Schweitzer          * it's because the name is too long...
1841ed7f274SPierre Schweitzer          * so, return appropriate status!
1851ed7f274SPierre Schweitzer          */
1861ed7f274SPierre Schweitzer         if (Status == STATUS_BUFFER_OVERFLOW)
1871ed7f274SPierre Schweitzer         {
1881ed7f274SPierre Schweitzer             SetLastError(ERROR_FILENAME_EXCED_RANGE);
1891ed7f274SPierre Schweitzer             return FALSE;
190c2c66affSColin Finck         }
191c2c66affSColin Finck 
1921ed7f274SPierre Schweitzer         BaseSetLastNTError(Status);
1931ed7f274SPierre Schweitzer         return FALSE;
194c2c66affSColin Finck     }
195c2c66affSColin Finck 
1961ed7f274SPierre Schweitzer     /* Convert target path if existing */
1971ed7f274SPierre Schweitzer     if (lpTargetPath != NULL)
1981ed7f274SPierre Schweitzer     {
1991ed7f274SPierre Schweitzer         RtlInitAnsiString(&AnsiString, lpTargetPath);
2001ed7f274SPierre Schweitzer         Status = RtlAnsiStringToUnicodeString(&TargetPathU, &AnsiString, TRUE);
2011ed7f274SPierre Schweitzer         if (!NT_SUCCESS(Status))
2021ed7f274SPierre Schweitzer         {
2031ed7f274SPierre Schweitzer             BaseSetLastNTError(Status);
2041ed7f274SPierre Schweitzer             return FALSE;
2051ed7f274SPierre Schweitzer         }
206c2c66affSColin Finck 
2071ed7f274SPierre Schweitzer         TargetPathBuffer = TargetPathU.Buffer;
2081ed7f274SPierre Schweitzer     }
2091ed7f274SPierre Schweitzer     else
2101ed7f274SPierre Schweitzer     {
2111ed7f274SPierre Schweitzer         TargetPathBuffer = NULL;
2121ed7f274SPierre Schweitzer     }
2131ed7f274SPierre Schweitzer 
2141ed7f274SPierre Schweitzer     /* Call W */
2151ed7f274SPierre Schweitzer     Result = DefineDosDeviceW(dwFlags, DeviceNameU->Buffer, TargetPathBuffer);
2161ed7f274SPierre Schweitzer 
2171ed7f274SPierre Schweitzer     /* Free target path if allocated */
2181ed7f274SPierre Schweitzer     if (TargetPathBuffer != NULL)
219c2c66affSColin Finck     {
220c2c66affSColin Finck         RtlFreeUnicodeString(&TargetPathU);
221c2c66affSColin Finck     }
222c2c66affSColin Finck 
223c2c66affSColin Finck     return Result;
224c2c66affSColin Finck }
225c2c66affSColin Finck 
226c2c66affSColin Finck 
227c2c66affSColin Finck /*
228c2c66affSColin Finck  * @implemented
229c2c66affSColin Finck  */
230c2c66affSColin Finck BOOL
231c2c66affSColin Finck WINAPI
DefineDosDeviceW(DWORD dwFlags,LPCWSTR lpDeviceName,LPCWSTR lpTargetPath)232c2c66affSColin Finck DefineDosDeviceW(
233c2c66affSColin Finck     DWORD dwFlags,
234c2c66affSColin Finck     LPCWSTR lpDeviceName,
235c2c66affSColin Finck     LPCWSTR lpTargetPath
236c2c66affSColin Finck     )
237c2c66affSColin Finck {
238c2c66affSColin Finck     ULONG ArgumentCount;
239c2c66affSColin Finck     ULONG BufferSize;
240c2c66affSColin Finck     BASE_API_MESSAGE ApiMessage;
241c2c66affSColin Finck     PBASE_DEFINE_DOS_DEVICE DefineDosDeviceRequest = &ApiMessage.Data.DefineDosDeviceRequest;
242c2c66affSColin Finck     PCSR_CAPTURE_BUFFER CaptureBuffer;
243c2c66affSColin Finck     UNICODE_STRING NtTargetPathU;
244c2c66affSColin Finck     UNICODE_STRING DeviceNameU;
245c2c66affSColin Finck     HANDLE hUser32;
246c2c66affSColin Finck     DEV_BROADCAST_VOLUME dbcv;
247c2c66affSColin Finck     DWORD dwRecipients;
248c2c66affSColin Finck     typedef long (WINAPI *BSM_type)(DWORD, LPDWORD, UINT, WPARAM, LPARAM);
249c2c66affSColin Finck     BSM_type BSM_ptr;
250*204bfa85SPierre Schweitzer     BOOLEAN LUIDDeviceMapsEnabled;
251*204bfa85SPierre Schweitzer     WCHAR Letter;
252*204bfa85SPierre Schweitzer     WPARAM wParam;
253c2c66affSColin Finck 
254*204bfa85SPierre Schweitzer     /* Get status about local device mapping */
255*204bfa85SPierre Schweitzer     LUIDDeviceMapsEnabled = BaseStaticServerData->LUIDDeviceMapsEnabled;
256*204bfa85SPierre Schweitzer 
257*204bfa85SPierre Schweitzer     /* Validate input & flags */
258*204bfa85SPierre Schweitzer     if ((dwFlags & 0xFFFFFFE0) ||
259c2c66affSColin Finck         ((dwFlags & DDD_EXACT_MATCH_ON_REMOVE) &&
260*204bfa85SPierre Schweitzer         !(dwFlags & DDD_REMOVE_DEFINITION)) ||
261*204bfa85SPierre Schweitzer         (lpTargetPath == NULL && !(dwFlags & (DDD_LUID_BROADCAST_DRIVE | DDD_REMOVE_DEFINITION))) ||
262*204bfa85SPierre Schweitzer         ((dwFlags & DDD_LUID_BROADCAST_DRIVE) &&
263*204bfa85SPierre Schweitzer          (lpDeviceName == NULL || lpTargetPath != NULL || dwFlags & (DDD_NO_BROADCAST_SYSTEM | DDD_EXACT_MATCH_ON_REMOVE | DDD_RAW_TARGET_PATH) || !LUIDDeviceMapsEnabled)))
264c2c66affSColin Finck     {
265c2c66affSColin Finck         SetLastError(ERROR_INVALID_PARAMETER);
266c2c66affSColin Finck         return FALSE;
267c2c66affSColin Finck     }
268c2c66affSColin Finck 
269*204bfa85SPierre Schweitzer     /* Initialize device unicode string to ease its use */
270*204bfa85SPierre Schweitzer     RtlInitUnicodeString(&DeviceNameU, lpDeviceName);
271*204bfa85SPierre Schweitzer 
272*204bfa85SPierre Schweitzer     /* The buffer for CSR call will contain it */
273*204bfa85SPierre Schweitzer     BufferSize = DeviceNameU.MaximumLength;
274c2c66affSColin Finck     ArgumentCount = 1;
275*204bfa85SPierre Schweitzer 
276*204bfa85SPierre Schweitzer     /* If we don't have target path, use empty string */
277*204bfa85SPierre Schweitzer     if (lpTargetPath == NULL)
278c2c66affSColin Finck     {
279*204bfa85SPierre Schweitzer         RtlInitUnicodeString(&NtTargetPathU, NULL);
280c2c66affSColin Finck     }
281c2c66affSColin Finck     else
282c2c66affSColin Finck     {
283*204bfa85SPierre Schweitzer         /* Else, use it raw if asked to */
284c2c66affSColin Finck         if (dwFlags & DDD_RAW_TARGET_PATH)
285c2c66affSColin Finck         {
286*204bfa85SPierre Schweitzer             RtlInitUnicodeString(&NtTargetPathU, lpTargetPath);
287c2c66affSColin Finck         }
288c2c66affSColin Finck         else
289c2c66affSColin Finck         {
290*204bfa85SPierre Schweitzer             /* Otherwise, use it converted */
291c2c66affSColin Finck             if (!RtlDosPathNameToNtPathName_U(lpTargetPath,
292c2c66affSColin Finck                                               &NtTargetPathU,
293c2c66affSColin Finck                                               NULL,
294c2c66affSColin Finck                                               NULL))
295c2c66affSColin Finck             {
296c2c66affSColin Finck                 WARN("RtlDosPathNameToNtPathName_U() failed\n");
297c2c66affSColin Finck                 BaseSetLastNTError(STATUS_OBJECT_NAME_INVALID);
298c2c66affSColin Finck                 return FALSE;
299c2c66affSColin Finck             }
300c2c66affSColin Finck         }
301*204bfa85SPierre Schweitzer 
302*204bfa85SPierre Schweitzer         /* This target path will be the second arg */
303c2c66affSColin Finck         ArgumentCount = 2;
304*204bfa85SPierre Schweitzer         BufferSize += NtTargetPathU.MaximumLength;
305c2c66affSColin Finck     }
306c2c66affSColin Finck 
307*204bfa85SPierre Schweitzer     /* Allocate the capture buffer for our strings */
308c2c66affSColin Finck     CaptureBuffer = CsrAllocateCaptureBuffer(ArgumentCount,
309c2c66affSColin Finck                                              BufferSize);
310*204bfa85SPierre Schweitzer     if (CaptureBuffer == NULL)
311c2c66affSColin Finck     {
312*204bfa85SPierre Schweitzer         if (!(dwFlags & DDD_RAW_TARGET_PATH))
313*204bfa85SPierre Schweitzer         {
314*204bfa85SPierre Schweitzer             RtlFreeUnicodeString(&NtTargetPathU);
315c2c66affSColin Finck         }
316*204bfa85SPierre Schweitzer 
317*204bfa85SPierre Schweitzer         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
318*204bfa85SPierre Schweitzer         return FALSE;
319*204bfa85SPierre Schweitzer     }
320*204bfa85SPierre Schweitzer 
321*204bfa85SPierre Schweitzer     /* Set the flags */
322c2c66affSColin Finck     DefineDosDeviceRequest->Flags = dwFlags;
323c2c66affSColin Finck 
324*204bfa85SPierre Schweitzer     /* Allocate a buffer for the device name */
325*204bfa85SPierre Schweitzer     DefineDosDeviceRequest->DeviceName.MaximumLength = CsrAllocateMessagePointer(CaptureBuffer,
326*204bfa85SPierre Schweitzer                                                                                  DeviceNameU.MaximumLength,
327c2c66affSColin Finck                                                                                  (PVOID*)&DefineDosDeviceRequest->DeviceName.Buffer);
328*204bfa85SPierre Schweitzer     /* And copy it while upcasing it */
329*204bfa85SPierre Schweitzer     RtlUpcaseUnicodeString(&DefineDosDeviceRequest->DeviceName, &DeviceNameU, FALSE);
330c2c66affSColin Finck 
331*204bfa85SPierre Schweitzer     /* If we have a target path, copy it too, and free it if allocated */
332*204bfa85SPierre Schweitzer     if (NtTargetPathU.Length != 0)
333c2c66affSColin Finck     {
334*204bfa85SPierre Schweitzer         DefineDosDeviceRequest->TargetPath.MaximumLength = CsrAllocateMessagePointer(CaptureBuffer,
335*204bfa85SPierre Schweitzer                                                                                      NtTargetPathU.MaximumLength,
336c2c66affSColin Finck                                                                                      (PVOID*)&DefineDosDeviceRequest->TargetPath.Buffer);
337*204bfa85SPierre Schweitzer         RtlCopyUnicodeString(&DefineDosDeviceRequest->TargetPath, &NtTargetPathU);
338c2c66affSColin Finck 
339*204bfa85SPierre Schweitzer         if (!(dwFlags & DDD_RAW_TARGET_PATH))
340*204bfa85SPierre Schweitzer         {
341*204bfa85SPierre Schweitzer             RtlFreeUnicodeString(&NtTargetPathU);
342*204bfa85SPierre Schweitzer         }
343*204bfa85SPierre Schweitzer     }
344*204bfa85SPierre Schweitzer     /* Otherwise, null initialize the string */
345*204bfa85SPierre Schweitzer     else
346*204bfa85SPierre Schweitzer     {
347*204bfa85SPierre Schweitzer         RtlInitUnicodeString(&DefineDosDeviceRequest->TargetPath, NULL);
348*204bfa85SPierre Schweitzer     }
349*204bfa85SPierre Schweitzer 
350*204bfa85SPierre Schweitzer     /* Finally,  call the server */
351c2c66affSColin Finck     CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
352c2c66affSColin Finck                         CaptureBuffer,
353c2c66affSColin Finck                         CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepDefineDosDevice),
354c2c66affSColin Finck                         sizeof(*DefineDosDeviceRequest));
355c2c66affSColin Finck     CsrFreeCaptureBuffer(CaptureBuffer);
356c2c66affSColin Finck 
357*204bfa85SPierre Schweitzer     /* Return failure if any */
358c2c66affSColin Finck     if (!NT_SUCCESS(ApiMessage.Status))
359c2c66affSColin Finck     {
360c2c66affSColin Finck         WARN("CsrClientCallServer() failed (Status %lx)\n", ApiMessage.Status);
361c2c66affSColin Finck         BaseSetLastNTError(ApiMessage.Status);
362*204bfa85SPierre Schweitzer         return FALSE;
363c2c66affSColin Finck     }
364*204bfa85SPierre Schweitzer 
365*204bfa85SPierre Schweitzer     /* Here is the success path, we will always return true */
366*204bfa85SPierre Schweitzer 
367*204bfa85SPierre Schweitzer     /* Should broadcast the event? Only do if not denied and if drive letter */
368c2c66affSColin Finck     if (!(dwFlags & DDD_NO_BROADCAST_SYSTEM) &&
369*204bfa85SPierre Schweitzer         DeviceNameU.Length == 2 * sizeof(WCHAR) &&
370*204bfa85SPierre Schweitzer         DeviceNameU.Buffer[1] == L':')
371c2c66affSColin Finck     {
372*204bfa85SPierre Schweitzer         /* Make sure letter is valid and there are no local device mappings */
373*204bfa85SPierre Schweitzer         Letter = RtlUpcaseUnicodeChar(DeviceNameU.Buffer[0]) - L'A';
374*204bfa85SPierre Schweitzer         if (Letter < 26 && !LUIDDeviceMapsEnabled)
375c2c66affSColin Finck         {
376*204bfa85SPierre Schweitzer             /* Rely on user32 for broadcasting */
377*204bfa85SPierre Schweitzer             hUser32 = LoadLibraryW(L"user32.dll");
378*204bfa85SPierre Schweitzer             if (hUser32 != 0)
379*204bfa85SPierre Schweitzer             {
380*204bfa85SPierre Schweitzer                 /* Get the function pointer */
381*204bfa85SPierre Schweitzer                 BSM_ptr = (BSM_type)GetProcAddress(hUser32, "BroadcastSystemMessageW");
382c2c66affSColin Finck                 if (BSM_ptr)
383c2c66affSColin Finck                 {
384*204bfa85SPierre Schweitzer                     /* Set our target */
385c2c66affSColin Finck                     dwRecipients = BSM_APPLICATIONS;
386*204bfa85SPierre Schweitzer 
387*204bfa85SPierre Schweitzer                     /* And initialize our structure */
388c2c66affSColin Finck                     dbcv.dbcv_size = sizeof(DEV_BROADCAST_VOLUME);
389c2c66affSColin Finck                     dbcv.dbcv_devicetype = DBT_DEVTYP_VOLUME;
390c2c66affSColin Finck                     dbcv.dbcv_reserved = 0;
391*204bfa85SPierre Schweitzer 
392*204bfa85SPierre Schweitzer                     /* Set the volume which had the event */
393*204bfa85SPierre Schweitzer                     dbcv.dbcv_unitmask = 1 << Letter;
394c2c66affSColin Finck                     dbcv.dbcv_flags = DBTF_NET;
395*204bfa85SPierre Schweitzer 
396*204bfa85SPierre Schweitzer                     /* And properly set the event (removal or arrival?) */
397*204bfa85SPierre Schweitzer                     wParam = (dwFlags & DDD_REMOVE_DEFINITION) ? DBT_DEVICEREMOVECOMPLETE : DBT_DEVICEARRIVAL;
398*204bfa85SPierre Schweitzer 
399*204bfa85SPierre Schweitzer                     /* And broadcast! */
400*204bfa85SPierre Schweitzer                     BSM_ptr(BSF_SENDNOTIFYMESSAGE | BSF_FLUSHDISK,
401c2c66affSColin Finck                             &dwRecipients,
402c2c66affSColin Finck                             WM_DEVICECHANGE,
403*204bfa85SPierre Schweitzer                             wParam,
404c2c66affSColin Finck                             (LPARAM)&dbcv);
405c2c66affSColin Finck                 }
406*204bfa85SPierre Schweitzer 
407*204bfa85SPierre Schweitzer                 /* We're done! */
408c2c66affSColin Finck                 FreeLibrary(hUser32);
409c2c66affSColin Finck             }
410c2c66affSColin Finck         }
411c2c66affSColin Finck     }
412c2c66affSColin Finck 
413*204bfa85SPierre Schweitzer     return TRUE;
414c2c66affSColin Finck }
415c2c66affSColin Finck 
416c2c66affSColin Finck 
417c2c66affSColin Finck /*
418c2c66affSColin Finck  * @implemented
419c2c66affSColin Finck  */
420c2c66affSColin Finck DWORD
421c2c66affSColin Finck WINAPI
QueryDosDeviceA(LPCSTR lpDeviceName,LPSTR lpTargetPath,DWORD ucchMax)422c2c66affSColin Finck QueryDosDeviceA(
423c2c66affSColin Finck     LPCSTR lpDeviceName,
424c2c66affSColin Finck     LPSTR lpTargetPath,
425c2c66affSColin Finck     DWORD ucchMax
426c2c66affSColin Finck     )
427c2c66affSColin Finck {
4288d128aa4SPierre Schweitzer     NTSTATUS Status;
4298d128aa4SPierre Schweitzer     USHORT CurrentPosition;
4308d128aa4SPierre Schweitzer     ANSI_STRING AnsiString;
431c2c66affSColin Finck     UNICODE_STRING TargetPathU;
4328d128aa4SPierre Schweitzer     PUNICODE_STRING DeviceNameU;
4338d128aa4SPierre Schweitzer     DWORD RetLength, CurrentLength, Length;
4348d128aa4SPierre Schweitzer     PWSTR DeviceNameBuffer, TargetPathBuffer;
435c2c66affSColin Finck 
4368d128aa4SPierre Schweitzer     /* If we want a specific device name, convert it */
4378d128aa4SPierre Schweitzer     if (lpDeviceName != NULL)
438c2c66affSColin Finck     {
4398d128aa4SPierre Schweitzer         /* Convert DeviceName using static unicode string */
4408d128aa4SPierre Schweitzer         RtlInitAnsiString(&AnsiString, lpDeviceName);
4418d128aa4SPierre Schweitzer         DeviceNameU = &NtCurrentTeb()->StaticUnicodeString;
4428d128aa4SPierre Schweitzer         Status = RtlAnsiStringToUnicodeString(DeviceNameU, &AnsiString, FALSE);
4438d128aa4SPierre Schweitzer         if (!NT_SUCCESS(Status))
4448d128aa4SPierre Schweitzer         {
4458d128aa4SPierre Schweitzer             /*
4468d128aa4SPierre Schweitzer              * If the static unicode string is too small,
4478d128aa4SPierre Schweitzer              * it's because the name is too long...
4488d128aa4SPierre Schweitzer              * so, return appropriate status!
4498d128aa4SPierre Schweitzer              */
4508d128aa4SPierre Schweitzer             if (Status == STATUS_BUFFER_OVERFLOW)
4518d128aa4SPierre Schweitzer             {
4528d128aa4SPierre Schweitzer                 SetLastError(ERROR_FILENAME_EXCED_RANGE);
4538d128aa4SPierre Schweitzer                 return FALSE;
4548d128aa4SPierre Schweitzer             }
4558d128aa4SPierre Schweitzer 
4568d128aa4SPierre Schweitzer             BaseSetLastNTError(Status);
4578d128aa4SPierre Schweitzer             return FALSE;
4588d128aa4SPierre Schweitzer         }
4598d128aa4SPierre Schweitzer 
4608d128aa4SPierre Schweitzer         DeviceNameBuffer = DeviceNameU->Buffer;
4618d128aa4SPierre Schweitzer     }
4628d128aa4SPierre Schweitzer     else
4638d128aa4SPierre Schweitzer     {
4648d128aa4SPierre Schweitzer         DeviceNameBuffer = NULL;
4658d128aa4SPierre Schweitzer     }
4668d128aa4SPierre Schweitzer 
4678d128aa4SPierre Schweitzer     /* Allocate the output buffer for W call */
4688d128aa4SPierre Schweitzer     TargetPathBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, ucchMax * sizeof(WCHAR));
4698d128aa4SPierre Schweitzer     if (TargetPathBuffer == NULL)
470c2c66affSColin Finck     {
471c2c66affSColin Finck         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
472c2c66affSColin Finck         return 0;
473c2c66affSColin Finck     }
4748d128aa4SPierre Schweitzer 
4758d128aa4SPierre Schweitzer     /* Call W */
4768d128aa4SPierre Schweitzer     Length = QueryDosDeviceW(DeviceNameBuffer, TargetPathBuffer, ucchMax);
4778d128aa4SPierre Schweitzer     /* We'll return that length in case of a success */
4788d128aa4SPierre Schweitzer     RetLength = Length;
4798d128aa4SPierre Schweitzer 
4808d128aa4SPierre Schweitzer     /* Handle the case where we would fill output buffer completly */
4818d128aa4SPierre Schweitzer     if (Length != 0 && Length == ucchMax)
482c2c66affSColin Finck     {
4838d128aa4SPierre Schweitzer         /* This will be our work length (but not the one we return) */
4848d128aa4SPierre Schweitzer         --Length;
4858d128aa4SPierre Schweitzer         /* Already 0 the last char */
4868d128aa4SPierre Schweitzer         lpTargetPath[Length] = ANSI_NULL;
487c2c66affSColin Finck     }
488c2c66affSColin Finck 
4898d128aa4SPierre Schweitzer     /* If we had an output, start the convert loop */
490c2c66affSColin Finck     if (Length != 0)
491c2c66affSColin Finck     {
4928d128aa4SPierre Schweitzer         /*
4938d128aa4SPierre Schweitzer          * We'll have to loop because TargetPathBuffer may contain
4948d128aa4SPierre Schweitzer          * several strings (NULL separated)
4958d128aa4SPierre Schweitzer          * We'll start at position 0
4968d128aa4SPierre Schweitzer          */
4978d128aa4SPierre Schweitzer         CurrentPosition = 0;
4988d128aa4SPierre Schweitzer         while (CurrentPosition < Length)
499c2c66affSColin Finck         {
5008d128aa4SPierre Schweitzer             /* Get the maximum length */
5018d128aa4SPierre Schweitzer             CurrentLength = min(Length - CurrentPosition, MAXUSHORT / 2);
502c2c66affSColin Finck 
5038d128aa4SPierre Schweitzer             /* Initialize our output string */
5048d128aa4SPierre Schweitzer             AnsiString.Length = 0;
5058d128aa4SPierre Schweitzer             AnsiString.MaximumLength = CurrentLength + sizeof(ANSI_NULL);
5068d128aa4SPierre Schweitzer             AnsiString.Buffer = &lpTargetPath[CurrentPosition];
507c2c66affSColin Finck 
5088d128aa4SPierre Schweitzer             /* Initialize input string that will be converted */
5098d128aa4SPierre Schweitzer             TargetPathU.Length = CurrentLength * sizeof(WCHAR);
5108d128aa4SPierre Schweitzer             TargetPathU.MaximumLength = CurrentLength * sizeof(WCHAR) + sizeof(UNICODE_NULL);
5118d128aa4SPierre Schweitzer             TargetPathU.Buffer = &TargetPathBuffer[CurrentPosition];
512c2c66affSColin Finck 
5138d128aa4SPierre Schweitzer             /* Convert to ANSI */
5148d128aa4SPierre Schweitzer             Status = RtlUnicodeStringToAnsiString(&AnsiString, &TargetPathU, FALSE);
5158d128aa4SPierre Schweitzer             if (!NT_SUCCESS(Status))
516c2c66affSColin Finck             {
5178d128aa4SPierre Schweitzer                 BaseSetLastNTError(Status);
5188d128aa4SPierre Schweitzer                 /* In case of a failure, forget about everything */
5198d128aa4SPierre Schweitzer                 RetLength = 0;
5208d128aa4SPierre Schweitzer 
5218d128aa4SPierre Schweitzer                 goto Leave;
522c2c66affSColin Finck             }
5238d128aa4SPierre Schweitzer 
5248d128aa4SPierre Schweitzer             /* Move to the next string */
5258d128aa4SPierre Schweitzer             CurrentPosition += CurrentLength;
5268d128aa4SPierre Schweitzer         }
5278d128aa4SPierre Schweitzer     }
5288d128aa4SPierre Schweitzer 
5298d128aa4SPierre Schweitzer Leave:
5308d128aa4SPierre Schweitzer     /* Free our intermediate buffer and leave */
5318d128aa4SPierre Schweitzer     RtlFreeHeap(RtlGetProcessHeap(), 0, TargetPathBuffer);
5328d128aa4SPierre Schweitzer 
5338d128aa4SPierre Schweitzer     return RetLength;
534c2c66affSColin Finck }
535c2c66affSColin Finck 
536c2c66affSColin Finck 
537c2c66affSColin Finck /*
538c2c66affSColin Finck  * @implemented
539c2c66affSColin Finck  */
540c2c66affSColin Finck DWORD
541c2c66affSColin Finck WINAPI
QueryDosDeviceW(LPCWSTR lpDeviceName,LPWSTR lpTargetPath,DWORD ucchMax)542c2c66affSColin Finck QueryDosDeviceW(
543c2c66affSColin Finck     LPCWSTR lpDeviceName,
544c2c66affSColin Finck     LPWSTR lpTargetPath,
545c2c66affSColin Finck     DWORD ucchMax
546c2c66affSColin Finck     )
547c2c66affSColin Finck {
548c2c66affSColin Finck     PWSTR Ptr;
5495d20d512SPierre Schweitzer     PVOID Buffer;
5505d20d512SPierre Schweitzer     NTSTATUS Status;
5515d20d512SPierre Schweitzer     USHORT i, TotalEntries;
5525d20d512SPierre Schweitzer     UNICODE_STRING UnicodeString;
5535d20d512SPierre Schweitzer     OBJECT_ATTRIBUTES ObjectAttributes;
5545d20d512SPierre Schweitzer     HANDLE DirectoryHandle, DeviceHandle;
5555d20d512SPierre Schweitzer     BOOLEAN IsGlobal, GlobalNeeded, Found;
5565d20d512SPierre Schweitzer     POBJECT_DIRECTORY_INFORMATION DirInfo;
5575d20d512SPierre Schweitzer     OBJECT_DIRECTORY_INFORMATION NullEntry = {{0}};
5585d20d512SPierre Schweitzer     ULONG ReturnLength, NameLength, Length, Context, BufferLength;
559c2c66affSColin Finck 
560c2c66affSColin Finck     /* Open the '\??' directory */
561c2c66affSColin Finck     RtlInitUnicodeString(&UnicodeString, L"\\??");
562c2c66affSColin Finck     InitializeObjectAttributes(&ObjectAttributes,
563c2c66affSColin Finck                                &UnicodeString,
564c2c66affSColin Finck                                OBJ_CASE_INSENSITIVE,
565c2c66affSColin Finck                                NULL,
566c2c66affSColin Finck                                NULL);
567c2c66affSColin Finck     Status = NtOpenDirectoryObject(&DirectoryHandle,
568c2c66affSColin Finck                                    DIRECTORY_QUERY,
569c2c66affSColin Finck                                    &ObjectAttributes);
570c2c66affSColin Finck     if (!NT_SUCCESS(Status))
571c2c66affSColin Finck     {
572c2c66affSColin Finck         WARN("NtOpenDirectoryObject() failed (Status %lx)\n", Status);
573c2c66affSColin Finck         BaseSetLastNTError(Status);
574c2c66affSColin Finck         return 0;
575c2c66affSColin Finck     }
576c2c66affSColin Finck 
5775d20d512SPierre Schweitzer     Buffer = NULL;
5785d20d512SPierre Schweitzer     _SEH2_TRY
5795d20d512SPierre Schweitzer     {
580c2c66affSColin Finck         if (lpDeviceName != NULL)
581c2c66affSColin Finck         {
582c2c66affSColin Finck             /* Open the lpDeviceName link object */
5835d20d512SPierre Schweitzer             RtlInitUnicodeString(&UnicodeString, lpDeviceName);
584c2c66affSColin Finck             InitializeObjectAttributes(&ObjectAttributes,
585c2c66affSColin Finck                                        &UnicodeString,
586c2c66affSColin Finck                                        OBJ_CASE_INSENSITIVE,
587c2c66affSColin Finck                                        DirectoryHandle,
588c2c66affSColin Finck                                        NULL);
589c2c66affSColin Finck             Status = NtOpenSymbolicLinkObject(&DeviceHandle,
590c2c66affSColin Finck                                               SYMBOLIC_LINK_QUERY,
591c2c66affSColin Finck                                               &ObjectAttributes);
592c2c66affSColin Finck             if (!NT_SUCCESS(Status))
593c2c66affSColin Finck             {
594c2c66affSColin Finck                 WARN("NtOpenSymbolicLinkObject() failed (Status %lx)\n", Status);
5955d20d512SPierre Schweitzer                 _SEH2_LEAVE;
596c2c66affSColin Finck             }
597c2c66affSColin Finck 
5985d20d512SPierre Schweitzer             /*
5995d20d512SPierre Schweitzer              * Make sure we don't overrun the output buffer, so convert our DWORD
6005d20d512SPierre Schweitzer              * size to USHORT size properly
6015d20d512SPierre Schweitzer              */
6025d20d512SPierre Schweitzer             Length = (ucchMax <= MAXULONG / sizeof(WCHAR)) ? (ucchMax * sizeof(WCHAR)) : MAXULONG;
6035d20d512SPierre Schweitzer 
604c2c66affSColin Finck             /* Query link target */
605c2c66affSColin Finck             UnicodeString.Length = 0;
6065d20d512SPierre Schweitzer             UnicodeString.MaximumLength = Length <= MAXUSHORT ? Length : MAXUSHORT;
607c2c66affSColin Finck             UnicodeString.Buffer = lpTargetPath;
608c2c66affSColin Finck 
609c2c66affSColin Finck             ReturnLength = 0;
610c2c66affSColin Finck             Status = NtQuerySymbolicLinkObject(DeviceHandle,
611c2c66affSColin Finck                                                &UnicodeString,
612c2c66affSColin Finck                                                &ReturnLength);
613c2c66affSColin Finck             NtClose(DeviceHandle);
614c2c66affSColin Finck             if (!NT_SUCCESS(Status))
615c2c66affSColin Finck             {
616c2c66affSColin Finck                 WARN("NtQuerySymbolicLinkObject() failed (Status %lx)\n", Status);
6175d20d512SPierre Schweitzer                 _SEH2_LEAVE;
618c2c66affSColin Finck             }
619c2c66affSColin Finck 
620c2c66affSColin Finck             TRACE("ReturnLength: %lu\n", ReturnLength);
621c2c66affSColin Finck             TRACE("TargetLength: %hu\n", UnicodeString.Length);
622c2c66affSColin Finck             TRACE("Target: '%wZ'\n", &UnicodeString);
623c2c66affSColin Finck 
6245d20d512SPierre Schweitzer             Length = ReturnLength / sizeof(WCHAR);
6255d20d512SPierre Schweitzer             /* Make sure we null terminate output buffer */
6265d20d512SPierre Schweitzer             if (Length == 0 || lpTargetPath[Length - 1] != UNICODE_NULL)
6275d20d512SPierre Schweitzer             {
6285d20d512SPierre Schweitzer                 if (Length >= ucchMax)
6295d20d512SPierre Schweitzer                 {
6305d20d512SPierre Schweitzer                     TRACE("Buffer is too small\n");
6315d20d512SPierre Schweitzer                     Status = STATUS_BUFFER_TOO_SMALL;
6325d20d512SPierre Schweitzer                     _SEH2_LEAVE;
6335d20d512SPierre Schweitzer                 }
6345d20d512SPierre Schweitzer 
6355d20d512SPierre Schweitzer                 /* Append null-character */
6365d20d512SPierre Schweitzer                 lpTargetPath[Length] = UNICODE_NULL;
6375d20d512SPierre Schweitzer                 Length++;
6385d20d512SPierre Schweitzer             }
6395d20d512SPierre Schweitzer 
640c2c66affSColin Finck             if (Length < ucchMax)
641c2c66affSColin Finck             {
642c2c66affSColin Finck                 /* Append null-character */
643c2c66affSColin Finck                 lpTargetPath[Length] = UNICODE_NULL;
644c2c66affSColin Finck                 Length++;
645c2c66affSColin Finck             }
646c2c66affSColin Finck 
6475d20d512SPierre Schweitzer             _SEH2_LEAVE;
6485d20d512SPierre Schweitzer         }
6495d20d512SPierre Schweitzer 
6505d20d512SPierre Schweitzer         /*
6515d20d512SPierre Schweitzer          * If LUID device maps are enabled,
6525d20d512SPierre Schweitzer          * ?? may not point to BaseNamedObjects
6535d20d512SPierre Schweitzer          * It may only be local DOS namespace.
6545d20d512SPierre Schweitzer          * And thus, it might be required to browse
6555d20d512SPierre Schweitzer          * Global?? for global devices
6565d20d512SPierre Schweitzer          */
6575d20d512SPierre Schweitzer         GlobalNeeded = FALSE;
6585d20d512SPierre Schweitzer         if (BaseStaticServerData->LUIDDeviceMapsEnabled)
659c2c66affSColin Finck         {
6605d20d512SPierre Schweitzer             /* Assume ?? == Global?? */
6615d20d512SPierre Schweitzer             IsGlobal = TRUE;
6625d20d512SPierre Schweitzer             /* Check if it's the case */
6635d20d512SPierre Schweitzer             Status = IsGlobalDeviceMap(DirectoryHandle, &IsGlobal);
6645d20d512SPierre Schweitzer             if (NT_SUCCESS(Status) && !IsGlobal)
6655d20d512SPierre Schweitzer             {
6665d20d512SPierre Schweitzer                 /* It's not, we'll have to browse Global?? too! */
6675d20d512SPierre Schweitzer                 GlobalNeeded = TRUE;
6685d20d512SPierre Schweitzer             }
6695d20d512SPierre Schweitzer         }
6705d20d512SPierre Schweitzer 
6715d20d512SPierre Schweitzer         /*
6725d20d512SPierre Schweitzer          * Make sure we don't overrun the output buffer, so convert our DWORD
6735d20d512SPierre Schweitzer          * size to USHORT size properly
6745d20d512SPierre Schweitzer          */
6755d20d512SPierre Schweitzer         BufferLength = (ucchMax <= MAXULONG / sizeof(WCHAR)) ? (ucchMax * sizeof(WCHAR)) : MAXULONG;
6765d20d512SPierre Schweitzer         Length = 0;
6775d20d512SPierre Schweitzer         Ptr = lpTargetPath;
6785d20d512SPierre Schweitzer 
6795d20d512SPierre Schweitzer         Context = 0;
6805d20d512SPierre Schweitzer         TotalEntries = 0;
6815d20d512SPierre Schweitzer 
6825d20d512SPierre Schweitzer         /*
6835d20d512SPierre Schweitzer          * We'll query all entries at once, with a rather big buffer
6845d20d512SPierre Schweitzer          * If it's too small, we'll grow it by 2.
6855d20d512SPierre Schweitzer          * Limit the number of attempts to 3.
6865d20d512SPierre Schweitzer          */
6875d20d512SPierre Schweitzer         for (i = 0; i < 3; ++i)
6885d20d512SPierre Schweitzer         {
6895d20d512SPierre Schweitzer             /* Allocate the query buffer */
6905d20d512SPierre Schweitzer             Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength);
6915d20d512SPierre Schweitzer             if (Buffer == NULL)
6925d20d512SPierre Schweitzer             {
6935d20d512SPierre Schweitzer                 Status = STATUS_INSUFFICIENT_RESOURCES;
6945d20d512SPierre Schweitzer                 _SEH2_LEAVE;
6955d20d512SPierre Schweitzer             }
6965d20d512SPierre Schweitzer 
6975d20d512SPierre Schweitzer             /* Perform the query */
698c2c66affSColin Finck             Status = NtQueryDirectoryObject(DirectoryHandle,
699c2c66affSColin Finck                                             Buffer,
7005d20d512SPierre Schweitzer                                             BufferLength,
7015d20d512SPierre Schweitzer                                             FALSE,
702c2c66affSColin Finck                                             TRUE,
703c2c66affSColin Finck                                             &Context,
704c2c66affSColin Finck                                             &ReturnLength);
7055d20d512SPierre Schweitzer             /* Only failure accepted is: no more entries */
706c2c66affSColin Finck             if (!NT_SUCCESS(Status))
707c2c66affSColin Finck             {
7085d20d512SPierre Schweitzer                 if (Status != STATUS_NO_MORE_ENTRIES)
709c2c66affSColin Finck                 {
7105d20d512SPierre Schweitzer                     _SEH2_LEAVE;
7115d20d512SPierre Schweitzer                 }
712c2c66affSColin Finck 
7135d20d512SPierre Schweitzer                 /*
7145d20d512SPierre Schweitzer                  * Which is a success! But break out,
7155d20d512SPierre Schweitzer                  * it means our query returned no results
7165d20d512SPierre Schweitzer                  * so, nothing to parse.
7175d20d512SPierre Schweitzer                  */
718c2c66affSColin Finck                 Status = STATUS_SUCCESS;
719c2c66affSColin Finck                 break;
720c2c66affSColin Finck             }
721c2c66affSColin Finck 
7225d20d512SPierre Schweitzer             /* In case we had them all, start browsing for devices */
7235d20d512SPierre Schweitzer             if (Status != STATUS_MORE_ENTRIES)
7245d20d512SPierre Schweitzer             {
7255d20d512SPierre Schweitzer                 DirInfo = Buffer;
7265d20d512SPierre Schweitzer 
7275d20d512SPierre Schweitzer                 /* Loop until we find the nul entry (terminating entry) */
7285d20d512SPierre Schweitzer                 while (TRUE)
7295d20d512SPierre Schweitzer                 {
7305d20d512SPierre Schweitzer                     /* It's an entry full of zeroes */
7315d20d512SPierre Schweitzer                     if (RtlCompareMemory(&NullEntry, DirInfo, sizeof(NullEntry)) == sizeof(NullEntry))
7325d20d512SPierre Schweitzer                     {
7335d20d512SPierre Schweitzer                         break;
7345d20d512SPierre Schweitzer                     }
7355d20d512SPierre Schweitzer 
7365d20d512SPierre Schweitzer                     /* Only handle symlinks */
737c2c66affSColin Finck                     if (!wcscmp(DirInfo->TypeName.Buffer, L"SymbolicLink"))
738c2c66affSColin Finck                     {
739c2c66affSColin Finck                         TRACE("Name: '%wZ'\n", &DirInfo->Name);
740c2c66affSColin Finck 
7415d20d512SPierre Schweitzer                         /* Get name length in chars to only comparisons */
742c2c66affSColin Finck                         NameLength = DirInfo->Name.Length / sizeof(WCHAR);
7435d20d512SPierre Schweitzer 
7445d20d512SPierre Schweitzer                         /* Make sure we don't overrun output buffer */
7455d20d512SPierre Schweitzer                         if (Length > ucchMax ||
7465d20d512SPierre Schweitzer                             NameLength > ucchMax - Length ||
7475d20d512SPierre Schweitzer                             ucchMax - NameLength - Length < sizeof(WCHAR))
748c2c66affSColin Finck                         {
7495d20d512SPierre Schweitzer                             Status = STATUS_BUFFER_TOO_SMALL;
7505d20d512SPierre Schweitzer                             _SEH2_LEAVE;
7515d20d512SPierre Schweitzer                         }
7525d20d512SPierre Schweitzer 
7535d20d512SPierre Schweitzer                         /* Copy and NULL terminate string */
7545d20d512SPierre Schweitzer                         memcpy(Ptr, DirInfo->Name.Buffer, DirInfo->Name.Length);
7555d20d512SPierre Schweitzer                         Ptr[NameLength] = UNICODE_NULL;
7565d20d512SPierre Schweitzer 
7575d20d512SPierre Schweitzer                         Ptr += (NameLength + 1);
7585d20d512SPierre Schweitzer                         Length += (NameLength + 1);
7595d20d512SPierre Schweitzer 
7605d20d512SPierre Schweitzer                         /*
7615d20d512SPierre Schweitzer                          * Keep the entries count, in case we would have to
7625d20d512SPierre Schweitzer                          * handle GLOBAL?? too
7635d20d512SPierre Schweitzer                          */
7645d20d512SPierre Schweitzer                         ++TotalEntries;
7655d20d512SPierre Schweitzer                     }
7665d20d512SPierre Schweitzer 
7675d20d512SPierre Schweitzer                     /* Move to the next entry */
7685d20d512SPierre Schweitzer                     ++DirInfo;
7695d20d512SPierre Schweitzer                 }
7705d20d512SPierre Schweitzer 
7715d20d512SPierre Schweitzer                 /*
7725d20d512SPierre Schweitzer                  * No need to loop again here, we got all the entries
7735d20d512SPierre Schweitzer                  * Note: we don't free the buffer here, because we may
7745d20d512SPierre Schweitzer                  * need it for GLOBAL??, so we save a few cycles here.
7755d20d512SPierre Schweitzer                  */
776c2c66affSColin Finck                 break;
777c2c66affSColin Finck             }
778c2c66affSColin Finck 
7795d20d512SPierre Schweitzer             /* Failure path here, we'll need bigger buffer */
7805d20d512SPierre Schweitzer             RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
7815d20d512SPierre Schweitzer             Buffer = NULL;
7825d20d512SPierre Schweitzer 
7835d20d512SPierre Schweitzer             /* We can't have bigger than that one, so leave */
7845d20d512SPierre Schweitzer             if (BufferLength == MAXULONG)
7855d20d512SPierre Schweitzer             {
7865d20d512SPierre Schweitzer                 break;
7875d20d512SPierre Schweitzer             }
7885d20d512SPierre Schweitzer 
7895d20d512SPierre Schweitzer             /* Prevent any overflow while computing new size */
7905d20d512SPierre Schweitzer             if (MAXULONG - BufferLength < BufferLength)
7915d20d512SPierre Schweitzer             {
7925d20d512SPierre Schweitzer                 BufferLength = MAXULONG;
7935d20d512SPierre Schweitzer             }
7945d20d512SPierre Schweitzer             else
7955d20d512SPierre Schweitzer             {
7965d20d512SPierre Schweitzer                 BufferLength *= 2;
7975d20d512SPierre Schweitzer             }
7985d20d512SPierre Schweitzer         }
7995d20d512SPierre Schweitzer 
8005d20d512SPierre Schweitzer         /*
8015d20d512SPierre Schweitzer          * Out of the hot loop, but with more entries left?
8025d20d512SPierre Schweitzer          * that's an error case, leave here!
8035d20d512SPierre Schweitzer          */
8045d20d512SPierre Schweitzer         if (Status == STATUS_MORE_ENTRIES)
8055d20d512SPierre Schweitzer         {
8065d20d512SPierre Schweitzer             Status = STATUS_BUFFER_TOO_SMALL;
8075d20d512SPierre Schweitzer             _SEH2_LEAVE;
8085d20d512SPierre Schweitzer         }
8095d20d512SPierre Schweitzer 
8105d20d512SPierre Schweitzer         /* Now, if we had to handle GLOBAL??, go for it! */
8115d20d512SPierre Schweitzer         if (BaseStaticServerData->LUIDDeviceMapsEnabled && NT_SUCCESS(Status) && GlobalNeeded)
8125d20d512SPierre Schweitzer         {
8135d20d512SPierre Schweitzer             NtClose(DirectoryHandle);
8145d20d512SPierre Schweitzer             DirectoryHandle = 0;
8155d20d512SPierre Schweitzer 
8165d20d512SPierre Schweitzer             RtlInitUnicodeString(&UnicodeString, L"\\GLOBAL??");
8175d20d512SPierre Schweitzer             InitializeObjectAttributes(&ObjectAttributes,
8185d20d512SPierre Schweitzer                                        &UnicodeString,
8195d20d512SPierre Schweitzer                                        OBJ_CASE_INSENSITIVE,
8205d20d512SPierre Schweitzer                                        NULL,
8215d20d512SPierre Schweitzer                                        NULL);
8225d20d512SPierre Schweitzer             Status = NtOpenDirectoryObject(&DirectoryHandle,
8235d20d512SPierre Schweitzer                                            DIRECTORY_QUERY,
8245d20d512SPierre Schweitzer                                            &ObjectAttributes);
8255d20d512SPierre Schweitzer             if (!NT_SUCCESS(Status))
8265d20d512SPierre Schweitzer             {
8275d20d512SPierre Schweitzer                 WARN("NtOpenDirectoryObject() failed (Status %lx)\n", Status);
8285d20d512SPierre Schweitzer                 _SEH2_LEAVE;
8295d20d512SPierre Schweitzer             }
8305d20d512SPierre Schweitzer 
8315d20d512SPierre Schweitzer             /*
8325d20d512SPierre Schweitzer              * We'll query all entries at once, with a rather big buffer
8335d20d512SPierre Schweitzer              * If it's too small, we'll grow it by 2.
8345d20d512SPierre Schweitzer              * Limit the number of attempts to 3.
8355d20d512SPierre Schweitzer              */
8365d20d512SPierre Schweitzer             for (i = 0; i < 3; ++i)
8375d20d512SPierre Schweitzer             {
8385d20d512SPierre Schweitzer                 /* If we had no buffer from previous attempt, allocate one */
8395d20d512SPierre Schweitzer                 if (Buffer == NULL)
8405d20d512SPierre Schweitzer                 {
8415d20d512SPierre Schweitzer                     Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength);
8425d20d512SPierre Schweitzer                     if (Buffer == NULL)
8435d20d512SPierre Schweitzer                     {
8445d20d512SPierre Schweitzer                         Status = STATUS_INSUFFICIENT_RESOURCES;
8455d20d512SPierre Schweitzer                         _SEH2_LEAVE;
8465d20d512SPierre Schweitzer                     }
8475d20d512SPierre Schweitzer                 }
8485d20d512SPierre Schweitzer 
8495d20d512SPierre Schweitzer                 /* Perform the query */
8505d20d512SPierre Schweitzer                 Status = NtQueryDirectoryObject(DirectoryHandle,
8515d20d512SPierre Schweitzer                                                 Buffer,
8525d20d512SPierre Schweitzer                                                 BufferLength,
8535d20d512SPierre Schweitzer                                                 FALSE,
8545d20d512SPierre Schweitzer                                                 TRUE,
8555d20d512SPierre Schweitzer                                                 &Context,
8565d20d512SPierre Schweitzer                                                 &ReturnLength);
8575d20d512SPierre Schweitzer                 /* Only failure accepted is: no more entries */
8585d20d512SPierre Schweitzer                 if (!NT_SUCCESS(Status))
8595d20d512SPierre Schweitzer                 {
8605d20d512SPierre Schweitzer                     if (Status != STATUS_NO_MORE_ENTRIES)
8615d20d512SPierre Schweitzer                     {
8625d20d512SPierre Schweitzer                         _SEH2_LEAVE;
8635d20d512SPierre Schweitzer                     }
8645d20d512SPierre Schweitzer 
8655d20d512SPierre Schweitzer                     /*
8665d20d512SPierre Schweitzer                      * Which is a success! But break out,
8675d20d512SPierre Schweitzer                      * it means our query returned no results
8685d20d512SPierre Schweitzer                      * so, nothing to parse.
8695d20d512SPierre Schweitzer                      */
8705d20d512SPierre Schweitzer                     Status = STATUS_SUCCESS;
8715d20d512SPierre Schweitzer                     break;
8725d20d512SPierre Schweitzer                 }
8735d20d512SPierre Schweitzer 
8745d20d512SPierre Schweitzer                 /* In case we had them all, start browsing for devices */
8755d20d512SPierre Schweitzer                 if (Status != STATUS_MORE_ENTRIES)
8765d20d512SPierre Schweitzer                 {
8775d20d512SPierre Schweitzer                     DirInfo = Buffer;
8785d20d512SPierre Schweitzer 
8795d20d512SPierre Schweitzer                     /* Loop until we find the nul entry (terminating entry) */
8805d20d512SPierre Schweitzer                     while (TRUE)
8815d20d512SPierre Schweitzer                     {
8825d20d512SPierre Schweitzer                         /* It's an entry full of zeroes */
8835d20d512SPierre Schweitzer                         if (RtlCompareMemory(&NullEntry, DirInfo, sizeof(NullEntry)) == sizeof(NullEntry))
8845d20d512SPierre Schweitzer                         {
8855d20d512SPierre Schweitzer                             break;
8865d20d512SPierre Schweitzer                         }
8875d20d512SPierre Schweitzer 
8885d20d512SPierre Schweitzer                         /* Only handle symlinks */
8895d20d512SPierre Schweitzer                         if (!wcscmp(DirInfo->TypeName.Buffer, L"SymbolicLink"))
8905d20d512SPierre Schweitzer                         {
8915d20d512SPierre Schweitzer                             TRACE("Name: '%wZ'\n", &DirInfo->Name);
8925d20d512SPierre Schweitzer 
8935d20d512SPierre Schweitzer                             /*
8945d20d512SPierre Schweitzer                              * Now, we previously already browsed ??, and we
8955d20d512SPierre Schweitzer                              * don't want to devices twice, so we'll check
8965d20d512SPierre Schweitzer                              * the output buffer for duplicates.
8975d20d512SPierre Schweitzer                              * We'll add our entry only if we don't have already
8985d20d512SPierre Schweitzer                              * returned it.
8995d20d512SPierre Schweitzer                              */
9005d20d512SPierre Schweitzer                             if (FindSymbolicLinkEntry(DirInfo->Name.Buffer,
9015d20d512SPierre Schweitzer                                                       lpTargetPath,
9025d20d512SPierre Schweitzer                                                       TotalEntries,
9035d20d512SPierre Schweitzer                                                       &Found) == ERROR_SUCCESS &&
9045d20d512SPierre Schweitzer                                 !Found)
9055d20d512SPierre Schweitzer                             {
9065d20d512SPierre Schweitzer                                 /* Get name length in chars to only comparisons */
9075d20d512SPierre Schweitzer                                 NameLength = DirInfo->Name.Length / sizeof(WCHAR);
9085d20d512SPierre Schweitzer 
9095d20d512SPierre Schweitzer                                 /* Make sure we don't overrun output buffer */
9105d20d512SPierre Schweitzer                                 if (Length > ucchMax ||
9115d20d512SPierre Schweitzer                                     NameLength > ucchMax - Length ||
9125d20d512SPierre Schweitzer                                     ucchMax - NameLength - Length < sizeof(WCHAR))
9135d20d512SPierre Schweitzer                                 {
9145d20d512SPierre Schweitzer                                     RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
9155d20d512SPierre Schweitzer                                     NtClose(DirectoryHandle);
9165d20d512SPierre Schweitzer                                     BaseSetLastNTError(STATUS_BUFFER_TOO_SMALL);
9175d20d512SPierre Schweitzer                                     return 0;
9185d20d512SPierre Schweitzer                                 }
9195d20d512SPierre Schweitzer 
9205d20d512SPierre Schweitzer                                 /* Copy and NULL terminate string */
921c2c66affSColin Finck                                 memcpy(Ptr, DirInfo->Name.Buffer, DirInfo->Name.Length);
9225d20d512SPierre Schweitzer                                 Ptr[NameLength] = UNICODE_NULL;
9235d20d512SPierre Schweitzer 
9245d20d512SPierre Schweitzer                                 Ptr += (NameLength + 1);
9255d20d512SPierre Schweitzer                                 Length += (NameLength + 1);
9265d20d512SPierre Schweitzer                             }
9275d20d512SPierre Schweitzer                         }
9285d20d512SPierre Schweitzer 
9295d20d512SPierre Schweitzer                         /* Move to the next entry */
9305d20d512SPierre Schweitzer                         ++DirInfo;
9315d20d512SPierre Schweitzer                     }
9325d20d512SPierre Schweitzer 
9335d20d512SPierre Schweitzer                     /* No need to loop again here, we got all the entries */
9345d20d512SPierre Schweitzer                     break;
9355d20d512SPierre Schweitzer                 }
9365d20d512SPierre Schweitzer 
9375d20d512SPierre Schweitzer                 /* Failure path here, we'll need bigger buffer */
9385d20d512SPierre Schweitzer                 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
9395d20d512SPierre Schweitzer                 Buffer = NULL;
9405d20d512SPierre Schweitzer 
9415d20d512SPierre Schweitzer                 /* We can't have bigger than that one, so leave */
9425d20d512SPierre Schweitzer                 if (BufferLength == MAXULONG)
9435d20d512SPierre Schweitzer                 {
9445d20d512SPierre Schweitzer                     break;
9455d20d512SPierre Schweitzer                 }
9465d20d512SPierre Schweitzer 
9475d20d512SPierre Schweitzer                 /* Prevent any overflow while computing new size */
9485d20d512SPierre Schweitzer                 if (MAXULONG - BufferLength < BufferLength)
9495d20d512SPierre Schweitzer                 {
9505d20d512SPierre Schweitzer                     BufferLength = MAXULONG;
9515d20d512SPierre Schweitzer                 }
9525d20d512SPierre Schweitzer                 else
9535d20d512SPierre Schweitzer                 {
9545d20d512SPierre Schweitzer                     BufferLength *= 2;
9555d20d512SPierre Schweitzer                 }
9565d20d512SPierre Schweitzer             }
9575d20d512SPierre Schweitzer 
9585d20d512SPierre Schweitzer             /*
9595d20d512SPierre Schweitzer              * Out of the hot loop, but with more entries left?
9605d20d512SPierre Schweitzer              * that's an error case, leave here!
9615d20d512SPierre Schweitzer              */
9625d20d512SPierre Schweitzer             if (Status == STATUS_MORE_ENTRIES)
9635d20d512SPierre Schweitzer             {
9645d20d512SPierre Schweitzer                 Status = STATUS_BUFFER_TOO_SMALL;
9655d20d512SPierre Schweitzer                 _SEH2_LEAVE;
9665d20d512SPierre Schweitzer             }
9675d20d512SPierre Schweitzer         }
9685d20d512SPierre Schweitzer 
9695d20d512SPierre Schweitzer         /* If we failed somewhere, just leave */
9705d20d512SPierre Schweitzer         if (!NT_SUCCESS(Status))
9715d20d512SPierre Schweitzer         {
9725d20d512SPierre Schweitzer             _SEH2_LEAVE;
9735d20d512SPierre Schweitzer         }
9745d20d512SPierre Schweitzer 
9755d20d512SPierre Schweitzer         /* If we returned no entries, time to write the empty string */
9765d20d512SPierre Schweitzer         if (Length == 0)
9775d20d512SPierre Schweitzer         {
9785d20d512SPierre Schweitzer             /* Unless output buffer is too small! */
9795d20d512SPierre Schweitzer             if (ucchMax <= 0)
9805d20d512SPierre Schweitzer             {
9815d20d512SPierre Schweitzer                 Status = STATUS_BUFFER_TOO_SMALL;
9825d20d512SPierre Schweitzer                 _SEH2_LEAVE;
9835d20d512SPierre Schweitzer             }
9845d20d512SPierre Schweitzer 
9855d20d512SPierre Schweitzer             /* Emptry string is one char (terminator!) */
986c2c66affSColin Finck             *Ptr = UNICODE_NULL;
9875d20d512SPierre Schweitzer             ++Ptr;
9885d20d512SPierre Schweitzer             Length = 1;
989c2c66affSColin Finck         }
990c2c66affSColin Finck 
9915d20d512SPierre Schweitzer         /*
9925d20d512SPierre Schweitzer          * If we have enough room, we need to double terminate the buffer:
9935d20d512SPierre Schweitzer          * that's a MULTI_SZ buffer, its end is marked by double NULL.
9945d20d512SPierre Schweitzer          * One was already added during the "copy string" process.
9955d20d512SPierre Schweitzer          * If we don't have enough room: that's a failure case.
9965d20d512SPierre Schweitzer          */
9975d20d512SPierre Schweitzer         if (Length < ucchMax)
9985d20d512SPierre Schweitzer         {
9995d20d512SPierre Schweitzer             *Ptr = UNICODE_NULL;
10005d20d512SPierre Schweitzer             ++Ptr;
1001c2c66affSColin Finck         }
10025d20d512SPierre Schweitzer         else
10035d20d512SPierre Schweitzer         {
10045d20d512SPierre Schweitzer             Status = STATUS_BUFFER_TOO_SMALL;
10055d20d512SPierre Schweitzer         }
10065d20d512SPierre Schweitzer     }
10075d20d512SPierre Schweitzer     _SEH2_FINALLY
10085d20d512SPierre Schweitzer     {
10095d20d512SPierre Schweitzer         if (DirectoryHandle != 0)
10105d20d512SPierre Schweitzer         {
1011c2c66affSColin Finck             NtClose(DirectoryHandle);
1012c2c66affSColin Finck         }
1013c2c66affSColin Finck 
10145d20d512SPierre Schweitzer         if (Buffer != NULL)
10155d20d512SPierre Schweitzer         {
10165d20d512SPierre Schweitzer             RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
10175d20d512SPierre Schweitzer         }
10185d20d512SPierre Schweitzer 
10195d20d512SPierre Schweitzer         if (!NT_SUCCESS(Status))
10205d20d512SPierre Schweitzer         {
10215d20d512SPierre Schweitzer             Length = 0;
10225d20d512SPierre Schweitzer             BaseSetLastNTError(Status);
10235d20d512SPierre Schweitzer         }
10245d20d512SPierre Schweitzer     }
10255d20d512SPierre Schweitzer     _SEH2_END;
10265d20d512SPierre Schweitzer 
1027c2c66affSColin Finck     return Length;
1028c2c66affSColin Finck }
1029c2c66affSColin Finck 
1030c2c66affSColin Finck /* EOF */
1031