update for HEAD-2002110701
[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 #include <internal/io.h>
21
22 #define NDEBUG
23 #include <internal/debug.h>
24
25 /* FUNCTIONS ************************************************************/
26
27 PVOID HEADER_TO_BODY(POBJECT_HEADER obj)
28 {
29    return(((void *)obj)+sizeof(OBJECT_HEADER)-sizeof(COMMON_BODY_HEADER));
30 }
31
32 POBJECT_HEADER BODY_TO_HEADER(PVOID body)
33 {
34    PCOMMON_BODY_HEADER chdr = (PCOMMON_BODY_HEADER)body;
35    return(CONTAINING_RECORD((&(chdr->Type)),OBJECT_HEADER,Type));
36 }
37
38
39 /**********************************************************************
40  * NAME                                                 PRIVATE
41  *      ObInitializeObject
42  *
43  * DESCRIPTION
44  *
45  * ARGUMENTS
46  *
47  * RETURN VALUE
48  */
49 VOID ObInitializeObject(POBJECT_HEADER ObjectHeader,
50                         PHANDLE Handle,
51                         ACCESS_MASK DesiredAccess,
52                         POBJECT_TYPE Type,
53                         POBJECT_ATTRIBUTES ObjectAttributes)
54 {
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    ULONG Attributes;
116    
117    DPRINT("ObFindObject(ObjectAttributes %x, ReturnedObject %x, "
118           "RemainingPath %x)\n",ObjectAttributes,ReturnedObject,RemainingPath);
119    DPRINT("ObjectAttributes->ObjectName %wZ\n",
120           ObjectAttributes->ObjectName);
121
122    RtlInitUnicodeString (RemainingPath, NULL);
123
124    if (ObjectAttributes->RootDirectory == NULL)
125      {
126         ObReferenceObjectByPointer(NameSpaceRoot,
127                                    DIRECTORY_TRAVERSE,
128                                    NULL,
129                                    UserMode);
130         CurrentObject = NameSpaceRoot;
131      }
132    else
133      {
134         Status = ObReferenceObjectByHandle(ObjectAttributes->RootDirectory,
135                                            DIRECTORY_TRAVERSE,
136                                            NULL,
137                                            UserMode,
138                                            &CurrentObject,
139                                            NULL);
140         if (!NT_SUCCESS(Status))
141           {
142              return(Status);
143           }
144      }
145    
146    Path = ObjectAttributes->ObjectName->Buffer;
147    
148    if (Path[0] == 0)
149      {
150         *ReturnedObject = CurrentObject;
151         return(STATUS_SUCCESS);
152      }
153    
154    if ((ObjectAttributes->RootDirectory == NULL) && (Path[0] != '\\'))
155      {
156         ObDereferenceObject(CurrentObject);
157         return(STATUS_UNSUCCESSFUL);
158      }
159    
160    if (Path)
161      {
162         RtlCreateUnicodeString (&PathString, Path);
163         current = PathString.Buffer;
164      }
165    else
166      {
167         RtlInitUnicodeString (&PathString, NULL);
168         current = NULL;
169      }
170
171    RootObject = CurrentObject;
172    Attributes = ObjectAttributes->Attributes;
173    if (ObjectType == IoSymbolicLinkType)
174      Attributes |= OBJ_OPENLINK;
175
176    while (TRUE)
177      {
178         DPRINT("current %S\n",current);
179         CurrentHeader = BODY_TO_HEADER(CurrentObject);
180
181         DPRINT("Current ObjectType %wZ\n",
182                &CurrentHeader->ObjectType->TypeName);
183
184         if (CurrentHeader->ObjectType->Parse == NULL)
185           {
186              DPRINT("Current object can't parse\n");
187              break;
188           }
189         Status = CurrentHeader->ObjectType->Parse(CurrentObject,
190                                                   &NextObject,
191                                                   &PathString,
192                                                   &current,
193                                                   Attributes);
194         if (Status == STATUS_REPARSE)
195           {
196              /* reparse the object path */
197              NextObject = RootObject;
198              current = PathString.Buffer;
199              
200              ObReferenceObjectByPointer(NextObject,
201                                         DIRECTORY_TRAVERSE,
202                                         NULL,
203                                         UserMode);
204           }
205
206         if (NextObject == NULL)
207           {
208              break;
209           }
210         ObDereferenceObject(CurrentObject);
211         CurrentObject = NextObject;
212      }
213    
214    if (current)
215       RtlCreateUnicodeString (RemainingPath, current);
216    RtlFreeUnicodeString (&PathString);
217    *ReturnedObject = CurrentObject;
218    
219    return(STATUS_SUCCESS);
220 }
221
222
223 /**********************************************************************
224  * NAME                                                 EXPORTED
225  *      ObCreateObject@36
226  *
227  * DESCRIPTION
228  *
229  * ARGUMENTS
230  *
231  * RETURN VALUE
232  */
233 NTSTATUS STDCALL
234 ObCreateObject(OUT PHANDLE Handle,
235                IN ACCESS_MASK DesiredAccess,
236                IN POBJECT_ATTRIBUTES ObjectAttributes,
237                IN POBJECT_TYPE Type,
238                OUT PVOID *Object)
239 {
240   PVOID Parent = NULL;
241   UNICODE_STRING RemainingPath;
242   POBJECT_HEADER Header;
243   POBJECT_HEADER ParentHeader = NULL;
244   NTSTATUS Status;
245   BOOLEAN ObjectAttached = FALSE;
246
247   assert_irql(APC_LEVEL);
248
249   DPRINT("ObCreateObject(Handle %x, ObjectAttributes %x, Type %x)\n",
250          Handle, ObjectAttributes, Type);
251
252   if (ObjectAttributes != NULL &&
253       ObjectAttributes->ObjectName != NULL &&
254       ObjectAttributes->ObjectName->Buffer != NULL)
255     {
256       Status = ObFindObject(ObjectAttributes,
257                             &Parent,
258                             &RemainingPath,
259                             NULL);
260       if (!NT_SUCCESS(Status))
261         {
262           DPRINT("ObFindObject() failed! (Status 0x%x)\n", Status);
263           return(Status);
264         }
265     }
266   else
267     {
268       RtlInitUnicodeString(&RemainingPath, NULL);
269     }
270
271   RtlMapGenericMask(&DesiredAccess,
272                     Type->Mapping);
273
274   Header = (POBJECT_HEADER)ExAllocatePoolWithTag(NonPagedPool,
275                                                  OBJECT_ALLOC_SIZE(Type),
276                                                  Type->Tag);
277   ObInitializeObject(Header,
278                      NULL,
279                      DesiredAccess,
280                      Type,
281                      ObjectAttributes);
282
283   if (Parent != NULL)
284     {
285       ParentHeader = BODY_TO_HEADER(Parent);
286     }
287
288   if (ParentHeader != NULL &&
289       ParentHeader->ObjectType == ObDirectoryType &&
290       RemainingPath.Buffer != NULL)
291     {
292       ObpAddEntryDirectory(Parent,
293                            Header,
294                            RemainingPath.Buffer+1);
295       ObjectAttached = TRUE;
296     }
297
298   if ((Header->ObjectType != NULL) &&
299       (Header->ObjectType->Create != NULL))
300     {
301       DPRINT("Calling %x\n", Header->ObjectType->Create);
302       Status = Header->ObjectType->Create(HEADER_TO_BODY(Header),
303                                           Parent,
304                                           RemainingPath.Buffer,
305                                           ObjectAttributes);
306       if (!NT_SUCCESS(Status))
307         {
308           if (ObjectAttached == TRUE)
309             {
310               ObpRemoveEntryDirectory(Header);
311             }
312           if (Parent)
313             {
314               ObDereferenceObject(Parent);
315             }
316           RtlFreeUnicodeString(&Header->Name);
317           RtlFreeUnicodeString(&RemainingPath);
318           ExFreePool(Header);
319           return(Status);
320         }
321     }
322   RtlFreeUnicodeString( &RemainingPath );
323
324   if (Object != NULL)
325     {
326       *Object = HEADER_TO_BODY(Header);
327     }
328
329   if (Handle != NULL)
330   {
331      ObCreateHandle(PsGetCurrentProcess(),
332                     *Object,
333                     DesiredAccess,
334                     ObjectAttributes && (ObjectAttributes->Attributes & OBJ_INHERIT) ? TRUE : FALSE,
335                     Handle);
336   }
337
338   return(STATUS_SUCCESS);
339 }
340
341
342 NTSTATUS STDCALL
343 ObReferenceObjectByPointer(IN PVOID Object,
344                            IN ACCESS_MASK DesiredAccess,
345                            IN POBJECT_TYPE ObjectType,
346                            IN KPROCESSOR_MODE AccessMode)
347 /*
348  * FUNCTION: Increments the pointer reference count for a given object
349  * ARGUMENTS:
350  *         ObjectBody = Object's body
351  *         DesiredAccess = Desired access to the object
352  *         ObjectType = Points to the object type structure
353  *         AccessMode = Type of access check to perform
354  * RETURNS: Status
355  */
356 {
357    POBJECT_HEADER Header;
358
359 //   DPRINT("ObReferenceObjectByPointer(Object %x, ObjectType %x)\n",
360 //        Object,ObjectType);
361    
362    Header = BODY_TO_HEADER(Object);
363    
364    if (ObjectType != NULL && Header->ObjectType != ObjectType)
365      {
366         DPRINT("Failed %x (type was %x %S) should be %x %S\n",
367                 Header,
368                 Header->ObjectType,
369                 Header->ObjectType->TypeName.Buffer,
370                 ObjectType,
371     ObjectType->TypeName.Buffer);
372         return(STATUS_UNSUCCESSFUL);
373      }
374    if (Header->ObjectType == PsProcessType)
375      {
376         DPRINT("Ref p 0x%x refcount %d type %x ",
377                 Object, Header->RefCount, PsProcessType);
378         DPRINT("eip %x\n", ((PULONG)&Object)[-1]);
379      }
380    if (Header->ObjectType == PsThreadType)
381      {
382         DPRINT("Deref t 0x%x with refcount %d type %x ",
383                 Object, Header->RefCount, PsThreadType);
384         DPRINT("eip %x\n", ((PULONG)&Object)[-1]);
385      }
386  
387    if (Header->CloseInProcess)
388    {
389       return(STATUS_UNSUCCESSFUL);
390    }
391
392    InterlockedIncrement(&Header->RefCount);
393    
394    return(STATUS_SUCCESS);
395 }
396
397
398 NTSTATUS STDCALL
399 ObOpenObjectByPointer(IN POBJECT Object,
400                       IN ULONG HandleAttributes,
401                       IN PACCESS_STATE PassedAccessState,
402                       IN ACCESS_MASK DesiredAccess,
403                       IN POBJECT_TYPE ObjectType,
404                       IN KPROCESSOR_MODE AccessMode,
405                       OUT PHANDLE Handle)
406 {
407    NTSTATUS Status;
408    
409    DPRINT("ObOpenObjectByPointer()\n");
410    
411    Status = ObReferenceObjectByPointer(Object,
412                                        0,
413                                        ObjectType,
414                                        AccessMode);
415    if (!NT_SUCCESS(Status))
416      {
417         return Status;
418      }
419    
420    Status = ObCreateHandle(PsGetCurrentProcess(),
421                            Object,
422                            DesiredAccess,
423                            HandleAttributes & OBJ_INHERIT,
424                            Handle);
425    
426    ObDereferenceObject(Object);
427    
428    return STATUS_SUCCESS;
429 }
430
431
432 static NTSTATUS
433 ObpPerformRetentionChecks(POBJECT_HEADER Header)
434 {
435 //  DPRINT("ObPerformRetentionChecks(Header %x), RefCount %d, HandleCount %d\n",
436 //        Header,Header->RefCount,Header->HandleCount);
437   
438   if (Header->RefCount < 0)
439     {
440       CPRINT("Object %x/%x has invalid reference count (%d)\n",
441              Header, HEADER_TO_BODY(Header), Header->RefCount);
442       KeBugCheck(0);
443     }
444   if (Header->HandleCount < 0)
445     {
446       CPRINT("Object %x/%x has invalid handle count (%d)\n",
447              Header, HEADER_TO_BODY(Header), Header->HandleCount);
448       KeBugCheck(0);
449     }
450   
451   if (Header->RefCount == 0 &&
452       Header->HandleCount == 0 &&
453       Header->Permanent == FALSE)
454     {
455       if (Header->CloseInProcess)
456       {
457          KeBugCheck(0);
458          return STATUS_UNSUCCESSFUL;
459       }
460       Header->CloseInProcess = TRUE;
461       if (Header->ObjectType != NULL &&
462           Header->ObjectType->Delete != NULL)
463         {
464           Header->ObjectType->Delete(HEADER_TO_BODY(Header));
465         }
466       if (Header->Name.Buffer != NULL)
467         {
468           ObpRemoveEntryDirectory(Header);
469           RtlFreeUnicodeString(&Header->Name);
470         }
471       DPRINT("ObPerformRetentionChecks() = Freeing object\n");
472       ExFreePool(Header);
473     }
474   return(STATUS_SUCCESS);
475 }
476
477
478 /**********************************************************************
479  * NAME                                                 EXPORTED
480  *      ObfReferenceObject@4
481  *
482  * DESCRIPTION
483  *      Increments a given object's reference count and performs
484  *      retention checks.
485  *
486  * ARGUMENTS
487  *  ObjectBody = Body of the object.
488  *
489  * RETURN VALUE
490  *      None.
491  */
492 VOID FASTCALL
493 ObfReferenceObject(IN PVOID Object)
494 {
495   POBJECT_HEADER Header;
496
497   assert(Object);
498
499   Header = BODY_TO_HEADER(Object);
500
501   if (Header->CloseInProcess)
502   {
503       KeBugCheck(0);
504   }
505   InterlockedIncrement(&Header->RefCount);
506
507   ObpPerformRetentionChecks(Header);
508 }
509
510
511 /**********************************************************************
512  * NAME                                                 EXPORTED
513  *      ObfDereferenceObject@4
514  *
515  * DESCRIPTION
516  *      Decrements a given object's reference count and performs
517  *      retention checks.
518  *
519  * ARGUMENTS
520  *      ObjectBody = Body of the object.
521  *
522  * RETURN VALUE
523  *      None.
524  */
525 VOID FASTCALL
526 ObfDereferenceObject(IN PVOID Object)
527 {
528   POBJECT_HEADER Header;
529   extern POBJECT_TYPE PsProcessType;
530
531   assert(Object);
532
533   Header = BODY_TO_HEADER(Object);
534
535   if (Header->ObjectType == PsProcessType)
536     {
537       DPRINT("Deref p 0x%x with refcount %d type %x ",
538              Object, Header->RefCount, PsProcessType);
539       DPRINT("eip %x\n", ((PULONG)&Object)[-1]);
540     }
541   if (Header->ObjectType == PsThreadType)
542     {
543       DPRINT("Deref t 0x%x with refcount %d type %x ",
544              Object, Header->RefCount, PsThreadType);
545       DPRINT("eip %x\n", ((PULONG)&Object)[-1]);
546     }
547   
548   InterlockedDecrement(&Header->RefCount);
549   
550   ObpPerformRetentionChecks(Header);
551 }
552
553
554 /**********************************************************************
555  * NAME                                                 EXPORTED
556  *      ObGetObjectPointerCount@4
557  *
558  * DESCRIPTION
559  *      Retrieves the pointer(reference) count of the given object.
560  *
561  * ARGUMENTS
562  *      ObjectBody = Body of the object.
563  *
564  * RETURN VALUE
565  *      Reference count.
566  */
567 ULONG STDCALL
568 ObGetObjectPointerCount(PVOID Object)
569 {
570   POBJECT_HEADER Header;
571
572   assert(Object);
573   Header = BODY_TO_HEADER(Object);
574
575   return(Header->RefCount);
576 }
577
578
579 /**********************************************************************
580  * NAME                                                 INTERNAL
581  *      ObGetObjectHandleCount@4
582  *
583  * DESCRIPTION
584  *      Retrieves the handle count of the given object.
585  *
586  * ARGUMENTS
587  *      ObjectBody = Body of the object.
588  *
589  * RETURN VALUE
590  *      Reference count.
591  */
592 ULONG
593 ObGetObjectHandleCount(PVOID Object)
594 {
595   POBJECT_HEADER Header;
596
597   assert(Object);
598   Header = BODY_TO_HEADER(Object);
599
600   return(Header->HandleCount);
601 }
602
603 /* EOF */