Precision: r58138 was part 2a/3 of my changes.
[reactos.git] / reactos / dll / win32 / kernel32 / client / dosdev.c
1 /* $Id: dosdev.c 54326 2011-11-07 00:18:13Z ion $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: lib/kernel32/file/dosdev.c
6 * PURPOSE: Dos device functions
7 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
8 * UPDATE HISTORY:
9 * Created 01/11/98
10 */
11
12 /* INCLUDES ******************************************************************/
13
14 #include <k32.h>
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,
39 (LPSTR)lpDeviceName))
40 {
41 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
42 return 0;
43 }
44
45 if (lpTargetPath &&
46 ! RtlCreateUnicodeStringFromAsciiz(&TargetPathU,
47 (LPSTR)lpTargetPath))
48 {
49 if (DeviceNameU.Buffer)
50 {
51 RtlFreeHeap(RtlGetProcessHeap (),
52 0,
53 DeviceNameU.Buffer);
54 }
55 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
56 return 0;
57 }
58
59 Result = DefineDosDeviceW(dwFlags,
60 DeviceNameU.Buffer,
61 TargetPathU.Buffer);
62
63 if (TargetPathU.Buffer)
64 {
65 RtlFreeHeap(RtlGetProcessHeap (),
66 0,
67 TargetPathU.Buffer);
68 }
69
70 if (DeviceNameU.Buffer)
71 {
72 RtlFreeHeap(RtlGetProcessHeap (),
73 0,
74 DeviceNameU.Buffer);
75 }
76 return Result;
77 }
78
79
80 /*
81 * @implemented
82 */
83 BOOL
84 WINAPI
85 DefineDosDeviceW(
86 DWORD dwFlags,
87 LPCWSTR lpDeviceName,
88 LPCWSTR lpTargetPath
89 )
90 {
91 ULONG ArgumentCount;
92 ULONG BufferSize;
93 PCSR_CAPTURE_BUFFER CaptureBuffer;
94 CSR_API_MESSAGE Request;
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 Request.Data.DefineDosDeviceRequest.dwFlags = dwFlags;
161
162 CsrCaptureMessageBuffer(CaptureBuffer,
163 (PVOID)DeviceUpcaseNameU.Buffer,
164 DeviceUpcaseNameU.Length,
165 (PVOID*)&Request.Data.DefineDosDeviceRequest.DeviceName.Buffer);
166
167 Request.Data.DefineDosDeviceRequest.DeviceName.Length =
168 DeviceUpcaseNameU.Length;
169 Request.Data.DefineDosDeviceRequest.DeviceName.MaximumLength =
170 DeviceUpcaseNameU.Length;
171
172 if (NtTargetPathU.Buffer)
173 {
174 CsrCaptureMessageBuffer(CaptureBuffer,
175 (PVOID)NtTargetPathU.Buffer,
176 NtTargetPathU.Length,
177 (PVOID*)&Request.Data.DefineDosDeviceRequest.TargetName.Buffer);
178 }
179 Request.Data.DefineDosDeviceRequest.TargetName.Length =
180 NtTargetPathU.Length;
181 Request.Data.DefineDosDeviceRequest.TargetName.MaximumLength =
182 NtTargetPathU.Length;
183
184 Status = CsrClientCallServer(&Request,
185 CaptureBuffer,
186 MAKE_CSR_API(DEFINE_DOS_DEVICE, CSR_CONSOLE),
187 sizeof(CSR_API_MESSAGE));
188 CsrFreeCaptureBuffer(CaptureBuffer);
189
190 if (! NT_SUCCESS(Status) ||
191 ! NT_SUCCESS(Status = Request.Status))
192 {
193 WARN("CsrClientCallServer() failed (Status %lx)\n",
194 Status);
195 BaseSetLastNTError(Status);
196 Result = FALSE;
197 }
198 else
199 {
200 if (! (dwFlags & DDD_NO_BROADCAST_SYSTEM) &&
201 DeviceUpcaseNameU.Length == 2 * sizeof(WCHAR) &&
202 DeviceUpcaseNameU.Buffer[1] == L':' &&
203 ( (DeviceUpcaseNameU.Buffer[0] - L'A') < 26 ))
204 {
205 hUser32 = LoadLibraryA("user32.dll");
206 if (hUser32)
207 {
208 BSM_ptr = (BSM_type)
209 GetProcAddress(hUser32, "BroadcastSystemMessageW");
210 if (BSM_ptr)
211 {
212 dwRecipients = BSM_APPLICATIONS;
213 dbcv.dbcv_size = sizeof(DEV_BROADCAST_VOLUME);
214 dbcv.dbcv_devicetype = DBT_DEVTYP_VOLUME;
215 dbcv.dbcv_reserved = 0;
216 dbcv.dbcv_unitmask |=
217 (1 << (DeviceUpcaseNameU.Buffer[0] - L'A'));
218 dbcv.dbcv_flags = DBTF_NET;
219 (void) BSM_ptr(BSF_SENDNOTIFYMESSAGE | BSF_FLUSHDISK,
220 &dwRecipients,
221 WM_DEVICECHANGE,
222 (WPARAM)DBT_DEVICEARRIVAL,
223 (LPARAM)&dbcv);
224 }
225 FreeLibrary(hUser32);
226 }
227 }
228 }
229 }
230
231 if (NtTargetPathU.Buffer)
232 {
233 RtlFreeHeap(RtlGetProcessHeap(),
234 0,
235 NtTargetPathU.Buffer);
236 }
237 RtlFreeUnicodeString(&DeviceUpcaseNameU);
238 return Result;
239 }
240
241
242 /*
243 * @implemented
244 */
245 DWORD
246 WINAPI
247 QueryDosDeviceA(
248 LPCSTR lpDeviceName,
249 LPSTR lpTargetPath,
250 DWORD ucchMax
251 )
252 {
253 UNICODE_STRING DeviceNameU;
254 UNICODE_STRING TargetPathU;
255 ANSI_STRING TargetPathA;
256 DWORD Length;
257 DWORD CurrentLength;
258 PWCHAR Buffer;
259
260 if (lpDeviceName)
261 {
262 if (!RtlCreateUnicodeStringFromAsciiz (&DeviceNameU,
263 (LPSTR)lpDeviceName))
264 {
265 SetLastError (ERROR_NOT_ENOUGH_MEMORY);
266 return 0;
267 }
268 }
269 Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
270 0,
271 ucchMax * sizeof(WCHAR));
272 if (Buffer == NULL)
273 {
274 if (lpDeviceName)
275 {
276 RtlFreeHeap (RtlGetProcessHeap (),
277 0,
278 DeviceNameU.Buffer);
279 }
280 SetLastError (ERROR_NOT_ENOUGH_MEMORY);
281 return 0;
282 }
283
284 Length = QueryDosDeviceW (lpDeviceName ? DeviceNameU.Buffer : NULL,
285 Buffer,
286 ucchMax);
287 if (Length != 0)
288 {
289 TargetPathA.Buffer = lpTargetPath;
290 TargetPathU.Buffer = Buffer;
291 ucchMax = Length;
292
293 while (ucchMax)
294 {
295 CurrentLength = min (ucchMax, MAXUSHORT / 2);
296 TargetPathU.MaximumLength = TargetPathU.Length = (USHORT)CurrentLength * sizeof(WCHAR);
297
298 TargetPathA.Length = 0;
299 TargetPathA.MaximumLength = (USHORT)CurrentLength;
300
301 RtlUnicodeStringToAnsiString (&TargetPathA,
302 &TargetPathU,
303 FALSE);
304 ucchMax -= CurrentLength;
305 TargetPathA.Buffer += TargetPathA.Length;
306 TargetPathU.Buffer += TargetPathU.Length / sizeof(WCHAR);
307 }
308 }
309
310 RtlFreeHeap (RtlGetProcessHeap (),
311 0,
312 Buffer);
313 if (lpDeviceName)
314 {
315 RtlFreeHeap (RtlGetProcessHeap (),
316 0,
317 DeviceNameU.Buffer);
318 }
319 return Length;
320 }
321
322
323 /*
324 * @implemented
325 */
326 DWORD
327 WINAPI
328 QueryDosDeviceW(
329 LPCWSTR lpDeviceName,
330 LPWSTR lpTargetPath,
331 DWORD ucchMax
332 )
333 {
334 POBJECT_DIRECTORY_INFORMATION DirInfo;
335 OBJECT_ATTRIBUTES ObjectAttributes;
336 UNICODE_STRING UnicodeString;
337 HANDLE DirectoryHandle;
338 HANDLE DeviceHandle;
339 ULONG ReturnLength;
340 ULONG NameLength;
341 ULONG Length;
342 ULONG Context;
343 BOOLEAN RestartScan;
344 NTSTATUS Status;
345 UCHAR Buffer[512];
346 PWSTR Ptr;
347
348 /* Open the '\??' directory */
349 RtlInitUnicodeString (&UnicodeString,
350 L"\\??");
351 InitializeObjectAttributes (&ObjectAttributes,
352 &UnicodeString,
353 OBJ_CASE_INSENSITIVE,
354 NULL,
355 NULL);
356 Status = NtOpenDirectoryObject (&DirectoryHandle,
357 DIRECTORY_QUERY,
358 &ObjectAttributes);
359 if (!NT_SUCCESS (Status))
360 {
361 WARN ("NtOpenDirectoryObject() failed (Status %lx)\n", Status);
362 BaseSetLastNTError (Status);
363 return 0;
364 }
365
366 Length = 0;
367
368 if (lpDeviceName != NULL)
369 {
370 /* Open the lpDeviceName link object */
371 RtlInitUnicodeString (&UnicodeString,
372 (PWSTR)lpDeviceName);
373 InitializeObjectAttributes (&ObjectAttributes,
374 &UnicodeString,
375 OBJ_CASE_INSENSITIVE,
376 DirectoryHandle,
377 NULL);
378 Status = NtOpenSymbolicLinkObject (&DeviceHandle,
379 SYMBOLIC_LINK_QUERY,
380 &ObjectAttributes);
381 if (!NT_SUCCESS (Status))
382 {
383 WARN ("NtOpenSymbolicLinkObject() failed (Status %lx)\n", Status);
384 NtClose (DirectoryHandle);
385 BaseSetLastNTError (Status);
386 return 0;
387 }
388
389 /* Query link target */
390 UnicodeString.Length = 0;
391 UnicodeString.MaximumLength = (USHORT)ucchMax * sizeof(WCHAR);
392 UnicodeString.Buffer = lpTargetPath;
393
394 ReturnLength = 0;
395 Status = NtQuerySymbolicLinkObject (DeviceHandle,
396 &UnicodeString,
397 &ReturnLength);
398 NtClose (DeviceHandle);
399 NtClose (DirectoryHandle);
400 if (!NT_SUCCESS (Status))
401 {
402 WARN ("NtQuerySymbolicLinkObject() failed (Status %lx)\n", Status);
403 BaseSetLastNTError (Status);
404 return 0;
405 }
406
407 TRACE ("ReturnLength: %lu\n", ReturnLength);
408 TRACE ("TargetLength: %hu\n", UnicodeString.Length);
409 TRACE ("Target: '%wZ'\n", &UnicodeString);
410
411 Length = UnicodeString.Length / sizeof(WCHAR);
412 if (Length < ucchMax)
413 {
414 /* Append null-charcter */
415 lpTargetPath[Length] = UNICODE_NULL;
416 Length++;
417 }
418 else
419 {
420 TRACE ("Buffer is too small\n");
421 BaseSetLastNTError (STATUS_BUFFER_TOO_SMALL);
422 return 0;
423 }
424 }
425 else
426 {
427 RestartScan = TRUE;
428 Context = 0;
429 Ptr = lpTargetPath;
430 DirInfo = (POBJECT_DIRECTORY_INFORMATION)Buffer;
431
432 while (TRUE)
433 {
434 Status = NtQueryDirectoryObject (DirectoryHandle,
435 Buffer,
436 sizeof (Buffer),
437 TRUE,
438 RestartScan,
439 &Context,
440 &ReturnLength);
441 if (!NT_SUCCESS(Status))
442 {
443 if (Status == STATUS_NO_MORE_ENTRIES)
444 {
445 /* Terminate the buffer */
446 *Ptr = UNICODE_NULL;
447 Length++;
448
449 Status = STATUS_SUCCESS;
450 }
451 else
452 {
453 Length = 0;
454 }
455 BaseSetLastNTError (Status);
456 break;
457 }
458
459 if (!wcscmp (DirInfo->TypeName.Buffer, L"SymbolicLink"))
460 {
461 TRACE ("Name: '%wZ'\n", &DirInfo->Name);
462
463 NameLength = DirInfo->Name.Length / sizeof(WCHAR);
464 if (Length + NameLength + 1 >= ucchMax)
465 {
466 Length = 0;
467 BaseSetLastNTError (STATUS_BUFFER_TOO_SMALL);
468 break;
469 }
470
471 memcpy (Ptr,
472 DirInfo->Name.Buffer,
473 DirInfo->Name.Length);
474 Ptr += NameLength;
475 Length += NameLength;
476 *Ptr = UNICODE_NULL;
477 Ptr++;
478 Length++;
479 }
480
481 RestartScan = FALSE;
482 }
483
484 NtClose (DirectoryHandle);
485 }
486
487 return Length;
488 }
489
490 /* EOF */