xref: /reactos/dll/win32/kernel32/client/dosdev.c (revision 5100859e)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS system libraries
4  * FILE:            dll/win32/kernel32/client/dosdev.c
5  * PURPOSE:         Dos device functions
6  * PROGRAMMER:      Ariadne (ariadne@xs4all.nl)
7  * UPDATE HISTORY:
8  *                  Created 01/11/98
9  */
10 
11 /* INCLUDES ******************************************************************/
12 
13 #include <k32.h>
14 
15 #define NDEBUG
16 #include <debug.h>
17 #include <dbt.h>
18 DEBUG_CHANNEL(kernel32file);
19 
20 /* FUNCTIONS *****************************************************************/
21 
22 /*
23  * @implemented
24  */
25 BOOL
26 WINAPI
27 DefineDosDeviceA(
28     DWORD dwFlags,
29     LPCSTR lpDeviceName,
30     LPCSTR lpTargetPath
31     )
32 {
33     UNICODE_STRING DeviceNameU = {0};
34     UNICODE_STRING TargetPathU = {0};
35     BOOL Result;
36 
37     if (lpDeviceName &&
38         !RtlCreateUnicodeStringFromAsciiz(&DeviceNameU, lpDeviceName))
39     {
40         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
41         return 0;
42     }
43 
44     if (lpTargetPath &&
45         !RtlCreateUnicodeStringFromAsciiz(&TargetPathU, lpTargetPath))
46     {
47         if (DeviceNameU.Buffer)
48         {
49             RtlFreeUnicodeString(&DeviceNameU);
50         }
51         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
52         return 0;
53     }
54 
55     Result = DefineDosDeviceW(dwFlags,
56                               DeviceNameU.Buffer,
57                               TargetPathU.Buffer);
58 
59     if (TargetPathU.Buffer)
60     {
61         RtlFreeUnicodeString(&TargetPathU);
62     }
63 
64     if (DeviceNameU.Buffer)
65     {
66         RtlFreeUnicodeString(&DeviceNameU);
67     }
68     return Result;
69 }
70 
71 
72 /*
73  * @implemented
74  */
75 BOOL
76 WINAPI
77 DefineDosDeviceW(
78     DWORD dwFlags,
79     LPCWSTR lpDeviceName,
80     LPCWSTR lpTargetPath
81     )
82 {
83     ULONG ArgumentCount;
84     ULONG BufferSize;
85     BASE_API_MESSAGE ApiMessage;
86     PBASE_DEFINE_DOS_DEVICE DefineDosDeviceRequest = &ApiMessage.Data.DefineDosDeviceRequest;
87     PCSR_CAPTURE_BUFFER CaptureBuffer;
88     UNICODE_STRING NtTargetPathU;
89     UNICODE_STRING DeviceNameU;
90     UNICODE_STRING DeviceUpcaseNameU;
91     HANDLE hUser32;
92     DEV_BROADCAST_VOLUME dbcv;
93     BOOL Result = TRUE;
94     DWORD dwRecipients;
95     typedef long (WINAPI *BSM_type)(DWORD, LPDWORD, UINT, WPARAM, LPARAM);
96     BSM_type BSM_ptr;
97 
98     if ( (dwFlags & 0xFFFFFFF0) ||
99         ((dwFlags & DDD_EXACT_MATCH_ON_REMOVE) &&
100         ! (dwFlags & DDD_REMOVE_DEFINITION)) )
101     {
102         SetLastError(ERROR_INVALID_PARAMETER);
103         return FALSE;
104     }
105 
106     ArgumentCount = 1;
107     BufferSize = 0;
108     if (!lpTargetPath)
109     {
110         RtlInitUnicodeString(&NtTargetPathU,
111                              NULL);
112     }
113     else
114     {
115         if (dwFlags & DDD_RAW_TARGET_PATH)
116         {
117             RtlInitUnicodeString(&NtTargetPathU,
118                                  lpTargetPath);
119         }
120         else
121         {
122             if (!RtlDosPathNameToNtPathName_U(lpTargetPath,
123                                               &NtTargetPathU,
124                                               NULL,
125                                               NULL))
126             {
127                 WARN("RtlDosPathNameToNtPathName_U() failed\n");
128                 BaseSetLastNTError(STATUS_OBJECT_NAME_INVALID);
129                 return FALSE;
130             }
131         }
132         ArgumentCount = 2;
133         BufferSize += NtTargetPathU.Length;
134     }
135 
136     RtlInitUnicodeString(&DeviceNameU,
137                          lpDeviceName);
138     RtlUpcaseUnicodeString(&DeviceUpcaseNameU,
139                            &DeviceNameU,
140                            TRUE);
141     BufferSize += DeviceUpcaseNameU.Length;
142 
143     CaptureBuffer = CsrAllocateCaptureBuffer(ArgumentCount,
144                                              BufferSize);
145     if (!CaptureBuffer)
146     {
147         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
148         Result = FALSE;
149     }
150     else
151     {
152         DefineDosDeviceRequest->Flags = dwFlags;
153 
154         CsrCaptureMessageBuffer(CaptureBuffer,
155                                 DeviceUpcaseNameU.Buffer,
156                                 DeviceUpcaseNameU.Length,
157                                 (PVOID*)&DefineDosDeviceRequest->DeviceName.Buffer);
158 
159         DefineDosDeviceRequest->DeviceName.Length =
160             DeviceUpcaseNameU.Length;
161         DefineDosDeviceRequest->DeviceName.MaximumLength =
162             DeviceUpcaseNameU.Length;
163 
164         if (NtTargetPathU.Buffer)
165         {
166             CsrCaptureMessageBuffer(CaptureBuffer,
167                                     NtTargetPathU.Buffer,
168                                     NtTargetPathU.Length,
169                                     (PVOID*)&DefineDosDeviceRequest->TargetPath.Buffer);
170         }
171         DefineDosDeviceRequest->TargetPath.Length =
172             NtTargetPathU.Length;
173         DefineDosDeviceRequest->TargetPath.MaximumLength =
174             NtTargetPathU.Length;
175 
176         CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
177                             CaptureBuffer,
178                             CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepDefineDosDevice),
179                             sizeof(*DefineDosDeviceRequest));
180         CsrFreeCaptureBuffer(CaptureBuffer);
181 
182         if (!NT_SUCCESS(ApiMessage.Status))
183         {
184             WARN("CsrClientCallServer() failed (Status %lx)\n", ApiMessage.Status);
185             BaseSetLastNTError(ApiMessage.Status);
186             Result = FALSE;
187         }
188         else
189         {
190             if (! (dwFlags & DDD_NO_BROADCAST_SYSTEM) &&
191                 DeviceUpcaseNameU.Length == 2 * sizeof(WCHAR) &&
192                 DeviceUpcaseNameU.Buffer[1] == L':' &&
193                 ( (DeviceUpcaseNameU.Buffer[0] - L'A') < 26 ))
194             {
195                 hUser32 = LoadLibraryA("user32.dll");
196                 if (hUser32)
197                 {
198                     BSM_ptr = (BSM_type)
199                         GetProcAddress(hUser32, "BroadcastSystemMessageW");
200                     if (BSM_ptr)
201                     {
202                         dwRecipients = BSM_APPLICATIONS;
203                         dbcv.dbcv_size = sizeof(DEV_BROADCAST_VOLUME);
204                         dbcv.dbcv_devicetype = DBT_DEVTYP_VOLUME;
205                         dbcv.dbcv_reserved = 0;
206                         dbcv.dbcv_unitmask |=
207                             (1 << (DeviceUpcaseNameU.Buffer[0] - L'A'));
208                         dbcv.dbcv_flags = DBTF_NET;
209                         (void) BSM_ptr(BSF_SENDNOTIFYMESSAGE | BSF_FLUSHDISK,
210                                        &dwRecipients,
211                                        WM_DEVICECHANGE,
212                                        (WPARAM)DBT_DEVICEARRIVAL,
213                                        (LPARAM)&dbcv);
214                     }
215                     FreeLibrary(hUser32);
216                 }
217             }
218         }
219     }
220 
221     if (NtTargetPathU.Buffer &&
222         NtTargetPathU.Buffer != lpTargetPath)
223     {
224         RtlFreeHeap(RtlGetProcessHeap(),
225                     0,
226                     NtTargetPathU.Buffer);
227     }
228     RtlFreeUnicodeString(&DeviceUpcaseNameU);
229     return Result;
230 }
231 
232 
233 /*
234  * @implemented
235  */
236 DWORD
237 WINAPI
238 QueryDosDeviceA(
239     LPCSTR lpDeviceName,
240     LPSTR lpTargetPath,
241     DWORD ucchMax
242     )
243 {
244     UNICODE_STRING DeviceNameU;
245     UNICODE_STRING TargetPathU;
246     ANSI_STRING TargetPathA;
247     DWORD Length;
248     DWORD CurrentLength;
249     PWCHAR Buffer;
250 
251     if (lpDeviceName)
252     {
253         if (!RtlCreateUnicodeStringFromAsciiz(&DeviceNameU,
254                                               (LPSTR)lpDeviceName))
255         {
256             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
257             return 0;
258         }
259     }
260     Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, ucchMax * sizeof(WCHAR));
261     if (Buffer == NULL)
262     {
263         if (lpDeviceName)
264         {
265             RtlFreeHeap(RtlGetProcessHeap(), 0, DeviceNameU.Buffer);
266         }
267         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
268         return 0;
269     }
270 
271     Length = QueryDosDeviceW(lpDeviceName ? DeviceNameU.Buffer : NULL,
272                              Buffer, ucchMax);
273     if (Length != 0)
274     {
275         TargetPathA.Buffer = lpTargetPath;
276         TargetPathU.Buffer = Buffer;
277         ucchMax = Length;
278 
279         while (ucchMax)
280         {
281             CurrentLength = min(ucchMax, MAXUSHORT / 2);
282             TargetPathU.MaximumLength = TargetPathU.Length = (USHORT)CurrentLength * sizeof(WCHAR);
283 
284             TargetPathA.Length = 0;
285             TargetPathA.MaximumLength = (USHORT)CurrentLength;
286 
287             RtlUnicodeStringToAnsiString(&TargetPathA, &TargetPathU, FALSE);
288             ucchMax -= CurrentLength;
289             TargetPathA.Buffer += TargetPathA.Length;
290             TargetPathU.Buffer += TargetPathU.Length / sizeof(WCHAR);
291         }
292     }
293 
294     RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
295     if (lpDeviceName)
296     {
297         RtlFreeHeap(RtlGetProcessHeap(), 0, DeviceNameU.Buffer);
298     }
299     return Length;
300 }
301 
302 
303 /*
304  * @implemented
305  */
306 DWORD
307 WINAPI
308 QueryDosDeviceW(
309     LPCWSTR lpDeviceName,
310     LPWSTR lpTargetPath,
311     DWORD ucchMax
312     )
313 {
314     POBJECT_DIRECTORY_INFORMATION DirInfo;
315     OBJECT_ATTRIBUTES ObjectAttributes;
316     UNICODE_STRING UnicodeString;
317     HANDLE DirectoryHandle;
318     HANDLE DeviceHandle;
319     ULONG ReturnLength;
320     ULONG NameLength;
321     ULONG Length;
322     ULONG Context;
323     BOOLEAN RestartScan;
324     NTSTATUS Status;
325     UCHAR Buffer[512];
326     PWSTR Ptr;
327 
328     /* Open the '\??' directory */
329     RtlInitUnicodeString(&UnicodeString, L"\\??");
330     InitializeObjectAttributes(&ObjectAttributes,
331                                &UnicodeString,
332                                OBJ_CASE_INSENSITIVE,
333                                NULL,
334                                NULL);
335     Status = NtOpenDirectoryObject(&DirectoryHandle,
336                                    DIRECTORY_QUERY,
337                                    &ObjectAttributes);
338     if (!NT_SUCCESS(Status))
339     {
340         WARN("NtOpenDirectoryObject() failed (Status %lx)\n", Status);
341         BaseSetLastNTError(Status);
342         return 0;
343     }
344 
345     Length = 0;
346 
347     if (lpDeviceName != NULL)
348     {
349         /* Open the lpDeviceName link object */
350         RtlInitUnicodeString(&UnicodeString, (PWSTR)lpDeviceName);
351         InitializeObjectAttributes(&ObjectAttributes,
352                                    &UnicodeString,
353                                    OBJ_CASE_INSENSITIVE,
354                                    DirectoryHandle,
355                                    NULL);
356         Status = NtOpenSymbolicLinkObject(&DeviceHandle,
357                                           SYMBOLIC_LINK_QUERY,
358                                           &ObjectAttributes);
359         if (!NT_SUCCESS(Status))
360         {
361             WARN("NtOpenSymbolicLinkObject() failed (Status %lx)\n", Status);
362             NtClose(DirectoryHandle);
363             BaseSetLastNTError(Status);
364             return 0;
365         }
366 
367         /* Query link target */
368         UnicodeString.Length = 0;
369         UnicodeString.MaximumLength = (USHORT)ucchMax * sizeof(WCHAR);
370         UnicodeString.Buffer = lpTargetPath;
371 
372         ReturnLength = 0;
373         Status = NtQuerySymbolicLinkObject(DeviceHandle,
374                                            &UnicodeString,
375                                            &ReturnLength);
376         NtClose(DeviceHandle);
377         NtClose(DirectoryHandle);
378         if (!NT_SUCCESS(Status))
379         {
380             WARN("NtQuerySymbolicLinkObject() failed (Status %lx)\n", Status);
381             BaseSetLastNTError(Status);
382             return 0;
383         }
384 
385         TRACE("ReturnLength: %lu\n", ReturnLength);
386         TRACE("TargetLength: %hu\n", UnicodeString.Length);
387         TRACE("Target: '%wZ'\n", &UnicodeString);
388 
389         Length = UnicodeString.Length / sizeof(WCHAR);
390         if (Length < ucchMax)
391         {
392             /* Append null-character */
393             lpTargetPath[Length] = UNICODE_NULL;
394             Length++;
395         }
396         else
397         {
398             TRACE("Buffer is too small\n");
399             BaseSetLastNTError(STATUS_BUFFER_TOO_SMALL);
400             return 0;
401         }
402     }
403     else
404     {
405         RestartScan = TRUE;
406         Context = 0;
407         Ptr = lpTargetPath;
408         DirInfo = (POBJECT_DIRECTORY_INFORMATION)Buffer;
409 
410         while (TRUE)
411         {
412             Status = NtQueryDirectoryObject(DirectoryHandle,
413                                             Buffer,
414                                             sizeof(Buffer),
415                                             TRUE,
416                                             RestartScan,
417                                             &Context,
418                                             &ReturnLength);
419             if (!NT_SUCCESS(Status))
420             {
421                 if (Status == STATUS_NO_MORE_ENTRIES)
422                 {
423                     /* Terminate the buffer */
424                     *Ptr = UNICODE_NULL;
425                     Length++;
426 
427                     Status = STATUS_SUCCESS;
428                 }
429                 else
430                 {
431                     Length = 0;
432                 }
433                 BaseSetLastNTError(Status);
434                 break;
435             }
436 
437             if (!wcscmp(DirInfo->TypeName.Buffer, L"SymbolicLink"))
438             {
439                 TRACE("Name: '%wZ'\n", &DirInfo->Name);
440 
441                 NameLength = DirInfo->Name.Length / sizeof(WCHAR);
442                 if (Length + NameLength + 1 >= ucchMax)
443                 {
444                     Length = 0;
445                     BaseSetLastNTError(STATUS_BUFFER_TOO_SMALL);
446                     break;
447                 }
448 
449                 memcpy(Ptr, DirInfo->Name.Buffer, DirInfo->Name.Length);
450                 Ptr += NameLength;
451                 Length += NameLength;
452                 *Ptr = UNICODE_NULL;
453                 Ptr++;
454                 Length++;
455             }
456 
457             RestartScan = FALSE;
458         }
459 
460         NtClose(DirectoryHandle);
461     }
462 
463     return Length;
464 }
465 
466 /* EOF */
467