[FASTFAT] Only initialize directory cache on use.
authorPierre Schweitzer <pierre@reactos.org>
Fri, 18 May 2018 12:03:20 +0000 (14:03 +0200)
committerPierre Schweitzer <pierre@reactos.org>
Fri, 18 May 2018 12:09:30 +0000 (14:09 +0200)
This avoids initializing cache directly on directory
open/create.
The advantage is we reduce the load on cache manager
and on memory manager by avoiding creating everytime
a stream file object, and initializing cache for it.

This will avoid initializing cache for started
applications 'current directory' which is just opened
for having a valid handle but no read/write is performed
in it, by default.

This is a step forward for autochk.

CORE-14629

drivers/filesystems/fastfat/cleanup.c
drivers/filesystems/fastfat/create.c
drivers/filesystems/fastfat/dir.c
drivers/filesystems/fastfat/direntry.c
drivers/filesystems/fastfat/dirwr.c
drivers/filesystems/fastfat/fcb.c
drivers/filesystems/fastfat/finfo.c
drivers/filesystems/fastfat/flush.c
drivers/filesystems/fastfat/vfat.h

index 3ab4a10..f611a69 100644 (file)
@@ -88,7 +88,7 @@ VfatCleanupFile(
 
         if (BooleanFlagOn(pFcb->Flags, FCB_IS_DIRTY))
         {
-            VfatUpdateEntry (pFcb, vfatVolumeIsFatX(DeviceExt));
+            VfatUpdateEntry (DeviceExt, pFcb);
         }
 
         if (BooleanFlagOn(pFcb->Flags, FCB_DELETE_PENDING) &&
index d9efa96..84751c2 100644 (file)
@@ -951,7 +951,7 @@ VfatCreateFile(
                                                &pFcb->entry.Fat.UpdateTime);
                 }
 
-                VfatUpdateEntry(pFcb, vfatVolumeIsFatX(DeviceExt));
+                VfatUpdateEntry(DeviceExt, pFcb);
             }
 
             ExAcquireResourceExclusiveLite(&(pFcb->MainResource), TRUE);
