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(POBJECT_CREATE_INFORMATION ObjectCreateInfo
,
26 PUNICODE_STRING ObjectName
,
27 PVOID
* ReturnedObject
,
28 PUNICODE_STRING RemainingPath
,
29 POBJECT_TYPE ObjectType
,
30 POBP_LOOKUP_CONTEXT Context
,
31 IN PACCESS_STATE AccessState
,
32 IN PVOID ParseContext
)
37 POBJECT_HEADER CurrentHeader
;
40 UNICODE_STRING PathString
;
42 UNICODE_STRING CurrentUs
;
46 DPRINT("ObFindObject(ObjectCreateInfo %x, ReturnedObject %x, "
47 "RemainingPath %x)\n",ObjectCreateInfo
,ReturnedObject
,RemainingPath
);
49 RtlInitUnicodeString (RemainingPath
, NULL
);
51 if (ObjectCreateInfo
->RootDirectory
== NULL
)
53 ObReferenceObjectByPointer(NameSpaceRoot
,
56 ObjectCreateInfo
->ProbeMode
);
57 CurrentObject
= NameSpaceRoot
;
61 Status
= ObReferenceObjectByHandle(ObjectCreateInfo
->RootDirectory
,
64 ObjectCreateInfo
->ProbeMode
,
67 if (!NT_SUCCESS(Status
))
73 if (ObjectName
->Length
== 0 ||
74 ObjectName
->Buffer
[0] == UNICODE_NULL
)
76 *ReturnedObject
= CurrentObject
;
77 return STATUS_SUCCESS
;
80 if (ObjectCreateInfo
->RootDirectory
== NULL
&&
81 ObjectName
->Buffer
[0] != L
'\\')
83 ObDereferenceObject (CurrentObject
);
85 return STATUS_UNSUCCESSFUL
;
88 /* Create a zero-terminated copy of the object name */
89 PathString
.Length
= ObjectName
->Length
;
90 PathString
.MaximumLength
= ObjectName
->Length
+ sizeof(WCHAR
);
91 PathString
.Buffer
= ExAllocatePool (NonPagedPool
,
92 PathString
.MaximumLength
);
93 if (PathString
.Buffer
== NULL
)
95 ObDereferenceObject (CurrentObject
);
96 return STATUS_INSUFFICIENT_RESOURCES
;
99 RtlCopyMemory (PathString
.Buffer
,
102 PathString
.Buffer
[PathString
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
104 current
= PathString
.Buffer
;
106 RootObject
= CurrentObject
;
107 Attributes
= ObjectCreateInfo
->Attributes
;
108 if (ObjectType
== ObSymbolicLinkType
)
109 Attributes
|= OBJ_OPENLINK
;
113 CurrentHeader
= OBJECT_TO_OBJECT_HEADER(CurrentObject
);
115 /* Loop as long as we're dealing with a directory */
116 while (CurrentHeader
->Type
== ObDirectoryType
)
120 UNICODE_STRING StartUs
;
123 if (!current
) goto Next
;
126 if (*Start
== L
'\\') Start
++;
128 End
= wcschr(Start
, L
'\\');
129 if (End
!= NULL
) *End
= 0;
131 RtlInitUnicodeString(&StartUs
, Start
);
132 Context
->DirectoryLocked
= TRUE
;
133 Context
->Directory
= CurrentObject
;
134 FoundObject
= ObpLookupEntryDirectory(CurrentObject
, &StartUs
, Attributes
, FALSE
, Context
);
135 if (FoundObject
== NULL
)
144 ObReferenceObjectByPointer(FoundObject
,
145 STANDARD_RIGHTS_REQUIRED
,
158 NextObject
= FoundObject
;
161 if (NextObject
== NULL
)
165 ObDereferenceObject(CurrentObject
);
166 CurrentObject
= NextObject
;
167 CurrentHeader
= OBJECT_TO_OBJECT_HEADER(CurrentObject
);
170 if (CurrentHeader
->Type
->TypeInfo
.ParseProcedure
== NULL
)
172 DPRINT("Current object can't parse\n");
176 RtlInitUnicodeString(&CurrentUs
, current
);
177 Status
= CurrentHeader
->Type
->TypeInfo
.ParseProcedure(CurrentObject
,
180 ExGetPreviousMode(), // fixme: should be a parameter, since caller decides.
185 NULL
, // fixme: where do we get this from? captured OBP?
187 current
= CurrentUs
.Buffer
;
188 if (Status
== STATUS_REPARSE
)
190 /* reparse the object path */
191 NextObject
= NameSpaceRoot
;
192 current
= PathString
.Buffer
;
194 ObReferenceObjectByPointer(NextObject
,
197 ObjectCreateInfo
->ProbeMode
);
201 if (NextObject
== NULL
)
205 ObDereferenceObject(CurrentObject
);
206 CurrentObject
= NextObject
;
211 RtlpCreateUnicodeString (RemainingPath
, current
, NonPagedPool
);
214 RtlFreeUnicodeString (&PathString
);
215 *ReturnedObject
= CurrentObject
;
217 return STATUS_SUCCESS
;
220 /* PUBLIC FUNCTIONS *********************************************************/
224 ObQueryNameString(IN PVOID Object
,
225 OUT POBJECT_NAME_INFORMATION ObjectNameInfo
,
227 OUT PULONG ReturnLength
)
229 POBJECT_HEADER_NAME_INFO LocalInfo
;
230 POBJECT_HEADER ObjectHeader
;
231 POBJECT_DIRECTORY ParentDirectory
;
236 DPRINT("ObQueryNameString: %x, %x\n", Object
, ObjectNameInfo
);
238 /* Get the Kernel Meta-Structures */
239 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
240 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
242 /* Check if a Query Name Procedure is available */
243 if (ObjectHeader
->Type
->TypeInfo
.QueryNameProcedure
)
245 /* Call the procedure */
246 DPRINT("Calling Object's Procedure\n");
247 Status
= ObjectHeader
->Type
->TypeInfo
.QueryNameProcedure(Object
,
253 /* Return the status */
257 /* Check if the object doesn't even have a name */
258 if (!LocalInfo
|| !LocalInfo
->Name
.Buffer
)
260 /* We're returning the name structure */
261 DPRINT("Nameless Object\n");
262 *ReturnLength
= sizeof(OBJECT_NAME_INFORMATION
);
264 /* Check if we were given enough space */
265 if (*ReturnLength
> Length
)
267 DPRINT1("Not enough buffer space\n");
268 return STATUS_INFO_LENGTH_MISMATCH
;
271 /* Return an empty buffer */
272 ObjectNameInfo
->Name
.Length
= 0;
273 ObjectNameInfo
->Name
.MaximumLength
= 0;
274 ObjectNameInfo
->Name
.Buffer
= NULL
;
276 return STATUS_SUCCESS
;
280 * Find the size needed for the name. We won't do
281 * this during the Name Creation loop because we want
282 * to let the caller know that the buffer isn't big
283 * enough right at the beginning, not work our way through
284 * and find out at the end
286 if (Object
== NameSpaceRoot
)
288 /* Size of the '\' string */
289 DPRINT("Object is Root\n");
290 NameSize
= sizeof(OBJ_NAME_PATH_SEPARATOR
);
294 /* Get the Object Directory and add name of Object */
295 ParentDirectory
= LocalInfo
->Directory
;
296 NameSize
= sizeof(OBJ_NAME_PATH_SEPARATOR
) + LocalInfo
->Name
.Length
;
298 /* Loop inside the directory to get the top-most one (meaning root) */
299 while ((ParentDirectory
!= NameSpaceRoot
) && (ParentDirectory
))
301 /* Get the Name Information */
302 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(OBJECT_TO_OBJECT_HEADER(ParentDirectory
));
304 /* Add the size of the Directory Name */
305 if (LocalInfo
&& LocalInfo
->Directory
)
307 /* Size of the '\' string + Directory Name */
308 NameSize
+= sizeof(OBJ_NAME_PATH_SEPARATOR
) + LocalInfo
->Name
.Length
;
310 /* Move to next parent Directory */
311 ParentDirectory
= LocalInfo
->Directory
;
315 /* Directory with no name. We append "...\" */
316 DPRINT("Nameless Directory\n");
317 NameSize
+= sizeof(L
"...") + sizeof(OBJ_NAME_PATH_SEPARATOR
);
323 /* Finally, add the name of the structure and the null char */
324 *ReturnLength
= NameSize
+ sizeof(OBJECT_NAME_INFORMATION
) + sizeof(UNICODE_NULL
);
325 DPRINT("Final Length: %x\n", *ReturnLength
);
327 /* Check if we were given enough space */
328 if (*ReturnLength
> Length
)
330 DPRINT1("Not enough buffer space\n");
331 return STATUS_INFO_LENGTH_MISMATCH
;
335 * Now we will actually create the name. We work backwards because
336 * it's easier to start off from the Name we have and walk up the
337 * parent directories. We use the same logic as Name Length calculation.
339 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
340 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectNameInfo
+ *ReturnLength
);
341 *--ObjectName
= UNICODE_NULL
;
343 if (Object
== NameSpaceRoot
)
345 /* This is already the Root Directory, return "\\" */
346 DPRINT("Returning Root Dir\n");
347 *--ObjectName
= OBJ_NAME_PATH_SEPARATOR
;
348 ObjectNameInfo
->Name
.Length
= (USHORT
)NameSize
;
349 ObjectNameInfo
->Name
.MaximumLength
= (USHORT
)(NameSize
+ sizeof(UNICODE_NULL
));
350 ObjectNameInfo
->Name
.Buffer
= ObjectName
;
352 return STATUS_SUCCESS
;
356 /* Start by adding the Object's Name */
357 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectName
- LocalInfo
->Name
.Length
);
358 RtlMoveMemory(ObjectName
, LocalInfo
->Name
.Buffer
, LocalInfo
->Name
.Length
);
360 /* Now parse the Parent directories until we reach the top */
361 ParentDirectory
= LocalInfo
->Directory
;
362 while ((ParentDirectory
!= NameSpaceRoot
) && (ParentDirectory
))
364 /* Get the name information */
365 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(OBJECT_TO_OBJECT_HEADER(ParentDirectory
));
368 *(--ObjectName
) = OBJ_NAME_PATH_SEPARATOR
;
370 /* Add the Parent Directory's Name */
371 if (LocalInfo
&& LocalInfo
->Name
.Buffer
)
374 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectName
- LocalInfo
->Name
.Length
);
375 RtlMoveMemory(ObjectName
, LocalInfo
->Name
.Buffer
, LocalInfo
->Name
.Length
);
377 /* Move to next parent */
378 ParentDirectory
= LocalInfo
->Directory
;
382 /* Directory without a name, we add "..." */
383 DPRINT("Nameless Directory\n");
384 ObjectName
-= sizeof(L
"...");
390 /* Add Root Directory Name */
391 *(--ObjectName
) = OBJ_NAME_PATH_SEPARATOR
;
392 DPRINT("Current Buffer: %S\n", ObjectName
);
393 ObjectNameInfo
->Name
.Length
= (USHORT
)NameSize
;
394 ObjectNameInfo
->Name
.MaximumLength
= (USHORT
)(NameSize
+ sizeof(UNICODE_NULL
));
395 ObjectNameInfo
->Name
.Buffer
= ObjectName
;
396 DPRINT("Complete: %wZ\n", ObjectNameInfo
);
399 return STATUS_SUCCESS
;
404 ObQueryDeviceMapInformation(IN PEPROCESS Process
,
405 IN PPROCESS_DEVICEMAP_INFORMATION DeviceMapInfo
)
410 * FIXME: This is an ugly hack for now, to always return the System Device Map
411 * instead of returning the Process Device Map. Not important yet since we don't use it
414 /* FIXME: Acquire the DeviceMap Spinlock */
415 // KeAcquireSpinLock(DeviceMap->Lock, &OldIrql);
418 DeviceMapInfo
->Query
.DriveMap
= ObSystemDeviceMap
->DriveMap
;
419 RtlMoveMemory(DeviceMapInfo
->Query
.DriveType
,
420 ObSystemDeviceMap
->DriveType
,
421 sizeof(ObSystemDeviceMap
->DriveType
));
423 /* FIXME: Release the DeviceMap Spinlock */
424 // KeReleasepinLock(DeviceMap->Lock, OldIrql);