changed ObLookupObject to use Parse member if nonnull
[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 POBJECT_TYPE ObDirectoryType = NULL;
26
27 static struct
28 {
29 OBJECT_HEADER hdr;
30 // DIRECTORY_OBJECT directory;
31 LIST_ENTRY head;
32 KSPIN_LOCK Lock;
33 } namespc_root = {{0,},};
34
35 /* FUNCTIONS **************************************************************/
36
37 NTSTATUS NtOpenDirectoryObject(PHANDLE DirectoryHandle,
38 ACCESS_MASK DesiredAccess,
39 POBJECT_ATTRIBUTES ObjectAttributes)
40 {
41 return(ZwOpenDirectoryObject(DirectoryHandle,
42 DesiredAccess,
43 ObjectAttributes));
44 }
45
46 NTSTATUS ZwOpenDirectoryObject(PHANDLE DirectoryHandle,
47 ACCESS_MASK DesiredAccess,
48 POBJECT_ATTRIBUTES ObjectAttributes)
49 /*
50 * FUNCTION: Opens a namespace directory object
51 * ARGUMENTS:
52 * DirectoryHandle (OUT) = Variable which receives the directory handle
53 * DesiredAccess = Desired access to the directory
54 * ObjectAttributes = Structure describing the directory
55 * RETURNS: Status
56 * NOTES: Undocumented
57 */
58 {
59 PVOID Object;
60 NTSTATUS Status;
61 PWSTR Ignored;
62
63 *DirectoryHandle = 0;
64
65 Status = ObOpenObjectByName(ObjectAttributes,&Object,&Ignored);
66 if (!NT_SUCCESS(Status))
67 {
68 return(Status);
69 }
70
71 if (BODY_TO_HEADER(Object)->Type!=OBJTYP_DIRECTORY)
72 {
73 return(STATUS_UNSUCCESSFUL);
74 }
75
76 *DirectoryHandle = ObInsertHandle(KeGetCurrentProcess(),Object,
77 DesiredAccess,FALSE);
78 CHECKPOINT;
79 return(STATUS_SUCCESS);
80 }
81
82 NTSTATUS NtQueryDirectoryObject(IN HANDLE DirObjHandle,
83 OUT POBJDIR_INFORMATION DirObjInformation,
84 IN ULONG BufferLength,
85 IN BOOLEAN GetNextIndex,
86 IN BOOLEAN IgnoreInputIndex,
87 IN OUT PULONG ObjectIndex,
88 OUT PULONG DataWritten OPTIONAL)
89 {
90 return(ZwQueryDirectoryObject(DirObjHandle,
91 DirObjInformation,
92 BufferLength,
93 GetNextIndex,
94 IgnoreInputIndex,
95 ObjectIndex,
96 DataWritten));
97 }
98
99 NTSTATUS ZwQueryDirectoryObject(IN HANDLE DirObjHandle,
100 OUT POBJDIR_INFORMATION DirObjInformation,
101 IN ULONG BufferLength,
102 IN BOOLEAN GetNextIndex,
103 IN BOOLEAN IgnoreInputIndex,
104 IN OUT PULONG ObjectIndex,
105 OUT PULONG DataWritten OPTIONAL)
106 /*
107 * FUNCTION: Reads information from a namespace directory
108 * ARGUMENTS:
109 * DirObjInformation (OUT) = Buffer to hold the data read
110 * BufferLength = Size of the buffer in bytes
111 * GetNextIndex = If TRUE then set ObjectIndex to the index of the
112 * next object
113 * If FALSE then set ObjectIndex to the number of
114 * objects in the directory
115 * IgnoreInputIndex = If TRUE start reading at index 0
116 * If FALSE start reading at the index specified
117 * by object index
118 * ObjectIndex = Zero based index into the directory, interpretation
119 * depends on IgnoreInputIndex and GetNextIndex
120 * DataWritten (OUT) = Caller supplied storage for the number of bytes
121 * written (or NULL)
122 * RETURNS: Status
123 */
124 {
125 PDIRECTORY_OBJECT dir = NULL;
126 ULONG EntriesToRead;
127 PLIST_ENTRY current_entry;
128 POBJECT_HEADER current;
129 ULONG i=0;
130 ULONG EntriesToSkip;
131 NTSTATUS Status;
132
133 DPRINT("ZwQueryDirectoryObject(DirObjHandle %x)\n",DirObjHandle);
134 DPRINT("dir %x namespc_root %x\n",dir,HEADER_TO_BODY(&(namespc_root.hdr)));
135
136 // assert_irql(PASSIVE_LEVEL);
137
138 Status = ObReferenceObjectByHandle(DirObjHandle,
139 DIRECTORY_QUERY,
140 ObDirectoryType,
141 UserMode,
142 (PVOID*)&dir,
143 NULL);
144 if (Status != STATUS_SUCCESS)
145 {
146 return(Status);
147 }
148
149 EntriesToRead = BufferLength / sizeof(OBJDIR_INFORMATION);
150 *DataWritten = 0;
151
152 DPRINT("EntriesToRead %d\n",EntriesToRead);
153
154 current_entry = dir->head.Flink;
155
156 /*
157 * Optionally, skip over some entries at the start of the directory
158 */
159 if (!IgnoreInputIndex)
160 {
161 CHECKPOINT;
162
163 EntriesToSkip = *ObjectIndex;
164 while ( i<EntriesToSkip && current_entry!=NULL)
165 {
166 current_entry = current_entry->Flink;
167 }
168 }
169
170 DPRINT("DirObjInformation %x\n",DirObjInformation);
171
172 /*
173 * Read the maximum entries possible into the buffer
174 */
175 while ( i<EntriesToRead && current_entry!=(&(dir->head)))
176 {
177 current = CONTAINING_RECORD(current_entry,OBJECT_HEADER,Entry);
178 DPRINT("Scanning %w\n",current->Name.Buffer);
179 DirObjInformation[i].ObjectName.Buffer =
180 ExAllocatePool(NonPagedPool,(current->Name.Length+1)*2);
181 DirObjInformation[i].ObjectName.Length = current->Name.Length;
182 DirObjInformation[i].ObjectName.MaximumLength = current->Name.Length;
183 DPRINT("DirObjInformation[i].ObjectName.Buffer %x\n",
184 DirObjInformation[i].ObjectName.Buffer);
185 RtlCopyUnicodeString(&DirObjInformation[i].ObjectName,
186 &(current->Name));
187 i++;
188 current_entry = current_entry->Flink;
189 (*DataWritten) = (*DataWritten) + sizeof(OBJDIR_INFORMATION);
190 CHECKPOINT;
191 }
192 CHECKPOINT;
193
194 /*
195 * Optionally, count the number of entries in the directory
196 */
197 if (GetNextIndex)
198 {
199 *ObjectIndex=i;
200 }
201 else
202 {
203 while ( current_entry!=(&(dir->head)) )
204 {
205 current_entry=current_entry->Flink;
206 i++;
207 }
208 *ObjectIndex=i;
209 }
210 return(STATUS_SUCCESS);
211 }
212
213
214 NTSTATUS ObReferenceObjectByName(PUNICODE_STRING ObjectPath,
215 ULONG Attributes,
216 PACCESS_STATE PassedAccessState,
217 ACCESS_MASK DesiredAccess,
218 POBJECT_TYPE ObjectType,
219 KPROCESSOR_MODE AccessMode,
220 PVOID ParseContext,
221 PVOID* ObjectPtr)
222 {
223 UNIMPLEMENTED;
224 }
225
226 NTSTATUS ObOpenObjectByName(POBJECT_ATTRIBUTES ObjectAttributes,
227 PVOID* Object, PWSTR* UnparsedSection)
228 {
229 NTSTATUS Status;
230
231 DPRINT("ObOpenObjectByName(ObjectAttributes %x, Object %x)\n",
232 ObjectAttributes,Object);
233 DPRINT("ObjectAttributes = {ObjectName %x ObjectName->Buffer %w}\n",
234 ObjectAttributes->ObjectName,ObjectAttributes->ObjectName->Buffer);
235 DPRINT("ObjectAttributes->ObjectName->Length %d\n",
236 ObjectAttributes->ObjectName->Length);
237
238 *Object = NULL;
239 Status = ObLookupObject(ObjectAttributes->RootDirectory,
240 ObjectAttributes->ObjectName->Buffer,
241 Object,
242 UnparsedSection,
243 ObjectAttributes->Attributes);
244 DPRINT("*Object %x\n",*Object);
245 DPRINT("ObjectAttributes->ObjectName->Length %d\n",
246 ObjectAttributes->ObjectName->Length);
247 return(Status);
248 }
249
250 void ObInit(void)
251 /*
252 * FUNCTION: Initialize the object manager namespace
253 */
254 {
255 ANSI_STRING AnsiString;
256
257 ObDirectoryType = ExAllocatePool(NonPagedPool,sizeof(OBJECT_TYPE));
258
259 ObDirectoryType->TotalObjects = 0;
260 ObDirectoryType->TotalHandles = 0;
261 ObDirectoryType->MaxObjects = ULONG_MAX;
262 ObDirectoryType->MaxHandles = ULONG_MAX;
263 ObDirectoryType->PagedPoolCharge = 0;
264 ObDirectoryType->NonpagedPoolCharge = sizeof(DIRECTORY_OBJECT);
265 ObDirectoryType->Dump = NULL;
266 ObDirectoryType->Open = NULL;
267 ObDirectoryType->Close = NULL;
268 ObDirectoryType->Delete = NULL;
269 ObDirectoryType->Parse = NULL;
270 ObDirectoryType->Security = NULL;
271 ObDirectoryType->QueryName = NULL;
272 ObDirectoryType->OkayToClose = NULL;
273
274 RtlInitAnsiString(&AnsiString,"Directory");
275 RtlAnsiStringToUnicodeString(&ObDirectoryType->TypeName,
276 &AnsiString,TRUE);
277
278 ObInitializeObjectHeader(ObDirectoryType,NULL,&namespc_root.hdr);
279 InitializeListHead(&namespc_root.head);
280 }
281
282 NTSTATUS NtCreateDirectoryObject(PHANDLE DirectoryHandle,
283 ACCESS_MASK DesiredAccess,
284 POBJECT_ATTRIBUTES ObjectAttributes)
285 {
286 return(ZwCreateDirectoryObject(DirectoryHandle,
287 DesiredAccess,
288 ObjectAttributes));
289 }
290
291 NTSTATUS ZwCreateDirectoryObject(PHANDLE DirectoryHandle,
292 ACCESS_MASK DesiredAccess,
293 POBJECT_ATTRIBUTES ObjectAttributes)
294 /*
295 * FUNCTION: Creates or opens a directory object (a container for other
296 * objects)
297 * ARGUMENTS:
298 * DirectoryHandle (OUT) = Caller supplied storage for the handle
299 * of the directory
300 * DesiredAccess = Access desired to the directory
301 * ObjectAttributes = Object attributes initialized with
302 * InitializeObjectAttributes
303 * RETURNS: Status
304 */
305 {
306 PDIRECTORY_OBJECT dir;
307
308 dir = ObGenericCreateObject(DirectoryHandle,DesiredAccess,ObjectAttributes,
309 ObDirectoryType);
310
311 /*
312 * Initialize the object body
313 */
314 InitializeListHead(&dir->head);
315 KeInitializeSpinLock(&(dir->Lock));
316
317 return(STATUS_SUCCESS);
318 }
319
320 VOID InitializeObjectAttributes(POBJECT_ATTRIBUTES InitializedAttributes,
321 PUNICODE_STRING ObjectName,
322 ULONG Attributes,
323 HANDLE RootDirectory,
324 PSECURITY_DESCRIPTOR SecurityDescriptor)
325 /*
326 * FUNCTION: Sets up a parameter of type OBJECT_ATTRIBUTES for a
327 * subsequent call to ZwCreateXXX or ZwOpenXXX
328 * ARGUMENTS:
329 * InitializedAttributes (OUT) = Caller supplied storage for the
330 * object attributes
331 * ObjectName = Full path name for object
332 * Attributes = Attributes for the object
333 * RootDirectory = Where the object should be placed or NULL
334 * SecurityDescriptor = Ignored
335 *
336 * NOTE:
337 * Either ObjectName is a fully qualified pathname or a path relative
338 * to RootDirectory
339 */
340 {
341 DPRINT("InitializeObjectAttributes(InitializedAttributes %x "
342 "ObjectName %x Attributes %x RootDirectory %x)\n",
343 InitializedAttributes,ObjectName,Attributes,RootDirectory);
344 InitializedAttributes->Length=sizeof(OBJECT_ATTRIBUTES);
345 InitializedAttributes->RootDirectory=RootDirectory;
346 InitializedAttributes->ObjectName=ObjectName;
347 InitializedAttributes->Attributes=Attributes;
348 InitializedAttributes->SecurityDescriptor=SecurityDescriptor;
349 InitializedAttributes->SecurityQualityOfService=NULL;
350 }
351
352 static PVOID ObDirLookup(PDIRECTORY_OBJECT dir, PWSTR name,
353 ULONG Attributes)
354 /*
355 * FUNCTION: Looks up an entry within a namespace directory
356 * ARGUMENTS:
357 * dir = Directory to lookup in
358 * name = Entry name to find
359 * RETURNS: A pointer to the object body if found
360 * NULL otherwise
361 */
362 {
363 LIST_ENTRY* current = dir->head.Flink;
364 POBJECT_HEADER current_obj;
365
366 DPRINT("ObDirLookup(dir %x, name %w)\n",dir,name);
367
368 if (name[0]==0)
369 {
370 return(dir);
371 }
372 if (name[0]=='.'&&name[1]==0)
373 {
374 return(dir);
375 }
376 if (name[0]=='.'&&name[1]=='.'&&name[2]==0)
377 {
378 return(BODY_TO_HEADER(dir)->Parent);
379 }
380 while (current!=(&(dir->head)))
381 {
382 current_obj = CONTAINING_RECORD(current,OBJECT_HEADER,Entry);
383 DPRINT("Scanning %w\n",current_obj->Name.Buffer);
384 if (Attributes & OBJ_CASE_INSENSITIVE)
385 {
386 if (wcsicmp(current_obj->Name.Buffer, name)==0)
387 {
388 DPRINT("Found it %x\n",HEADER_TO_BODY(current_obj));
389 return(HEADER_TO_BODY(current_obj));
390 }
391 }
392 else
393 {
394 if ( wcscmp(current_obj->Name.Buffer, name)==0)
395 {
396 DPRINT("Found it %x\n",HEADER_TO_BODY(current_obj));
397 return(HEADER_TO_BODY(current_obj));
398 }
399 }
400 current = current->Flink;
401 }
402 DPRINT("%s() = NULL\n",__FUNCTION__);
403 return(NULL);
404 }
405
406 VOID ObRemoveEntry(POBJECT_HEADER Header)
407 {
408 KIRQL oldlvl;
409
410 DPRINT("ObRemoveEntry(Header %x)\n",Header);
411
412 KeAcquireSpinLock(&(Header->Parent->Lock),&oldlvl);
413 RemoveEntryList(&(Header->Entry));
414 KeReleaseSpinLock(&(Header->Parent->Lock),oldlvl);
415 }
416
417 VOID ObCreateEntry(PDIRECTORY_OBJECT parent,POBJECT_HEADER Object)
418 /*
419 * FUNCTION: Add an entry to a namespace directory
420 * ARGUMENTS:
421 * parent = directory to add in
422 * name = Name to give the entry
423 * Object = Header of the object to add the entry for
424 */
425 {
426 DPRINT("ObjCreateEntry(%x,%x,%x,%w)\n",parent,Object,Object->Name.Buffer,
427 Object->Name.Buffer);
428
429 /*
430 * Insert ourselves in our parents list
431 */
432 InsertTailList(&parent->head,&Object->Entry);
433 }
434
435 NTSTATUS
436 ObLookupObject(HANDLE rootdir,
437 PWSTR string,
438 PVOID* Object,
439 PWSTR* UnparsedSection,
440 ULONG Attributes)
441 /*
442 * FUNCTION: Lookup an object within the system namespc
443 * ARGUMENTS:
444 * root = Directory to start lookup from
445 * _string = Pathname to lookup
446 * RETURNS: On success a pointer to the object body
447 * On failure NULL
448 */
449 {
450 PWSTR current;
451 PWSTR next;
452 PDIRECTORY_OBJECT current_dir = NULL;
453 NTSTATUS Status;
454
455 DPRINT("ObLookupObject(rootdir %x, string %x, string %w, Object %x, "
456 "UnparsedSection %x)\n",rootdir,string,string,Object,
457 UnparsedSection);
458 *UnparsedSection = NULL;
459 *Object = NULL;
460
461 if (rootdir == NULL)
462 {
463 current_dir = HEADER_TO_BODY(&(namespc_root.hdr));
464 }
465 else
466 {
467 ObReferenceObjectByHandle(rootdir,
468 DIRECTORY_TRAVERSE,
469 NULL,
470 UserMode,
471 (PVOID*)&current_dir,
472 NULL);
473 }
474
475 /*
476 * Bit of a hack this
477 */
478 if (string[0] == 0)
479 {
480 *Object = current_dir;
481 return STATUS_SUCCESS;
482 }
483
484 if (string[0] != '\\')
485 {
486 DbgPrint("Non absolute pathname passed\n");
487 return STATUS_UNSUCCESSFUL;
488 }
489
490 next = string;
491 current = next + 1;
492
493 while (next != NULL &&
494 BODY_TO_HEADER(current_dir)->ObjectType == ObDirectoryType)
495 {
496 *next = '\\';
497 current = next + 1;
498 next = wcschr(next + 1,'\\');
499 if (next != NULL)
500 {
501 *next = 0;
502 }
503
504 DPRINT("current %w current[5] %x next %x ", current, current[5], next);
505 if (next != NULL)
506 {
507 DPRINT("(next+1) %w", next + 1);
508 }
509 DPRINT("\n",0);
510
511 current_dir = (PDIRECTORY_OBJECT)ObDirLookup(current_dir,
512 current,
513 Attributes);
514 if (current_dir == NULL)
515 {
516 DbgPrint("Path component %w not found\n", current);
517 return STATUS_UNSUCCESSFUL;
518 }
519
520 if (BODY_TO_HEADER(current_dir)->ObjectType == IoSymbolicLinkType)
521 {
522 current_dir = IoOpenSymlink(current_dir);
523 }
524
525 }
526 DPRINT("next %x\n",next);
527 DPRINT("current %x current %w\n",current,current);
528 if (next == NULL)
529 {
530 if (current_dir == NULL)
531 {
532 Status = STATUS_UNSUCCESSFUL;
533 }
534 else
535 {
536 Status = STATUS_SUCCESS;
537 }
538 }
539 else
540 {
541 CHECKPOINT;
542 *next = '\\';
543 *UnparsedSection = next;
544 if (BODY_TO_HEADER(current_dir)->ObjectType == IoDeviceType)
545 {
546 Status = STATUS_FS_QUERY_REQUIRED;
547 }
548 else if (BODY_TO_HEADER(current_dir)->ObjectType->Parse != NULL)
549 {
550 current_dir = BODY_TO_HEADER(current_dir)->ObjectType->
551 Parse(current_dir,
552 UnparsedSection);
553 Status = (current_dir != NULL) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
554 }
555 else
556 {
557 Status = STATUS_UNSUCCESSFUL;
558 }
559 }
560 CHECKPOINT;
561 *Object = current_dir;
562 DPRINT("current_dir %x\n", current_dir);
563
564 return Status;
565 }
566