Fixed some bugs.
[reactos.git] / reactos / ntoskrnl / ob / object.c
1 /* $Id: object.c,v 1.52 2002/07/17 21:04:56 dwelch Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ob/object.c
6 * PURPOSE: Implements generic object managment functions
7 * PROGRAMMER: David Welch (welch@cwcom.net)
8 * UPDATE HISTORY:
9 * 10/06/98: Created
10 */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <ddk/ntddk.h>
15 #include <roscfg.h>
16 #include <internal/ob.h>
17 #include <internal/ps.h>
18 #include <internal/id.h>
19 #include <internal/ke.h>
20
21 #define NDEBUG
22 #include <internal/debug.h>
23
24 /* FUNCTIONS ************************************************************/
25
26 PVOID HEADER_TO_BODY(POBJECT_HEADER obj)
27 {
28 return(((void *)obj)+sizeof(OBJECT_HEADER)-sizeof(COMMON_BODY_HEADER));
29 }
30
31 POBJECT_HEADER BODY_TO_HEADER(PVOID body)
32 {
33 PCOMMON_BODY_HEADER chdr = (PCOMMON_BODY_HEADER)body;
34 return(CONTAINING_RECORD((&(chdr->Type)),OBJECT_HEADER,Type));
35 }
36
37
38 /**********************************************************************
39 * NAME PRIVATE
40 * ObInitializeObject
41 *
42 * DESCRIPTION
43 *
44 * ARGUMENTS
45 *
46 * RETURN VALUE
47 */
48 VOID ObInitializeObject(POBJECT_HEADER ObjectHeader,
49 PHANDLE Handle,
50 ACCESS_MASK DesiredAccess,
51 POBJECT_TYPE Type,
52 POBJECT_ATTRIBUTES ObjectAttributes)
53 {
54 ObjectHeader->HandleCount = 0;
55 ObjectHeader->RefCount = 1;
56 ObjectHeader->ObjectType = Type;
57 if (ObjectAttributes != NULL &&
58 ObjectAttributes->Attributes & OBJ_PERMANENT)
59 {
60 ObjectHeader->Permanent = TRUE;
61 }
62 else
63 {
64 ObjectHeader->Permanent = FALSE;
65 }
66 RtlInitUnicodeString(&(ObjectHeader->Name),NULL);
67 if (Handle != NULL)
68 {
69 ObCreateHandle(PsGetCurrentProcess(),
70 HEADER_TO_BODY(ObjectHeader),
71 DesiredAccess,
72 ObjectAttributes && (ObjectAttributes->Attributes & OBJ_INHERIT) ? TRUE : FALSE,
73 Handle);
74 }
75 }
76
77
78 /**********************************************************************
79 * NAME PRIVATE
80 * ObFindObject@16
81 *
82 * DESCRIPTION
83 *
84 * ARGUMENTS
85 * ObjectAttributes
86 *
87 * ReturnedObject
88 *
89 * RemainigPath
90 * Pointer to a unicode string that will contain the
91 * remaining path if the function returns successfully.
92 * The caller must free the buffer after use by calling
93 * RtlFreeUnicodeString ().
94 *
95 * ObjectType
96 * Optional pointer to an object type. This is used to
97 * descide if a symbolic link object will be parsed or not.
98 *
99 * RETURN VALUE
100 */
101 NTSTATUS ObFindObject(POBJECT_ATTRIBUTES ObjectAttributes,
102 PVOID* ReturnedObject,
103 PUNICODE_STRING RemainingPath,
104 POBJECT_TYPE ObjectType)
105 {
106 PVOID NextObject;
107 PVOID CurrentObject;
108 PVOID RootObject;
109 POBJECT_HEADER CurrentHeader;
110 NTSTATUS Status;
111 PWSTR Path;
112 PWSTR current;
113 UNICODE_STRING PathString;
114
115 DPRINT("ObFindObject(ObjectAttributes %x, ReturnedObject %x, "
116 "RemainingPath %x)\n",ObjectAttributes,ReturnedObject,RemainingPath);
117 DPRINT("ObjectAttributes->ObjectName %wZ\n",
118 ObjectAttributes->ObjectName);
119
120 RtlInitUnicodeString (RemainingPath, NULL);
121
122 if (ObjectAttributes->RootDirectory == NULL)
123 {
124 ObReferenceObjectByPointer(NameSpaceRoot,
125 DIRECTORY_TRAVERSE,
126 NULL,
127 UserMode);
128 CurrentObject = NameSpaceRoot;
129 }
130 else
131 {
132 Status = ObReferenceObjectByHandle(ObjectAttributes->RootDirectory,
133 DIRECTORY_TRAVERSE,
134 NULL,
135 UserMode,
136 &CurrentObject,
137 NULL);
138 if (!NT_SUCCESS(Status))
139 {
140 return(Status);
141 }
142 }
143
144 Path = ObjectAttributes->ObjectName->Buffer;
145
146 if (Path[0] == 0)
147 {
148 *ReturnedObject = CurrentObject;
149 return(STATUS_SUCCESS);
150 }
151
152 if ((ObjectAttributes->RootDirectory == NULL) && (Path[0] != '\\'))
153 {
154 ObDereferenceObject(CurrentObject);
155 return(STATUS_UNSUCCESSFUL);
156 }
157
158 if (Path)
159 {
160 RtlCreateUnicodeString (&PathString, Path);
161 current = PathString.Buffer;
162 }
163 else
164 {
165 RtlInitUnicodeString (&PathString, NULL);
166 current = NULL;
167 }
168
169 RootObject = CurrentObject;
170
171 while (TRUE)
172 {
173 DPRINT("current %S\n",current);
174 CurrentHeader = BODY_TO_HEADER(CurrentObject);
175
176 DPRINT("Current ObjectType %wZ\n",
177 &CurrentHeader->ObjectType->TypeName);
178
179 if (CurrentHeader->ObjectType->Parse == NULL)
180 {
181 DPRINT("Current object can't parse\n");
182 break;
183 }
184 Status = CurrentHeader->ObjectType->Parse(CurrentObject,
185 &NextObject,
186 &PathString,
187 &current,
188 ObjectAttributes->Attributes);
189 if (Status == STATUS_REPARSE)
190 {
191 /* reparse the object path */
192 NextObject = RootObject;
193 current = PathString.Buffer;
194
195 ObReferenceObjectByPointer(NextObject,
196 DIRECTORY_TRAVERSE,
197 NULL,
198 UserMode);
199 }
200
201 if (NextObject == NULL)
202 {
203 break;
204 }
205 ObDereferenceObject(CurrentObject);
206 CurrentObject = NextObject;
207 }
208
209 if (current)
210 RtlCreateUnicodeString (RemainingPath, current);
211 RtlFreeUnicodeString (&PathString);
212 *ReturnedObject = CurrentObject;
213
214 return(STATUS_SUCCESS);
215 }
216
217
218 /**********************************************************************
219 * NAME EXPORTED
220 * ObCreateObject@36
221 *
222 * DESCRIPTION
223 *
224 * ARGUMENTS
225 *
226 * RETURN VALUE
227 */
228 NTSTATUS STDCALL
229 ObCreateObject(OUT PHANDLE Handle,
230 IN ACCESS_MASK DesiredAccess,
231 IN POBJECT_ATTRIBUTES ObjectAttributes,
232 IN POBJECT_TYPE Type,
233 OUT PVOID *Object)
234 {
235 PVOID Parent = NULL;
236 UNICODE_STRING RemainingPath;
237 POBJECT_HEADER Header;
238 POBJECT_HEADER ParentHeader = NULL;
239 NTSTATUS Status;
240 BOOLEAN ObjectAttached = FALSE;
241
242 assert_irql(APC_LEVEL);
243
244 DPRINT("ObCreateObject(Handle %x, ObjectAttributes %x, Type %x)\n",
245 Handle, ObjectAttributes, Type);
246 if (ObjectAttributes != NULL &&
247 ObjectAttributes->ObjectName != NULL)
248 {
249 DPRINT("ObjectAttributes->ObjectName->Buffer %S\n",
250 ObjectAttributes->ObjectName->Buffer);
251 }
252
253 if (ObjectAttributes != NULL &&
254 ObjectAttributes->ObjectName != NULL)
255 {
256 Status = ObFindObject(ObjectAttributes,
257 &Parent,
258 &RemainingPath,
259 NULL);
260 if (!NT_SUCCESS(Status))
261 {
262 DPRINT("ObFindObject() failed! (Status 0x%x)\n", Status);
263 return(Status);
264 }
265 }
266 else
267 {
268 RtlInitUnicodeString(&RemainingPath, NULL);
269 }
270
271 RtlMapGenericMask(&DesiredAccess,
272 Type->Mapping);
273
274 Header = (POBJECT_HEADER)ExAllocatePoolWithTag(NonPagedPool,
275 OBJECT_ALLOC_SIZE(Type),
276 Type->Tag);
277 ObInitializeObject(Header,
278 NULL,
279 DesiredAccess,
280 Type,
281 ObjectAttributes);
282
283 if (Parent != NULL)
284 {
285 ParentHeader = BODY_TO_HEADER(Parent);
286 }
287
288 if (ParentHeader != NULL &&
289 ParentHeader->ObjectType == ObDirectoryType &&
290 RemainingPath.Buffer != NULL)
291 {
292 ObpAddEntryDirectory(Parent,
293 Header,
294 RemainingPath.Buffer+1);
295 ObjectAttached = TRUE;
296 }
297
298 if ((Header->ObjectType != NULL) &&
299 (Header->ObjectType->Create != NULL))
300 {
301 DPRINT("Calling %x\n", Header->ObjectType->Create);
302 Status = Header->ObjectType->Create(HEADER_TO_BODY(Header),
303 Parent,
304 RemainingPath.Buffer,
305 ObjectAttributes);
306 if (!NT_SUCCESS(Status))
307 {
308 if (ObjectAttached == TRUE)
309 {
310 ObpRemoveEntryDirectory(Header);
311 }
312 if (Parent)
313 {
314 ObDereferenceObject(Parent);
315 }
316 RtlFreeUnicodeString(&Header->Name);
317 RtlFreeUnicodeString(&RemainingPath);
318 ExFreePool(Header);
319 return(Status);
320 }
321 }
322 RtlFreeUnicodeString( &RemainingPath );
323
324 if (Object != NULL)
325 {
326 *Object = HEADER_TO_BODY(Header);
327 }
328
329 if (Handle != NULL)
330 {
331 ObCreateHandle(PsGetCurrentProcess(),
332 *Object,
333 DesiredAccess,
334 ObjectAttributes && (ObjectAttributes->Attributes & OBJ_INHERIT) ? TRUE : FALSE,
335 Handle);
336 }
337
338 return(STATUS_SUCCESS);
339 }
340
341
342 NTSTATUS STDCALL
343 ObReferenceObjectByPointer(IN PVOID Object,
344 IN ACCESS_MASK DesiredAccess,
345 IN POBJECT_TYPE ObjectType,
346 IN KPROCESSOR_MODE AccessMode)
347 /*
348 * FUNCTION: Increments the pointer reference count for a given object
349 * ARGUMENTS:
350 * ObjectBody = Object's body
351 * DesiredAccess = Desired access to the object
352 * ObjectType = Points to the object type structure
353 * AccessMode = Type of access check to perform
354 * RETURNS: Status
355 */
356 {
357 POBJECT_HEADER Header;
358
359 // DPRINT("ObReferenceObjectByPointer(Object %x, ObjectType %x)\n",
360 // Object,ObjectType);
361
362 Header = BODY_TO_HEADER(Object);
363
364 if (ObjectType != NULL && Header->ObjectType != ObjectType)
365 {
366 DPRINT("Failed %x (type was %x %S) should be %x %S\n",
367 Header,
368 Header->ObjectType,
369 Header->ObjectType->TypeName.Buffer,
370 ObjectType,
371 ObjectType->TypeName.Buffer);
372 return(STATUS_UNSUCCESSFUL);
373 }
374 if (Header->ObjectType == PsProcessType)
375 {
376 DPRINT("Ref p 0x%x refcount %d type %x ",
377 Object, Header->RefCount, PsProcessType);
378 DPRINT("eip %x\n", ((PULONG)&Object)[-1]);
379 }
380 if (Header->ObjectType == PsThreadType)
381 {
382 DPRINT("Deref t 0x%x with refcount %d type %x ",
383 Object, Header->RefCount, PsThreadType);
384 DPRINT("eip %x\n", ((PULONG)&Object)[-1]);
385 }
386
387 InterlockedIncrement(&Header->RefCount);
388
389 return(STATUS_SUCCESS);
390 }
391
392
393 NTSTATUS STDCALL
394 ObOpenObjectByPointer(IN POBJECT Object,
395 IN ULONG HandleAttributes,
396 IN PACCESS_STATE PassedAccessState,
397 IN ACCESS_MASK DesiredAccess,
398 IN POBJECT_TYPE ObjectType,
399 IN KPROCESSOR_MODE AccessMode,
400 OUT PHANDLE Handle)
401 {
402 NTSTATUS Status;
403
404 DPRINT("ObOpenObjectByPointer()\n");
405
406 Status = ObReferenceObjectByPointer(Object,
407 0,
408 ObjectType,
409 AccessMode);
410 if (!NT_SUCCESS(Status))
411 {
412 return Status;
413 }
414
415 Status = ObCreateHandle(PsGetCurrentProcess(),
416 Object,
417 DesiredAccess,
418 HandleAttributes & OBJ_INHERIT,
419 Handle);
420
421 ObDereferenceObject(Object);
422
423 return STATUS_SUCCESS;
424 }
425
426
427 static NTSTATUS
428 ObpPerformRetentionChecks(POBJECT_HEADER Header)
429 {
430 // DPRINT("ObPerformRetentionChecks(Header %x), RefCount %d, HandleCount %d\n",
431 // Header,Header->RefCount,Header->HandleCount);
432
433 if (Header->RefCount < 0)
434 {
435 CPRINT("Object %x/%x has invalid reference count (%d)\n",
436 Header, HEADER_TO_BODY(Header), Header->RefCount);
437 KeBugCheck(0);
438 }
439 if (Header->HandleCount < 0)
440 {
441 CPRINT("Object %x/%x has invalid handle count (%d)\n",
442 Header, HEADER_TO_BODY(Header), Header->HandleCount);
443 KeBugCheck(0);
444 }
445
446 if (Header->RefCount == 0 &&
447 Header->HandleCount == 0 &&
448 Header->Permanent == FALSE)
449 {
450 if (Header->ObjectType != NULL &&
451 Header->ObjectType->Delete != NULL)
452 {
453 Header->ObjectType->Delete(HEADER_TO_BODY(Header));
454 }
455 if (Header->Name.Buffer != NULL)
456 {
457 ObpRemoveEntryDirectory(Header);
458 RtlFreeUnicodeString(&Header->Name);
459 }
460 DPRINT("ObPerformRetentionChecks() = Freeing object\n");
461 ExFreePool(Header);
462 }
463 return(STATUS_SUCCESS);
464 }
465
466
467 /**********************************************************************
468 * NAME EXPORTED
469 * ObfReferenceObject@4
470 *
471 * DESCRIPTION
472 * Increments a given object's reference count and performs
473 * retention checks.
474 *
475 * ARGUMENTS
476 * ObjectBody = Body of the object.
477 *
478 * RETURN VALUE
479 * None.
480 */
481 VOID FASTCALL
482 ObfReferenceObject(IN PVOID Object)
483 {
484 POBJECT_HEADER Header;
485
486 assert(Object);
487
488 Header = BODY_TO_HEADER(Object);
489
490 InterlockedIncrement(&Header->RefCount);
491
492 ObpPerformRetentionChecks(Header);
493 }
494
495
496 /**********************************************************************
497 * NAME EXPORTED
498 * ObfDereferenceObject@4
499 *
500 * DESCRIPTION
501 * Decrements a given object's reference count and performs
502 * retention checks.
503 *
504 * ARGUMENTS
505 * ObjectBody = Body of the object.
506 *
507 * RETURN VALUE
508 * None.
509 */
510 VOID FASTCALL
511 ObfDereferenceObject(IN PVOID Object)
512 {
513 POBJECT_HEADER Header;
514 extern POBJECT_TYPE PsProcessType;
515
516 assert(Object);
517
518 Header = BODY_TO_HEADER(Object);
519
520 if (Header->ObjectType == PsProcessType)
521 {
522 DPRINT("Deref p 0x%x with refcount %d type %x ",
523 Object, Header->RefCount, PsProcessType);
524 DPRINT("eip %x\n", ((PULONG)&Object)[-1]);
525 }
526 if (Header->ObjectType == PsThreadType)
527 {
528 DPRINT("Deref t 0x%x with refcount %d type %x ",
529 Object, Header->RefCount, PsThreadType);
530 DPRINT("eip %x\n", ((PULONG)&Object)[-1]);
531 }
532
533 InterlockedDecrement(&Header->RefCount);
534
535 ObpPerformRetentionChecks(Header);
536 }
537
538
539 /**********************************************************************
540 * NAME EXPORTED
541 * ObGetObjectPointerCount@4
542 *
543 * DESCRIPTION
544 * Retrieves the pointer(reference) count of the given object.
545 *
546 * ARGUMENTS
547 * ObjectBody = Body of the object.
548 *
549 * RETURN VALUE
550 * Reference count.
551 */
552 ULONG STDCALL
553 ObGetObjectPointerCount(PVOID Object)
554 {
555 POBJECT_HEADER Header;
556
557 assert(Object);
558 Header = BODY_TO_HEADER(Object);
559
560 return(Header->RefCount);
561 }
562
563
564 /**********************************************************************
565 * NAME INTERNAL
566 * ObGetObjectHandleCount@4
567 *
568 * DESCRIPTION
569 * Retrieves the handle count of the given object.
570 *
571 * ARGUMENTS
572 * ObjectBody = Body of the object.
573 *
574 * RETURN VALUE
575 * Reference count.
576 */
577 ULONG
578 ObGetObjectHandleCount(PVOID Object)
579 {
580 POBJECT_HEADER Header;
581
582 assert(Object);
583 Header = BODY_TO_HEADER(Object);
584
585 return(Header->HandleCount);
586 }
587
588 /* EOF */