index dd53080..18c6dcc 100644 (file)
@@ -599,6 +599,7 @@ DoQuery(
 
     DPRINT("Buffer=%p tofind=%wZ\n", Buffer, &pCcb->SearchPattern);
 
+    DirContext.DeviceExt = IrpContext->DeviceExt;
     DirContext.LongNameU.Buffer = LongNameBuffer;
     DirContext.LongNameU.MaximumLength = sizeof(LongNameBuffer);
     DirContext.ShortNameU.Buffer = ShortNameBuffer;
index f018282..aa1e12f 100644 (file)
@@ -41,12 +41,14 @@ vfatDirEntryGetFirstCluster(
 
 BOOLEAN
 FATIsDirectoryEmpty(
+    PDEVICE_EXTENSION DeviceExt,
     PVFATFCB Fcb)
 {
     LARGE_INTEGER FileOffset;
     PVOID Context = NULL;
     PFAT_DIR_ENTRY FatDirEntry;
     ULONG Index, MaxIndex;
+    NTSTATUS Status;
 
     if (vfatFCBIsRoot(Fcb))
     {
@@ -60,6 +62,12 @@ FATIsDirectoryEmpty(
     FileOffset.QuadPart = 0;
     MaxIndex = Fcb->RFCB.FileSize.u.LowPart / sizeof(FAT_DIR_ENTRY);
 
+    Status = vfatFCBInitializeCacheFromVolume(DeviceExt, Fcb);
+    if (!NT_SUCCESS(Status))
+    {
+        return FALSE;
+    }
+
     while (Index < MaxIndex)
     {
         if (Context == NULL || (Index % FAT_ENTRIES_PER_PAGE) == 0)
@@ -109,16 +117,24 @@ FATIsDirectoryEmpty(
 
 BOOLEAN
 FATXIsDirectoryEmpty(
+    PDEVICE_EXTENSION DeviceExt,
     PVFATFCB Fcb)
 {
     LARGE_INTEGER FileOffset;
     PVOID Context = NULL;
     PFATX_DIR_ENTRY FatXDirEntry;
     ULONG Index = 0, MaxIndex;
+    NTSTATUS Status;
 
     FileOffset.QuadPart = 0;
     MaxIndex = Fcb->RFCB.FileSize.u.LowPart / sizeof(FATX_DIR_ENTRY);
 
+    Status = vfatFCBInitializeCacheFromVolume(DeviceExt, Fcb);
+    if (!NT_SUCCESS(Status))
+    {
+        return FALSE;
+    }
+
     while (Index < MaxIndex)
     {
         if (Context == NULL || (Index % FATX_ENTRIES_PER_PAGE) == 0)
@@ -186,12 +202,20 @@ FATGetNextDirEntry(
     BOOLEAN Valid = TRUE;
     BOOLEAN Back = FALSE;
 
+    NTSTATUS Status;
+
     DirContext->LongNameU.Length = 0;
     DirContext->LongNameU.Buffer[0] = UNICODE_NULL;
 
     FileOffset.u.HighPart = 0;
     FileOffset.u.LowPart = ROUND_DOWN(DirContext->DirIndex * sizeof(FAT_DIR_ENTRY), PAGE_SIZE);
 
+    Status = vfatFCBInitializeCacheFromVolume(DirContext->DeviceExt, pDirFcb);
+    if (!NT_SUCCESS(Status))
+    {
+        return Status;
+    }
+
     if (*pContext == NULL || (DirContext->DirIndex % FAT_ENTRIES_PER_PAGE) == 0)
     {
         if (*pContext != NULL)
@@ -461,6 +485,7 @@ FATXGetNextDirEntry(
     PFATX_DIR_ENTRY fatxDirEntry;
     OEM_STRING StringO;
     ULONG DirIndex = DirContext->DirIndex;
+    NTSTATUS Status;
 
     FileOffset.u.HighPart = 0;
 
@@ -498,6 +523,12 @@ FATXGetNextDirEntry(
         }
     }
 
+    Status = vfatFCBInitializeCacheFromVolume(DirContext->DeviceExt, pDirFcb);
+    if (!NT_SUCCESS(Status))
+    {
+        return Status;
+    }
+
     if (*pContext == NULL || (DirIndex % FATX_ENTRIES_PER_PAGE) == 0)
     {
         if (*pContext != NULL)
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);
 
index 35bb675..89c8dc2 100644 (file)
@@ -640,62 +640,6 @@ vfatGrabFCBFromTable(
     return NULL;
 }
 
-static
-NTSTATUS
-vfatFCBInitializeCacheFromVolume(
-    PVCB vcb,
-    PVFATFCB fcb)
-{
-    PFILE_OBJECT fileObject;
-    PVFATCCB newCCB;
-    NTSTATUS status;
-
-    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);
-    return STATUS_SUCCESS;
-}
-
 PVFATFCB
 vfatMakeRootFCB(
     PDEVICE_EXTENSION pVCB)
@@ -788,16 +732,6 @@ vfatMakeFCBFromDirEntry(
     vfatInitFCBFromDirEntry(vcb, rcFCB, DirContext);
 
     rcFCB->RefCount = 1;
-    if (vfatFCBIsDirectory(rcFCB))
-    {
-        Status = vfatFCBInitializeCacheFromVolume(vcb, rcFCB);
-        if (!NT_SUCCESS(Status))
-        {
-            vfatReleaseFCB(vcb, rcFCB);
-            ExFreePoolWithTag(NameU.Buffer, TAG_FCB);
-            return Status;
-        }
-    }
     rcFCB->parentFcb = directoryFCB;
     InsertTailList(&directoryFCB->ParentListHead, &rcFCB->ParentListEntry);
     vfatAddFCBToTable(vcb, rcFCB);
@@ -880,6 +814,7 @@ vfatDirFindFile(
     DirContext.ShortNameU.Buffer = ShortNameBuffer;
     DirContext.ShortNameU.Length = 0;
     DirContext.ShortNameU.MaximumLength = sizeof(ShortNameBuffer);
+    DirContext.DeviceExt = pDeviceExt;
 
     while (TRUE)
     {
index 97067b9..d860cd6 100644 (file)
@@ -265,7 +265,7 @@ VfatSetBasicInformation(
         }
     }
 
-    VfatUpdateEntry(FCB, vfatVolumeIsFatX(DeviceExt));
+    VfatUpdateEntry(DeviceExt, FCB);
 
     if (NotifyFilter != 0)
     {
@@ -1407,7 +1407,7 @@ VfatSetAllocationSizeInformation(
     Fcb->Flags |= FCB_IS_DIRTY;
     if (AllocSizeChanged)
     {
-        VfatUpdateEntry(Fcb, vfatVolumeIsFatX(DeviceExt));
+        VfatUpdateEntry(DeviceExt, Fcb);
 
         vfatReportChange(DeviceExt, Fcb, FILE_NOTIFY_CHANGE_SIZE, FILE_ACTION_MODIFIED);
     }
index 0629491..ebf1925 100644 (file)
@@ -35,7 +35,7 @@ VfatFlushFile(
 
     if (BooleanFlagOn(Fcb->Flags, FCB_IS_DIRTY))
     {
-        Status = VfatUpdateEntry(Fcb, vfatVolumeIsFatX(DeviceExt));
+        Status = VfatUpdateEntry(DeviceExt, Fcb);
         if (!NT_SUCCESS(Status))
         {
             IoStatus.Status = Status;
index e58b61b..1f29395 100644 (file)
@@ -281,7 +281,7 @@ typedef NTSTATUS (*PGET_NEXT_CLUSTER)(PDEVICE_EXTENSION,ULONG,PULONG);
 typedef NTSTATUS (*PFIND_AND_MARK_AVAILABLE_CLUSTER)(PDEVICE_EXTENSION,PULONG);
 typedef NTSTATUS (*PWRITE_CLUSTER)(PDEVICE_EXTENSION,ULONG,ULONG,PULONG);
 
-typedef BOOLEAN (*PIS_DIRECTORY_EMPTY)(struct _VFATFCB*);
+typedef BOOLEAN (*PIS_DIRECTORY_EMPTY)(PDEVICE_EXTENSION,struct _VFATFCB*);
 typedef NTSTATUS (*PADD_ENTRY)(PDEVICE_EXTENSION,PUNICODE_STRING,struct _VFATFCB**,struct _VFATFCB*,ULONG,UCHAR,struct _VFAT_MOVE_CONTEXT*);
 typedef NTSTATUS (*PDEL_ENTRY)(PDEVICE_EXTENSION,struct _VFATFCB*,struct _VFAT_MOVE_CONTEXT*);
 typedef NTSTATUS (*PGET_NEXT_DIR_ENTRY)(PVOID*,PVOID*,struct _VFATFCB*,struct _VFAT_DIRENTRY_CONTEXT*,BOOLEAN);
@@ -352,7 +352,7 @@ BOOLEAN
 VfatIsDirectoryEmpty(PDEVICE_EXTENSION DeviceExt,
                      struct _VFATFCB* Fcb)
 {
-    return DeviceExt->Dispatch.IsDirectoryEmpty(Fcb);
+    return DeviceExt->Dispatch.IsDirectoryEmpty(DeviceExt, Fcb);
 }
 
 FORCEINLINE
@@ -570,6 +570,7 @@ typedef struct _VFAT_DIRENTRY_CONTEXT
     DIR_ENTRY DirEntry;
     UNICODE_STRING LongNameU;
     UNICODE_STRING ShortNameU;
+    PDEVICE_EXTENSION DeviceExt;
 } VFAT_DIRENTRY_CONTEXT, *PVFAT_DIRENTRY_CONTEXT;
 
 typedef struct _VFAT_MOVE_CONTEXT
@@ -736,10 +737,15 @@ vfatDirEntryGetFirstCluster(
 
 /* dirwr.c */
 
+NTSTATUS
+vfatFCBInitializeCacheFromVolume(
+    PVCB vcb,
+    PVFATFCB fcb);
+
 NTSTATUS
 VfatUpdateEntry(
-    PVFATFCB pFcb,
-    IN BOOLEAN IsFatX);
+    IN PDEVICE_EXTENSION DeviceExt,
+    PVFATFCB pFcb);
 
 BOOLEAN
 vfatFindDirSpace(