bd876a9e72277abaaa3061c3185c0ea5f3ecb89e
[reactos.git] / reactos / ntoskrnl / ob / namespc.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ob/namespc.c
5 * PURPOSE: Manages the system namespace
6 * PROGRAMMER: David Welch (welch@mcmail.com)
7 * UPDATE HISTORY:
8 * 22/05/98: Created
9 */
10
11 /* INCLUDES ***************************************************************/
12
13 #include <windows.h>
14 #include <wstring.h>
15 #include <ddk/ntddk.h>
16 #include <internal/ob.h>
17 #include <internal/io.h>
18 #include <internal/string.h>
19
20 #define NDEBUG
21 #include <internal/debug.h>
22
23 /* GLOBALS ****************************************************************/
24
25 OBJECT_TYPE DirectoryObjectType = {{0,0,NULL},
26 0,
27 0,
28 ULONG_MAX,
29 ULONG_MAX,
30 sizeof(DIRECTORY_OBJECT),
31 0,
32 NULL,
33 NULL,
34 NULL,
35 NULL,
36 NULL,
37 NULL,
38 NULL,
39 NULL,
40 };
41
42
43 static struct
44 {
45 OBJECT_HEADER hdr;
46 // DIRECTORY_OBJECT directory;
47 LIST_ENTRY head;
48 KSPIN_LOCK Lock;
49 } namespc_root = {{0,},};
50
51 /* FUNCTIONS **************************************************************/
52
53 NTSTATUS ZwOpenDirectoryObject(PHANDLE DirectoryHandle,
54 ACCESS_MASK DesiredAccess,
55 POBJECT_ATTRIBUTES ObjectAttributes)
56 /*
57 * FUNCTION: Opens a namespace directory object
58 * ARGUMENTS:
59 * DirectoryHandle (OUT) = Variable which receives the directory handle
60 * DesiredAccess = Desired access to the directory
61 * ObjectAttributes = Structure describing the directory
62 * RETURNS: Status
63 * NOTES: Undocumented
64 */
65 {
66 PVOID Object;
67 NTSTATUS Status;
68 PWSTR Ignored;
69
70 *DirectoryHandle = 0;
71
72 Status = ObOpenObjectByName(ObjectAttributes,&Object,&Ignored);
73 if (!NT_SUCCESS(Status))
74 {
75 return(Status);
76 }
77
78 if (BODY_TO_HEADER(Object)->Type!=OBJTYP_DIRECTORY)
79 {
80 return(STATUS_UNSUCCESSFUL);
81 }
82
83 *DirectoryHandle = ObAddHandle(Object);
84 CHECKPOINT;
85 return(STATUS_SUCCESS);
86 }
87
88 NTSTATUS ZwQueryDirectoryObject(IN HANDLE DirObjHandle,
89 OUT POBJDIR_INFORMATION DirObjInformation,
90 IN ULONG BufferLength,
91 IN BOOLEAN GetNextIndex,
92 IN BOOLEAN IgnoreInputIndex,
93 IN OUT PULONG ObjectIndex,
94 OUT PULONG DataWritten OPTIONAL)
95 /*
96 * FUNCTION: Reads information from a namespace directory
97 * ARGUMENTS:
98 * DirObjInformation (OUT) = Buffer to hold the data read
99 * BufferLength = Size of the buffer in bytes
100 * GetNextIndex = If TRUE then set ObjectIndex to the index of the
101 * next object
102 * If FALSE then set ObjectIndex to the number of
103 * objects in the directory
104 * IgnoreInputIndex = If TRUE start reading at index 0
105 * If FALSE start reading at the index specified
106 * by object index
107 * ObjectIndex = Zero based index into the directory, interpretation
108 * depends on IgnoreInputIndex and GetNextIndex
109 * DataWritten (OUT) = Caller supplied storage for the number of bytes
110 * written (or NULL)
111 * RETURNS: Status
112 */
113 {
114 COMMON_BODY_HEADER* hdr = ObGetObjectByHandle(DirObjHandle);
115 PDIRECTORY_OBJECT dir = (PDIRECTORY_OBJECT)hdr;
116 ULONG EntriesToRead;
117 PLIST_ENTRY current_entry;
118 POBJECT_HEADER current;
119 ULONG i=0;
120 ULONG EntriesToSkip;
121
122 DPRINT("ZwQueryDirectoryObject(DirObjHandle %x)\n",DirObjHandle);
123 DPRINT("dir %x namespc_root %x\n",dir,HEADER_TO_BODY(&(namespc_root.hdr)));
124
125 assert_irql(PASSIVE_LEVEL);
126
127 EntriesToRead = BufferLength / sizeof(OBJDIR_INFORMATION);
128 *DataWritten = 0;
129
130 DPRINT("EntriesToRead %d\n",EntriesToRead);
131
132 current_entry = dir->head.Flink;
133
134 /*
135 * Optionally, skip over some entries at the start of the directory
136 */
137 if (!IgnoreInputIndex)
138 {
139 CHECKPOINT;
140
141 EntriesToSkip = *ObjectIndex;
142 while ( i<EntriesToSkip && current_entry!=NULL)
143 {
144 current_entry = current_entry->Flink;
145 }
146 }
147
148 DPRINT("DirObjInformation %x\n",DirObjInformation);
149
150 /*
151 * Read the maximum entries possible into the buffer
152 */
153 while ( i<EntriesToRead && current_entry!=(&(dir->head)))
154 {
155 current = CONTAINING_RECORD(current_entry,OBJECT_HEADER,entry);
156 DPRINT("Scanning %w\n",current->name.Buffer);
157 DirObjInformation[i].ObjectName.Buffer =
158 ExAllocatePool(NonPagedPool,current->name.Length);
159 DirObjInformation[i].ObjectName.Length = current->name.Length;
160 DirObjInformation[i].ObjectName.MaximumLength = current->name.Length;
161 DPRINT("DirObjInformation[i].ObjectName.Buffer %x\n",
162 DirObjInformation[i].ObjectName.Buffer);
163 RtlCopyUnicodeString(&DirObjInformation[i].ObjectName,
164 &(current->name));
165 i++;
166 current_entry = current_entry->Flink;
167 (*DataWritten) = (*DataWritten) + sizeof(OBJDIR_INFORMATION);
168 CHECKPOINT;
169 }
170 CHECKPOINT;
171
172 /*
173 * Optionally, count the number of entries in the directory
174 */
175 if (GetNextIndex)
176 {
177 *ObjectIndex=i;
178 }
179 else
180 {
181 while ( current_entry!=(&(dir->head)) )
182 {
183 current_entry=current_entry->Flink;
184 i++;
185 }
186 *ObjectIndex=i;
187 }
188 return(STATUS_SUCCESS);
189 }
190
191
192 NTSTATUS ObReferenceObjectByName(PUNICODE_STRING ObjectPath,
193 ULONG Attributes,
194 PACCESS_STATE PassedAccessState,
195 ACCESS_MASK DesiredAccess,
196 POBJECT_TYPE ObjectType,
197 KPROCESSOR_MODE Accessmode,
198 PVOID ParseContext,
199 PVOID* ObjectPtr)
200 {
201 UNIMPLEMENTED;
202 }
203
204 NTSTATUS ObOpenObjectByName(POBJECT_ATTRIBUTES ObjectAttributes,
205 PVOID* Object, PWSTR* UnparsedSection)
206 {
207 NTSTATUS Status;
208
209 DPRINT("ObOpenObjectByName(ObjectAttributes %x, Object %x)\n",
210 ObjectAttributes,Object);
211 DPRINT("ObjectAttributes = {ObjectName %x ObjectName->Buffer %w}\n",
212 ObjectAttributes->ObjectName,ObjectAttributes->ObjectName->Buffer);
213
214 *Object = NULL;
215 Status = ObLookupObject(ObjectAttributes->RootDirectory,
216 ObjectAttributes->ObjectName->Buffer,
217 Object,
218 UnparsedSection);
219 DPRINT("*Object %x\n",*Object);
220 return(Status);
221 }
222
223 void ObInit(void)
224 /*
225 * FUNCTION: Initialize the object manager namespace
226 */
227 {
228 ANSI_STRING ansi_str;
229
230 ObInitializeObjectHeader(OBJTYP_DIRECTORY,NULL,&namespc_root.hdr);
231 InitializeListHead(&namespc_root.head);
232
233 RtlInitAnsiString(&ansi_str,"Directory");
234 RtlAnsiStringToUnicodeString(&DirectoryObjectType.TypeName,&ansi_str,
235 TRUE);
236 ObRegisterType(OBJTYP_DIRECTORY,&DirectoryObjectType);
237 }
238
239 NTSTATUS ZwCreateDirectoryObject(PHANDLE DirectoryHandle,
240 ACCESS_MASK DesiredAccess,
241 POBJECT_ATTRIBUTES ObjectAttributes)
242 /*
243 * FUNCTION: Creates or opens a directory object (a container for other
244 * objects)
245 * ARGUMENTS:
246 * DirectoryHandle (OUT) = Caller supplied storage for the handle
247 * of the directory
248 * DesiredAccess = Access desired to the directory
249 * ObjectAttributes = Object attributes initialized with
250 * InitializeObjectAttributes
251 * RETURNS: Status
252 */
253 {
254 PDIRECTORY_OBJECT dir;
255
256 dir = ObGenericCreateObject(DirectoryHandle,DesiredAccess,ObjectAttributes,
257 OBJTYP_DIRECTORY);
258
259 /*
260 * Initialize the object body
261 */
262 InitializeListHead(&dir->head);
263 KeInitializeSpinLock(&(dir->Lock));
264
265 return(STATUS_SUCCESS);
266 }
267
268 VOID InitializeObjectAttributes(POBJECT_ATTRIBUTES InitializedAttributes,
269 PUNICODE_STRING ObjectName,
270 ULONG Attributes,
271 HANDLE RootDirectory,
272 PSECURITY_DESCRIPTOR SecurityDescriptor)
273 /*
274 * FUNCTION: Sets up a parameter of type OBJECT_ATTRIBUTES for a
275 * subsequent call to ZwCreateXXX or ZwOpenXXX
276 * ARGUMENTS:
277 * InitializedAttributes (OUT) = Caller supplied storage for the
278 * object attributes
279 * ObjectName = Full path name for object
280 * Attributes = Attributes for the object
281 * RootDirectory = Where the object should be placed or NULL
282 * SecurityDescriptor = Ignored
283 *
284 * NOTE:
285 * Either ObjectName is a fully qualified pathname or a path relative
286 * to RootDirectory
287 */
288 {
289 DPRINT("InitializeObjectAttributes(InitializedAttributes %x "
290 "ObjectName %x Attributes %x RootDirectory %x)\n",
291 InitializedAttributes,ObjectName,Attributes,RootDirectory);
292 InitializedAttributes->Length=sizeof(OBJECT_ATTRIBUTES);
293 InitializedAttributes->RootDirectory=RootDirectory;
294 InitializedAttributes->ObjectName=ObjectName;
295 InitializedAttributes->Attributes=Attributes;
296 InitializedAttributes->SecurityDescriptor=SecurityDescriptor;
297 InitializedAttributes->SecurityQualityOfService=NULL;
298 }
299
300 static PVOID ObDirLookup(PDIRECTORY_OBJECT dir, PWSTR name)
301 /*
302 * FUNCTION: Looks up an entry within a namespace directory
303 * ARGUMENTS:
304 * dir = Directory to lookup in
305 * name = Entry name to find
306 * RETURNS: A pointer to the object body if found
307 * NULL otherwise
308 */
309 {
310 LIST_ENTRY* current = dir->head.Flink;
311 POBJECT_HEADER current_obj;
312
313 DPRINT("ObDirLookup(dir %x, name %w)\n",dir,name);
314
315 if (name[0]==0)
316 {
317 return(dir);
318 }
319 if (name[0]=='.'&&name[1]==0)
320 {
321 return(dir);
322 }
323 if (name[0]=='.'&&name[1]=='.'&&name[2]==0)
324 {
325 return(BODY_TO_HEADER(dir)->Parent);
326 }
327 while (current!=(&(dir->head)))
328 {
329 current_obj = CONTAINING_RECORD(current,OBJECT_HEADER,entry);
330 DPRINT("Scanning %w\n",current_obj->name.Buffer);
331 if ( wcscmp(current_obj->name.Buffer, name)==0)
332 {
333 return(HEADER_TO_BODY(current_obj));
334 }
335 current = current->Flink;
336 }
337 DPRINT("%s() = NULL\n",__FUNCTION__);
338 return(NULL);
339 }
340
341
342 VOID ObCreateEntry(PDIRECTORY_OBJECT parent,POBJECT_HEADER Object)
343 /*
344 * FUNCTION: Add an entry to a namespace directory
345 * ARGUMENTS:
346 * parent = directory to add in
347 * name = Name to give the entry
348 * Object = Header of the object to add the entry for
349 */
350 {
351 DPRINT("ObjCreateEntry(%x,%x,%x,%w)\n",parent,Object,Object->name.Buffer,
352 Object->name.Buffer);
353 assert(parent->Type == OBJTYP_DIRECTORY);
354
355 /*
356 * Insert ourselves in our parents list
357 */
358 InsertTailList(&parent->head,&Object->entry);
359 }
360
361 NTSTATUS ObLookupObject(HANDLE rootdir, PWSTR string, PVOID* Object,
362 PWSTR* UnparsedSection)
363 /*
364 * FUNCTION: Lookup an object within the system namespc
365 * ARGUMENTS:
366 * root = Directory to start lookup from
367 * _string = Pathname to lookup
368 * RETURNS: On success a pointer to the object body
369 * On failure NULL
370 */
371 {
372 PWSTR current;
373 PWSTR next;
374 PDIRECTORY_OBJECT current_dir = NULL;
375 NTSTATUS Status;
376
377 DPRINT("ObLookupObject(rootdir %x, string %x, string %w, Object %x, "
378 "UnparsedSection %x)\n",rootdir,string,string,Object,
379 UnparsedSection);
380
381
382 *UnparsedSection = NULL;
383 *Object = NULL;
384
385 if (rootdir==NULL)
386 {
387 current_dir = HEADER_TO_BODY(&(namespc_root.hdr));
388 }
389 else
390 {
391 ObReferenceObjectByHandle(rootdir,DIRECTORY_TRAVERSE,NULL,
392 UserMode,(PVOID*)&current_dir,NULL);
393 }
394
395 /*
396 * Bit of a hack this
397 */
398 if (string[0]==0)
399 {
400 *Object=current_dir;
401 return(STATUS_SUCCESS);
402 }
403
404 if (string[0]!='\\')
405 {
406 DbgPrint("(%s:%d) Non absolute pathname passed to %s\n",__FILE__,
407 __LINE__,__FUNCTION__);
408 return(STATUS_UNSUCCESSFUL);
409 }
410
411 next = &string[0];
412 current = next+1;
413
414 while (next!=NULL && current_dir->Type==OBJTYP_DIRECTORY)
415 {
416 *next = '\\';
417 current = next+1;
418 next = wcschr(next+1,'\\');
419 if (next!=NULL)
420 {
421 *next=0;
422 }
423
424 DPRINT("current %w current[5] %x next %x ",current,current[5],next);
425 if (next!=NULL)
426 {
427 DPRINT("(next+1) %w",next+1);
428 }
429 DPRINT("\n",0);
430
431 current_dir=(PDIRECTORY_OBJECT)ObDirLookup(current_dir,current);
432 if (current_dir==NULL)
433 {
434 DbgPrint("(%s:%d) Path component not found\n",__FILE__,
435 __LINE__);
436 ExFreePool(string);
437 return(STATUS_UNSUCCESSFUL);
438 }
439
440 DPRINT("current_dir %x\n",current_dir);
441 DPRINT("current_dir->Type %d OBJTYP_SYMLNK %d OBJTYP_DIRECTORY %d\n",
442 current_dir->Type,OBJTYP_SYMLNK,OBJTYP_DIRECTORY);
443 DPRINT("&(current_dir->Type) %x\n",&(current_dir->Type));
444 if (current_dir->Type==OBJTYP_SYMLNK)
445 {
446 current_dir = IoOpenSymlink(current_dir);
447 }
448
449 }
450 DPRINT("next %x\n",next);
451 DPRINT("current %x current %w\n",current,current);
452 if (next==NULL)
453 {
454 if (current_dir==NULL)
455 {
456 Status = STATUS_UNSUCCESSFUL;
457 }
458 else
459 {
460 Status = STATUS_SUCCESS;
461 }
462 }
463 else
464 {
465 CHECKPOINT;
466 *next = '\\';
467 *UnparsedSection = next;
468 switch(current_dir->Type)
469 {
470 case OBJTYP_DEVICE:
471 CHECKPOINT;
472 Status = STATUS_FS_QUERY_REQUIRED;
473 break;
474
475 default:
476 current_dir = NULL;
477 Status = STATUS_UNSUCCESSFUL;
478 break;
479 }
480 }
481 CHECKPOINT;
482 *Object = current_dir;
483
484 return(Status);
485 }
486