* Sync up to trunk head (r65298).
[reactos.git] / drivers / filesystems / fastfat / direntry.c
index 0601029..336f014 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;
 
@@ -38,7 +41,8 @@ vfatDirEntryGetFirstCluster (PDEVICE_EXTENSION  pDeviceExt,
 
 static
 BOOLEAN
-FATIsDirectoryEmpty(PVFATFCB Fcb)
+FATIsDirectoryEmpty(
+    PVFATFCB Fcb)
 {
     LARGE_INTEGER FileOffset;
     PVOID Context = NULL;
@@ -101,7 +105,8 @@ FATIsDirectoryEmpty(PVFATFCB Fcb)
 
 static
 BOOLEAN
-FATXIsDirectoryEmpty(PVFATFCB Fcb)
+FATXIsDirectoryEmpty(
+    PVFATFCB Fcb)
 {
     LARGE_INTEGER FileOffset;
     PVOID Context = NULL;
@@ -154,7 +159,8 @@ FATXIsDirectoryEmpty(PVFATFCB Fcb)
 }
 
 BOOLEAN
-VfatIsDirectoryEmpty(PVFATFCB Fcb)
+VfatIsDirectoryEmpty(
+    PVFATFCB Fcb)
 {
     if (Fcb->Flags & FCB_IS_FATX_ENTRY)
         return FATXIsDirectoryEmpty(Fcb);
@@ -163,11 +169,12 @@ VfatIsDirectoryEmpty(PVFATFCB 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,7 +188,8 @@ FATGetNextDirEntry(PVOID *pContext,
     BOOLEAN Valid = TRUE;
     BOOLEAN Back = FALSE;
 
-    DirContext->LongNameU.Buffer[0] = 0;
+    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);
@@ -293,7 +301,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;
@@ -304,13 +312,29 @@ FATGetNextDirEntry(PVOID *pContext,
                     6, longNameEntry->name5_10,
                     2, longNameEntry->name11_12);
 
-                index = (longNameEntry->id & 0x1f) - 1;
-                dirMap |= 1 << index;
-                pName = DirContext->LongNameU.Buffer + 13 * index;
-
-                RtlCopyMemory(pName, longNameEntry->name0_4, 5 * sizeof(WCHAR));
-                RtlCopyMemory(pName + 5, longNameEntry->name5_10, 6 * sizeof(WCHAR));
-                RtlCopyMemory(pName + 11, longNameEntry->name11_12, 2 * sizeof(WCHAR));
+                index = longNameEntry->id & 0x3f; // Note: it can be 0 for corrupted FS
+                
+                /* Make sure index is valid and we have enaugh space in buffer
+                  (we count one char for \0) */
+                if (index > 0 &&
+                    index * 13 < DirContext->LongNameU.MaximumLength / sizeof(WCHAR))
+                {
+                    index--; // make index 0 based
+                    dirMap |= 1 << index;
+
+                    pName = DirContext->LongNameU.Buffer + index * 13;
+                    RtlCopyMemory(pName, longNameEntry->name0_4, 5 * sizeof(WCHAR));
+                    RtlCopyMemory(pName + 5, longNameEntry->name5_10, 6 * sizeof(WCHAR));
+                    RtlCopyMemory(pName + 11, longNameEntry->name11_12, 2 * sizeof(WCHAR));
+
+                    if (longNameEntry->id & 0x40)
+                    {
+                        /* It's last LFN entry. Terminate filename with \0 */
+                        pName[13] = UNICODE_NULL;
+                    }
+                }
+                else
+                    DPRINT1("Long name entry has invalid index: %x!\n", longNameEntry->id);
 
                 DPRINT ("  longName: [%S]\n", DirContext->LongNameU.Buffer);
 
@@ -372,121 +396,127 @@ FATGetNextDirEntry(PVOID *pContext,
         }
     }
 
+    /* Make sure filename is NULL terminate and calculate length */
+    DirContext->LongNameU.Buffer[DirContext->LongNameU.MaximumLength / sizeof(WCHAR) - 1]
+        = UNICODE_NULL;
     DirContext->LongNameU.Length = wcslen(DirContext->LongNameU.Buffer) * sizeof(WCHAR);
+    
+    /* Init short name */
     vfat8Dot3ToString(&DirContext->DirEntry.Fat, &DirContext->ShortNameU);
 
+    /* If we found no LFN, use short name as long */
     if (DirContext->LongNameU.Length == 0)
-    {
         RtlCopyUnicodeString(&DirContext->LongNameU, &DirContext->ShortNameU);
-    }
 
     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;
-            DirContext->LongNameU.Buffer[0] = 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;
-            DirContext->LongNameU.Buffer[0] = DirContext->LongNameU.Buffer[1] = 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;
+
+    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;
+        }
+    }
+
+    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;
-         }
-         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 ||
+                !CcMapData(pDirFcb->FileObject, &FileOffset, PAGE_SIZE, TRUE, pContext, pPage))
+            {
+                *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;
 }