[fastfat_new]
[reactos.git] / reactos / drivers / filesystems / fastfat_new / fcb.c
index ba62929..b18509e 100644 (file)
@@ -3,7 +3,7 @@
  * LICENSE:         GPL - See COPYING in the top level directory
  * FILE:            drivers/filesystems/fastfat/fcb.c
  * PURPOSE:         FCB manipulation routines.
- * PROGRAMMERS:     Alexey Vlasov
+ * PROGRAMMERS:     Aleksey Bragin <aleksey@reactos.org>
  */
 
 /* INCLUDES *****************************************************************/
 #define NDEBUG
 #include "fastfat.h"
 
+#define TAG_FILENAME 'fBnF'
+
 /* FUNCTIONS ****************************************************************/
 
-/**
- * Locates FCB by the supplied name in the cache trie of fcbs.
- *
- * @param ParentFcb
- * Supplies a pointer to the parent FCB
- *
- * @param Name
- * Supplied a name of the FCB to be located in cache.
- *
- * @return
- * Pointer to the found FCB or NULL.
- */
+FSRTL_COMPARISON_RESULT
+NTAPI
+FatiCompareNames(PSTRING NameA,
+                 PSTRING NameB)
+{
+    ULONG MinimumLen, i;
+
+    /* Calc the minimum length */
+    MinimumLen = NameA->Length < NameB->Length ? NameA->Length :
+                                                NameB->Length;
+
+    /* Actually compare them */
+    i = (ULONG)RtlCompareMemory( NameA->Buffer, NameB->Buffer, MinimumLen );
+
+    if (i < MinimumLen)
+    {
+        /* Compare prefixes */
+        if (NameA->Buffer[i] < NameB->Buffer[i])
+            return LessThan;
+        else
+            return GreaterThan;
+    }
+
+    /* Final comparison */
+    if (NameA->Length < NameB->Length)
+        return LessThan;
+    else if (NameA->Length > NameB->Length)
+        return GreaterThan;
+    else
+        return EqualTo;
+}
+
 PFCB
-FatLookupFcbByName(
-       IN PFCB ParentFcb,
-       IN PUNICODE_STRING Name)
+NTAPI
+FatFindFcb(PFAT_IRP_CONTEXT IrpContext,
+           PRTL_SPLAY_LINKS *RootNode,
+           PSTRING AnsiName,
+           PBOOLEAN IsDosName)
 {
     PFCB_NAME_LINK Node;
-       PRTL_SPLAY_LINKS Links;
-
-    /* Get sub-trie root node from the parent FCB */
-       Links = ParentFcb->Dcb.SplayLinks;
-       while (Links != NULL)
-       {
-               LONG Comparison;
-
-               Node = CONTAINING_RECORD(Links, FCB_NAME_LINK, Links);
-
-       /*
-        * Compare the name stored in the node
-        * and determine the direction to walk.
-        */
-               Comparison = RtlCompareUnicodeString(&Node->String, Name, TRUE);
-               if (Comparison > 0) {
-            /* Left child */
-                       Links = RtlLeftChild(&Node->Links);
-               }
-               else if (Comparison < 0)
-               {
-            /* Right child */
-                       Links = RtlRightChild(&Node->Links);
-               }
-               else
-               {
-            /* Strings are equal, we have found the node! */
-                       break;
-               }
-       }
-
-    /* The case when nothing was found. */
-       if (Links == NULL)
-               return NULL;
-
-    /* Cast node to the FCB structure. */
-       return CONTAINING_RECORD(Links, FCB, FileName[Node->Type]);
+    FSRTL_COMPARISON_RESULT Comparison;
+    PRTL_SPLAY_LINKS Links;
+
+    Links = *RootNode;
+
+    while (Links)
+    {
+        Node = CONTAINING_RECORD(Links, FCB_NAME_LINK, Links);
+
+        /* Compare the prefix */
+        if (*(PUCHAR)Node->Name.Ansi.Buffer != *(PUCHAR)AnsiName->Buffer)
+        {
+            if (*(PUCHAR)Node->Name.Ansi.Buffer < *(PUCHAR)AnsiName->Buffer)
+                Comparison = LessThan;
+            else
+                Comparison = GreaterThan;
+        }
+        else
+        {
+            /* Perform real comparison */
+            Comparison = FatiCompareNames(&Node->Name.Ansi, AnsiName);
+        }
+
+        /* Do they match? */
+        if (Comparison == GreaterThan)
+        {
+            /* No, it's greater, go to the left child */
+            Links = RtlLeftChild(Links);
+        }
+        else if (Comparison == LessThan)
+        {
+            /* No, it's lesser, go to the right child */
+            Links = RtlRightChild(Links);
+        }
+        else
+        {
+            /* Exact match, balance the tree */
+            *RootNode = RtlSplay(Links);
+
+            /* Save type of the name, if needed */
+            if (IsDosName)
+                *IsDosName = Node->IsDosName;
+
+            /* Return the found fcb */
+            return Node->Fcb;
+        }
+    }
+
+    /* Nothing found */
+    return NULL;
 }
 
