diff --git a/reactos/drivers/filesystems/fastfat_new/create.c b/reactos/drivers/filesystems/fastfat_new/create.c index 090e5eea7e8..6530750ef21 100644 --- a/reactos/drivers/filesystems/fastfat_new/create.c +++ b/reactos/drivers/filesystems/fastfat_new/create.c @@ -11,6 +11,16 @@ #define NDEBUG #include "fastfat.h" +NTSYSAPI +NTSTATUS +NTAPI +RtlUpcaseUnicodeStringToCountedOemString( + IN OUT POEM_STRING DestinationString, + IN PCUNICODE_STRING SourceString, + IN BOOLEAN AllocateDestinationString +); + + /* FUNCTIONS *****************************************************************/ IO_STATUS_BLOCK @@ -52,7 +62,7 @@ FatiCreate(IN PFAT_IRP_CONTEXT IrpContext, /* Control blocks */ PVCB Vcb, DecodedVcb; - PFCB Fcb; + PFCB Fcb, NextFcb; PCCB Ccb; PFCB ParentDcb; @@ -72,6 +82,11 @@ FatiCreate(IN PFAT_IRP_CONTEXT IrpContext, NTSTATUS Status; IO_STATUS_BLOCK Iosb; PIO_STACK_LOCATION IrpSp; + BOOLEAN EndBackslash = FALSE, OpenedAsDos; + UNICODE_STRING RemainingPart, FirstName, NextName; + OEM_STRING AnsiFirstName; + + Iosb.Status = STATUS_SUCCESS; /* Get current IRP stack location */ IrpSp = IoGetCurrentIrpStackLocation(Irp); @@ -266,10 +281,178 @@ FatiCreate(IN PFAT_IRP_CONTEXT IrpContext, ParentDcb = Vcb->RootDcb; DPRINT1("ParentDcb %p\n", ParentDcb); } + + /* Check for backslash at the end */ + if (FileName.Length && + FileName.Buffer[FileName.Length / sizeof(WCHAR) - 1] == L'\\') + { + /* Cut it out */ + FileName.Length -= sizeof(WCHAR); + + /* Remember we cut it */ + EndBackslash = TRUE; + } + + /* Ensure the name is set */ + if (!ParentDcb->FullFileName.Buffer) + { + DPRINT1("ParentDcb->FullFileName.Buffer is NULL\n"); + } + + /* Check max path length */ + if (ParentDcb->FullFileName.Length + FileName.Length + sizeof(WCHAR) <= FileName.Length) + { + DPRINT1("Max length is way off\n"); + Iosb.Status = STATUS_OBJECT_NAME_INVALID; + ASSERT(FALSE); + } + + /* Loop through FCBs to find a good one */ + while (TRUE) + { + Fcb = ParentDcb; + + /* Dissect the name */ + RemainingPart = FileName; + while (RemainingPart.Length) + { + FsRtlDissectName(RemainingPart, &FirstName, &NextName); + + /* Check for validity */ + if ((NextName.Length && NextName.Buffer[0] == L'\\') || + (NextName.Length > 255 * sizeof(WCHAR))) + { + /* The name is invalid */ + DPRINT1("Invalid name found\n"); + Iosb.Status = STATUS_OBJECT_NAME_INVALID; + ASSERT(FALSE); + } + + /* Convert the name to ANSI */ + AnsiFirstName.Buffer = ExAllocatePool(PagedPool, FirstName.Length); + AnsiFirstName.Length = 0; + AnsiFirstName.MaximumLength = FirstName.Length; + Status = RtlUpcaseUnicodeStringToCountedOemString(&AnsiFirstName, &FirstName, FALSE); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("RtlUpcaseUnicodeStringToCountedOemString() failed with 0x%08x\n", Status); + ASSERT(FALSE); + NextFcb = NULL; + AnsiFirstName.Length = 0; + } + else + { + /* Find the coresponding FCB */ + NextFcb = FatFindFcb(IrpContext, + &Fcb->Dcb.SplayLinksAnsi, + (PSTRING)&AnsiFirstName, + &OpenedAsDos); + } + + /* Check if we found anything */ + if (!NextFcb && Fcb->Dcb.SplayLinksUnicode) + { + ASSERT(FALSE); + } + + /* Move to the next FCB */ + if (NextFcb) + { + Fcb = NextFcb; + RemainingPart = NextName; + } + + /* Break out of this loop if nothing can be found */ + if (!NextFcb || + NextName.Length == 0 || + FatNodeType(NextFcb) == FAT_NTC_FCB) + { + break; + } + } + + /* Ensure remaining name doesn't start from a backslash */ + if (RemainingPart.Length && + RemainingPart.Buffer[0] == L'\\') + { + /* Cut it */ + RemainingPart.Buffer++; + RemainingPart.Length -= sizeof(WCHAR); + } + + if (Fcb->Condition == FcbGood) + { + /* Good FCB, break out of the loop */ + break; + } + else + { + ASSERT(FALSE); + } + } + + /* We have a valid FCB now */ + if (!RemainingPart.Length) + { + DPRINT1("It's possible to open an existing FCB\n"); + ASSERT(FALSE); + } + + /* During parsing we encountered a part which has no attached FCB/DCB. + Check that the parent is really DCB and not FCB */ + if (FatNodeType(Fcb) != FAT_NTC_ROOT_DCB && + FatNodeType(Fcb) != FAT_NTC_DCB) + { + DPRINT1("Weird FCB node type %x, expected DCB or root DCB\n", FatNodeType(Fcb)); + ASSERT(FALSE); + } + + /* Create additional DCBs for all path items */ + ParentDcb = Fcb; + while (TRUE) + { + FsRtlDissectName(RemainingPart, &FirstName, &RemainingPart); + + /* Check for validity */ + if ((RemainingPart.Length && RemainingPart.Buffer[0] == L'\\') || + (NextName.Length > 255 * sizeof(WCHAR))) + { + /* The name is invalid */ + DPRINT1("Invalid name found\n"); + Iosb.Status = STATUS_OBJECT_NAME_INVALID; + ASSERT(FALSE); + } + + /* Convert the name to ANSI */ + AnsiFirstName.Buffer = ExAllocatePool(PagedPool, FirstName.Length); + AnsiFirstName.Length = 0; + AnsiFirstName.MaximumLength = FirstName.Length; + Status = RtlUpcaseUnicodeStringToCountedOemString(&AnsiFirstName, &FirstName, FALSE); + + if (!NT_SUCCESS(Status)) + { + ASSERT(FALSE); + } + + DPRINT1("FirstName %wZ, RemainingPart %wZ\n", &FirstName, &RemainingPart); + + /* Break if came to the end */ + if (!RemainingPart.Length) break; + + // TODO: Create a DCB for this entry + } + + // Simulate that we opened the file + //Iosb.Information = FILE_OPENED; + Irp->IoStatus.Information = FILE_OPENED; + FileObject->SectionObjectPointer = (PSECTION_OBJECT_POINTERS)0x1; } - //return Iosb.Status; - return STATUS_SUCCESS; + /* Complete the request */ + FatCompleteRequest(IrpContext, Irp, Iosb.Status); + + return Iosb.Status; } NTSTATUS diff --git a/reactos/drivers/filesystems/fastfat_new/fastfat.h b/reactos/drivers/filesystems/fastfat_new/fastfat.h index 7833e4dcb07..349f3b88b66 100644 --- a/reactos/drivers/filesystems/fastfat_new/fastfat.h +++ b/reactos/drivers/filesystems/fastfat_new/fastfat.h @@ -153,6 +153,14 @@ FatDecodeFileObject(IN PFILE_OBJECT FileObject, OUT PFCB *FcbOrDcb, OUT PCCB *Ccb); +/* --------------------------------------------------------- fcb.c */ + +PFCB NTAPI +FatFindFcb(PFAT_IRP_CONTEXT IrpContext, + PRTL_SPLAY_LINKS *RootNode, + PSTRING AnsiName, + PBOOLEAN IsDosName); + /* --------------------------------------------------------- fullfat.c */ FF_T_SINT32 diff --git a/reactos/drivers/filesystems/fastfat_new/fatstruc.h b/reactos/drivers/filesystems/fastfat_new/fatstruc.h index 290bb3a0b3b..6382f44760e 100644 --- a/reactos/drivers/filesystems/fastfat_new/fatstruc.h +++ b/reactos/drivers/filesystems/fastfat_new/fatstruc.h @@ -221,13 +221,14 @@ enum _FCB_NAME_TYPE { } FCB_NAME_TYPE; typedef struct _FCB_NAME_LINK { + struct _FCB *Fcb; RTL_SPLAY_LINKS Links; union { OEM_STRING Ansi; UNICODE_STRING String; } Name; - UCHAR Type; + BOOLEAN IsDosName; } FCB_NAME_LINK, *PFCB_NAME_LINK; typedef enum _FCB_CONDITION @@ -287,7 +288,9 @@ typedef struct _FCB PFILE_OBJECT StreamFileObject; /* Bitmap to search for free dirents. */ RTL_BITMAP FreeBitmap; - PRTL_SPLAY_LINKS SplayLinks; + /* Names */ + PRTL_SPLAY_LINKS SplayLinksAnsi; + PRTL_SPLAY_LINKS SplayLinksUnicode; } Dcb; }; } FCB, *PFCB; diff --git a/reactos/drivers/filesystems/fastfat_new/fcb.c b/reactos/drivers/filesystems/fastfat_new/fcb.c index c52d15261b3..21e29384e68 100644 --- a/reactos/drivers/filesystems/fastfat_new/fcb.c +++ b/reactos/drivers/filesystems/fastfat_new/fcb.c @@ -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 */ /* INCLUDES *****************************************************************/ @@ -12,318 +12,98 @@ #include "fastfat.h" /* FUNCTIONS ****************************************************************/ -#if 0 -/** - * 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; + FSRTL_COMPARISON_RESULT Comparison; + PRTL_SPLAY_LINKS Links; - /* Get sub-trie root node from the parent FCB */ - Links = ParentFcb->Dcb.SplayLinks; - while (Links != NULL) - { - LONG Comparison; + Links = *RootNode; - 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]); -} - -/** - * 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_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; -} - -/** - * 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) -{ - /* 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); -} - -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) -{ - 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) + while (Links) { - /* Swap lfn back to the input parameter */ - *LongFileName = Fcb->FileName[FcbLongName].String; - } - ExFreeToNPagedLookasideList(&FatGlobalData.NonPagedFcbList, Fcb); - return Status; -} + Node = CONTAINING_RECORD(Links, FCB_NAME_LINK, Links); -NTSTATUS -FatOpenFcb( - OUT PFCB* Fcb, - IN PFAT_IRP_CONTEXT IrpContext, - IN PFCB ParentFcb, - IN PUNICODE_STRING FileName) -{ - FAT_FIND_DIRENT_CONTEXT Context; - UNICODE_STRING LongFileName; - PDIR_ENTRY Dirent; - NTSTATUS Status; + /* 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); + } - // TODO: _SEH_TRY { - if (ParentFcb->Dcb.StreamFileObject == NULL) - { - PFILE_OBJECT FileObject; - PVPB Vpb; - - Vpb = IrpContext->Vcb->Vpb; + /* 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); - /* Create stream file object */ - FileObject = IoCreateStreamFileObject(NULL, Vpb->RealDevice); - FileObject->Vpb = Vpb; - FileObject->SectionObjectPointer = &ParentFcb->SectionObjectPointers; - FileObject->FsContext = ParentFcb; - FileObject->FsContext2 = NULL; - - /* Store it in parent fcb */ - ParentFcb->Dcb.StreamFileObject = FileObject; + /* Save type of the name, if needed */ + if (IsDosName) + *IsDosName = Node->IsDosName; + /* Return the found fcb */ + return Node->Fcb; + } } - /* Check if cache is initialized. */ - if (ParentFcb->Dcb.StreamFileObject->PrivateCacheMap == NULL ) - { - CcInitializeCacheMap(ParentFcb->Dcb.StreamFileObject, - (PCC_FILE_SIZES) &ParentFcb->Header.AllocationSize, - TRUE, - &FatGlobalData.CacheMgrNoopCallbacks, - ParentFcb); - } - - /* 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; + /* Nothing found */ + return NULL; } -#endif + + /* EOF */