Exemplo n.º 1
0
Arquivo: rtl.c Projeto: RPG-7/reactos
LONG NTAPI
RtlCompareUnicodeString(
    IN PCUNICODE_STRING String1,
    IN PCUNICODE_STRING String2,
    IN BOOLEAN CaseInSensitive)
{
    USHORT i;
    WCHAR c1, c2;

    for (i = 0; i <= String1->Length / sizeof(WCHAR) && i <= String2->Length / sizeof(WCHAR); i++)
    {
        if (CaseInSensitive)
        {
            c1 = RtlUpcaseUnicodeChar(String1->Buffer[i]);
            c2 = RtlUpcaseUnicodeChar(String2->Buffer[i]);
        }
        else
        {
            c1 = String1->Buffer[i];
            c2 = String2->Buffer[i];
        }

        if (c1 < c2)
            return -1;
        else if (c1 > c2)
            return 1;
    }

    return 0;
}
Exemplo n.º 2
0
PSMP_VOLUME_DESCRIPTOR
NTAPI
SmpSearchVolumeDescriptor(IN WCHAR DriveLetter)
{
    WCHAR UpLetter;
    PSMP_VOLUME_DESCRIPTOR Volume = NULL;
    PLIST_ENTRY NextEntry;

    /* Use upper case to reduce differences */
    UpLetter = RtlUpcaseUnicodeChar(DriveLetter);

    /* Loop each volume */
    NextEntry = SmpVolumeDescriptorList.Flink;
    while (NextEntry != &SmpVolumeDescriptorList)
    {
        /* Grab the entry */
        Volume = CONTAINING_RECORD(NextEntry, SMP_VOLUME_DESCRIPTOR, Entry);

        /* Make sure it's a valid entry with an uppcase drive letter */
        ASSERT(Volume->Flags & SMP_VOLUME_INSERTED); // Volume->Initialized in ASSERT
        ASSERT(Volume->DriveLetter >= L'A' && Volume->DriveLetter <= L'Z');

        /* Break if it matches, if not, keep going */
        if (Volume->DriveLetter == UpLetter) break;
        NextEntry = NextEntry->Flink;
    }

    /* Return the volume if one was found */
    if (NextEntry == &SmpVolumeDescriptorList) Volume = NULL;
    return Volume;
}
Exemplo n.º 3
0
BOOL _FileInfo_CheckPrefix (UNICODE_STRING* pusPath, LPCWSTR wszPrefix)
{
  int i ;

  ASSERT (pusPath!=NULL) ;
  ASSERT (pusPath->Buffer!=NULL) ;
  ASSERT (wszPrefix!=NULL) ;

  for( i=0 ; wszPrefix[i] ; i++ )
    {
      if( i>=pusPath->Length ) return FALSE ;
      if( pusPath->Buffer[i]==0 ) return FALSE ;

      if( RtlUpcaseUnicodeChar(pusPath->Buffer[i])  !=
	  RtlUpcaseUnicodeChar(wszPrefix[i]) ) 
	return FALSE ;
    }
      
  return TRUE;
}
Exemplo n.º 4
0
static BOOLEAN
CmiCompareKeyNamesI(
	IN PCUNICODE_STRING KeyName,
	IN PCM_KEY_NODE KeyCell)
{
	PWCHAR UnicodeName;
	USHORT i;

	DPRINT("Flags: %hx\n", KeyCell->Flags);

	if (KeyCell->Flags & KEY_COMP_NAME)
	{
		if (KeyName->Length != KeyCell->NameLength * sizeof(WCHAR))
			return FALSE;

		/* FIXME: use _strnicmp */
		for (i = 0; i < KeyCell->NameLength; i++)
		{
			if (RtlUpcaseUnicodeChar(KeyName->Buffer[i]) !=
				RtlUpcaseUnicodeChar(((PCHAR)KeyCell->Name)[i]))
			return FALSE;
		}
	}
	else
	{
		if (KeyName->Length != KeyCell->NameLength)
			return FALSE;

		UnicodeName = (PWCHAR)KeyCell->Name;
		/* FIXME: use _strnicmp */
		for (i = 0; i < KeyCell->NameLength / sizeof(WCHAR); i++)
		{
			if (RtlUpcaseUnicodeChar(KeyName->Buffer[i]) !=
				RtlUpcaseUnicodeChar(UnicodeName[i]))
				return FALSE;
		}
	}

	return TRUE;
}
Exemplo n.º 5
0
LONG
NTAPI
CmpCompareCompressedName(IN PCUNICODE_STRING SearchName,
                         IN PWCHAR CompressedName,
                         IN ULONG NameLength)
{
    WCHAR *p;
    CHAR *pp;
    WCHAR p1, p2;
    USHORT SearchLength;
    LONG Result;

    /* Set the pointers and length and then loop */
    p = SearchName->Buffer;
    pp = (PCHAR)CompressedName;
    SearchLength = (SearchName->Length / sizeof(WCHAR));
    while ((SearchLength) && (NameLength))
    {
        /* Get the characters */
        p1 = *p++;
        p2 = (WCHAR)(*pp++);

        /* Check if we have a direct match */
        if (p1 != p2)
        {
            /* See if they match and return result if they don't */
            Result = (LONG)RtlUpcaseUnicodeChar(p1) -
                     (LONG)RtlUpcaseUnicodeChar(p2);
            if (Result) return Result;
        }

        /* Next chars */
        SearchLength--;
        NameLength--;
    }

    /* Return the difference directly */
    return SearchLength - NameLength;
}
Exemplo n.º 6
0
static BOOLEAN
CmiComparePackedNames(
	IN PCUNICODE_STRING Name,
	IN PUCHAR NameBuffer,
	IN USHORT NameBufferSize,
	IN BOOLEAN NamePacked)
{
	PWCHAR UNameBuffer;
	ULONG i;

	if (NamePacked == TRUE)
	{
		if (Name->Length != NameBufferSize * sizeof(WCHAR))
			return FALSE;

		for (i = 0; i < Name->Length / sizeof(WCHAR); i++)
		{
			if (RtlUpcaseUnicodeChar(Name->Buffer[i]) != RtlUpcaseUnicodeChar((WCHAR)NameBuffer[i]))
				return FALSE;
		}
	}
	else
	{
		if (Name->Length != NameBufferSize)
			return FALSE;

		UNameBuffer = (PWCHAR)NameBuffer;

		for (i = 0; i < Name->Length / sizeof(WCHAR); i++)
		{
			if (RtlUpcaseUnicodeChar(Name->Buffer[i]) != RtlUpcaseUnicodeChar(UNameBuffer[i]))
				return FALSE;
		}
	}

	return TRUE;
}
Exemplo n.º 7
0
/**
 * Generates a hash code for a string, case-insensitive.
 *
 * \param String The string.
 * \param Count The number of characters to hash.
 */
