Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

obdir.c File Reference

#include "obp.h"

Go to the source code of this file.

Functions

NTSTATUS NtCreateDirectoryObject (OUT PHANDLE DirectoryHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes)
NTSTATUS NtOpenDirectoryObject (OUT PHANDLE DirectoryHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes)
NTSTATUS NtQueryDirectoryObject (IN HANDLE DirectoryHandle, OUT PVOID Buffer, IN ULONG Length, IN BOOLEAN ReturnSingleEntry, IN BOOLEAN RestartScan, IN OUT PULONG Context, OUT PULONG ReturnLength OPTIONAL)
PVOID ObpLookupDirectoryEntry (IN POBJECT_DIRECTORY Directory, IN PUNICODE_STRING Name, IN ULONG Attributes)
BOOLEAN ObpInsertDirectoryEntry (IN POBJECT_DIRECTORY Directory, IN PVOID Object)
BOOLEAN ObpDeleteDirectoryEntry (IN POBJECT_DIRECTORY Directory)
NTSTATUS ObpLookupObjectName (IN HANDLE RootDirectoryHandle OPTIONAL, IN PUNICODE_STRING ObjectName, IN ULONG Attributes, IN POBJECT_TYPE ObjectType, IN KPROCESSOR_MODE AccessMode, IN PVOID ParseContext OPTIONAL, IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL, IN PVOID InsertObject OPTIONAL, IN OUT PACCESS_STATE AccessState, OUT PBOOLEAN DirectoryLocked, OUT PVOID *FoundObject)


Function Documentation

NTSTATUS NtCreateDirectoryObject OUT PHANDLE  DirectoryHandle,
IN ACCESS_MASK  DesiredAccess,
IN POBJECT_ATTRIBUTES  ObjectAttributes
 

Definition at line 32 of file obdir.c.

References Directory(), DirectoryHandle, EXCEPTION_EXECUTE_HANDLER, Handle, KernelMode, KPROCESSOR_MODE, NT_SUCCESS, NTSTATUS(), NULL, ObCreateObject(), ObInsertObject(), ObjectAttributes, ObpDirectoryObjectType, ObpValidateIrql, PAGED_CODE, ProbeForWriteHandle, and Status.

Referenced by DumpObjectDirs(), ExpInitializeCallbacks(), IopCreateRootDirectories(), ObInitSystem(), ObpCreateDosDevicesDirectory(), obtest(), SepInitializationPhase1(), and TestParent().

