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