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