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 #include <ddk/ntddk.h>
15 #include <internal/ob.h>
16 #include <internal/io.h>
19 #include <internal/debug.h>
22 /* FUNCTIONS **************************************************************/
25 /**********************************************************************
27 * NtOpenDirectoryObject
30 * Opens a namespace directory object.
33 * DirectoryHandle (OUT)
34 * Variable which receives the directory handle.
37 * Desired access to the directory.
40 * Structure describing the directory.
48 NTSTATUS STDCALL NtOpenDirectoryObject(PHANDLE DirectoryHandle,
49 ACCESS_MASK DesiredAccess,
50 POBJECT_ATTRIBUTES ObjectAttributes)
57 Status = ObReferenceObjectByName(ObjectAttributes->ObjectName,
58 ObjectAttributes->Attributes,
65 if (!NT_SUCCESS(Status))
70 Status = ObCreateHandle(PsGetCurrentProcess(),
75 return STATUS_SUCCESS;
79 /**********************************************************************
81 * NtQueryDirectoryObject
84 * Reads information from a directory in the system namespace.
88 * Handle, obtained with NtOpenDirectoryObject(), which
89 * must grant DIRECTORY_QUERY access to the directory
92 * DirObjInformation (OUT)
93 * Buffer to hold the data read.
96 * Size of the buffer in bytes.
99 * When TRUE, only 1 entry is written in DirObjInformation;
100 * otherwise as many as will fit in the buffer.
103 * If TRUE start reading at index 0.
104 * If FALSE start reading at the index specified
105 * by object index *ObjectIndex.
108 * Zero based index into the directory, interpretation
109 * depends on RestartScan.
112 * Caller supplied storage for the number of bytes
120 * Changed 4th, and 5th parameter names after
121 * G.Nebbett "WNT/W2k Native API Reference".
124 NTSTATUS STDCALL NtQueryDirectoryObject (IN HANDLE DirObjHandle,
125 OUT POBJDIR_INFORMATION
127 IN ULONG BufferLength,
128 IN BOOLEAN ReturnSingleEntry,
129 IN BOOLEAN RestartScan,
130 IN OUT PULONG ObjectIndex,
131 OUT PULONG DataWritten OPTIONAL)
133 PDIRECTORY_OBJECT dir = NULL;
134 PLIST_ENTRY current_entry = NULL;
135 POBJECT_HEADER current = NULL;
137 NTSTATUS Status = STATUS_SUCCESS;
138 DWORD DirectoryCount = 0;
139 DWORD DirectorySize = 0;
140 ULONG SpaceLeft = BufferLength;
141 ULONG SpaceRequired = 0;
142 ULONG NameLength = 0;
143 ULONG TypeNameLength = 0;
144 POBJDIR_INFORMATION current_odi = DirObjInformation;
145 PBYTE FirstFree = (PBYTE) DirObjInformation;
148 DPRINT("NtQueryDirectoryObject(DirObjHandle %x)\n", DirObjHandle);
150 /* FIXME: if previous mode == user, use ProbeForWrite
153 /* Reference the DIRECTORY_OBJECT */
154 Status = ObReferenceObjectByHandle(DirObjHandle,
160 if (!NT_SUCCESS(Status))
164 /* Check ObjectIndex is not NULL */
165 if (NULL == ObjectIndex)
167 return (STATUS_INVALID_PARAMETER);
170 * Compute the number of directory entries
171 * and the size of the array (in bytes).
172 * One more entry marks the end of the array.
174 if (FALSE == ReturnSingleEntry)
176 for ( current_entry = dir->head.Flink;
177 (current_entry != & dir->head);
178 current_entry = current_entry->Flink
188 // count is DirectoryCount + one null entry
189 DirectorySize = (DirectoryCount + 1) * sizeof (OBJDIR_INFORMATION);
190 if (DirectorySize > SpaceLeft)
192 return (STATUS_BUFFER_TOO_SMALL);
195 * Optionally, skip over some entries at the start of the directory
196 * (use *ObjectIndex value)
198 current_entry = dir->head.Flink;
199 if (FALSE == RestartScan)
201 /* RestartScan == FALSE */
202 register ULONG EntriesToSkip = *ObjectIndex;
207 ((EntriesToSkip --) && (current_entry != & dir->head));
208 current_entry = current_entry->Flink
210 if ((EntriesToSkip) && (current_entry == & dir->head))
212 return (STATUS_NO_MORE_ENTRIES);
216 * Initialize the array of OBJDIR_INFORMATION.
218 RtlZeroMemory (FirstFree, DirectorySize);
220 * Move FirstFree to point to the Unicode strings area
222 FirstFree += DirectorySize;
224 * Compute how much space is left after allocating the
225 * array in the user buffer.
227 SpaceLeft -= DirectorySize;
228 /* Scan the directory */
232 * Check if we reached the end of the directory.
234 if (current_entry == & dir->head)
237 if (i) break; /* DONE */
238 /* FIXME: better error handling here! */
239 return (STATUS_NO_MORE_ENTRIES);
242 * Compute the current OBJECT_HEADER memory
245 current = CONTAINING_RECORD(current_entry, OBJECT_HEADER, Entry);
247 * Compute the space required in the user buffer to copy
248 * the data from the current object:
250 * Name (WCHAR) 0 TypeName (WCHAR) 0
252 NameLength = (wcslen (current->Name.Buffer) * sizeof (WCHAR));
253 TypeNameLength = (wcslen (current->ObjectType->TypeName.Buffer) * sizeof (WCHAR));
254 SpaceRequired = (NameLength + 1) * sizeof (WCHAR)
255 + (TypeNameLength + 1) * sizeof (WCHAR);
257 * Check for free space in the user buffer.
259 if (SpaceRequired > SpaceLeft)
261 return (STATUS_BUFFER_TOO_SMALL);
264 * Copy the current directory entry's data into the buffer
265 * and update the OBJDIR_INFORMATION entry in the array.
267 /* --- Object's name --- */
268 current_odi->ObjectName.Length = NameLength;
269 current_odi->ObjectName.MaximumLength = (NameLength + sizeof (WCHAR));
270 current_odi->ObjectName.Buffer = (PWCHAR) FirstFree;
271 wcscpy ((PWCHAR) FirstFree, current->Name.Buffer);
272 FirstFree += (current_odi->ObjectName.MaximumLength);
273 /* --- Object type's name --- */
274 current_odi->ObjectTypeName.Length = TypeNameLength;
275 current_odi->ObjectTypeName.MaximumLength = (TypeNameLength + sizeof (WCHAR));
276 current_odi->ObjectTypeName.Buffer = (PWCHAR) FirstFree;
277 wcscpy ((PWCHAR) FirstFree, current->ObjectType->TypeName.Buffer);
278 FirstFree += (current_odi->ObjectTypeName.MaximumLength);
279 /* Next entry in the array */
281 /* Decrease the space left count */
282 SpaceLeft -= SpaceRequired;
283 /* Increase the object index number */
285 /* Next object in the directory */
286 current_entry = current_entry->Flink;
288 } while (FALSE == ReturnSingleEntry);
290 * Store current index in ObjectIndex
292 *ObjectIndex += DirectoryCount;
294 * Report to the caller how much bytes
295 * we wrote in the user buffer.
297 if (NULL != DataWritten)
299 *DataWritten = (BufferLength - SpaceLeft);
301 return (STATUS_SUCCESS);
305 /**********************************************************************
306 * NAME (EXPORTED as Zw)
307 * NtCreateDirectoryObject
310 * Creates or opens a directory object (a container for other
314 * DirectoryHandle (OUT)
315 * Caller supplied storage for the handle of the
319 * Access desired to the directory.
322 * Object attributes initialized with
323 * InitializeObjectAttributes.
329 NtCreateDirectoryObject(PHANDLE DirectoryHandle,
330 ACCESS_MASK DesiredAccess,
331 POBJECT_ATTRIBUTES ObjectAttributes)
333 PDIRECTORY_OBJECT dir;
335 DPRINT("NtCreateDirectoryObject(DirectoryHandle %x, "
336 "DesiredAccess %x, ObjectAttributes %x, "
337 "ObjectAttributes->ObjectName %S)\n",
338 DirectoryHandle, DesiredAccess, ObjectAttributes,
339 ObjectAttributes->ObjectName);
341 return(ObCreateObject(DirectoryHandle,