[FASTFAT] Only initialize directory cache on use.
[reactos.git] / drivers / filesystems / fastfat / direntry.c
index 8a2c3f5..aa1e12f 100644 (file)
 
 /*  -------------------------------------------------------  INCLUDES  */
 
-#define NDEBUG
 #include "vfat.h"
 
+#define NDEBUG
+#include <debug.h>
+
 ULONG
-vfatDirEntryGetFirstCluster (PDEVICE_EXTENSION  pDeviceExt,
-                             PDIR_ENTRY  pFatDirEntry)
+vfatDirEntryGetFirstCluster(
+    PDEVICE_EXTENSION pDeviceExt,
+    PDIR_ENTRY pFatDirEntry)
 {
     ULONG cluster;
 
@@ -24,7 +27,7 @@ vfatDirEntryGetFirstCluster (PDEVICE_EXTENSION  pDeviceExt,
         cluster = pFatDirEntry->Fat.FirstCluster |
                  (pFatDirEntry->Fat.FirstClusterHigh << 16);
     }
-    else if (pDeviceExt->Flags & VCB_IS_FATX)
+    else if (vfatVolumeIsFatX(pDeviceExt))
     {
         cluster = pFatDirEntry->FatX.FirstCluster;
     }
@@ -36,14 +39,16 @@ vfatDirEntryGetFirstCluster (PDEVICE_EXTENSION  pDeviceExt,
     return  cluster;
 }
 
-static
 BOOLEAN
-FATIsDirectoryEmpty(PVFATFCB Fcb)
+FATIsDirectoryEmpty(
+    PDEVICE_EXTENSION DeviceExt,
+    PVFATFCB Fcb)
 {
     LARGE_INTEGER FileOffset;
     PVOID Context = NULL;
     PFAT_DIR_ENTRY FatDirEntry;
     ULONG Index, MaxIndex;
+    NTSTATUS Status;
 
     if (vfatFCBIsRoot(Fcb))
     {
@@ -57,6 +62,12 @@ FATIsDirectoryEmpty(PVFATFCB Fcb)
     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)
@@ -66,10 +77,15 @@ FATIsDirectoryEmpty(PVFATFCB Fcb)
                 CcUnpinData(Context);
             }
 
-            if (!CcMapData(Fcb->FileObject, &FileOffset, sizeof(FAT_DIR_ENTRY), TRUE, &Context, (PVOID*)&FatDirEntry))
+            _SEH2_TRY
+            {
+                CcMapData(Fcb->FileObject, &FileOffset, sizeof(FAT_DIR_ENTRY), MAP_WAIT, &Context, (PVOID*)&FatDirEntry);
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
             {
-                return TRUE;
+                _SEH2_YIELD(return TRUE);
             }
+            _SEH2_END;
 
             FatDirEntry += Index % FAT_ENTRIES_PER_PAGE;
             FileOffset.QuadPart += PAGE_SIZE;
@@ -99,18 +115,26 @@ FATIsDirectoryEmpty(PVFATFCB Fcb)
     return TRUE;
 }
 
-static
 BOOLEAN
-FATXIsDirectoryEmpty(PVFATFCB Fcb)
+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)
@@ -120,10 +144,15 @@ FATXIsDirectoryEmpty(PVFATFCB Fcb)
                 CcUnpinData(Context);
             }
 
-            if (!CcMapData(Fcb->FileObject, &FileOffset, sizeof(FATX_DIR_ENTRY), TRUE, &Context, (PVOID*)&FatXDirEntry))
+            _SEH2_TRY
             {
-                return TRUE;
+                CcMapData(Fcb->FileObject, &FileOffset, sizeof(FATX_DIR_ENTRY), MAP_WAIT, &Context, (PVOID*)&FatXDirEntry);
             }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                _SEH2_YIELD(return TRUE);
+            }
+            _SEH2_END;
 
             FatXDirEntry += Index % FATX_ENTRIES_PER_PAGE;
             FileOffset.QuadPart += PAGE_SIZE;
@@ -153,21 +182,13 @@ FATXIsDirectoryEmpty(PVFATFCB Fcb)
     return TRUE;
 }
 
