Added CloseInProcess to the structure OBJECT_HEADER.
[reactos.git] / reactos / ntoskrnl / ob / object.c
1 /* $Id: object.c,v 1.54 2002/08/27 06:34:22 hbirr 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
247 if (ObjectAttributes != NULL &&
248 ObjectAttributes->ObjectName != NULL &&
249 ObjectAttributes->ObjectName->Buffer != NULL)
250 {
251 Status = ObFindObject(ObjectAttributes,
252 &Parent,
253 &RemainingPath,
254 NULL);
255 if (!NT_SUCCESS(Status))
256 {
257 DPRINT("ObFindObject() failed! (Status 0x%x)\n", Status);
258 return(Status);
259 }
260 }
261 else
262 {
263 RtlInitUnicodeString(&RemainingPath, NULL);
264 }
265
266 RtlMapGenericMask(&DesiredAccess,
267 Type->Mapping);
268
269 Header = (POBJECT_HEADER)ExAllocatePoolWithTag(NonPagedPool,
270 OBJECT_ALLOC_SIZE(Type),
271 Type->Tag);
272 ObInitializeObject(Header,
273 NULL,
274 DesiredAccess,
275 Type,
276 ObjectAttributes);
277
278 if (Parent != NULL)
279 {
280 ParentHeader = BODY_TO_HEADER(Parent);
281 }
282
283 if (ParentHeader != NULL &&
284 ParentHeader->ObjectType == ObDirectoryType &&
285 RemainingPath.Buffer != NULL)
286 {
287 ObpAddEntryDirectory(Parent,
288 Header,
289 RemainingPath.Buffer+1);
290 ObjectAttached = TRUE;
291 }
292
293 if ((Header->ObjectType != NULL) &&
294 (Header->ObjectType->Create != NULL))
295 {
296 DPRINT("Calling %x\n", Header->ObjectType->Create);
297 Status = Header->ObjectType->Create(HEADER_TO_BODY(Header),
298 Parent,
299 RemainingPath.Buffer,
300 ObjectAttributes);
301 if (!NT_SUCCESS(Status))
302 {
303 if (ObjectAttached == TRUE)
304 {
305 ObpRemoveEntryDirectory(Header);
306 }
307 if (Parent)
308 {
309 ObDereferenceObject(Parent);
310 }
311 RtlFreeUnicodeString(&Header->Name);
312 RtlFreeUnicodeString(&RemainingPath);
313 ExFreePool(Header);
314 return(Status);
315 }
316 }
317 RtlFreeUnicodeString( &RemainingPath );
318
319 if (Object != NULL)
320 {
321 *Object = HEADER_TO_BODY(Header);
322 }
323
324 if (Handle != NULL)
325 {
326 ObCreateHandle(PsGetCurrentProcess(),
327 *Object,
328 DesiredAccess,
329 ObjectAttributes && (ObjectAttributes->Attributes & OBJ_INHERIT) ? TRUE : FALSE,
330 Handle);
331 }
332
333 return(STATUS_SUCCESS);
334 }
335
336
337 NTSTATUS STDCALL
338 ObReferenceObjectByPointer(IN PVOID Object,
339 IN ACCESS_MASK DesiredAccess,
340 IN POBJECT_TYPE ObjectType,
341 IN KPROCESSOR_MODE AccessMode)
342 /*
343 * FUNCTION: Increments the pointer reference count for a given object
344 * ARGUMENTS:
345 * ObjectBody = Object's body
346 * DesiredAccess = Desired access to the object
347 * ObjectType = Points to the object type structure
348 * AccessMode = Type of access check to perform
349 * RETURNS: Status
350 */
351 {
352 POBJECT_HEADER Header;
353
354 // DPRINT("ObReferenceObjectByPointer(Object %x, ObjectType %x)\n",
355 // Object,ObjectType);
356
357 Header = BODY_TO_HEADER(Object);
358
359 if (ObjectType != NULL && Header->ObjectType != ObjectType)
360 {
361 DPRINT("Failed %x (type was %x %S) should be %x %S\n",
362 Header,
363 Header->ObjectType,
364 Header->ObjectType->TypeName.Buffer,
365 ObjectType,
366 ObjectType->TypeName.Buffer);
367 return(STATUS_UNSUCCESSFUL);
368 }
369 if (Header->ObjectType == PsProcessType)
370 {
371 DPRINT("Ref p 0x%x refcount %d type %x ",
372 Object, Header->RefCount, PsProcessType);
373 DPRINT("eip %x\n", ((PULONG)&Object)[-1]);
374 }
375 if (Header->ObjectType == PsThreadType)
376 {
377 DPRINT("Deref t 0x%x with refcount %d type %x ",
378 Object, Header->RefCount, PsThreadType);
379 DPRINT("eip %x\n", ((PULONG)&Object)[-1]);
380 }
381
382 if (Header->CloseInProcess)
383 {
384 return(STATUS_UNSUCCESSFUL);
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->CloseInProcess)
451 {
452 KeBugCheck(0);
453 return STATUS_UNSUCCESSFUL;
454 }
455 Header->CloseInProcess = TRUE;
456 if (Header->ObjectType != NULL &&
457 Header->ObjectType->Delete != NULL)
458 {
459 Header->ObjectType->Delete(HEADER_TO_BODY(Header));
460 }
461 if (Header->Name.Buffer != NULL)
462 {
463 ObpRemoveEntryDirectory(Header);
464 RtlFreeUnicodeString(&Header->Name);
465 }
466 DPRINT("ObPerformRetentionChecks() = Freeing object\n");
467 ExFreePool(Header);
468 }
469 return(STATUS_SUCCESS);
470 }
471
472
473 /**********************************************************************
474 * NAME EXPORTED
475 * ObfReferenceObject@4
476 *
477 * DESCRIPTION
478 * Increments a given object's reference count and performs
479 * retention checks.
480 *
481 * ARGUMENTS
482 * ObjectBody = Body of the object.
483 *
484 * RETURN VALUE
485 * None.
486 */
487 VOID FASTCALL
488 ObfReferenceObject(IN PVOID Object)
489 {
490 POBJECT_HEADER Header;
491
492 assert(Object);
493
494 Header = BODY_TO_HEADER(Object);
495
496 if (Header->CloseInProcess)
497 {
498 KeBugCheck(0);
499 }
500 InterlockedIncrement(&Header->RefCount);
501
502 ObpPerformRetentionChecks(Header);
503 }
504
505
506 /**********************************************************************
507 * NAME EXPORTED
508 * ObfDereferenceObject@4
509 *
510 * DESCRIPTION
511 * Decrements a given object's reference count and performs
512 * retention checks.
513 *
514 * ARGUMENTS
515 * ObjectBody = Body of the object.
516 *
517 * RETURN VALUE
518 * None.
519 */
520 VOID FASTCALL
521 ObfDereferenceObject(IN PVOID Object)
522 {
523 POBJECT_HEADER Header;
524 extern POBJECT_TYPE PsProcessType;
525
526 assert(Object);
527
528 Header = BODY_TO_HEADER(Object);
529
530 if (Header->ObjectType == PsProcessType)
531 {
532 DPRINT("Deref p 0x%x with refcount %d type %x ",
533 Object, Header->RefCount, PsProcessType);
534 DPRINT("eip %x\n", ((PULONG)&Object)[-1]);
535 }
536 if (Header->ObjectType == PsThreadType)
537 {
538 DPRINT("Deref t 0x%x with refcount %d type %x ",
539 Object, Header->RefCount, PsThreadType);
540 DPRINT("eip %x\n", ((PULONG)&Object)[-1]);
541 }
542
543 InterlockedDecrement(&Header->RefCount);
544
545 ObpPerformRetentionChecks(Header);
546 }
547
548
549 /**********************************************************************
550 * NAME EXPORTED
551 * ObGetObjectPointerCount@4
552 *
553 * DESCRIPTION
554 * Retrieves the pointer(reference) count of the given object.
555 *
556 * ARGUMENTS
557 * ObjectBody = Body of the object.
558 *
559 * RETURN VALUE
560 * Reference count.
561 */
562 ULONG STDCALL
563 ObGetObjectPointerCount(PVOID Object)
564 {
565 POBJECT_HEADER Header;
566
567 assert(Object);
568 Header = BODY_TO_HEADER(Object);
569
570 return(Header->RefCount);
571 }
572
573
574 /**********************************************************************
575 * NAME INTERNAL
576 * ObGetObjectHandleCount@4
577 *
578 * DESCRIPTION
579 * Retrieves the handle count of the given object.
580 *
581 * ARGUMENTS
582 * ObjectBody = Body of the object.
583 *
584 * RETURN VALUE
585 * Reference count.
586 */
587 ULONG
588 ObGetObjectHandleCount(PVOID Object)
589 {
590 POBJECT_HEADER Header;
591
592 assert(Object);
593 Header = BODY_TO_HEADER(Object);
594
595 return(Header->HandleCount);
596 }
597
598 /* EOF */