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