2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ob/namespc.c
5 * PURPOSE: Manages the system namespace
6 * PROGRAMMER: David Welch (welch@mcmail.com)
11 /* INCLUDES ***************************************************************/
15 #include <ddk/ntddk.h>
16 #include <internal/ob.h>
17 #include <internal/io.h>
18 #include <internal/string.h>
21 #include <internal/debug.h>
23 /* GLOBALS ****************************************************************/
25 POBJECT_TYPE ObDirectoryType
= NULL
;
30 // DIRECTORY_OBJECT directory;
33 } namespc_root
= {{0,},};
35 /* FUNCTIONS **************************************************************/
37 NTSTATUS
NtOpenDirectoryObject(PHANDLE DirectoryHandle
,
38 ACCESS_MASK DesiredAccess
,
39 POBJECT_ATTRIBUTES ObjectAttributes
)
41 return(ZwOpenDirectoryObject(DirectoryHandle
,
46 NTSTATUS
ZwOpenDirectoryObject(PHANDLE DirectoryHandle
,
47 ACCESS_MASK DesiredAccess
,
48 POBJECT_ATTRIBUTES ObjectAttributes
)
50 * FUNCTION: Opens a namespace directory object
52 * DirectoryHandle (OUT) = Variable which receives the directory handle
53 * DesiredAccess = Desired access to the directory
54 * ObjectAttributes = Structure describing the directory
65 Status
= ObOpenObjectByName(ObjectAttributes
,&Object
,&Ignored
);
66 if (!NT_SUCCESS(Status
))
71 if (BODY_TO_HEADER(Object
)->Type
!=OBJTYP_DIRECTORY
)
73 return(STATUS_UNSUCCESSFUL
);
76 *DirectoryHandle
= ObInsertHandle(KeGetCurrentProcess(),Object
,
79 return(STATUS_SUCCESS
);
82 NTSTATUS
NtQueryDirectoryObject(IN HANDLE DirObjHandle
,
83 OUT POBJDIR_INFORMATION DirObjInformation
,
84 IN ULONG BufferLength
,
85 IN BOOLEAN GetNextIndex
,
86 IN BOOLEAN IgnoreInputIndex
,
87 IN OUT PULONG ObjectIndex
,
88 OUT PULONG DataWritten OPTIONAL
)
90 return(ZwQueryDirectoryObject(DirObjHandle
,
99 NTSTATUS
ZwQueryDirectoryObject(IN HANDLE DirObjHandle
,
100 OUT POBJDIR_INFORMATION DirObjInformation
,
101 IN ULONG BufferLength
,
102 IN BOOLEAN GetNextIndex
,
103 IN BOOLEAN IgnoreInputIndex
,
104 IN OUT PULONG ObjectIndex
,
105 OUT PULONG DataWritten OPTIONAL
)
107 * FUNCTION: Reads information from a namespace directory
109 * DirObjInformation (OUT) = Buffer to hold the data read
110 * BufferLength = Size of the buffer in bytes
111 * GetNextIndex = If TRUE then set ObjectIndex to the index of the
113 * If FALSE then set ObjectIndex to the number of
114 * objects in the directory
115 * IgnoreInputIndex = If TRUE start reading at index 0
116 * If FALSE start reading at the index specified
118 * ObjectIndex = Zero based index into the directory, interpretation
119 * depends on IgnoreInputIndex and GetNextIndex
120 * DataWritten (OUT) = Caller supplied storage for the number of bytes
125 PDIRECTORY_OBJECT dir
= NULL
;
127 PLIST_ENTRY current_entry
;
128 POBJECT_HEADER current
;
133 DPRINT("ZwQueryDirectoryObject(DirObjHandle %x)\n",DirObjHandle
);
134 DPRINT("dir %x namespc_root %x\n",dir
,HEADER_TO_BODY(&(namespc_root
.hdr
)));
136 // assert_irql(PASSIVE_LEVEL);
138 Status
= ObReferenceObjectByHandle(DirObjHandle
,
144 if (Status
!= STATUS_SUCCESS
)
149 EntriesToRead
= BufferLength
/ sizeof(OBJDIR_INFORMATION
);
152 DPRINT("EntriesToRead %d\n",EntriesToRead
);
154 current_entry
= dir
->head
.Flink
;
157 * Optionally, skip over some entries at the start of the directory
159 if (!IgnoreInputIndex
)
163 EntriesToSkip
= *ObjectIndex
;
164 while ( i
<EntriesToSkip
&& current_entry
!=NULL
)
166 current_entry
= current_entry
->Flink
;
170 DPRINT("DirObjInformation %x\n",DirObjInformation
);
173 * Read the maximum entries possible into the buffer
175 while ( i
<EntriesToRead
&& current_entry
!=(&(dir
->head
)))
177 current
= CONTAINING_RECORD(current_entry
,OBJECT_HEADER
,Entry
);
178 DPRINT("Scanning %w\n",current
->Name
.Buffer
);
179 DirObjInformation
[i
].ObjectName
.Buffer
=
180 ExAllocatePool(NonPagedPool
,(current
->Name
.Length
+1)*2);
181 DirObjInformation
[i
].ObjectName
.Length
= current
->Name
.Length
;
182 DirObjInformation
[i
].ObjectName
.MaximumLength
= current
->Name
.Length
;
183 DPRINT("DirObjInformation[i].ObjectName.Buffer %x\n",
184 DirObjInformation
[i
].ObjectName
.Buffer
);
185 RtlCopyUnicodeString(&DirObjInformation
[i
].ObjectName
,
188 current_entry
= current_entry
->Flink
;
189 (*DataWritten
) = (*DataWritten
) + sizeof(OBJDIR_INFORMATION
);
195 * Optionally, count the number of entries in the directory
203 while ( current_entry
!=(&(dir
->head
)) )
205 current_entry
=current_entry
->Flink
;
210 return(STATUS_SUCCESS
);
214 NTSTATUS
ObReferenceObjectByName(PUNICODE_STRING ObjectPath
,
216 PACCESS_STATE PassedAccessState
,
217 ACCESS_MASK DesiredAccess
,
218 POBJECT_TYPE ObjectType
,
219 KPROCESSOR_MODE AccessMode
,
226 NTSTATUS
ObOpenObjectByName(POBJECT_ATTRIBUTES ObjectAttributes
,
227 PVOID
* Object
, PWSTR
* UnparsedSection
)
231 DPRINT("ObOpenObjectByName(ObjectAttributes %x, Object %x)\n",
232 ObjectAttributes
,Object
);
233 DPRINT("ObjectAttributes = {ObjectName %x ObjectName->Buffer %w}\n",
234 ObjectAttributes
->ObjectName
,ObjectAttributes
->ObjectName
->Buffer
);
235 DPRINT("ObjectAttributes->ObjectName->Length %d\n",
236 ObjectAttributes
->ObjectName
->Length
);
239 Status
= ObLookupObject(ObjectAttributes
->RootDirectory
,
240 ObjectAttributes
->ObjectName
->Buffer
,
243 ObjectAttributes
->Attributes
);
244 DPRINT("*Object %x\n",*Object
);
245 DPRINT("ObjectAttributes->ObjectName->Length %d\n",
246 ObjectAttributes
->ObjectName
->Length
);
252 * FUNCTION: Initialize the object manager namespace
255 ANSI_STRING AnsiString
;
257 ObDirectoryType
= ExAllocatePool(NonPagedPool
,sizeof(OBJECT_TYPE
));
259 ObDirectoryType
->TotalObjects
= 0;
260 ObDirectoryType
->TotalHandles
= 0;
261 ObDirectoryType
->MaxObjects
= ULONG_MAX
;
262 ObDirectoryType
->MaxHandles
= ULONG_MAX
;
263 ObDirectoryType
->PagedPoolCharge
= 0;
264 ObDirectoryType
->NonpagedPoolCharge
= sizeof(DIRECTORY_OBJECT
);
265 ObDirectoryType
->Dump
= NULL
;
266 ObDirectoryType
->Open
= NULL
;
267 ObDirectoryType
->Close
= NULL
;
268 ObDirectoryType
->Delete
= NULL
;
269 ObDirectoryType
->Parse
= NULL
;
270 ObDirectoryType
->Security
= NULL
;
271 ObDirectoryType
->QueryName
= NULL
;
272 ObDirectoryType
->OkayToClose
= NULL
;
274 RtlInitAnsiString(&AnsiString
,"Directory");
275 RtlAnsiStringToUnicodeString(&ObDirectoryType
->TypeName
,
278 ObInitializeObjectHeader(ObDirectoryType
,NULL
,&namespc_root
.hdr
);
279 InitializeListHead(&namespc_root
.head
);
282 NTSTATUS
NtCreateDirectoryObject(PHANDLE DirectoryHandle
,
283 ACCESS_MASK DesiredAccess
,
284 POBJECT_ATTRIBUTES ObjectAttributes
)
286 return(ZwCreateDirectoryObject(DirectoryHandle
,
291 NTSTATUS
ZwCreateDirectoryObject(PHANDLE DirectoryHandle
,
292 ACCESS_MASK DesiredAccess
,
293 POBJECT_ATTRIBUTES ObjectAttributes
)
295 * FUNCTION: Creates or opens a directory object (a container for other
298 * DirectoryHandle (OUT) = Caller supplied storage for the handle
300 * DesiredAccess = Access desired to the directory
301 * ObjectAttributes = Object attributes initialized with
302 * InitializeObjectAttributes
306 PDIRECTORY_OBJECT dir
;
308 dir
= ObGenericCreateObject(DirectoryHandle
,DesiredAccess
,ObjectAttributes
,
312 * Initialize the object body
314 InitializeListHead(&dir
->head
);
315 KeInitializeSpinLock(&(dir
->Lock
));
317 return(STATUS_SUCCESS
);
320 VOID
InitializeObjectAttributes(POBJECT_ATTRIBUTES InitializedAttributes
,
321 PUNICODE_STRING ObjectName
,
323 HANDLE RootDirectory
,
324 PSECURITY_DESCRIPTOR SecurityDescriptor
)
326 * FUNCTION: Sets up a parameter of type OBJECT_ATTRIBUTES for a
327 * subsequent call to ZwCreateXXX or ZwOpenXXX
329 * InitializedAttributes (OUT) = Caller supplied storage for the
331 * ObjectName = Full path name for object
332 * Attributes = Attributes for the object
333 * RootDirectory = Where the object should be placed or NULL
334 * SecurityDescriptor = Ignored
337 * Either ObjectName is a fully qualified pathname or a path relative
341 DPRINT("InitializeObjectAttributes(InitializedAttributes %x "
342 "ObjectName %x Attributes %x RootDirectory %x)\n",
343 InitializedAttributes
,ObjectName
,Attributes
,RootDirectory
);
344 InitializedAttributes
->Length
=sizeof(OBJECT_ATTRIBUTES
);
345 InitializedAttributes
->RootDirectory
=RootDirectory
;
346 InitializedAttributes
->ObjectName
=ObjectName
;
347 InitializedAttributes
->Attributes
=Attributes
;
348 InitializedAttributes
->SecurityDescriptor
=SecurityDescriptor
;
349 InitializedAttributes
->SecurityQualityOfService
=NULL
;
352 static PVOID
ObDirLookup(PDIRECTORY_OBJECT dir
, PWSTR name
,
355 * FUNCTION: Looks up an entry within a namespace directory
357 * dir = Directory to lookup in
358 * name = Entry name to find
359 * RETURNS: A pointer to the object body if found
363 LIST_ENTRY
* current
= dir
->head
.Flink
;
364 POBJECT_HEADER current_obj
;
366 DPRINT("ObDirLookup(dir %x, name %w)\n",dir
,name
);
372 if (name
[0]=='.'&&name
[1]==0)
376 if (name
[0]=='.'&&name
[1]=='.'&&name
[2]==0)
378 return(BODY_TO_HEADER(dir
)->Parent
);
380 while (current
!=(&(dir
->head
)))
382 current_obj
= CONTAINING_RECORD(current
,OBJECT_HEADER
,Entry
);
383 DPRINT("Scanning %w\n",current_obj
->Name
.Buffer
);
384 if (Attributes
& OBJ_CASE_INSENSITIVE
)
386 if (wcsicmp(current_obj
->Name
.Buffer
, name
)==0)
388 DPRINT("Found it %x\n",HEADER_TO_BODY(current_obj
));
389 return(HEADER_TO_BODY(current_obj
));
394 if ( wcscmp(current_obj
->Name
.Buffer
, name
)==0)
396 DPRINT("Found it %x\n",HEADER_TO_BODY(current_obj
));
397 return(HEADER_TO_BODY(current_obj
));
400 current
= current
->Flink
;
402 DPRINT("%s() = NULL\n",__FUNCTION__
);
406 VOID
ObRemoveEntry(POBJECT_HEADER Header
)
410 DPRINT("ObRemoveEntry(Header %x)\n",Header
);
412 KeAcquireSpinLock(&(Header
->Parent
->Lock
),&oldlvl
);
413 RemoveEntryList(&(Header
->Entry
));
414 KeReleaseSpinLock(&(Header
->Parent
->Lock
),oldlvl
);
417 VOID
ObCreateEntry(PDIRECTORY_OBJECT parent
,POBJECT_HEADER Object
)
419 * FUNCTION: Add an entry to a namespace directory
421 * parent = directory to add in
422 * name = Name to give the entry
423 * Object = Header of the object to add the entry for
426 DPRINT("ObjCreateEntry(%x,%x,%x,%w)\n",parent
,Object
,Object
->Name
.Buffer
,
427 Object
->Name
.Buffer
);
430 * Insert ourselves in our parents list
432 InsertTailList(&parent
->head
,&Object
->Entry
);
436 ObLookupObject(HANDLE rootdir
,
439 PWSTR
* UnparsedSection
,
442 * FUNCTION: Lookup an object within the system namespc
444 * root = Directory to start lookup from
445 * _string = Pathname to lookup
446 * RETURNS: On success a pointer to the object body
452 PDIRECTORY_OBJECT current_dir
= NULL
;
455 DPRINT("ObLookupObject(rootdir %x, string %x, string %w, Object %x, "
456 "UnparsedSection %x)\n",rootdir
,string
,string
,Object
,
458 *UnparsedSection
= NULL
;
463 current_dir
= HEADER_TO_BODY(&(namespc_root
.hdr
));
467 ObReferenceObjectByHandle(rootdir
,
471 (PVOID
*)¤t_dir
,
480 *Object
= current_dir
;
481 return STATUS_SUCCESS
;
484 if (string
[0] != '\\')
486 DbgPrint("Non absolute pathname passed\n");
487 return STATUS_UNSUCCESSFUL
;
493 while (next
!= NULL
&&
494 BODY_TO_HEADER(current_dir
)->ObjectType
== ObDirectoryType
)
498 next
= wcschr(next
+ 1,'\\');
504 DPRINT("current %w current[5] %x next %x ", current
, current
[5], next
);
507 DPRINT("(next+1) %w", next
+ 1);
511 current_dir
= (PDIRECTORY_OBJECT
)ObDirLookup(current_dir
,
514 if (current_dir
== NULL
)
516 DbgPrint("Path component %w not found\n", current
);
517 return STATUS_UNSUCCESSFUL
;
520 if (BODY_TO_HEADER(current_dir
)->ObjectType
== IoSymbolicLinkType
)
522 current_dir
= IoOpenSymlink(current_dir
);
526 DPRINT("next %x\n",next
);
527 DPRINT("current %x current %w\n",current
,current
);
530 if (current_dir
== NULL
)
532 Status
= STATUS_UNSUCCESSFUL
;
536 Status
= STATUS_SUCCESS
;
543 *UnparsedSection
= next
;
544 if (BODY_TO_HEADER(current_dir
)->ObjectType
== IoDeviceType
)
546 Status
= STATUS_FS_QUERY_REQUIRED
;
548 else if (BODY_TO_HEADER(current_dir
)->ObjectType
->Parse
!= NULL
)
550 current_dir
= BODY_TO_HEADER(current_dir
)->ObjectType
->
553 Status
= (current_dir
!= NULL
) ? STATUS_SUCCESS
: STATUS_UNSUCCESSFUL
;
557 Status
= STATUS_UNSUCCESSFUL
;
561 *Object
= current_dir
;
562 DPRINT("current_dir %x\n", current_dir
);