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