-/**
- * Inserts FCB into FCBs cache trie.
- *
- * @param ParentFcb
- * Supplies a pointer to the parent FCB
- *
- * @param Fcb
- * Supplied a pointer to the being inserted FCB.
- *
- * @return
- * TRUE if the FCB was successfully inserted,
- * FASLE in the case of name collision.
- */
-BOOLEAN
-FatLinkFcbNames(
-       IN PFCB ParentFcb,
-       IN PFCB Fcb)
+PFCB
+NTAPI
+FatCreateFcb(IN PFAT_IRP_CONTEXT IrpContext,
+             IN PVCB Vcb,
+             IN PFCB ParentDcb,
+             IN FF_FILE *FileHandle)
 {
-    PFCB_NAME_LINK Name;
-       PRTL_SPLAY_LINKS Links;
-       
-    /* None of the parameters can be NULL */
-       ASSERT(ParentFcb != NULL && Fcb != NULL);
-
-    /* Get root links of the parent FCB. */
-       Links = ParentFcb->Dcb.SplayLinks;
-
-   /*
-    * Get first file name
-    * (short name for FAT because it's always there.
-    */
-       Name = Fcb->FileName;
-
-   /*
-    * Check if ParentDcb links are initialized,
-    * at least one child FCB is cached.
-    */
-       if (Links == NULL)
-       {
-               ParentFcb->Dcb.SplayLinks = Links = &Name->Links;
-               RtlInitializeSplayLinks(Links);
-
-        /* Check if we have more names to cache. */
-               if ((++Name)->String.Length == 0)
-                       return TRUE;
-       }
-    /* Lookup for the insertion point in the trie. */
-       do
-       {
-               LONG Comparison;
-               PFCB_NAME_LINK Node;
-               PRTL_SPLAY_LINKS PrevLinks;
-
-               PrevLinks = Links;
-               Node = CONTAINING_RECORD(Links, FCB_NAME_LINK, Links);
-               Comparison = RtlCompareUnicodeString(&Node->String, &Name->String, TRUE);
-               if (Comparison > 0) {
-                       Links = RtlLeftChild(&Node->Links);
-                       if (Links == NULL)
-                       {
-                               RtlInsertAsLeftChild(PrevLinks, &Name->Links);
-                               break;
-                       }
-               }
-               else if (Comparison < 0)
-               {
-                       Links = RtlRightChild(&Node->Links);
-                       if (Links == NULL)
-                       {
-                               RtlInsertAsRightChild(PrevLinks, &Name->Links);
-                               break;
-                       }
-               }
-               else
-               {
-                       return FALSE;
-               }
-
-        /* Possibly switch to the second (lfn) name and cache that. */
-       } while (Name == Fcb->FileName && (++Name)->String.Length > 0);
-       return TRUE;
+    PFCB Fcb;
+
+    /* Allocate it and zero it */
+    Fcb = ExAllocatePoolWithTag(NonPagedPool, sizeof(FCB), TAG_FCB);
+    RtlZeroMemory(Fcb, sizeof(FCB));
+
+    /* Set node types */
+    Fcb->Header.NodeTypeCode = FAT_NTC_FCB;
+    Fcb->Header.NodeByteSize = sizeof(FCB);
+    Fcb->Condition = FcbGood;
+
+    /* Initialize resources */
+    Fcb->Header.Resource = &Fcb->Resource;
+    ExInitializeResourceLite(Fcb->Header.Resource);
+
+    Fcb->Header.PagingIoResource = &Fcb->PagingIoResource;
+    ExInitializeResourceLite(Fcb->Header.PagingIoResource);
+
+    /* Initialize mutexes */
+    Fcb->Header.FastMutex = &Fcb->HeaderMutex;
+    ExInitializeFastMutex(&Fcb->HeaderMutex);
+    FsRtlSetupAdvancedHeader(&Fcb->Header, &Fcb->HeaderMutex);
+
+    /* Insert into parent's DCB list */
+    InsertTailList(&ParentDcb->Dcb.ParentDcbList, &Fcb->ParentDcbLinks);
+
+    /* Set backlinks */
+    Fcb->ParentFcb = ParentDcb;
+    Fcb->Vcb = Vcb;
+
+    /* Set file handle and sizes */
+    Fcb->Header.FileSize.LowPart = FileHandle->Filesize;
+    Fcb->Header.ValidDataLength.LowPart = FileHandle->Filesize;
+    Fcb->FatHandle = FileHandle;
+
+    /* Set names */
+    FatSetFcbNames(IrpContext, Fcb);
+
+    return Fcb;
 }
 