00040 : 00041 00042 This routine creates a new directory object according to user 00043 specified object attributes 00044 00045 Arguments: 00046 00047 DirectoryHandle - Receives the handle for the newly created 00048 directory object 00049 00050 DesiredAccess - Supplies the access being requested for this 00051 new directory object 00052 00053 ObjectAttributes - Supplies caller specified attributes for new 00054 directory object 00055 00056 Return Value: 00057 00058 An appropriate status value. 00059 00060 --*/ 00061 00062 { 00063 POBJECT_DIRECTORY Directory; 00064 HANDLE Handle; 00065 KPROCESSOR_MODE PreviousMode; 00066 NTSTATUS Status; 00067 00068 PAGED_CODE(); 00069 00070 ObpValidateIrql( "NtCreateDirectoryObject" ); 00071 00072 // 00073 // Get previous processor mode and probe output arguments if necessary. 00074 // 00075 00076 PreviousMode = KeGetPreviousMode(); 00077 00078 if (PreviousMode != KernelMode) { 00079 00080 try { 00081 00082 ProbeForWriteHandle( DirectoryHandle ); 00083 00084 } except( EXCEPTION_EXECUTE_HANDLER ) { 00085 00086 return( GetExceptionCode() ); 00087 } 00088 } 00089 00090 // 00091 // Allocate and initialize a new Directory Object. We don't need 00092 // to specify a parse context or charge any quota. The size of 00093 // the object body is simply a directory object. This call gets 00094 // us a new referenced object. 00095 // 00096 00097 Status = ObCreateObject( PreviousMode, 00098 ObpDirectoryObjectType, 00099 ObjectAttributes, 00100 PreviousMode, 00101 NULL, 00102 sizeof( *Directory ), 00103 0, 00104 0, 00105 (PVOID *)&Directory ); 00106 00107 if (!NT_SUCCESS( Status )) { 00108 00109 return( Status ); 00110 } 00111 00112 RtlZeroMemory( Directory, sizeof( *Directory ) ); 00113 00114 // 00115 // Insert directory object in the current processes handle table, 00116 // set directory handle value and return status. 00117 // 00118 // **** If the insert fails should we backout the create? 00119 // 00120 00121 Status = ObInsertObject( Directory, 00122 NULL, 00123 DesiredAccess, 00124 0, 00125 (PVOID *)NULL, 00126 &Handle ); 00127 00128 try { 00129 00130 *DirectoryHandle = Handle; 00131 00132 } except( EXCEPTION_EXECUTE_HANDLER ) { 00133 00134 // 00135 // Fall through, since we do not want to undo what we have done. 00136 // 00137 } 00138 00139 return( Status ); 00140 }

NTSTATUS NtOpenDirectoryObject OUT PHANDLE  DirectoryHandle,
IN ACCESS_MASK  DesiredAccess,
IN POBJECT_ATTRIBUTES  ObjectAttributes
 

Definition at line 144 of file obdir.c.

References DirectoryHandle, EXCEPTION_EXECUTE_HANDLER, Handle, KernelMode, KPROCESSOR_MODE, NTSTATUS(), NULL, ObjectAttributes, ObOpenObjectByName(), ObpDirectoryObjectType, ObpValidateIrql, PAGED_CODE, ProbeForWriteHandle, and Status.

Referenced by CleanupSessionObjectDirectories(), CommonCreateWindowStation(), CommonOpenWindowStation(), LdrpInitializeProcess(), main(), TestChild(), and TestParent().

00152 : 00153 00154 This routine opens an existing directory object. 00155 00156 Arguments: 00157 00158 DirectoryHandle - Receives the handle for the newly opened directory 00159 object 00160 00161 DesiredAccess - Supplies the access being requested for this 00162 directory object 00163 00164 ObjectAttributes - Supplies caller specified attributes for the 00165 directory object 00166 00167 Return Value: 00168 00169 An appropriate status value. 00170 00171 --*/ 00172 00173 { 00174 KPROCESSOR_MODE PreviousMode; 00175 NTSTATUS Status; 00176 HANDLE Handle; 00177 00178 PAGED_CODE(); 00179 00180 ObpValidateIrql( "NtOpenDirectoryObject" ); 00181 00182 // 00183 // Get previous processor mode and probe output arguments if necessary. 00184 // 00185 00186 PreviousMode = KeGetPreviousMode(); 00187 00188 if (PreviousMode != KernelMode) { 00189 00190 try { 00191 00192 ProbeForWriteHandle( DirectoryHandle ); 00193 00194 } except( EXCEPTION_EXECUTE_HANDLER ) { 00195 00196 return( GetExceptionCode() ); 00197 } 00198 } 00199 00200 // 00201 // Open handle to the directory object with the specified desired access, 00202 // set directory handle value, and return service completion status. 00203 // 00204 00205 Status = ObOpenObjectByName( ObjectAttributes, 00206 ObpDirectoryObjectType, 00207 PreviousMode, 00208 NULL, 00209 DesiredAccess, 00210 NULL, 00211 &Handle ); 00212 00213 try { 00214 00215 *DirectoryHandle = Handle; 00216 00217 } except( EXCEPTION_EXECUTE_HANDLER ) { 00218 00219 // 00220 // Fall through, since we do not want to undo what we have done. 00221 // 00222 } 00223 00224 return Status; 00225 }

NTSTATUS NtQueryDirectoryObject IN HANDLE  DirectoryHandle,
OUT PVOID  Buffer,
IN ULONG  Length,
IN BOOLEAN  ReturnSingleEntry,
IN BOOLEAN  RestartScan,
IN OUT PULONG  Context,
OUT PULONG ReturnLength  OPTIONAL
 

Definition at line 229 of file obdir.c.

References Buffer, _OBJECT_DIRECTORY_ENTRY::ChainLink, Directory(), DirectoryHandle, ExAllocatePoolWithTag, EXCEPTION_EXECUTE_HANDLER, ExFreePool(), KernelMode, KPROCESSOR_MODE, _OBJECT_TYPE::Name, _OBJECT_HEADER_NAME_INFO::Name, NT_SUCCESS, NTSTATUS(), NULL, NUMBER_HASH_BUCKETS, ObDereferenceObject, _OBJECT_DIRECTORY_ENTRY::Object, OBJECT_HEADER_TO_NAME_INFO, OBJECT_TO_OBJECT_HEADER, ObpDirectoryObjectType, ObpEnterRootDirectoryMutex, ObpIsOverflow, ObpLeaveRootDirectoryMutex, ObpValidateIrql, ObReferenceObjectByHandle(), PAGED_CODE, PagedPool, ProbeForWrite(), ProbeForWriteUlong, RtlInitUnicodeString(), Status, _OBJECT_HEADER::Type, and USHORT.

Referenced by CleanupSessionObjectDirectories(), and DumpObjectDirs().

00241 : 00242 00243 This function returns information regarding a specified object 00244 directory. 00245 00246 Arguments: 00247 00248 DirectoryHandle - Supplies a handle to the directory being queried 00249 00250 Buffer - Supplies the output buffer to receive the directory 00251 information. On return this contains one or more OBJECT DIRECTORY 00252 INFORMATION structures, the last one being null. And then this is 00253 followed by the string names for the directory entries. 00254 00255 Length - Supplies the length, in bytes, of the user supplied output 00256 buffer 00257 00258 ReturnSingleEntry - Indicates if this routine should just return 00259 one entry in the directory 00260 00261 RestartScan - Indicates if we are to restart the scan or continue 00262 relative to the enumeration context passed in as the next 00263 parameter 00264 00265 Context - Supplies an enumeration context that must be resupplied 00266 to this routine on subsequent calls to keep the enumeration 00267 in sync 00268 00269 ReturnLength - Optionally receives the length, in bytes, that this 00270 routine has stuffed into the output buffer 00271 00272 Return Value: 00273 00274 An appropriate status value. 00275 00276 --*/ 00277 00278 { 00279 POBJECT_DIRECTORY Directory; 00280 POBJECT_DIRECTORY_ENTRY DirectoryEntry; 00281 POBJECT_HEADER ObjectHeader; 00282 POBJECT_HEADER_NAME_INFO NameInfo; 00283 UNICODE_STRING ObjectName; 00284 POBJECT_DIRECTORY_INFORMATION DirInfo; 00285 PWCH NameBuffer; 00286 KPROCESSOR_MODE PreviousMode; 00287 NTSTATUS Status; 00288 ULONG Bucket, EntryNumber, CapturedContext; 00289 ULONG TotalLengthNeeded, LengthNeeded, EntriesFound; 00290 PCHAR TempBuffer; 00291 00292 PAGED_CODE(); 00293 00294 ObpValidateIrql( "NtQueryDirectoryObject" ); 00295 00296 // 00297 // Get previous processor mode and probe output arguments if necessary. 00298 // 00299 00300 PreviousMode = KeGetPreviousMode(); 00301 00302 if (PreviousMode != KernelMode) { 00303 00304 try { 00305 00306 ProbeForWrite( Buffer, Length, sizeof( WCHAR ) ); 00307 ProbeForWriteUlong( Context ); 00308 00309 if (ARGUMENT_PRESENT( ReturnLength )) { 00310 00311 ProbeForWriteUlong( ReturnLength ); 00312 } 00313 00314 if (RestartScan) { 00315 00316 CapturedContext = 0; 00317 00318 } else { 00319 00320 CapturedContext = *Context; 00321 } 00322 00323 } except( EXCEPTION_EXECUTE_HANDLER ) { 00324 00325 return( GetExceptionCode() ); 00326 } 00327 00328 } else { 00329 00330 if (RestartScan) { 00331 00332 CapturedContext = 0; 00333 00334 } else { 00335 00336 CapturedContext = *Context; 00337 } 00338 } 00339 00340 // 00341 // Allocate space for a temporary work buffer, make sure we got it, 00342 // and then zero it out. Make sure the buffer is large enough to 00343 // hold at least one dir info record. This will make the logic work 00344 // better when the a bad length is passed in. 00345 // 00346 00347 00348 // 00349 // Test for 64 bit if Length + sizeof( OBJECT_DIRECTORY_INFORMATION ) is less than Length 00350 // Return STATUS_INVALID_PARAMETER if there is an overflow 00351 // 00352 00353 if (ObpIsOverflow( Length, sizeof( OBJECT_DIRECTORY_INFORMATION ))) { 00354 00355 return( STATUS_INVALID_PARAMETER ); 00356 } 00357 00358 TempBuffer = ExAllocatePoolWithTag( PagedPool, 00359 Length + sizeof( OBJECT_DIRECTORY_INFORMATION ), 00360 'mNbO' ); 00361 00362 if (TempBuffer == NULL) { 00363 00364 return( STATUS_INSUFFICIENT_RESOURCES ); 00365 } 00366 00367 RtlZeroMemory( TempBuffer, Length ); 00368 00369 // 00370 // Reference the directory object 00371 // 00372 00373 Status = ObReferenceObjectByHandle( DirectoryHandle, 00374 DIRECTORY_QUERY, 00375 ObpDirectoryObjectType, 00376 PreviousMode, 00377 (PVOID *)&Directory, 00378 NULL ); 00379 00380 if (!NT_SUCCESS( Status )) { 00381 00382 ExFreePool( TempBuffer ); 00383 00384 return( Status ); 00385 } 00386 00387 // 00388 // Lock down the directory structures for the life of this 00389 // procedure 00390 // 00391 00392 ObpEnterRootDirectoryMutex(); 00393 00394 // 00395 // DirInfo is used to march through the output buffer filling 00396 // in directory information. We'll start off by making sure 00397 // there is room for a NULL entry at end. 00398 // 00399 00400 DirInfo = (POBJECT_DIRECTORY_INFORMATION)TempBuffer; 00401 00402 TotalLengthNeeded = sizeof( *DirInfo ); 00403 00404 // 00405 // Keep track of the number of entries found and actual 00406 // entry that we are processing 00407 // 00408 00409 EntryNumber = 0; 00410 EntriesFound = 0; 00411 00412 // 00413 // By default we'll say there are no more entries until the 00414 // following loop put in some data 00415 // 00416 00417 Status = STATUS_NO_MORE_ENTRIES; 00418 00419 // 00420 // Our outer loop processes each hash bucket in the directory object 00421 // 00422 00423 for (Bucket=0; Bucket<NUMBER_HASH_BUCKETS; Bucket++) { 00424 00425 DirectoryEntry = Directory->HashBuckets[ Bucket ]; 00426 00427 // 00428 // For this hash bucket we'll zip through its list of entries. 00429 // This is a singly linked list so when the next pointer is null 00430 // (i.e., false) we at the end of the hash list 00431 // 00432 00433 while (DirectoryEntry) { 00434 00435 // 00436 // The captured context is simply the entry count unless the 00437 // user specified otherwise we start at zero, which means 00438 // the first entry is always returned in the enumeration. 00439 // If we have an match based on the entry index then we 00440 // process this entry. We bump the captured context further 00441 // done in the code. 00442 // 00443 00444 if (CapturedContext == EntryNumber++) { 00445 00446 // 00447 // For this directory entry we'll get a pointer to the 00448 // object body and see if it has an object name. If it 00449 // doesn't have a name then we'll give it an empty name. 00450 // 00451 00452 ObjectHeader = OBJECT_TO_OBJECT_HEADER( DirectoryEntry->Object ); 00453 NameInfo = OBJECT_HEADER_TO_NAME_INFO( ObjectHeader ); 00454 00455 if (NameInfo != NULL) { 00456 00457 ObjectName = NameInfo->Name; 00458 00459 } else { 00460 00461 RtlInitUnicodeString( &ObjectName, NULL ); 00462 } 00463 00464 // 00465 // Now compute the length needed for this entry. This would 00466 // be the size of the object directory information record, 00467 // plus the size of the object name and object type name both 00468 // null terminated. 00469 // 00470 00471 LengthNeeded = sizeof( *DirInfo ) + 00472 ObjectName.Length + sizeof( UNICODE_NULL ) + 00473 ObjectHeader->Type->Name.Length + sizeof( UNICODE_NULL ); 00474 00475 // 00476 // If there isn't enough room then take the following error 00477 // path. If the user wanted a single entry then tell the 00478 // caller what length is really needed and say the buffer was 00479 // too small. Otherwise the user wanted multiple entries, 00480 // so we'll just say there are more entries in the directory. 00481 // In both cases we drop down the entry number because we 00482 // weren't able to fit it in on this call 00483 // 00484 00485 if ((TotalLengthNeeded + LengthNeeded) > Length) { 00486 00487 if (ReturnSingleEntry) { 00488 00489 TotalLengthNeeded += LengthNeeded; 00490 00491 Status = STATUS_BUFFER_TOO_SMALL; 00492 00493 } else { 00494 00495 Status = STATUS_MORE_ENTRIES; 00496 } 00497 00498 EntryNumber -= 1; 00499 goto querydone; 00500 } 00501 00502 // 00503 // The information will fit in the buffer. So now fill 00504 // in the output buffer. We temporarily put in pointers 00505 // to the name buffer as stored in the object and object 00506 // type. We copy the data buffer to the user buffer 00507 // right before we return to the caller 00508 // 00509 00510 try { 00511 00512 DirInfo->Name.Length = ObjectName.Length; 00513 DirInfo->Name.MaximumLength = (USHORT)(ObjectName.Length+sizeof( UNICODE_NULL )); 00514 DirInfo->Name.Buffer = ObjectName.Buffer; 00515 00516 DirInfo->TypeName.Length = ObjectHeader->Type->Name.Length; 00517 DirInfo->TypeName.MaximumLength = (USHORT)(ObjectHeader->Type->Name.Length+sizeof( UNICODE_NULL )); 00518 DirInfo->TypeName.Buffer = ObjectHeader->Type->Name.Buffer; 00519 00520 Status = STATUS_SUCCESS; 00521 00522 } except( EXCEPTION_EXECUTE_HANDLER ) { 00523 00524 Status = GetExceptionCode(); 00525 } 00526 00527 if (!NT_SUCCESS( Status )) { 00528 00529 goto querydone; 00530 } 00531 00532 // 00533 // Update the total number of bytes needed in this query. 00534 // Push the dir info pointer to the next output location, 00535 // and indicate how many entries we've processed 00536 // 00537 // 00538 00539 TotalLengthNeeded += LengthNeeded; 00540 00541 DirInfo++; 00542 EntriesFound++; 00543 00544 // 00545 // If we are to return only one entry then move on to the 00546 // post processing phase, otherwise indicate that we're 00547 // processing the next entry and go back to the top of 00548 // the inner loop 00549 // 00550 00551 if (ReturnSingleEntry) { 00552 00553 goto querydone; 00554 00555 } else { 00556 00557 // 00558 // Bump the captured context by one entry. 00559 // 00560 00561 CapturedContext++; 00562 } 00563 } 00564 00565 // 00566 // Get the next directory entry from the singly linked hash 00567 // bucket chain 00568 // 00569 00570 DirectoryEntry = DirectoryEntry->ChainLink; 00571 } 00572 } 00573 00574 // 00575 // At this point we've processed the directory entries and the first 00576 // part of the output buffer now contains a bunch of object directory 00577 // information records, but the pointers in them refer to the wrong 00578 // copies. So now we have some fixup to do. 00579 // 00580 00581 querydone: 00582 00583 try { 00584 00585 // 00586 // We'll only do this post processing if we've been successful 00587 // so far. Note that this means we could be returning in the 00588 // user's output buffer system address that are meaningless, but 00589 // then getting back an error status should tell the caller to 00590 // forget about everything in the output buffer. Given back 00591 // a system address also isn't harmful because there is nothing 00592 // that the user can really do with it. 00593 // 00594 00595 if (NT_SUCCESS( Status )) { 00596 00597 // 00598 // Null terminate the string of object directory information 00599 // records and point to where the actual names will go 00600 // 00601 00602 RtlZeroMemory( DirInfo, sizeof( *DirInfo )); 00603 00604 DirInfo++; 00605 00606 NameBuffer = (PWCH)DirInfo; 00607 00608 // 00609 // Now for every entry that we've put in the output buffer 00610 // DirInfo will point to the entry and EntriesFound kept the 00611 // count. Note that we are guaranteed space because of 00612 // the math we did earlier in computing TotalLengthNeeded. 00613 // 00614 00615 DirInfo = (POBJECT_DIRECTORY_INFORMATION)TempBuffer; 00616 00617 while (EntriesFound--) { 00618 00619 // 00620 // Copy over the object name, set the dir info pointer into 00621 // the user's buffer, then null terminate the string. Note 00622 // that we are really copying the data into our temp buffer 00623 // but the pointer fix up is for the user's buffer which 00624 // we'll copy into right after this loop. 00625 // 00626 00627 RtlMoveMemory( NameBuffer, 00628 DirInfo->Name.Buffer, 00629 DirInfo->Name.Length ); 00630 00631 DirInfo->Name.Buffer = (PVOID)((ULONG_PTR)Buffer + ((ULONG_PTR)NameBuffer - (ULONG_PTR)TempBuffer)); 00632 NameBuffer = (PWCH)((ULONG_PTR)NameBuffer + DirInfo->Name.Length); 00633 *NameBuffer++ = UNICODE_NULL; 00634 00635 // 00636 // Do the same copy with the object type name 00637 // 00638 00639 RtlMoveMemory( NameBuffer, 00640 DirInfo->TypeName.Buffer, 00641 DirInfo->TypeName.Length ); 00642 00643 DirInfo->TypeName.Buffer = (PVOID)((ULONG_PTR)Buffer + ((ULONG_PTR)NameBuffer - (ULONG_PTR)TempBuffer)); 00644 NameBuffer = (PWCH)((ULONG_PTR)NameBuffer + DirInfo->TypeName.Length); 00645 *NameBuffer++ = UNICODE_NULL; 00646 00647 // 00648 // Move on to the next dir info record 00649 // 00650 00651 DirInfo++; 00652 } 00653 00654 // 00655 // Set the enumeration context to the entry number of the next 00656 // entry to return. 00657 // 00658 00659 *Context = EntryNumber; 00660 } 00661 00662 // 00663 // Copy over the results from our temp buffer to the users buffer. 00664 // But adjust the amount copied just in case the total length needed 00665 // exceeds the length we allocated. 00666 // 00667 00668 RtlMoveMemory( Buffer, 00669 TempBuffer, 00670 (TotalLengthNeeded <= Length ? TotalLengthNeeded : Length) ); 00671 00672 // 00673 // In all cases we'll tell the caller how much space if really needed 00674 // provided the user asked for this information 00675 // 00676 00677 if (ARGUMENT_PRESENT( ReturnLength )) { 00678 00679 *ReturnLength = TotalLengthNeeded; 00680 } 00681 00682 } except( EXCEPTION_EXECUTE_HANDLER ) { 00683 00684 // 00685 // Fall through, since we do not want to undo what we have done. 00686 // 00687 } 00688 00689 // 00690 // Unlock the directroy structures, dereference the directory object, 00691 // free up our temp buffer, and return to our caller 00692 // 00693 00694 ObpLeaveRootDirectoryMutex(); 00695 00696 ObDereferenceObject( Directory ); 00697 00698 ExFreePool( TempBuffer ); 00699 00700 return( Status ); 00701 }

BOOLEAN ObpDeleteDirectoryEntry IN POBJECT_DIRECTORY  Directory  ) 
 

Definition at line 1009 of file obdir.c.

References _OBJECT_DIRECTORY_ENTRY::ChainLink, Directory(), ExFreePool(), FALSE, NULL, and TRUE.

Referenced by ObInsertObject(), and ObpDeleteNameCheck().

01015 : 01016 01017 This routine deletes the most recently found directory entry from 01018 the specified directory object. It will only succeed after a 01019 successful ObpLookupDirectoryEntry call. 01020 01021 Arguments: 01022 01023 Directory - Supplies the directory being modified 01024 01025 Return Value: 01026 01027 TRUE if the deletion succeeded and FALSE otherwise 01028 01029 --*/ 01030 01031 { 01032 POBJECT_DIRECTORY_ENTRY *HeadDirectoryEntry; 01033 POBJECT_DIRECTORY_ENTRY DirectoryEntry; 01034 01035 // 01036 // Make sure we have a directory and that it has a found entry 01037 // 01038 01039 if (!Directory || !Directory->LookupFound) { 01040 01041 return( FALSE ); 01042 } 01043 01044 // 01045 // Also make sure that the lookup bucket is valid 01046 // 01047 01048 HeadDirectoryEntry = Directory->LookupBucket; 01049 01050 if (!HeadDirectoryEntry) { 01051 01052 return( FALSE ); 01053 } 01054 01055 DirectoryEntry = *HeadDirectoryEntry; 01056 01057 if (!DirectoryEntry) { 01058 01059 return( FALSE ); 01060 } 01061 01062 // 01063 // Unlink the entry from the head of the bucket chain and free the 01064 // memory for the entry. 01065 // 01066 01067 *HeadDirectoryEntry = DirectoryEntry->ChainLink; 01068 DirectoryEntry->ChainLink = NULL; 01069 01070 ExFreePool( DirectoryEntry ); 01071 01072 // 01073 // Return success 01074 // 01075 01076 return( TRUE ); 01077 }

BOOLEAN ObpInsertDirectoryEntry IN POBJECT_DIRECTORY  Directory,
IN PVOID  Object
 

Definition at line 903 of file obdir.c.

References _OBJECT_DIRECTORY_ENTRY::ChainLink, Directory(), _OBJECT_HEADER_NAME_INFO::Directory, ExAllocatePoolWithTag, FALSE, NULL, _OBJECT_DIRECTORY_ENTRY::Object, OBJECT_HEADER_TO_NAME_INFO, OBJECT_TO_OBJECT_HEADER, PagedPool, and TRUE.

Referenced by ObCreateObjectType(), ObInitSystem(), and ObpLookupObjectName().

00910 : 00911 00912 This routine will insert a new directory entry into a directory 00913 object. The directory must have already have been searched using 00914 ObpLookupDirectoryEntry because that routine sets the LookupBucket 00915 00916 Arguments: 00917 00918 Directory - Supplies the directory object being modified. This 00919 function assumes that we earlier did a lookup on the name 00920 that was successful or we just did an insertion 00921 00922 Object - Supplies the object to insert into the directory 00923 00924 Return Value: 00925 00926 TRUE if the object is inserted successfully and FALSE otherwise 00927 00928 --*/ 00929 00930 { 00931 POBJECT_DIRECTORY_ENTRY *HeadDirectoryEntry; 00932 POBJECT_DIRECTORY_ENTRY NewDirectoryEntry; 00933 POBJECT_HEADER_NAME_INFO NameInfo; 00934 00935 // 00936 // Make sure we have a directory and that the last search was 00937 // successful, meaning there is a lookupbuket 00938 // 00939 00940 if (!Directory || Directory->LookupFound) { 00941 00942 return( FALSE ); 00943 } 00944 00945 // 00946 // Also verify that we have a good lookupbucket 00947 // 00948 00949 HeadDirectoryEntry = Directory->LookupBucket; 00950 00951 if (!HeadDirectoryEntry) { 00952 00953 return( FALSE ); 00954 } 00955 00956 // 00957 // Translate the object into a name info record, and make sure 00958 // that the object has a name 00959 // 00960 00961 NameInfo = OBJECT_HEADER_TO_NAME_INFO( OBJECT_TO_OBJECT_HEADER( Object ) ); 00962 00963 if (NameInfo == NULL) { 00964 00965 return FALSE; 00966 } 00967 00968 // 00969 // Allocate memory for a new entry, and fail if not enough memory. 00970 // 00971 00972 NewDirectoryEntry = (POBJECT_DIRECTORY_ENTRY)ExAllocatePoolWithTag( PagedPool, 00973 sizeof( OBJECT_DIRECTORY_ENTRY ), 00974 'iDbO' ); 00975 00976 if (NewDirectoryEntry == NULL) { 00977 00978 return( FALSE ); 00979 } 00980 00981 // 00982 // Link the new entry into the chain at the insertion point. 00983 // This puts the new object right at the head of the current 00984 // hash bucket chain 00985 // 00986 00987 NewDirectoryEntry->ChainLink = *HeadDirectoryEntry; 00988 *HeadDirectoryEntry = NewDirectoryEntry; 00989 NewDirectoryEntry->Object = Object; 00990 00991 // 00992 // Point the object header back to the directory we just inserted 00993 // it into. 00994 // 00995 00996 NameInfo->Directory = Directory; 00997 00998 // 00999 // Return success. 01000 // 01001 01002 Directory->LookupFound = TRUE; 01003 01004 return( TRUE ); 01005 }

PVOID ObpLookupDirectoryEntry IN POBJECT_DIRECTORY  Directory,
IN PUNICODE_STRING  Name,
IN ULONG  Attributes
 

Definition at line 705 of file obdir.c.

References Buffer, _OBJECT_DIRECTORY_ENTRY::ChainLink, Directory(), FALSE, Name, _OBJECT_HEADER_NAME_INFO::Name, NULL, NUMBER_HASH_BUCKETS, _OBJECT_DIRECTORY_ENTRY::Object, OBJECT_HEADER_TO_NAME_INFO, OBJECT_TO_OBJECT_HEADER, PAGED_CODE, RtlEqualUnicodeString(), RtlUpcaseUnicodeChar(), and TRUE.

Referenced by ObCreateObjectType(), ObInitSystem(), ObpDeleteNameCheck(), ObpLookupObjectName(), and ObpProcessDosDeviceSymbolicLink().

00713 : 00714 00715 This routine will lookup a single directory entry in a given directory. 00716 00717 I believe this routine assumes that it is called with the root directory 00718 locked. 00719 00720 Also note that this routine does not reference the returned object 00721 00722 Arguments: 00723 00724 Directory - Supplies the directory being searched 00725 00726 Name - Supplies the name of entry we're looking for 00727 00728 Attributes - Indicates if the lookup should be case insensitive 00729 or not 00730 00731 Return Value: 00732 00733 Returns a pointer to the corresponding object body if found and NULL 00734 otherwise. 00735 00736 --*/ 00737 00738 { 00739 POBJECT_DIRECTORY_ENTRY *HeadDirectoryEntry; 00740 POBJECT_DIRECTORY_ENTRY DirectoryEntry; 00741 POBJECT_HEADER ObjectHeader; 00742 POBJECT_HEADER_NAME_INFO NameInfo; 00743 PWCH Buffer; 00744 WCHAR Wchar; 00745 ULONG HashIndex; 00746 ULONG WcharLength; 00747 BOOLEAN CaseInSensitive; 00748 00749 PAGED_CODE(); 00750 00751 // 00752 // The caller needs to specify both a directory and a name otherwise 00753 // we can't process the request 00754 // 00755 00756 if (!Directory || !Name) { 00757 00758 return( NULL ); // BUG BUG 00759 } 00760 00761 // 00762 // Set a local variable to tell us if the search is case sensitive 00763 // 00764 00765 if (Attributes & OBJ_CASE_INSENSITIVE) { 00766 00767 CaseInSensitive = TRUE; 00768 00769 } else { 00770 00771 CaseInSensitive = FALSE; 00772 } 00773 00774 // 00775 // Establish our local pointer to the input name buffer and get the 00776 // number of unicode characters in the input name. Also make sure 00777 // the caller gave us a non null name 00778 // 00779 00780 Buffer = Name->Buffer; 00781 WcharLength = Name->Length / sizeof( *Buffer ); 00782 00783 if (!WcharLength || !Buffer) { 00784 00785 return( NULL ); // BUG BUG 00786 } 00787 00788 // 00789 // Compute the address of the head of the bucket chain for this name. 00790 // 00791 00792 HashIndex = 0; 00793 while (WcharLength--) { 00794 00795 Wchar = *Buffer++; 00796 HashIndex += (HashIndex << 1) + (HashIndex >> 1); 00797 00798 if (Wchar < 'a') { 00799 00800 HashIndex += Wchar; 00801 00802 } else if (Wchar > 'z') { 00803 00804 HashIndex += RtlUpcaseUnicodeChar( Wchar ); 00805 00806 } else { 00807 00808 HashIndex += (Wchar - ('a'-'A')); 00809 } 00810 } 00811 00812 HashIndex %= NUMBER_HASH_BUCKETS; 00813 00814 HeadDirectoryEntry = (POBJECT_DIRECTORY_ENTRY *)&Directory->HashBuckets[ HashIndex ]; 00815 00816 Directory->LookupBucket = HeadDirectoryEntry; 00817 00818 // 00819 // Walk the chain of directory entries for this hash bucket, looking 00820 // for either a match, or the insertion point if no match in the chain. 00821 // 00822 00823 while ((DirectoryEntry = *HeadDirectoryEntry) != NULL) { 00824 00825 // 00826 // Get the object header and name from the object body 00827 // 00828 // This function assumes the name must exist, otherwise it 00829 // wouldn't be in a directory 00830 // 00831 00832 ObjectHeader = OBJECT_TO_OBJECT_HEADER( DirectoryEntry->Object ); 00833 NameInfo = OBJECT_HEADER_TO_NAME_INFO( ObjectHeader ); 00834 00835 // 00836 // Compare strings using appropriate function. 00837 // 00838 00839 if ((Name->Length == NameInfo->Name.Length) && 00840 RtlEqualUnicodeString( Name, 00841 &NameInfo->Name, 00842 CaseInSensitive )) { 00843 00844 // 00845 // If name matches, then exit loop with DirectoryEntry 00846 // pointing to matching entry. 00847 // 00848 00849 break; 00850 } 00851 00852 HeadDirectoryEntry = &DirectoryEntry->ChainLink; 00853 } 00854 00855 // 00856 // At this point, there are two possiblilities: 00857 // 00858 // - we found an entry that matched and DirectoryEntry points to that 00859 // entry. Update the bucket chain so that the entry found is at the 00860 // head of the bucket chain. This is so the ObpDeleteDirectoryEntry 00861 // and ObpInsertDirectoryEntry functions will work. Also repeated 00862 // lookups of the same name will succeed quickly. 00863 // 00864 // - we did not find an entry that matched and DirectoryEntry is NULL. 00865 // 00866 00867 if (DirectoryEntry) { 00868 00869 Directory->LookupFound = TRUE; 00870 00871 // 00872 // The following convoluted piece of code moves a directory entry 00873 // we've found to the front of the hash list. 00874 // 00875 00876 if (HeadDirectoryEntry != Directory->LookupBucket) { 00877 00878 *HeadDirectoryEntry = DirectoryEntry->ChainLink; 00879 DirectoryEntry->ChainLink = *(Directory->LookupBucket); 00880 *(Directory->LookupBucket) = DirectoryEntry; 00881 } 00882 00883 // 00884 // Now return the object to our caller 00885 // 00886 00887 return( DirectoryEntry->Object ); 00888 00889 } else { 00890 00891 // 00892 // Otherwise we didn't find anything so return null 00893 // 00894 00895 Directory->LookupFound = FALSE; 00896 00897 return( NULL ); 00898 } 00899 }

NTSTATUS ObpLookupObjectName IN HANDLE RootDirectoryHandle  OPTIONAL,
IN PUNICODE_STRING  ObjectName,
IN ULONG  Attributes,
IN POBJECT_TYPE  ObjectType,
IN KPROCESSOR_MODE  AccessMode,
IN PVOID ParseContext  OPTIONAL,
IN PSECURITY_QUALITY_OF_SERVICE SecurityQos  OPTIONAL,
IN PVOID InsertObject  OPTIONAL,
IN OUT PACCESS_STATE  AccessState,
OUT PBOOLEAN  DirectoryLocked,
OUT PVOID *  FoundObject
 

Definition at line 1081 of file obdir.c.

References ASSERT, _OBJECT_HEADER::Body, _OBJECT_DIRECTORY::DeviceMap, Directory(), _DEVICE_MAP::DosDevicesDirectory, ExAllocatePoolWithTag, ExFreePool(), FALSE, IoFileObjectType, _OBJECT_HEADER_NAME_INFO::Name, NewName, NT_SUCCESS, NTSTATUS(), NULL, OB_PARSE_METHOD, ObCheckCreateObjectAccess(), ObDereferenceObject, OBJECT_HEADER_TO_NAME_INFO, OBJECT_TO_OBJECT_HEADER, ObpBeginTypeSpecificCallOut, ObpCheckTraverseAccess(), ObpDeviceMapLock, ObpDirectoryObjectType, ObpDosDevicesShortName, ObpDosDevicesShortNamePrefix, ObpDosDevicesShortNameRoot, ObpEndTypeSpecificCallOut, ObpEnterRootDirectoryMutex, ObpIncrPointerCount, ObpInsertDirectoryEntry(), ObpLeaveRootDirectoryMutex, ObpLookupDirectoryEntry(), ObpParseSymbolicLink(), ObpRootDirectoryObject, ObpValidateIrql, ObReferenceObject, ObReferenceObjectByHandle(), ObReferenceObjectByPointer(), PagedPool, _OBJECT_TYPE_INITIALIZER::ParseProcedure, PsGetCurrentProcess, _DEVICE_MAP::ReferenceCount, SecurityQos, Status, TOKEN_HAS_TRAVERSE_PRIVILEGE, TRUE, _OBJECT_HEADER::Type, and _OBJECT_TYPE::TypeInfo.

Referenced by ObInsertObject(), ObOpenObjectByName(), and ObReferenceObjectByName().

01097 : 01098 01099 This function will search a given directoroy for a specified 01100 object name. It will also create a new object specified by 01101 InsertObject. 01102 01103 Arguments: 01104 01105 RootDirectoryHandle - Optionally supplies the directory being 01106 searched. If not supplied then this routine searches 01107 the root directory 01108 01109 ObjectName - Supplies the name of object to lookup 01110 01111 Attributes - Specifies the attributes for the lookup (e.g., case 01112 insensitive) 01113 01114 ObjectType - Specifies the type of the object to lookup 01115 01116 AccessMode - Specifies the callers processor mode 01117 01118 ParseContext - Optionally supplies a parse context that is blindly 01119 passed to the parse callback routines 01120 01121 SecurityQos - Optionally supplies a pointer to the passed Security 01122 Quality of Service parameter that is blindly passed to the parse 01123 callback routines 01124 01125 InsertObject - Optionally supplies the object we think will be found. 01126 This is used if the caller did not give a root directory handle 01127 and the object name is "\" and the root object directory hasn't 01128 been created yet. In other cases where we wind up creating 01129 a new directory entry this is the object inserted. 01130 01131 AccessState - Current access state, describing already granted access 01132 types, the privileges used to get them, and any access types yet to 01133 be granted. The access masks may not contain any generic access 01134 types. 01135 01136 DirectoryLocked - Receives an indication if this routine has returned 01137 with the input directory locked 01138 01139 FoundObject - Receives a pointer to the object body if found 01140 01141 Return Value: 01142 01143 An appropriate status value 01144 01145 --*/ 01146 01147 { 01148 POBJECT_DIRECTORY RootDirectory; 01149 POBJECT_DIRECTORY Directory; 01150 POBJECT_DIRECTORY ParentDirectory = NULL; 01151 POBJECT_HEADER ObjectHeader; 01152 POBJECT_HEADER_NAME_INFO NameInfo; 01153 PDEVICE_MAP DeviceMap = NULL; 01154 PVOID Object; 01155 UNICODE_STRING RemainingName; 01156 UNICODE_STRING ComponentName; 01157 PWCH NewName; 01158 NTSTATUS Status; 01159 BOOLEAN Reparse; 01160 ULONG MaxReparse = OBJ_MAX_REPARSE_ATTEMPTS; 01161 OB_PARSE_METHOD ParseProcedure; 01162 extern POBJECT_TYPE IoFileObjectType; 01163 01164 ObpValidateIrql( "ObpLookupObjectName" ); 01165 01166 // 01167 // Initialize our output variables to say we haven't lock or found 01168 // anything but we were successful at it 01169 // 01170 01171 *DirectoryLocked = FALSE; 01172 *FoundObject = NULL; 01173 Status = STATUS_SUCCESS; 01174 01175 Object = NULL; 01176 01177 // 01178 // Check if the caller has given us a directory to search. Otherwise 01179 // we'll search the root object directory 01180 // 01181 01182 if (ARGUMENT_PRESENT( RootDirectoryHandle )) { 01183 01184 // 01185 // Otherwise reference the directory object and make sure 01186 // that we successfully got the object 01187 // 01188 01189 Status = ObReferenceObjectByHandle( RootDirectoryHandle, 01190 0, 01191 NULL, 01192 AccessMode, 01193 (PVOID *)&RootDirectory, 01194 NULL ); 01195 01196 if (!NT_SUCCESS( Status )) { 01197 01198 return( Status ); 01199 } 01200 01201 // 01202 // Translate the directory object to its object header 01203 // 01204 01205 ObjectHeader = OBJECT_TO_OBJECT_HEADER( RootDirectory ); 01206 01207 // 01208 // Now if the name we're looking up starts with a "\" and it 01209 // does not have a parse procedure then the syntax is bad 01210 // 01211 01212 if ((ObjectName->Buffer != NULL) && 01213 (*(ObjectName->Buffer) == OBJ_NAME_PATH_SEPARATOR) && 01214 (ObjectHeader->Type != IoFileObjectType)) { 01215 01216 ObDereferenceObject( RootDirectory ); 01217 01218 return( STATUS_OBJECT_PATH_SYNTAX_BAD ); 01219 } 01220 01221 // 01222 // Now make sure that we do not have the directory of the 01223 // object types 01224 // 01225 01226 if (ObjectHeader->Type != ObpDirectoryObjectType) { 01227 01228 // 01229 // We have an object directory that is not the object type 01230 // directory. So now if it doesn't have a parse routine 01231 // then there is nothing we can 01232 // 01233 01234 if (ObjectHeader->Type->TypeInfo.ParseProcedure == NULL) { 01235 01236 ObDereferenceObject( RootDirectory ); 01237 01238 return( STATUS_INVALID_HANDLE ); 01239 01240 } else { 01241 01242 MaxReparse = OBJ_MAX_REPARSE_ATTEMPTS; 01243 01244 // 01245 // The following loop cycles cycles through the various 01246 // parse routine to we could encounter trying to resolve 01247 // this name through symbolic links. 01248 // 01249 01250 while (TRUE) { 01251 01252 KIRQL SaveIrql; 01253 01254 RemainingName = *ObjectName; 01255 01256 // 01257 // Invoke the callback routine to parse the remaining 01258 // object name 01259 // 01260 01261 ObpBeginTypeSpecificCallOut( SaveIrql ); 01262 01263 Status = (*ObjectHeader->Type->TypeInfo.ParseProcedure)( RootDirectory, 01264 ObjectType, 01265 AccessState, 01266 AccessMode, 01267 Attributes, 01268 ObjectName, 01269 &RemainingName, 01270 ParseContext, 01271 SecurityQos, 01272 &Object ); 01273 01274 ObpEndTypeSpecificCallOut( SaveIrql, "Parse", ObjectHeader->Type, Object ); 01275 01276 // 01277 // If the status was not to do a reparse and the lookup 01278 // was not successful then we found nothing so we 01279 // dereference the directory and return the status to 01280 // our caller. If the object we got back was null then 01281 // we'll tell our caller that we couldn't find the name. 01282 // Lastly if we did not get a reparse and we were 01283 // successful and the object is not null then everything 01284 // gets nicely returned to our caller 01285 // 01286 01287 if ( ( Status != STATUS_REPARSE ) && 01288 ( Status != STATUS_REPARSE_OBJECT )) { 01289 01290 if (!NT_SUCCESS( Status )) { 01291 01292 Object = NULL; 01293 01294 } else if (Object == NULL) { 01295 01296 Status = STATUS_OBJECT_NAME_NOT_FOUND; 01297 } 01298 01299 ObDereferenceObject( RootDirectory ); 01300 01301 *FoundObject = Object; 01302 01303 return( Status ); 01304 01305 // 01306 // We got a status reparse, which means the object 01307 // name has been modified to have use start all over 01308 // again. If the reparse target is now empty or it 01309 // is a path separator then we start the parse at the 01310 // root directory 01311 // 01312 01313 } else if ((ObjectName->Length == 0) || 01314 (ObjectName->Buffer == NULL) || 01315 (*(ObjectName->Buffer) == OBJ_NAME_PATH_SEPARATOR)) { 01316 01317 // 01318 // Restart the parse relative to the root directory. 01319 // 01320 01321 ObDereferenceObject( RootDirectory ); 01322 01323 RootDirectory = ObpRootDirectoryObject; 01324 RootDirectoryHandle = NULL; 01325 01326 break; 01327 01328 // 01329 // We got a reparse and we actually have a new name to 01330 // go to we if we haven't exhausted our reparse attempts 01331 // yet then just continue to the top of this loop. 01332 // 01333 01334 } else if (--MaxReparse) { 01335 01336 continue; 01337 01338 // 01339 // We got a reparse and we've exhausted our times through 01340 // the loop so we'll return what we found. 01341 // 01342 // **** this doesn't seem right. It probably should be 01343 // an error 01344 // 01345 01346 } else { 01347 01348 ObDereferenceObject( RootDirectory ); 01349 01350 *FoundObject = Object; 01351 01352 // 01353 // At this point we were failing in stress by 01354 // returning to the caller with a success status but 01355 // a null object pointer. 01356 // 01357 01358 if (Object == NULL) { 01359 01360 Status = STATUS_OBJECT_NAME_NOT_FOUND; 01361 } 01362 01363 return( Status ); 01364 } 01365 } 01366 } 01367 01368 // 01369 // At this point the caller has given us the directory of object 01370 // types. If the caller didn't specify a name then we'll return 01371 // a pointer to the root object directory. 01372 // 01373 01374 } else if ((ObjectName->Length == 0) || 01375 (ObjectName->Buffer == NULL)) { 01376 01377 Status = ObReferenceObjectByPointer( RootDirectory, 01378 0, 01379 ObjectType, 01380 AccessMode ); 01381 01382 if (NT_SUCCESS( Status )) { 01383 01384 Object = RootDirectory; 01385 } 01386 01387 ObDereferenceObject( RootDirectory ); 01388 01389 *FoundObject = Object; 01390 01391 return( Status ); 01392 } 01393 01394 // 01395 // Otherwise the caller did not specify a directory to search so 01396 // we'll default to the object root directory 01397 // 01398 01399 } else { 01400 01401 RootDirectory = ObpRootDirectoryObject; 01402 01403 // 01404 // If the name we're looking for is empty then it is illformed. 01405 // Also it has to start with a "\" or it is illformed. 01406 // 01407 01408 if ((ObjectName->Length == 0) || 01409 (ObjectName->Buffer == NULL) || 01410 (*(ObjectName->Buffer) != OBJ_NAME_PATH_SEPARATOR)) { 01411 01412 return( STATUS_OBJECT_PATH_SYNTAX_BAD ); 01413 } 01414 01415 // 01416 // Check if the name is has only one character (that is the "\") 01417 // Which means that the caller really just wants to lookup the 01418 // root directory. 01419 // 01420 01421 if (ObjectName->Length == sizeof( OBJ_NAME_PATH_SEPARATOR )) { 01422 01423 // 01424 // If there is not a root directory yet. Then we really 01425 // can't return it, however if the caller specified 01426 // an insert object that is the one we'll reference and 01427 // return to our caller 01428 // 01429 01430 if (!RootDirectory) { 01431 01432 if (InsertObject) { 01433 01434 Status = ObReferenceObjectByPointer( InsertObject, 01435 0, 01436 ObjectType, 01437 AccessMode ); 01438 01439 if (NT_SUCCESS( Status )) { 01440 01441 *FoundObject = InsertObject; 01442 } 01443 01444 return( Status ); 01445 01446 } else { 01447 01448 return( STATUS_INVALID_PARAMETER ); 01449 } 01450 01451 // 01452 // At this point the caller did not specify a root directory, 01453 // the name is "\" and the root object directory exists so 01454 // we'll simply return the real root directory object 01455 // 01456 01457 } else { 01458 01459 Status = ObReferenceObjectByPointer( RootDirectory, 01460 0, 01461 ObjectType, 01462 AccessMode ); 01463 01464 if (NT_SUCCESS( Status )) { 01465 01466 *FoundObject = RootDirectory; 01467 } 01468 01469 return( Status ); 01470 } 01471 01472 // 01473 // At this pointer the caller did not specify a root directory, 01474 // and the name is more than just a "\" 01475 // 01476 // Now if the lookup is case insensitive, and the name buffer is a 01477 // legitimate pointer (meaning that is it quadword aligned), and 01478 // there is a dos device map for the process. Then we'll handle 01479 // the situation here. First get the device map and make sure it 01480 // doesn't go away while we're using it. 01481 // 01482 01483 } else { 01484 01485 KIRQL OldIrql; 01486 01487 ExAcquireSpinLock( &ObpDeviceMapLock, &OldIrql ); 01488 01489 if ((DeviceMap = PsGetCurrentProcess()->DeviceMap) != NULL) { 01490 01491 DeviceMap->ReferenceCount++; 01492 ExReleaseSpinLock( &ObpDeviceMapLock, OldIrql ); 01493 01494 if (!((ULONG_PTR)(ObjectName->Buffer) & (sizeof(ULONGLONG)-1)) 01495 01496 && 01497 01498 (DeviceMap->DosDevicesDirectory != NULL )) { 01499 01500 // 01501 // Check if the object name is actually equal to the 01502 // global dos devices short name prefix "\??\" 01503 // 01504 01505 if ((ObjectName->Length >= ObpDosDevicesShortName.Length) 01506 01507 && 01508 01509 (*(PULONGLONG)(ObjectName->Buffer) == ObpDosDevicesShortNamePrefix.QuadPart)) { 01510 01511 // 01512 // The user gave us the dos short name prefix so we'll 01513 // look down the directory, and start the search at the 01514 // dos device directory 01515 // 01516 01517 *DirectoryLocked = TRUE; 01518 01519 ObpEnterRootDirectoryMutex(); 01520 01521 ParentDirectory = RootDirectory; 01522 01523 Directory = DeviceMap->DosDevicesDirectory; 01524 01525 RemainingName = *ObjectName; 01526 RemainingName.Buffer += (ObpDosDevicesShortName.Length / sizeof( WCHAR )); 01527 RemainingName.Length -= ObpDosDevicesShortName.Length; 01528 01529 goto quickStart; 01530 01531 // 01532 // The name is not equal to "\??\" but check if it is 01533 // equal to "\??" 01534 // 01535 01536 } else if ((ObjectName->Length == ObpDosDevicesShortName.Length - sizeof( WCHAR )) 01537 01538 && 01539 01540 (*(PULONG)(ObjectName->Buffer) == ObpDosDevicesShortNameRoot.LowPart) 01541 01542 && 01543 01544 (*((PWCHAR)(ObjectName->Buffer)+2) == (WCHAR)(ObpDosDevicesShortNameRoot.HighPart))) { 01545 01546 // 01547 // The user specified "\??" so we return to dos devices 01548 // directory to our caller 01549 // 01550 01551 Status = ObReferenceObjectByPointer( DeviceMap->DosDevicesDirectory, 01552 0, 01553 ObjectType, 01554 AccessMode ); 01555 01556 if (NT_SUCCESS( Status )) { 01557 01558 *FoundObject = DeviceMap->DosDevicesDirectory; 01559 } 01560 01561 // 01562 // Dereference the Device Map 01563 // 01564 01565 { 01566 KIRQL OldIrql; 01567 01568 ExAcquireSpinLock( &ObpDeviceMapLock, &OldIrql ); 01569 01570 DeviceMap->ReferenceCount--; 01571 01572 if (DeviceMap->ReferenceCount == 0) { 01573 01574 ExReleaseSpinLock( &ObpDeviceMapLock, OldIrql ); 01575 01576 DeviceMap->DosDevicesDirectory->DeviceMap = NULL; 01577 ObDereferenceObject( DeviceMap->DosDevicesDirectory ); 01578 01579 ExFreePool( DeviceMap ); 01580 01581 } else { 01582 01583 ExReleaseSpinLock( &ObpDeviceMapLock, OldIrql ); 01584 } 01585 } 01586 01587 return( Status ); 01588 } 01589 } 01590 01591 } else { 01592 01593 ExReleaseSpinLock( &ObpDeviceMapLock, OldIrql ); 01594 } 01595 } 01596 } 01597 01598 // 01599 // At this point either 01600 // 01601 // the user specified a directory that is not the object 01602 // type directory and got repase back to the root directory 01603 // 01604 // the user specified the object type directory and gave us 01605 // a name to actually look up 01606 // 01607 // the user did not specify a search directory (default 01608 // to root object directory) and if the name did start off 01609 // with the dos device prefix we've munged outselves back to 01610 // it to the dos device directory for the process 01611 // 01612 01613 Reparse = TRUE; 01614 MaxReparse = OBJ_MAX_REPARSE_ATTEMPTS; 01615 01616 while (Reparse) { 01617 01618 RemainingName = *ObjectName; 01619 01620 quickStart: 01621 01622 Reparse = FALSE; 01623 01624 while (TRUE) { 01625 01626 Object = NULL; 01627 01628 //if (RemainingName.Length == 0) { 01629 // Status = STATUS_OBJECT_NAME_INVALID; 01630 // break; 01631 // } 01632 01633 // 01634 // If the remaining name for the object starts with a 01635 // "\" then just gobble up the "\" 01636 // 01637 01638 if ( (RemainingName.Length != 0) && 01639 (*(RemainingName.Buffer) == OBJ_NAME_PATH_SEPARATOR) ) { 01640 01641 RemainingName.Buffer++; 01642 RemainingName.Length -= sizeof( OBJ_NAME_PATH_SEPARATOR ); 01643 } 01644 01645 // 01646 // The following piece of code will calculate the first 01647 // component of the remaining name. If there is not 01648 // a remaining component then the object name is illformed 01649 // 01650 01651 ComponentName = RemainingName; 01652 01653 while (RemainingName.Length != 0) { 01654 01655 if (*(RemainingName.Buffer) == OBJ_NAME_PATH_SEPARATOR) { 01656 01657 break; 01658 } 01659 01660 RemainingName.Buffer++; 01661 RemainingName.Length -= sizeof( OBJ_NAME_PATH_SEPARATOR ); 01662 } 01663 01664 ComponentName.Length -= RemainingName.Length; 01665 01666 if (ComponentName.Length == 0) { 01667 01668 Status = STATUS_OBJECT_NAME_INVALID; 01669 break; 01670 } 01671 01672 // 01673 // Now we have the first component name to lookup so we'll 01674 // look the directory is necessary 01675 // 01676 01677 if (!*DirectoryLocked) { 01678 01679 *DirectoryLocked = TRUE; 01680 ObpEnterRootDirectoryMutex(); 01681 Directory = RootDirectory; 01682 } 01683 01684 // 01685 // Now if the caller does not have traverse privilege and 01686 // there is a parent directory then we must check if the 01687 // user has traverse access to the directory. Our local 01688 // Reparse variable should be false at this point so we'll 01689 // drop out of both loops 01690 // 01691 01692 if ( !(AccessState->Flags & TOKEN_HAS_TRAVERSE_PRIVILEGE) && (ParentDirectory != NULL) ) { 01693 01694 if (!ObpCheckTraverseAccess( ParentDirectory, 01695 DIRECTORY_TRAVERSE, 01696 AccessState, 01697 FALSE, 01698 AccessMode, 01699 &Status )) { 01700 01701 break; 01702 } 01703 } 01704 01705 // 01706 // If the object already exists in this directory, find it, 01707 // else return NULL. 01708 // 01709 01710 Object = ObpLookupDirectoryEntry( Directory, &ComponentName, Attributes ); 01711 01712 if (!Object) { 01713 01714 // 01715 // We didn't find the object. If there is some remaining 01716 // name left (meaning the component name is a directory in 01717 // path we trying to break) or the caller didn't specify an 01718 // insert object then we then we'll break out here with an 01719 // error status 01720 // 01721 01722 if (RemainingName.Length != 0) { 01723 01724 Status = STATUS_OBJECT_PATH_NOT_FOUND; 01725 break; 01726 } 01727 01728 if (!InsertObject) { 01729 01730 Status = STATUS_OBJECT_NAME_NOT_FOUND; 01731 break; 01732 } 01733 01734 // 01735 // Check that the caller has the access to the directory 01736 // to either create a subdirectory (in the object type 01737 // directory) or to create an object of the given component 01738 // name. If the call fails then we'll break out of here 01739 // with the status value set 01740 // 01741 01742 if (!ObCheckCreateObjectAccess( Directory, 01743 ObjectType == ObpDirectoryObjectType ? 01744 DIRECTORY_CREATE_SUBDIRECTORY : 01745 DIRECTORY_CREATE_OBJECT, 01746 AccessState, 01747 &ComponentName, 01748 FALSE, 01749 AccessMode, 01750 &Status )) { 01751 01752 break; 01753 } 01754 01755 // 01756 // The object does not exist in the directory and 01757 // we are allowed to create one. So allocate space 01758 // for the name and insert the name into the directory 01759 // 01760 01761 NewName = ExAllocatePoolWithTag( PagedPool, ComponentName.Length, 'mNbO' ); 01762 01763 if ((NewName == NULL) || 01764 !ObpInsertDirectoryEntry( Directory, InsertObject )) { 01765 01766 if (NewName != NULL) { 01767 01768 ExFreePool( NewName ); 01769 } 01770 01771 Status = STATUS_INSUFFICIENT_RESOURCES; 01772 break; 01773 } 01774 01775 // 01776 // We have an insert object so now get its name info, 01777 // because we are going to change its name and insert it 01778 // into the directory 01779 // 01780 01781 ObReferenceObject( InsertObject ); 01782 01783 ObjectHeader = OBJECT_TO_OBJECT_HEADER( InsertObject ); 01784 01785 NameInfo = OBJECT_HEADER_TO_NAME_INFO( ObjectHeader ); 01786 01787 ObReferenceObject( Directory ); 01788 01789 RtlMoveMemory( NewName, 01790 ComponentName.Buffer, 01791 ComponentName.Length ); 01792 01793 if (NameInfo->Name.Buffer) { 01794 01795 ExFreePool( NameInfo->Name.Buffer ); 01796 } 01797 01798 NameInfo->Name.Buffer = NewName; 01799 NameInfo->Name.Length = ComponentName.Length; 01800 NameInfo->Name.MaximumLength = ComponentName.Length; 01801 01802 Object = InsertObject; 01803 01804 Status = STATUS_SUCCESS; 01805 01806 break; 01807 } 01808 01809 // 01810 // At this point we've found the component name within 01811 // the directory. So we'll now grab the components object 01812 // header, and get its parse routine 01813 // 01814 01815 ReparseObject: 01816 01817 ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object ); 01818 ParseProcedure = ObjectHeader->Type->TypeInfo.ParseProcedure; 01819 01820 // 01821 // Now if there is a parse routine for the type and we are not 01822 // inserting a new object or the parse routine is for symbolic 01823 // links then we'll actually call the parse routine 01824 // 01825 01826 if (ParseProcedure && (!InsertObject || (ParseProcedure == ObpParseSymbolicLink))) { 01827 01828 KIRQL SaveIrql; 01829 01830 // 01831 // Reference the object and then free the directory lock 01832 // This will keep the object from going away with the 01833 // directory unlocked 01834 // 01835 01836 ObpIncrPointerCount( ObjectHeader ); 01837 01838 ASSERT(*DirectoryLocked); 01839 01840 ObpLeaveRootDirectoryMutex(); 01841 01842 *DirectoryLocked = FALSE; 01843 01844 ObpBeginTypeSpecificCallOut( SaveIrql ); 01845 01846 // 01847 // Call the objects parse routine 01848 // 01849 01850 Status = (*ParseProcedure)( Object, 01851 (PVOID)ObjectType, 01852 AccessState, 01853 AccessMode, 01854 Attributes, 01855 ObjectName, 01856 &RemainingName, 01857 ParseContext, 01858 SecurityQos, 01859 &Object ); 01860 01861 ObpEndTypeSpecificCallOut( SaveIrql, "Parse", ObjectHeader->Type, Object ); 01862 01863 // 01864 // We can now decrement the object reference count 01865 // 01866 01867 ObDereferenceObject( &ObjectHeader->Body ); 01868 01869 // 01870 // Check if we have some reparsing to do 01871 // 01872 01873 if ((Status == STATUS_REPARSE) || (Status == STATUS_REPARSE_OBJECT)) { 01874 01875 // 01876 // See if we've reparsed too many times already and if 01877 // so we'll fail the request 01878 // 01879 01880 if (--MaxReparse) { 01881 01882 // 01883 // Tell the outer loop to continue looping 01884 // 01885 01886 Reparse = TRUE; 01887 01888 // 01889 // Check if we have a reparse object or the name 01890 // starts with a "\" 01891 // 01892 01893 if ((Status == STATUS_REPARSE_OBJECT) || 01894 (*(ObjectName->Buffer) == OBJ_NAME_PATH_SEPARATOR)) { 01895 01896 // 01897 // If the user specified a start directory then 01898 // remove this information because we're taking 01899 // a reparse point to someplace else 01900 // 01901 01902 if (ARGUMENT_PRESENT( RootDirectoryHandle )) { 01903 01904 ObDereferenceObject( RootDirectory ); 01905 RootDirectoryHandle = NULL; 01906 } 01907 01908 // 01909 // And where we start is the root directory 01910 // object 01911 // 01912 01913 ParentDirectory = NULL; 01914 RootDirectory = ObpRootDirectoryObject; 01915 01916 // 01917 // Now if this is a reparse object (means we have 01918 // encountered a symbolic link that has already been 01919 // snapped so we have an object and remaining 01920 // name that need to be examined) and we didn't 01921 // find an object from the parse routine object 01922 // break out of both loops. 01923 // 01924 01925 if (Status == STATUS_REPARSE_OBJECT) { 01926 01927 Reparse = FALSE; 01928 01929 if (Object == NULL) { 01930 01931 Status = STATUS_OBJECT_NAME_NOT_FOUND; 01932 01933 } else { 01934 01935 // 01936 // At this point we have a reparse object 01937 // so we'll look the directory down and 01938 // parse the new object 01939 // 01940 01941 *DirectoryLocked = TRUE; 01942 ObpEnterRootDirectoryMutex(); 01943 01944 goto ReparseObject; 01945 } 01946 } 01947 01948 // 01949 // We did not have a reparse object and the name 01950 // does not start with a "\". Meaning we got back 01951 // STATUS_REPASE, so now check if the directory 01952 // is the root object directory and if so then 01953 // we didn't the name otherwise we'll drop out of 01954 // the inner loop and reparse true to get back to 01955 // outer loop 01956 // 01957 01958 } else if (RootDirectory == ObpRootDirectoryObject) { 01959 01960 Object = NULL; 01961 Status = STATUS_OBJECT_NAME_NOT_FOUND; 01962 01963 Reparse = FALSE; 01964 } 01965 01966 } else { 01967 01968 // 01969 // **** this should probably be a differnt error 01970 // status related to too many reparse points 01971 // 01972 01973 Object = NULL; 01974 Status = STATUS_OBJECT_NAME_NOT_FOUND; 01975 } 01976 01977 // 01978 // We are not reparsing and if we did not get success then 01979 // the object is null and we'll break out of our loops 01980 // 01981 01982 } else if (!NT_SUCCESS( Status )) { 01983 01984 Object = NULL; 01985 01986 // 01987 // We are not reparsing and we got back success but check 01988 // if the object is null because that means we really didn't 01989 // find the object, and then break out of our loops 01990 // 01991 // If the object is not null then we've been successful and 01992 // prosperous so break out with the object set. 01993 // 01994 01995 } else if (Object == NULL) { 01996 01997 Status = STATUS_OBJECT_NAME_NOT_FOUND; 01998 } 01999 02000 break; 02001 02002 } else { 02003 02004 // 02005 // At this point we do not have a parse routine or if there 02006 // is a parse routine it is not for symbolic links or there 02007 // may not be a specified insert object 02008 // 02009 // Check to see if we have exhausted the remaining name 02010 // 02011 02012 if (RemainingName.Length == 0) { 02013 02014 // 02015 // Check if the caller specified an object to insert. 02016 // If specified then we'll break out of our loops with 02017 // the object that we've found 02018 // 02019 02020 if (!InsertObject) { 02021 02022 // 02023 // The user did not specify an insert object 02024 // so we're opening an existing object. Make sure 02025 // we have traverse access to the container 02026 // directory. 02027 // 02028 02029 if ( !(AccessState->Flags & TOKEN_HAS_TRAVERSE_PRIVILEGE) ) { 02030 02031 if (!ObpCheckTraverseAccess( Directory, 02032 DIRECTORY_TRAVERSE, 02033 AccessState, 02034 FALSE, 02035 AccessMode, 02036 &Status )) { 02037 02038 Object = NULL; 02039 break; 02040 } 02041 } 02042 02043 Status = ObReferenceObjectByPointer( Object, 02044 0, 02045 ObjectType, 02046 AccessMode ); 02047 02048 if (!NT_SUCCESS( Status )) { 02049 02050 Object = NULL; 02051 } 02052 } 02053 02054 break; 02055 02056 } else { 02057 02058 // 02059 // There is some name remaining names to process 02060 // if the directory we're looking at is the 02061 // directory of object types and set ourselves 02062 // up to parse it all over again. 02063 // 02064 02065 if (ObjectHeader->Type == ObpDirectoryObjectType) { 02066 02067 ParentDirectory = Directory; 02068 Directory = (POBJECT_DIRECTORY)Object; 02069 02070 } else { 02071 02072 // 02073 // Otherwise there has been a mismatch so we'll 02074 // set our error status and break out of the 02075 // loops 02076 // 02077 02078 Status = STATUS_OBJECT_TYPE_MISMATCH; 02079 Object = NULL; 02080 02081 break; 02082 } 02083 } 02084 } 02085 } 02086 } 02087 02088 // 02089 // If the device map has been referenced then dereference it 02090 // 02091 02092 if (DeviceMap != NULL) { 02093 02094 KIRQL OldIrql; 02095 02096 ExAcquireSpinLock( &ObpDeviceMapLock, &OldIrql ); 02097 02098 DeviceMap->ReferenceCount--; 02099 02100 if (DeviceMap->ReferenceCount == 0) { 02101 02102 ExReleaseSpinLock( &ObpDeviceMapLock, OldIrql ); 02103 02104 DeviceMap->DosDevicesDirectory->DeviceMap = NULL; 02105 ObDereferenceObject( DeviceMap->DosDevicesDirectory ); 02106 02107 ExFreePool( DeviceMap ); 02108 02109 } else { 02110 02111 ExReleaseSpinLock( &ObpDeviceMapLock, OldIrql ); 02112 } 02113 } 02114 02115 // 02116 // At this point we've parsed the object name as much as possible 02117 // going through symbolic links as necessary. So now set the 02118 // output object pointer, and if we really did not find an object 02119 // then we might need to modify the error status. If the 02120 // status was repase or some success status then translate it 02121 // to name not found. 02122 // 02123 02124 if (!(*FoundObject = Object)) { 02125 02126 if (Status == STATUS_REPARSE) { 02127 02128 Status = STATUS_OBJECT_NAME_NOT_FOUND; 02129 02130 } else if (NT_SUCCESS( Status )) { 02131 02132 Status = STATUS_OBJECT_NAME_NOT_FOUND; 02133 } 02134 } 02135 02136 // 02137 // If the caller gave us a root directory to search (and we didn't 02138 // zero out this value) then free up our reference 02139 // 02140 02141 if (ARGUMENT_PRESENT( RootDirectoryHandle )) { 02142 02143 ObDereferenceObject( RootDirectory ); 02144 RootDirectoryHandle = NULL; 02145 } 02146 02147 // 02148 // And return to our caller 02149 // 02150 02151 return( Status ); 02152 }


Generated on Sat May 15 19:44:57 2004 for test by doxygen 1.3.7