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