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 ProbeForWriteHandle(DirectoryHandle
);
65 Status
= _SEH_GetExceptionCode();
69 if(!NT_SUCCESS(Status
))
71 DPRINT1("NtOpenDirectoryObject failed, Status: 0x%x\n", Status
);
76 Status
= ObOpenObjectByName(ObjectAttributes
,
83 if(NT_SUCCESS(Status
))
87 *DirectoryHandle
= hDirectory
;
91 Status
= _SEH_GetExceptionCode();
100 /**********************************************************************
102 * NtQueryDirectoryObject
105 * Reads information from a directory in the system namespace.
109 * Handle, obtained with NtOpenDirectoryObject(), which
110 * must grant DIRECTORY_QUERY access to the directory
114 * Buffer to hold the data read.
117 * Size of the buffer in bytes.
120 * When TRUE, only 1 entry is written in DirObjInformation;
121 * otherwise as many as will fit in the buffer.
124 * If TRUE start reading at index 0.
125 * If FALSE start reading at the index specified
126 * by object index *ObjectIndex.
129 * Zero based index into the directory, interpretation
130 * depends on RestartScan.
133 * Caller supplied storage for the number of bytes
137 * STATUS_SUCCESS - At least one (possibly more, depending on
138 * parameters and buffer size) dir entry is
140 * STATUS_NO_MORE_ENTRIES - Directory is exhausted
141 * STATUS_BUFFER_TOO_SMALL - There isn't enough room in the
142 * buffer to return even 1 entry.
143 * ReturnLength will hold the required
144 * buffer size to return all remaining
146 * Other - Status code
150 * Although you can iterate over the directory by calling this
151 * function multiple times, the directory is unlocked between
152 * calls. This means that another thread can change the directory
153 * and so iterating doesn't guarantee a consistent picture of the
154 * directory. Best thing is to retrieve all directory entries in
158 NtQueryDirectoryObject (IN HANDLE DirectoryHandle
,
160 IN ULONG BufferLength
,
161 IN BOOLEAN ReturnSingleEntry
,
162 IN BOOLEAN RestartScan
,
163 IN OUT PULONG Context
,
164 OUT PULONG ReturnLength OPTIONAL
)
166 PDIRECTORY_OBJECT Directory
;
167 KPROCESSOR_MODE PreviousMode
;
168 ULONG SkipEntries
= 0;
171 NTSTATUS Status
= STATUS_SUCCESS
;
175 PreviousMode
= ExGetPreviousMode();
177 if(PreviousMode
!= KernelMode
)
181 /* a test showed that the Buffer pointer just has to be 16 bit aligned,
182 propably due to the fact that most information that needs to be copied
183 is unicode strings */
184 ProbeForWrite(Buffer
,
187 ProbeForWriteUlong(Context
);
190 SkipEntries
= *Context
;
192 if(ReturnLength
!= NULL
)
194 ProbeForWriteUlong(ReturnLength
);
199 Status
= _SEH_GetExceptionCode();
203 if(!NT_SUCCESS(Status
))
205 DPRINT1("NtQueryDirectoryObject failed, Status: 0x%x\n", Status
);
209 else if(!RestartScan
)
211 SkipEntries
= *Context
;
214 Status
= ObReferenceObjectByHandle(DirectoryHandle
,
220 if(NT_SUCCESS(Status
))
222 PVOID TemporaryBuffer
= ExAllocatePool(PagedPool
,
224 if(TemporaryBuffer
!= NULL
)
226 POBJECT_HEADER EntryHeader
;
227 PLIST_ENTRY ListEntry
;
229 ULONG RequiredSize
= 0;
230 ULONG nDirectories
= 0;
231 POBJECT_DIRECTORY_INFORMATION DirInfo
= (POBJECT_DIRECTORY_INFORMATION
)TemporaryBuffer
;
233 Status
= STATUS_NO_MORE_ENTRIES
;
235 KeAcquireSpinLock(&Directory
->Lock
, &OldLevel
);
237 for(ListEntry
= Directory
->head
.Flink
;
238 ListEntry
!= &Directory
->head
;
239 ListEntry
= ListEntry
->Flink
)
244 PUNICODE_STRING Name
, Type
;
247 EntryHeader
= CONTAINING_RECORD(ListEntry
, OBJECT_HEADER
, Entry
);
249 /* calculate the size of the required buffer space for this entry */
250 Name
= (HEADER_TO_OBJECT_NAME(EntryHeader
)->Name
.Length
!= 0 ? &HEADER_TO_OBJECT_NAME(EntryHeader
)->Name
: NULL
);
251 Type
= &EntryHeader
->Type
->Name
;
252 EntrySize
= sizeof(OBJECT_DIRECTORY_INFORMATION
) +
253 ((Name
!= NULL
) ? ((ULONG
)Name
->Length
+ sizeof(WCHAR
)) : 0) +
254 (ULONG
)EntryHeader
->Type
->Name
.Length
+ sizeof(WCHAR
);
256 if(RequiredSize
+ EntrySize
<= BufferLength
)
258 /* the buffer is large enough to receive this entry. It would've
259 been much easier if the strings were directly appended to the
260 OBJECT_DIRECTORY_INFORMATION structured written into the buffer */
262 DirInfo
->ObjectName
= *Name
;
265 DirInfo
->ObjectName
.Length
= DirInfo
->ObjectName
.MaximumLength
= 0;
266 DirInfo
->ObjectName
.Buffer
= NULL
;
268 DirInfo
->ObjectTypeName
= *Type
;
271 RequiredSize
+= EntrySize
;
273 Status
= STATUS_SUCCESS
;
275 if(ReturnSingleEntry
)
277 /* we're only supposed to query one entry, so bail and copy the
278 strings to the buffer */
285 if(ReturnSingleEntry
)
287 /* the buffer is too small, so return the number of bytes that
288 would've been required for this query */
289 RequiredSize
+= EntrySize
;
290 Status
= STATUS_BUFFER_TOO_SMALL
;
293 /* we couldn't query this entry, so leave the index that will be stored
294 in Context to this entry so the caller can query it the next time
295 he queries (hopefully with a buffer that is large enough then...) */
298 /* just copy the entries that fit into the buffer */
309 if(!ReturnSingleEntry
&& ListEntry
!= &Directory
->head
)
311 /* there are more entries to enumerate but the buffer is already full.
312 only tell this to the user if he queries multiple entries */
313 Status
= STATUS_MORE_ENTRIES
;
316 if(NT_SUCCESS(Status
) && nDirectories
> 0)
318 PWSTR strbuf
= (PWSTR
)((POBJECT_DIRECTORY_INFORMATION
)TemporaryBuffer
+ nDirectories
);
319 PWSTR deststrbuf
= (PWSTR
)((POBJECT_DIRECTORY_INFORMATION
)Buffer
+ nDirectories
);
321 CopyBytes
= nDirectories
* sizeof(OBJECT_DIRECTORY_INFORMATION
);
323 /* copy the names from the objects and append them to the list of the
324 objects. copy to the temporary buffer only because the directory
325 lock can't be released and the buffer might be pagable memory! */
326 for(DirInfo
= (POBJECT_DIRECTORY_INFORMATION
)TemporaryBuffer
;
328 nDirectories
--, DirInfo
++)
332 if(DirInfo
->ObjectName
.Length
> 0)
334 RtlCopyMemory(strbuf
,
335 DirInfo
->ObjectName
.Buffer
,
336 DirInfo
->ObjectName
.Length
);
337 /* change the buffer pointer to the buffer */
338 DirInfo
->ObjectName
.Buffer
= deststrbuf
;
339 NameLength
= DirInfo
->ObjectName
.Length
/ sizeof(WCHAR
);
340 /* NULL-terminate the string */
341 strbuf
[NameLength
] = L
'\0';
342 strbuf
+= NameLength
+ 1;
343 deststrbuf
+= NameLength
+ 1;
345 CopyBytes
+= (NameLength
+ 1) * sizeof(WCHAR
);
348 RtlCopyMemory(strbuf
,
349 DirInfo
->ObjectTypeName
.Buffer
,
350 DirInfo
->ObjectTypeName
.Length
);
351 /* change the buffer pointer to the buffer */
352 DirInfo
->ObjectTypeName
.Buffer
= deststrbuf
;
353 NameLength
= DirInfo
->ObjectTypeName
.Length
/ sizeof(WCHAR
);
354 /* NULL-terminate the string */
355 strbuf
[NameLength
] = L
'\0';
356 strbuf
+= NameLength
+ 1;
357 deststrbuf
+= NameLength
+ 1;
359 CopyBytes
+= (NameLength
+ 1) * sizeof(WCHAR
);
363 KeReleaseSpinLock(&Directory
->Lock
, OldLevel
);
364 ObDereferenceObject(Directory
);
366 if(NT_SUCCESS(Status
) || ReturnSingleEntry
)
372 RtlCopyMemory(Buffer
,
376 *Context
= NextEntry
;
377 if(ReturnLength
!= NULL
)
379 *ReturnLength
= RequiredSize
;
384 Status
= _SEH_GetExceptionCode();
389 ExFreePool(TemporaryBuffer
);
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 ProbeForWriteHandle(DirectoryHandle
);
450 Status
= _SEH_GetExceptionCode();
454 if(!NT_SUCCESS(Status
))
456 DPRINT1("NtCreateDirectoryObject failed, Status: 0x%x\n", Status
);
461 Status
= ObCreateObject(PreviousMode
,
466 sizeof(DIRECTORY_OBJECT
),
471 if(NT_SUCCESS(Status
))
473 Status
= ObInsertObject((PVOID
)Directory
,
479 if (!NT_SUCCESS(Status
))
481 ObMakeTemporaryObject(Directory
);
483 ObDereferenceObject(Directory
);
485 if(NT_SUCCESS(Status
))
489 *DirectoryHandle
= hDirectory
;
493 Status
= _SEH_GetExceptionCode();