-/**
- * Unlinks FCB from the FCBs cache trie.
- *
- * @param ParentFcb
- * Supplies a pointer to the parent FCB
- *
- * @param Fcb
- * Supplied a pointer to the being unlinked FCB.
- *
- * @return
- * VOID
- */
-VOID
-FatUnlinkFcbNames(
-       IN PFCB ParentFcb,
-       IN PFCB Fcb)
+PCCB
+NTAPI
+FatCreateCcb()
 {
-    /* See if there is an lfn and unlink that. */
-       if (Fcb->FileName[FcbLongName].String.Length > 0)
-               ParentFcb->Dcb.SplayLinks =
-                       RtlDelete(&Fcb->FileName[FcbLongName].Links);
-
-    /* See if there is a short name and unlink that. */
-       if (Fcb->FileName[FcbShortName].String.Length > 0)
-               ParentFcb->Dcb.SplayLinks =
-                       RtlDelete(&Fcb->FileName[FcbShortName].Links);
+    PCCB Ccb;
+
+    /* Allocate the CCB and zero it */
+    Ccb = ExAllocatePoolWithTag(NonPagedPool, sizeof(CCB), TAG_CCB);
+    RtlZeroMemory(Ccb, sizeof(CCB));
+
+    /* Set mandatory header */
+    Ccb->NodeTypeCode = FAT_NTC_FCB;
+    Ccb->NodeByteSize = sizeof(CCB);
+
+    return Ccb;
 }
 
