2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ob/namespce.c
5 * PURPOSE: Manages all functions related to the Object Manager name-
6 * space, such as finding objects or querying their names.
7 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
9 * Thomas Weidenmueller (w3seek@reactos.org)
12 /* INCLUDES ******************************************************************/
16 #include <internal/debug.h>
18 POBJECT_DIRECTORY NameSpaceRoot
= NULL
;
19 POBJECT_DIRECTORY ObpTypeDirectoryObject
= NULL
;
21 /* PRIVATE FUNCTIONS *********************************************************/
25 ObFindObject(IN HANDLE RootHandle
,
26 IN PUNICODE_STRING ObjectName
,
28 IN KPROCESSOR_MODE PreviousMode
,
29 IN PVOID
*ReturnedObject
,
30 IN POBJECT_TYPE ObjectType
,
31 IN POBP_LOOKUP_CONTEXT Context
,
32 IN PACCESS_STATE AccessState
,
33 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos
,
34 IN PVOID ParseContext
,
40 POBJECT_HEADER CurrentHeader
;
41 NTSTATUS Status
= STATUS_SUCCESS
;
43 UNICODE_STRING PathString
;
44 UNICODE_STRING CurrentUs
;
46 PUNICODE_STRING RemainingPath
= &Path
;
50 DPRINT("ObFindObject(ObjectCreateInfo %x, ReturnedObject %x, "
51 "RemainingPath %x)\n",ObjectCreateInfo
,ReturnedObject
,RemainingPath
);
53 RtlInitUnicodeString (RemainingPath
, NULL
);
55 if (RootHandle
== NULL
)
57 ObReferenceObjectByPointer(NameSpaceRoot
,
61 CurrentObject
= NameSpaceRoot
;
65 Status
= ObReferenceObjectByHandle(RootHandle
,
71 if (!NT_SUCCESS(Status
))
77 if (ObjectName
->Length
== 0 ||
78 ObjectName
->Buffer
[0] == UNICODE_NULL
)
80 *ReturnedObject
= CurrentObject
;
81 return STATUS_SUCCESS
;
84 if (RootHandle
== NULL
&&
85 ObjectName
->Buffer
[0] != L
'\\')
87 ObDereferenceObject (CurrentObject
);
89 return STATUS_UNSUCCESSFUL
;
92 /* Create a zero-terminated copy of the object name */
93 PathString
.Length
= ObjectName
->Length
;
94 PathString
.MaximumLength
= ObjectName
->Length
+ sizeof(WCHAR
);
95 PathString
.Buffer
= ExAllocatePool (NonPagedPool
,
96 PathString
.MaximumLength
);
97 if (PathString
.Buffer
== NULL
)
99 ObDereferenceObject (CurrentObject
);
100 return STATUS_INSUFFICIENT_RESOURCES
;
103 RtlCopyMemory (PathString
.Buffer
,
106 PathString
.Buffer
[PathString
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
108 current
= PathString
.Buffer
;
110 RootObject
= CurrentObject
;
111 if (ObjectType
== ObSymbolicLinkType
)
112 Attributes
|= OBJ_OPENLINK
;
116 CurrentHeader
= OBJECT_TO_OBJECT_HEADER(CurrentObject
);
118 /* Loop as long as we're dealing with a directory */
119 while (CurrentHeader
->Type
== ObDirectoryType
)
123 UNICODE_STRING StartUs
;
126 if (!current
) goto Next
;
129 if (*Start
== L
'\\') Start
++;
131 End
= wcschr(Start
, L
'\\');
132 if (End
!= NULL
) *End
= 0;
134 RtlInitUnicodeString(&StartUs
, Start
);
135 Context
->DirectoryLocked
= TRUE
;
136 Context
->Directory
= CurrentObject
;
137 FoundObject
= ObpLookupEntryDirectory(CurrentObject
, &StartUs
, Attributes
, FALSE
, Context
);
138 if (FoundObject
== NULL
)
147 ObReferenceObjectByPointer(FoundObject
,
148 STANDARD_RIGHTS_REQUIRED
,
161 NextObject
= FoundObject
;
164 if (NextObject
== NULL
)
168 ObDereferenceObject(CurrentObject
);
169 CurrentObject
= NextObject
;
170 CurrentHeader
= OBJECT_TO_OBJECT_HEADER(CurrentObject
);
173 if (CurrentHeader
->Type
->TypeInfo
.ParseProcedure
== NULL
)
175 DPRINT("Current object can't parse\n");
179 RtlInitUnicodeString(&CurrentUs
, current
);
180 Status
= CurrentHeader
->Type
->TypeInfo
.ParseProcedure(CurrentObject
,
190 current
= CurrentUs
.Buffer
;
191 if (Status
== STATUS_REPARSE
)
193 /* reparse the object path */
194 NextObject
= NameSpaceRoot
;
195 current
= PathString
.Buffer
;
197 ObReferenceObjectByPointer(NextObject
,
204 if (NextObject
== NULL
)
208 ObDereferenceObject(CurrentObject
);
209 CurrentObject
= NextObject
;
214 RtlpCreateUnicodeString (RemainingPath
, current
, NonPagedPool
);
217 RtlFreeUnicodeString (&PathString
);
218 *ReturnedObject
= CurrentObject
;
221 * Icky hack: put the code that was in ObInsertObject here so that
222 * we can get rid of the "RemainingPath" stuff, which shouldn't
223 * be exposed outside of here.
224 * Also makes the interface closer to NT parsing, and will make the
225 * eventual changes easier to deal with
229 PVOID FoundObject
= NULL
;
230 POBJECT_HEADER Header
= OBJECT_TO_OBJECT_HEADER(Insert
);
231 POBJECT_HEADER FoundHeader
= NULL
;
232 BOOLEAN ObjectAttached
= FALSE
;
233 FoundObject
= *ReturnedObject
;
236 FoundHeader
= OBJECT_TO_OBJECT_HEADER(FoundObject
);
239 if (FoundHeader
&& RemainingPath
->Buffer
== NULL
)
241 DPRINT("Object exists\n");
242 ObDereferenceObject(FoundObject
);
243 return STATUS_OBJECT_NAME_COLLISION
;
246 if (FoundHeader
&& FoundHeader
->Type
== ObDirectoryType
&&
247 RemainingPath
->Buffer
)
249 /* The name was changed so let's update it */
251 PWSTR BufferPos
= RemainingPath
->Buffer
;
253 POBJECT_HEADER_NAME_INFO ObjectNameInfo
;
255 ObjectNameInfo
= OBJECT_HEADER_TO_NAME_INFO(Header
);
257 if (BufferPos
[0] == L
'\\')
260 Delta
= sizeof(WCHAR
);
262 NewName
= ExAllocatePool(NonPagedPool
, RemainingPath
->MaximumLength
- Delta
);
263 RtlMoveMemory(NewName
, BufferPos
, RemainingPath
->MaximumLength
- Delta
);
264 if (ObjectNameInfo
->Name
.Buffer
) ExFreePool(ObjectNameInfo
->Name
.Buffer
);
265 ObjectNameInfo
->Name
.Buffer
= NewName
;
266 ObjectNameInfo
->Name
.Length
= RemainingPath
->Length
- Delta
;
267 ObjectNameInfo
->Name
.MaximumLength
= RemainingPath
->MaximumLength
- Delta
;
268 ObpInsertEntryDirectory(FoundObject
, Context
, Header
);
269 ObjectAttached
= TRUE
;
272 if ((Header
->Type
== IoFileObjectType
) ||
273 (Header
->Type
->TypeInfo
.OpenProcedure
!= NULL
))
275 DPRINT("About to call Open Routine\n");
276 if (Header
->Type
== IoFileObjectType
)
278 /* TEMPORARY HACK. DO NOT TOUCH -- Alex */
279 DPRINT("Calling IopCreateFile: %x\n", FoundObject
);
280 Status
= IopCreateFile(&Header
->Body
,
282 RemainingPath
->Buffer
,
284 DPRINT("Called IopCreateFile: %x\n", Status
);
287 else if (Header
->Type
->TypeInfo
.OpenProcedure
!= NULL
)
289 DPRINT("Calling %x\n", Header
->Type
->TypeInfo
.OpenProcedure
);
290 Status
= Header
->Type
->TypeInfo
.OpenProcedure(ObCreateHandle
,
297 if (!NT_SUCCESS(Status
))
299 DPRINT("Create Failed\n");
300 if (ObjectAttached
== TRUE
)
302 ObpDeleteEntryDirectory(Context
);
306 ObDereferenceObject(FoundObject
);
308 RtlFreeUnicodeString(RemainingPath
);
312 RtlFreeUnicodeString(RemainingPath
);
317 DPRINT("REmaining path: %wZ\n", RemainingPath
);
318 if (RemainingPath
->Buffer
!= NULL
)
320 if (wcschr(RemainingPath
->Buffer
+ 1, L
'\\') == NULL
)
321 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
323 Status
=STATUS_OBJECT_PATH_NOT_FOUND
;
330 /* PUBLIC FUNCTIONS *********************************************************/
334 ObQueryNameString(IN PVOID Object
,
335 OUT POBJECT_NAME_INFORMATION ObjectNameInfo
,
337 OUT PULONG ReturnLength
)
339 POBJECT_HEADER_NAME_INFO LocalInfo
;
340 POBJECT_HEADER ObjectHeader
;
341 POBJECT_DIRECTORY ParentDirectory
;
345 /* Get the Kernel Meta-Structures */
346 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
347 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
349 /* Check if a Query Name Procedure is available */
350 if (ObjectHeader
->Type
->TypeInfo
.QueryNameProcedure
)
352 /* Call the procedure */
353 return ObjectHeader
->Type
->TypeInfo
.QueryNameProcedure(Object
,
360 /* Check if the object doesn't even have a name */
361 if (!LocalInfo
|| !LocalInfo
->Name
.Buffer
)
363 /* We're returning the name structure */
364 *ReturnLength
= sizeof(OBJECT_NAME_INFORMATION
);
366 /* Check if we were given enough space */
367 if (*ReturnLength
> Length
) return STATUS_INFO_LENGTH_MISMATCH
;
369 /* Return an empty buffer */
370 RtlInitEmptyUnicodeString(&ObjectNameInfo
->Name
, NULL
, 0);
371 return STATUS_SUCCESS
;
375 * Find the size needed for the name. We won't do
376 * this during the Name Creation loop because we want
377 * to let the caller know that the buffer isn't big
378 * enough right at the beginning, not work our way through
379 * and find out at the end
381 if (Object
== NameSpaceRoot
)
383 /* Size of the '\' string */
384 NameSize
= sizeof(OBJ_NAME_PATH_SEPARATOR
);
388 /* Get the Object Directory and add name of Object */
389 ParentDirectory
= LocalInfo
->Directory
;
390 NameSize
= sizeof(OBJ_NAME_PATH_SEPARATOR
) + LocalInfo
->Name
.Length
;
392 /* Loop inside the directory to get the top-most one (meaning root) */
393 while ((ParentDirectory
!= NameSpaceRoot
) && (ParentDirectory
))
395 /* Get the Name Information */
396 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(
397 OBJECT_TO_OBJECT_HEADER(ParentDirectory
));
399 /* Add the size of the Directory Name */
400 if (LocalInfo
&& LocalInfo
->Directory
)
402 /* Size of the '\' string + Directory Name */
403 NameSize
+= sizeof(OBJ_NAME_PATH_SEPARATOR
) +
404 LocalInfo
->Name
.Length
;
406 /* Move to next parent Directory */
407 ParentDirectory
= LocalInfo
->Directory
;
411 /* Directory with no name. We append "...\" */
412 NameSize
+= sizeof(L
"...") + sizeof(OBJ_NAME_PATH_SEPARATOR
);
418 /* Finally, add the name of the structure and the null char */
419 *ReturnLength
= NameSize
+
420 sizeof(OBJECT_NAME_INFORMATION
) +
421 sizeof(UNICODE_NULL
);
423 /* Check if we were given enough space */
424 if (*ReturnLength
> Length
) return STATUS_INFO_LENGTH_MISMATCH
;
427 * Now we will actually create the name. We work backwards because
428 * it's easier to start off from the Name we have and walk up the
429 * parent directories. We use the same logic as Name Length calculation.
431 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
432 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectNameInfo
+ *ReturnLength
);
433 *--ObjectName
= UNICODE_NULL
;
435 /* Check if the object is actually the Root directory */
436 if (Object
== NameSpaceRoot
)
438 /* This is already the Root Directory, return "\\" */
439 *--ObjectName
= OBJ_NAME_PATH_SEPARATOR
;
440 ObjectNameInfo
->Name
.Length
= (USHORT
)NameSize
;
441 ObjectNameInfo
->Name
.MaximumLength
= (USHORT
)(NameSize
+
442 sizeof(UNICODE_NULL
));
443 ObjectNameInfo
->Name
.Buffer
= ObjectName
;
444 return STATUS_SUCCESS
;
448 /* Start by adding the Object's Name */
449 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectName
-
450 LocalInfo
->Name
.Length
);
451 RtlMoveMemory(ObjectName
,
452 LocalInfo
->Name
.Buffer
,
453 LocalInfo
->Name
.Length
);
455 /* Now parse the Parent directories until we reach the top */
456 ParentDirectory
= LocalInfo
->Directory
;
457 while ((ParentDirectory
!= NameSpaceRoot
) && (ParentDirectory
))
459 /* Get the name information */
460 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(
461 OBJECT_TO_OBJECT_HEADER(ParentDirectory
));
464 *(--ObjectName
) = OBJ_NAME_PATH_SEPARATOR
;
466 /* Add the Parent Directory's Name */
467 if (LocalInfo
&& LocalInfo
->Name
.Buffer
)
470 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectName
-
471 LocalInfo
->Name
.Length
);
472 RtlMoveMemory(ObjectName
,
473 LocalInfo
->Name
.Buffer
,
474 LocalInfo
->Name
.Length
);
476 /* Move to next parent */
477 ParentDirectory
= LocalInfo
->Directory
;
481 /* Directory without a name, we add "..." */
482 DPRINT("Nameless Directory\n");
483 ObjectName
-= sizeof(L
"...");
489 /* Add Root Directory Name */
490 *(--ObjectName
) = OBJ_NAME_PATH_SEPARATOR
;
491 ObjectNameInfo
->Name
.Length
= (USHORT
)NameSize
;
492 ObjectNameInfo
->Name
.MaximumLength
= (USHORT
)(NameSize
+
493 sizeof(UNICODE_NULL
));
494 ObjectNameInfo
->Name
.Buffer
= ObjectName
;
498 return STATUS_SUCCESS
;
503 ObQueryDeviceMapInformation(IN PEPROCESS Process
,
504 IN PPROCESS_DEVICEMAP_INFORMATION DeviceMapInfo
)
509 * FIXME: This is an ugly hack for now, to always return the System Device Map
510 * instead of returning the Process Device Map. Not important yet since we don't use it
513 /* FIXME: Acquire the DeviceMap Spinlock */
514 // KeAcquireSpinLock(DeviceMap->Lock, &OldIrql);
517 DeviceMapInfo
->Query
.DriveMap
= ObSystemDeviceMap
->DriveMap
;
518 RtlMoveMemory(DeviceMapInfo
->Query
.DriveType
,
519 ObSystemDeviceMap
->DriveType
,
520 sizeof(ObSystemDeviceMap
->DriveType
));
522 /* FIXME: Release the DeviceMap Spinlock */
523 // KeReleasepinLock(DeviceMap->Lock, OldIrql);