From 388ffabace8ca6e43ed410d032cdf3ebb7693138 Mon Sep 17 00:00:00 2001 From: Aleksey Bragin Date: Mon, 12 Oct 2009 09:30:41 +0000 Subject: [PATCH] [fastfat_new] - Implement all infrastructue for constructing filenames in FCBs, and use it to build full file names. Every FCB has four names: a short upcased name in ANSI, a long upcased name in Unicode, a name in exact case in Unicode, and finally a full file name including all path up to the root. - FatiQueryFileNameInformation now returns correct file name, and other places relying on presence of a correct name work now. svn path=/trunk/; revision=43390 --- .../drivers/filesystems/fastfat_new/create.c | 3 +- .../drivers/filesystems/fastfat_new/fastfat.h | 4 + .../filesystems/fastfat_new/fatstruc.h | 2 + reactos/drivers/filesystems/fastfat_new/fcb.c | 195 ++++++++++++++++++ .../drivers/filesystems/fastfat_new/finfo.c | 15 +- 5 files changed, 212 insertions(+), 7 deletions(-) diff --git a/reactos/drivers/filesystems/fastfat_new/create.c b/reactos/drivers/filesystems/fastfat_new/create.c index 33511ae8cfd..d619ba956ce 100644 --- a/reactos/drivers/filesystems/fastfat_new/create.c +++ b/reactos/drivers/filesystems/fastfat_new/create.c @@ -376,7 +376,8 @@ FatiCreate(IN PFAT_IRP_CONTEXT IrpContext, /* Ensure the name is set */ if (!ParentDcb->FullFileName.Buffer) { - DPRINT1("ParentDcb->FullFileName.Buffer is NULL\n"); + /* Set it if it's missing */ + FatSetFullFileNameInFcb(IrpContext, ParentDcb); } /* Check max path length */ diff --git a/reactos/drivers/filesystems/fastfat_new/fastfat.h b/reactos/drivers/filesystems/fastfat_new/fastfat.h index 55657cc5cf4..ccfb7a2feb4 100644 --- a/reactos/drivers/filesystems/fastfat_new/fastfat.h +++ b/reactos/drivers/filesystems/fastfat_new/fastfat.h @@ -306,6 +306,10 @@ VOID NTAPI FatSetFullNameInFcb(PFCB Fcb, PUNICODE_STRING Name); +VOID NTAPI +FatSetFullFileNameInFcb(IN PFAT_IRP_CONTEXT IrpContext, + IN PFCB Fcb); + VOID NTAPI FatSetFcbNames(IN PFAT_IRP_CONTEXT IrpContext, IN PFCB Fcb); diff --git a/reactos/drivers/filesystems/fastfat_new/fatstruc.h b/reactos/drivers/filesystems/fastfat_new/fatstruc.h index 857ee887810..246cfd407b2 100644 --- a/reactos/drivers/filesystems/fastfat_new/fatstruc.h +++ b/reactos/drivers/filesystems/fastfat_new/fatstruc.h @@ -281,6 +281,8 @@ typedef struct _FCB UNICODE_STRING FullFileName; /* Long name with exact case */ UNICODE_STRING ExactCaseLongName; + /* Hint for the filename length */ + ULONG FileNameLength; /* A copy of fat attribute byte */ UCHAR DirentFatFlags; /* File basic info */ diff --git a/reactos/drivers/filesystems/fastfat_new/fcb.c b/reactos/drivers/filesystems/fastfat_new/fcb.c index 6ca33e6de3e..bffdf7a556c 100644 --- a/reactos/drivers/filesystems/fastfat_new/fcb.c +++ b/reactos/drivers/filesystems/fastfat_new/fcb.c @@ -172,6 +172,84 @@ FatCreateCcb() return Ccb; } +VOID +NTAPI +FatGetFcbUnicodeName(IN PFAT_IRP_CONTEXT IrpContext, + IN PFCB Fcb, + OUT PUNICODE_STRING LongName) +{ + FF_DIRENT DirEnt; + FF_ERROR Err; + OEM_STRING ShortName; + CHAR ShortNameBuf[13]; + UCHAR EntryBuffer[32]; + UCHAR NumLFNs; + OEM_STRING LongNameOem; + NTSTATUS Status; + + /* We support only files now, not directories */ + if (Fcb->Header.NodeTypeCode != FAT_NTC_FCB) + { + UNIMPLEMENTED; + ASSERT(FALSE); + } + + /* 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); + + /* Check if we only have a short name. + Convert it to unicode and return if that's the case */ + if (NumLFNs == 0) + { + /* Initialize short name string */ + ShortName.Buffer = ShortNameBuf; + ShortName.Length = 0; + ShortName.MaximumLength = 12; + + /* Convert raw short name to a proper string */ + Fati8dot3ToString((PCHAR)EntryBuffer, FALSE, &ShortName); + + /* Convert it to unicode */ + Status = RtlOemStringToCountedUnicodeString(LongName, + &ShortName, + FALSE); + + /* Ensure conversion was successful */ + ASSERT(Status == STATUS_SUCCESS); + + /* Exit */ + return; + } + + /* Convert LFN from OEM to unicode and return */ + LongNameOem.Buffer = DirEnt.FileName; + LongNameOem.MaximumLength = FF_MAX_FILENAME; + LongNameOem.Length = strlen(DirEnt.FileName); + + /* Convert it to unicode */ + Status = RtlOemStringToUnicodeString(LongName, &LongNameOem, FALSE); + + /* Ensure conversion was successful */ + ASSERT(Status == STATUS_SUCCESS); +} + + VOID NTAPI FatSetFullNameInFcb(PFCB Fcb, @@ -244,6 +322,99 @@ FatSetFullNameInFcb(PFCB Fcb, } } +VOID +NTAPI +FatSetFullFileNameInFcb(IN PFAT_IRP_CONTEXT IrpContext, + IN PFCB Fcb) +{ + UNICODE_STRING LongName; + PFCB CurFcb = Fcb; + PFCB StopFcb; + PWCHAR TmpBuffer; + ULONG PathLength = 0; + + /* Do nothing if it's already set */ + if (Fcb->FullFileName.Buffer) return; + + /* Allocate a temporary buffer */ + LongName.Length = 0; + LongName.MaximumLength = FF_MAX_FILENAME * sizeof(WCHAR); + LongName.Buffer = + FsRtlAllocatePoolWithTag(PagedPool, + FF_MAX_FILENAME * sizeof(WCHAR), + TAG_FILENAME); + + /* Go through all parents to calculate needed length */ + while (CurFcb != Fcb->Vcb->RootDcb) + { + /* Does current FCB have FullFileName set? */ + if (CurFcb != Fcb && + CurFcb->FullFileName.Buffer) + { + /* Yes, just use it! */ + PathLength += CurFcb->FullFileName.Length; + + Fcb->FullFileName.Buffer = + FsRtlAllocatePoolWithTag(PagedPool, + PathLength, + TAG_FILENAME); + + RtlCopyMemory(Fcb->FullFileName.Buffer, + CurFcb->FullFileName.Buffer, + CurFcb->FullFileName.Length); + + break; + } + + /* Sum up length of a current item */ + PathLength += CurFcb->FileNameLength + sizeof(WCHAR); + + /* Go to the parent */ + CurFcb = CurFcb->ParentFcb; + } + + /* Allocate FullFileName if it wasn't already allocated above */ + if (!Fcb->FullFileName.Buffer) + { + Fcb->FullFileName.Buffer = + FsRtlAllocatePoolWithTag(PagedPool, + PathLength, + TAG_FILENAME); + } + + StopFcb = CurFcb; + + CurFcb = Fcb; + TmpBuffer = Fcb->FullFileName.Buffer + PathLength / sizeof(WCHAR); + + /* Set lengths */ + Fcb->FullFileName.Length = PathLength; + Fcb->FullFileName.MaximumLength = PathLength; + + while (CurFcb != StopFcb) + { + /* Get its unicode name */ + FatGetFcbUnicodeName(IrpContext, + CurFcb, + &LongName); + + /* Copy it */ + TmpBuffer -= LongName.Length / sizeof(WCHAR); + RtlCopyMemory(TmpBuffer, LongName.Buffer, LongName.Length); + + /* Append with a backslash */ + TmpBuffer -= 1; + *TmpBuffer = L'\\'; + + /* Go to the parent */ + CurFcb = CurFcb->ParentFcb; + } + + /* Free the temp buffer */ + ExFreePool(LongName.Buffer); +} + + VOID NTAPI FatSetFcbNames(IN PFAT_IRP_CONTEXT IrpContext, @@ -313,6 +484,21 @@ FatSetFcbNames(IN PFAT_IRP_CONTEXT IrpContext, ASSERT(FALSE); } + /* Set its length */ + Fcb->FileNameLength = UnicodeName->Length; + + /* Save case-preserved copy */ + Fcb->ExactCaseLongName.Length = UnicodeName->Length; + Fcb->ExactCaseLongName.MaximumLength = UnicodeName->Length; + Fcb->ExactCaseLongName.Buffer = + FsRtlAllocatePoolWithTag(PagedPool, UnicodeName->Length, TAG_FILENAME); + + RtlCopyMemory(Fcb->ExactCaseLongName.Buffer, + UnicodeName->Buffer, + UnicodeName->Length); + + /* Perform a trick which is done by MS's FASTFAT driver to monocase + the filename */ RtlDowncaseUnicodeString(UnicodeName, UnicodeName, FALSE); RtlUpcaseUnicodeString(UnicodeName, UnicodeName, FALSE); @@ -325,6 +511,15 @@ FatSetFcbNames(IN PFAT_IRP_CONTEXT IrpContext, /* Indicate that this FCB has a unicode long name */ SetFlag(Fcb->State, FCB_STATE_HAS_UNICODE_NAME); } + else + { + /* No LFN, set exact case name to 0 length */ + Fcb->ExactCaseLongName.Length = 0; + Fcb->ExactCaseLongName.MaximumLength = 0; + + /* Set the length based on the short name */ + Fcb->FileNameLength = RtlOemStringToCountedUnicodeSize(ShortName); + } /* Mark the fact that names were added to splay trees*/ SetFlag(Fcb->State, FCB_STATE_HAS_NAMES); diff --git a/reactos/drivers/filesystems/fastfat_new/finfo.c b/reactos/drivers/filesystems/fastfat_new/finfo.c index ead084273a4..3458ae15aff 100644 --- a/reactos/drivers/filesystems/fastfat_new/finfo.c +++ b/reactos/drivers/filesystems/fastfat_new/finfo.c @@ -59,10 +59,10 @@ FatiQueryInternalInformation(IN PFAT_IRP_CONTEXT IrpContext, VOID NTAPI FatiQueryNameInformation(IN PFAT_IRP_CONTEXT IrpContext, - IN PFCB Fcb, - IN PFILE_OBJECT FileObject, - IN OUT PFILE_NAME_INFORMATION Buffer, - IN OUT PLONG Length) + IN PFCB Fcb, + IN PFILE_OBJECT FileObject, + IN OUT PFILE_NAME_INFORMATION Buffer, + IN OUT PLONG Length) { ULONG ByteSize; ULONG Trim = 0; @@ -71,8 +71,11 @@ FatiQueryNameInformation(IN PFAT_IRP_CONTEXT IrpContext, /* Deduct the minimum written length */ *Length -= FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]); - // Build full name if needed - //if (!Fcb->FullFileName.Buffer) + /* Build full name if needed */ + if (!Fcb->FullFileName.Buffer) + { + FatSetFullFileNameInFcb(IrpContext, Fcb); + } DPRINT1("FullFileName %wZ\n", &Fcb->FullFileName); -- 2.17.1