[NTOSKRNL] Implement ObIsLUIDDeviceMapsEnabled and call it in NtQueryInformationProcess
[reactos.git] / ntoskrnl / ob / obdir.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ob/obdir.c
5 * PURPOSE: Manages the Object Manager's Directory Implementation,
6 * such as functions for addition, deletion and lookup into
7 * the Object Manager's namespace. These routines are separate
8 * from the Namespace Implementation because they are largely
9 * independent and could be used for other namespaces.
10 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
11 * Thomas Weidenmueller (w3seek@reactos.org)
12 */
13
14 /* INCLUDES ***************************************************************/
15
16 #include <ntoskrnl.h>
17 #define NDEBUG
18 #include <debug.h>
19
20 POBJECT_TYPE ObpDirectoryObjectType = NULL;
21
22 /* PRIVATE FUNCTIONS ******************************************************/
23
24 /*++
25 * @name ObpInsertEntryDirectory
26 *
27 * The ObpInsertEntryDirectory routine <FILLMEIN>.
28 *
29 * @param Parent
30 * <FILLMEIN>.
31 *
32 * @param Context
33 * <FILLMEIN>.
34 *
35 * @param ObjectHeader
36 * <FILLMEIN>.
37 *
38 * @return TRUE if the object was inserted, FALSE otherwise.
39 *
40 * @remarks None.
41 *
42 *--*/
43 BOOLEAN
44 NTAPI
45 ObpInsertEntryDirectory(IN POBJECT_DIRECTORY Parent,
46 IN POBP_LOOKUP_CONTEXT Context,
47 IN POBJECT_HEADER ObjectHeader)
48 {
49 POBJECT_DIRECTORY_ENTRY *AllocatedEntry;
50 POBJECT_DIRECTORY_ENTRY NewEntry;
51 POBJECT_HEADER_NAME_INFO HeaderNameInfo;
52
53 /* Make sure we have a name */
54 ASSERT(ObjectHeader->NameInfoOffset != 0);
55
56 /* Validate the context */
57 if ((Context->Object) ||
58 !(Context->DirectoryLocked) ||
59 (Parent != Context->Directory))
60 {
61 /* Invalid context */
62 DPRINT1("OB: ObpInsertEntryDirectory - invalid context %p %u\n",
63 Context, Context->DirectoryLocked);
64 ASSERT(FALSE);
65 return FALSE;
66 }
67
68 /* Allocate a new Directory Entry */
69 NewEntry = ExAllocatePoolWithTag(PagedPool,
70 sizeof(OBJECT_DIRECTORY_ENTRY),
71 OB_DIR_TAG);
72 if (!NewEntry) return FALSE;
73
74 /* Save the hash */
75 NewEntry->HashValue = Context->HashValue;
76
77 /* Get the Object Name Information */
78 HeaderNameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
79
80 /* Get the Allocated entry */
81 AllocatedEntry = &Parent->HashBuckets[Context->HashIndex];
82
83 /* Set it */
84 NewEntry->ChainLink = *AllocatedEntry;
85 *AllocatedEntry = NewEntry;
86
87 /* Associate the Object */
88 NewEntry->Object = &ObjectHeader->Body;
89
90 /* Associate the Directory */
91 HeaderNameInfo->Directory = Parent;
92 return TRUE;
93 }
94
95 /*++
96 * @name ObpLookupEntryDirectory
97 *
98 * The ObpLookupEntryDirectory routine <FILLMEIN>.
99 *
100 * @param Directory
101 * <FILLMEIN>.
102 *
103 * @param Name
104 * <FILLMEIN>.
105 *
106 * @param Attributes
107 * <FILLMEIN>.
108 *
109 * @param SearchShadow
110 * <FILLMEIN>.
111 *
112 * @param Context
113 * <FILLMEIN>.
114 *
115 * @return Pointer to the object which was found, or NULL otherwise.
116 *
117 * @remarks None.
118 *
119 *--*/
120 PVOID
121 NTAPI
122 ObpLookupEntryDirectory(IN POBJECT_DIRECTORY Directory,
123 IN PUNICODE_STRING Name,
124 IN ULONG Attributes,
125 IN UCHAR SearchShadow,
126 IN POBP_LOOKUP_CONTEXT Context)
127 {
128 BOOLEAN CaseInsensitive = FALSE;
129 POBJECT_HEADER_NAME_INFO HeaderNameInfo;
130 POBJECT_HEADER ObjectHeader;
131 ULONG HashValue;
132 ULONG HashIndex;
133 LONG TotalChars;
134 WCHAR CurrentChar;
135 POBJECT_DIRECTORY_ENTRY *AllocatedEntry;
136 POBJECT_DIRECTORY_ENTRY *LookupBucket;
137 POBJECT_DIRECTORY_ENTRY CurrentEntry;
138 PVOID FoundObject = NULL;
139 PWSTR Buffer;
140 PAGED_CODE();
141
142 /* Check if we should search the shadow directory */
143 if (ObpLUIDDeviceMapsEnabled == 0) SearchShadow = FALSE;
144
145 /* Fail if we don't have a directory or name */
146 if (!(Directory) || !(Name)) goto Quickie;
147
148 /* Get name information */
149 TotalChars = Name->Length / sizeof(WCHAR);
150 Buffer = Name->Buffer;
151
152 /* Set up case-sensitivity */
153 if (Attributes & OBJ_CASE_INSENSITIVE) CaseInsensitive = TRUE;
154
155 /* Fail if the name is empty */
156 if (!(Buffer) || !(TotalChars)) goto Quickie;
157
158 /* Create the Hash */
159 for (HashValue = 0; TotalChars; TotalChars--)
160 {
161 /* Go to the next Character */
162 CurrentChar = *Buffer++;
163
164 /* Prepare the Hash */
165 HashValue += (HashValue << 1) + (HashValue >> 1);
166
167 /* Create the rest based on the name */
168 if (CurrentChar < 'a') HashValue += CurrentChar;
169 else if (CurrentChar > 'z') HashValue += RtlUpcaseUnicodeChar(CurrentChar);
170 else HashValue += (CurrentChar - ('a'-'A'));
171 }
172
173 /* Merge it with our number of hash buckets */
174 HashIndex = HashValue % 37;
175
176 /* Save the result */
177 Context->HashValue = HashValue;
178 Context->HashIndex = (USHORT)HashIndex;
179
180 /* Get the root entry and set it as our lookup bucket */
181 AllocatedEntry = &Directory->HashBuckets[HashIndex];
182 LookupBucket = AllocatedEntry;
183
184 /* Check if the directory is already locked */
185 if (!Context->DirectoryLocked)
186 {
187 /* Lock it */
188 ObpAcquireDirectoryLockShared(Directory, Context);
189 }
190
191 /* Start looping */
192 while ((CurrentEntry = *AllocatedEntry))
193 {
194 /* Do the hashes match? */
195 if (CurrentEntry->HashValue == HashValue)
196 {
197 /* Make sure that it has a name */
198 ObjectHeader = OBJECT_TO_OBJECT_HEADER(CurrentEntry->Object);
199
200 /* Get the name information */
201 ASSERT(ObjectHeader->NameInfoOffset != 0);
202 HeaderNameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
203
204 /* Do the names match? */
205 if ((Name->Length == HeaderNameInfo->Name.Length) &&
206 (RtlEqualUnicodeString(Name, &HeaderNameInfo->Name, CaseInsensitive)))
207 {
208 break;
209 }
210 }
211
212 /* Move to the next entry */
213 AllocatedEntry = &CurrentEntry->ChainLink;
214 }
215
216 /* Check if we still have an entry */
217 if (CurrentEntry)
218 {
219 /* Set this entry as the first, to speed up incoming insertion */
220 if (AllocatedEntry != LookupBucket)
221 {
222 /* Check if the directory was locked or convert the lock */
223 if ((Context->DirectoryLocked) ||
224 (ExConvertPushLockSharedToExclusive(&Directory->Lock)))
225 {
226 /* Set the Current Entry */
227 *AllocatedEntry = CurrentEntry->ChainLink;
228
229 /* Link to the old Hash Entry */
230 CurrentEntry->ChainLink = *LookupBucket;
231
232 /* Set the new Hash Entry */
233 *LookupBucket = CurrentEntry;
234 }
235 }
236
237 /* Save the found object */
238 FoundObject = CurrentEntry->Object;
239 goto Quickie;
240 }
241 else
242 {
243 /* Check if the directory was locked */
244 if (!Context->DirectoryLocked)
245 {
246 /* Release the lock */
247 ObpReleaseDirectoryLock(Directory, Context);
248 }
249
250 /* Check if we should scan the shadow directory */
251 if ((SearchShadow) && (Directory->DeviceMap))
252 {
253 /* FIXME: We don't support this yet */
254 ASSERT(FALSE);
255 }
256 }
257
258 Quickie:
259 /* Check if we inserted an object */
260 if (FoundObject)
261 {
262 /* Get the object name information */
263 ObjectHeader = OBJECT_TO_OBJECT_HEADER(FoundObject);
264 ObpReferenceNameInfo(ObjectHeader);
265
266 /* Reference the object being looked up */
267 ObReferenceObject(FoundObject);
268
269 /* Check if the directory was locked */
270 if (!Context->DirectoryLocked)
271 {
272 /* Release the lock */
273 ObpReleaseDirectoryLock(Directory, Context);
274 }
275 }
276
277 /* Check if we found an object already */
278 if (Context->Object)
279 {
280 /* We already did a lookup, so remove this object's query reference */
281 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Context->Object);
282 HeaderNameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
283 ObpDereferenceNameInfo(HeaderNameInfo);
284
285 /* Also dereference the object itself */
286 ObDereferenceObject(Context->Object);
287 }
288
289 /* Return the object we found */
290 Context->Object = FoundObject;
291 return FoundObject;
292 }
293
294 /*++
295 * @name ObpDeleteEntryDirectory
296 *
297 * The ObpDeleteEntryDirectory routine <FILLMEIN>.
298 *
299 * @param Context
300 * <FILLMEIN>.
301 *
302 * @return TRUE if the object was deleted, FALSE otherwise.
303 *
304 * @remarks None.
305 *
306 *--*/
307 BOOLEAN
308 NTAPI
309 ObpDeleteEntryDirectory(POBP_LOOKUP_CONTEXT Context)
310 {
311 POBJECT_DIRECTORY Directory;
312 POBJECT_DIRECTORY_ENTRY *AllocatedEntry;
313 POBJECT_DIRECTORY_ENTRY CurrentEntry;
314
315 /* Get the Directory */
316 Directory = Context->Directory;
317 if (!Directory) return FALSE;
318
319 /* Get the Entry */
320 AllocatedEntry = &Directory->HashBuckets[Context->HashIndex];
321 CurrentEntry = *AllocatedEntry;
322
323 /* Unlink the Entry */
324 *AllocatedEntry = CurrentEntry->ChainLink;
325 CurrentEntry->ChainLink = NULL;
326
327 /* Free it */
328 ExFreePoolWithTag(CurrentEntry, OB_DIR_TAG);
329
330 /* Return */
331 return TRUE;
332 }
333
334 /* FUNCTIONS **************************************************************/
335
336 /*++
337 * @name NtOpenDirectoryObject
338 * @implemented NT4
339 *
340 * The NtOpenDirectoryObject routine opens a namespace directory object.
341 *
342 * @param DirectoryHandle
343 * Variable which receives the directory handle.
344 *
345 * @param DesiredAccess
346 * Desired access to the directory.
347 *
348 * @param ObjectAttributes
349 * Structure describing the directory.
350 *
351 * @return STATUS_SUCCESS or appropriate error value.
352 *
353 * @remarks None.
354 *
355 *--*/
356 NTSTATUS
357 NTAPI
358 NtOpenDirectoryObject(OUT PHANDLE DirectoryHandle,
359 IN ACCESS_MASK DesiredAccess,
360 IN POBJECT_ATTRIBUTES ObjectAttributes)
361 {
362 HANDLE Directory;
363 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
364 NTSTATUS Status;
365 PAGED_CODE();
366
367 /* Check if we need to do any probing */
368 if (PreviousMode != KernelMode)
369 {
370 _SEH2_TRY
371 {
372 /* Probe the return handle */
373 ProbeForWriteHandle(DirectoryHandle);
374 }
375 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
376 {
377 /* Return the exception code */
378 _SEH2_YIELD(return _SEH2_GetExceptionCode());
379 }
380 _SEH2_END;
381 }
382
383 /* Open the directory object */
384 Status = ObOpenObjectByName(ObjectAttributes,
385 ObpDirectoryObjectType,
386 PreviousMode,
387 NULL,
388 DesiredAccess,
389 NULL,
390 &Directory);
391 if (NT_SUCCESS(Status))
392 {
393 _SEH2_TRY
394 {
395 /* Write back the handle to the caller */
396 *DirectoryHandle = Directory;
397 }
398 _SEH2_EXCEPT(ExSystemExceptionFilter())
399 {
400 /* Get the exception code */
401 Status = _SEH2_GetExceptionCode();
402 }
403 _SEH2_END;
404 }
405
406 /* Return the status to the caller */
407 return Status;
408 }
409
410 /*++
411 * @name NtQueryDirectoryObject
412 * @implemented NT4
413 *
414 * The NtQueryDirectoryObject routine reads information from a directory in
415 * the system namespace.
416 *
417 * @param DirectoryHandle
418 * Handle obtained with NtOpenDirectoryObject which
419 * must grant DIRECTORY_QUERY access to the directory object.
420 *
421 * @param Buffer
422 * Buffer to hold the data read.
423 *
424 * @param BufferLength
425 * Size of the buffer in bytes.
426 *
427 * @param ReturnSingleEntry
428 * When TRUE, only 1 entry is written in DirObjInformation;
429 * otherwise as many as will fit in the buffer.
430 *
431 * @param RestartScan
432 * If TRUE start reading at index 0.
433 * If FALSE start reading at the index specified by *ObjectIndex.
434 *
435 * @param Context
436 * Zero based index into the directory, interpretation
437 * depends on RestartScan.
438 *
439 * @param ReturnLength
440 * Caller supplied storage for the number of bytes
441 * written (or NULL).
442 *
443 * @return STATUS_SUCCESS or appropriate error value.
444 *
445 * @remarks Although you can iterate over the directory by calling this
446 * function multiple times, the directory is unlocked between
447 * calls. This means that another thread can change the directory
448 * and so iterating doesn't guarantee a consistent picture of the
449 * directory. Best thing is to retrieve all directory entries in
450 * one call.
451 *
452 *--*/
453 NTSTATUS
454 NTAPI
455 NtQueryDirectoryObject(IN HANDLE DirectoryHandle,
456 OUT PVOID Buffer,
457 IN ULONG BufferLength,
458 IN BOOLEAN ReturnSingleEntry,
459 IN BOOLEAN RestartScan,
460 IN OUT PULONG Context,
461 OUT PULONG ReturnLength OPTIONAL)
462 {
463 POBJECT_DIRECTORY Directory;
464 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
465 ULONG SkipEntries = 0;
466 NTSTATUS Status;
467 PVOID LocalBuffer;
468 POBJECT_DIRECTORY_INFORMATION DirectoryInfo;
469 ULONG Length, TotalLength;
470 ULONG Count, CurrentEntry;
471 ULONG Hash;
472 POBJECT_DIRECTORY_ENTRY Entry;
473 POBJECT_HEADER ObjectHeader;
474 POBJECT_HEADER_NAME_INFO ObjectNameInfo;
475 UNICODE_STRING Name;
476 PWSTR p;
477 OBP_LOOKUP_CONTEXT LookupContext;
478 PAGED_CODE();
479
480 /* Initialize lookup */
481 ObpInitializeLookupContext(&LookupContext);
482
483 /* Check if we need to do any probing */
484 if (PreviousMode != KernelMode)
485 {
486 _SEH2_TRY
487 {
488 /* Probe the buffer (assuming it will hold Unicode characters) */
489 ProbeForWrite(Buffer, BufferLength, sizeof(WCHAR));
490
491 /* Probe the context and copy it unless scan-restart was requested */
492 ProbeForWriteUlong(Context);
493 if (!RestartScan) SkipEntries = *Context;
494
495 /* Probe the return length if the caller specified one */
496 if (ReturnLength) ProbeForWriteUlong(ReturnLength);
497 }
498 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
499 {
500 /* Return the exception code */
501 _SEH2_YIELD(return _SEH2_GetExceptionCode());
502 }
503 _SEH2_END;
504 }
505 else if (!RestartScan)
506 {
507 /* This is kernel mode, save the context without probing, if needed */
508 SkipEntries = *Context;
509 }
510
511 /* Allocate a buffer */
512 LocalBuffer = ExAllocatePoolWithTag(PagedPool,
513 sizeof(OBJECT_DIRECTORY_INFORMATION) +
514 BufferLength,
515 OB_NAME_TAG);
516 if (!LocalBuffer) return STATUS_INSUFFICIENT_RESOURCES;
517 RtlZeroMemory(LocalBuffer, BufferLength);
518
519 /* Get a reference to directory */
520 Status = ObReferenceObjectByHandle(DirectoryHandle,
521 DIRECTORY_QUERY,
522 ObpDirectoryObjectType,
523 PreviousMode,
524 (PVOID*)&Directory,
525 NULL);
526 if (!NT_SUCCESS(Status))
527 {
528 /* Free the buffer and fail */
529 ExFreePoolWithTag(LocalBuffer, OB_NAME_TAG);
530 return Status;
531 }
532
533 /* Lock directory in shared mode */
534 ObpAcquireDirectoryLockShared(Directory, &LookupContext);
535
536 /* Start at position 0 */
537 DirectoryInfo = (POBJECT_DIRECTORY_INFORMATION)LocalBuffer;
538 TotalLength = sizeof(OBJECT_DIRECTORY_INFORMATION);
539
540 /* Start with 0 entries */
541 Count = 0;
542 CurrentEntry = 0;
543
544 /* Set default status and start looping */
545 Status = STATUS_NO_MORE_ENTRIES;
546 for (Hash = 0; Hash < 37; Hash++)
547 {
548 /* Get this entry and loop all of them */
549 Entry = Directory->HashBuckets[Hash];
550 while (Entry)
551 {
552 /* Check if we should process this entry */
553 if (SkipEntries == CurrentEntry++)
554 {
555 /* Get the header data */
556 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Entry->Object);
557 ObjectNameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
558
559 /* Get the object name */
560 if (ObjectNameInfo)
561 {
562 /* Use the one we have */
563 Name = ObjectNameInfo->Name;
564 }
565 else
566 {
567 /* Otherwise, use an empty one */
568 RtlInitEmptyUnicodeString(&Name, NULL, 0);
569 }
570
571 /* Calculate the length for this entry */
572 Length = sizeof(OBJECT_DIRECTORY_INFORMATION) +
573 Name.Length + sizeof(UNICODE_NULL) +
574 ObjectHeader->Type->Name.Length + sizeof(UNICODE_NULL);
575
576 /* Make sure this entry won't overflow */
577 if ((TotalLength + Length) > BufferLength)
578 {
579 /* Check if the caller wanted only an entry */
580 if (ReturnSingleEntry)
581 {
582 /* Then we'll fail and ask for more buffer */
583 TotalLength += Length;
584 Status = STATUS_BUFFER_TOO_SMALL;
585 }
586 else
587 {
588 /* Otherwise, we'll say we're done for now */
589 Status = STATUS_MORE_ENTRIES;
590 }
591
592 /* Decrease the entry since we didn't process */
593 CurrentEntry--;
594 goto Quickie;
595 }
596
597 /* Now fill in the buffer */
598 DirectoryInfo->Name.Length = Name.Length;
599 DirectoryInfo->Name.MaximumLength = Name.Length +
600 sizeof(UNICODE_NULL);
601 DirectoryInfo->Name.Buffer = Name.Buffer;
602 DirectoryInfo->TypeName.Length = ObjectHeader->
603 Type->Name.Length;
604 DirectoryInfo->TypeName.MaximumLength = ObjectHeader->
605 Type->Name.Length +
606 sizeof(UNICODE_NULL);
607 DirectoryInfo->TypeName.Buffer = ObjectHeader->
608 Type->Name.Buffer;
609
610 /* Set success */
611 Status = STATUS_SUCCESS;
612
613 /* Increase statistics */
614 TotalLength += Length;
615 DirectoryInfo++;
616 Count++;
617
618 /* If the caller only wanted an entry, bail out */
619 if (ReturnSingleEntry) goto Quickie;
620
621 /* Increase the key by one */
622 SkipEntries++;
623 }
624
625 /* Move to the next directory */
626 Entry = Entry->ChainLink;
627 }
628 }
629
630 Quickie:
631 /* Make sure we got success */
632 if (NT_SUCCESS(Status))
633 {
634 /* Clear the current pointer and set it */
635 RtlZeroMemory(DirectoryInfo, sizeof(OBJECT_DIRECTORY_INFORMATION));
636 DirectoryInfo++;
637
638 /* Set the buffer here now and loop entries */
639 p = (PWSTR)DirectoryInfo;
640 DirectoryInfo = LocalBuffer;
641 while (Count--)
642 {
643 /* Copy the name buffer */
644 RtlCopyMemory(p,
645 DirectoryInfo->Name.Buffer,
646 DirectoryInfo->Name.Length);
647
648 /* Now fixup the pointers */
649 DirectoryInfo->Name.Buffer = (PVOID)((ULONG_PTR)Buffer +
650 ((ULONG_PTR)p -
651 (ULONG_PTR)LocalBuffer));
652
653 /* Advance in buffer and NULL-terminate */
654 p = (PVOID)((ULONG_PTR)p + DirectoryInfo->Name.Length);
655 *p++ = UNICODE_NULL;
656
657 /* Now copy the type name buffer */
658 RtlCopyMemory(p,
659 DirectoryInfo->TypeName.Buffer,
660 DirectoryInfo->TypeName.Length);
661
662 /* Now fixup the pointers */
663 DirectoryInfo->TypeName.Buffer = (PVOID)((ULONG_PTR)Buffer +
664 ((ULONG_PTR)p -
665 (ULONG_PTR)LocalBuffer));
666
667 /* Advance in buffer and NULL-terminate */
668 p = (PVOID)((ULONG_PTR)p + DirectoryInfo->TypeName.Length);
669 *p++ = UNICODE_NULL;
670
671 /* Move to the next entry */
672 DirectoryInfo++;
673 }
674
675 /* Set the key */
676 *Context = CurrentEntry;
677 }
678
679 _SEH2_TRY
680 {
681 /* Copy the buffer */
682 RtlCopyMemory(Buffer,
683 LocalBuffer,
684 (TotalLength <= BufferLength) ?
685 TotalLength : BufferLength);
686
687 /* Check if the caller requested the return length and return it*/
688 if (ReturnLength) *ReturnLength = TotalLength;
689 }
690 _SEH2_EXCEPT(ExSystemExceptionFilter())
691 {
692 /* Get the exception code */
693 Status = _SEH2_GetExceptionCode();
694 }
695 _SEH2_END;
696
697 /* Unlock the directory */
698 ObpReleaseDirectoryLock(Directory, &LookupContext);
699
700 /* Dereference the directory and free our buffer */
701 ObDereferenceObject(Directory);
702 ExFreePoolWithTag(LocalBuffer, OB_NAME_TAG);
703
704 /* Return status to caller */
705 return Status;
706 }
707
708 /*++
709 * @name NtCreateDirectoryObject
710 * @implemented NT4
711 *
712 * The NtOpenDirectoryObject routine creates or opens a directory object.
713 *
714 * @param DirectoryHandle
715 * Variable which receives the directory handle.
716 *
717 * @param DesiredAccess
718 * Desired access to the directory.
719 *
720 * @param ObjectAttributes
721 * Structure describing the directory.
722 *
723 * @return STATUS_SUCCESS or appropriate error value.
724 *
725 * @remarks None.
726 *
727 *--*/
728 NTSTATUS
729 NTAPI
730 NtCreateDirectoryObject(OUT PHANDLE DirectoryHandle,
731 IN ACCESS_MASK DesiredAccess,
732 IN POBJECT_ATTRIBUTES ObjectAttributes)
733 {
734 POBJECT_DIRECTORY Directory;
735 HANDLE NewHandle;
736 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
737 NTSTATUS Status;
738 PAGED_CODE();
739
740 /* Check if we need to do any probing */
741 if (PreviousMode != KernelMode)
742 {
743 _SEH2_TRY
744 {
745 /* Probe the return handle */
746 ProbeForWriteHandle(DirectoryHandle);
747 }
748 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
749 {
750 /* Return the exception code */
751 _SEH2_YIELD(return _SEH2_GetExceptionCode());
752 }
753 _SEH2_END;
754 }
755
756 /* Create the object */
757 Status = ObCreateObject(PreviousMode,
758 ObpDirectoryObjectType,
759 ObjectAttributes,
760 PreviousMode,
761 NULL,
762 sizeof(OBJECT_DIRECTORY),
763 0,
764 0,
765 (PVOID*)&Directory);
766 if (!NT_SUCCESS(Status)) return Status;
767
768 /* Setup the object */
769 RtlZeroMemory(Directory, sizeof(OBJECT_DIRECTORY));
770 ExInitializePushLock(&Directory->Lock);
771 Directory->SessionId = -1;
772
773 /* Insert it into the handle table */
774 Status = ObInsertObject((PVOID)Directory,
775 NULL,
776 DesiredAccess,
777 0,
778 NULL,
779 &NewHandle);
780
781 /* Enter SEH to protect write */
782 _SEH2_TRY
783 {
784 /* Return the handle back to the caller */
785 *DirectoryHandle = NewHandle;
786 }
787 _SEH2_EXCEPT(ExSystemExceptionFilter())
788 {
789 /* Get the exception code */
790 Status = _SEH2_GetExceptionCode();
791 }
792 _SEH2_END;
793
794 /* Return status to caller */
795 return Status;
796 }
797
798 /* EOF */