FORCEINLINE ULONG EtpHashStringIgnoreCase(
    __in PWSTR String,
    __in SIZE_T Count
    )
{
    ULONG hash = (ULONG)Count;

    if (Count == 0)
        return 0;

    do
    {
        hash = RtlUpcaseUnicodeChar(*String) + (hash << 6) + (hash << 16) - hash;
        String++;
    } while (--Count != 0);

    return hash;
}
Exemplo n.º 8
0
PCM_KEY_CONTROL_BLOCK
CmpCreateKeyControlBlock(
    PHHIVE          Hive,
    HCELL_INDEX     Cell,
    PCM_KEY_NODE    Node,
    PCM_KEY_CONTROL_BLOCK ParentKcb,
    BOOLEAN         FakeKey,
    PUNICODE_STRING KeyName
    )
/*++

Routine Description:

    Allocate and initialize a key control block, insert it into
    the kcb tree.

    Full path will be BaseName + '\' + KeyName, unless BaseName
    NULL, in which case the full path is simply KeyName.

    RefCount of returned KCB WILL have been incremented to reflect
    callers ref.

Arguments:

    Hive - Supplies Hive that holds the key we are creating a KCB for.

    Cell - Supplies Cell that contains the key we are creating a KCB for.

    Node - Supplies pointer to key node.

    ParentKcb - Parent kcb of the kcb to be created

    FakeKey - Whether the kcb to be create is a fake one or not

    KeyName - the subkey name to of the KCB to be created.
 
    NOTE:  We need the parameter instead of just using the name in the KEY_NODE 
           because there is no name in the root cell of a hive.

Return Value:

    NULL - failure (insufficient memory)
    else a pointer to the new kcb.

--*/
{
    PCM_KEY_CONTROL_BLOCK   kcb;
    PCM_KEY_CONTROL_BLOCK   kcbmatch=NULL;
    PCMHIVE CmHive;
    ULONG namelength;
    PUNICODE_STRING         fullname;
    ULONG       Size;
    ULONG i;

    UNICODE_STRING         NodeName;
    ULONG ConvKey=0;
    ULONG Cnt;
    WCHAR *Cp;

    //
    // ParentKCb has the base hash value.
    //
    if (ParentKcb) {
        ConvKey = ParentKcb->ConvKey;
    }

    NodeName = *KeyName;

    while ((NodeName.Length > 0) && (NodeName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR)) {
        //
        // This must be the \REGISTRY.
        // Strip off the leading OBJ_NAME_PATH_SEPARATOR
        //
        NodeName.Buffer++;
        NodeName.Length -= sizeof(WCHAR);
    }

    //
    // Manually compute the hash to use.
    //
    ASSERT(NodeName.Length > 0);

    if (NodeName.Length) {
        Cp = NodeName.Buffer;
        for (Cnt=0; Cnt<NodeName.Length; Cnt += sizeof(WCHAR)) {
            if ((*Cp != OBJ_NAME_PATH_SEPARATOR) &&
                (*Cp != UNICODE_NULL)) {
                ConvKey = 37 * ConvKey + (ULONG)RtlUpcaseUnicodeChar(*Cp);
            }
            ++Cp;
        }
    }

    //
    // Create a new kcb, which we will free if one already exists
    // for this key.
    // Now it is a fixed size structure.
    //
    kcb = ExAllocatePoolWithTag(PagedPool,
                                sizeof(CM_KEY_CONTROL_BLOCK),
                                CM_KCB_TAG | PROTECTED_POOL);


    if (kcb == NULL) {
        return(NULL);
    } else {
        SET_KCB_SIGNATURE(kcb, KCB_SIGNATURE);
        INIT_KCB_KEYBODY_LIST(kcb);
        kcb->Delete = FALSE;
        kcb->RefCount = 1;
        kcb->KeyHive = Hive;
        kcb->KeyCell = Cell;
        kcb->KeyNode = Node;
        kcb->ConvKey = ConvKey;

    }

    ASSERT_KCB(kcb);
    //
    // Find location to insert kcb in kcb tree.
    //


    LOCK_KCB_TREE();

    //
    // Add the KCB to the hash table
    //
    kcbmatch = CmpInsertKeyHash(&kcb->KeyHash, FakeKey);
    if (kcbmatch != NULL) {
        //
        // A match was found.
        //
        ASSERT(!kcbmatch->Delete);
        SET_KCB_SIGNATURE(kcb, '1FmC');
        ASSERT_KEYBODY_LIST_EMPTY(kcb);
        ExFreePoolWithTag(kcb, CM_KCB_TAG | PROTECTED_POOL);
        ASSERT_KCB(kcbmatch);
        kcb = kcbmatch;
        if (kcb->RefCount == 0) {
            //
            // This kcb is on the delayed close list. Remove it from that
            // list.
            //
            CmpRemoveFromDelayedClose(kcb);
        }
        if ((USHORT)(kcb->RefCount + 1) == 0) {
            //
            // We have maxed out the ref count on this key. Probably
            // some bogus app has opened the same key 64K times without
            // ever closing it. Just fail the open, they've got enough
            // handles already.
            //
            ASSERT(kcb->RefCount + 1 != 0);
            kcb = NULL;
        } else {
            ++kcb->RefCount;
        }
    }
    else {
        //
        // No kcb created previously, fill in all the data.
        //

        //
        // Now try to reference the parentkcb
        //
        
        if (ParentKcb) {
            if (CmpReferenceKeyControlBlock(ParentKcb)) {
                kcb->ParentKcb = ParentKcb;
                kcb->TotalLevels = ParentKcb->TotalLevels + 1;
            } else {
                //
                // We have maxed out the ref count on the parent.
                // Since it has been cached in the cachetable,
                // remove it first before we free the allocation.
                //
                CmpRemoveKeyControlBlock(kcb);
                SET_KCB_SIGNATURE(kcb, '2FmC');
                ASSERT_KEYBODY_LIST_EMPTY(kcb);
                ExFreePoolWithTag(kcb, CM_KCB_TAG | PROTECTED_POOL);
                kcb = NULL;
            }
        } else {
            //
            // It is the \REGISTRY node.
            //
            kcb->ParentKcb = NULL;
            kcb->TotalLevels = 1;
        }

        if (kcb) {
            //
            // Now try to find the Name Control block that has the name for this node.
            //
    
            kcb->NameBlock = CmpGetNameControlBlock (&NodeName);

            if (kcb->NameBlock) {
                //
                // Now fill in all the data needed for the cache.
                //
                kcb->ValueCache.Count = Node->ValueList.Count;
                kcb->ValueCache.ValueList = (ULONG_PTR) Node->ValueList.List;
        
                kcb->Flags = Node->Flags;
                kcb->ExtFlags = 0;
                kcb->DelayedCloseIndex = 0;
        
                //
                // Cache the security cells in the kcb
                //
                kcb->Security = Node->Security;
        
                if (FakeKey) {
                    //
                    // The KCb to be created is a fake one
                    //
                    kcb->ExtFlags |= CM_KCB_KEY_NON_EXIST;
                }
            } else {
                //
                // We have maxed out the ref count on the Name.
                //
                
                //
                // First dereference the parent KCB.
                //
                CmpDereferenceKeyControlBlockWithLock(ParentKcb);

                CmpRemoveKeyControlBlock(kcb);
                SET_KCB_SIGNATURE(kcb, '3FmC');
                ASSERT_KEYBODY_LIST_EMPTY(kcb);
                ExFreePoolWithTag(kcb, CM_KCB_TAG | PROTECTED_POOL);
                kcb = NULL;
            }
        }
    }


    UNLOCK_KCB_TREE();
    return kcb;
}
Exemplo n.º 9
0
PCM_NAME_CONTROL_BLOCK
CmpGetNameControlBlock(
    PUNICODE_STRING NodeName
    )
{
    PCM_NAME_CONTROL_BLOCK   Ncb;
    ULONG  Cnt;
    WCHAR *Cp;
    WCHAR *Cp2;
    ULONG Index;
    ULONG i;
    ULONG      Size;
    PCM_NAME_HASH CurrentName;
    ULONG rc;
    BOOLEAN NameFound = FALSE;
    USHORT NameSize;
    BOOLEAN NameCompressed;
    ULONG NameConvKey=0;
    LONG Result;

    //
    // Calculate the ConvKey for this NadeName;
    //

    Cp = NodeName->Buffer;
    for (Cnt=0; Cnt<NodeName->Length; Cnt += sizeof(WCHAR)) {
        if (*Cp != OBJ_NAME_PATH_SEPARATOR) {
            NameConvKey = 37 * NameConvKey + (ULONG) RtlUpcaseUnicodeChar(*Cp);
        }
        ++Cp;
    }

    //
    // Find the Name Size;
    // 
    NameCompressed = TRUE;
    NameSize = NodeName->Length / sizeof(WCHAR);
    for (i=0;i<NodeName->Length/sizeof(WCHAR);i++) {
        if ((USHORT)NodeName->Buffer[i] > (UCHAR)-1) {
            NameSize = NodeName->Length;
            NameCompressed = FALSE;
        }
    }

    Index = GET_HASH_INDEX(NameConvKey);
    CurrentName = CmpNameCacheTable[Index];

    while (CurrentName) {
        Ncb =  CONTAINING_RECORD(CurrentName, CM_NAME_CONTROL_BLOCK, NameHash);

        if ((NameConvKey == CurrentName->ConvKey) &&
            (NameSize == Ncb->NameLength)) {
            //
            // Hash value matches, compare the names.
            //
            NameFound = TRUE;
            if (Ncb->Compressed) {
                if (CmpCompareCompressedName(NodeName, Ncb->Name, NameSize)) {
                    NameFound = FALSE;
                }
            } else {
                Cp = (WCHAR *) NodeName->Buffer;
                Cp2 = (WCHAR *) Ncb->Name;
                for (i=0 ;i<Ncb->NameLength; i+= sizeof(WCHAR)) {
                    if (RtlUpcaseUnicodeChar(*Cp) != RtlUpcaseUnicodeChar(*Cp2)) {
                        NameFound = FALSE;
                        break;
                    }
                    ++Cp;
                    ++Cp2;
                }
            }
            if (NameFound) {
                //
                // Found it, increase the refcount.
                //
                if ((USHORT) (Ncb->RefCount + 1) == 0) {
                    //
                    // We have maxed out the ref count.
                    // fail the call.
                    //
                    Ncb = NULL;
                } else {
                    ++Ncb->RefCount;
                }
                break;
            }
        }
        CurrentName = CurrentName->NextHash;
    }
    
    if (NameFound == FALSE) {
        //
        // Now need to create one Name block for this string.
        //
        Size = FIELD_OFFSET(CM_NAME_CONTROL_BLOCK, Name) + NameSize;
 
        Ncb = ExAllocatePoolWithTag(PagedPool,
                                    Size,
                                    CM_NAME_TAG | PROTECTED_POOL);
 
        if (Ncb == NULL) {
            return(NULL);
        }
        RtlZeroMemory(Ncb, Size);
 
        //
        // Update all the info for this newly created Name block.
        //
        if (NameCompressed) {
            Ncb->Compressed = TRUE;
            for (i=0;i<NameSize;i++) {
                ((PUCHAR)Ncb->Name)[i] = (UCHAR)(NodeName->Buffer[i]);
            }
        } else {
            Ncb->Compressed = FALSE;
            RtlCopyMemory((PVOID)(Ncb->Name), (PVOID)(NodeName->Buffer), NameSize);
        }

        Ncb->ConvKey = NameConvKey;
        Ncb->RefCount = 1;
        Ncb->NameLength = NameSize;
        
        CurrentName = &(Ncb->NameHash);
        //
        // Insert into Name Hash table.
        //
        CurrentName->NextHash = CmpNameCacheTable[Index];
        CmpNameCacheTable[Index] = CurrentName;
    }

    return(Ncb);
}
Exemplo n.º 10
0
LONG
CmpCompareCompressedName(
    IN PUNICODE_STRING SearchName,
    IN PWCHAR CompressedName,
    IN ULONG NameLength
    )

