Of course, I forgot to commit the new file in revision 22049...
[reactos.git] / reactos / ntoskrnl / ob / obname.c
1 /*
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)
8 * Eric Kohl
9 * Thomas Weidenmueller (w3seek@reactos.org)
10 */
11
12 /* INCLUDES ******************************************************************/
13
14 #include <ntoskrnl.h>
15 #define NDEBUG
16 #include <internal/debug.h>
17
18 POBJECT_DIRECTORY NameSpaceRoot = NULL;
19 POBJECT_DIRECTORY ObpTypeDirectoryObject = NULL;
20
21 /* PRIVATE FUNCTIONS *********************************************************/
22
23 NTSTATUS
24 NTAPI
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)
33 {
34 PVOID NextObject;
35 PVOID CurrentObject;
36 PVOID RootObject;
37 POBJECT_HEADER CurrentHeader;
38 NTSTATUS Status;
39 PWSTR current;
40 UNICODE_STRING PathString;
41 ULONG Attributes;
42 UNICODE_STRING CurrentUs;
43
44 PAGED_CODE();
45
46 DPRINT("ObFindObject(ObjectCreateInfo %x, ReturnedObject %x, "
47 "RemainingPath %x)\n",ObjectCreateInfo,ReturnedObject,RemainingPath);
48
49 RtlInitUnicodeString (RemainingPath, NULL);
50
51 if (ObjectCreateInfo->RootDirectory == NULL)
52 {
53 ObReferenceObjectByPointer(NameSpaceRoot,
54 DIRECTORY_TRAVERSE,
55 NULL,
56 ObjectCreateInfo->ProbeMode);
57 CurrentObject = NameSpaceRoot;
58 }
59 else
60 {
61 Status = ObReferenceObjectByHandle(ObjectCreateInfo->RootDirectory,
62 0,
63 NULL,
64 ObjectCreateInfo->ProbeMode,
65 &CurrentObject,
66 NULL);
67 if (!NT_SUCCESS(Status))
68 {
69 return Status;
70 }
71 }
72
73 if (ObjectName->Length == 0 ||
74 ObjectName->Buffer[0] == UNICODE_NULL)
75 {
76 *ReturnedObject = CurrentObject;
77 return STATUS_SUCCESS;
78 }
79
80 if (ObjectCreateInfo->RootDirectory == NULL &&
81 ObjectName->Buffer[0] != L'\\')
82 {
83 ObDereferenceObject (CurrentObject);
84 DPRINT1("failed\n");
85 return STATUS_UNSUCCESSFUL;
86 }
87
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)
94 {
95 ObDereferenceObject (CurrentObject);
96 return STATUS_INSUFFICIENT_RESOURCES;
97 }
98
99 RtlCopyMemory (PathString.Buffer,
100 ObjectName->Buffer,
101 ObjectName->Length);
102 PathString.Buffer[PathString.Length / sizeof(WCHAR)] = UNICODE_NULL;
103
104 current = PathString.Buffer;
105
106 RootObject = CurrentObject;
107 Attributes = ObjectCreateInfo->Attributes;
108 if (ObjectType == ObSymbolicLinkType)
109 Attributes |= OBJ_OPENLINK;
110
111 while (TRUE)
112 {
113 CurrentHeader = OBJECT_TO_OBJECT_HEADER(CurrentObject);
114
115 /* Loop as long as we're dealing with a directory */
116 while (CurrentHeader->Type == ObDirectoryType)
117 {
118 PWSTR Start, End;
119 PVOID FoundObject;
120 UNICODE_STRING StartUs;
121 NextObject = NULL;
122
123 if (!current) goto Next;
124
125 Start = current;
126 if (*Start == L'\\') Start++;
127
128 End = wcschr(Start, L'\\');
129 if (End != NULL) *End = 0;
130
131 RtlInitUnicodeString(&StartUs, Start);
132 Context->DirectoryLocked = TRUE;
133 Context->Directory = CurrentObject;
134 FoundObject = ObpLookupEntryDirectory(CurrentObject, &StartUs, Attributes, FALSE, Context);
135 if (FoundObject == NULL)
136 {
137 if (End != NULL)
138 {
139 *End = L'\\';
140 }
141 goto Next;
142 }
143
144 ObReferenceObjectByPointer(FoundObject,
145 STANDARD_RIGHTS_REQUIRED,
146 NULL,
147 UserMode);
148 if (End != NULL)
149 {
150 *End = L'\\';
151 current = End;
152 }
153 else
154 {
155 current = NULL;
156 }
157
158 NextObject = FoundObject;
159
160 Next:
161 if (NextObject == NULL)
162 {
163 break;
164 }
165 ObDereferenceObject(CurrentObject);
166 CurrentObject = NextObject;
167 CurrentHeader = OBJECT_TO_OBJECT_HEADER(CurrentObject);
168 }
169
170 if (CurrentHeader->Type->TypeInfo.ParseProcedure == NULL)
171 {
172 DPRINT("Current object can't parse\n");
173 break;
174 }
175
176 RtlInitUnicodeString(&CurrentUs, current);
177 Status = CurrentHeader->Type->TypeInfo.ParseProcedure(CurrentObject,
178 CurrentHeader->Type,
179 AccessState,
180 ExGetPreviousMode(), // fixme: should be a parameter, since caller decides.
181 Attributes,
182 &PathString,
183 &CurrentUs,
184 ParseContext,
185 NULL, // fixme: where do we get this from? captured OBP?
186 &NextObject);
187 current = CurrentUs.Buffer;
188 if (Status == STATUS_REPARSE)
189 {
190 /* reparse the object path */
191 NextObject = NameSpaceRoot;
192 current = PathString.Buffer;
193
194 ObReferenceObjectByPointer(NextObject,
195 DIRECTORY_TRAVERSE,
196 NULL,
197 ObjectCreateInfo->ProbeMode);
198 }
199
200
201 if (NextObject == NULL)
202 {
203 break;
204 }
205 ObDereferenceObject(CurrentObject);
206 CurrentObject = NextObject;
207 }
208
209 if (current)
210 {
211 RtlpCreateUnicodeString (RemainingPath, current, NonPagedPool);
212 }
213
214 RtlFreeUnicodeString (&PathString);
215 *ReturnedObject = CurrentObject;
216
217 return STATUS_SUCCESS;
218 }
219
220 /* PUBLIC FUNCTIONS *********************************************************/
221
222 NTSTATUS
223 STDCALL
224 ObQueryNameString(IN PVOID Object,
225 OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
226 IN ULONG Length,
227 OUT PULONG ReturnLength)
228 {
229 POBJECT_HEADER_NAME_INFO LocalInfo;
230 POBJECT_HEADER ObjectHeader;
231 POBJECT_DIRECTORY ParentDirectory;
232 ULONG NameSize;
233 PWCH ObjectName;
234 NTSTATUS Status;
235
236 DPRINT("ObQueryNameString: %x, %x\n", Object, ObjectNameInfo);
237
238 /* Get the Kernel Meta-Structures */
239 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
240 LocalInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
241
242 /* Check if a Query Name Procedure is available */
243 if (ObjectHeader->Type->TypeInfo.QueryNameProcedure)
244 {
245 /* Call the procedure */
246 DPRINT("Calling Object's Procedure\n");
247 Status = ObjectHeader->Type->TypeInfo.QueryNameProcedure(Object,
248 TRUE, //fixme
249 ObjectNameInfo,
250 Length,
251 ReturnLength);
252
253 /* Return the status */
254 return Status;
255 }
256
257 /* Check if the object doesn't even have a name */
258 if (!LocalInfo || !LocalInfo->Name.Buffer)
259 {
260 /* We're returning the name structure */
261 DPRINT("Nameless Object\n");
262 *ReturnLength = sizeof(OBJECT_NAME_INFORMATION);
263
264 /* Check if we were given enough space */
265 if (*ReturnLength > Length)
266 {
267 DPRINT1("Not enough buffer space\n");
268 return STATUS_INFO_LENGTH_MISMATCH;
269 }
270
271 /* Return an empty buffer */
272 ObjectNameInfo->Name.Length = 0;
273 ObjectNameInfo->Name.MaximumLength = 0;
274 ObjectNameInfo->Name.Buffer = NULL;
275
276 return STATUS_SUCCESS;
277 }
278
279 /*
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
285 */
286 if (Object == NameSpaceRoot)
287 {
288 /* Size of the '\' string */
289 DPRINT("Object is Root\n");
290 NameSize = sizeof(OBJ_NAME_PATH_SEPARATOR);
291 }
292 else
293 {
294 /* Get the Object Directory and add name of Object */
295 ParentDirectory = LocalInfo->Directory;
296 NameSize = sizeof(OBJ_NAME_PATH_SEPARATOR) + LocalInfo->Name.Length;
297
298 /* Loop inside the directory to get the top-most one (meaning root) */
299 while ((ParentDirectory != NameSpaceRoot) && (ParentDirectory))
300 {
301 /* Get the Name Information */
302 LocalInfo = OBJECT_HEADER_TO_NAME_INFO(OBJECT_TO_OBJECT_HEADER(ParentDirectory));
303
304 /* Add the size of the Directory Name */
305 if (LocalInfo && LocalInfo->Directory)
306 {
307 /* Size of the '\' string + Directory Name */
308 NameSize += sizeof(OBJ_NAME_PATH_SEPARATOR) + LocalInfo->Name.Length;
309
310 /* Move to next parent Directory */
311 ParentDirectory = LocalInfo->Directory;
312 }
313 else
314 {
315 /* Directory with no name. We append "...\" */
316 DPRINT("Nameless Directory\n");
317 NameSize += sizeof(L"...") + sizeof(OBJ_NAME_PATH_SEPARATOR);
318 break;
319 }
320 }
321 }
322
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);
326
327 /* Check if we were given enough space */
328 if (*ReturnLength > Length)
329 {
330 DPRINT1("Not enough buffer space\n");
331 return STATUS_INFO_LENGTH_MISMATCH;
332 }
333
334 /*
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.
338 */
339 LocalInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
340 ObjectName = (PWCH)((ULONG_PTR)ObjectNameInfo + *ReturnLength);
341 *--ObjectName = UNICODE_NULL;
342
343 if (Object == NameSpaceRoot)
344 {
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;
351
352 return STATUS_SUCCESS;
353 }
354 else
355 {
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);
359
360 /* Now parse the Parent directories until we reach the top */
361 ParentDirectory = LocalInfo->Directory;
362 while ((ParentDirectory != NameSpaceRoot) && (ParentDirectory))
363 {
364 /* Get the name information */
365 LocalInfo = OBJECT_HEADER_TO_NAME_INFO(OBJECT_TO_OBJECT_HEADER(ParentDirectory));
366
367 /* Add the "\" */
368 *(--ObjectName) = OBJ_NAME_PATH_SEPARATOR;
369
370 /* Add the Parent Directory's Name */
371 if (LocalInfo && LocalInfo->Name.Buffer)
372 {
373 /* Add the name */
374 ObjectName = (PWCH)((ULONG_PTR)ObjectName - LocalInfo->Name.Length);
375 RtlMoveMemory(ObjectName, LocalInfo->Name.Buffer, LocalInfo->Name.Length);
376
377 /* Move to next parent */
378 ParentDirectory = LocalInfo->Directory;
379 }
380 else
381 {
382 /* Directory without a name, we add "..." */
383 DPRINT("Nameless Directory\n");
384 ObjectName -= sizeof(L"...");
385 ObjectName = L"...";
386 break;
387 }
388 }
389
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);
397 }
398
399 return STATUS_SUCCESS;
400 }
401
402 VOID
403 NTAPI
404 ObQueryDeviceMapInformation(IN PEPROCESS Process,
405 IN PPROCESS_DEVICEMAP_INFORMATION DeviceMapInfo)
406 {
407 //KIRQL OldIrql ;
408
409 /*
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
412 */
413
414 /* FIXME: Acquire the DeviceMap Spinlock */
415 // KeAcquireSpinLock(DeviceMap->Lock, &OldIrql);
416
417 /* Make a copy */
418 DeviceMapInfo->Query.DriveMap = ObSystemDeviceMap->DriveMap;
419 RtlMoveMemory(DeviceMapInfo->Query.DriveType,
420 ObSystemDeviceMap->DriveType,
421 sizeof(ObSystemDeviceMap->DriveType));
422
423 /* FIXME: Release the DeviceMap Spinlock */
424 // KeReleasepinLock(DeviceMap->Lock, OldIrql);
425 }
426
427 /* EOF */