-NTSTATUS
-FatCreateFcb(
-    OUT PFCB* CreatedFcb,
-    IN PFAT_IRP_CONTEXT IrpContext,
-    IN PFCB ParentFcb,
-       IN PDIR_ENTRY Dirent,
-    IN PUNICODE_STRING FileName,
-       IN PUNICODE_STRING LongFileName OPTIONAL)
+VOID
+NTAPI
+FatSetFullNameInFcb(PFCB Fcb,
+                    PUNICODE_STRING Name)
 {
-       NTSTATUS Status;
-       PFCB Fcb;
-
-    /* Allocate FCB structure. */
-       Fcb = (PFCB) ExAllocateFromNPagedLookasideList(&FatGlobalData.NonPagedFcbList);
-       if (Fcb == NULL)
-               return STATUS_INSUFFICIENT_RESOURCES;
-       RtlZeroMemory(Fcb, sizeof(FCB));
-
-    /* Setup FCB Advanced Header. */
-       Fcb->Header.NodeTypeCode = FAT_NTC_FCB;
-       Fcb->Header.NodeByteSize = sizeof(*Fcb);
-       ExInitializeResourceLite(&Fcb->Resource);
-       Fcb->Header.Resource = &Fcb->Resource;
-       ExInitializeResourceLite(&Fcb->PagingIoResource);
-       Fcb->Header.PagingIoResource = &Fcb->PagingIoResource;
-       ExInitializeFastMutex(&Fcb->HeaderMutex);
-       FsRtlSetupAdvancedHeader(&Fcb->Header, &Fcb->HeaderMutex);
-       Fcb->Header.FileSize.QuadPart = Dirent->FileSize;
-       Fcb->Header.ValidDataLength.QuadPart = Dirent->FileSize;
-       Fcb->Header.IsFastIoPossible = FastIoIsNotPossible;
-
-    /* Setup main fields. */
-       FsRtlInitializeFileLock(&Fcb->Lock, NULL, NULL);
-       FsRtlInitializeLargeMcb(&Fcb->Mcb, PagedPool);
-       Fcb->Vcb = IrpContext->Vcb;
-       Fcb->ParentFcb = ParentFcb;
-       Fcb->FirstCluster = Dirent->FirstCluster
-               | (Dirent->FirstClusterOfFileHi << 0x10);
-
-    /* Setup basic info. */
-    Fcb->BasicInfo.FileAttributes = Dirent->Attributes;
-    FatQueryFileTimes(&Fcb->BasicInfo.CreationTime, Dirent);
-
-    /* Setup short name since always present in FAT. */
-       Fcb->FileName[FcbShortName].Type = FcbShortName;
-       Fcb->FileName[FcbShortName].String.Buffer = Fcb->ShortNameBuffer;
-       Fcb->FileName[FcbShortName].String.MaximumLength = 0x0c;
-       Fcb->FileName[FcbShortName].String.Length = FileName->Length;
-    RtlCopyMemory(Fcb->ShortNameBuffer, FileName->Buffer, FileName->Length);
-
-    /* Just swap optional lfn. */
-       if (ARGUMENT_PRESENT(LongFileName) && LongFileName->Length > 0)
-       {
-               Fcb->FileName[FcbLongName].Type = FcbLongName;
-        Fcb->FileName[FcbLongName].String = *LongFileName;
-        RtlZeroMemory(LongFileName, sizeof(UNICODE_STRING));
-       }
-
-    /* Put FCB into cache trie. */
-       if (!FatLinkFcbNames(ParentFcb, Fcb))
-       {
-               Status = STATUS_OBJECT_NAME_COLLISION;
-               goto FsdFatCreateFcbCleanup;
-       }
-    *CreatedFcb = Fcb;
-
-    /* We are done! */
-       return STATUS_SUCCESS;
-
-FsdFatCreateFcbCleanup:
-    if (ARGUMENT_PRESENT(LongFileName) &&
-        Fcb->FileName[FcbLongName].String.Buffer != NULL)
+    PUNICODE_STRING ParentName;
+
+    /* Make sure this FCB's name wasn't already set */
+    ASSERT(Fcb->FullFileName.Buffer == NULL);
+
+    /* First of all, check exact case name */
+    if (Fcb->ExactCaseLongName.Buffer)
     {
-        /* Swap lfn back to the input parameter */
-        *LongFileName = Fcb->FileName[FcbLongName].String;
+        ASSERT(Fcb->ExactCaseLongName.Length != 0);
+
+        /* Use exact case name */
+        Name = &Fcb->ExactCaseLongName;
+    }
+
+    /* Treat root dir different */
+    if (FatNodeType(Fcb->ParentFcb) == FAT_NTC_ROOT_DCB)
+    {
+        /* Set lengths */
+        Fcb->FullFileName.MaximumLength = sizeof(WCHAR) + Name->Length;
+        Fcb->FullFileName.Length = Fcb->FullFileName.MaximumLength;
+
+        /* Allocate a buffer */
+        Fcb->FullFileName.Buffer = FsRtlAllocatePoolWithTag(PagedPool,
+                                                            Fcb->FullFileName.Length,
+                                                            TAG_FILENAME);
+
+        /* Prefix with a backslash */
+        Fcb->FullFileName.Buffer[0] = L'\\';
+
+        /* Copy the name here */
+        RtlCopyMemory(&Fcb->FullFileName.Buffer[1],
+                      &Name->Buffer[0],
+                       Name->Length );
+    }
+    else
+    {
+        ParentName = &Fcb->ParentFcb->FullFileName;
+
+        /* Check if parent's name is set */
+        if (!ParentName->Buffer)
+            return;
+
+        /* Set lengths */
+        Fcb->FullFileName.MaximumLength =
+            ParentName->Length + sizeof(WCHAR) + Name->Length;
+        Fcb->FullFileName.Length = Fcb->FullFileName.MaximumLength;
+
+        /* Allocate a buffer */
+        Fcb->FullFileName.Buffer = FsRtlAllocatePoolWithTag(PagedPool,
+                                                            Fcb->FullFileName.Length,
+                                                            TAG_FILENAME );
+
+        /* Copy parent's name here */
+        RtlCopyMemory(&Fcb->FullFileName.Buffer[0],
+                      &ParentName->Buffer[0],
+                      ParentName->Length );
+
+        /* Add a backslash */
+        Fcb->FullFileName.Buffer[ParentName->Length / sizeof(WCHAR)] = L'\\';
+
+        /* Copy given name here */
+        RtlCopyMemory(&Fcb->FullFileName.Buffer[(ParentName->Length / sizeof(WCHAR)) + 1],
+                      &Name->Buffer[0],
+                      Name->Length );
     }
-    ExFreeToNPagedLookasideList(&FatGlobalData.NonPagedFcbList, Fcb);
-       return Status;
 }
 