/*++

Routine Description:

    Compares a compressed registry string to a Unicode string.  Does a case-insensitive
    comparison.

Arguments:

    SearchName - Supplies the Unicode string to be compared

    CompressedName - Supplies the compressed string to be compared

    NameLength - Supplies the length of the compressed string

Return Value:

    0 = SearchName == CompressedName (of Cell)

    < 0 = SearchName < CompressedName

    > 0 = SearchName > CompressedName

--*/

{
    WCHAR *s1;
    UCHAR *s2;
    USHORT n1, n2;
    WCHAR c1;
    WCHAR c2;
    LONG cDiff;

    s1 = SearchName->Buffer;
    s2 = (UCHAR *)CompressedName;
    n1 = (USHORT )(SearchName->Length / sizeof(WCHAR));
    n2 = (USHORT )(NameLength);
    while (n1 && n2) {
        c1 = *s1++;
        c2 = (WCHAR)(*s2++);

        c1 = RtlUpcaseUnicodeChar(c1);
        c2 = RtlUpcaseUnicodeChar(c2);

        if ((cDiff = ((LONG)c1 - (LONG)c2)) != 0) {
            return( cDiff );
        }

        n1--;
        n2--;
    }

    return( n1 - n2 );
}
Exemplo n.º 11
0
PCM_KEY_CONTROL_BLOCK
NTAPI
CmpCreateKeyControlBlock(IN PHHIVE Hive,
                         IN HCELL_INDEX Index,
                         IN PCM_KEY_NODE Node,
                         IN PCM_KEY_CONTROL_BLOCK Parent,
                         IN ULONG Flags,
                         IN PUNICODE_STRING KeyName)
{
    PCM_KEY_CONTROL_BLOCK Kcb, FoundKcb = NULL;
    UNICODE_STRING NodeName;
    ULONG ConvKey = 0, i;
    BOOLEAN IsFake, HashLock;
    PWCHAR p;

    /* Make sure we own this hive in case it's being unloaded */
    if ((Hive->HiveFlags & HIVE_IS_UNLOADING) &&
            (((PCMHIVE)Hive)->CreatorOwner != KeGetCurrentThread()))
    {
        /* Fail */
        return NULL;
    }

    /* Check if this is a fake KCB */
    IsFake = Flags & CMP_CREATE_FAKE_KCB ? TRUE : FALSE;

    /* If we have a parent, use its ConvKey */
    if (Parent) ConvKey = Parent->ConvKey;

    /* Make a copy of the name */
    NodeName = *KeyName;

    /* Remove leading slash */
    while ((NodeName.Length) && (*NodeName.Buffer == OBJ_NAME_PATH_SEPARATOR))
    {
        /* Move the buffer by one */
        NodeName.Buffer++;
        NodeName.Length -= sizeof(WCHAR);
    }

    /* Make sure we didn't get just a slash or something */
    ASSERT(NodeName.Length > 0);

    /* Now setup the hash */
    p = NodeName.Buffer;
    for (i = 0; i < NodeName.Length; i += sizeof(WCHAR))
    {
        /* Make sure it's a valid character */
        if (*p != OBJ_NAME_PATH_SEPARATOR)
        {
            /* Add this key to the hash */
            ConvKey = 37 * ConvKey + RtlUpcaseUnicodeChar(*p);
        }

        /* Move on */
        p++;
    }

    /* Allocate the KCB */
    Kcb = CmpAllocateKeyControlBlock();
    if (!Kcb) return NULL;

    /* Initailize the key list */
    InitializeKCBKeyBodyList(Kcb);

    /* Set it up */
    Kcb->Signature = CM_KCB_SIGNATURE;
    Kcb->Delete = FALSE;
    Kcb->RefCount = 1;
    Kcb->KeyHive = Hive;
    Kcb->KeyCell = Index;
    Kcb->ConvKey = ConvKey;
    Kcb->DelayedCloseIndex = CmpDelayedCloseSize;
    Kcb->InDelayClose = 0;
    ASSERT_KCB_VALID(Kcb);

    /* Check if we have two hash entires */
    HashLock = Flags & CMP_LOCK_HASHES_FOR_KCB ? TRUE : FALSE;
    if (!HashLock)
    {
        /* It's not locked, do we have a parent? */
        if (Parent)
        {
            /* Lock the parent KCB and ourselves */
            CmpAcquireTwoKcbLocksExclusiveByKey(ConvKey, Parent->ConvKey);
        }
        else
        {
            /* Lock only ourselves */
            CmpAcquireKcbLockExclusive(Kcb);
        }
    }

    /* Check if we already have a KCB */
    FoundKcb = CmpInsertKeyHash(&Kcb->KeyHash, IsFake);
    if (FoundKcb)
    {
        /* Sanity check */
        ASSERT(!FoundKcb->Delete);
        Kcb->Signature = CM_KCB_INVALID_SIGNATURE;

        /* Free the one we allocated and reference this one */
        CmpFreeKeyControlBlock(Kcb);
        ASSERT_KCB_VALID(FoundKcb);
        Kcb = FoundKcb;
        if (!CmpReferenceKeyControlBlock(Kcb))
        {
            /* We got too many handles */
            ASSERT(Kcb->RefCount + 1 != 0);
            Kcb = NULL;
        }
        else
        {
            /* Check if we're not creating a fake one, but it used to be fake */
            if ((Kcb->ExtFlags & CM_KCB_KEY_NON_EXIST) && !(IsFake))
            {
                /* Set the hive and cell */
                Kcb->KeyHive = Hive;
                Kcb->KeyCell = Index;

                /* This means that our current information is invalid */
                Kcb->ExtFlags = CM_KCB_INVALID_CACHED_INFO;
            }

            /* Check if we didn't have any valid data */
            if (!(Kcb->ExtFlags & (CM_KCB_NO_SUBKEY |
                                   CM_KCB_SUBKEY_ONE |
                                   CM_KCB_SUBKEY_HINT)))
            {
                /* Calculate the index hint */
                Kcb->SubKeyCount = Node->SubKeyCounts[Stable] +
                                   Node->SubKeyCounts[Volatile];

                /* Cached information is now valid */
                Kcb->ExtFlags &= ~CM_KCB_INVALID_CACHED_INFO;
            }

            /* Setup the other data */
            Kcb->KcbLastWriteTime = Node->LastWriteTime;
            Kcb->KcbMaxNameLen = (USHORT)Node->MaxNameLen;
            Kcb->KcbMaxValueNameLen = (USHORT)Node->MaxValueNameLen;
            Kcb->KcbMaxValueDataLen = Node->MaxValueDataLen;
        }
    }
    else
    {
        /* No KCB, do we have a parent? */
        if (Parent)
        {
            /* Reference the parent */
            if (((Parent->TotalLevels + 1) < 512) &&
                    (CmpReferenceKeyControlBlock(Parent)))
            {
                /* Link it */
                Kcb->ParentKcb = Parent;
                Kcb->TotalLevels = Parent->TotalLevels + 1;
            }
            else
            {
                /* Remove the KCB and free it */
                CmpRemoveKeyControlBlock(Kcb);
                Kcb->Signature = CM_KCB_INVALID_SIGNATURE;
                CmpFreeKeyControlBlock(Kcb);
                Kcb = NULL;
            }
        }
        else
        {
            /* No parent, this is the root node */
            Kcb->ParentKcb = NULL;
            Kcb->TotalLevels = 1;
        }

        /* Check if we have a KCB */
        if (Kcb)
        {
            /* Get the NCB */
            Kcb->NameBlock = CmpGetNameControlBlock(&NodeName);
            if (Kcb->NameBlock)
            {
                /* Fill it out */
                Kcb->ValueCache.Count = Node->ValueList.Count;
                Kcb->ValueCache.ValueList = Node->ValueList.List;
                Kcb->Flags = Node->Flags;
                Kcb->ExtFlags = 0;
                Kcb->DelayedCloseIndex = CmpDelayedCloseSize;

                /* Remember if this is a fake key */
                if (IsFake) Kcb->ExtFlags |= CM_KCB_KEY_NON_EXIST;

                /* Setup the other data */
                Kcb->SubKeyCount = Node->SubKeyCounts[Stable] +
                                   Node->SubKeyCounts[Volatile];
                Kcb->KcbLastWriteTime = Node->LastWriteTime;
                Kcb->KcbMaxNameLen = (USHORT)Node->MaxNameLen;
                Kcb->KcbMaxValueNameLen = (USHORT)Node->MaxValueNameLen;
                Kcb->KcbMaxValueDataLen = (USHORT)Node->MaxValueDataLen;
            }
            else
            {
                /* Dereference the KCB */
                CmpDereferenceKeyControlBlockWithLock(Parent, FALSE);

                /* Remove the KCB and free it */
                CmpRemoveKeyControlBlock(Kcb);
                Kcb->Signature = CM_KCB_INVALID_SIGNATURE;
                CmpFreeKeyControlBlock(Kcb);
                Kcb = NULL;
            }
        }
    }

    /* Check if this is a KCB inside a frozen hive */
    if ((Kcb) && (((PCMHIVE)Hive)->Frozen) && (!(Kcb->Flags & KEY_SYM_LINK)))
    {
        /* Don't add these to the delay close */
        Kcb->ExtFlags |= CM_KCB_NO_DELAY_CLOSE;
    }

    /* Sanity check */
    ASSERT((!Kcb) || (Kcb->Delete == FALSE));

    /* Check if we had locked the hashes */
    if (!HashLock)
    {
        /* We locked them manually, do we have a parent? */
        if (Parent)
        {
            /* Unlock the parent KCB and ourselves */
            CmpReleaseTwoKcbLockByKey(ConvKey, Parent->ConvKey);
        }
        else
        {
            /* Unlock only ourselves */
            CmpReleaseKcbLockByKey(ConvKey);
        }
    }

    /* Return the KCB */
    return Kcb;
}
Exemplo n.º 12
0
PCM_NAME_CONTROL_BLOCK
NTAPI
CmpGetNameControlBlock(IN PUNICODE_STRING NodeName)
{
    PCM_NAME_CONTROL_BLOCK Ncb = NULL;
    ULONG ConvKey = 0;
    PWCHAR p, pp;
    ULONG i;
    BOOLEAN IsCompressed = TRUE, Found = FALSE;
    PCM_NAME_HASH HashEntry;
    ULONG Length, NcbSize;

    /* Loop the name */
    p = NodeName->Buffer;
    for (i = 0; i < NodeName->Length; i += sizeof(WCHAR))
    {
        /* Make sure it's not a slash */
        if (*p != OBJ_NAME_PATH_SEPARATOR)
        {
            /* Add it to the hash */
            ConvKey = 37 * ConvKey + RtlUpcaseUnicodeChar(*p);
        }

        /* Next character */
        p++;
    }

    /* Set assumed lengh and loop to check */
    Length = NodeName->Length / sizeof(WCHAR);
    for (i = 0; i < (NodeName->Length / sizeof(WCHAR)); i++)
    {
        /* Check if this is a 16-bit character */
        if (NodeName->Buffer[i] > (UCHAR)-1)
        {
            /* This is the actual size, and we know we're not compressed */
            Length = NodeName->Length;
            IsCompressed = FALSE;
            break;
        }
    }

    /* Lock the NCB entry */
    CmpAcquireNcbLockExclusiveByKey(ConvKey);

    /* Get the hash entry */
    HashEntry = GET_HASH_ENTRY(CmpNameCacheTable, ConvKey).Entry;
    while (HashEntry)
    {
        /* Get the current NCB */
        Ncb = CONTAINING_RECORD(HashEntry, CM_NAME_CONTROL_BLOCK, NameHash);

        /* Check if the hash matches */
        if ((ConvKey == HashEntry->ConvKey) && (Length == Ncb->NameLength))
        {
            /* Assume success */
            Found = TRUE;

            /* If the NCB is compressed, do a compressed name compare */
            if (Ncb->Compressed)
            {
                /* Compare names */
                if (CmpCompareCompressedName(NodeName, Ncb->Name, Length))
                {
                    /* We failed */
                    Found = FALSE;
                }
            }
            else
            {
                /* Do a manual compare */
                p = NodeName->Buffer;
                pp = Ncb->Name;
                for (i = 0; i < Ncb->NameLength; i += sizeof(WCHAR))
                {
                    /* Compare the character */
                    if (RtlUpcaseUnicodeChar(*p) != RtlUpcaseUnicodeChar(*pp))
                    {
                        /* Failed */
                        Found = FALSE;
                        break;
                    }

                    /* Next chars */
                    p++;
                    pp++;
                }
            }

            /* Check if we found a name */
            if (Found)
            {
                /* Reference it */
                ASSERT(Ncb->RefCount != 0xFFFF);
                Ncb->RefCount++;
                break;
            }
        }

        /* Go to the next hash */
        HashEntry = HashEntry->NextHash;
    }

    /* Check if we didn't find it */
    if (!Found)
    {
        /* Allocate one */
        NcbSize = FIELD_OFFSET(CM_NAME_CONTROL_BLOCK, Name) + Length;
        Ncb = CmpAllocate(NcbSize, TRUE, TAG_CM);
        if (!Ncb)
        {
            /* Release the lock and fail */
            CmpReleaseNcbLockByKey(ConvKey);
            return NULL;
        }

        /* Clear it out */
        RtlZeroMemory(Ncb, NcbSize);

        /* Check if the name was compressed */
        if (IsCompressed)
        {
            /* Copy the compressed name */
            for (i = 0; i < NodeName->Length / sizeof(WCHAR); i++)
            {
                /* Copy Unicode to ANSI */
                ((PCHAR)Ncb->Name)[i] = (CHAR)RtlUpcaseUnicodeChar(NodeName->Buffer[i]);
            }
        }
        else
        {
            /* Copy the name directly */
            for (i = 0; i < NodeName->Length / sizeof(WCHAR); i++)
            {
                /* Copy each unicode character */
                Ncb->Name[i] = RtlUpcaseUnicodeChar(NodeName->Buffer[i]);
            }
        }

        /* Setup the rest of the NCB */
        Ncb->Compressed = IsCompressed;
        Ncb->ConvKey = ConvKey;
        Ncb->RefCount++;
        Ncb->NameLength = Length;

        /* Insert the name in the hash table */
        HashEntry = &Ncb->NameHash;
        HashEntry->NextHash = GET_HASH_ENTRY(CmpNameCacheTable, ConvKey).Entry;
        GET_HASH_ENTRY(CmpNameCacheTable, ConvKey).Entry = HashEntry;
    }

    /* Release NCB lock */
    CmpReleaseNcbLockByKey(ConvKey);

    /* Return the NCB found */
    return Ncb;
}
Exemplo n.º 13
0
RTL_GENERIC_COMPARE_RESULTS
NTAPI
CompareUnicodeStrings(IN PUNICODE_STRING Prefix,
                      IN PUNICODE_STRING String,
                      IN ULONG CaseCheckChar)
{
    ULONG StringLength = String->Length / sizeof(WCHAR);
    ULONG PrefixLength = Prefix->Length / sizeof(WCHAR);
    ULONG ScanLength = min(StringLength, PrefixLength);
    ULONG i;
    WCHAR FoundPrefix, FoundString;
    PWCHAR p, p1;

    /* Handle case noticed in npfs when Prefix = '\' and name starts with '\' */
    if ((PrefixLength == 1) &&
        (Prefix->Buffer[0] == '\\') &&
        (StringLength > 1) &&
        (String->Buffer[0] == '\\'))
    {
        /* The string is actually a prefix */
        return -1;
    }

    /* Validate the Case Check Character Position */
    if (CaseCheckChar > ScanLength) CaseCheckChar = ScanLength;

    /* Do the case sensitive comparison first */
    for (i = 0; i < CaseCheckChar; i++)
    {
        /* Compare the two characters */
        if (Prefix->Buffer[i] != String->Buffer[i]) break;
    }

    /* Save the characters we found */
    FoundPrefix = Prefix->Buffer[i];
    FoundString = String->Buffer[i];

    /* Check if we exausted the search above */
    if (i == CaseCheckChar)
    {
        /* Do a case-insensitive search */
        p = &Prefix->Buffer[i];
        p1 = &String->Buffer[i];
        do
        {
            /* Move to the next character */
            FoundPrefix = *p++;
            FoundString = *p1++;

            /* Compare it */
            if (FoundPrefix != FoundString)
            {
                /* Upcase the characters */
                FoundPrefix = RtlUpcaseUnicodeChar(FoundPrefix);
                FoundString = RtlUpcaseUnicodeChar(FoundString);

                /* Compare them again */
                if (FoundPrefix != FoundString) break;
            }

            /* Move to the next char */
            i++;
        } while (i < ScanLength);
    }

    /* Check if we weren't able to find a match in the loops */
    if (i < ScanLength)
    {
        /* If the prefix character found was a backslash, this is a less */
        if (FoundPrefix == '\\') return GenericLessThan;

        /* If the string character found was a backslack, then this is a more */
        if (FoundString == '\\') return GenericGreaterThan;

        /* None of those two special cases, do a normal check */
        if (FoundPrefix < FoundString) return GenericLessThan;

        /* The only choice left is that Prefix > String */
        return GenericGreaterThan;
    }

    /* If we got here, a match was found. Check if the prefix is smaller */
    if (PrefixLength < StringLength)
    {
        /* Check if the string is actually a prefix */
        if (String->Buffer[PrefixLength] == '\\') return -1;

        /* It's not a prefix, and it's shorter, so it's a less */
        return GenericLessThan;
    }

    /* Check if the prefix is longer */
    if (PrefixLength > StringLength) return GenericGreaterThan;

    /* If we got here, then they are 100% equal */
    return GenericEqual;
}
Exemplo n.º 14
0
NTSTATUS
NTAPI
SmpCreateVolumeDescriptors(VOID)
{
    NTSTATUS Status;
    UNICODE_STRING VolumePath;
    BOOLEAN BootVolumeFound = FALSE;
    WCHAR StartChar, Drive, DriveDiff;
    HANDLE VolumeHandle;
    OBJECT_ATTRIBUTES ObjectAttributes;
    IO_STATUS_BLOCK IoStatusBlock;
    PROCESS_DEVICEMAP_INFORMATION ProcessInformation;
    FILE_FS_DEVICE_INFORMATION DeviceInfo;
    FILE_FS_SIZE_INFORMATION SizeInfo;
    PSMP_VOLUME_DESCRIPTOR Volume;
    LARGE_INTEGER FreeSpace, FinalFreeSpace;
    WCHAR Buffer[32];

    /* We should be starting with an empty list */
    ASSERT(IsListEmpty(&SmpVolumeDescriptorList));

    /* Query the device map so we can get the drive letters */
    Status = NtQueryInformationProcess(NtCurrentProcess(),
                                       ProcessDeviceMap,
                                       &ProcessInformation,
                                       sizeof(ProcessInformation),
                                       NULL);
    if (!NT_SUCCESS(Status))
    {
        DPRINT1("SMSS:PFILE: Query(ProcessDeviceMap) failed with status %X \n",
                Status);
        return Status;
    }

    /* Build the volume string, starting with A: (we'll edit this in place) */
    wcscpy(Buffer, L"\\??\\A:\\");
    RtlInitUnicodeString(&VolumePath, Buffer);

    /* Start with the C drive except on weird Japanese NECs... */
    StartChar = SharedUserData->AlternativeArchitecture ? L'A' : L'C';
    for (Drive = StartChar, DriveDiff = StartChar - L'A'; Drive <= L'Z'; Drive++, DriveDiff++)
    {
        /* Skip the disk if it's not in the drive map */
        if (!((1 << DriveDiff) & ProcessInformation.Query.DriveMap)) continue;

        /* Write the drive letter and try to open the volume */
        VolumePath.Buffer[STANDARD_DRIVE_LETTER_OFFSET] = Drive;
        InitializeObjectAttributes(&ObjectAttributes,
                                   &VolumePath,
                                   OBJ_CASE_INSENSITIVE,
                                   NULL,
                                   NULL);
        Status = NtOpenFile(&VolumeHandle,
                            FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
                            &ObjectAttributes,
                            &IoStatusBlock,
                            FILE_SHARE_READ | FILE_SHARE_WRITE,
                            FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE);
        if (!NT_SUCCESS(Status))
        {
            /* Skip the volume if we failed */
            DPRINT1("SMSS:PFILE: Open volume `%wZ' failed with status %X \n",
                    &VolumePath, Status);
            continue;
        }

        /* Now query device information on the volume */
        Status = NtQueryVolumeInformationFile(VolumeHandle,
                                              &IoStatusBlock,
                                              &DeviceInfo,
                                              sizeof(DeviceInfo),
                                              FileFsDeviceInformation);
        if (!NT_SUCCESS(Status))
        {
            /* Move to the next volume if we failed */
            DPRINT1("SMSS:PFILE: Query volume `%wZ' (handle %p) for device info"
                    " failed with status %X \n",
                    &VolumePath,
                    VolumeHandle,
                    Status);
            NtClose(VolumeHandle);
            continue;
        }

        /* Check if this is a fixed disk */
        if (DeviceInfo.Characteristics & (FILE_FLOPPY_DISKETTE |
                                          FILE_READ_ONLY_DEVICE |
                                          FILE_REMOTE_DEVICE |
                                          FILE_REMOVABLE_MEDIA))
        {
            /* It isn't, so skip it */
            DPRINT1("SMSS:PFILE: Volume `%wZ' (%X) cannot store a paging file \n",
                    &VolumePath,
                    DeviceInfo.Characteristics);
            NtClose(VolumeHandle);
            continue;
        }

        /* We found a fixed volume, allocate a descriptor for it */
        Volume = RtlAllocateHeap(RtlGetProcessHeap(),
                                 HEAP_ZERO_MEMORY,
                                 sizeof(SMP_VOLUME_DESCRIPTOR));
        if (!Volume)
        {
            /* Failed to allocate memory, try the next disk */
            DPRINT1("SMSS:PFILE: Failed to allocate a volume descriptor (%u bytes) \n",
                    sizeof(SMP_VOLUME_DESCRIPTOR));
            NtClose(VolumeHandle);
            continue;
        }

        /* Save the drive letter and device information */
        Volume->DriveLetter = Drive;
        Volume->DeviceInfo = DeviceInfo;

        /* Check if this is the boot volume */
        if (RtlUpcaseUnicodeChar(Drive) ==
                RtlUpcaseUnicodeChar(SharedUserData->NtSystemRoot[0]))
        {
            /* Save it */
            ASSERT(BootVolumeFound == FALSE);
            Volume->Flags |= SMP_VOLUME_IS_BOOT;
            BootVolumeFound = TRUE;
        }

        /* Now get size information on the volume */
        Status = NtQueryVolumeInformationFile(VolumeHandle,
                                              &IoStatusBlock,
                                              &SizeInfo,
                                              sizeof(SizeInfo),
                                              FileFsSizeInformation);
        if (!NT_SUCCESS(Status))
        {
            /* We failed -- keep going */
            DPRINT1("SMSS:PFILE: Query volume `%wZ' (handle %p) for size failed"
                    " with status %X \n",
                    &VolumePath,
                    VolumeHandle,
                    Status);
            RtlFreeHeap(RtlGetProcessHeap(), 0, Volume);
            NtClose(VolumeHandle);
            continue;
        }

        /* Done querying volume information, close the handle */
        NtClose(VolumeHandle);

        /* Compute how much free space we have */
        FreeSpace.QuadPart = SizeInfo.AvailableAllocationUnits.QuadPart *
                             SizeInfo.SectorsPerAllocationUnit;
        FinalFreeSpace.QuadPart = FreeSpace.QuadPart * SizeInfo.BytesPerSector;

        /* Check if there's less than 32MB free so we don't starve the disk */
        if (FinalFreeSpace.QuadPart <= MINIMUM_TO_KEEP_FREE)
        {
            /* In this case, act as if there's no free space  */
            Volume->FreeSpace.QuadPart = 0;
        }
        else
        {
            /* Trim off 32MB to give the disk a bit of breathing room */
            Volume->FreeSpace.QuadPart = FinalFreeSpace.QuadPart -
                                         MINIMUM_TO_KEEP_FREE;
        }

        /* All done, add this volume to our descriptor list */
        InsertTailList(&SmpVolumeDescriptorList, &Volume->Entry);
        Volume->Flags |= SMP_VOLUME_INSERTED;
        DPRINT("SMSS:PFILE: Created volume descriptor for`%wZ' \n", &VolumePath);
    }

    /* We must've found at least the boot volume */
    ASSERT(BootVolumeFound == TRUE);
    ASSERT(!IsListEmpty(&SmpVolumeDescriptorList));
    if (!IsListEmpty(&SmpVolumeDescriptorList)) return STATUS_SUCCESS;

    /* Something is really messed up if we found no disks at all */
    return STATUS_UNEXPECTED_IO_ERROR;
}
Exemplo n.º 15
0
NTSTATUS
NTAPI
SmpCreatePagingFileDescriptor(IN PUNICODE_STRING PageFileToken)
{
    NTSTATUS Status;
    ULONG MinSize = 0, MaxSize = 0;
    BOOLEAN SystemManaged = FALSE, ZeroSize = TRUE;
    PSMP_PAGEFILE_DESCRIPTOR Descriptor, ListDescriptor;
    ULONG i;
    WCHAR c;
    PLIST_ENTRY NextEntry;
    UNICODE_STRING PageFileName, Arguments, SecondArgument;

    /* Make sure we don't have too many */
    if (SmpNumberOfPagingFiles >= 16)
    {
        DPRINT1("SMSS:PFILE: Too many paging files specified - %lu\n",
                SmpNumberOfPagingFiles);
        return STATUS_TOO_MANY_PAGING_FILES;
    }

    /* Parse the specified and get the name and arguments out of it */
    DPRINT("SMSS:PFILE: Paging file specifier `%wZ' \n", PageFileToken);
    Status = SmpParseCommandLine(PageFileToken,
                                 NULL,
                                 &PageFileName,
                                 NULL,
                                 &Arguments);
    if (!NT_SUCCESS(Status))
    {
        /* Fail */
        DPRINT1("SMSS:PFILE: SmpParseCommandLine( %wZ ) failed - Status == %lx\n",
                PageFileToken, Status);
        return Status;
    }

    /* Set the variable to let everyone know we have a pagefile token */
    SmpRegistrySpecifierPresent = TRUE;

    /* Parse the arguments, if any */
    if (Arguments.Buffer)
    {
        /* Parse the pagefile size */
        for (i = 0; i < Arguments.Length / sizeof(WCHAR); i++)
        {
            /* Check if it's zero */
            c = Arguments.Buffer[i];
            if ((c != L' ') && (c != L'\t') && (c != L'0'))
            {
                /* It isn't, break out */
                ZeroSize = FALSE;
                break;
            }
        }
    }

    /* Was a pagefile not specified, or was it specified with no size? */
    if (!(Arguments.Buffer) || (ZeroSize))
    {
        /* In this case, the system will manage its size */
        SystemManaged = TRUE;
    }
    else
    {
        /* We do have a size, so convert the arguments into a number */
        Status = RtlUnicodeStringToInteger(&Arguments, 0, &MinSize);
        if (!NT_SUCCESS(Status))
        {
            /* Fail */
            RtlFreeUnicodeString(&PageFileName);
            RtlFreeUnicodeString(&Arguments);
            return Status;
        }

        /* Now advance to the next argument */
        for (i = 0; i < Arguments.Length / sizeof(WCHAR); i++)
        {
            /* Found a space -- second argument must start here */
            if (Arguments.Buffer[i] == L' ')
            {
                /* Use the rest of the arguments as a maximum size */
                SecondArgument.Buffer = &Arguments.Buffer[i];
                SecondArgument.Length = (USHORT)(Arguments.Length -
                                                 i * sizeof(WCHAR));
                SecondArgument.MaximumLength = (USHORT)(Arguments.MaximumLength -
                                                        i * sizeof(WCHAR));
                Status = RtlUnicodeStringToInteger(&SecondArgument, 0, &MaxSize);
                if (!NT_SUCCESS(Status))
                {
                    /* Fail */
                    RtlFreeUnicodeString(&PageFileName);
                    RtlFreeUnicodeString(&Arguments);
                    return Status;
                }

                break;
            }
        }
    }

    /* We are done parsing arguments */
    RtlFreeUnicodeString(&Arguments);

    /* Now we can allocate our descriptor */
    Descriptor = RtlAllocateHeap(RtlGetProcessHeap(),
                                 HEAP_ZERO_MEMORY,
                                 sizeof(SMP_PAGEFILE_DESCRIPTOR));
    if (!Descriptor)
    {
        /* Fail if we couldn't */
        RtlFreeUnicodeString(&PageFileName);
        return STATUS_NO_MEMORY;
    }

    /* Capture all our data into the descriptor */
    Descriptor->Token = *PageFileToken;
    Descriptor->Name = PageFileName;
    Descriptor->MinSize.QuadPart = MinSize * MEGABYTE;
    Descriptor->MaxSize.QuadPart = MaxSize * MEGABYTE;
    if (SystemManaged) Descriptor->Flags |= SMP_PAGEFILE_SYSTEM_MANAGED;
    Descriptor->Name.Buffer[STANDARD_DRIVE_LETTER_OFFSET] =
        RtlUpcaseUnicodeChar(Descriptor->Name.Buffer[STANDARD_DRIVE_LETTER_OFFSET]);
    if (Descriptor->Name.Buffer[STANDARD_DRIVE_LETTER_OFFSET] == '?')
    {
        Descriptor->Flags |= SMP_PAGEFILE_ON_ANY_DRIVE;
    }

    /* Now loop the existing descriptors */
    NextEntry = SmpPagingFileDescriptorList.Flink;
    do
    {
        /* Are there none, or have we looped back to the beginning? */
        if (NextEntry == &SmpPagingFileDescriptorList)
        {
            /* This means no duplicates exist, so insert our descriptor! */
            InsertTailList(&SmpPagingFileDescriptorList, &Descriptor->Entry);
            SmpNumberOfPagingFiles++;
            DPRINT("SMSS:PFILE: Created descriptor for `%wZ' (`%wZ') \n",
                   PageFileToken, &Descriptor->Name);
            return STATUS_SUCCESS;
        }

        /* Keep going until we find a duplicate, unless we are in "any" mode */
        ListDescriptor = CONTAINING_RECORD(NextEntry, SMP_PAGEFILE_DESCRIPTOR, Entry);
        NextEntry = NextEntry->Flink;
    } while (!(ListDescriptor->Flags & SMP_PAGEFILE_ON_ANY_DRIVE) ||
             !(Descriptor->Flags & SMP_PAGEFILE_ON_ANY_DRIVE));

    /* We found a duplicate, so skip this descriptor/pagefile and fail */
    DPRINT1("SMSS:PFILE: Skipping duplicate specifier `%wZ' \n", PageFileToken);
    RtlFreeUnicodeString(&PageFileName);
    RtlFreeHeap(RtlGetProcessHeap(), 0, Descriptor);
    return STATUS_INVALID_PARAMETER;
}
Exemplo n.º 16
0
VOID
ObpHandleDosDeviceName(
    POBJECT_SYMBOLIC_LINK SymbolicLink
    )

