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;
173 NTSTATUS Status
= STATUS_SUCCESS
;
177 PreviousMode
= ExGetPreviousMode();
179 if(PreviousMode
!= KernelMode
)
183 /* a test showed that the Buffer pointer just has to be 16 bit aligned,
184 propably due to the fact that most information that needs to be copied
185 is unicode strings */
186 ProbeForWrite(Buffer
,
189 ProbeForWrite(Context
,
194 SkipEntries
= *Context
;
196 if(ReturnLength
!= NULL
)
198 ProbeForWrite(ReturnLength
,
205 Status
= _SEH_GetExceptionCode();
209 if(!NT_SUCCESS(Status
))
211 DPRINT1("NtQueryDirectoryObject failed, Status: 0x%x\n", Status
);
215 else if(!RestartScan
)
217 SkipEntries
= *Context
;
220 Status
= ObReferenceObjectByHandle(DirectoryHandle
,
226 if(NT_SUCCESS(Status
))
228 PVOID TemporaryBuffer
= ExAllocatePool(PagedPool
,
230 if(TemporaryBuffer
!= NULL
)
232 POBJECT_HEADER EntryHeader
;
233 PLIST_ENTRY ListEntry
;
235 ULONG RequiredSize
= 0;
236 ULONG nDirectories
= 0;
237 POBJECT_DIRECTORY_INFORMATION DirInfo
= (POBJECT_DIRECTORY_INFORMATION
)TemporaryBuffer
;
239 Status
= STATUS_NO_MORE_ENTRIES
;
241 KeAcquireSpinLock(&Directory
->Lock
, &OldLevel
);
243 for(ListEntry
= Directory
->head
.Flink
;
244 ListEntry
!= &Directory
->head
;
245 ListEntry
= ListEntry
->Flink
)
250 PUNICODE_STRING Name
, Type
;
253 EntryHeader
= CONTAINING_RECORD(ListEntry
, OBJECT_HEADER
, Entry
);
255 /* calculate the size of the required buffer space for this entry */
256 Name
= (EntryHeader
->Name
.Length
!= 0 ? &EntryHeader
->Name
: NULL
);
257 Type
= &EntryHeader
->ObjectType
->Name
;
258 EntrySize
= sizeof(OBJECT_DIRECTORY_INFORMATION
) +
259 ((Name
!= NULL
) ? ((ULONG
)Name
->Length
+ sizeof(WCHAR
)) : 0) +
260 (ULONG
)EntryHeader
->ObjectType
->Name
.Length
+ sizeof(WCHAR
);
262 if(RequiredSize
+ EntrySize
<= BufferLength
)
264 /* the buffer is large enough to receive this entry. It would've
265 been much easier if the strings were directly appended to the
266 OBJECT_DIRECTORY_INFORMATION structured written into the buffer */
268 DirInfo
->ObjectName
= *Name
;
271 DirInfo
->ObjectName
.Length
= DirInfo
->ObjectName
.MaximumLength
= 0;
272 DirInfo
->ObjectName
.Buffer
= NULL
;
274 DirInfo
->ObjectTypeName
= *Type
;
277 RequiredSize
+= EntrySize
;
279 Status
= STATUS_SUCCESS
;
281 if(ReturnSingleEntry
)
283 /* we're only supposed to query one entry, so bail and copy the
284 strings to the buffer */
291 if(ReturnSingleEntry
)
293 /* the buffer is too small, so return the number of bytes that
294 would've been required for this query */
295 RequiredSize
+= EntrySize
;
296 Status
= STATUS_BUFFER_TOO_SMALL
;
299 /* we couldn't query this entry, so leave the index that will be stored
300 in Context to this entry so the caller can query it the next time
301 he queries (hopefully with a buffer that is large enough then...) */
304 /* just copy the entries that fit into the buffer */
315 if(!ReturnSingleEntry
&& ListEntry
!= &Directory
->head
)
317 /* there are more entries to enumerate but the buffer is already full.
318 only tell this to the user if he queries multiple entries */
319 Status
= STATUS_MORE_ENTRIES
;
322 if(NT_SUCCESS(Status
) && nDirectories
> 0)
324 PWSTR strbuf
= (PWSTR
)((POBJECT_DIRECTORY_INFORMATION
)TemporaryBuffer
+ nDirectories
);
325 PWSTR deststrbuf
= (PWSTR
)((POBJECT_DIRECTORY_INFORMATION
)Buffer
+ nDirectories
);
327 CopyBytes
= nDirectories
* sizeof(OBJECT_DIRECTORY_INFORMATION
);
329 /* copy the names from the objects and append them to the list of the
330 objects. copy to the temporary buffer only because the directory
331 lock can't be released and the buffer might be pagable memory! */
332 for(DirInfo
= (POBJECT_DIRECTORY_INFORMATION
)TemporaryBuffer
;
334 nDirectories
--, DirInfo
++)
338 if(DirInfo
->ObjectName
.Length
> 0)
340 RtlCopyMemory(strbuf
,
341 DirInfo
->ObjectName
.Buffer
,
342 DirInfo
->ObjectName
.Length
);
343 /* change the buffer pointer to the buffer */
344 DirInfo
->ObjectName
.Buffer
= deststrbuf
;
345 NameLength
= DirInfo
->ObjectName
.Length
/ sizeof(WCHAR
);
346 /* NULL-terminate the string */
347 strbuf
[NameLength
] = L
'\0';
348 strbuf
+= NameLength
+ 1;
349 deststrbuf
+= NameLength
+ 1;
351 CopyBytes
+= (NameLength
+ 1) * sizeof(WCHAR
);
354 RtlCopyMemory(strbuf
,
355 DirInfo
->ObjectTypeName
.Buffer
,
356 DirInfo
->ObjectTypeName
.Length
);
357 /* change the buffer pointer to the buffer */
358 DirInfo
->ObjectTypeName
.Buffer
= deststrbuf
;
359 NameLength
= DirInfo
->ObjectTypeName
.Length
/ sizeof(WCHAR
);
360 /* NULL-terminate the string */
361 strbuf
[NameLength
] = L
'\0';
362 strbuf
+= NameLength
+ 1;
363 deststrbuf
+= NameLength
+ 1;
365 CopyBytes
+= (NameLength
+ 1) * sizeof(WCHAR
);
369 KeReleaseSpinLock(&Directory
->Lock
, OldLevel
);
370 ObDereferenceObject(Directory
);
372 if(NT_SUCCESS(Status
) || ReturnSingleEntry
)
378 RtlCopyMemory(Buffer
,
382 *Context
= NextEntry
;
383 if(ReturnLength
!= NULL
)
385 *ReturnLength
= RequiredSize
;
390 Status
= _SEH_GetExceptionCode();
395 ExFreePool(TemporaryBuffer
);
399 Status
= STATUS_INSUFFICIENT_RESOURCES
;
407 /**********************************************************************
408 * NAME (EXPORTED as Zw)
409 * NtCreateDirectoryObject
412 * Creates or opens a directory object (a container for other
416 * DirectoryHandle (OUT)
417 * Caller supplied storage for the handle of the
421 * Access desired to the directory.
424 * Object attributes initialized with
425 * InitializeObjectAttributes.
431 NtCreateDirectoryObject (OUT PHANDLE DirectoryHandle
,
432 IN ACCESS_MASK DesiredAccess
,
433 IN POBJECT_ATTRIBUTES ObjectAttributes
)
435 PDIRECTORY_OBJECT Directory
;
437 KPROCESSOR_MODE PreviousMode
;
438 NTSTATUS Status
= STATUS_SUCCESS
;
442 DPRINT("NtCreateDirectoryObject(DirectoryHandle %x, "
443 "DesiredAccess %x, ObjectAttributes %x\n",
444 DirectoryHandle
, DesiredAccess
, ObjectAttributes
);
446 PreviousMode
= ExGetPreviousMode();
448 if(PreviousMode
!= KernelMode
)
452 ProbeForWrite(DirectoryHandle
,
458 Status
= _SEH_GetExceptionCode();
462 if(!NT_SUCCESS(Status
))
464 DPRINT1("NtCreateDirectoryObject failed, Status: 0x%x\n", Status
);
469 Status
= ObCreateObject(PreviousMode
,
474 sizeof(DIRECTORY_OBJECT
),
479 if(NT_SUCCESS(Status
))
481 Status
= ObInsertObject((PVOID
)Directory
,
487 ObDereferenceObject(Directory
);
489 if(NT_SUCCESS(Status
))
493 *DirectoryHandle
= hDirectory
;
497 Status
= _SEH_GetExceptionCode();