-NTSTATUS
-FatOpenFcb(
-    OUT PFCB* Fcb,
-    IN PFAT_IRP_CONTEXT IrpContext,
-    IN PFCB ParentFcb,
-    IN PUNICODE_STRING FileName)
+VOID
+NTAPI
+FatSetFcbNames(IN PFAT_IRP_CONTEXT IrpContext,
+               IN PFCB Fcb)
 {
-    FAT_FIND_DIRENT_CONTEXT Context;
-    UNICODE_STRING LongFileName;
-    PDIR_ENTRY Dirent;
+    FF_DIRENT DirEnt;
+    FF_ERROR Err;
+    POEM_STRING ShortName;
+    CHAR ShortNameRaw[13];
+    UCHAR EntryBuffer[32];
+    UCHAR NumLFNs;
+    PUNICODE_STRING UnicodeName;
+    OEM_STRING LongNameOem;
     NTSTATUS Status;
 
-    // TODO: _SEH_TRY {
-    if (ParentFcb->Dcb.StreamFileObject == NULL)
+    /* Get the dir entry */
+    Err = FF_GetEntry(Fcb->Vcb->Ioman,
+                      Fcb->FatHandle->DirEntry,
+                      Fcb->FatHandle->DirCluster,
+                      &DirEnt);
+
+    if (Err != FF_ERR_NONE)
+    {
+        DPRINT1("Error %d getting dirent of a file\n", Err);
+        return;
+    }
+
+    /* Read the dirent to fetch the raw short name */
+    FF_FetchEntry(Fcb->Vcb->Ioman,
+                  Fcb->FatHandle->DirCluster,
+                  Fcb->FatHandle->DirEntry,
+                  EntryBuffer);
+    NumLFNs = (UCHAR)(EntryBuffer[0] & ~0x40);
+    RtlCopyMemory(ShortNameRaw, EntryBuffer, 11);
+
+    /* Initialize short name string */
+    ShortName = &Fcb->ShortName.Name.Ansi;
+    ShortName->Buffer = Fcb->ShortNameBuffer;
+    ShortName->Length = 0;
+    ShortName->MaximumLength = sizeof(Fcb->ShortNameBuffer);
+
+    /* Convert raw short name to a proper string */
+    Fati8dot3ToString(ShortNameRaw, FALSE, ShortName);
+
+    /* Get the long file name (if any) */
+    if (NumLFNs > 0)
     {
-        PFILE_OBJECT FileObject;
-        PVPB Vpb;
-    
-        Vpb = IrpContext->Vcb->Vpb;
+        /* Prepare the oem string */
+        LongNameOem.Buffer = DirEnt.FileName;
+        LongNameOem.MaximumLength = FF_MAX_FILENAME;
+        LongNameOem.Length = strlen(DirEnt.FileName);
+
+        /* Prepare the unicode string */
+        UnicodeName = &Fcb->LongName.Name.String;
+        UnicodeName->Length = (LongNameOem.Length + 1) * sizeof(WCHAR);
+        UnicodeName->MaximumLength = UnicodeName->Length;
+        UnicodeName->Buffer = FsRtlAllocatePool(PagedPool, UnicodeName->Length);
+
+        /* Convert it to unicode */
+        Status = RtlOemStringToUnicodeString(UnicodeName, &LongNameOem, FALSE);
+        if (!NT_SUCCESS(Status))
+        {
+            ASSERT(FALSE);
+        }
+
+        RtlDowncaseUnicodeString(UnicodeName, UnicodeName, FALSE);
+        RtlUpcaseUnicodeString(UnicodeName, UnicodeName, FALSE);
+
+        DPRINT1("Converted long name: %wZ\n", UnicodeName);
+    }
 
-        /* Create stream file object */
-        FileObject = IoCreateStreamFileObject(NULL, Vpb->RealDevice);
-        FileObject->Vpb = Vpb;
-        FileObject->SectionObjectPointer = &ParentFcb->SectionObjectPointers;
-        FileObject->FsContext = ParentFcb;
-        FileObject->FsContext2 = NULL;
+    // TODO: Add names to the splay tree
+}
 
