- Formatting/comment fixes.
[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(IN HANDLE RootHandle,
26 IN PUNICODE_STRING ObjectName,
27 IN ULONG Attributes,
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,
35 IN PVOID Insert)
36 {
37 PVOID NextObject;
38 PVOID CurrentObject;
39 PVOID RootObject;
40 POBJECT_HEADER CurrentHeader;
41 NTSTATUS Status = STATUS_SUCCESS;
42 PWSTR current;
43 UNICODE_STRING PathString;
44 UNICODE_STRING CurrentUs;
45 UNICODE_STRING Path;
46 PUNICODE_STRING RemainingPath = &Path;
47
48 PAGED_CODE();
49
50 DPRINT("ObFindObject(ObjectCreateInfo %x, ReturnedObject %x, "
51 "RemainingPath %x)\n",ObjectCreateInfo,ReturnedObject,RemainingPath);
52
53 RtlInitUnicodeString (RemainingPath, NULL);
54
55 if (RootHandle == NULL)
56 {
57 ObReferenceObjectByPointer(NameSpaceRoot,
58 DIRECTORY_TRAVERSE,
59 NULL,
60 PreviousMode);
61 CurrentObject = NameSpaceRoot;
62 }
63 else
64 {
65 Status = ObReferenceObjectByHandle(RootHandle,
66 0,
67 NULL,
68 PreviousMode,
69 &CurrentObject,
70 NULL);
71 if (!NT_SUCCESS(Status))
72 {
73 return Status;
74 }
75 }
76
77 if (ObjectName->Length == 0 ||
78 ObjectName->Buffer[0] == UNICODE_NULL)
79 {
80 *ReturnedObject = CurrentObject;
81 return STATUS_SUCCESS;
82 }
83
84 if (RootHandle == NULL &&
85 ObjectName->Buffer[0] != L'\\')
86 {
87 ObDereferenceObject (CurrentObject);
88 DPRINT1("failed\n");
89 return STATUS_UNSUCCESSFUL;
90 }
91
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)
98 {
99 ObDereferenceObject (CurrentObject);
100 return STATUS_INSUFFICIENT_RESOURCES;
101 }
102
103 RtlCopyMemory (PathString.Buffer,
104 ObjectName->Buffer,
105 ObjectName->Length);
106 PathString.Buffer[PathString.Length / sizeof(WCHAR)] = UNICODE_NULL;
107
108 current = PathString.Buffer;
109
110 RootObject = CurrentObject;
111 if (ObjectType == ObSymbolicLinkType)
112 Attributes |= OBJ_OPENLINK;
113
114 while (TRUE)
115 {
116 CurrentHeader = OBJECT_TO_OBJECT_HEADER(CurrentObject);
117
118 /* Loop as long as we're dealing with a directory */
119 while (CurrentHeader->Type == ObDirectoryType)
120 {
121 PWSTR Start, End;
122 PVOID FoundObject;
123 UNICODE_STRING StartUs;
124 NextObject = NULL;
125
126 if (!current) goto Next;
127
128 Start = current;
129 if (*Start == L'\\') Start++;
130
131 End = wcschr(Start, L'\\');
132 if (End != NULL) *End = 0;
133
134 RtlInitUnicodeString(&StartUs, Start);
135 Context->DirectoryLocked = TRUE;
136 Context->Directory = CurrentObject;
137 FoundObject = ObpLookupEntryDirectory(CurrentObject, &StartUs, Attributes, FALSE, Context);
138 if (FoundObject == NULL)
139 {
140 if (End != NULL)
141 {
142 *End = L'\\';
143 }
144 goto Next;
145 }
146
147 ObReferenceObjectByPointer(FoundObject,
148 STANDARD_RIGHTS_REQUIRED,
149 NULL,
150 UserMode);
151 if (End != NULL)
152 {
153 *End = L'\\';
154 current = End;
155 }
156 else
157 {
158 current = NULL;
159 }
160
161 NextObject = FoundObject;
162
163 Next:
164 if (NextObject == NULL)
165 {
166 break;
167 }
168 ObDereferenceObject(CurrentObject);
169 CurrentObject = NextObject;
170 CurrentHeader = OBJECT_TO_OBJECT_HEADER(CurrentObject);
171 }
172
173 if (CurrentHeader->Type->TypeInfo.ParseProcedure == NULL)
174 {
175 DPRINT("Current object can't parse\n");
176 break;
177 }
178
179 RtlInitUnicodeString(&CurrentUs, current);
180 Status = CurrentHeader->Type->TypeInfo.ParseProcedure(CurrentObject,
181 CurrentHeader->Type,
182 AccessState,
183 PreviousMode,
184 Attributes,
185 &PathString,
186 &CurrentUs,
187 ParseContext,
188 SecurityQos,
189 &NextObject);
190 current = CurrentUs.Buffer;
191 if (Status == STATUS_REPARSE)
192 {
193 /* reparse the object path */
194 NextObject = NameSpaceRoot;
195 current = PathString.Buffer;
196
197 ObReferenceObjectByPointer(NextObject,
198 DIRECTORY_TRAVERSE,
199 NULL,
200 PreviousMode);
201 }
202
203
204 if (NextObject == NULL)
205 {
206 break;
207 }
208 ObDereferenceObject(CurrentObject);
209 CurrentObject = NextObject;
210 }
211
212 if (current)
213 {
214 RtlpCreateUnicodeString (RemainingPath, current, NonPagedPool);
215 }
216
217 RtlFreeUnicodeString (&PathString);
218 *ReturnedObject = CurrentObject;
219
220 /*
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
226 */
227 if (Insert)
228 {
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;
234 if (FoundObject)
235 {
236 FoundHeader = OBJECT_TO_OBJECT_HEADER(FoundObject);
237 }
238
239 if (FoundHeader && RemainingPath->Buffer == NULL)
240 {
241 DPRINT("Object exists\n");
242 ObDereferenceObject(FoundObject);
243 return STATUS_OBJECT_NAME_COLLISION;
244 }
245
246 if (FoundHeader && FoundHeader->Type == ObDirectoryType &&
247 RemainingPath->Buffer)
248 {
249 /* The name was changed so let's update it */
250 PVOID NewName;
251 PWSTR BufferPos = RemainingPath->Buffer;
252 ULONG Delta = 0;
253 POBJECT_HEADER_NAME_INFO ObjectNameInfo;
254
255 ObjectNameInfo = OBJECT_HEADER_TO_NAME_INFO(Header);
256
257 if (BufferPos[0] == L'\\')
258 {
259 BufferPos++;
260 Delta = sizeof(WCHAR);
261 }
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;
270 }
271
272 if ((Header->Type == IoFileObjectType) ||
273 (Header->Type->TypeInfo.OpenProcedure != NULL))
274 {
275 DPRINT("About to call Open Routine\n");
276 if (Header->Type == IoFileObjectType)
277 {
278 /* TEMPORARY HACK. DO NOT TOUCH -- Alex */
279 DPRINT("Calling IopCreateFile: %x\n", FoundObject);
280 Status = IopCreateFile(&Header->Body,
281 FoundObject,
282 RemainingPath->Buffer,
283 NULL);
284 DPRINT("Called IopCreateFile: %x\n", Status);
285
286 }
287 else if (Header->Type->TypeInfo.OpenProcedure != NULL)
288 {
289 DPRINT("Calling %x\n", Header->Type->TypeInfo.OpenProcedure);
290 Status = Header->Type->TypeInfo.OpenProcedure(ObCreateHandle,
291 NULL,
292 &Header->Body,
293 0,
294 0);
295 }
296
297 if (!NT_SUCCESS(Status))
298 {
299 DPRINT("Create Failed\n");
300 if (ObjectAttached == TRUE)
301 {
302 ObpDeleteEntryDirectory(Context);
303 }
304 if (FoundObject)
305 {
306 ObDereferenceObject(FoundObject);
307 }
308 RtlFreeUnicodeString(RemainingPath);
309 return Status;
310 }
311 }
312 RtlFreeUnicodeString(RemainingPath);
313 }
314 else
315 {
316 /* ROS Hack */
317 DPRINT("REmaining path: %wZ\n", RemainingPath);
318 if (RemainingPath->Buffer != NULL)
319 {
320 if (wcschr(RemainingPath->Buffer + 1, L'\\') == NULL)
321 Status = STATUS_OBJECT_NAME_NOT_FOUND;
322 else
323 Status =STATUS_OBJECT_PATH_NOT_FOUND;
324 }
325 }
326
327 return Status;
328 }
329
330 /* PUBLIC FUNCTIONS *********************************************************/
331
332 NTSTATUS
333 STDCALL
334 ObQueryNameString(IN PVOID Object,
335 OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
336 IN ULONG Length,
337 OUT PULONG ReturnLength)
338 {
339 POBJECT_HEADER_NAME_INFO LocalInfo;
340 POBJECT_HEADER ObjectHeader;
341 POBJECT_DIRECTORY ParentDirectory;
342 ULONG NameSize;
343 PWCH ObjectName;
344
345 /* Get the Kernel Meta-Structures */
346 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
347 LocalInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
348
349 /* Check if a Query Name Procedure is available */
350 if (ObjectHeader->Type->TypeInfo.QueryNameProcedure)
351 {
352 /* Call the procedure */
353 return ObjectHeader->Type->TypeInfo.QueryNameProcedure(Object,
354 TRUE, //fixme
355 ObjectNameInfo,
356 Length,
357 ReturnLength);
358 }
359
360 /* Check if the object doesn't even have a name */
361 if (!LocalInfo || !LocalInfo->Name.Buffer)
362 {
363 /* We're returning the name structure */
364 *ReturnLength = sizeof(OBJECT_NAME_INFORMATION);
365
366 /* Check if we were given enough space */
367 if (*ReturnLength > Length) return STATUS_INFO_LENGTH_MISMATCH;
368
369 /* Return an empty buffer */
370 RtlInitEmptyUnicodeString(&ObjectNameInfo->Name, NULL, 0);
371 return STATUS_SUCCESS;
372 }
373
374 /*
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
380 */
381 if (Object == NameSpaceRoot)
382 {
383 /* Size of the '\' string */
384 NameSize = sizeof(OBJ_NAME_PATH_SEPARATOR);
385 }
386 else
387 {
388 /* Get the Object Directory and add name of Object */
389 ParentDirectory = LocalInfo->Directory;
390 NameSize = sizeof(OBJ_NAME_PATH_SEPARATOR) + LocalInfo->Name.Length;
391
392 /* Loop inside the directory to get the top-most one (meaning root) */
393 while ((ParentDirectory != NameSpaceRoot) && (ParentDirectory))
394 {
395 /* Get the Name Information */
396 LocalInfo = OBJECT_HEADER_TO_NAME_INFO(
397 OBJECT_TO_OBJECT_HEADER(ParentDirectory));
398
399 /* Add the size of the Directory Name */
400 if (LocalInfo && LocalInfo->Directory)
401 {
402 /* Size of the '\' string + Directory Name */
403 NameSize += sizeof(OBJ_NAME_PATH_SEPARATOR) +
404 LocalInfo->Name.Length;
405
406 /* Move to next parent Directory */
407 ParentDirectory = LocalInfo->Directory;
408 }
409 else
410 {
411 /* Directory with no name. We append "...\" */
412 NameSize += sizeof(L"...") + sizeof(OBJ_NAME_PATH_SEPARATOR);
413 break;
414 }
415 }
416 }
417
418 /* Finally, add the name of the structure and the null char */
419 *ReturnLength = NameSize +
420 sizeof(OBJECT_NAME_INFORMATION) +
421 sizeof(UNICODE_NULL);
422
423 /* Check if we were given enough space */
424 if (*ReturnLength > Length) return STATUS_INFO_LENGTH_MISMATCH;
425
426 /*
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.
430 */
431 LocalInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
432 ObjectName = (PWCH)((ULONG_PTR)ObjectNameInfo + *ReturnLength);
433 *--ObjectName = UNICODE_NULL;
434
435 /* Check if the object is actually the Root directory */
436 if (Object == NameSpaceRoot)
437 {
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;
445 }
446 else
447 {
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);
454
455 /* Now parse the Parent directories until we reach the top */
456 ParentDirectory = LocalInfo->Directory;
457 while ((ParentDirectory != NameSpaceRoot) && (ParentDirectory))
458 {
459 /* Get the name information */
460 LocalInfo = OBJECT_HEADER_TO_NAME_INFO(
461 OBJECT_TO_OBJECT_HEADER(ParentDirectory));
462
463 /* Add the "\" */
464 *(--ObjectName) = OBJ_NAME_PATH_SEPARATOR;
465
466 /* Add the Parent Directory's Name */
467 if (LocalInfo && LocalInfo->Name.Buffer)
468 {
469 /* Add the name */
470 ObjectName = (PWCH)((ULONG_PTR)ObjectName -
471 LocalInfo->Name.Length);
472 RtlMoveMemory(ObjectName,
473 LocalInfo->Name.Buffer,
474 LocalInfo->Name.Length);
475
476 /* Move to next parent */
477 ParentDirectory = LocalInfo->Directory;
478 }
479 else
480 {
481 /* Directory without a name, we add "..." */
482 DPRINT("Nameless Directory\n");
483 ObjectName -= sizeof(L"...");
484 ObjectName = L"...";
485 break;
486 }
487 }
488
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;
495 }
496
497 /* Return success */
498 return STATUS_SUCCESS;
499 }
500
501 VOID
502 NTAPI
503 ObQueryDeviceMapInformation(IN PEPROCESS Process,
504 IN PPROCESS_DEVICEMAP_INFORMATION DeviceMapInfo)
505 {
506 //KIRQL OldIrql ;
507
508 /*
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
511 */
512
513 /* FIXME: Acquire the DeviceMap Spinlock */
514 // KeAcquireSpinLock(DeviceMap->Lock, &OldIrql);
515
516 /* Make a copy */
517 DeviceMapInfo->Query.DriveMap = ObSystemDeviceMap->DriveMap;
518 RtlMoveMemory(DeviceMapInfo->Query.DriveType,
519 ObSystemDeviceMap->DriveType,
520 sizeof(ObSystemDeviceMap->DriveType));
521
522 /* FIXME: Release the DeviceMap Spinlock */
523 // KeReleasepinLock(DeviceMap->Lock, OldIrql);
524 }
525
526 /* EOF */