4dcaff1c832d71585277783a63d63e762a887a34
[reactos.git] / ntoskrnl / ob / devicemap.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ob/devicemap.c
5 * PURPOSE: Device map implementation
6 * PROGRAMMERS: Eric Kohl (eric.kohl@reactos.org)
7 * Alex Ionescu (alex.ionescu@reactos.org)
8 */
9
10 /* INCLUDES ***************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 ULONG ObpLUIDDeviceMapsDisabled;
17 ULONG ObpLUIDDeviceMapsEnabled;
18
19 /* PRIVATE FUNCTIONS ******************************************************/
20
21 NTSTATUS
22 NTAPI
23 ObSetDeviceMap(IN PEPROCESS Process,
24 IN HANDLE DirectoryHandle)
25 {
26 POBJECT_DIRECTORY DirectoryObject = NULL;
27 PDEVICE_MAP DeviceMap = NULL, NewDeviceMap = NULL, OldDeviceMap;
28 NTSTATUS Status;
29 PEPROCESS WorkProcess;
30 BOOLEAN MakePermanant = FALSE;
31
32 Status = ObReferenceObjectByHandle(DirectoryHandle,
33 DIRECTORY_TRAVERSE,
34 ObpDirectoryObjectType,
35 KeGetPreviousMode(),
36 (PVOID*)&DirectoryObject,
37 NULL);
38 if (!NT_SUCCESS(Status))
39 {
40 DPRINT("ObReferenceObjectByHandle() failed (Status 0x%08lx)\n", Status);
41 return Status;
42 }
43
44 /* Allocate and initialize a new device map */
45 DeviceMap = ExAllocatePoolWithTag(PagedPool,
46 sizeof(*DeviceMap),
47 'mDbO');
48 if (DeviceMap == NULL)
49 {
50 ObDereferenceObject(DirectoryObject);
51 return STATUS_INSUFFICIENT_RESOURCES;
52 }
53
54 /* Initialize the device map */
55 RtlZeroMemory(DeviceMap, sizeof(*DeviceMap));
56 DeviceMap->ReferenceCount = 1;
57 DeviceMap->DosDevicesDirectory = DirectoryObject;
58
59 /* Acquire the device map lock */
60 KeAcquireGuardedMutex(&ObpDeviceMapLock);
61
62 /* Attach the device map to the directory object */
63 if (DirectoryObject->DeviceMap == NULL)
64 {
65 DirectoryObject->DeviceMap = DeviceMap;
66 }
67 else
68 {
69 NewDeviceMap = DeviceMap;
70
71 /* There's already a device map,
72 so reuse it */
73 DeviceMap = DirectoryObject->DeviceMap;
74 ++DeviceMap->ReferenceCount;
75 }
76
77 /* Caller gave a process, use it */
78 if (Process != NULL)
79 {
80 WorkProcess = Process;
81 }
82 /* If no process given, use current and
83 * set system device map */
84 else
85 {
86 WorkProcess = PsGetCurrentProcess();
87 ObSystemDeviceMap = DeviceMap;
88 }
89
90 /* If current object isn't system one, save system one in current
91 * device map */
92 if (DirectoryObject != ObSystemDeviceMap->DosDevicesDirectory)
93 {
94 /* We also need to make the object permanant */
95 DeviceMap->GlobalDosDevicesDirectory = ObSystemDeviceMap->DosDevicesDirectory;
96 MakePermanant = TRUE;
97 }
98
99 /* Save old process device map */
100 OldDeviceMap = WorkProcess->DeviceMap;
101 /* Attach the device map to the process */
102 WorkProcess->DeviceMap = DeviceMap;
103
104 /* Release the device map lock */
105 KeReleaseGuardedMutex(&ObpDeviceMapLock);
106
107 /* If we have to make the object permamant, do it now */
108 if (MakePermanant)
109 {
110 POBJECT_HEADER ObjectHeader;
111 POBJECT_HEADER_NAME_INFO HeaderNameInfo;
112
113 ObjectHeader = OBJECT_TO_OBJECT_HEADER(DirectoryObject);
114 HeaderNameInfo = ObpReferenceNameInfo(ObjectHeader);
115
116 ObpEnterObjectTypeMutex(ObjectHeader->Type);
117 if (HeaderNameInfo != NULL && HeaderNameInfo->Directory != NULL)
118 {
119 ObjectHeader->Flags |= OB_FLAG_PERMANENT;
120 }
121 ObpLeaveObjectTypeMutex(ObjectHeader->Type);
122
123 if (HeaderNameInfo != NULL)
124 {
125 ObpDereferenceNameInfo(HeaderNameInfo);
126 }
127 }
128
129 /* Release useless device map if required */
130 if (NewDeviceMap != NULL)
131 {
132 ObfDereferenceObject(DirectoryObject);
133 ExFreePoolWithTag(NewDeviceMap, 'mDbO');
134 }
135
136 /* And dereference previous process device map */
137 if (OldDeviceMap != NULL)
138 {
139 ObfDereferenceDeviceMap(OldDeviceMap);
140 }
141
142 return STATUS_SUCCESS;
143 }
144
145
146 PDEVICE_MAP
147 NTAPI
148 ObpReferenceDeviceMap(VOID)
149 {
150 UNIMPLEMENTED;
151 return NULL;
152 }
153
154
155 VOID
156 NTAPI
157 ObDereferenceDeviceMap(IN PEPROCESS Process)
158 {
159 PDEVICE_MAP DeviceMap;
160
161 DPRINT("ObDereferenceDeviceMap()\n");
162
163 /* Get the pointer to this process devicemap and reset it
164 holding the device map lock */
165 KeAcquireGuardedMutex(&ObpDeviceMapLock);
166 DeviceMap = Process->DeviceMap;
167 Process->DeviceMap = NULL;
168 KeReleaseGuardedMutex(&ObpDeviceMapLock);
169
170 /* Continue only if there is a device map */
171 if (DeviceMap != NULL)
172 ObfDereferenceDeviceMap(DeviceMap);
173 }
174
175
176 VOID
177 FASTCALL
178 ObfDereferenceDeviceMap(IN PDEVICE_MAP DeviceMap)
179 {
180 DPRINT("ObfDereferenceDeviceMap()\n");
181
182 /* Acquire the device map lock */
183 KeAcquireGuardedMutex(&ObpDeviceMapLock);
184
185 /* Decrement the reference counter */
186 DeviceMap->ReferenceCount--;
187 DPRINT("ReferenceCount: %lu\n", DeviceMap->ReferenceCount);
188
189 /* Leave, if there are still references to this device map */
190 if (DeviceMap->ReferenceCount != 0)
191 {
192 /* Release the device map lock and leave */
193 KeReleaseGuardedMutex(&ObpDeviceMapLock);
194 return;
195 }
196
197 /* Nobody is referencing it anymore, unlink the DOS directory */
198 DeviceMap->DosDevicesDirectory->DeviceMap = NULL;
199
200 /* Release the devicemap lock */
201 KeReleaseGuardedMutex(&ObpDeviceMapLock);
202
203 /* Dereference the DOS Devices Directory and free the Device Map */
204 ObMakeTemporaryObject(DeviceMap->DosDevicesDirectory);
205 ObDereferenceObject(DeviceMap->DosDevicesDirectory);
206 ExFreePoolWithTag(DeviceMap, 'mDbO');
207 }
208
209
210 VOID
211 NTAPI
212 ObInheritDeviceMap(IN PEPROCESS Parent,
213 IN PEPROCESS Process)
214 {
215 PDEVICE_MAP DeviceMap;
216
217 DPRINT("ObInheritDeviceMap()\n");
218
219 /* Acquire the device map lock */
220 KeAcquireGuardedMutex(&ObpDeviceMapLock);
221
222 /* Get the parent process device map or the system device map */
223 DeviceMap = (Parent != NULL) ? Parent->DeviceMap : ObSystemDeviceMap;
224 if (DeviceMap != NULL)
225 {
226 /* Reference the device map and attach it to the new process */
227 DeviceMap->ReferenceCount++;
228 DPRINT("ReferenceCount: %lu\n", DeviceMap->ReferenceCount);
229
230 Process->DeviceMap = DeviceMap;
231 }
232
233 /* Release the device map lock */
234 KeReleaseGuardedMutex(&ObpDeviceMapLock);
235 }
236
237
238 NTSTATUS
239 NTAPI
240 ObQueryDeviceMapInformation(IN PEPROCESS Process,
241 IN PPROCESS_DEVICEMAP_INFORMATION DeviceMapInfo,
242 IN ULONG Flags)
243 {
244 PDEVICE_MAP DeviceMap = NULL, GlobalDeviceMap;
245 BOOLEAN Dereference;
246 PROCESS_DEVICEMAP_INFORMATION MapInfo;
247 ULONG BitMask, i;
248 BOOLEAN ReturnAny;
249 NTSTATUS Status;
250
251 /* Validate flags */
252 if (Flags & ~PROCESS_LUID_DOSDEVICES_ONLY)
253 {
254 return STATUS_INVALID_PARAMETER;
255 }
256
257 Dereference = FALSE;
258 /* Do we want to return anything? */
259 ReturnAny = ~Flags & PROCESS_LUID_DOSDEVICES_ONLY;
260
261 /* If LUID mappings are enabled... */
262 if (ObpLUIDDeviceMapsEnabled != 0)
263 {
264 /* Check for process parameter validness */
265 if (Process != NULL && Process != PsGetCurrentProcess())
266 {
267 return STATUS_INVALID_PARAMETER;
268 }
269
270 /* And get the device map */
271 DeviceMap = ObpReferenceDeviceMap();
272 }
273
274 /* Acquire the device map lock */
275 KeAcquireGuardedMutex(&ObpDeviceMapLock);
276
277 /*
278 * If we had a device map, if because of LUID mappings,
279 * we'll have to dereference it afterwards
280 */
281 if (DeviceMap != NULL)
282 {
283 Dereference = TRUE;
284 }
285 else
286 {
287 /* Get the process device map or the system device map */
288 DeviceMap = (Process != NULL) ? Process->DeviceMap : ObSystemDeviceMap;
289 }
290
291 /* Fail if no device map */
292 if (DeviceMap == NULL)
293 {
294 KeReleaseGuardedMutex(&ObpDeviceMapLock);
295 return STATUS_END_OF_FILE;
296 }
297
298 /* At that point, assume success */
299 Status = STATUS_SUCCESS;
300
301 /* Try to get the global device map if any */
302 GlobalDeviceMap = DeviceMap;
303 if (DeviceMap->GlobalDosDevicesDirectory != NULL)
304 {
305 if (DeviceMap->GlobalDosDevicesDirectory->DeviceMap != NULL)
306 {
307 GlobalDeviceMap = DeviceMap->GlobalDosDevicesDirectory->DeviceMap;
308 }
309 }
310
311 /* Now, setup our device map info, especially drive types */
312 MapInfo.Query.DriveMap = DeviceMap->DriveMap;
313 /* Browse every device */
314 for (i = 0, BitMask = 1; i < 32; ++i, BitMask *= 2)
315 {
316 /* Set the type given current device map */
317 MapInfo.Query.DriveType[i] = DeviceMap->DriveType[i];
318
319 /*
320 * If device is not existing and we're asked to return
321 * more than just LUID mapped, get the entry
322 * from global device map if not remote
323 */
324 if (!(MapInfo.Query.DriveMap & BitMask) && ReturnAny)
325 {
326 if (ObpLUIDDeviceMapsEnabled != 0 ||
327 (GlobalDeviceMap->DriveType[i] != DOSDEVICE_DRIVE_REMOTE &&
328 GlobalDeviceMap->DriveType[i] != DOSDEVICE_DRIVE_CALCULATE))
329 {
330 MapInfo.Query.DriveType[i] = GlobalDeviceMap->DriveType[i];
331 MapInfo.Query.DriveMap |= BitMask & GlobalDeviceMap->DriveMap;
332 }
333 }
334 }
335
336 /* Release the device map lock */
337 KeReleaseGuardedMutex(&ObpDeviceMapLock);
338
339 /* Dereference LUID device map */
340 if (Dereference)
341 {
342 ObfDereferenceDeviceMap(DeviceMap);
343 }
344
345 /* Copy back data */
346 _SEH2_TRY
347 {
348 RtlCopyMemory(DeviceMapInfo, &MapInfo, sizeof(PROCESS_DEVICEMAP_INFORMATION));
349 }
350 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
351 {
352 Status = _SEH2_GetExceptionCode();
353 }
354 _SEH2_END;
355
356 return Status;
357 }
358
359
360 ULONG
361 NTAPI
362 ObIsLUIDDeviceMapsEnabled(VOID)
363 {
364 return ObpLUIDDeviceMapsEnabled;
365 }
366
367
368 #if 0
369 NTSTATUS
370 NTAPI
371 ObIsDosDeviceLocallyMapped(
372 IN ULONG Index,
373 OUT PUCHAR DosDeviceState)
374 {
375 /* Check the index */
376 if (Index < 1 || Index > 26)
377 return STATUS_INVALID_PARAMETER;
378
379 /* Acquire the device map lock */
380 KeAcquireGuardedMutex(&ObpDeviceMapLock);
381
382 /* Get drive mapping status */
383 *DosDeviceState = (ObSystemDeviceMap->DriveMap & (1 << Index)) != 0;
384
385 /* Release the device map lock */
386 KeReleaseGuardedMutex(&ObpDeviceMapLock);
387
388 return STATUS_SUCCESS;
389 }
390 #endif
391
392 /* EOF */