-BOOLEAN
-VfatIsDirectoryEmpty(PVFATFCB Fcb)
-{
-    if (Fcb->Flags & FCB_IS_FATX_ENTRY)
-        return FATXIsDirectoryEmpty(Fcb);
-    else
-        return FATIsDirectoryEmpty(Fcb);
-}
-
 NTSTATUS
-FATGetNextDirEntry(PVOID *pContext,
-                   PVOID *pPage,
-                   IN PVFATFCB pDirFcb,
-                   PVFAT_DIRENTRY_CONTEXT DirContext,
-                   BOOLEAN First)
+FATGetNextDirEntry(
+    PVOID *pContext,
+    PVOID *pPage,
+    IN PVFATFCB pDirFcb,
+    PVFAT_DIRENTRY_CONTEXT DirContext,
+    BOOLEAN First)
 {
     ULONG dirMap;
     PWCHAR pName;
@@ -181,12 +202,20 @@ FATGetNextDirEntry(PVOID *pContext,
     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)
@@ -194,12 +223,22 @@ FATGetNextDirEntry(PVOID *pContext,
             CcUnpinData(*pContext);
         }
 
-        if (FileOffset.u.LowPart >= pDirFcb->RFCB.FileSize.u.LowPart ||
-            !CcMapData(pDirFcb->FileObject, &FileOffset, PAGE_SIZE, TRUE, pContext, pPage))
+        if (FileOffset.u.LowPart >= pDirFcb->RFCB.FileSize.u.LowPart)
         {
             *pContext = NULL;
             return STATUS_NO_MORE_ENTRIES;
         }
+
+        _SEH2_TRY
+        {
+            CcMapData(pDirFcb->FileObject, &FileOffset, PAGE_SIZE, MAP_WAIT, pContext, pPage);
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            *pContext = NULL;
+            _SEH2_YIELD(return STATUS_NO_MORE_ENTRIES);
+        }
+        _SEH2_END;
     }
 
     fatDirEntry = (PFAT_DIR_ENTRY)(*pPage) + DirContext->DirIndex % FAT_ENTRIES_PER_PAGE;
@@ -225,13 +264,23 @@ FATGetNextDirEntry(PVOID *pContext,
                 CcUnpinData(*pContext);
                 FileOffset.u.LowPart -= PAGE_SIZE;
 
-                if (FileOffset.u.LowPart >= pDirFcb->RFCB.FileSize.u.LowPart ||
-                    !CcMapData(pDirFcb->FileObject, &FileOffset, PAGE_SIZE, TRUE, pContext, pPage))
+                if (FileOffset.u.LowPart >= pDirFcb->RFCB.FileSize.u.LowPart)
                 {
                     *pContext = NULL;
                     return STATUS_NO_MORE_ENTRIES;
                 }
 
+                _SEH2_TRY
+                {
+                    CcMapData(pDirFcb->FileObject, &FileOffset, PAGE_SIZE, MAP_WAIT, pContext, pPage);
+                }
+                _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+                {
+                    *pContext = NULL;
+                    _SEH2_YIELD(return STATUS_NO_MORE_ENTRIES);
+                }
+                _SEH2_END;
+
                 fatDirEntry = (PFAT_DIR_ENTRY)(*pPage) + DirContext->DirIndex % FAT_ENTRIES_PER_PAGE;
                 longNameEntry = (slot*) fatDirEntry;
             }
@@ -252,13 +301,23 @@ FATGetNextDirEntry(PVOID *pContext,
                 CcUnpinData(*pContext);
                 FileOffset.u.LowPart += PAGE_SIZE;
 
-                if (FileOffset.u.LowPart >= pDirFcb->RFCB.FileSize.u.LowPart ||
-                   !CcMapData(pDirFcb->FileObject, &FileOffset, PAGE_SIZE, TRUE, pContext, pPage))
+                if (FileOffset.u.LowPart >= pDirFcb->RFCB.FileSize.u.LowPart)
                 {
                     *pContext = NULL;
                     return STATUS_NO_MORE_ENTRIES;
                 }
 
+                _SEH2_TRY
+                {
+                    CcMapData(pDirFcb->FileObject, &FileOffset, PAGE_SIZE, MAP_WAIT, pContext, pPage);
+                }
+                _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+                {
+                    *pContext = NULL;
+                    _SEH2_YIELD(return STATUS_NO_MORE_ENTRIES);
+                }
+                _SEH2_END;
+
                 fatDirEntry = (PFAT_DIR_ENTRY)*pPage;
                 longNameEntry = (slot*) *pPage;
             }
