+ntoskrnl/ke/mutex.c
[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 #ifndef LIBCAPTIVE
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 NtOpenDirectoryObject(PHANDLE DirectoryHandle,
50                                        ACCESS_MASK DesiredAccess,
51                                        POBJECT_ATTRIBUTES ObjectAttributes)
52 {
53    PVOID Object;
54    NTSTATUS Status;
55
56    *DirectoryHandle = 0;
57    
58    Status = ObReferenceObjectByName(ObjectAttributes->ObjectName,
59                                     ObjectAttributes->Attributes,
60                                     NULL,
61                                     DesiredAccess,
62                                     ObDirectoryType,
63                                     UserMode,
64                                     NULL,
65                                     &Object);
66    if (!NT_SUCCESS(Status))
67      {
68         return Status;
69      }
70    
71    Status = ObCreateHandle(PsGetCurrentProcess(),
72                            Object,
73                            DesiredAccess,
74                            FALSE,
75                            DirectoryHandle);
76    return STATUS_SUCCESS;
77 }
78
79
80 /**********************************************************************
81  * NAME                                                 EXPORTED
82  *      NtQueryDirectoryObject
83  * 
84  * DESCRIPTION
85  *      Reads information from a directory in the system namespace.
86  *      
87  * ARGUMENTS
88  *      DirObjHandle
89  *              Handle, obtained with NtOpenDirectoryObject(), which
90  *              must grant DIRECTORY_QUERY access to the directory
91  *              object.
92  *              
93  *      DirObjInformation (OUT)
94  *              Buffer to hold the data read.
95  *              
96  *      BufferLength
97  *              Size of the buffer in bytes.
98  *              
99  *      ReturnSingleEntry
100  *              When TRUE, only 1 entry is written in DirObjInformation;
101  *              otherwise as many as will fit in the buffer.
102  *              
103  *      RestartScan
104  *              If TRUE start reading at index 0.
105  *              If FALSE start reading at the index specified
106  *              by object index *ObjectIndex.
107  *              
108  *      ObjectIndex
109  *              Zero based index into the directory, interpretation
110  *              depends on RestartScan.
111  *              
112  *      DataWritten (OUT)
113  *              Caller supplied storage for the number of bytes
114  *              written (or NULL).
115  *
116  * RETURN VALUE
117  *      Status.
118  *
119  * REVISIONS
120  *      2001-05-01 (ea)
121  *              Changed 4th, and 5th parameter names after
122  *              G.Nebbett "WNT/W2k Native API Reference".
123  *              Mostly rewritten.
124  */
125 NTSTATUS STDCALL NtQueryDirectoryObject (IN HANDLE DirObjHandle,
126                                          OUT POBJDIR_INFORMATION 
127                                                     DirObjInformation, 
128                                          IN ULONG BufferLength, 
129                                          IN BOOLEAN ReturnSingleEntry,
130                                          IN BOOLEAN RestartScan, 
131                                          IN OUT PULONG ObjectIndex,
132                                          OUT PULONG DataWritten OPTIONAL)
133 {
134     PDIRECTORY_OBJECT   dir = NULL;
135     PLIST_ENTRY         current_entry = NULL;
136     POBJECT_HEADER      current = NULL;
137     ULONG               i = 0;
138     NTSTATUS            Status = STATUS_SUCCESS;
139     DWORD               DirectoryCount = 0;
140     DWORD               DirectorySize = 0;
141     ULONG               SpaceLeft = BufferLength;
142     ULONG               SpaceRequired = 0;
143     ULONG               NameLength = 0;
144     ULONG               TypeNameLength = 0;
145     POBJDIR_INFORMATION current_odi = DirObjInformation;
146     PBYTE               FirstFree = (PBYTE) DirObjInformation;
147
148
149     DPRINT("NtQueryDirectoryObject(DirObjHandle %x)\n", DirObjHandle);
150
151     /* FIXME: if previous mode == user, use ProbeForWrite
152      * on user params. */
153
154     /* Reference the DIRECTORY_OBJECT */
155     Status = ObReferenceObjectByHandle(DirObjHandle,
156                                       DIRECTORY_QUERY,
157                                       ObDirectoryType,
158                                       UserMode,
159                                       (PVOID*)&dir,
160                                       NULL);
161     if (!NT_SUCCESS(Status))
162       {
163         return (Status);
164       }
165     /* Check ObjectIndex is not NULL */
166     if (NULL == ObjectIndex)
167       {
168         return (STATUS_INVALID_PARAMETER);
169       }
170     /*
171      * Compute the number of directory entries
172      * and the size of the array (in bytes).
173      * One more entry marks the end of the array.
174      */
175     if (FALSE == ReturnSingleEntry)
176     {
177         for ( current_entry = dir->head.Flink;
178               (current_entry != & dir->head);
179               current_entry = current_entry->Flink
180               )
181         {
182           ++ DirectoryCount;
183         }
184     }
185     else
186     {
187         DirectoryCount = 1;
188     }
189     // count is DirectoryCount + one null entry
190     DirectorySize = (DirectoryCount + 1) * sizeof (OBJDIR_INFORMATION);
191     if (DirectorySize > SpaceLeft)
192     {
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 = *ObjectIndex;
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             return (STATUS_NO_MORE_ENTRIES);
214           }
215       }
216     /*
217      * Initialize the array of OBJDIR_INFORMATION.
218      */
219     RtlZeroMemory (FirstFree, DirectorySize);
220     /*
221      * Move FirstFree to point to the Unicode strings area
222      */
223     FirstFree += DirectorySize;
224     /*
225      * Compute how much space is left after allocating the
226      * array in the user buffer.
227      */
228     SpaceLeft -= DirectorySize;
229     /* Scan the directory */
230     do
231     { 
232         /*
233          * Check if we reached the end of the directory.
234          */
235         if (current_entry == & dir->head)
236           {
237       /* Any data? */
238             if (i) break; /* DONE */
239             /* FIXME: better error handling here! */
240             return (STATUS_NO_MORE_ENTRIES);
241           }
242   /*
243          * Compute the current OBJECT_HEADER memory
244          * object's address.
245          */
246    current = CONTAINING_RECORD(current_entry, OBJECT_HEADER, Entry);
247   /*
248    * Compute the space required in the user buffer to copy
249    * the data from the current object:
250          *
251          * Name (WCHAR) 0 TypeName (WCHAR) 0
252    */
253         NameLength = (wcslen (current->Name.Buffer) * sizeof (WCHAR));
254         TypeNameLength = (wcslen (current->ObjectType->TypeName.Buffer) * sizeof (WCHAR));
255   SpaceRequired = (NameLength + 1) * sizeof (WCHAR)
256     + (TypeNameLength + 1) * sizeof (WCHAR);
257         /*
258          * Check for free space in the user buffer.
259          */
260         if (SpaceRequired > SpaceLeft)
261         {
262                 return (STATUS_BUFFER_TOO_SMALL);
263         }
264   /*
265    * Copy the current directory entry's data into the buffer
266          * and update the OBJDIR_INFORMATION entry in the array.
267    */
268         /* --- Object's name --- */
269         current_odi->ObjectName.Length        = NameLength;
270         current_odi->ObjectName.MaximumLength = (NameLength + sizeof (WCHAR));
271         current_odi->ObjectName.Buffer        = (PWCHAR) FirstFree;
272         wcscpy ((PWCHAR) FirstFree, current->Name.Buffer);
273         FirstFree += (current_odi->ObjectName.MaximumLength);
274         /* --- Object type's name --- */
275         current_odi->ObjectTypeName.Length        = TypeNameLength;
276         current_odi->ObjectTypeName.MaximumLength = (TypeNameLength + sizeof (WCHAR));
277         current_odi->ObjectTypeName.Buffer        = (PWCHAR) FirstFree;
278         wcscpy ((PWCHAR) FirstFree, current->ObjectType->TypeName.Buffer);
279         FirstFree += (current_odi->ObjectTypeName.MaximumLength);
280         /* Next entry in the array */
281         ++ current_odi;
282         /* Decrease the space left count */     
283         SpaceLeft -= SpaceRequired;
284         /* Increase the object index number */
285         ++ i;
286         /* Next object in the directory */
287         current_entry = current_entry->Flink;
288
289     } while (FALSE == ReturnSingleEntry);
290     /*
291      * Store current index in ObjectIndex
292      */
293     *ObjectIndex += DirectoryCount;
294     /*
295      * Report to the caller how much bytes
296      * we wrote in the user buffer.
297      */
298     if (NULL != DataWritten) 
299       {
300         *DataWritten = (BufferLength - SpaceLeft);
301       }
302     return (STATUS_SUCCESS);
303 }
304
305 #endif /* LIBCAPTIVE */
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(PHANDLE DirectoryHandle,
332                         ACCESS_MASK DesiredAccess,
333                         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(ObCreateObject(DirectoryHandle,
344                          DesiredAccess,
345                          ObjectAttributes,
346                          ObDirectoryType,
347                          (PVOID*)&dir));
348 }
349
350 /* EOF */