1 /* $Id: dirobj.c,v 1.23 2004/08/15 16:39:09 chorns Exp $
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 ***************************************************************/
16 #include <internal/debug.h>
19 /* FUNCTIONS **************************************************************/
22 /**********************************************************************
24 * NtOpenDirectoryObject
27 * Opens a namespace directory object.
30 * DirectoryHandle (OUT)
31 * Variable which receives the directory handle.
34 * Desired access to the directory.
37 * Structure describing the directory.
46 NtOpenDirectoryObject (OUT PHANDLE DirectoryHandle
,
47 IN ACCESS_MASK DesiredAccess
,
48 IN POBJECT_ATTRIBUTES ObjectAttributes
)
55 Status
= ObReferenceObjectByName(ObjectAttributes
->ObjectName
,
56 ObjectAttributes
->Attributes
,
63 if (!NT_SUCCESS(Status
))
68 Status
= ObCreateHandle(PsGetCurrentProcess(),
73 return STATUS_SUCCESS
;
77 /**********************************************************************
79 * NtQueryDirectoryObject
82 * Reads information from a directory in the system namespace.
86 * Handle, obtained with NtOpenDirectoryObject(), which
87 * must grant DIRECTORY_QUERY access to the directory
91 * Buffer to hold the data read.
94 * Size of the buffer in bytes.
97 * When TRUE, only 1 entry is written in DirObjInformation;
98 * otherwise as many as will fit in the buffer.
101 * If TRUE start reading at index 0.
102 * If FALSE start reading at the index specified
103 * by object index *ObjectIndex.
106 * Zero based index into the directory, interpretation
107 * depends on RestartScan.
110 * Caller supplied storage for the number of bytes
118 * Changed 4th, and 5th parameter names after
119 * G.Nebbett "WNT/W2k Native API Reference".
123 NtQueryDirectoryObject (IN HANDLE DirectoryHandle
,
125 IN ULONG BufferLength
,
126 IN BOOLEAN ReturnSingleEntry
,
127 IN BOOLEAN RestartScan
,
128 IN OUT PULONG Context
,
129 OUT PULONG ReturnLength OPTIONAL
)
131 PDIRECTORY_OBJECT dir
= NULL
;
132 PLIST_ENTRY current_entry
= NULL
;
133 POBJECT_HEADER current
= NULL
;
135 NTSTATUS Status
= STATUS_SUCCESS
;
136 ULONG DirectoryCount
= 0;
137 ULONG DirectorySize
= 0;
138 ULONG SpaceLeft
= BufferLength
;
139 ULONG SpaceRequired
= 0;
140 ULONG NameLength
= 0;
141 ULONG TypeNameLength
= 0;
142 PDIRECTORY_BASIC_INFORMATION current_odi
= (PDIRECTORY_BASIC_INFORMATION
) Buffer
;
143 PUCHAR FirstFree
= (PUCHAR
) Buffer
;
146 DPRINT("NtQueryDirectoryObject(DirectoryHandle %x)\n", DirectoryHandle
);
148 /* FIXME: if previous mode == user, use ProbeForWrite
151 /* Check Context is not NULL */
154 return (STATUS_INVALID_PARAMETER
);
157 /* Reference the DIRECTORY_OBJECT */
158 Status
= ObReferenceObjectByHandle(DirectoryHandle
,
164 if (!NT_SUCCESS(Status
))
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 (DIRECTORY_BASIC_INFORMATION
);
190 if (DirectorySize
> SpaceLeft
)
192 ObDereferenceObject(dir
);
193 return (STATUS_BUFFER_TOO_SMALL
);
196 * Optionally, skip over some entries at the start of the directory
197 * (use *ObjectIndex value)
199 current_entry
= dir
->head
.Flink
;
200 if (FALSE
== RestartScan
)
202 /* RestartScan == FALSE */
203 register ULONG EntriesToSkip
= *Context
;
208 ((EntriesToSkip
--) && (current_entry
!= & dir
->head
));
209 current_entry
= current_entry
->Flink
211 if ((EntriesToSkip
) && (current_entry
== & dir
->head
))
213 ObDereferenceObject(dir
);
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 ObDereferenceObject(dir
);
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 ObDereferenceObject(dir
);
265 return (STATUS_BUFFER_TOO_SMALL
);
268 * Copy the current directory entry's data into the buffer
269 * and update the OBJDIR_INFORMATION entry in the array.
271 /* --- Object's name --- */
272 current_odi
->ObjectName
.Length
= NameLength
;
273 current_odi
->ObjectName
.MaximumLength
= (NameLength
+ sizeof (WCHAR
));
274 current_odi
->ObjectName
.Buffer
= (PWCHAR
) FirstFree
;
275 wcscpy ((PWCHAR
) FirstFree
, current
->Name
.Buffer
);
276 FirstFree
+= (current_odi
->ObjectName
.MaximumLength
);
277 /* --- Object type's name --- */
278 current_odi
->ObjectTypeName
.Length
= TypeNameLength
;
279 current_odi
->ObjectTypeName
.MaximumLength
= (TypeNameLength
+ sizeof (WCHAR
));
280 current_odi
->ObjectTypeName
.Buffer
= (PWCHAR
) FirstFree
;
281 wcscpy ((PWCHAR
) FirstFree
, current
->ObjectType
->TypeName
.Buffer
);
282 FirstFree
+= (current_odi
->ObjectTypeName
.MaximumLength
);
283 /* Next entry in the array */
285 /* Decrease the space left count */
286 SpaceLeft
-= SpaceRequired
;
287 /* Increase the object index number */
289 /* Next object in the directory */
290 current_entry
= current_entry
->Flink
;
292 } while (FALSE
== ReturnSingleEntry
);
294 * Store current index in Context
296 *Context
+= DirectoryCount
;
298 * Report to the caller how much bytes
299 * we wrote in the user buffer.
301 if (NULL
!= ReturnLength
)
303 *ReturnLength
= (BufferLength
- SpaceLeft
);
305 ObDereferenceObject(dir
);
306 return (STATUS_SUCCESS
);
310 /**********************************************************************
311 * NAME (EXPORTED as Zw)
312 * NtCreateDirectoryObject
315 * Creates or opens a directory object (a container for other
319 * DirectoryHandle (OUT)
320 * Caller supplied storage for the handle of the
324 * Access desired to the directory.
327 * Object attributes initialized with
328 * InitializeObjectAttributes.
334 NtCreateDirectoryObject (OUT PHANDLE DirectoryHandle
,
335 IN ACCESS_MASK DesiredAccess
,
336 IN POBJECT_ATTRIBUTES ObjectAttributes
)
338 PDIRECTORY_OBJECT DirectoryObject
;
341 DPRINT("NtCreateDirectoryObject(DirectoryHandle %x, "
342 "DesiredAccess %x, ObjectAttributes %x, "
343 "ObjectAttributes->ObjectName %wZ)\n",
344 DirectoryHandle
, DesiredAccess
, ObjectAttributes
,
345 ObjectAttributes
->ObjectName
);
347 Status
= ObCreateObject (ExGetPreviousMode(),
352 sizeof(DIRECTORY_OBJECT
),
355 (PVOID
*)&DirectoryObject
);
356 if (!NT_SUCCESS(Status
))
361 Status
= ObInsertObject ((PVOID
)DirectoryObject
,
368 ObDereferenceObject(DirectoryObject
);