/*
-* FILE: drivers/fs/vfat/fcb.c
-* PURPOSE: Routines to manipulate FCBs.
-* COPYRIGHT: See COPYING in the top level directory
-* PROJECT: ReactOS kernel
-* PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
-* Rex Jolliff (rex@lvcablemodem.com)
-* Herve Poussineau (reactos@poussine.freesurf.fr)
-*/
+ * PROJECT: ReactOS FAT file system driver
+ * LICENSE: GNU GPLv3 as published by the Free Software Foundation
+ * FILE: drivers/filesystems/fastfat/fcb.c
+ * PURPOSE: FCB manipulation routines.
+ * PROGRAMMERS: Aleksey Bragin <aleksey@reactos.org>
+ */
-/* ------------------------------------------------------- INCLUDES */
-
-#ifdef __GNUC__
-#include <wctype.h> /* towlower prototype */
-#endif
+/* INCLUDES *****************************************************************/
#define NDEBUG
#include "fastfat.h"
-/* -------------------------------------------------------- DEFINES */
-
-#define TAG_FCB TAG('V', 'F', 'C', 'B')
+#define TAG_FILENAME 'fBnF'
-/* -------------------------------------------------------- PUBLICS */
+/* FUNCTIONS ****************************************************************/
-static ULONG vfatNameHash(ULONG hash, PUNICODE_STRING NameU)
+FSRTL_COMPARISON_RESULT
+NTAPI
+FatiCompareNames(PSTRING NameA,
+ PSTRING NameB)
{
- PWCHAR last;
- PWCHAR curr;
- register WCHAR c;
-
- ASSERT(NameU->Buffer[0] != L'.');
- curr = NameU->Buffer;
- last = NameU->Buffer + NameU->Length / sizeof(WCHAR);
-
- while(curr < last)
- {
- c = towlower(*curr++);
- hash = (hash + (c << 4) + (c >> 4)) * 11;
- }
- return hash;
+ 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;
}
-VOID
-vfatSplitPathName(PUNICODE_STRING PathNameU, PUNICODE_STRING DirNameU, PUNICODE_STRING FileNameU)
+PFCB
+NTAPI
+FatFindFcb(PFAT_IRP_CONTEXT IrpContext,
+ PRTL_SPLAY_LINKS *RootNode,
+ PSTRING AnsiName,
+ PBOOLEAN IsDosName)
{
- PWCHAR pName;
- USHORT Length = 0;
- pName = PathNameU->Buffer + PathNameU->Length / sizeof(WCHAR) - 1;
- while (*pName != L'\\' && pName >= PathNameU->Buffer)
- {
- pName--;
- Length++;
- }
- ASSERT(*pName == L'\\' || pName < PathNameU->Buffer);
- if (FileNameU)
- {
- FileNameU->Buffer = pName + 1;
- FileNameU->Length = FileNameU->MaximumLength = Length * sizeof(WCHAR);
- }
- if (DirNameU)
- {
- DirNameU->Buffer = PathNameU->Buffer;
- DirNameU->Length = (pName + 1 - PathNameU->Buffer) * sizeof(WCHAR);
- DirNameU->MaximumLength = DirNameU->Length;
- }
+ PFCB_NAME_LINK Node;
+ 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;
}
-static VOID
-vfatInitFcb(PVFATFCB Fcb, PUNICODE_STRING NameU)
+PFCB
+NTAPI
+FatCreateFcb(IN PFAT_IRP_CONTEXT IrpContext,
+ IN PVCB Vcb,
+ IN PFCB ParentDcb,
+ IN FF_FILE *FileHandle)
{
- USHORT PathNameBufferLength;
-
- if (NameU)
- PathNameBufferLength = NameU->Length + sizeof(WCHAR);
- else
- PathNameBufferLength = 0;
-
- Fcb->PathNameBuffer = ExAllocatePoolWithTag(NonPagedPool, PathNameBufferLength, TAG_FCB);
- if (!Fcb->PathNameBuffer)
- {
- /* FIXME: what to do if no more memory? */
- DPRINT1("Unable to initialize FCB for filename '%wZ'\n", NameU);
- KeBugCheckEx(0, (ULONG_PTR)Fcb, (ULONG_PTR)NameU, 0, 0);
- }
-
- Fcb->PathNameU.Length = 0;
- Fcb->PathNameU.Buffer = Fcb->PathNameBuffer;
- Fcb->PathNameU.MaximumLength = PathNameBufferLength;
- Fcb->ShortNameU.Length = 0;
- Fcb->ShortNameU.Buffer = Fcb->ShortNameBuffer;
- Fcb->ShortNameU.MaximumLength = sizeof(Fcb->ShortNameBuffer);
- Fcb->DirNameU.Buffer = Fcb->PathNameU.Buffer;
- if (NameU && NameU->Length)
- {
- RtlCopyUnicodeString(&Fcb->PathNameU, NameU);
- vfatSplitPathName(&Fcb->PathNameU, &Fcb->DirNameU, &Fcb->LongNameU);
- }
- else
- {
- Fcb->DirNameU.Buffer = Fcb->LongNameU.Buffer = NULL;
- Fcb->DirNameU.MaximumLength = Fcb->DirNameU.Length = 0;
- Fcb->LongNameU.MaximumLength = Fcb->LongNameU.Length = 0;
- }
- RtlZeroMemory(&Fcb->FCBShareAccess, sizeof(SHARE_ACCESS));
- Fcb->OpenHandleCount = 0;
+ 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;
}
-PVFATFCB
-vfatNewFCB(PDEVICE_EXTENSION pVCB, PUNICODE_STRING pFileNameU)
+PCCB
+NTAPI
+FatCreateCcb()
{
- PVFATFCB rcFCB;
-
- DPRINT("'%wZ'\n", pFileNameU);
-
- rcFCB = ExAllocateFromNPagedLookasideList(&VfatGlobalData->FcbLookasideList);
- if (rcFCB == NULL)
- {
- return NULL;
- }
- RtlZeroMemory(rcFCB, sizeof(VFATFCB));
- vfatInitFcb(rcFCB, pFileNameU);
- if (pVCB->Flags & VCB_IS_FATX)
- {
- rcFCB->Flags |= FCB_IS_FATX_ENTRY;
- rcFCB->Attributes = &rcFCB->entry.FatX.Attrib;
- }
- else
- rcFCB->Attributes = &rcFCB->entry.Fat.Attrib;
- rcFCB->Hash.Hash = vfatNameHash(0, &rcFCB->PathNameU);
- rcFCB->Hash.self = rcFCB;
- rcFCB->ShortHash.self = rcFCB;
- ExInitializeResourceLite(&rcFCB->PagingIoResource);
- ExInitializeResourceLite(&rcFCB->MainResource);
- FsRtlInitializeFileLock(&rcFCB->FileLock, NULL, NULL);
- ExInitializeFastMutex(&rcFCB->LastMutex);
- rcFCB->RFCB.PagingIoResource = &rcFCB->PagingIoResource;
- rcFCB->RFCB.Resource = &rcFCB->MainResource;
- rcFCB->RFCB.IsFastIoPossible = FastIoIsNotPossible;
-
- return rcFCB;
+ 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;
}
-VOID
-vfatDestroyCCB(PVFATCCB pCcb)
+IO_STATUS_BLOCK
+NTAPI
+FatiOpenExistingFcb(IN PFAT_IRP_CONTEXT IrpContext,
+ IN PFILE_OBJECT FileObject,
+ IN PVCB Vcb,
+ IN PFCB Fcb,
+ IN PACCESS_MASK DesiredAccess,
+ IN USHORT ShareAccess,
+ IN ULONG AllocationSize,
+ IN PFILE_FULL_EA_INFORMATION EaBuffer,
+ IN ULONG EaLength,
+ IN UCHAR FileAttributes,
+ IN ULONG CreateDisposition,
+ IN BOOLEAN NoEaKnowledge,
+ IN BOOLEAN DeleteOnClose,
+ IN BOOLEAN OpenedAsDos,
+ OUT PBOOLEAN OplockPostIrp)
{
- if (pCcb->SearchPattern.Buffer)
- {
- ExFreePool(pCcb->SearchPattern.Buffer);
- }
- ExFreeToNPagedLookasideList(&VfatGlobalData->CcbLookasideList, pCcb);
+ IO_STATUS_BLOCK Iosb = {{0}};
+ ACCESS_MASK AddedAccess = 0;
+ BOOLEAN Hidden;
+ BOOLEAN System;
+ PCCB Ccb = NULL;
+ NTSTATUS Status;
+
+ /* Acquire exclusive FCB lock */
+ (VOID)FatAcquireExclusiveFcb(IrpContext, Fcb);
+
+ *OplockPostIrp = FALSE;
+
+ /* Check if there is a batch oplock */
+ if (FsRtlCurrentBatchOplock(&Fcb->Fcb.Oplock))
+ {
+ /* Return with a special information field */
+ Iosb.Information = FILE_OPBATCH_BREAK_UNDERWAY;
+
+ /* Check the oplock */
+ Iosb.Status = FsRtlCheckOplock(&Fcb->Fcb.Oplock,
+ IrpContext->Irp,
+ IrpContext,
+ FatOplockComplete,
+ FatPrePostIrp);
+
+ if (Iosb.Status != STATUS_SUCCESS &&
+ Iosb.Status != STATUS_OPLOCK_BREAK_IN_PROGRESS)
+ {
+ /* The Irp needs to be queued */
+ *OplockPostIrp = TRUE;
+
+ /* Release the FCB and return */
+ FatReleaseFcb(IrpContext, Fcb);
+ return Iosb;
+ }
+ }
+
+ /* Validate parameters and modify access */
+ if (CreateDisposition == FILE_CREATE)
+ {
+ Iosb.Status = STATUS_OBJECT_NAME_COLLISION;
+
+ /* Release the FCB and return */
+ FatReleaseFcb(IrpContext, Fcb);
+ return Iosb;
+ }
+ else if (CreateDisposition == FILE_SUPERSEDE)
+ {
+ SetFlag(AddedAccess, DELETE & ~(*DesiredAccess));
+ *DesiredAccess |= DELETE;
+ }
+ else if ((CreateDisposition == FILE_OVERWRITE) ||
+ (CreateDisposition == FILE_OVERWRITE_IF))
+ {
+ SetFlag(AddedAccess,
+ (FILE_WRITE_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES)
+ & ~(*DesiredAccess) );
+
+ *DesiredAccess |= FILE_WRITE_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES;
+ }
+
+ // TODO: Check desired access
+
+ // TODO: Check if this file is readonly and DeleteOnClose is set
+
+ /* Validate disposition information */
+ if ((CreateDisposition == FILE_SUPERSEDE) ||
+ (CreateDisposition == FILE_OVERWRITE) ||
+ (CreateDisposition == FILE_OVERWRITE_IF))
+ {
+ // TODO: Get this attributes from the dirent
+ Hidden = FALSE;
+ System = FALSE;
+
+ if ((Hidden && !FlagOn(FileAttributes, FILE_ATTRIBUTE_HIDDEN)) ||
+ (System && !FlagOn(FileAttributes, FILE_ATTRIBUTE_SYSTEM)))
+ {
+ DPRINT1("Hidden/system attributes don't match\n");
+
+ Iosb.Status = STATUS_ACCESS_DENIED;
+
+ /* Release the FCB and return */
+ FatReleaseFcb(IrpContext, Fcb);
+ return Iosb;
+ }
+
+ // TODO: Check for write protected volume
+ }
+
+ /* Check share access */
+ Iosb.Status = IoCheckShareAccess(*DesiredAccess,
+ ShareAccess,
+ FileObject,
+ &Fcb->ShareAccess,
+ FALSE);
+ if (!NT_SUCCESS(Iosb.Status))
+ {
+ /* Release the FCB and return */
+ FatReleaseFcb(IrpContext, Fcb);
+ return Iosb;
+ }
+
+ /* Check the oplock status after checking for share access */
+ Iosb.Status = FsRtlCheckOplock(&Fcb->Fcb.Oplock,
+ IrpContext->Irp,
+ IrpContext,
+ FatOplockComplete,
+ FatPrePostIrp );
+
+ if (Iosb.Status != STATUS_SUCCESS &&
+ Iosb.Status != STATUS_OPLOCK_BREAK_IN_PROGRESS)
+ {
+ /* The Irp needs to be queued */
+ *OplockPostIrp = TRUE;
+
+ /* Release the FCB and return */
+ FatReleaseFcb(IrpContext, Fcb);
+ return Iosb;
+ }
+
+ /* Set Fast I/O flag */
+ Fcb->Header.IsFastIoPossible = FALSE; //FatiIsFastIoPossible(Fcb);
+
+ /* Make sure image is not mapped */
+ if (DeleteOnClose || FlagOn(*DesiredAccess, FILE_WRITE_DATA))
+ {
+ /* Try to flush the image section */
+ if (!MmFlushImageSection(&Fcb->SectionObjectPointers, MmFlushForWrite))
+ {
+ /* Yes, image section exists, set correct status code */
+ if (DeleteOnClose)
+ Iosb.Status = STATUS_CANNOT_DELETE;
+ else
+ Iosb.Status = STATUS_SHARING_VIOLATION;
+
+ /* Release the FCB and return */
+ FatReleaseFcb(IrpContext, Fcb);
+ return Iosb;
+ }
+ }
+
+ /* Flush the cache if it's non-cached non-pagefile access */
+ if (FlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING) &&
+ Fcb->SectionObjectPointers.DataSectionObject &&
+ !FlagOn(Fcb->State, FCB_STATE_PAGEFILE))
+ {
+ /* Set the flag that create is in progress */
+ SetFlag(Fcb->Vcb->State, VCB_STATE_CREATE_IN_PROGRESS);
+
+ /* Flush the cache */
+ CcFlushCache(&Fcb->SectionObjectPointers, NULL, 0, NULL);
+
+ /* Acquire and release Paging I/O resource before purging the cache section
+ to let lazy writer finish */
+ ExAcquireResourceExclusiveLite( Fcb->Header.PagingIoResource, TRUE);
+ ExReleaseResourceLite( Fcb->Header.PagingIoResource );
+
+ /* Delete the cache section */
+ CcPurgeCacheSection(&Fcb->SectionObjectPointers, NULL, 0, FALSE);
+
+ /* Clear the flag */
+ ClearFlag(Fcb->Vcb->State, VCB_STATE_CREATE_IN_PROGRESS);
+ }
+
+ /* Check create disposition flags and branch accordingly */
+ if (CreateDisposition == FILE_OPEN ||
+ CreateDisposition == FILE_OPEN_IF)
+ {
+ DPRINT("Opening a file\n");
+
+ /* Check if we need to bother with EA */
+ if (NoEaKnowledge && FALSE /* FatIsFat32(Vcb)*/)
+ {
+ UNIMPLEMENTED;
+ }
+
+ /* Set up file object */
+ Ccb = FatCreateCcb(IrpContext);
+ FatSetFileObject(FileObject,
+ UserFileOpen,
+ Fcb,
+ Ccb);
+
+ FileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
+
+ /* The file is opened */
+ Iosb.Information = FILE_OPENED;
+ goto SuccComplete;
+ }
+ else if ((CreateDisposition == FILE_SUPERSEDE) ||
+ (CreateDisposition == FILE_OVERWRITE) ||
+ (CreateDisposition == FILE_OVERWRITE_IF))
+ {
+ UNIMPLEMENTED;
+ ASSERT(FALSE);
+ }
+ else
+ {
+ /* We can't get here */
+ KeBugCheckEx(0x23, CreateDisposition, 0, 0, 0);
+ }
+
+
+SuccComplete:
+ /* If all is fine */
+ if (Iosb.Status != STATUS_PENDING &&
+ NT_SUCCESS(Iosb.Status))
+ {
+ /* Update access if needed */
+ if (AddedAccess)
+ {
+ /* Remove added access flags from desired access */
+ ClearFlag(*DesiredAccess, AddedAccess);
+
+ /* Check share access */
+ Status = IoCheckShareAccess(*DesiredAccess,
+ ShareAccess,
+ FileObject,
+ &Fcb->ShareAccess,
+ TRUE);
+
+ /* Make sure it's success */
+ ASSERT(Status == STATUS_SUCCESS);
+ }
+ else
+ {
+ /* Update the share access */
+ IoUpdateShareAccess(FileObject, &Fcb->ShareAccess);
+ }
+
+ /* Clear the delay close */
+ ClearFlag(Fcb->State, FCB_STATE_DELAY_CLOSE);
+
+ /* Increase counters */
+ Fcb->OpenCount++;
+ Vcb->OpenFileCount++;
+
+ // TODO: Handle DeleteOnClose and OpenedAsDos by storing those flags in CCB
+ }
+
+ return Iosb;
}
VOID
-vfatDestroyFCB(PVFATFCB pFCB)
+NTAPI
+FatGetFcbUnicodeName(IN PFAT_IRP_CONTEXT IrpContext,
+ IN PFCB Fcb,
+ OUT PUNICODE_STRING LongName)
{
- FsRtlUninitializeFileLock(&pFCB->FileLock);
- ExFreePool(pFCB->PathNameBuffer);
- ExDeleteResourceLite(&pFCB->PagingIoResource);
- ExDeleteResourceLite(&pFCB->MainResource);
- ExFreeToNPagedLookasideList(&VfatGlobalData->FcbLookasideList, pFCB);
+ FF_DIRENT DirEnt;
+ FF_ERROR Err;
+ OEM_STRING ShortName;
+ CHAR ShortNameBuf[13];
+ UCHAR EntryBuffer[32];
+ UCHAR NumLFNs;
+ OEM_STRING LongNameOem;
+ NTSTATUS Status;
+
+ /* Make sure this FCB has a FullFAT handle associated with it */
+ if (Fcb->FatHandle == NULL &&
+ FatNodeType(Fcb) == FAT_NTC_DCB)
+ {
+ /* Open the dir with FullFAT */
+ Fcb->FatHandle = FF_OpenW(Fcb->Vcb->Ioman, &Fcb->FullFileName, FF_MODE_DIR, NULL);
+ if (!Fcb->FatHandle)
+ {
+ 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);
}
-BOOLEAN
-vfatFCBIsDirectory(PVFATFCB FCB)
-{
- return *FCB->Attributes & FILE_ATTRIBUTE_DIRECTORY;
-}
-BOOLEAN
-vfatFCBIsRoot(PVFATFCB FCB)
+VOID
+NTAPI
+FatSetFullNameInFcb(PFCB Fcb,
+ PUNICODE_STRING Name)
{
- return FCB->PathNameU.Length == sizeof(WCHAR) && FCB->PathNameU.Buffer[0] == L'\\' ? TRUE : FALSE;
+ 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)
+ {
+ 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 );
+ }
}
VOID
-vfatReleaseFCB(PDEVICE_EXTENSION pVCB, PVFATFCB pFCB)
+NTAPI
+FatSetFullFileNameInFcb(IN PFAT_IRP_CONTEXT IrpContext,
+ IN PFCB Fcb)
{
- HASHENTRY* entry;
- ULONG Index;
- ULONG ShortIndex;
- PVFATFCB tmpFcb;
-
- DPRINT ("releasing FCB at %p: %wZ, refCount:%d\n",
- pFCB,
- &pFCB->PathNameU,
- pFCB->RefCount);
-
- while (pFCB)
- {
- Index = pFCB->Hash.Hash % pVCB->HashTableSize;
- ShortIndex = pFCB->ShortHash.Hash % pVCB->HashTableSize;
- pFCB->RefCount--;
- if (pFCB->RefCount == 0)
- {
- tmpFcb = pFCB->parentFcb;
- RemoveEntryList (&pFCB->FcbListEntry);
- if (pFCB->Hash.Hash != pFCB->ShortHash.Hash)
- {
- entry = pVCB->FcbHashTable[ShortIndex];
- if (entry->self == pFCB)
- {
- pVCB->FcbHashTable[ShortIndex] = entry->next;
- }
- else
- {
- while (entry->next->self != pFCB)
- {
- entry = entry->next;
- }
- entry->next = pFCB->ShortHash.next;
- }
- }
- entry = pVCB->FcbHashTable[Index];
- if (entry->self == pFCB)
- {
- pVCB->FcbHashTable[Index] = entry->next;
- }
- else
- {
- while (entry->next->self != pFCB)
- {
- entry = entry->next;
- }
- entry->next = pFCB->Hash.next;
- }
- vfatDestroyFCB (pFCB);
- }
- else
- {
- tmpFcb = NULL;
- }
- pFCB = tmpFcb;
- }
+ 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
-vfatAddFCBToTable(PDEVICE_EXTENSION pVCB, PVFATFCB pFCB)
+NTAPI
+FatSetFcbNames(IN PFAT_IRP_CONTEXT IrpContext,
+ IN PFCB Fcb)
{
- ULONG Index;
- ULONG ShortIndex;
-
- Index = pFCB->Hash.Hash % pVCB->HashTableSize;
- ShortIndex = pFCB->ShortHash.Hash % pVCB->HashTableSize;
-
- InsertTailList (&pVCB->FcbListHead, &pFCB->FcbListEntry);
-
- pFCB->Hash.next = pVCB->FcbHashTable[Index];
- pVCB->FcbHashTable[Index] = &pFCB->Hash;
- if (pFCB->Hash.Hash != pFCB->ShortHash.Hash)
- {
- pFCB->ShortHash.next = pVCB->FcbHashTable[ShortIndex];
- pVCB->FcbHashTable[ShortIndex] = &pFCB->ShortHash;
- }
- if (pFCB->parentFcb)
- {
- pFCB->parentFcb->RefCount++;
- }
+ 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;
+
+ /* 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);
+
+ /* Add the short name link */
+ FatInsertName(IrpContext, &Fcb->ParentFcb->Dcb.SplayLinksAnsi, &Fcb->ShortName);
+ Fcb->ShortName.Fcb = Fcb;
+
+ /* Get the long file name (if any) */
+ if (NumLFNs > 0)
+ {
+ /* 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);
+ }
+
+ /* 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);
+
+ DPRINT("Converted long name: %wZ\n", UnicodeName);
+
+ /* Add the long unicode name link */
+ FatInsertName(IrpContext, &Fcb->ParentFcb->Dcb.SplayLinksUnicode, &Fcb->LongName);
+ Fcb->LongName.Fcb = Fcb;
+
+ /* 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);
}
-PVFATFCB
-vfatGrabFCBFromTable(PDEVICE_EXTENSION pVCB, PUNICODE_STRING PathNameU)
+VOID
+NTAPI
+Fati8dot3ToString(IN PCHAR FileName,
+ IN BOOLEAN DownCase,
+ OUT POEM_STRING OutString)
{
- PVFATFCB rcFCB;
- ULONG Hash;
- UNICODE_STRING DirNameU;
- UNICODE_STRING FileNameU;
- PUNICODE_STRING FcbNameU;
-
- HASHENTRY* entry;
-
- DPRINT("'%wZ'\n", PathNameU);
-
- Hash = vfatNameHash(0, PathNameU);
-
- entry = pVCB->FcbHashTable[Hash % pVCB->HashTableSize];
- if (entry)
- {
- vfatSplitPathName(PathNameU, &DirNameU, &FileNameU);
- }
-
- while (entry)
- {
- if (entry->Hash == Hash)
- {
- rcFCB = entry->self;
- DPRINT("'%wZ' '%wZ'\n", &DirNameU, &rcFCB->DirNameU);
- if (RtlEqualUnicodeString(&DirNameU, &rcFCB->DirNameU, TRUE))
- {
- if (rcFCB->Hash.Hash == Hash)
- {
- FcbNameU = &rcFCB->LongNameU;
- }
- else
- {
- FcbNameU = &rcFCB->ShortNameU;
- }
- /* compare the file name */
- DPRINT("'%wZ' '%wZ'\n", &FileNameU, FcbNameU);
- if (RtlEqualUnicodeString(&FileNameU, FcbNameU, TRUE))
- {
- rcFCB->RefCount++;
- return rcFCB;
- }
- }
- }
- entry = entry->next;
- }
- return NULL;
+ 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;
+ }
+
+ for (ExtLen = 3; ExtLen > 0; ExtLen--)
+ {
+ if (FileName[8 + ExtLen - 1] != ' ') break;
+ }
+
+ /* 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;
+
+ DPRINT("'%s', len %d\n", OutString->Buffer, OutString->Length);
}
-static NTSTATUS
-vfatFCBInitializeCacheFromVolume (PVCB vcb, PVFATFCB fcb)
+VOID
+NTAPI
+FatInsertName(IN PFAT_IRP_CONTEXT IrpContext,
+ IN PRTL_SPLAY_LINKS *RootNode,
+ IN PFCB_NAME_LINK Name)
{
- PFILE_OBJECT fileObject;
- PVFATCCB newCCB;
-
- fileObject = IoCreateStreamFileObject (NULL, vcb->StorageDevice);
-
- newCCB = ExAllocateFromNPagedLookasideList(&VfatGlobalData->CcbLookasideList);
- if (newCCB == NULL)
- {
- return STATUS_INSUFFICIENT_RESOURCES;
- }
- RtlZeroMemory(newCCB, sizeof (VFATCCB));
-
- fileObject->SectionObjectPointer = &fcb->SectionObjectPointers;
- fileObject->FsContext = fcb;
- fileObject->FsContext2 = newCCB;
- fcb->FileObject = fileObject;
- fcb->RefCount++;
-
- CcInitializeCacheMap(fileObject,
- (PCC_FILE_SIZES)(&fcb->RFCB.AllocationSize),
- TRUE,
- &VfatGlobalData->CacheMgrCallbacks,
- fcb);
-
- fcb->Flags |= FCB_CACHE_INITIALIZED;
- return STATUS_SUCCESS;
+ PFCB_NAME_LINK NameLink;
+ FSRTL_COMPARISON_RESULT Comparison;
+
+ /* Initialize the splay links */
+ RtlInitializeSplayLinks(&Name->Links);
+
+ /* Is this the first entry? */
+ if (*RootNode == NULL)
+ {
+ /* Yes, become root and return */
+ *RootNode = &Name->Links;
+ return;
+ }
+
+ /* Get the name link */
+ NameLink = CONTAINING_RECORD(*RootNode, FCB_NAME_LINK, Links);
+ while (TRUE)
+ {
+ /* Compare the prefix */
+ if (*(PUCHAR)NameLink->Name.Ansi.Buffer != *(PUCHAR)&Name->Name.Ansi.Buffer)
+ {
+ if (*(PUCHAR)NameLink->Name.Ansi.Buffer < *(PUCHAR)&Name->Name.Ansi.Buffer)
+ Comparison = LessThan;
+ else
+ Comparison = GreaterThan;
+ }
+ else
+ {
+ /* Perform real comparison */
+ Comparison = FatiCompareNames(&NameLink->Name.Ansi, &Name->Name.Ansi);
+ }
+
+ /* Check the bad case first */
+ if (Comparison == EqualTo)
+ {
+ /* Must not happen */
+ ASSERT(FALSE);
+ }
+
+ /* Check comparison result */
+ if (Comparison == GreaterThan)
+ {
+ /* Go to the left child */
+ if (!RtlLeftChild(&NameLink->Links))
+ {
+ /* It's absent, insert here and break */
+ RtlInsertAsLeftChild(&NameLink->Links, &Name->Links);
+ break;
+ }
+ else
+ {
+ /* It's present, go inside it */
+ NameLink = CONTAINING_RECORD(RtlLeftChild(&NameLink->Links),
+ FCB_NAME_LINK,
+ Links);
+ }
+ }
+ else
+ {
+ /* Go to the right child */
+ if (!RtlRightChild(&NameLink->Links))
+ {
+ /* It's absent, insert here and break */
+ RtlInsertAsRightChild(&NameLink->Links, &Name->Links);
+ break;
+ }
+ else
+ {
+ /* It's present, go inside it */
+ NameLink = CONTAINING_RECORD(RtlRightChild(&NameLink->Links),
+ FCB_NAME_LINK,
+ Links);
+ }
+ }
+ }
}
-PVFATFCB
-vfatMakeRootFCB(PDEVICE_EXTENSION pVCB)
+VOID
+NTAPI
+FatRemoveNames(IN PFAT_IRP_CONTEXT IrpContext,
+ IN PFCB Fcb)
{
- PVFATFCB FCB;
- ULONG FirstCluster, CurrentCluster, Size = 0;
- NTSTATUS Status = STATUS_SUCCESS;
- UNICODE_STRING NameU = RTL_CONSTANT_STRING(L"\\");
-
- FCB = vfatNewFCB(pVCB, &NameU);
- if (FCB->Flags & FCB_IS_FATX_ENTRY)
- {
- memset(FCB->entry.FatX.Filename, ' ', 42);
- FCB->entry.FatX.FileSize = pVCB->FatInfo.rootDirectorySectors * pVCB->FatInfo.BytesPerSector;
- FCB->entry.FatX.Attrib = FILE_ATTRIBUTE_DIRECTORY;
- FCB->entry.FatX.FirstCluster = 1;
- Size = pVCB->FatInfo.rootDirectorySectors * pVCB->FatInfo.BytesPerSector;
- }
- else
- {
- memset(FCB->entry.Fat.ShortName, ' ', 11);
- FCB->entry.Fat.FileSize = pVCB->FatInfo.rootDirectorySectors * pVCB->FatInfo.BytesPerSector;
- FCB->entry.Fat.Attrib = FILE_ATTRIBUTE_DIRECTORY;
- if (pVCB->FatInfo.FatType == FAT32)
- {
- CurrentCluster = FirstCluster = pVCB->FatInfo.RootCluster;
- FCB->entry.Fat.FirstCluster = (unsigned short)(FirstCluster & 0xffff);
- FCB->entry.Fat.FirstClusterHigh = (unsigned short)(FirstCluster >> 16);
-
- while (CurrentCluster != 0xffffffff && NT_SUCCESS(Status))
- {
- Size += pVCB->FatInfo.BytesPerCluster;
- Status = NextCluster (pVCB, FirstCluster, &CurrentCluster, FALSE);
- }
- }
- else
- {
- FCB->entry.Fat.FirstCluster = 1;
- Size = pVCB->FatInfo.rootDirectorySectors * pVCB->FatInfo.BytesPerSector;
- }
- }
- FCB->ShortHash.Hash = FCB->Hash.Hash;
- FCB->RefCount = 2;
- FCB->dirIndex = 0;
- FCB->RFCB.FileSize.QuadPart = Size;
- FCB->RFCB.ValidDataLength.QuadPart = Size;
- FCB->RFCB.AllocationSize.QuadPart = Size;
- FCB->RFCB.IsFastIoPossible = FastIoIsNotPossible;
-
- vfatFCBInitializeCacheFromVolume(pVCB, FCB);
- vfatAddFCBToTable(pVCB, FCB);
-
- return(FCB);
-}
+ PRTL_SPLAY_LINKS RootNew;
+ PFCB Parent;
-PVFATFCB
-vfatOpenRootFCB(PDEVICE_EXTENSION pVCB)
-{
- PVFATFCB FCB;
- UNICODE_STRING NameU = RTL_CONSTANT_STRING(L"\\");
+ /* Reference the parent for simplicity */
+ Parent = Fcb->ParentFcb;
- FCB = vfatGrabFCBFromTable (pVCB, &NameU);
- if (FCB == NULL)
- {
- FCB = vfatMakeRootFCB (pVCB);
- }
+ /* If this FCB hasn't been added to splay trees - just return */
+ if (!FlagOn( Fcb->State, FCB_STATE_HAS_NAMES ))
+ return;
- return FCB;
-}
+ /* Delete the short name link */
+ RootNew = RtlDelete(&Fcb->ShortName.Links);
-NTSTATUS
-vfatMakeFCBFromDirEntry(
- PVCB vcb,
- PVFATFCB directoryFCB,
- PVFAT_DIRENTRY_CONTEXT DirContext,
- PVFATFCB* fileFCB)
-{
- PVFATFCB rcFCB;
- PWCHAR PathNameBuffer;
- USHORT PathNameLength;
- ULONG Size;
- ULONG hash;
-
- UNICODE_STRING NameU;
-
- PathNameLength = directoryFCB->PathNameU.Length + max(DirContext->LongNameU.Length, DirContext->ShortNameU.Length);
- if (!vfatFCBIsRoot (directoryFCB))
- {
- PathNameLength += sizeof(WCHAR);
- }
-
- if (PathNameLength > LONGNAME_MAX_LENGTH * sizeof(WCHAR))
- {
- return STATUS_OBJECT_NAME_INVALID;
- }
- PathNameBuffer = ExAllocatePoolWithTag(NonPagedPool, PathNameLength + sizeof(WCHAR), TAG_FCB);
- if (!PathNameBuffer)
- {
- return STATUS_INSUFFICIENT_RESOURCES;
- }
- NameU.Buffer = PathNameBuffer;
- NameU.Length = 0;
- NameU.MaximumLength = PathNameLength;
-
- RtlCopyUnicodeString(&NameU, &directoryFCB->PathNameU);
- if (!vfatFCBIsRoot (directoryFCB))
- {
- RtlAppendUnicodeToString(&NameU, L"\\");
- }
- hash = vfatNameHash(0, &NameU);
- if (DirContext->LongNameU.Length > 0)
- {
- RtlAppendUnicodeStringToString(&NameU, &DirContext->LongNameU);
- }
- else
- {
- RtlAppendUnicodeStringToString(&NameU, &DirContext->ShortNameU);
- }
- NameU.Buffer[NameU.Length / sizeof(WCHAR)] = 0;
-
- rcFCB = vfatNewFCB (vcb, &NameU);
- RtlCopyMemory (&rcFCB->entry, &DirContext->DirEntry, sizeof (DIR_ENTRY));
- RtlCopyUnicodeString(&rcFCB->ShortNameU, &DirContext->ShortNameU);
- if (vcb->Flags & VCB_IS_FATX)
- {
- rcFCB->ShortHash.Hash = rcFCB->Hash.Hash;
- }
- else
- {
- rcFCB->ShortHash.Hash = vfatNameHash(hash, &rcFCB->ShortNameU);
- }
-
- if (vfatFCBIsDirectory(rcFCB))
- {
- ULONG FirstCluster, CurrentCluster;
- NTSTATUS Status;
- Size = 0;
- FirstCluster = vfatDirEntryGetFirstCluster (vcb, &rcFCB->entry);
- if (FirstCluster == 1)
- {
- Size = vcb->FatInfo.rootDirectorySectors * vcb->FatInfo.BytesPerSector;
- }
- else if (FirstCluster != 0)
- {
- CurrentCluster = FirstCluster;
- while (CurrentCluster != 0xffffffff)
- {
- Size += vcb->FatInfo.BytesPerCluster;
- Status = NextCluster (vcb, FirstCluster, &CurrentCluster, FALSE);
- }
- }
- }
- else if (rcFCB->Flags & FCB_IS_FATX_ENTRY)
- {
- Size = rcFCB->entry.FatX.FileSize;
- }
- else
- {
- Size = rcFCB->entry.Fat.FileSize;
- }
- rcFCB->dirIndex = DirContext->DirIndex;
- rcFCB->startIndex = DirContext->StartIndex;
- if ((rcFCB->Flags & FCB_IS_FATX_ENTRY) && !vfatFCBIsRoot (directoryFCB))
- {
- ASSERT(DirContext->DirIndex >= 2 && DirContext->StartIndex >= 2);
- rcFCB->dirIndex = DirContext->DirIndex-2;
- rcFCB->startIndex = DirContext->StartIndex-2;
- }
- rcFCB->RFCB.FileSize.QuadPart = Size;
- rcFCB->RFCB.ValidDataLength.QuadPart = Size;
- rcFCB->RFCB.AllocationSize.QuadPart = ROUND_UP(Size, vcb->FatInfo.BytesPerCluster);
- rcFCB->RefCount++;
- if (vfatFCBIsDirectory(rcFCB))
- {
- vfatFCBInitializeCacheFromVolume(vcb, rcFCB);
- }
- rcFCB->parentFcb = directoryFCB;
- vfatAddFCBToTable (vcb, rcFCB);
- *fileFCB = rcFCB;
-
- ExFreePool(PathNameBuffer);
- return STATUS_SUCCESS;
-}
+ /* Set the new root */
+ Parent->Dcb.SplayLinksAnsi = RootNew;
-NTSTATUS
-vfatAttachFCBToFileObject (
- PDEVICE_EXTENSION vcb,
- PVFATFCB fcb,
- PFILE_OBJECT fileObject)
-{
- PVFATCCB newCCB;
+ /* Deal with a unicode name if it exists */
+ if (FlagOn( Fcb->State, FCB_STATE_HAS_UNICODE_NAME ))
+ {
+ /* Delete the long unicode name link */
+ RootNew = RtlDelete(&Fcb->LongName.Links);
- newCCB = ExAllocateFromNPagedLookasideList(&VfatGlobalData->CcbLookasideList);
- if (newCCB == NULL)
- {
- return STATUS_INSUFFICIENT_RESOURCES;
- }
- RtlZeroMemory (newCCB, sizeof (VFATCCB));
+ /* Set the new root */
+ Parent->Dcb.SplayLinksUnicode = RootNew;
- fileObject->SectionObjectPointer = &fcb->SectionObjectPointers;
- fileObject->FsContext = fcb;
- fileObject->FsContext2 = newCCB;
- DPRINT ("file open: fcb:%p PathName:%wZ\n", fcb, &fcb->PathNameU);
+ /* Free the long name string's buffer*/
+ RtlFreeUnicodeString(&Fcb->LongName.Name.String);
- return STATUS_SUCCESS;
-}
+ /* Clear the "has unicode name" flag */
+ ClearFlag(Fcb->State, FCB_STATE_HAS_UNICODE_NAME);
+ }
-NTSTATUS
-vfatDirFindFile (
- PDEVICE_EXTENSION pDeviceExt,
- PVFATFCB pDirectoryFCB,
- PUNICODE_STRING FileToFindU,
- PVFATFCB * pFoundFCB)
-{
- NTSTATUS status;
- PVOID Context = NULL;
- PVOID Page = NULL;
- BOOLEAN First = TRUE;
- VFAT_DIRENTRY_CONTEXT DirContext;
- /* This buffer must have a size of 260 characters, because
- vfatMakeFCBFromDirEntry can copy 20 name entries with 13 characters. */
- WCHAR LongNameBuffer[260];
- WCHAR ShortNameBuffer[13];
- BOOLEAN FoundLong = FALSE;
- BOOLEAN FoundShort = FALSE;
-
- ASSERT(pDeviceExt);
- ASSERT(pDirectoryFCB);
- ASSERT(FileToFindU);
-
- DPRINT ("vfatDirFindFile(VCB:%p, dirFCB:%p, File:%wZ)\n",
- pDeviceExt,
- pDirectoryFCB,
- FileToFindU);
- DPRINT ("Dir Path:%wZ\n", &pDirectoryFCB->PathNameU);
-
- DirContext.DirIndex = 0;
- DirContext.LongNameU.Buffer = LongNameBuffer;
- DirContext.LongNameU.Length = 0;
- DirContext.LongNameU.MaximumLength = sizeof(LongNameBuffer);
- DirContext.ShortNameU.Buffer = ShortNameBuffer;
- DirContext.ShortNameU.Length = 0;
- DirContext.ShortNameU.MaximumLength = sizeof(ShortNameBuffer);
-
- while (TRUE)
- {
- status = pDeviceExt->GetNextDirEntry(&Context,
- &Page,
- pDirectoryFCB,
- &DirContext,
- First);
- First = FALSE;
- if (status == STATUS_NO_MORE_ENTRIES)
- {
- return STATUS_OBJECT_NAME_NOT_FOUND;
- }
- if (!NT_SUCCESS(status))
- {
- return status;
- }
-
- DPRINT (" Index:%d longName:%wZ\n",
- DirContext.DirIndex,
- &DirContext.LongNameU);
- DirContext.LongNameU.Buffer[DirContext.LongNameU.Length / sizeof(WCHAR)] = 0;
- DirContext.ShortNameU.Buffer[DirContext.ShortNameU.Length / sizeof(WCHAR)] = 0;
- if (!ENTRY_VOLUME(pDeviceExt, &DirContext.DirEntry))
- {
- FoundLong = RtlEqualUnicodeString(FileToFindU, &DirContext.LongNameU, TRUE);
- if (FoundLong == FALSE)
- {
- FoundShort = RtlEqualUnicodeString(FileToFindU, &DirContext.ShortNameU, TRUE);
- }
- if (FoundLong || FoundShort)
- {
- status = vfatMakeFCBFromDirEntry (pDeviceExt,
- pDirectoryFCB,
- &DirContext,
- pFoundFCB);
- CcUnpinData(Context);
- return status;
- }
- }
- DirContext.DirIndex++;
- }
-
- return STATUS_OBJECT_NAME_NOT_FOUND;
+ /* This FCB has no names added to splay trees now */
+ ClearFlag(Fcb->State, FCB_STATE_HAS_NAMES);
}
-NTSTATUS
-vfatGetFCBForFile (
- PDEVICE_EXTENSION pVCB,
- PVFATFCB *pParentFCB,
- PVFATFCB *pFCB,
- PUNICODE_STRING pFileNameU)
-{
- NTSTATUS status;
- PVFATFCB FCB = NULL;
- PVFATFCB parentFCB;
- UNICODE_STRING NameU;
- UNICODE_STRING RootNameU = RTL_CONSTANT_STRING(L"\\");
- UNICODE_STRING FileNameU;
- WCHAR NameBuffer[260];
- PWCHAR curr, prev, last;
- ULONG Length;
-
- DPRINT ("vfatGetFCBForFile (%p,%p,%p,%wZ)\n",
- pVCB,
- pParentFCB,
- pFCB,
- pFileNameU);
-
- FileNameU.Buffer = NameBuffer;
- FileNameU.MaximumLength = sizeof(NameBuffer);
- RtlCopyUnicodeString(&FileNameU, pFileNameU);
-
- parentFCB = *pParentFCB;
-
- if (parentFCB == NULL)
- {
- // Trivial case, open of the root directory on volume
- if (RtlEqualUnicodeString(&FileNameU, &RootNameU, FALSE))
- {
- DPRINT ("returning root FCB\n");
-
- FCB = vfatOpenRootFCB (pVCB);
- *pFCB = FCB;
- *pParentFCB = NULL;
-
- return (FCB != NULL) ? STATUS_SUCCESS : STATUS_OBJECT_PATH_NOT_FOUND;
- }
-
- /* Check for an existing FCB */
- FCB = vfatGrabFCBFromTable (pVCB, &FileNameU);
- if (FCB)
- {
- *pFCB = FCB;
- *pParentFCB = FCB->parentFcb;
- (*pParentFCB)->RefCount++;
- return STATUS_SUCCESS;
- }
-
- last = curr = FileNameU.Buffer + FileNameU.Length / sizeof(WCHAR) - 1;
- while (*curr != L'\\' && curr > FileNameU.Buffer)
- {
- curr--;
- }
-
- if (curr > FileNameU.Buffer)
- {
- NameU.Buffer = FileNameU.Buffer;
- NameU.MaximumLength = NameU.Length = (curr - FileNameU.Buffer) * sizeof(WCHAR);
- FCB = vfatGrabFCBFromTable(pVCB, &NameU);
- if (FCB)
- {
- Length = (curr - FileNameU.Buffer) * sizeof(WCHAR);
- if (Length != FCB->PathNameU.Length)
- {
- if (FileNameU.Length + FCB->PathNameU.Length - Length > FileNameU.MaximumLength)
- {
- vfatReleaseFCB (pVCB, FCB);
- return STATUS_OBJECT_NAME_INVALID;
- }
- RtlMoveMemory(FileNameU.Buffer + FCB->PathNameU.Length / sizeof(WCHAR),
- curr, FileNameU.Length - Length);
- FileNameU.Length += (USHORT)(FCB->PathNameU.Length - Length);
- curr = FileNameU.Buffer + FCB->PathNameU.Length / sizeof(WCHAR);
- last = FileNameU.Buffer + FileNameU.Length / sizeof(WCHAR) - 1;
- }
- RtlCopyMemory(FileNameU.Buffer, FCB->PathNameU.Buffer, FCB->PathNameU.Length);
- }
- }
- else
- {
- FCB = NULL;
- }
-
- if (FCB == NULL)
- {
- FCB = vfatOpenRootFCB(pVCB);
- curr = FileNameU.Buffer;
- }
-
- parentFCB = NULL;
- prev = curr;
- }
- else
- {
- FCB = parentFCB;
- parentFCB = NULL;
- prev = curr = FileNameU.Buffer - 1;
- last = FileNameU.Buffer + FileNameU.Length / sizeof(WCHAR) - 1;
- }
-
- while (curr <= last)
- {
- if (parentFCB)
- {
- vfatReleaseFCB (pVCB, parentFCB);
- parentFCB = 0;
- }
- // fail if element in FCB is not a directory
- if (!vfatFCBIsDirectory (FCB))
- {
- DPRINT ("Element in requested path is not a directory\n");
-
- vfatReleaseFCB (pVCB, FCB);
- FCB = NULL;
- *pParentFCB = NULL;
- *pFCB = NULL;
-
- return STATUS_OBJECT_PATH_NOT_FOUND;
- }
- parentFCB = FCB;
- if (prev < curr)
- {
- Length = (curr - prev) * sizeof(WCHAR);
- if (Length != parentFCB->LongNameU.Length)
- {
- if (FileNameU.Length + parentFCB->LongNameU.Length - Length > FileNameU.MaximumLength)
- {
- vfatReleaseFCB (pVCB, parentFCB);
- return STATUS_OBJECT_NAME_INVALID;
- }
- RtlMoveMemory(prev + parentFCB->LongNameU.Length / sizeof(WCHAR), curr,
- FileNameU.Length - (curr - FileNameU.Buffer) * sizeof(WCHAR));
- FileNameU.Length += (USHORT)(parentFCB->LongNameU.Length - Length);
- curr = prev + parentFCB->LongNameU.Length / sizeof(WCHAR);
- last = FileNameU.Buffer + FileNameU.Length / sizeof(WCHAR) - 1;
- }
- RtlCopyMemory(prev, parentFCB->LongNameU.Buffer, parentFCB->LongNameU.Length);
- }
- curr++;
- prev = curr;
- while (*curr != L'\\' && curr <= last)
- {
- curr++;
- }
- NameU.Buffer = FileNameU.Buffer;
- NameU.Length = (curr - NameU.Buffer) * sizeof(WCHAR);
- NameU.MaximumLength = FileNameU.MaximumLength;
- DPRINT("%wZ\n", &NameU);
- FCB = vfatGrabFCBFromTable(pVCB, &NameU);
- if (FCB == NULL)
- {
- NameU.Buffer = prev;
- NameU.MaximumLength = NameU.Length = (curr - prev) * sizeof(WCHAR);
- status = vfatDirFindFile(pVCB, parentFCB, &NameU, &FCB);
- if (status == STATUS_OBJECT_NAME_NOT_FOUND)
- {
- *pFCB = NULL;
- if (curr > last)
- {
- *pParentFCB = parentFCB;
- return STATUS_OBJECT_NAME_NOT_FOUND;
- }
- else
- {
- vfatReleaseFCB (pVCB, parentFCB);
- *pParentFCB = NULL;
- return STATUS_OBJECT_PATH_NOT_FOUND;
- }
- }
- else if (!NT_SUCCESS (status))
- {
- vfatReleaseFCB (pVCB, parentFCB);
- *pParentFCB = NULL;
- *pFCB = NULL;
-
- return status;
- }
- }
- }
-
- *pParentFCB = parentFCB;
- *pFCB = FCB;
-
- return STATUS_SUCCESS;
-}
+/* EOF */