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