ObInitializeObject(): ObjectHeader->CloseInProcess: Fixed missing initialization
[reactos.git] / ntoskrnl / ob / object.c
1 /* $Id$
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->CloseInProcess = FALSE;
55    ObjectHeader->HandleCount = 0;
56    ObjectHeader->RefCount = 1;
57    ObjectHeader->ObjectType = Type;
58    if (ObjectAttributes != NULL &&
59        ObjectAttributes->Attributes & OBJ_PERMANENT)
60      {
61         ObjectHeader->Permanent = TRUE;
62      }
63    else
64      {
65         ObjectHeader->Permanent = FALSE;
66      }
67    RtlInitUnicodeString(&(ObjectHeader->Name),NULL);
68    if (Handle != NULL)
69      {
70         ObCreateHandle(PsGetCurrentProcess(),
71                        HEADER_TO_BODY(ObjectHeader),
72                        DesiredAccess,
73                        ObjectAttributes && (ObjectAttributes->Attributes & OBJ_INHERIT) ? TRUE : FALSE,
74                        Handle);
75      }
76 }
77
78
79 /**********************************************************************
80  * NAME                                                 PRIVATE
81  *      ObFindObject@16
82  *
83  * DESCRIPTION
84  *
85  * ARGUMENTS
86  *      ObjectAttributes
87  *
88  *      ReturnedObject
89  *
90  *      RemainigPath
91  *              Pointer to a unicode string that will contain the
92  *              remaining path if the function returns successfully.
93  *              The caller must free the buffer after use by calling
94  *              RtlFreeUnicodeString ().
95  *
96  *      ObjectType
97  *              Optional pointer to an object type. This is used to
98  *              descide if a symbolic link object will be parsed or not.
99  *
100  * RETURN VALUE
101  */
102 NTSTATUS ObFindObject(POBJECT_ATTRIBUTES ObjectAttributes,
103                       PVOID* ReturnedObject,
104                       PUNICODE_STRING RemainingPath,
105                       POBJECT_TYPE ObjectType)
106 {
107    PVOID NextObject;
108    PVOID CurrentObject;
109    PVOID RootObject;
110    POBJECT_HEADER CurrentHeader;
111    NTSTATUS Status;
112    PWSTR Path;
113    PWSTR current;
114    UNICODE_STRING PathString;
115    
116    DPRINT("ObFindObject(ObjectAttributes %x, ReturnedObject %x, "
117           "RemainingPath %x)\n",ObjectAttributes,ReturnedObject,RemainingPath);
118    DPRINT("ObjectAttributes->ObjectName %wZ\n",
119           ObjectAttributes->ObjectName);
120
121    RtlInitUnicodeString (RemainingPath, NULL);
122
123    if (ObjectAttributes->RootDirectory == NULL)
124      {
125         ObReferenceObjectByPointer(NameSpaceRoot,
126                                    DIRECTORY_TRAVERSE,
127                                    NULL,
128                                    UserMode);
129         CurrentObject = NameSpaceRoot;
130      }
131    else
132      {
133         Status = ObReferenceObjectByHandle(ObjectAttributes->RootDirectory,
134                                            DIRECTORY_TRAVERSE,
135                                            NULL,
136                                            UserMode,
137                                            &CurrentObject,
138                                            NULL);
139         if (!NT_SUCCESS(Status))
140           {
141              return(Status);
142           }
143      }
144    
145    Path = ObjectAttributes->ObjectName->Buffer;
146    
147    if (Path[0] == 0)
148      {
149         *ReturnedObject = CurrentObject;
150         return(STATUS_SUCCESS);
151      }
152    
153    if ((ObjectAttributes->RootDirectory == NULL) && (Path[0] != '\\'))
154      {
155         ObDereferenceObject(CurrentObject);
156         return(STATUS_UNSUCCESSFUL);
157      }
158    
159    if (Path)
160      {
161         RtlCreateUnicodeString (&PathString, Path);
162         current = PathString.Buffer;
163      }
164    else
165      {
166         RtlInitUnicodeString (&PathString, NULL);
167         current = NULL;
168      }
169
170    RootObject = CurrentObject;
171
172    while (TRUE)
173      {
174         DPRINT("current %S\n",current);
175         CurrentHeader = BODY_TO_HEADER(CurrentObject);
176
177         DPRINT("Current ObjectType %wZ\n",
178                &CurrentHeader->ObjectType->TypeName);
179
180         if (CurrentHeader->ObjectType->Parse == NULL)
181           {
182              DPRINT("Current object can't parse\n");
183              break;
184           }
185         Status = CurrentHeader->ObjectType->Parse(CurrentObject,
186                                                   &NextObject,
187                                                   &PathString,
188                                                   &current,
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
248   if (ObjectAttributes != NULL &&
249       ObjectAttributes->ObjectName != NULL &&
250       ObjectAttributes->ObjectName->Buffer != NULL)
251     {
252       Status = ObFindObject(ObjectAttributes,
253                             &Parent,
254                             &RemainingPath,
255                             NULL);
256       if (!NT_SUCCESS(Status))
257         {
258           DPRINT("ObFindObject() failed! (Status 0x%x)\n", Status);
259           return(Status);
260         }
261     }
262   else
263     {
264       RtlInitUnicodeString(&RemainingPath, NULL);
265     }
266
267   RtlMapGenericMask(&DesiredAccess,
268                     Type->Mapping);
269
270   Header = (POBJECT_HEADER)ExAllocatePoolWithTag(NonPagedPool,
271                                                  OBJECT_ALLOC_SIZE(Type),
272                                                  Type->Tag);
273   ObInitializeObject(Header,
274                      NULL,
275                      DesiredAccess,
276                      Type,
277                      ObjectAttributes);
278
279   if (Parent != NULL)
280     {
281       ParentHeader = BODY_TO_HEADER(Parent);
282     }
283
284   if (ParentHeader != NULL &&
285       ParentHeader->ObjectType == ObDirectoryType &&
286       RemainingPath.Buffer != NULL)
287     {
288       ObpAddEntryDirectory(Parent,
289                            Header,
290                            RemainingPath.Buffer+1);
291       ObjectAttached = TRUE;
292     }
293
294   if ((Header->ObjectType != NULL) &&
295       (Header->ObjectType->Create != NULL))
296     {
297       DPRINT("Calling %x\n", Header->ObjectType->Create);
298       Status = Header->ObjectType->Create(HEADER_TO_BODY(Header),
299                                           Parent,
300                                           RemainingPath.Buffer,
301                                           ObjectAttributes);
302       if (!NT_SUCCESS(Status))
303         {
304           if (ObjectAttached == TRUE)
305             {
306               ObpRemoveEntryDirectory(Header);
307             }
308           if (Parent)
309             {
310               ObDereferenceObject(Parent);
311             }
312           RtlFreeUnicodeString(&Header->Name);
313           RtlFreeUnicodeString(&RemainingPath);
314           ExFreePool(Header);
315           return(Status);
316         }
317     }
318   RtlFreeUnicodeString( &RemainingPath );
319
320   if (Object != NULL)
321     {
322       *Object = HEADER_TO_BODY(Header);
323     }
324
325   if (Handle != NULL)
326   {
327      ObCreateHandle(PsGetCurrentProcess(),
328                     *Object,
329                     DesiredAccess,
330                     ObjectAttributes && (ObjectAttributes->Attributes & OBJ_INHERIT) ? TRUE : FALSE,
331                     Handle);
332   }
333
334   return(STATUS_SUCCESS);
335 }
336
337
338 NTSTATUS STDCALL
339 ObReferenceObjectByPointer(IN PVOID Object,
340                            IN ACCESS_MASK DesiredAccess,
341                            IN POBJECT_TYPE ObjectType,
342                            IN KPROCESSOR_MODE AccessMode)
343 /*
344  * FUNCTION: Increments the pointer reference count for a given object
345  * ARGUMENTS:
346  *         ObjectBody = Object's body
347  *         DesiredAccess = Desired access to the object
348  *         ObjectType = Points to the object type structure
349  *         AccessMode = Type of access check to perform
350  * RETURNS: Status
351  */
352 {
353    POBJECT_HEADER Header;
354
355 //   DPRINT("ObReferenceObjectByPointer(Object %x, ObjectType %x)\n",
356 //        Object,ObjectType);
357    
358    Header = BODY_TO_HEADER(Object);
359    
360    if (ObjectType != NULL && Header->ObjectType != ObjectType)
361      {
362         DPRINT("Failed %x (type was %x %S) should be %x %S\n",
363                 Header,
364                 Header->ObjectType,
365                 Header->ObjectType->TypeName.Buffer,
366                 ObjectType,
367     ObjectType->TypeName.Buffer);
368         return(STATUS_UNSUCCESSFUL);
369      }
370    if (Header->ObjectType == PsProcessType)
371      {
372         DPRINT("Ref p 0x%x refcount %d type %x ",
373                 Object, Header->RefCount, PsProcessType);
374         DPRINT("eip %x\n", ((PULONG)&Object)[-1]);
375      }
376    if (Header->ObjectType == PsThreadType)
377      {
378         DPRINT("Deref t 0x%x with refcount %d type %x ",
379                 Object, Header->RefCount, PsThreadType);
380         DPRINT("eip %x\n", ((PULONG)&Object)[-1]);
381      }
382  
383    if (Header->CloseInProcess)
384    {
385       return(STATUS_UNSUCCESSFUL);
386    }
387
388    InterlockedIncrement(&Header->RefCount);
389    
390    return(STATUS_SUCCESS);
391 }
392
393 #ifndef LIBCAPTIVE
394
395 NTSTATUS STDCALL
396 ObOpenObjectByPointer(IN POBJECT Object,
397                       IN ULONG HandleAttributes,
398                       IN PACCESS_STATE PassedAccessState,
399                       IN ACCESS_MASK DesiredAccess,
400                       IN POBJECT_TYPE ObjectType,
401                       IN KPROCESSOR_MODE AccessMode,
402                       OUT PHANDLE Handle)
403 {
404    NTSTATUS Status;
405    
406    DPRINT("ObOpenObjectByPointer()\n");
407    
408    Status = ObReferenceObjectByPointer(Object,
409                                        0,
410                                        ObjectType,
411                                        AccessMode);
412    if (!NT_SUCCESS(Status))
413      {
414         return Status;
415      }
416    
417    Status = ObCreateHandle(PsGetCurrentProcess(),
418                            Object,
419                            DesiredAccess,
420                            HandleAttributes & OBJ_INHERIT,
421                            Handle);
422    
423    ObDereferenceObject(Object);
424    
425    return STATUS_SUCCESS;
426 }
427
428 #endif /* LIBCAPTIVE */
429
430 static NTSTATUS
431 ObpPerformRetentionChecks(POBJECT_HEADER Header)
432 {
433 //  DPRINT("ObPerformRetentionChecks(Header %x), RefCount %d, HandleCount %d\n",
434 //        Header,Header->RefCount,Header->HandleCount);
435   
436   if (Header->RefCount < 0)
437     {
438       CPRINT("Object %x/%x has invalid reference count (%d)\n",
439              Header, HEADER_TO_BODY(Header), Header->RefCount);
440       KeBugCheck(0);
441     }
442   if (Header->HandleCount < 0)
443     {
444       CPRINT("Object %x/%x has invalid handle count (%d)\n",
445              Header, HEADER_TO_BODY(Header), Header->HandleCount);
446       KeBugCheck(0);
447     }
448   
449   if (Header->RefCount == 0 &&
450       Header->HandleCount == 0 &&
451       Header->Permanent == FALSE)
452     {
453       if (Header->CloseInProcess)
454       {
455          KeBugCheck(0);
456          return STATUS_UNSUCCESSFUL;
457       }
458       Header->CloseInProcess = TRUE;
459       if (Header->ObjectType != NULL &&
460           Header->ObjectType->Delete != NULL)
461         {
462           Header->ObjectType->Delete(HEADER_TO_BODY(Header));
463         }
464       if (Header->Name.Buffer != NULL)
465         {
466           ObpRemoveEntryDirectory(Header);
467           RtlFreeUnicodeString(&Header->Name);
468         }
469       DPRINT("ObPerformRetentionChecks() = Freeing object\n");
470       ExFreePool(Header);
471     }
472   return(STATUS_SUCCESS);
473 }
474
475
476 /**********************************************************************
477  * NAME                                                 EXPORTED
478  *      ObfReferenceObject@4
479  *
480  * DESCRIPTION
481  *      Increments a given object's reference count and performs
482  *      retention checks.
483  *
484  * ARGUMENTS
485  *  ObjectBody = Body of the object.
486  *
487  * RETURN VALUE
488  *      None.
489  */
490 VOID FASTCALL
491 ObfReferenceObject(IN PVOID Object)
492 {
493   POBJECT_HEADER Header;
494
495   assert(Object);
496
497   Header = BODY_TO_HEADER(Object);
498
499   if (Header->CloseInProcess)
500   {
501       KeBugCheck(0);
502   }
503   InterlockedIncrement(&Header->RefCount);
504
505   ObpPerformRetentionChecks(Header);
506 }
507
508
509 /**********************************************************************
510  * NAME                                                 EXPORTED
511  *      ObfDereferenceObject@4
512  *
513  * DESCRIPTION
514  *      Decrements a given object's reference count and performs
515  *      retention checks.
516  *
517  * ARGUMENTS
518  *      ObjectBody = Body of the object.
519  *
520  * RETURN VALUE
521  *      None.
522  */
523 VOID FASTCALL
524 ObfDereferenceObject(IN PVOID Object)
525 {
526   POBJECT_HEADER Header;
527   extern POBJECT_TYPE PsProcessType;
528
529   assert(Object);
530
531   Header = BODY_TO_HEADER(Object);
532
533   if (Header->ObjectType == PsProcessType)
534     {
535       DPRINT("Deref p 0x%x with refcount %d type %x ",
536              Object, Header->RefCount, PsProcessType);
537       DPRINT("eip %x\n", ((PULONG)&Object)[-1]);
538     }
539   if (Header->ObjectType == PsThreadType)
540     {
541       DPRINT("Deref t 0x%x with refcount %d type %x ",
542              Object, Header->RefCount, PsThreadType);
543       DPRINT("eip %x\n", ((PULONG)&Object)[-1]);
544     }
545   
546   InterlockedDecrement(&Header->RefCount);
547   
548   ObpPerformRetentionChecks(Header);
549 }
550
551 #ifndef LIBCAPTIVE
552
553 /**********************************************************************
554  * NAME                                                 EXPORTED
555  *      ObGetObjectPointerCount@4
556  *
557  * DESCRIPTION
558  *      Retrieves the pointer(reference) count of the given object.
559  *
560  * ARGUMENTS
561  *      ObjectBody = Body of the object.
562  *
563  * RETURN VALUE
564  *      Reference count.
565  */
566 ULONG STDCALL
567 ObGetObjectPointerCount(PVOID Object)
568 {
569   POBJECT_HEADER Header;
570
571   assert(Object);
572   Header = BODY_TO_HEADER(Object);
573
574   return(Header->RefCount);
575 }
576
577
578 /**********************************************************************
579  * NAME                                                 INTERNAL
580  *      ObGetObjectHandleCount@4
581  *
582  * DESCRIPTION
583  *      Retrieves the handle count of the given object.
584  *
585  * ARGUMENTS
586  *      ObjectBody = Body of the object.
587  *
588  * RETURN VALUE
589  *      Reference count.
590  */
591 ULONG
592 ObGetObjectHandleCount(PVOID Object)
593 {
594   POBJECT_HEADER Header;
595
596   assert(Object);
597   Header = BODY_TO_HEADER(Object);
598
599   return(Header->HandleCount);
600 }
601
602 #endif /* LIBCAPTIVE */
603
604 /* EOF */