3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ob/dirobj.c
6 * PURPOSE: Interface functions to directory object
8 * PROGRAMMERS: David Welch (welch@mcmail.com)
11 /* INCLUDES ***************************************************************/
15 #include <internal/debug.h>
18 /* FUNCTIONS **************************************************************/
21 /**********************************************************************
23 * NtOpenDirectoryObject
26 * Opens a namespace directory object.
29 * DirectoryHandle (OUT)
30 * Variable which receives the directory handle.
33 * Desired access to the directory.
36 * Structure describing the directory.
45 NtOpenDirectoryObject (OUT PHANDLE DirectoryHandle
,
46 IN ACCESS_MASK DesiredAccess
,
47 IN POBJECT_ATTRIBUTES ObjectAttributes
)
50 KPROCESSOR_MODE PreviousMode
;
51 NTSTATUS Status
= STATUS_SUCCESS
;
55 PreviousMode
= ExGetPreviousMode();
57 if(PreviousMode
!= KernelMode
)
61 ProbeForWrite(DirectoryHandle
,
67 Status
= _SEH_GetExceptionCode();
71 if(!NT_SUCCESS(Status
))
73 DPRINT1("NtOpenDirectoryObject failed, Status: 0x%x\n", Status
);
78 Status
= ObOpenObjectByName(ObjectAttributes
,
85 if(NT_SUCCESS(Status
))
89 *DirectoryHandle
= hDirectory
;
93 Status
= _SEH_GetExceptionCode();
102 /**********************************************************************
104 * NtQueryDirectoryObject
107 * Reads information from a directory in the system namespace.
111 * Handle, obtained with NtOpenDirectoryObject(), which
112 * must grant DIRECTORY_QUERY access to the directory
116 * Buffer to hold the data read.
119 * Size of the buffer in bytes.
122 * When TRUE, only 1 entry is written in DirObjInformation;
123 * otherwise as many as will fit in the buffer.
126 * If TRUE start reading at index 0.
127 * If FALSE start reading at the index specified
128 * by object index *ObjectIndex.
131 * Zero based index into the directory, interpretation
132 * depends on RestartScan.
135 * Caller supplied storage for the number of bytes
139 * STATUS_SUCCESS - At least one (possibly more, depending on
140 * parameters and buffer size) dir entry is
142 * STATUS_NO_MORE_ENTRIES - Directory is exhausted
143 * STATUS_BUFFER_TOO_SMALL - There isn't enough room in the
144 * buffer to return even 1 entry.
145 * ReturnLength will hold the required
146 * buffer size to return all remaining
148 * Other - Status code
152 * Although you can iterate over the directory by calling this
153 * function multiple times, the directory is unlocked between
154 * calls. This means that another thread can change the directory
155 * and so iterating doesn't guarantee a consistent picture of the
156 * directory. Best thing is to retrieve all directory entries in
160 NtQueryDirectoryObject (IN HANDLE DirectoryHandle
,
162 IN ULONG BufferLength
,
163 IN BOOLEAN ReturnSingleEntry
,
164 IN BOOLEAN RestartScan
,
165 IN OUT PULONG Context
,
166 OUT PULONG ReturnLength OPTIONAL
)
168 PDIRECTORY_OBJECT Directory
;
169 KPROCESSOR_MODE PreviousMode
;
170 ULONG SkipEntries
= 0;
172 NTSTATUS Status
= STATUS_SUCCESS
;
176 PreviousMode
= ExGetPreviousMode();
178 if(PreviousMode
!= KernelMode
)
182 /* a test showed that the Buffer pointer just has to be 16 bit aligned,
183 propably due to the fact that most information that needs to be copied
184 is unicode strings */
185 ProbeForWrite(Buffer
,
188 ProbeForWrite(Context
,
193 SkipEntries
= *Context
;
195 if(ReturnLength
!= NULL
)
197 ProbeForWrite(ReturnLength
,
204 Status
= _SEH_GetExceptionCode();
208 if(!NT_SUCCESS(Status
))
210 DPRINT1("NtQueryDirectoryObject failed, Status: 0x%x\n", Status
);
214 else if(!RestartScan
)
216 SkipEntries
= *Context
;
219 Status
= ObReferenceObjectByHandle(DirectoryHandle
,
225 if(NT_SUCCESS(Status
))
227 PVOID TemporaryBuffer
= ExAllocatePool(PagedPool
,
229 if(TemporaryBuffer
!= NULL
)
231 POBJECT_HEADER EntryHeader
;
232 PLIST_ENTRY ListEntry
;
234 ULONG RequiredSize
= 0;
235 ULONG nDirectories
= 0;
236 POBJECT_DIRECTORY_INFORMATION DirInfo
= (POBJECT_DIRECTORY_INFORMATION
)TemporaryBuffer
;
238 Status
= STATUS_NO_MORE_ENTRIES
;
240 KeAcquireSpinLock(&Directory
->Lock
, &OldLevel
);
242 for(ListEntry
= Directory
->head
.Flink
;
243 ListEntry
!= &Directory
->head
;
244 ListEntry
= ListEntry
->Flink
)
249 PUNICODE_STRING Name
, Type
;
252 EntryHeader
= CONTAINING_RECORD(ListEntry
, OBJECT_HEADER
, Entry
);
254 /* calculate the size of the required buffer space for this entry */
255 Name
= (EntryHeader
->Name
.Length
!= 0 ? &EntryHeader
->Name
: NULL
);
256 Type
= &EntryHeader
->ObjectType
->TypeName
;
257 EntrySize
= sizeof(OBJECT_DIRECTORY_INFORMATION
) +
258 ((Name
!= NULL
) ? ((ULONG
)Name
->Length
+ sizeof(WCHAR
)) : 0) +
259 (ULONG
)EntryHeader
->ObjectType
->TypeName
.Length
+ sizeof(WCHAR
);
261 if(RequiredSize
+ EntrySize
<= BufferLength
)
263 /* the buffer is large enough to receive this entry. It would've
264 been much easier if the strings were directly appended to the
265 OBJECT_DIRECTORY_INFORMATION structured written into the buffer */
267 DirInfo
->ObjectName
= *Name
;
270 DirInfo
->ObjectName
.Length
= DirInfo
->ObjectName
.MaximumLength
= 0;
271 DirInfo
->ObjectName
.Buffer
= NULL
;
273 DirInfo
->ObjectTypeName
= *Type
;
276 RequiredSize
+= EntrySize
;
278 Status
= STATUS_SUCCESS
;
280 if(ReturnSingleEntry
)
282 /* we're only supposed to query one entry, so bail and copy the
283 strings to the buffer */
290 if(ReturnSingleEntry
)
292 /* the buffer is too small, so return the number of bytes that
293 would've been required for this query */
294 RequiredSize
+= EntrySize
;
295 Status
= STATUS_BUFFER_TOO_SMALL
;
298 /* we couldn't query this entry, so leave the index that will be stored
299 in Context to this entry so the caller can query it the next time
300 he queries (hopefully with a buffer that is large enough then...) */
303 /* just copy the entries that fit into the buffer */
314 if(!ReturnSingleEntry
&& ListEntry
!= &Directory
->head
)
316 /* there are more entries to enumerate but the buffer is already full.
317 only tell this to the user if he queries multiple entries */
318 Status
= STATUS_MORE_ENTRIES
;
321 if(NT_SUCCESS(Status
))
327 POBJECT_DIRECTORY_INFORMATION DestDirInfo
= (POBJECT_DIRECTORY_INFORMATION
)Buffer
;
328 PWSTR strbuf
= (PWSTR
)((POBJECT_DIRECTORY_INFORMATION
)Buffer
+ nDirectories
);
330 /* copy all OBJECT_DIRECTORY_INFORMATION structures to the buffer and
331 just append all strings (whose pointers are stored in the buffer!)
332 and replace the pointers */
333 for(DirInfo
= (POBJECT_DIRECTORY_INFORMATION
)TemporaryBuffer
;
335 nDirectories
--, DirInfo
++, DestDirInfo
++)
337 if(DirInfo
->ObjectName
.Length
> 0)
339 DestDirInfo
->ObjectName
.Length
= DirInfo
->ObjectName
.Length
;
340 DestDirInfo
->ObjectName
.MaximumLength
= DirInfo
->ObjectName
.MaximumLength
;
341 DestDirInfo
->ObjectName
.Buffer
= strbuf
;
342 RtlCopyMemory(strbuf
,
343 DirInfo
->ObjectName
.Buffer
,
344 DirInfo
->ObjectName
.Length
);
345 /* NULL-terminate the string */
346 strbuf
[DirInfo
->ObjectName
.Length
/ sizeof(WCHAR
)] = L
'\0';
347 strbuf
+= (DirInfo
->ObjectName
.Length
/ sizeof(WCHAR
)) + 1;
350 DestDirInfo
->ObjectTypeName
.Length
= DirInfo
->ObjectTypeName
.Length
;
351 DestDirInfo
->ObjectTypeName
.MaximumLength
= DirInfo
->ObjectTypeName
.MaximumLength
;
352 DestDirInfo
->ObjectTypeName
.Buffer
= strbuf
;
353 RtlCopyMemory(strbuf
,
354 DirInfo
->ObjectTypeName
.Buffer
,
355 DirInfo
->ObjectTypeName
.Length
);
356 /* NULL-terminate the string */
357 strbuf
[DirInfo
->ObjectTypeName
.Length
/ sizeof(WCHAR
)] = L
'\0';
358 strbuf
+= (DirInfo
->ObjectTypeName
.Length
/ sizeof(WCHAR
)) + 1;
363 Status
= _SEH_GetExceptionCode();
369 KeReleaseSpinLock(&Directory
->Lock
, OldLevel
);
370 ObDereferenceObject(Directory
);
372 ExFreePool(TemporaryBuffer
);
374 if(NT_SUCCESS(Status
) || ReturnSingleEntry
)
378 *Context
= NextEntry
;
379 if(ReturnLength
!= NULL
)
381 *ReturnLength
= RequiredSize
;
386 Status
= _SEH_GetExceptionCode();
393 Status
= STATUS_INSUFFICIENT_RESOURCES
;
401 /**********************************************************************
402 * NAME (EXPORTED as Zw)
403 * NtCreateDirectoryObject
406 * Creates or opens a directory object (a container for other
410 * DirectoryHandle (OUT)
411 * Caller supplied storage for the handle of the
415 * Access desired to the directory.
418 * Object attributes initialized with
419 * InitializeObjectAttributes.
425 NtCreateDirectoryObject (OUT PHANDLE DirectoryHandle
,
426 IN ACCESS_MASK DesiredAccess
,
427 IN POBJECT_ATTRIBUTES ObjectAttributes
)
429 PDIRECTORY_OBJECT Directory
;
431 KPROCESSOR_MODE PreviousMode
;
432 NTSTATUS Status
= STATUS_SUCCESS
;
436 DPRINT("NtCreateDirectoryObject(DirectoryHandle %x, "
437 "DesiredAccess %x, ObjectAttributes %x\n",
438 DirectoryHandle
, DesiredAccess
, ObjectAttributes
);
440 PreviousMode
= ExGetPreviousMode();
442 if(PreviousMode
!= KernelMode
)
446 ProbeForWrite(DirectoryHandle
,
452 Status
= _SEH_GetExceptionCode();
456 if(!NT_SUCCESS(Status
))
458 DPRINT1("NtCreateDirectoryObject failed, Status: 0x%x\n", Status
);
463 Status
= ObCreateObject(PreviousMode
,
468 sizeof(DIRECTORY_OBJECT
),
472 if(NT_SUCCESS(Status
))
474 Status
= ObInsertObject((PVOID
)Directory
,
480 ObDereferenceObject(Directory
);
482 if(NT_SUCCESS(Status
))
486 *DirectoryHandle
= hDirectory
;
490 Status
= _SEH_GetExceptionCode();