[FASTFAT] Only initialize directory cache on use.
[reactos.git] / drivers / filesystems / fastfat / dirwr.c
index 68f1579..e2026b8 100644 (file)
 #define NDEBUG
 #include <debug.h>
 
+#ifdef KDBG
+extern UNICODE_STRING DebugFile;
+#endif
+
+NTSTATUS
+vfatFCBInitializeCacheFromVolume(
+    PVCB vcb,
+    PVFATFCB fcb)
+{
+    PFILE_OBJECT fileObject;
+    PVFATCCB newCCB;
+    NTSTATUS status;
+    BOOLEAN Acquired;
+
+    /* Don't re-initialize if already done */
+    if (BooleanFlagOn(fcb->Flags, FCB_CACHE_INITIALIZED))
+    {
+        return STATUS_SUCCESS;
+    }
+
+    ASSERT(vfatFCBIsDirectory(fcb));
+
+    Acquired = FALSE;
+    if (!ExIsResourceAcquiredExclusive(&vcb->DirResource))
+    {
+        ExAcquireResourceExclusiveLite(&vcb->DirResource, TRUE);
+        Acquired = TRUE;
+    }
+
+    fileObject = IoCreateStreamFileObject (NULL, vcb->StorageDevice);
+
+#ifdef KDBG
+    if (DebugFile.Buffer != NULL && FsRtlIsNameInExpression(&DebugFile, &fcb->LongNameU, FALSE, NULL))
+    {
+        DPRINT1("Attaching %p to %p (%d)\n", fcb, fileObject, fcb->RefCount);
+    }
+#endif
+
+    newCCB = ExAllocateFromNPagedLookasideList(&VfatGlobalData->CcbLookasideList);
+    if (newCCB == NULL)
+    {
+        ObDereferenceObject(fileObject);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+    RtlZeroMemory(newCCB, sizeof (VFATCCB));
+
+    fileObject->SectionObjectPointer = &fcb->SectionObjectPointers;
+    fileObject->FsContext = fcb;
+    fileObject->FsContext2 = newCCB;
+    fileObject->Vpb = vcb->IoVPB;
+    fcb->FileObject = fileObject;
+
+    _SEH2_TRY
+    {
+        CcInitializeCacheMap(fileObject,
+                             (PCC_FILE_SIZES)(&fcb->RFCB.AllocationSize),
+                             TRUE,
+                             &VfatGlobalData->CacheMgrCallbacks,
+                             fcb);
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        status = _SEH2_GetExceptionCode();
+        fcb->FileObject = NULL;
+        ExFreeToNPagedLookasideList(&VfatGlobalData->CcbLookasideList, newCCB);
+        ObDereferenceObject(fileObject);
+        return status;
+    }
+    _SEH2_END;
+
+    vfatGrabFCB(vcb, fcb);
+    SetFlag(fcb->Flags, FCB_CACHE_INITIALIZED);
+
+    if (Acquired)
+    {
+        ExReleaseResourceLite(&vcb->DirResource);
+    }
+
+    return STATUS_SUCCESS;
+}
+
 /*
  * update an existing FAT entry
  */
 NTSTATUS
 VfatUpdateEntry(
-    IN PVFATFCB pFcb,
-    IN BOOLEAN IsFatX)
+    IN PDEVICE_EXTENSION DeviceExt,
+    IN PVFATFCB pFcb)
 {
     PVOID Context;
     PDIR_ENTRY PinEntry;
     LARGE_INTEGER Offset;
     ULONG SizeDirEntry;
     ULONG dirIndex;
+    NTSTATUS Status;
 
     ASSERT(pFcb);
 
-    if (IsFatX)
+    if (vfatVolumeIsFatX(DeviceExt))
     {
         SizeDirEntry = sizeof(FATX_DIR_ENTRY);
         dirIndex = pFcb->startIndex;
@@ -52,6 +134,12 @@ VfatUpdateEntry(
 
     ASSERT(pFcb->parentFcb);
 
+    Status = vfatFCBInitializeCacheFromVolume(DeviceExt, pFcb->parentFcb);
+    if (!NT_SUCCESS(Status))
+    {
+        return Status;
+    }
+
     Offset.u.HighPart = 0;
     Offset.u.LowPart = dirIndex * SizeDirEntry;
     _SEH2_TRY
@@ -91,6 +179,12 @@ vfatRenameEntry(
 
     DPRINT("vfatRenameEntry(%p, %p, %wZ, %d)\n", DeviceExt, pFcb, FileName, CaseChangeOnly);
 
+    Status = vfatFCBInitializeCacheFromVolume(DeviceExt, pFcb->parentFcb);
+    if (!NT_SUCCESS(Status))
+    {
+        return Status;
+    }
+
     if (vfatVolumeIsFatX(DeviceExt))
     {
         VFAT_DIRENTRY_CONTEXT DirContext;
@@ -120,6 +214,7 @@ vfatRenameEntry(
         pDirEntry->FilenameLength = (unsigned char)NameA.Length;
 
         /* Update FCB */
+        DirContext.DeviceExt = DeviceExt;
         DirContext.ShortNameU.Length = 0;
         DirContext.ShortNameU.MaximumLength = 0;
         DirContext.ShortNameU.Buffer = NULL;
@@ -169,6 +264,12 @@ vfatFindDirSpace(
     else
         SizeDirEntry = sizeof(FAT_DIR_ENTRY);
 
+    Status = vfatFCBInitializeCacheFromVolume(DeviceExt, pDirFcb);
+    if (!NT_SUCCESS(Status))
+    {
+        return Status;
+    }
+
     count = pDirFcb->RFCB.FileSize.u.LowPart / SizeDirEntry;
     size = DeviceExt->FatInfo.BytesPerCluster / SizeDirEntry;
     for (i = 0; i < count; i++, pFatEntry = (PDIR_ENTRY)((ULONG_PTR)pFatEntry + SizeDirEntry))
@@ -343,6 +444,7 @@ FATAddEntry(
     NameA.Length = 0;
     NameA.MaximumLength = sizeof(aName);
 
+    DirContext.DeviceExt = DeviceExt;
     DirContext.ShortNameU.Buffer = ShortNameBuffer;
     DirContext.ShortNameU.Length = 0;
     DirContext.ShortNameU.MaximumLength = sizeof(ShortNameBuffer);
@@ -359,6 +461,7 @@ FATAddEntry(
         needTilde = TRUE;
         needLong = TRUE;
         RtlZeroMemory(&NameContext, sizeof(GENERATE_NAME_CONTEXT));
+        SearchContext.DeviceExt = DeviceExt;
         SearchContext.LongNameU.Buffer = LongNameBuffer;
         SearchContext.LongNameU.MaximumLength = sizeof(LongNameBuffer);
         SearchContext.ShortNameU.Buffer = ShortSearchName;
@@ -577,6 +680,8 @@ FATAddEntry(
         DirContext.DirEntry.Fat.FirstCluster = (unsigned short)CurrentCluster;
     }
 
+    /* No need to init cache here, vfatFindDirSpace() will have done it for us */
+
     i = DeviceExt->FatInfo.BytesPerCluster / sizeof(FAT_DIR_ENTRY);
     FileOffset.u.HighPart = 0;
     FileOffset.u.LowPart = DirContext.StartIndex * sizeof(FAT_DIR_ENTRY);
@@ -659,6 +764,12 @@ FATAddEntry(
 
     if (IsDirectory)
     {
+        Status = vfatFCBInitializeCacheFromVolume(DeviceExt, (*Fcb));
+        if (!NT_SUCCESS(Status))
+        {
+            return Status;
+        }
+
         FileOffset.QuadPart = 0;
         _SEH2_TRY
         {
@@ -741,6 +852,7 @@ FATXAddEntry(
     DirContext.ShortNameU.Buffer = 0;
     DirContext.ShortNameU.Length = 0;
     DirContext.ShortNameU.MaximumLength = 0;
+    DirContext.DeviceExt = DeviceExt;
     RtlZeroMemory(&DirContext.DirEntry.FatX, sizeof(FATX_DIR_ENTRY));
     memset(DirContext.DirEntry.FatX.Filename, 0xff, 42);
     /* Use cluster, if moving */
@@ -784,6 +896,8 @@ FATXAddEntry(
         DirContext.DirEntry.FatX.FileSize = MoveContext->FileSize;
     }
 
+    /* No need to init cache here, vfatFindDirSpace() will have done it for us */
+
     /* add entry into parent directory */
     FileOffset.u.HighPart = 0;
     FileOffset.u.LowPart = Index * sizeof(FATX_DIR_ENTRY);
@@ -829,10 +943,17 @@ FATDelEntry(
     PVOID Context = NULL;
     LARGE_INTEGER Offset;
     PFAT_DIR_ENTRY pDirEntry = NULL;
+    NTSTATUS Status;
 
     ASSERT(pFcb);
     ASSERT(pFcb->parentFcb);
 
+    Status = vfatFCBInitializeCacheFromVolume(DeviceExt, pFcb->parentFcb);
+    if (!NT_SUCCESS(Status))
+    {
+        return Status;
+    }
+
     DPRINT("delEntry PathName \'%wZ\'\n", &pFcb->PathNameU);
     DPRINT("delete entry: %u to %u\n", pFcb->startIndex, pFcb->dirIndex);
     Offset.u.HighPart = 0;
@@ -910,6 +1031,7 @@ FATXDelEntry(
     LARGE_INTEGER Offset;
     PFATX_DIR_ENTRY pDirEntry;
     ULONG StartIndex;
+    NTSTATUS Status;
 
     ASSERT(pFcb);
     ASSERT(pFcb->parentFcb);
@@ -917,6 +1039,12 @@ FATXDelEntry(
 
     StartIndex = pFcb->startIndex;
 
+    Status = vfatFCBInitializeCacheFromVolume(DeviceExt, pFcb->parentFcb);
+    if (!NT_SUCCESS(Status))
+    {
+        return Status;
+    }
+
     DPRINT("delEntry PathName \'%wZ\'\n", &pFcb->PathNameU);
     DPRINT("delete entry: %u\n", StartIndex);
     Offset.u.HighPart = 0;
@@ -1004,8 +1132,8 @@ VfatMoveEntry(
     return Status;
 }
 
-extern BOOLEAN FATXIsDirectoryEmpty(PVFATFCB Fcb);
-extern BOOLEAN FATIsDirectoryEmpty(PVFATFCB Fcb);
+extern BOOLEAN FATXIsDirectoryEmpty(PDEVICE_EXTENSION DeviceExt, PVFATFCB Fcb);
+extern BOOLEAN FATIsDirectoryEmpty(PDEVICE_EXTENSION DeviceExt, PVFATFCB Fcb);
 extern NTSTATUS FATGetNextDirEntry(PVOID *pContext, PVOID *pPage, PVFATFCB pDirFcb, PVFAT_DIRENTRY_CONTEXT DirContext, BOOLEAN First);
 extern NTSTATUS FATXGetNextDirEntry(PVOID *pContext, PVOID *pPage, PVFATFCB pDirFcb, PVFAT_DIRENTRY_CONTEXT DirContext, BOOLEAN First);