[fastfat_new]

- Add directory path parsing which tries to find existing FCBs for path names.
- Add a framework for creating DCBs during path dissection. Currently just prints out path names.
- Cleanup fcb.c, Alexey Vlasov's version was great, but it is a bit different from what I want to implement now.

svn path=/trunk/; revision=43225
This commit is contained in:
Aleksey Bragin 2009-09-29 13:09:16 +00:00
parent 83836038f7
commit a7532a398b
4 changed files with 281 additions and 307 deletions

View file

@ -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

View file

@ -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

View file

@ -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;

View 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 *****************************************************************/
@ -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 */