:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[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 #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     // count is DirectoryCount + one null entry
189     DirectorySize = (DirectoryCount + 1) * sizeof (OBJDIR_INFORMATION);
190     if (DirectorySize > SpaceLeft)
191     {
192         return (STATUS_BUFFER_TOO_SMALL);
193     }
194     /*
195      * Optionally, skip over some entries at the start of the directory
196      * (use *ObjectIndex value)
197      */
198     current_entry = dir->head.Flink;
199     if (FALSE == RestartScan)
200       {
201         /* RestartScan == FALSE */
202         register ULONG EntriesToSkip = *ObjectIndex;
203
204         CHECKPOINT;
205         
206         for (   ;
207                 ((EntriesToSkip --) && (current_entry != & dir->head));
208                 current_entry = current_entry->Flink
209                 );
210         if ((EntriesToSkip) && (current_entry == & dir->head))
211           {
212             return (STATUS_NO_MORE_ENTRIES);
213           }
214       }
215     /*
216      * Initialize the array of OBJDIR_INFORMATION.
217      */
218     RtlZeroMemory (FirstFree, DirectorySize);
219     /*
220      * Move FirstFree to point to the Unicode strings area
221      */
222     FirstFree += DirectorySize;
223     /*
224      * Compute how much space is left after allocating the
225      * array in the user buffer.
226      */
227     SpaceLeft -= DirectorySize;
228     /* Scan the directory */
229     do
230     { 
231         /*
232          * Check if we reached the end of the directory.
233          */
234         if (current_entry == & dir->head)
235           {
236       /* Any data? */
237             if (i) break; /* DONE */
238             /* FIXME: better error handling here! */
239             return (STATUS_NO_MORE_ENTRIES);
240           }
241   /*
242          * Compute the current OBJECT_HEADER memory
243          * object's address.
244          */
245    current = CONTAINING_RECORD(current_entry, OBJECT_HEADER, Entry);
246   /*
247    * Compute the space required in the user buffer to copy
248    * the data from the current object:
249          *
250          * Name (WCHAR) 0 TypeName (WCHAR) 0
251    */
252         NameLength = (wcslen (current->Name.Buffer) * sizeof (WCHAR));
253         TypeNameLength = (wcslen (current->ObjectType->TypeName.Buffer) * sizeof (WCHAR));
254   SpaceRequired = (NameLength + 1) * sizeof (WCHAR)
255     + (TypeNameLength + 1) * sizeof (WCHAR);
256         /*
257          * Check for free space in the user buffer.
258          */
259         if (SpaceRequired > SpaceLeft)
260         {
261                 return (STATUS_BUFFER_TOO_SMALL);
262         }
263   /*
264    * Copy the current directory entry's data into the buffer
265          * and update the OBJDIR_INFORMATION entry in the array.
266    */
267         /* --- Object's name --- */
268         current_odi->ObjectName.Length        = NameLength;
269         current_odi->ObjectName.MaximumLength = (NameLength + sizeof (WCHAR));
270         current_odi->ObjectName.Buffer        = (PWCHAR) FirstFree;
271         wcscpy ((PWCHAR) FirstFree, current->Name.Buffer);
272         FirstFree += (current_odi->ObjectName.MaximumLength);
273         /* --- Object type's name --- */
274         current_odi->ObjectTypeName.Length        = TypeNameLength;
275         current_odi->ObjectTypeName.MaximumLength = (TypeNameLength + sizeof (WCHAR));
276         current_odi->ObjectTypeName.Buffer        = (PWCHAR) FirstFree;
277         wcscpy ((PWCHAR) FirstFree, current->ObjectType->TypeName.Buffer);
278         FirstFree += (current_odi->ObjectTypeName.MaximumLength);
279         /* Next entry in the array */
280         ++ current_odi;
281         /* Decrease the space left count */     
282         SpaceLeft -= SpaceRequired;
283         /* Increase the object index number */
284         ++ i;
285         /* Next object in the directory */
286         current_entry = current_entry->Flink;
287
288     } while (FALSE == ReturnSingleEntry);
289     /*
290      * Store current index in ObjectIndex
291      */
292     *ObjectIndex += DirectoryCount;
293     /*
294      * Report to the caller how much bytes
295      * we wrote in the user buffer.
296      */
297     if (NULL != DataWritten) 
298       {
299         *DataWritten = (BufferLength - SpaceLeft);
300       }
301     return (STATUS_SUCCESS);
302 }
303
304
305 /**********************************************************************
306  * NAME                                         (EXPORTED as Zw)
307  *      NtCreateDirectoryObject
308  *      
309  * DESCRIPTION
310  *      Creates or opens a directory object (a container for other
311  *      objects).
312  *      
313  * ARGUMENTS
314  *      DirectoryHandle (OUT)
315  *              Caller supplied storage for the handle of the 
316  *              directory.
317  *              
318  *      DesiredAccess
319  *              Access desired to the directory.
320  *              
321  *      ObjectAttributes
322  *              Object attributes initialized with
323  *              InitializeObjectAttributes.
324  *              
325  * RETURN VALUE
326  *      Status.
327  */
328 NTSTATUS STDCALL
329 NtCreateDirectoryObject(PHANDLE DirectoryHandle,
330                         ACCESS_MASK DesiredAccess,
331                         POBJECT_ATTRIBUTES ObjectAttributes)
332 {
333    PDIRECTORY_OBJECT dir;
334
335    DPRINT("NtCreateDirectoryObject(DirectoryHandle %x, "
336           "DesiredAccess %x, ObjectAttributes %x, "
337           "ObjectAttributes->ObjectName %S)\n",
338           DirectoryHandle, DesiredAccess, ObjectAttributes,
339           ObjectAttributes->ObjectName);
340    
341    return(ObCreateObject(DirectoryHandle,
342                          DesiredAccess,
343                          ObjectAttributes,
344                          ObDirectoryType,
345                          (PVOID*)&dir));
346 }
347
348 /* EOF */