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