#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
/* Control blocks */
PVCB Vcb, DecodedVcb;
- PFCB Fcb;
+ PFCB Fcb, NextFcb;
PCCB Ccb;
PFCB ParentDcb;
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);
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
* 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 *****************************************************************/
#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.
- */
-PFCB
-FatLookupFcbByName(
- IN PFCB ParentFcb,
- IN PUNICODE_STRING Name)
-{
- 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]);
-}
-
-/**
- * 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)
+FSRTL_COMPARISON_RESULT
+NTAPI
+FatiCompareNames(PSTRING NameA,
+ PSTRING NameB)
{
- PFCB_NAME_LINK Name;
- PRTL_SPLAY_LINKS Links;
-
- /* None of the parameters can be NULL */
- ASSERT(ParentFcb != NULL && Fcb != NULL);
+ ULONG MinimumLen, i;
- /* Get root links of the parent FCB. */
- Links = ParentFcb->Dcb.SplayLinks;
+ /* Calc the minimum length */
+ MinimumLen = NameA->Length < NameB->Length ? NameA->Length :
+ NameB->Length;
- /*
- * 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);
-}
+ /* Actually compare them */
+ i = (ULONG)RtlCompareMemory( NameA->Buffer, NameB->Buffer, MinimumLen );
-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)
+ if (i < MinimumLen)
{
- /* Swap lfn back to the input parameter */
- *LongFileName = Fcb->FileName[FcbLongName].String;
+ /* Compare prefixes */
+ if (NameA->Buffer[i] < NameB->Buffer[i])
+ return LessThan;
+ else
+ return GreaterThan;
}
- ExFreeToNPagedLookasideList(&FatGlobalData.NonPagedFcbList, Fcb);
- return Status;
+
+ /* Final comparison */
+ if (NameA->Length < NameB->Length)
+ return LessThan;
+ else if (NameA->Length > NameB->Length)
+ return GreaterThan;
+ else
+ return EqualTo;
}
-NTSTATUS
-FatOpenFcb(
- OUT PFCB* Fcb,
- IN PFAT_IRP_CONTEXT IrpContext,
- IN PFCB ParentFcb,
- IN PUNICODE_STRING FileName)
+PFCB
+NTAPI
+FatFindFcb(PFAT_IRP_CONTEXT IrpContext,
+ PRTL_SPLAY_LINKS *RootNode,
+ PSTRING AnsiName,
+ PBOOLEAN IsDosName)
{
- FAT_FIND_DIRENT_CONTEXT Context;
- UNICODE_STRING LongFileName;
- PDIR_ENTRY Dirent;
- NTSTATUS Status;
-
- // TODO: _SEH_TRY {
- if (ParentFcb->Dcb.StreamFileObject == NULL)
- {
- PFILE_OBJECT FileObject;
- PVPB Vpb;
-
- Vpb = IrpContext->Vcb->Vpb;
-
- /* 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;
+ PFCB_NAME_LINK Node;
+ FSRTL_COMPARISON_RESULT Comparison;
+ PRTL_SPLAY_LINKS Links;
- }
+ Links = *RootNode;
- /* Check if cache is initialized. */
- if (ParentFcb->Dcb.StreamFileObject->PrivateCacheMap == NULL )
+ while (Links)
{
- CcInitializeCacheMap(ParentFcb->Dcb.StreamFileObject,
- (PCC_FILE_SIZES) &ParentFcb->Header.AllocationSize,
- TRUE,
- &FatGlobalData.CacheMgrNoopCallbacks,
- ParentFcb);
+ 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;
+ }
}
- /* 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;
+ /* Nothing found */
+ return NULL;
+}
- /* 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;
-}
-#endif
/* EOF */