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 **************************************************************/
26 /**********************************************************************
28 * NtOpenDirectoryObject
31 * Opens a namespace directory object.
34 * DirectoryHandle (OUT)
35 * Variable which receives the directory handle.
38 * Desired access to the directory.
41 * Structure describing the directory.
50 NtOpenDirectoryObject (OUT PHANDLE DirectoryHandle,
51 IN ACCESS_MASK DesiredAccess,
52 IN POBJECT_ATTRIBUTES ObjectAttributes)
59 Status = ObReferenceObjectByName(ObjectAttributes->ObjectName,
60 ObjectAttributes->Attributes,
67 if (!NT_SUCCESS(Status))
72 Status = ObCreateHandle(PsGetCurrentProcess(),
77 return STATUS_SUCCESS;
81 /**********************************************************************
83 * NtQueryDirectoryObject
86 * Reads information from a directory in the system namespace.
90 * Handle, obtained with NtOpenDirectoryObject(), which
91 * must grant DIRECTORY_QUERY access to the directory
95 * Buffer to hold the data read.
98 * Size of the buffer in bytes.
101 * When TRUE, only 1 entry is written in DirObjInformation;
102 * otherwise as many as will fit in the buffer.
105 * If TRUE start reading at index 0.
106 * If FALSE start reading at the index specified
107 * by object index *ObjectIndex.
110 * Zero based index into the directory, interpretation
111 * depends on RestartScan.
114 * Caller supplied storage for the number of bytes
122 * Changed 4th, and 5th parameter names after
123 * G.Nebbett "WNT/W2k Native API Reference".
127 NtQueryDirectoryObject (IN HANDLE DirectoryHandle,
129 IN ULONG BufferLength,
130 IN BOOLEAN ReturnSingleEntry,
131 IN BOOLEAN RestartScan,
132 IN OUT PULONG Context,
133 OUT PULONG ReturnLength OPTIONAL)
135 PDIRECTORY_OBJECT dir = NULL;
136 PLIST_ENTRY current_entry = NULL;
137 POBJECT_HEADER current = NULL;
139 NTSTATUS Status = STATUS_SUCCESS;
140 ULONG DirectoryCount = 0;
141 ULONG DirectorySize = 0;
142 ULONG SpaceLeft = BufferLength;
143 ULONG SpaceRequired = 0;
144 ULONG NameLength = 0;
145 ULONG TypeNameLength = 0;
146 PDIRECTORY_BASIC_INFORMATION current_odi = (PDIRECTORY_BASIC_INFORMATION) Buffer;
147 PUCHAR FirstFree = (PUCHAR) Buffer;
150 DPRINT("NtQueryDirectoryObject(DirObjHandle %x)\n", DirObjHandle);
152 /* FIXME: if previous mode == user, use ProbeForWrite
155 /* Reference the DIRECTORY_OBJECT */
156 Status = ObReferenceObjectByHandle(DirectoryHandle,
162 if (!NT_SUCCESS(Status))
166 /* Check Context is not NULL */
169 return (STATUS_INVALID_PARAMETER);
172 * Compute the number of directory entries
173 * and the size of the array (in bytes).
174 * One more entry marks the end of the array.
176 if (FALSE == ReturnSingleEntry)
178 for ( current_entry = dir->head.Flink;
179 (current_entry != & dir->head);
180 current_entry = current_entry->Flink
190 // count is DirectoryCount + one null entry
191 DirectorySize = (DirectoryCount + 1) * sizeof (DIRECTORY_BASIC_INFORMATION);
192 if (DirectorySize > SpaceLeft)
194 return (STATUS_BUFFER_TOO_SMALL);
197 * Optionally, skip over some entries at the start of the directory
198 * (use *ObjectIndex value)
200 current_entry = dir->head.Flink;
201 if (FALSE == RestartScan)
203 /* RestartScan == FALSE */
204 register ULONG EntriesToSkip = *Context;
209 ((EntriesToSkip --) && (current_entry != & dir->head));
210 current_entry = current_entry->Flink
212 if ((EntriesToSkip) && (current_entry == & dir->head))
214 return (STATUS_NO_MORE_ENTRIES);
218 * Initialize the array of OBJDIR_INFORMATION.
220 RtlZeroMemory (FirstFree, DirectorySize);
222 * Move FirstFree to point to the Unicode strings area
224 FirstFree += DirectorySize;
226 * Compute how much space is left after allocating the
227 * array in the user buffer.
229 SpaceLeft -= DirectorySize;
230 /* Scan the directory */
234 * Check if we reached the end of the directory.
236 if (current_entry == & dir->head)
239 if (i) break; /* DONE */
240 /* FIXME: better error handling here! */
241 return (STATUS_NO_MORE_ENTRIES);
244 * Compute the current OBJECT_HEADER memory
247 current = CONTAINING_RECORD(current_entry, OBJECT_HEADER, Entry);
249 * Compute the space required in the user buffer to copy
250 * the data from the current object:
252 * Name (WCHAR) 0 TypeName (WCHAR) 0
254 NameLength = (wcslen (current->Name.Buffer) * sizeof (WCHAR));
255 TypeNameLength = (wcslen (current->ObjectType->TypeName.Buffer) * sizeof (WCHAR));
256 SpaceRequired = (NameLength + 1) * sizeof (WCHAR)
257 + (TypeNameLength + 1) * sizeof (WCHAR);
259 * Check for free space in the user buffer.
261 if (SpaceRequired > SpaceLeft)
263 return (STATUS_BUFFER_TOO_SMALL);
266 * Copy the current directory entry's data into the buffer
267 * and update the OBJDIR_INFORMATION entry in the array.
269 /* --- Object's name --- */
270 current_odi->ObjectName.Length = NameLength;
271 current_odi->ObjectName.MaximumLength = (NameLength + sizeof (WCHAR));
272 current_odi->ObjectName.Buffer = (PWCHAR) FirstFree;
273 wcscpy ((PWCHAR) FirstFree, current->Name.Buffer);
274 FirstFree += (current_odi->ObjectName.MaximumLength);
275 /* --- Object type's name --- */
276 current_odi->ObjectTypeName.Length = TypeNameLength;
277 current_odi->ObjectTypeName.MaximumLength = (TypeNameLength + sizeof (WCHAR));
278 current_odi->ObjectTypeName.Buffer = (PWCHAR) FirstFree;
279 wcscpy ((PWCHAR) FirstFree, current->ObjectType->TypeName.Buffer);
280 FirstFree += (current_odi->ObjectTypeName.MaximumLength);
281 /* Next entry in the array */
283 /* Decrease the space left count */
284 SpaceLeft -= SpaceRequired;
285 /* Increase the object index number */
287 /* Next object in the directory */
288 current_entry = current_entry->Flink;
290 } while (FALSE == ReturnSingleEntry);
292 * Store current index in Context
294 *Context += DirectoryCount;
296 * Report to the caller how much bytes
297 * we wrote in the user buffer.
299 if (NULL != ReturnLength)
301 *ReturnLength = (BufferLength - SpaceLeft);
303 return (STATUS_SUCCESS);
307 /**********************************************************************
308 * NAME (EXPORTED as Zw)
309 * NtCreateDirectoryObject
312 * Creates or opens a directory object (a container for other
316 * DirectoryHandle (OUT)
317 * Caller supplied storage for the handle of the
321 * Access desired to the directory.
324 * Object attributes initialized with
325 * InitializeObjectAttributes.
331 NtCreateDirectoryObject (OUT PHANDLE DirectoryHandle,
332 IN ACCESS_MASK DesiredAccess,
333 IN POBJECT_ATTRIBUTES ObjectAttributes)
335 PDIRECTORY_OBJECT dir;
337 DPRINT("NtCreateDirectoryObject(DirectoryHandle %x, "
338 "DesiredAccess %x, ObjectAttributes %x, "
339 "ObjectAttributes->ObjectName %S)\n",
340 DirectoryHandle, DesiredAccess, ObjectAttributes,
341 ObjectAttributes->ObjectName);
343 return(ObRosCreateObject(DirectoryHandle,