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
7 * PROGRAMMER: David Welch (welch@mcmail.com)
12 /* INCLUDES ***************************************************************/
14 #define NTOS_MODE_KERNEL
16 #include <internal/ob.h>
17 #include <internal/io.h>
20 #include <internal/debug.h>
23 /* FUNCTIONS **************************************************************/
27 /**********************************************************************
29 * NtOpenDirectoryObject
32 * Opens a namespace directory object.
35 * DirectoryHandle (OUT)
36 * Variable which receives the directory handle.
39 * Desired access to the directory.
42 * Structure describing the directory.
51 NtOpenDirectoryObject (OUT PHANDLE DirectoryHandle,
52 IN ACCESS_MASK DesiredAccess,
53 IN POBJECT_ATTRIBUTES ObjectAttributes)
60 Status = ObReferenceObjectByName(ObjectAttributes->ObjectName,
61 ObjectAttributes->Attributes,
68 if (!NT_SUCCESS(Status))
73 Status = ObCreateHandle(PsGetCurrentProcess(),
78 return STATUS_SUCCESS;
82 /**********************************************************************
84 * NtQueryDirectoryObject
87 * Reads information from a directory in the system namespace.
91 * Handle, obtained with NtOpenDirectoryObject(), which
92 * must grant DIRECTORY_QUERY access to the directory
96 * Buffer to hold the data read.
99 * Size of the buffer in bytes.
102 * When TRUE, only 1 entry is written in DirObjInformation;
103 * otherwise as many as will fit in the buffer.
106 * If TRUE start reading at index 0.
107 * If FALSE start reading at the index specified
108 * by object index *ObjectIndex.
111 * Zero based index into the directory, interpretation
112 * depends on RestartScan.
115 * Caller supplied storage for the number of bytes
123 * Changed 4th, and 5th parameter names after
124 * G.Nebbett "WNT/W2k Native API Reference".
128 NtQueryDirectoryObject (IN HANDLE DirectoryHandle,
130 IN ULONG BufferLength,
131 IN BOOLEAN ReturnSingleEntry,
132 IN BOOLEAN RestartScan,
133 IN OUT PULONG Context,
134 OUT PULONG ReturnLength OPTIONAL)
136 PDIRECTORY_OBJECT dir = NULL;
137 PLIST_ENTRY current_entry = NULL;
138 POBJECT_HEADER current = NULL;
140 NTSTATUS Status = STATUS_SUCCESS;
141 ULONG DirectoryCount = 0;
142 ULONG DirectorySize = 0;
143 ULONG SpaceLeft = BufferLength;
144 ULONG SpaceRequired = 0;
145 ULONG NameLength = 0;
146 ULONG TypeNameLength = 0;
147 PDIRECTORY_BASIC_INFORMATION current_odi = (PDIRECTORY_BASIC_INFORMATION) Buffer;
148 PUCHAR FirstFree = (PUCHAR) Buffer;
151 DPRINT("NtQueryDirectoryObject(DirObjHandle %x)\n", DirObjHandle);
153 /* FIXME: if previous mode == user, use ProbeForWrite
156 /* Reference the DIRECTORY_OBJECT */
157 Status = ObReferenceObjectByHandle(DirectoryHandle,
163 if (!NT_SUCCESS(Status))
167 /* Check Context is not NULL */
170 return (STATUS_INVALID_PARAMETER);
173 * Compute the number of directory entries
174 * and the size of the array (in bytes).
175 * One more entry marks the end of the array.
177 if (FALSE == ReturnSingleEntry)
179 for ( current_entry = dir->head.Flink;
180 (current_entry != & dir->head);
181 current_entry = current_entry->Flink
191 // count is DirectoryCount + one null entry
192 DirectorySize = (DirectoryCount + 1) * sizeof (DIRECTORY_BASIC_INFORMATION);
193 if (DirectorySize > SpaceLeft)
195 return (STATUS_BUFFER_TOO_SMALL);
198 * Optionally, skip over some entries at the start of the directory
199 * (use *ObjectIndex value)
201 current_entry = dir->head.Flink;
202 if (FALSE == RestartScan)
204 /* RestartScan == FALSE */
205 register ULONG EntriesToSkip = *Context;
210 ((EntriesToSkip --) && (current_entry != & dir->head));
211 current_entry = current_entry->Flink
213 if ((EntriesToSkip) && (current_entry == & dir->head))
215 return (STATUS_NO_MORE_ENTRIES);
219 * Initialize the array of OBJDIR_INFORMATION.
221 RtlZeroMemory (FirstFree, DirectorySize);
223 * Move FirstFree to point to the Unicode strings area
225 FirstFree += DirectorySize;
227 * Compute how much space is left after allocating the
228 * array in the user buffer.
230 SpaceLeft -= DirectorySize;
231 /* Scan the directory */
235 * Check if we reached the end of the directory.
237 if (current_entry == & dir->head)
240 if (i) break; /* DONE */
241 /* FIXME: better error handling here! */
242 return (STATUS_NO_MORE_ENTRIES);
245 * Compute the current OBJECT_HEADER memory
248 current = CONTAINING_RECORD(current_entry, OBJECT_HEADER, Entry);
250 * Compute the space required in the user buffer to copy
251 * the data from the current object:
253 * Name (WCHAR) 0 TypeName (WCHAR) 0
255 NameLength = (wcslen (current->Name.Buffer) * sizeof (WCHAR));
256 TypeNameLength = (wcslen (current->ObjectType->TypeName.Buffer) * sizeof (WCHAR));
257 SpaceRequired = (NameLength + 1) * sizeof (WCHAR)
258 + (TypeNameLength + 1) * sizeof (WCHAR);
260 * Check for free space in the user buffer.
262 if (SpaceRequired > SpaceLeft)
264 return (STATUS_BUFFER_TOO_SMALL);
267 * Copy the current directory entry's data into the buffer
268 * and update the OBJDIR_INFORMATION entry in the array.
270 /* --- Object's name --- */
271 current_odi->ObjectName.Length = NameLength;
272 current_odi->ObjectName.MaximumLength = (NameLength + sizeof (WCHAR));
273 current_odi->ObjectName.Buffer = (PWCHAR) FirstFree;
274 wcscpy ((PWCHAR) FirstFree, current->Name.Buffer);
275 FirstFree += (current_odi->ObjectName.MaximumLength);
276 /* --- Object type's name --- */
277 current_odi->ObjectTypeName.Length = TypeNameLength;
278 current_odi->ObjectTypeName.MaximumLength = (TypeNameLength + sizeof (WCHAR));
279 current_odi->ObjectTypeName.Buffer = (PWCHAR) FirstFree;
280 wcscpy ((PWCHAR) FirstFree, current->ObjectType->TypeName.Buffer);
281 FirstFree += (current_odi->ObjectTypeName.MaximumLength);
282 /* Next entry in the array */
284 /* Decrease the space left count */
285 SpaceLeft -= SpaceRequired;
286 /* Increase the object index number */
288 /* Next object in the directory */
289 current_entry = current_entry->Flink;
291 } while (FALSE == ReturnSingleEntry);
293 * Store current index in Context
295 *Context += DirectoryCount;
297 * Report to the caller how much bytes
298 * we wrote in the user buffer.
300 if (NULL != ReturnLength)
302 *ReturnLength = (BufferLength - SpaceLeft);
304 return (STATUS_SUCCESS);
307 #endif /* LIBCAPTIVE */
309 /**********************************************************************
310 * NAME (EXPORTED as Zw)
311 * NtCreateDirectoryObject
314 * Creates or opens a directory object (a container for other
318 * DirectoryHandle (OUT)
319 * Caller supplied storage for the handle of the
323 * Access desired to the directory.
326 * Object attributes initialized with
327 * InitializeObjectAttributes.
333 NtCreateDirectoryObject (OUT PHANDLE DirectoryHandle,
334 IN ACCESS_MASK DesiredAccess,
335 IN POBJECT_ATTRIBUTES ObjectAttributes)
337 PDIRECTORY_OBJECT dir;
339 DPRINT("NtCreateDirectoryObject(DirectoryHandle %x, "
340 "DesiredAccess %x, ObjectAttributes %x, "
341 "ObjectAttributes->ObjectName %wZ)\n",
342 DirectoryHandle, DesiredAccess, ObjectAttributes,
343 ObjectAttributes->ObjectName);
345 return(ObRosCreateObject(DirectoryHandle,