bootstrap
[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 #ifndef LIBCAPTIVE
393
394 NTSTATUS STDCALL
395 ObOpenObjectByPointer(IN POBJECT Object,
396                       IN ULONG HandleAttributes,
397                       IN PACCESS_STATE PassedAccessState,
398                       IN ACCESS_MASK DesiredAccess,
399                       IN POBJECT_TYPE ObjectType,
400                       IN KPROCESSOR_MODE AccessMode,
401                       OUT PHANDLE Handle)
402 {
403    NTSTATUS Status;
404    
405    DPRINT("ObOpenObjectByPointer()\n");
406    
407    Status = ObReferenceObjectByPointer(Object,
408                                        0,
409                                        ObjectType,
410                                        AccessMode);
411    if (!NT_SUCCESS(Status))
412      {
413         return Status;
414      }
415    
416    Status = ObCreateHandle(PsGetCurrentProcess(),
417                            Object,
418                            DesiredAccess,
419                            HandleAttributes & OBJ_INHERIT,
420                            Handle);
421    
422    ObDereferenceObject(Object);
423    
424    return STATUS_SUCCESS;
425 }
426
427 #endif /* LIBCAPTIVE */
428
429 static NTSTATUS
430 ObpPerformRetentionChecks(POBJECT_HEADER Header)
431 {
432 //  DPRINT("ObPerformRetentionChecks(Header %x), RefCount %d, HandleCount %d\n",
433 //        Header,Header->RefCount,Header->HandleCount);
434   
435   if (Header->RefCount < 0)
436     {
437       CPRINT("Object %x/%x has invalid reference count (%d)\n",
438              Header, HEADER_TO_BODY(Header), Header->RefCount);
439       KeBugCheck(0);
440     }
441   if (Header->HandleCount < 0)
442     {
443       CPRINT("Object %x/%x has invalid handle count (%d)\n",
444              Header, HEADER_TO_BODY(Header), Header->HandleCount);
445       KeBugCheck(0);
446     }
447   
448   if (Header->RefCount == 0 &&
449       Header->HandleCount == 0 &&
450       Header->Permanent == FALSE)
451     {
452       if (Header->CloseInProcess)
453       {
454          KeBugCheck(0);
455          return STATUS_UNSUCCESSFUL;
456       }
457       Header->CloseInProcess = TRUE;
458       if (Header->ObjectType != NULL &&
459           Header->ObjectType->Delete != NULL)
460         {
461           Header->ObjectType->Delete(HEADER_TO_BODY(Header));
462         }
463       if (Header->Name.Buffer != NULL)
464         {
465           ObpRemoveEntryDirectory(Header);
466           RtlFreeUnicodeString(&Header->Name);
467         }
468       DPRINT("ObPerformRetentionChecks() = Freeing object\n");
469       ExFreePool(Header);
470     }
471   return(STATUS_SUCCESS);
472 }
473
474 #ifndef LIBCAPTIVE
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 #endif /* LIBCAPTIVE */
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 #ifndef LIBCAPTIVE
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 #endif /* LIBCAPTIVE */
604
605 /* EOF */