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
);
435 NTSTATUS
ObLookupObject(HANDLE rootdir
, PWSTR string
, PVOID
* Object
,
436 PWSTR
* UnparsedSection
, ULONG Attributes
)
438 * FUNCTION: Lookup an object within the system namespc
440 * root = Directory to start lookup from
441 * _string = Pathname to lookup
442 * RETURNS: On success a pointer to the object body
448 PDIRECTORY_OBJECT current_dir
= NULL
;
451 DPRINT("ObLookupObject(rootdir %x, string %x, string %w, Object %x, "
452 "UnparsedSection %x)\n",rootdir
,string
,string
,Object
,
456 *UnparsedSection
= NULL
;
461 current_dir
= HEADER_TO_BODY(&(namespc_root
.hdr
));
465 ObReferenceObjectByHandle(rootdir
,DIRECTORY_TRAVERSE
,NULL
,
466 UserMode
,(PVOID
*)¤t_dir
,NULL
);
475 return(STATUS_SUCCESS
);
480 DbgPrint("(%s:%d) Non absolute pathname passed to %s\n",__FILE__
,
481 __LINE__
,__FUNCTION__
);
482 return(STATUS_UNSUCCESSFUL
);
489 BODY_TO_HEADER(current_dir
)->ObjectType
==ObDirectoryType
)
493 next
= wcschr(next
+1,'\\');
499 DPRINT("current %w current[5] %x next %x ",current
,current
[5],next
);
502 DPRINT("(next+1) %w",next
+1);
506 current_dir
=(PDIRECTORY_OBJECT
)ObDirLookup(current_dir
,current
,
508 if (current_dir
==NULL
)
510 DbgPrint("(%s:%d) Path component %w not found\n",__FILE__
,
512 return(STATUS_UNSUCCESSFUL
);
515 if (BODY_TO_HEADER(current_dir
)->ObjectType
==IoSymbolicLinkType
)
517 current_dir
= IoOpenSymlink(current_dir
);
521 DPRINT("next %x\n",next
);
522 DPRINT("current %x current %w\n",current
,current
);
525 if (current_dir
==NULL
)
527 Status
= STATUS_UNSUCCESSFUL
;
531 Status
= STATUS_SUCCESS
;
538 *UnparsedSection
= next
;
539 if (BODY_TO_HEADER(current_dir
)->ObjectType
== IoDeviceType
)
541 Status
= STATUS_FS_QUERY_REQUIRED
;
545 Status
= STATUS_UNSUCCESSFUL
;
549 *Object
= current_dir
;