update for HEAD-2003091401
[reactos.git] / ntoskrnl / ob / namespc.c
1 /* $Id$
2  *
3  * COPYRIGHT:      See COPYING in the top level directory
4  * PROJECT:        ReactOS kernel
5  * FILE:           ntoskrnl/ob/namespc.c
6  * PURPOSE:        Manages the system namespace
7  * PROGRAMMER:     David Welch (welch@mcmail.com)
8  * UPDATE HISTORY:
9  *                 22/05/98: Created
10  */
11
12 /* INCLUDES ***************************************************************/
13
14 #include <limits.h>
15 #define NTOS_MODE_KERNEL
16 #include <ntos.h>
17 #include <internal/ob.h>
18 #include <internal/io.h>
19 #include <internal/pool.h>
20
21 #define NDEBUG
22 #include <internal/debug.h>
23
24
25 /* GLOBALS ****************************************************************/
26
27 POBJECT_TYPE ObDirectoryType = NULL;
28 POBJECT_TYPE ObTypeObjectType = NULL;
29
30 PDIRECTORY_OBJECT NameSpaceRoot = NULL;
31
32 static GENERIC_MAPPING ObpDirectoryMapping = {
33         STANDARD_RIGHTS_READ|DIRECTORY_QUERY|DIRECTORY_TRAVERSE,
34         STANDARD_RIGHTS_WRITE|DIRECTORY_CREATE_OBJECT|DIRECTORY_CREATE_SUBDIRECTORY,
35         STANDARD_RIGHTS_EXECUTE|DIRECTORY_QUERY|DIRECTORY_TRAVERSE,
36         DIRECTORY_ALL_ACCESS};
37
38 static GENERIC_MAPPING ObpTypeMapping = {
39         STANDARD_RIGHTS_READ,
40         STANDARD_RIGHTS_WRITE,
41         STANDARD_RIGHTS_EXECUTE,
42         0x000F0001};
43
44 /* FUNCTIONS **************************************************************/
45
46 /*
47  * @implemented
48  */
49 NTSTATUS STDCALL
50 ObReferenceObjectByName(PUNICODE_STRING ObjectPath,
51                         ULONG Attributes,
52                         PACCESS_STATE PassedAccessState,
53                         ACCESS_MASK DesiredAccess,
54                         POBJECT_TYPE ObjectType,
55                         KPROCESSOR_MODE AccessMode,
56                         PVOID ParseContext,
57                         PVOID* ObjectPtr)
58 {
59    PVOID Object = NULL;
60    UNICODE_STRING RemainingPath;
61    OBJECT_ATTRIBUTES ObjectAttributes;
62    NTSTATUS Status;
63
64    InitializeObjectAttributes(&ObjectAttributes,
65                               ObjectPath,
66                               Attributes,
67                               NULL,
68                               NULL);
69    Status = ObFindObject(&ObjectAttributes,
70                          &Object,
71                          &RemainingPath,
72                          ObjectType);
73    if (!NT_SUCCESS(Status))
74      {
75         return(Status);
76      }
77 CHECKPOINT;
78 DPRINT("RemainingPath.Buffer '%S' Object %p\n", RemainingPath.Buffer, Object);
79
80    if (RemainingPath.Buffer != NULL || Object == NULL)
81      {
82 CHECKPOINT;
83 DPRINT("Object %p\n", Object);
84         *ObjectPtr = NULL;
85         RtlFreeUnicodeString (&RemainingPath);
86         return(STATUS_UNSUCCESSFUL);
87      }
88    *ObjectPtr = Object;
89    RtlFreeUnicodeString (&RemainingPath);
90    return(STATUS_SUCCESS);
91 }
92
93
94 /**********************************************************************
95  * NAME                                                 EXPORTED
96  *      ObOpenObjectByName
97  *      
98  * DESCRIPTION
99  *      Obtain a handle to an existing object.
100  *      
101  * ARGUMENTS
102  *      ObjectAttributes
103  *              ...
104  *      ObjectType
105  *              ...
106  *      ParseContext
107  *              ...
108  *      AccessMode
109  *              ...
110  *      DesiredAccess
111  *              ...
112  *      PassedAccessState
113  *              ...
114  *      Handle
115  *              Handle to close.
116  *
117  * RETURN VALUE
118  *      Status.
119  *
120  * @implemented
121  */
122 NTSTATUS STDCALL
123 ObOpenObjectByName(IN POBJECT_ATTRIBUTES ObjectAttributes,
124                    IN POBJECT_TYPE ObjectType,
125                    IN OUT PVOID ParseContext,
126                    IN KPROCESSOR_MODE AccessMode,
127                    IN ACCESS_MASK DesiredAccess,
128                    IN PACCESS_STATE PassedAccessState,
129                    OUT PHANDLE Handle)
130 {
131    UNICODE_STRING RemainingPath;
132    PVOID Object = NULL;
133    NTSTATUS Status;
134
135    DPRINT("ObOpenObjectByName(...)\n");
136
137    Status = ObFindObject(ObjectAttributes,
138                          &Object,
139                          &RemainingPath,
140                          ObjectType);
141    if (!NT_SUCCESS(Status))
142      {
143         DPRINT("ObFindObject() failed (Status %lx)\n", Status);
144         return Status;
145      }
146
147    if (RemainingPath.Buffer != NULL ||
148        Object == NULL)
149      {
150         RtlFreeUnicodeString(&RemainingPath);
151         return STATUS_UNSUCCESSFUL;
152      }
153
154    Status = ObCreateHandle(PsGetCurrentProcess(),
155                            Object,
156                            DesiredAccess,
157                            FALSE,
158                            Handle);
159
160    ObDereferenceObject(Object);
161    RtlFreeUnicodeString(&RemainingPath);
162
163    return Status;
164 }
165
166
167 VOID
168 ObpAddEntryDirectory(PDIRECTORY_OBJECT Parent,
169                      POBJECT_HEADER Header,
170                      PWSTR Name)
171 /*
172  * FUNCTION: Add an entry to a namespace directory
173  * ARGUMENTS:
174  *         Parent = directory to add in
175  *         Header = Header of the object to add the entry for
176  *         Name = Name to give the entry
177  */
178 {
179   KIRQL oldlvl;
180
181   RtlCreateUnicodeString(&Header->Name, Name);
182   Header->Parent = Parent;
183
184   KeAcquireSpinLock(&Parent->Lock, &oldlvl);
185   InsertTailList(&Parent->head, &Header->Entry);
186   KeReleaseSpinLock(&Parent->Lock, oldlvl);
187 }
188
189
190 VOID
191 ObpRemoveEntryDirectory(POBJECT_HEADER Header)
192 /*
193  * FUNCTION: Remove an entry from a namespace directory
194  * ARGUMENTS:
195  *         Header = Header of the object to remove
196  */
197 {
198   KIRQL oldlvl;
199
200   DPRINT("ObpRemoveEntryDirectory(Header %x)\n",Header);
201
202   KeAcquireSpinLock(&(Header->Parent->Lock),&oldlvl);
203   RemoveEntryList(&(Header->Entry));
204   KeReleaseSpinLock(&(Header->Parent->Lock),oldlvl);
205 }
206
207
208 PVOID
209 ObpFindEntryDirectory(PDIRECTORY_OBJECT DirectoryObject,
210                       PWSTR Name,
211                       ULONG Attributes)
212 {
213    PLIST_ENTRY current = DirectoryObject->head.Flink;
214    POBJECT_HEADER current_obj;
215
216    DPRINT("ObFindEntryDirectory(dir %x, name %S)\n",DirectoryObject, Name);
217    
218    if (Name[0]==0)
219      {
220         return(DirectoryObject);
221      }
222    if (Name[0]=='.' && Name[1]==0)
223      {
224         return(DirectoryObject);
225      }
226    if (Name[0]=='.' && Name[1]=='.' && Name[2]==0)
227      {
228         return(BODY_TO_HEADER(DirectoryObject)->Parent);
229      }
230    while (current!=(&(DirectoryObject->head)))
231      {
232         current_obj = CONTAINING_RECORD(current,OBJECT_HEADER,Entry);
233         DPRINT("  Scanning: %S for: %S\n",current_obj->Name.Buffer, Name);
234         if (Attributes & OBJ_CASE_INSENSITIVE)
235           {
236              if (_wcsicmp(current_obj->Name.Buffer, Name)==0)
237                {
238                   DPRINT("Found it %x\n",HEADER_TO_BODY(current_obj));
239                   return(HEADER_TO_BODY(current_obj));
240                }
241           }
242         else
243           {
244              if ( wcscmp(current_obj->Name.Buffer, Name)==0)
245                {
246                   DPRINT("Found it %x\n",HEADER_TO_BODY(current_obj));
247                   return(HEADER_TO_BODY(current_obj));
248                }
249           }
250         current = current->Flink;
251      }
252    DPRINT("    Not Found: %s() = NULL\n",__FUNCTION__);
253    return(NULL);
254 }
255
256
257 NTSTATUS STDCALL
258 ObpParseDirectory(PVOID Object,
259                   PVOID * NextObject,
260                   PUNICODE_STRING FullPath,
261                   PWSTR * Path,
262                   ULONG Attributes)
263 {
264   PWSTR Start;
265   PWSTR End;
266   PVOID FoundObject;
267
268   DPRINT("ObpParseDirectory(Object %x, Path %x, *Path %S)\n",
269          Object,Path,*Path);
270
271   *NextObject = NULL;
272
273   if ((*Path) == NULL)
274     {
275       return STATUS_UNSUCCESSFUL;
276     }
277
278   Start = *Path;
279   if (*Start == L'\\')
280     Start++;
281
282   End = wcschr(Start, L'\\');
283   if (End != NULL)
284     {
285       *End = 0;
286     }
287
288   FoundObject = ObpFindEntryDirectory(Object, Start, Attributes);
289   if (FoundObject == NULL)
290     {
291       if (End != NULL)
292         {
293           *End = L'\\';
294         }
295       return STATUS_UNSUCCESSFUL;
296     }
297
298   ObReferenceObjectByPointer(FoundObject,
299                              STANDARD_RIGHTS_REQUIRED,
300                              NULL,
301                              UserMode);
302
303   if (End != NULL)
304     {
305       *End = L'\\';
306       *Path = End;
307     }
308   else
309     {
310       *Path = NULL;
311     }
312
313   *NextObject = FoundObject;
314
315   return STATUS_SUCCESS;
316 }
317
318
319 NTSTATUS STDCALL
320 ObpCreateDirectory(PVOID ObjectBody,
321                    PVOID Parent,
322                    PWSTR RemainingPath,
323                    POBJECT_ATTRIBUTES ObjectAttributes)
324 {
325   PDIRECTORY_OBJECT DirectoryObject = (PDIRECTORY_OBJECT)ObjectBody;
326
327   DPRINT("ObpCreateDirectory(ObjectBody %x, Parent %x, RemainingPath %S)\n",
328          ObjectBody, Parent, RemainingPath);
329
330   if (RemainingPath != NULL && wcschr(RemainingPath+1, '\\') != NULL)
331     {
332       return(STATUS_UNSUCCESSFUL);
333     }
334
335   InitializeListHead(&DirectoryObject->head);
336   KeInitializeSpinLock(&DirectoryObject->Lock);
337
338   return(STATUS_SUCCESS);
339 }
340
341
342 VOID
343 ObInit(VOID)
344 /*
345  * FUNCTION: Initialize the object manager namespace
346  */
347 {
348   OBJECT_ATTRIBUTES ObjectAttributes;
349   UNICODE_STRING Name;
350
351   /* create 'directory' object type */
352   ObDirectoryType = ExAllocatePool(NonPagedPool,sizeof(OBJECT_TYPE));
353   
354   ObDirectoryType->Tag = TAG('D', 'I', 'R', 'T');
355   ObDirectoryType->TotalObjects = 0;
356   ObDirectoryType->TotalHandles = 0;
357   ObDirectoryType->MaxObjects = ULONG_MAX;
358   ObDirectoryType->MaxHandles = ULONG_MAX;
359   ObDirectoryType->PagedPoolCharge = 0;
360   ObDirectoryType->NonpagedPoolCharge = sizeof(DIRECTORY_OBJECT);
361   ObDirectoryType->Mapping = &ObpDirectoryMapping;
362   ObDirectoryType->Dump = NULL;
363   ObDirectoryType->Open = NULL;
364   ObDirectoryType->Close = NULL;
365   ObDirectoryType->Delete = NULL;
366   ObDirectoryType->Parse = ObpParseDirectory;
367   ObDirectoryType->Security = NULL;
368   ObDirectoryType->QueryName = NULL;
369   ObDirectoryType->OkayToClose = NULL;
370   ObDirectoryType->Create = ObpCreateDirectory;
371   ObDirectoryType->DuplicationNotify = NULL;
372   
373   RtlInitUnicodeStringFromLiteral(&ObDirectoryType->TypeName,
374                        L"Directory");
375
376   /* create 'type' object type*/
377   ObTypeObjectType = ExAllocatePool(NonPagedPool,sizeof(OBJECT_TYPE));
378   
379   ObTypeObjectType->Tag = TAG('T', 'y', 'p', 'T');
380   ObTypeObjectType->TotalObjects = 0;
381   ObTypeObjectType->TotalHandles = 0;
382   ObTypeObjectType->MaxObjects = ULONG_MAX;
383   ObTypeObjectType->MaxHandles = ULONG_MAX;
384   ObTypeObjectType->PagedPoolCharge = 0;
385   ObTypeObjectType->NonpagedPoolCharge = sizeof(TYPE_OBJECT);
386   ObTypeObjectType->Mapping = &ObpTypeMapping;
387   ObTypeObjectType->Dump = NULL;
388   ObTypeObjectType->Open = NULL;
389   ObTypeObjectType->Close = NULL;
390   ObTypeObjectType->Delete = NULL;
391   ObTypeObjectType->Parse = NULL;
392   ObTypeObjectType->Security = NULL;
393   ObTypeObjectType->QueryName = NULL;
394   ObTypeObjectType->OkayToClose = NULL;
395   ObTypeObjectType->Create = NULL;
396   ObTypeObjectType->DuplicationNotify = NULL;
397   
398   RtlInitUnicodeStringFromLiteral(&ObTypeObjectType->TypeName,
399                        L"ObjectType");
400
401   /* create root directory */
402   ObRosCreateObject(NULL,
403                  STANDARD_RIGHTS_REQUIRED,
404                  NULL,
405                  ObDirectoryType,
406                  (PVOID*)&NameSpaceRoot);
407
408   /* create '\ObjectTypes' directory */
409   RtlInitUnicodeStringFromLiteral(&Name,
410                        L"\\ObjectTypes");
411   InitializeObjectAttributes(&ObjectAttributes,
412                              &Name,
413                              OBJ_PERMANENT,
414                              NULL,
415                              NULL);
416   ObRosCreateObject(NULL,
417                  STANDARD_RIGHTS_REQUIRED,
418                  &ObjectAttributes,
419                  ObDirectoryType,
420                  NULL);
421
422   ObpCreateTypeObject(ObDirectoryType);
423   ObpCreateTypeObject(ObTypeObjectType);
424
425   /* Create 'symbolic link' object type */
426   ObInitSymbolicLinkImplementation();
427 }
428
429
430 NTSTATUS
431 ObpCreateTypeObject(POBJECT_TYPE ObjectType)
432 {
433   OBJECT_ATTRIBUTES ObjectAttributes;
434   WCHAR NameString[120];
435   PTYPE_OBJECT TypeObject = NULL;
436   UNICODE_STRING Name;
437   NTSTATUS Status;
438
439   DPRINT("ObpCreateTypeObject(ObjectType: %wZ)\n", &ObjectType->TypeName);
440   wcscpy(NameString, L"\\ObjectTypes\\");
441   wcscat(NameString, ObjectType->TypeName.Buffer);
442   RtlInitUnicodeString(&Name,
443                        NameString);
444
445   InitializeObjectAttributes(&ObjectAttributes,
446                              &Name,
447                              OBJ_PERMANENT,
448                              NULL,
449                              NULL);
450   Status = ObRosCreateObject(NULL,
451                           STANDARD_RIGHTS_REQUIRED,
452                           &ObjectAttributes,
453                           ObTypeObjectType,
454                           (PVOID*)&TypeObject);
455   if (NT_SUCCESS(Status))
456     {
457       TypeObject->ObjectType = ObjectType;
458     }
459
460   return(STATUS_SUCCESS);
461 }
462
463 /* EOF */