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