2004-08-15 Casper S. Hornstrup <chorns@users.sourceforge.net>
[reactos.git] / reactos / ntoskrnl / ob / dirobj.c
1 /* $Id: dirobj.c,v 1.23 2004/08/15 16:39:09 chorns Exp $
2 *
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)
8 * UPDATE HISTORY:
9 * 22/05/98: Created
10 */
11
12 /* INCLUDES ***************************************************************/
13
14 #include <ntoskrnl.h>
15 #define NDEBUG
16 #include <internal/debug.h>
17
18
19 /* FUNCTIONS **************************************************************/
20
21
22 /**********************************************************************
23 * NAME EXPORTED
24 * NtOpenDirectoryObject
25 *
26 * DESCRIPTION
27 * Opens a namespace directory object.
28 *
29 * ARGUMENTS
30 * DirectoryHandle (OUT)
31 * Variable which receives the directory handle.
32 *
33 * DesiredAccess
34 * Desired access to the directory.
35 *
36 * ObjectAttributes
37 * Structure describing the directory.
38 *
39 * RETURN VALUE
40 * Status.
41 *
42 * NOTES
43 * Undocumented.
44 */
45 NTSTATUS STDCALL
46 NtOpenDirectoryObject (OUT PHANDLE DirectoryHandle,
47 IN ACCESS_MASK DesiredAccess,
48 IN POBJECT_ATTRIBUTES ObjectAttributes)
49 {
50 PVOID Object;
51 NTSTATUS Status;
52
53 *DirectoryHandle = 0;
54
55 Status = ObReferenceObjectByName(ObjectAttributes->ObjectName,
56 ObjectAttributes->Attributes,
57 NULL,
58 DesiredAccess,
59 ObDirectoryType,
60 UserMode,
61 NULL,
62 &Object);
63 if (!NT_SUCCESS(Status))
64 {
65 return Status;
66 }
67
68 Status = ObCreateHandle(PsGetCurrentProcess(),
69 Object,
70 DesiredAccess,
71 FALSE,
72 DirectoryHandle);
73 return STATUS_SUCCESS;
74 }
75
76
77 /**********************************************************************
78 * NAME EXPORTED
79 * NtQueryDirectoryObject
80 *
81 * DESCRIPTION
82 * Reads information from a directory in the system namespace.
83 *
84 * ARGUMENTS
85 * DirectoryHandle
86 * Handle, obtained with NtOpenDirectoryObject(), which
87 * must grant DIRECTORY_QUERY access to the directory
88 * object.
89 *
90 * Buffer (OUT)
91 * Buffer to hold the data read.
92 *
93 * BufferLength
94 * Size of the buffer in bytes.
95 *
96 * ReturnSingleEntry
97 * When TRUE, only 1 entry is written in DirObjInformation;
98 * otherwise as many as will fit in the buffer.
99 *
100 * RestartScan
101 * If TRUE start reading at index 0.
102 * If FALSE start reading at the index specified
103 * by object index *ObjectIndex.
104 *
105 * Context
106 * Zero based index into the directory, interpretation
107 * depends on RestartScan.
108 *
109 * ReturnLength (OUT)
110 * Caller supplied storage for the number of bytes
111 * written (or NULL).
112 *
113 * RETURN VALUE
114 * Status.
115 *
116 * REVISIONS
117 * 2001-05-01 (ea)
118 * Changed 4th, and 5th parameter names after
119 * G.Nebbett "WNT/W2k Native API Reference".
120 * Mostly rewritten.
121 */
122 NTSTATUS STDCALL
123 NtQueryDirectoryObject (IN HANDLE DirectoryHandle,
124 OUT PVOID Buffer,
125 IN ULONG BufferLength,
126 IN BOOLEAN ReturnSingleEntry,
127 IN BOOLEAN RestartScan,
128 IN OUT PULONG Context,
129 OUT PULONG ReturnLength OPTIONAL)
130 {
131 PDIRECTORY_OBJECT dir = NULL;
132 PLIST_ENTRY current_entry = NULL;
133 POBJECT_HEADER current = NULL;
134 ULONG i = 0;
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;
144
145
146 DPRINT("NtQueryDirectoryObject(DirectoryHandle %x)\n", DirectoryHandle);
147
148 /* FIXME: if previous mode == user, use ProbeForWrite
149 * on user params. */
150
151 /* Check Context is not NULL */
152 if (NULL == Context)
153 {
154 return (STATUS_INVALID_PARAMETER);
155 }
156
157 /* Reference the DIRECTORY_OBJECT */
158 Status = ObReferenceObjectByHandle(DirectoryHandle,
159 DIRECTORY_QUERY,
160 ObDirectoryType,
161 UserMode,
162 (PVOID*)&dir,
163 NULL);
164 if (!NT_SUCCESS(Status))
165 {
166 return (Status);
167 }
168
169 /*
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.
173 */
174 if (FALSE == ReturnSingleEntry)
175 {
176 for ( current_entry = dir->head.Flink;
177 (current_entry != & dir->head);
178 current_entry = current_entry->Flink
179 )
180 {
181 ++ DirectoryCount;
182 }
183 }
184 else
185 {
186 DirectoryCount = 1;
187 }
188 // count is DirectoryCount + one null entry
189 DirectorySize = (DirectoryCount + 1) * sizeof (DIRECTORY_BASIC_INFORMATION);
190 if (DirectorySize > SpaceLeft)
191 {
192 ObDereferenceObject(dir);
193 return (STATUS_BUFFER_TOO_SMALL);
194 }
195 /*
196 * Optionally, skip over some entries at the start of the directory
197 * (use *ObjectIndex value)
198 */
199 current_entry = dir->head.Flink;
200 if (FALSE == RestartScan)
201 {
202 /* RestartScan == FALSE */
203 register ULONG EntriesToSkip = *Context;
204
205 CHECKPOINT;
206
207 for ( ;
208 ((EntriesToSkip --) && (current_entry != & dir->head));
209 current_entry = current_entry->Flink
210 );
211 if ((EntriesToSkip) && (current_entry == & dir->head))
212 {
213 ObDereferenceObject(dir);
214 return (STATUS_NO_MORE_ENTRIES);
215 }
216 }
217 /*
218 * Initialize the array of OBJDIR_INFORMATION.
219 */
220 RtlZeroMemory (FirstFree, DirectorySize);
221 /*
222 * Move FirstFree to point to the Unicode strings area
223 */
224 FirstFree += DirectorySize;
225 /*
226 * Compute how much space is left after allocating the
227 * array in the user buffer.
228 */
229 SpaceLeft -= DirectorySize;
230 /* Scan the directory */
231 do
232 {
233 /*
234 * Check if we reached the end of the directory.
235 */
236 if (current_entry == & dir->head)
237 {
238 /* Any data? */
239 if (i) break; /* DONE */
240 /* FIXME: better error handling here! */
241 ObDereferenceObject(dir);
242 return (STATUS_NO_MORE_ENTRIES);
243 }
244 /*
245 * Compute the current OBJECT_HEADER memory
246 * object's address.
247 */
248 current = CONTAINING_RECORD(current_entry, OBJECT_HEADER, Entry);
249 /*
250 * Compute the space required in the user buffer to copy
251 * the data from the current object:
252 *
253 * Name (WCHAR) 0 TypeName (WCHAR) 0
254 */
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);
259 /*
260 * Check for free space in the user buffer.
261 */
262 if (SpaceRequired > SpaceLeft)
263 {
264 ObDereferenceObject(dir);
265 return (STATUS_BUFFER_TOO_SMALL);
266 }
267 /*
268 * Copy the current directory entry's data into the buffer
269 * and update the OBJDIR_INFORMATION entry in the array.
270 */
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 */
284 ++ current_odi;
285 /* Decrease the space left count */
286 SpaceLeft -= SpaceRequired;
287 /* Increase the object index number */
288 ++ i;
289 /* Next object in the directory */
290 current_entry = current_entry->Flink;
291
292 } while (FALSE == ReturnSingleEntry);
293 /*
294 * Store current index in Context
295 */
296 *Context += DirectoryCount;
297 /*
298 * Report to the caller how much bytes
299 * we wrote in the user buffer.
300 */
301 if (NULL != ReturnLength)
302 {
303 *ReturnLength = (BufferLength - SpaceLeft);
304 }
305 ObDereferenceObject(dir);
306 return (STATUS_SUCCESS);
307 }
308
309
310 /**********************************************************************
311 * NAME (EXPORTED as Zw)
312 * NtCreateDirectoryObject
313 *
314 * DESCRIPTION
315 * Creates or opens a directory object (a container for other
316 * objects).
317 *
318 * ARGUMENTS
319 * DirectoryHandle (OUT)
320 * Caller supplied storage for the handle of the
321 * directory.
322 *
323 * DesiredAccess
324 * Access desired to the directory.
325 *
326 * ObjectAttributes
327 * Object attributes initialized with
328 * InitializeObjectAttributes.
329 *
330 * RETURN VALUE
331 * Status.
332 */
333 NTSTATUS STDCALL
334 NtCreateDirectoryObject (OUT PHANDLE DirectoryHandle,
335 IN ACCESS_MASK DesiredAccess,
336 IN POBJECT_ATTRIBUTES ObjectAttributes)
337 {
338 PDIRECTORY_OBJECT DirectoryObject;
339 NTSTATUS Status;
340
341 DPRINT("NtCreateDirectoryObject(DirectoryHandle %x, "
342 "DesiredAccess %x, ObjectAttributes %x, "
343 "ObjectAttributes->ObjectName %wZ)\n",
344 DirectoryHandle, DesiredAccess, ObjectAttributes,
345 ObjectAttributes->ObjectName);
346
347 Status = ObCreateObject (ExGetPreviousMode(),
348 ObDirectoryType,
349 ObjectAttributes,
350 ExGetPreviousMode(),
351 NULL,
352 sizeof(DIRECTORY_OBJECT),
353 0,
354 0,
355 (PVOID*)&DirectoryObject);
356 if (!NT_SUCCESS(Status))
357 {
358 return Status;
359 }
360
361 Status = ObInsertObject ((PVOID)DirectoryObject,
362 NULL,
363 DesiredAccess,
364 0,
365 NULL,
366 DirectoryHandle);
367
368 ObDereferenceObject(DirectoryObject);
369
370 return Status;
371 }
372
373 /* EOF */