7ac999662cf8b21859368bf0319669dae2209e29
[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->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 */