Added ObGetObjectHandleCount().
[reactos.git] / reactos / ntoskrnl / ob / object.c
1 /* $Id: object.c,v 1.46 2002/03/05 00:19:28 ekohl 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 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 ObjectType,
189 ObjectAttributes->Attributes);
190 if (Status == STATUS_REPARSE)
191 {
192 /* reparse the object path */
193 NextObject = RootObject;
194 current = PathString.Buffer;
195
196 ObReferenceObjectByPointer(NextObject,
197 DIRECTORY_TRAVERSE,
198 NULL,
199 UserMode);
200 }
201
202 if (NextObject == NULL)
203 {
204 break;
205 }
206 ObDereferenceObject(CurrentObject);
207 CurrentObject = NextObject;
208 }
209
210 if (current)
211 RtlCreateUnicodeString (RemainingPath, current);
212 RtlFreeUnicodeString (&PathString);
213 *ReturnedObject = CurrentObject;
214
215 return(STATUS_SUCCESS);
216 }
217
218
219 /**********************************************************************
220 * NAME EXPORTED
221 * ObCreateObject@36
222 *
223 * DESCRIPTION
224 *
225 * ARGUMENTS
226 *
227 * RETURN VALUE
228 */
229 NTSTATUS STDCALL
230 ObCreateObject(OUT PHANDLE Handle,
231 IN ACCESS_MASK DesiredAccess,
232 IN POBJECT_ATTRIBUTES ObjectAttributes,
233 IN POBJECT_TYPE Type,
234 OUT PVOID *Object)
235 {
236 PVOID Parent = NULL;
237 UNICODE_STRING RemainingPath;
238 POBJECT_HEADER Header;
239 POBJECT_HEADER ParentHeader = NULL;
240 NTSTATUS Status;
241 BOOLEAN ObjectAttached = FALSE;
242
243 assert_irql(APC_LEVEL);
244
245 DPRINT("ObCreateObject(Handle %x, ObjectAttributes %x, Type %x)\n",
246 Handle, ObjectAttributes, Type);
247 if (ObjectAttributes != NULL &&
248 ObjectAttributes->ObjectName != NULL)
249 {
250 DPRINT("ObjectAttributes->ObjectName->Buffer %S\n",
251 ObjectAttributes->ObjectName->Buffer);
252 }
253
254 if (ObjectAttributes != NULL &&
255 ObjectAttributes->ObjectName != NULL)
256 {
257 Status = ObFindObject(ObjectAttributes,
258 &Parent,
259 &RemainingPath,
260 NULL);
261 if (!NT_SUCCESS(Status))
262 {
263 DPRINT("ObFindObject() failed! (Status 0x%x)\n", Status);
264 return(Status);
265 }
266 }
267 else
268 {
269 RtlInitUnicodeString(&RemainingPath, NULL);
270 }
271
272 RtlMapGenericMask(&DesiredAccess,
273 Type->Mapping);
274
275 Header = (POBJECT_HEADER)ExAllocatePoolWithTag(NonPagedPool,
276 OBJECT_ALLOC_SIZE(Type),
277 Type->Tag);
278 ObInitializeObject(Header,
279 Handle,
280 DesiredAccess,
281 Type,
282 ObjectAttributes);
283
284 if (Parent != NULL)
285 {
286 ParentHeader = BODY_TO_HEADER(Parent);
287 }
288
289 if (ParentHeader != NULL &&
290 ParentHeader->ObjectType == ObDirectoryType &&
291 RemainingPath.Buffer != NULL)
292 {
293 ObpAddEntryDirectory(Parent,
294 Header,
295 RemainingPath.Buffer+1);
296 ObjectAttached = TRUE;
297 }
298
299 if ((Header->ObjectType != NULL) &&
300 (Header->ObjectType->Create != NULL))
301 {
302 DPRINT("Calling %x\n", Header->ObjectType->Create);
303 Status = Header->ObjectType->Create(HEADER_TO_BODY(Header),
304 Parent,
305 RemainingPath.Buffer,
306 ObjectAttributes);
307 if (!NT_SUCCESS(Status))
308 {
309 if (ObjectAttached == TRUE)
310 {
311 ObpRemoveEntryDirectory(Header);
312 }
313 if (Parent)
314 {
315 ObDereferenceObject(Parent);
316 }
317 RtlFreeUnicodeString(&Header->Name);
318 RtlFreeUnicodeString(&RemainingPath);
319 ExFreePool(Header);
320 return(Status);
321 }
322 }
323 RtlFreeUnicodeString( &RemainingPath );
324
325 *Object = HEADER_TO_BODY(Header);
326
327 return(STATUS_SUCCESS);
328 }
329
330
331 NTSTATUS STDCALL
332 ObReferenceObjectByPointer(IN PVOID Object,
333 IN ACCESS_MASK DesiredAccess,
334 IN POBJECT_TYPE ObjectType,
335 IN KPROCESSOR_MODE AccessMode)
336 /*
337 * FUNCTION: Increments the pointer reference count for a given object
338 * ARGUMENTS:
339 * ObjectBody = Object's body
340 * DesiredAccess = Desired access to the object
341 * ObjectType = Points to the object type structure
342 * AccessMode = Type of access check to perform
343 * RETURNS: Status
344 */
345 {
346 POBJECT_HEADER Header;
347
348 // DPRINT("ObReferenceObjectByPointer(Object %x, ObjectType %x)\n",
349 // Object,ObjectType);
350
351 Header = BODY_TO_HEADER(Object);
352
353 if (ObjectType != NULL && Header->ObjectType != ObjectType)
354 {
355 DPRINT("Failed %x (type was %x %S) should be %x %S\n",
356 Header,
357 Header->ObjectType,
358 Header->ObjectType->TypeName.Buffer,
359 ObjectType,
360 ObjectType->TypeName.Buffer);
361 return(STATUS_UNSUCCESSFUL);
362 }
363 if (Header->ObjectType == PsProcessType)
364 {
365 DPRINT("Ref p 0x%x refcount %d type %x ",
366 Object, Header->RefCount, PsProcessType);
367 DPRINT("eip %x\n", ((PULONG)&Object)[-1]);
368 }
369 if (Header->ObjectType == PsThreadType)
370 {
371 DPRINT("Deref t 0x%x with refcount %d type %x ",
372 Object, Header->RefCount, PsThreadType);
373 DPRINT("eip %x\n", ((PULONG)&Object)[-1]);
374 }
375
376 Header->RefCount++;
377
378 return(STATUS_SUCCESS);
379 }
380
381
382 NTSTATUS STDCALL
383 ObOpenObjectByPointer(IN POBJECT Object,
384 IN ULONG HandleAttributes,
385 IN PACCESS_STATE PassedAccessState,
386 IN ACCESS_MASK DesiredAccess,
387 IN POBJECT_TYPE ObjectType,
388 IN KPROCESSOR_MODE AccessMode,
389 OUT PHANDLE Handle)
390 {
391 NTSTATUS Status;
392
393 DPRINT("ObOpenObjectByPointer()\n");
394
395 Status = ObReferenceObjectByPointer(Object,
396 0,
397 ObjectType,
398 AccessMode);
399 if (!NT_SUCCESS(Status))
400 {
401 return Status;
402 }
403
404 Status = ObCreateHandle(PsGetCurrentProcess(),
405 Object,
406 DesiredAccess,
407 FALSE,
408 Handle);
409
410 ObDereferenceObject(Object);
411
412 return STATUS_SUCCESS;
413 }
414
415
416 static NTSTATUS
417 ObpPerformRetentionChecks(POBJECT_HEADER Header)
418 {
419 // DPRINT("ObPerformRetentionChecks(Header %x), RefCount %d, HandleCount %d\n",
420 // Header,Header->RefCount,Header->HandleCount);
421
422 if (Header->RefCount < 0)
423 {
424 CPRINT("Object %x/%x has invalid reference count (%d)\n",
425 Header, HEADER_TO_BODY(Header), Header->RefCount);
426 KeBugCheck(0);
427 }
428 if (Header->HandleCount < 0)
429 {
430 CPRINT("Object %x/%x has invalid handle count (%d)\n",
431 Header, HEADER_TO_BODY(Header), Header->HandleCount);
432 KeBugCheck(0);
433 }
434
435 if (Header->RefCount == 0 &&
436 Header->HandleCount == 0 &&
437 Header->Permanent == FALSE)
438 {
439 if (Header->ObjectType != NULL &&
440 Header->ObjectType->Delete != NULL)
441 {
442 Header->ObjectType->Delete(HEADER_TO_BODY(Header));
443 }
444 if (Header->Name.Buffer != NULL)
445 {
446 ObpRemoveEntryDirectory(Header);
447 RtlFreeUnicodeString(&Header->Name);
448 }
449 DPRINT("ObPerformRetentionChecks() = Freeing object\n");
450 ExFreePool(Header);
451 }
452 return(STATUS_SUCCESS);
453 }
454
455
456 /**********************************************************************
457 * NAME EXPORTED
458 * ObfReferenceObject@4
459 *
460 * DESCRIPTION
461 * Increments a given object's reference count and performs
462 * retention checks.
463 *
464 * ARGUMENTS
465 * ObjectBody = Body of the object.
466 *
467 * RETURN VALUE
468 * None.
469 */
470 VOID FASTCALL
471 ObfReferenceObject(IN PVOID Object)
472 {
473 POBJECT_HEADER Header;
474
475 assert(Object);
476
477 Header = BODY_TO_HEADER(Object);
478
479 Header->RefCount++;
480
481 ObpPerformRetentionChecks(Header);
482 }
483
484
485 /**********************************************************************
486 * NAME EXPORTED
487 * ObfDereferenceObject@4
488 *
489 * DESCRIPTION
490 * Decrements a given object's reference count and performs
491 * retention checks.
492 *
493 * ARGUMENTS
494 * ObjectBody = Body of the object.
495 *
496 * RETURN VALUE
497 * None.
498 */
499 VOID FASTCALL
500 ObfDereferenceObject(IN PVOID Object)
501 {
502 POBJECT_HEADER Header;
503 extern POBJECT_TYPE PsProcessType;
504
505 assert(Object);
506
507 Header = BODY_TO_HEADER(Object);
508
509 if (Header->ObjectType == PsProcessType)
510 {
511 DPRINT("Deref p 0x%x with refcount %d type %x ",
512 Object, Header->RefCount, PsProcessType);
513 DPRINT("eip %x\n", ((PULONG)&Object)[-1]);
514 }
515 if (Header->ObjectType == PsThreadType)
516 {
517 DPRINT("Deref t 0x%x with refcount %d type %x ",
518 Object, Header->RefCount, PsThreadType);
519 DPRINT("eip %x\n", ((PULONG)&Object)[-1]);
520 }
521
522 Header->RefCount--;
523
524 ObpPerformRetentionChecks(Header);
525 }
526
527
528 /**********************************************************************
529 * NAME EXPORTED
530 * ObGetObjectPointerCount@4
531 *
532 * DESCRIPTION
533 * Retrieves the pointer(reference) count of the given object.
534 *
535 * ARGUMENTS
536 * ObjectBody = Body of the object.
537 *
538 * RETURN VALUE
539 * Reference count.
540 */
541 ULONG STDCALL
542 ObGetObjectPointerCount(PVOID Object)
543 {
544 POBJECT_HEADER Header;
545
546 assert(Object);
547 Header = BODY_TO_HEADER(Object);
548
549 return(Header->RefCount);
550 }
551
552
553 /**********************************************************************
554 * NAME INTERNAL
555 * ObGetObjectHandleCount@4
556 *
557 * DESCRIPTION
558 * Retrieves the handle count of the given object.
559 *
560 * ARGUMENTS
561 * ObjectBody = Body of the object.
562 *
563 * RETURN VALUE
564 * Reference count.
565 */
566 ULONG
567 ObGetObjectHandleCount(PVOID Object)
568 {
569 POBJECT_HEADER Header;
570
571 assert(Object);
572 Header = BODY_TO_HEADER(Object);
573
574 return(Header->HandleCount);
575 }
576
577 /* EOF */