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