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