/*++

Routine Description:

    This routine does extra processing symbolic links being created in the \??
    object directory.  This processing consists of:

    1.  Determine if the name of the symbolic link is of the form \??\x:
        where x can be any upper or lower case letter.  If this is the
        case then we need to set the bit in KUSER_SHARED_DATA.DosDeviceMap
        to indicate that the drive letter exists.  We also set
        KUSER_SHARED_DATA.DosDeviceDriveType to unknown for now.

    2.  Process the link target, trying to resolve it into a pointer to
        an object other than a object directory object.  All object directories
        traversed must grant world traverse access other wise we bail out.
        If we successfully find a non object directory object, then reference
        the object pointer and store it in the symbolic link object, along
        with a remaining string if any.  ObpLookupObjectName will used this
        cache object pointer to short circuit the name lookup directly to
        the cached object's parse routine.  For any object directory objects
        traversed along the way, increment their symbolic link SymbolicLinkUsageCount
        field.  This field is used whenever an object directory is deleted or
        its security is changed such that it no longer grants world traverse
        access.  In either case, if the field is non-zero we walk all the symbolic links
        and resnap them.

Arguments:

    SymbolicLink - pointer to symbolic link object being created.

    Name - pointer to the name of this symbolic link

Return Value:

    None.

--*/