-        /* Store it in parent fcb */
-        ParentFcb->Dcb.StreamFileObject = FileObject;
+VOID
+NTAPI
+Fati8dot3ToString(IN PCHAR FileName,
+                  IN BOOLEAN DownCase,
+                  OUT POEM_STRING OutString)
+{
+#if 1
+    ULONG BaseLen, ExtLen;
+    CHAR  *cString = OutString->Buffer;
+    ULONG i;
 
+    /* Calc base and ext lens */
+    for (BaseLen = 8; BaseLen > 0; BaseLen--)
+    {
+        if (FileName[BaseLen - 1] != ' ') break;
     }
 
-    /* Check if cache is initialized. */
-    if (ParentFcb->Dcb.StreamFileObject->PrivateCacheMap == NULL )
+    for (ExtLen = 3; ExtLen > 0; ExtLen--)
     {
-        CcInitializeCacheMap(ParentFcb->Dcb.StreamFileObject,
-            (PCC_FILE_SIZES) &ParentFcb->Header.AllocationSize,
-            TRUE,
-            &FatGlobalData.CacheMgrNoopCallbacks,
-            ParentFcb);
+        if (FileName[8 + ExtLen - 1] != ' ') break;
     }
 
-    /* Page context */
-    Context.Page.FileObject = ParentFcb->Dcb.StreamFileObject;
-    Context.Page.EndOfData = ParentFcb->Header.FileSize;
-    Context.Page.Offset.QuadPart = -1LL;
-    Context.Page.Bcb = NULL;
-    Context.Page.CanWait = BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT);
-    Context.Page.EndOfData = ParentFcb->Header.FileSize;
-
-    /* Search context */
-    Context.ShortName.Length = 0;
-    Context.ShortName.Buffer = Context.ShortNameBuffer;
-    Context.ShortName.MaximumLength = sizeof(Context.ShortNameBuffer);
-    Context.FileName = FileName;
-    Context.Valid8dot3Name = RtlIsNameLegalDOS8Dot3(FileName, NULL, NULL);
-
-    /* Locate the dirent */
-    FatFindDirent(&Context, &Dirent, &LongFileName);
-    Status = FatCreateFcb(Fcb, IrpContext, ParentFcb, Dirent,
-        &Context.ShortName, &LongFileName);
-    return Status;
+    /* Process base name */
+    if (BaseLen)
+    {
+        RtlCopyMemory(cString, FileName, BaseLen);
+
+        /* Substitute the e5 thing */
+        if (cString[0] == 0x05) cString[0] = 0xe5;
+
+        /* Downcase if asked to */
+        if (DownCase)
+        {
+            /* Do it manually */
+            for (i = 0; i < BaseLen; i++)
+            {
+                if (cString[i] >= 'A' &&
+                    cString[i] <= 'Z')
+                {
+                    /* Lowercase it */
+                    cString[i] += 'a' - 'A';
+                }
+
+            }
+        }
+    }
+
+    /* Process extension */
+    if (ExtLen)
+    {
+        /* Add the dot */
+        cString[BaseLen] = '.';
+        BaseLen++;
+
+        /* Copy the extension */
+        for (i = 0; i < ExtLen; i++)
+        {
+            cString[BaseLen + i] = FileName[8 + i];
+        }
+
+        /* Lowercase the extension if asked to */
+        if (DownCase)
+        {
+            /* Do it manually */
+            for (i = BaseLen; i < BaseLen + ExtLen; i++)
+            {
+                if (cString[i] >= 'A' &&
+                    cString[i] <= 'Z')
+                {
+                    /* Lowercase it */
+                    cString[i] += 'a' - 'A';
+                }
+            }
+        }
+    }
+
+    /* Set the length */
+    OutString->Length = BaseLen + ExtLen;
+#else
+    RtlCopyMemory(OutString->Buffer, FileName, 11);
+    OutString->Length = strlen(FileName);
+    ASSERT(OutString->Length <= 12);
+#endif
+
+    DPRINT1("'%s', len %d\n", OutString->Buffer, OutString->Length);
 }
+
+
 /* EOF */