update for HEAD-2003091401
[reactos.git] / lib / kernel32 / file / dosdev.c
1 /* $Id$
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
16 #define NDEBUG
17 #include <kernel32/kernel32.h>
18
19
20 /* FUNCTIONS *****************************************************************/
21
22 /*
23  * @implemented
24  */
25 WINBOOL
26 STDCALL
27 DefineDosDeviceA(
28     DWORD dwFlags,
29     LPCSTR lpDeviceName,
30     LPCSTR lpTargetPath
31     )
32 {
33   UNICODE_STRING DeviceNameU;
34   UNICODE_STRING TargetPathU;
35   BOOL Result;
36
37   if (!RtlCreateUnicodeStringFromAsciiz (&DeviceNameU,
38                                          (LPSTR)lpDeviceName))
39   {
40     SetLastError (ERROR_NOT_ENOUGH_MEMORY);
41     return 0;
42   }
43
44   if (!RtlCreateUnicodeStringFromAsciiz (&TargetPathU,
45                                          (LPSTR)lpTargetPath))
46   {
47     RtlFreeHeap (RtlGetProcessHeap (),
48                  0,
49                  DeviceNameU.Buffer);
50     SetLastError (ERROR_NOT_ENOUGH_MEMORY);
51     return 0;
52   }
53
54   Result = DefineDosDeviceW (dwFlags,
55                              DeviceNameU.Buffer,
56                              TargetPathU.Buffer);
57
58   RtlFreeHeap (RtlGetProcessHeap (),
59                0,
60                TargetPathU.Buffer);
61   RtlFreeHeap (RtlGetProcessHeap (),
62                0,
63                DeviceNameU.Buffer);
64
65   return Result;
66 }
67
68
69 /*
70  * @unimplemented
71  */
72 WINBOOL
73 STDCALL
74 DefineDosDeviceW(
75     DWORD dwFlags,
76     LPCWSTR lpDeviceName,
77     LPCWSTR lpTargetPath
78     )
79 {
80         return FALSE;
81 }
82
83
84 /*
85  * @implemented
86  */
87 DWORD
88 STDCALL
89 QueryDosDeviceA(
90     LPCSTR lpDeviceName,
91     LPSTR lpTargetPath,
92     DWORD ucchMax
93     )
94 {
95   UNICODE_STRING DeviceNameU;
96   UNICODE_STRING TargetPathU;
97   ANSI_STRING TargetPathA;
98   DWORD Length;
99
100   if (!RtlCreateUnicodeStringFromAsciiz (&DeviceNameU,
101                                          (LPSTR)lpDeviceName))
102   {
103     SetLastError (ERROR_NOT_ENOUGH_MEMORY);
104     return 0;
105   }
106
107   TargetPathU.Length = 0;
108   TargetPathU.MaximumLength = (USHORT)ucchMax * sizeof(WCHAR);
109   TargetPathU.Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
110                                         0,
111                                         TargetPathU.MaximumLength);
112   if (TargetPathU.Buffer == NULL)
113   {
114     SetLastError (ERROR_NOT_ENOUGH_MEMORY);
115     return 0;
116   }
117
118   Length = QueryDosDeviceW (DeviceNameU.Buffer,
119                             TargetPathU.Buffer,
120                             ucchMax);
121   if (Length != 0)
122   {
123     TargetPathU.Length = Length * sizeof(WCHAR);
124
125     TargetPathA.Length = 0;
126     TargetPathA.MaximumLength = (USHORT)ucchMax;
127     TargetPathA.Buffer = lpTargetPath;
128
129     RtlUnicodeStringToAnsiString (&TargetPathA,
130                                   &TargetPathU,
131                                   FALSE);
132
133     DPRINT ("TargetPathU: '%wZ'\n", &TargetPathU);
134     DPRINT ("TargetPathA: '%Z'\n", &TargetPathA);
135   }
136
137   RtlFreeHeap (RtlGetProcessHeap (),
138                0,
139                TargetPathU.Buffer);
140   RtlFreeHeap (RtlGetProcessHeap (),
141                0,
142                DeviceNameU.Buffer);
143
144   return Length;
145 }
146
147
148 /*
149  * @implemented
150  */
151 DWORD
152 STDCALL
153 QueryDosDeviceW(
154     LPCWSTR lpDeviceName,
155     LPWSTR lpTargetPath,
156     DWORD ucchMax
157     )
158 {
159   PDIRECTORY_BASIC_INFORMATION DirInfo;
160   OBJECT_ATTRIBUTES ObjectAttributes;
161   UNICODE_STRING UnicodeString;
162   HANDLE DirectoryHandle;
163   HANDLE DeviceHandle;
164   ULONG ReturnLength;
165   ULONG NameLength;
166   ULONG Length;
167   ULONG Context;
168   BOOLEAN RestartScan;
169   NTSTATUS Status;
170   UCHAR Buffer[512];
171   PWSTR Ptr;
172
173   /* Open the '\??' directory */
174   RtlInitUnicodeString (&UnicodeString,
175                         L"\\??");
176   InitializeObjectAttributes (&ObjectAttributes,
177                               &UnicodeString,
178                               OBJ_CASE_INSENSITIVE,
179                               NULL,
180                               NULL);
181   Status = NtOpenDirectoryObject (&DirectoryHandle,
182                                   DIRECTORY_QUERY,
183                                   &ObjectAttributes);
184   if (!NT_SUCCESS (Status))
185   {
186     DPRINT ("NtOpenDirectoryObject() failed (Status %lx)\n", Status);
187     SetLastErrorByStatus (Status);
188     return 0;
189   }
190
191   Length = 0;
192
193   if (lpDeviceName != NULL)
194   {
195     /* Open the lpDeviceName link object */
196     RtlInitUnicodeString (&UnicodeString,
197                           (PWSTR)lpDeviceName);
198     InitializeObjectAttributes (&ObjectAttributes,
199                                 &UnicodeString,
200                                 OBJ_CASE_INSENSITIVE,
201                                 DirectoryHandle,
202                                 NULL);
203     Status = NtOpenSymbolicLinkObject (&DeviceHandle,
204                                        SYMBOLIC_LINK_QUERY,
205                                        &ObjectAttributes);
206     if (!NT_SUCCESS (Status))
207     {
208       DPRINT ("NtOpenSymbolicLinkObject() failed (Status %lx)\n", Status);
209       NtClose (DirectoryHandle);
210       SetLastErrorByStatus (Status);
211       return 0;
212     }
213
214     /* Query link target */
215     UnicodeString.Length = 0;
216     UnicodeString.MaximumLength = (USHORT)ucchMax * sizeof(WCHAR);
217     UnicodeString.Buffer = lpTargetPath;
218
219     ReturnLength = 0;
220     Status = NtQuerySymbolicLinkObject (DeviceHandle,
221                                         &UnicodeString,
222                                         &ReturnLength);
223     NtClose (DeviceHandle);
224     NtClose (DirectoryHandle);
225     if (!NT_SUCCESS (Status))
226     {
227       DPRINT ("NtQuerySymbolicLinkObject() failed (Status %lx)\n", Status);
228       SetLastErrorByStatus (Status);
229       return 0;
230     }
231
232     DPRINT ("ReturnLength: %lu\n", ReturnLength);
233     DPRINT ("TargetLength: %hu\n", UnicodeString.Length);
234     DPRINT ("Target: '%wZ'\n", &UnicodeString);
235
236     Length = ReturnLength / sizeof(WCHAR);
237     if (Length < ucchMax)
238     {
239       /* Append null-charcter */
240       lpTargetPath[Length] = UNICODE_NULL;
241       Length++;
242     }
243     else
244     {
245       DPRINT ("Buffer is too small\n");
246       SetLastErrorByStatus (STATUS_BUFFER_TOO_SMALL);
247       return 0;
248     }
249   }
250   else
251   {
252     RestartScan = TRUE;
253     Context = 0;
254     Ptr = lpTargetPath;
255     DirInfo = (PDIRECTORY_BASIC_INFORMATION)Buffer;
256
257     while (TRUE)
258     {
259       Status = NtQueryDirectoryObject (DirectoryHandle,
260                                        Buffer,
261                                        sizeof (Buffer),
262                                        TRUE,
263                                        RestartScan,
264                                        &Context,
265                                        &ReturnLength);
266       if (!NT_SUCCESS(Status))
267       {
268         if (Status == STATUS_NO_MORE_ENTRIES)
269         {
270           /* Terminate the buffer */
271           *Ptr = UNICODE_NULL;
272           Length++;
273
274           Status = STATUS_SUCCESS;
275         }
276         else
277         {
278           Length = 0;
279         }
280         SetLastErrorByStatus (Status);
281         break;
282       }
283
284       if (!wcscmp (DirInfo->ObjectTypeName.Buffer, L"SymbolicLink"))
285       {
286         DPRINT ("Name: '%wZ'\n", &DirInfo->ObjectName);
287
288         NameLength = DirInfo->ObjectName.Length / sizeof(WCHAR);
289         if (Length + NameLength + 1 >= ucchMax)
290         {
291           Length = 0;
292           SetLastErrorByStatus (STATUS_BUFFER_TOO_SMALL);
293           break;
294         }
295
296         memcpy (Ptr,
297                 DirInfo->ObjectName.Buffer,
298                 DirInfo->ObjectName.Length);
299         Ptr += NameLength;
300         Length += NameLength;
301         *Ptr = UNICODE_NULL;
302         Ptr++;
303         Length++;
304       }
305
306       RestartScan = FALSE;
307     }
308
309     NtClose (DirectoryHandle);
310   }
311
312   return Length;
313 }
314
315 /* EOF */