{
    POBJECT_HEADER ObjectHeader;
    POBJECT_HEADER_NAME_INFO NameInfo;
    WCHAR DosDeviceDriveLetter;
    ULONG DosDeviceDriveIndex;

    //
    // Now see if this symbolic link is being created in the \?? object directory
    // Since we are only called from NtCreateSymbolicLinkObject, after the handle
    // to this symbolic link has been created but before it is returned to the caller
    // the handle can't be closed while we are executing, unless via a random close
    // So no need to hold the type specific mutex while we look at the name.
    //
    ObjectHeader = OBJECT_TO_OBJECT_HEADER( SymbolicLink );
    NameInfo = OBJECT_HEADER_TO_NAME_INFO( ObjectHeader );
    if (NameInfo == NULL || NameInfo->Directory != ObpDosDevicesDirectoryObject) {
        return;
        }

    //
    // Here if we are creating a symbolic link in the \?? object directory
    // See if this is a drive letter definition.  If so set the bit in
    // KUSER_SHARED_DATA.DosDeviceMap
    //
    DosDeviceDriveIndex = 0;
    if (NameInfo->Name.Length == 2 * sizeof( WCHAR ) &&
        NameInfo->Name.Buffer[ 1 ] == L':'
       ) {
        DosDeviceDriveLetter = RtlUpcaseUnicodeChar( NameInfo->Name.Buffer[ 0 ] );
        if (DosDeviceDriveLetter >= L'A' && DosDeviceDriveLetter <= L'Z') {
            DosDeviceDriveIndex = DosDeviceDriveLetter - L'A';
            DosDeviceDriveIndex += 1;
            SymbolicLink->DosDeviceDriveIndex = DosDeviceDriveIndex;
            }
        }

    //
    // Now traverse the target path seeing if we can snap the link now.
    //

    ObpEnterRootDirectoryMutex();
    ObpEnterObjectTypeMutex( ObpSymbolicLinkObjectType );

    ObpProcessDosDeviceSymbolicLink( SymbolicLink, CREATE_SYMBOLIC_LINK );

    ObpLeaveRootDirectoryMutex();
    ObpLeaveObjectTypeMutex( ObpSymbolicLinkObjectType );
    return;
}