@@ -294,7 +353,7 @@ FATGetNextDirEntry(PVOID *pContext,
             {
                 if (dirMap == 0)
                 {
-                    DPRINT ("  long name entry found at %d\n", DirContext->DirIndex);
+                    DPRINT ("  long name entry found at %u\n", DirContext->DirIndex);
                     RtlZeroMemory(DirContext->LongNameU.Buffer, DirContext->LongNameU.MaximumLength);
                     CheckSum = longNameEntry->alias_checksum;
                     Valid = TRUE;
@@ -307,7 +366,7 @@ FATGetNextDirEntry(PVOID *pContext,
 
                 index = longNameEntry->id & 0x3f; // Note: it can be 0 for corrupted FS
                 
-                /* Make sure index is valid and we have enaugh space in buffer
+                /* Make sure index is valid and we have enough space in buffer
                   (we count one char for \0) */
                 if (index > 0 &&
                     index * 13 < DirContext->LongNameU.MaximumLength / sizeof(WCHAR))
@@ -372,13 +431,23 @@ FATGetNextDirEntry(PVOID *pContext,
             CcUnpinData(*pContext);
             FileOffset.u.LowPart += PAGE_SIZE;
 
-            if (FileOffset.u.LowPart >= pDirFcb->RFCB.FileSize.u.LowPart ||
-                !CcMapData(pDirFcb->FileObject, &FileOffset, PAGE_SIZE, TRUE, pContext, pPage))
+            if (FileOffset.u.LowPart >= pDirFcb->RFCB.FileSize.u.LowPart)
             {
                 *pContext = NULL;
                 return STATUS_NO_MORE_ENTRIES;
             }
 
+            _SEH2_TRY
+            {
+                CcMapData(pDirFcb->FileObject, &FileOffset, PAGE_SIZE, MAP_WAIT, pContext, pPage);
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                *pContext = NULL;
+                _SEH2_YIELD(return STATUS_NO_MORE_ENTRIES);
+            }
+            _SEH2_END;
+
             fatDirEntry = (PFAT_DIR_ENTRY)*pPage;
             longNameEntry = (slot*) *pPage;
         }
@@ -404,110 +473,140 @@ FATGetNextDirEntry(PVOID *pContext,
     return STATUS_SUCCESS;
 }
 
-NTSTATUS FATXGetNextDirEntry(PVOID * pContext,
-                             PVOID * pPage,
-                             IN PVFATFCB pDirFcb,
-                             PVFAT_DIRENTRY_CONTEXT DirContext,
-                             BOOLEAN First)
+NTSTATUS
+FATXGetNextDirEntry(
+    PVOID *pContext,
+    PVOID *pPage,
+    IN PVFATFCB pDirFcb,
+    PVFAT_DIRENTRY_CONTEXT DirContext,
+    BOOLEAN First)
 {
-   LARGE_INTEGER FileOffset;
-   PFATX_DIR_ENTRY fatxDirEntry;
-   OEM_STRING StringO;
-   ULONG DirIndex = DirContext->DirIndex;
-
-   FileOffset.u.HighPart = 0;
-
-   if (!vfatFCBIsRoot(pDirFcb))
-   {
-      /* need to add . and .. entries */
-      switch (DirContext->DirIndex)
-      {
-         case 0: /* entry . */
-         {
-            DirContext->ShortNameU.Buffer[0] = 0;
-            DirContext->ShortNameU.Length = 0;
-            wcscpy(DirContext->LongNameU.Buffer, L".");
-            DirContext->LongNameU.Length = sizeof(WCHAR);
-            RtlCopyMemory(&DirContext->DirEntry.FatX, &pDirFcb->entry.FatX, sizeof(FATX_DIR_ENTRY));
-            DirContext->DirEntry.FatX.Filename[0] = '.';
-            DirContext->DirEntry.FatX.FilenameLength = 1;
-            DirContext->StartIndex = 0;
-            return STATUS_SUCCESS;
-         }
-         case 1: /* entry .. */
-         {
-            DirContext->ShortNameU.Buffer[0] = 0;
-            DirContext->ShortNameU.Length = 0;
-            wcscpy(DirContext->LongNameU.Buffer, L"..");
-            DirContext->LongNameU.Length = 2 * sizeof(WCHAR);
-            RtlCopyMemory(&DirContext->DirEntry.FatX, &pDirFcb->entry.FatX, sizeof(FATX_DIR_ENTRY));
-            DirContext->DirEntry.FatX.Filename[0] = DirContext->DirEntry.FatX.Filename[1] = '.';
-            DirContext->DirEntry.FatX.FilenameLength = 2;
-            DirContext->StartIndex = 1;
-            return STATUS_SUCCESS;
-         }
-         default:
-            DirIndex -= 2;
-      }
-   }
-
-   if (*pContext == NULL || (DirIndex % FATX_ENTRIES_PER_PAGE) == 0)
-   {
-      if (*pContext != NULL)
-      {
-         CcUnpinData(*pContext);
-      }
-      FileOffset.u.LowPart = ROUND_DOWN(DirIndex * sizeof(FATX_DIR_ENTRY), PAGE_SIZE);
-      if (FileOffset.u.LowPart >= pDirFcb->RFCB.FileSize.u.LowPart ||
-          !CcMapData(pDirFcb->FileObject, &FileOffset, PAGE_SIZE, TRUE, pContext, pPage))
-      {
-         *pContext = NULL;
-         return STATUS_NO_MORE_ENTRIES;
-      }
-   }
-
-   fatxDirEntry = (PFATX_DIR_ENTRY)(*pPage) + DirIndex % FATX_ENTRIES_PER_PAGE;
-
-   DirContext->StartIndex = DirContext->DirIndex;
-
-   while (TRUE)
-   {
-      if (FATX_ENTRY_END(fatxDirEntry))
-      {
-          CcUnpinData(*pContext);
-          *pContext = NULL;
-          return STATUS_NO_MORE_ENTRIES;
-      }
-
-      if (!FATX_ENTRY_DELETED(fatxDirEntry))
-      {
-          RtlCopyMemory(&DirContext->DirEntry.FatX, fatxDirEntry, sizeof(FATX_DIR_ENTRY));
-          break;
-      }
-      DirContext->DirIndex++;
-      DirContext->StartIndex++;
-      DirIndex++;
-      if ((DirIndex % FATX_ENTRIES_PER_PAGE) == 0)
-      {
-         CcUnpinData(*pContext);
-         FileOffset.u.LowPart += PAGE_SIZE;
-         if (FileOffset.u.LowPart >= pDirFcb->RFCB.FileSize.u.LowPart ||
-             !CcMapData(pDirFcb->FileObject, &FileOffset, PAGE_SIZE, TRUE, pContext, pPage))
-         {
+    LARGE_INTEGER FileOffset;
+    PFATX_DIR_ENTRY fatxDirEntry;
+    OEM_STRING StringO;
+    ULONG DirIndex = DirContext->DirIndex;
+    NTSTATUS Status;
+
+    FileOffset.u.HighPart = 0;
+
+    UNREFERENCED_PARAMETER(First);
+
+    if (!vfatFCBIsRoot(pDirFcb))
+    {
+        /* need to add . and .. entries */
+        switch (DirContext->DirIndex)
+        {
+            case 0: /* entry . */
+                DirContext->ShortNameU.Buffer[0] = 0;
+                DirContext->ShortNameU.Length = 0;
+                wcscpy(DirContext->LongNameU.Buffer, L".");
+                DirContext->LongNameU.Length = sizeof(WCHAR);
+                RtlCopyMemory(&DirContext->DirEntry.FatX, &pDirFcb->entry.FatX, sizeof(FATX_DIR_ENTRY));
+                DirContext->DirEntry.FatX.Filename[0] = '.';
+                DirContext->DirEntry.FatX.FilenameLength = 1;
+                DirContext->StartIndex = 0;
+                return STATUS_SUCCESS;
+
+            case 1: /* entry .. */
+                DirContext->ShortNameU.Buffer[0] = 0;
+                DirContext->ShortNameU.Length = 0;
+                wcscpy(DirContext->LongNameU.Buffer, L"..");
+                DirContext->LongNameU.Length = 2 * sizeof(WCHAR);
+                RtlCopyMemory(&DirContext->DirEntry.FatX, &pDirFcb->entry.FatX, sizeof(FATX_DIR_ENTRY));
+                DirContext->DirEntry.FatX.Filename[0] = DirContext->DirEntry.FatX.Filename[1] = '.';
+                DirContext->DirEntry.FatX.FilenameLength = 2;
+                DirContext->StartIndex = 1;
+                return STATUS_SUCCESS;
+
+            default:
+                DirIndex -= 2;
+        }
+    }
+
+    Status = vfatFCBInitializeCacheFromVolume(DirContext->DeviceExt, pDirFcb);
+    if (!NT_SUCCESS(Status))
+    {
+        return Status;
+    }
+
+    if (*pContext == NULL || (DirIndex % FATX_ENTRIES_PER_PAGE) == 0)
+    {
+        if (*pContext != NULL)
+        {
+            CcUnpinData(*pContext);
+        }
+        FileOffset.u.LowPart = ROUND_DOWN(DirIndex * sizeof(FATX_DIR_ENTRY), PAGE_SIZE);
+        if (FileOffset.u.LowPart >= pDirFcb->RFCB.FileSize.u.LowPart)
+        {
+            *pContext = NULL;
+            return STATUS_NO_MORE_ENTRIES;
+        }
+
+        _SEH2_TRY
+        {
+            CcMapData(pDirFcb->FileObject, &FileOffset, PAGE_SIZE, MAP_WAIT, pContext, pPage);
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            *pContext = NULL;
+            _SEH2_YIELD(return STATUS_NO_MORE_ENTRIES);
+        }
+        _SEH2_END;
+    }
+
+    fatxDirEntry = (PFATX_DIR_ENTRY)(*pPage) + DirIndex % FATX_ENTRIES_PER_PAGE;
+
+    DirContext->StartIndex = DirContext->DirIndex;
+
+    while (TRUE)
+    {
+        if (FATX_ENTRY_END(fatxDirEntry))
+        {
+            CcUnpinData(*pContext);
             *pContext = NULL;
-           return STATUS_NO_MORE_ENTRIES;
-         }
-         fatxDirEntry = (PFATX_DIR_ENTRY)*pPage;
-      }
-      else
-      {
-         fatxDirEntry++;
-      }
-   }
-   DirContext->ShortNameU.Buffer[0] = 0;
-   DirContext->ShortNameU.Length = 0;
-   StringO.Buffer = (PCHAR)fatxDirEntry->Filename;
-   StringO.Length = StringO.MaximumLength = fatxDirEntry->FilenameLength;
-   RtlOemStringToUnicodeString(&DirContext->LongNameU, &StringO, FALSE);
-   return STATUS_SUCCESS;
+            return STATUS_NO_MORE_ENTRIES;
+        }
+
+        if (!FATX_ENTRY_DELETED(fatxDirEntry))
+        {
+            RtlCopyMemory(&DirContext->DirEntry.FatX, fatxDirEntry, sizeof(FATX_DIR_ENTRY));
+            break;
+        }
+        DirContext->DirIndex++;
+        DirContext->StartIndex++;
+        DirIndex++;
+        if ((DirIndex % FATX_ENTRIES_PER_PAGE) == 0)
+        {
+            CcUnpinData(*pContext);
+            FileOffset.u.LowPart += PAGE_SIZE;
+            if (FileOffset.u.LowPart >= pDirFcb->RFCB.FileSize.u.LowPart)
+            {
+                *pContext = NULL;
+                return STATUS_NO_MORE_ENTRIES;
+            }
+
+            _SEH2_TRY
+            {
+                CcMapData(pDirFcb->FileObject, &FileOffset, PAGE_SIZE, MAP_WAIT, pContext, pPage);
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                *pContext = NULL;
+                _SEH2_YIELD(return STATUS_NO_MORE_ENTRIES);
+            }
+            _SEH2_END;
+
+            fatxDirEntry = (PFATX_DIR_ENTRY)*pPage;
+        }
+        else
+        {
+            fatxDirEntry++;
+        }
+    }
+    DirContext->ShortNameU.Buffer[0] = 0;
+    DirContext->ShortNameU.Length = 0;
+    StringO.Buffer = (PCHAR)fatxDirEntry->Filename;
+    StringO.Length = StringO.MaximumLength = fatxDirEntry->FilenameLength;
+    RtlOemStringToUnicodeString(&DirContext->LongNameU, &StringO, FALSE);
+    return STATUS_SUCCESS;
 }