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