Fixed some problems if special parameters are delivered like SL_RESTART_SCAN, SL_INDE...
[reactos.git] / reactos / drivers / fs / vfat / dir.c
index b632435..8a87c39 100644 (file)
@@ -1,32 +1,29 @@
 /*
- * $Id: dir.c,v 1.22 2002/02/02 14:04:55 hbirr Exp $
+ * $Id$
  *
  * COPYRIGHT:        See COPYING in the top level directory
  * PROJECT:          ReactOS kernel
- * FILE:             services/fs/vfat/dir.c
+ * FILE:             drivers/fs/vfat/dir.c
  * PURPOSE:          VFAT Filesystem : directory control
  * UPDATE HISTORY:
      19-12-1998 : created
 
 */
 
-#include <ddk/ntddk.h>
-#include <wchar.h>
-
 #define NDEBUG
-#include <debug.h>
-
 #include "vfat.h"
 
 
 // function like DosDateTimeToFileTime
-BOOL FsdDosDateTimeToFileTime (WORD wDosDate, WORD wDosTime, TIME * FileTime)
+BOOLEAN
+FsdDosDateTimeToSystemTime (PDEVICE_EXTENSION DeviceExt, USHORT DosDate, USHORT DosTime, PLARGE_INTEGER SystemTime)
 {
-  PDOSTIME pdtime = (PDOSTIME) & wDosTime;
-  PDOSDATE pddate = (PDOSDATE) & wDosDate;
+  PDOSTIME pdtime = (PDOSTIME) &DosTime;
+  PDOSDATE pddate = (PDOSDATE) &DosDate;
   TIME_FIELDS TimeFields;
+  LARGE_INTEGER LocalTime;
 
-  if (FileTime == NULL)
+  if (SystemTime == NULL)
     return FALSE;
 
   TimeFields.Milliseconds = 0;
@@ -36,26 +33,28 @@ BOOL FsdDosDateTimeToFileTime (WORD wDosDate, WORD wDosTime, TIME * FileTime)
 
   TimeFields.Day = pddate->Day;
   TimeFields.Month = pddate->Month;
-  TimeFields.Year = 1980 + pddate->Year;
+  TimeFields.Year = (CSHORT)(DeviceExt->BaseDateYear + pddate->Year);
 
-  RtlTimeFieldsToTime (&TimeFields, (PLARGE_INTEGER) FileTime);
+  RtlTimeFieldsToTime (&TimeFields, &LocalTime);
+  ExLocalTimeToSystemTime(&LocalTime, SystemTime);
 
   return TRUE;
 }
 
-
 // function like FileTimeToDosDateTime
-BOOL
-FsdFileTimeToDosDateTime (TIME * FileTime, WORD * pwDosDate, WORD * pwDosTime)
+BOOLEAN
+FsdSystemTimeToDosDateTime (PDEVICE_EXTENSION DeviceExt, PLARGE_INTEGER SystemTime, USHORT *pDosDate, USHORT *pDosTime)
 {
-  PDOSTIME pdtime = (PDOSTIME) pwDosTime;
-  PDOSDATE pddate = (PDOSDATE) pwDosDate;
+  PDOSTIME pdtime = (PDOSTIME) pDosTime;
+  PDOSDATE pddate = (PDOSDATE) pDosDate;
   TIME_FIELDS TimeFields;
+  LARGE_INTEGER LocalTime;
 
-  if (FileTime == NULL)
+  if (SystemTime == NULL)
     return FALSE;
 
-  RtlTimeToTimeFields ((PLARGE_INTEGER) FileTime, &TimeFields);
+  ExSystemTimeToLocalTime (SystemTime, &LocalTime);
+  RtlTimeToTimeFields (&LocalTime, &TimeFields);
 
   if (pdtime)
     {
@@ -68,157 +67,228 @@ FsdFileTimeToDosDateTime (TIME * FileTime, WORD * pwDosDate, WORD * pwDosTime)
     {
       pddate->Day = TimeFields.Day;
       pddate->Month = TimeFields.Month;
-      pddate->Year = TimeFields.Year - 1980;
+      pddate->Year = (USHORT) (TimeFields.Year - DeviceExt->BaseDateYear);
     }
 
   return TRUE;
 }
 
-
-
-unsigned long
-vfat_wstrlen (PWSTR s)
-{
-  WCHAR c = ' ';
-  unsigned int len = 0;
-
-  while (c != 0)
-    {
-      c = *s;
-      s++;
-      len++;
-    };
-  s -= len;
-
-  return len - 1;
-}
-
-#define DWORD_ROUND_UP(x) ( (((ULONG)(x))%32) ? ((((ULONG)x)&(~0x1f))+0x20) : ((ULONG)x) )
+#define ULONG_ROUND_UP(x)   ROUND_UP((x), (sizeof(ULONG)))
 
 NTSTATUS
-VfatGetFileNameInformation (PVFATFCB pFcb,
-                          PFILE_NAMES_INFORMATION pInfo, ULONG BufferLength)
+VfatGetFileNameInformation (PVFAT_DIRENTRY_CONTEXT DirContext,
+                           PFILE_NAMES_INFORMATION pInfo, ULONG BufferLength)
 {
-  ULONG Length;
-  Length = vfat_wstrlen (pFcb->ObjectName) * sizeof(WCHAR);
-  if ((sizeof (FILE_DIRECTORY_INFORMATION) + Length) > BufferLength)
+  if ((sizeof (FILE_DIRECTORY_INFORMATION) + DirContext->LongNameU.Length) > BufferLength)
     return STATUS_BUFFER_OVERFLOW;
-  pInfo->FileNameLength = Length;
+  pInfo->FileNameLength = DirContext->LongNameU.Length;
   pInfo->NextEntryOffset =
-    DWORD_ROUND_UP (sizeof (FILE_DIRECTORY_INFORMATION) + Length);
-  memcpy (pInfo->FileName, pFcb->ObjectName, Length);
+    ULONG_ROUND_UP (sizeof (FILE_DIRECTORY_INFORMATION) + DirContext->LongNameU.Length);
+  RtlCopyMemory (pInfo->FileName, DirContext->LongNameU.Buffer, DirContext->LongNameU.Length);
   return STATUS_SUCCESS;
 }
 
 NTSTATUS
-VfatGetFileDirectoryInformation (PVFATFCB pFcb,
-                               PDEVICE_EXTENSION DeviceExt,
-                               PFILE_DIRECTORY_INFORMATION pInfo,
-                               ULONG BufferLength)
+VfatGetFileDirectoryInformation (PVFAT_DIRENTRY_CONTEXT DirContext,
+                                PDEVICE_EXTENSION DeviceExt,
+                                PFILE_DIRECTORY_INFORMATION pInfo,
+                                ULONG BufferLength)
 {
-  unsigned long long AllocSize;
-  ULONG Length;
-  Length = vfat_wstrlen (pFcb->ObjectName) * sizeof(WCHAR);
-  if ((sizeof (FILE_DIRECTORY_INFORMATION) + Length) > BufferLength)
+  if ((sizeof (FILE_DIRECTORY_INFORMATION) + DirContext->LongNameU.Length) > BufferLength)
     return STATUS_BUFFER_OVERFLOW;
-  pInfo->FileNameLength = Length;
+  pInfo->FileNameLength = DirContext->LongNameU.Length;
   pInfo->NextEntryOffset =
-    DWORD_ROUND_UP (sizeof (FILE_DIRECTORY_INFORMATION) + Length);
-  memcpy (pInfo->FileName, pFcb->ObjectName, Length);
+    ULONG_ROUND_UP (sizeof (FILE_DIRECTORY_INFORMATION) + DirContext->LongNameU.Length);
+  RtlCopyMemory (pInfo->FileName, DirContext->LongNameU.Buffer, DirContext->LongNameU.Length);
 //      pInfo->FileIndex=;
-  FsdDosDateTimeToFileTime (pFcb->entry.CreationDate,
-                           pFcb->entry.CreationTime, &pInfo->CreationTime);
-  FsdDosDateTimeToFileTime (pFcb->entry.AccessDate, 0,
-                           &pInfo->LastAccessTime);
-  FsdDosDateTimeToFileTime (pFcb->entry.UpdateDate, pFcb->entry.UpdateTime,
-                           &pInfo->LastWriteTime);
-  FsdDosDateTimeToFileTime (pFcb->entry.UpdateDate, pFcb->entry.UpdateTime,
-                           &pInfo->ChangeTime);
-  pInfo->EndOfFile = RtlConvertUlongToLargeInteger (pFcb->entry.FileSize);
-  /* Make allocsize a rounded up multiple of BytesPerCluster */
-  AllocSize = ((pFcb->entry.FileSize + DeviceExt->BytesPerCluster - 1) /
-              DeviceExt->BytesPerCluster) * DeviceExt->BytesPerCluster;
-  pInfo->AllocationSize.QuadPart = AllocSize;
-  pInfo->FileAttributes = pFcb->entry.Attrib;
+  if (DeviceExt->Flags & VCB_IS_FATX)
+  {
+    FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.FatX.CreationDate,
+                             DirContext->DirEntry.FatX.CreationTime,
+                             &pInfo->CreationTime);
+    FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.FatX.AccessDate,
+               DirContext->DirEntry.FatX.AccessTime,
+                             &pInfo->LastAccessTime);
+    FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.FatX.UpdateDate,
+                             DirContext->DirEntry.FatX.UpdateTime,
+                             &pInfo->LastWriteTime);
+    pInfo->ChangeTime = pInfo->LastWriteTime;
+    if (DirContext->DirEntry.FatX.Attrib & FILE_ATTRIBUTE_DIRECTORY)
+      {
+        pInfo->EndOfFile.QuadPart = 0LL;
+        pInfo->AllocationSize.QuadPart = 0LL;
+      }
+    else
+      {
+        pInfo->EndOfFile.u.HighPart = 0;
+        pInfo->EndOfFile.u.LowPart = DirContext->DirEntry.FatX.FileSize;
+        /* Make allocsize a rounded up multiple of BytesPerCluster */
+        pInfo->AllocationSize.u.HighPart = 0;
+        pInfo->AllocationSize.u.LowPart = ROUND_UP(DirContext->DirEntry.FatX.FileSize, DeviceExt->FatInfo.BytesPerCluster);
+      }
+    pInfo->FileAttributes = DirContext->DirEntry.FatX.Attrib & 0x3f;
+  }
+  else
+  {
+    FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.Fat.CreationDate,
+                             DirContext->DirEntry.Fat.CreationTime,
+                             &pInfo->CreationTime);
+    FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.Fat.AccessDate, 0,
+                             &pInfo->LastAccessTime);
+    FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.Fat.UpdateDate,
+                             DirContext->DirEntry.Fat.UpdateTime,
+                             &pInfo->LastWriteTime);
+    pInfo->ChangeTime = pInfo->LastWriteTime;
+    if (DirContext->DirEntry.Fat.Attrib & FILE_ATTRIBUTE_DIRECTORY)
+      {
+        pInfo->EndOfFile.QuadPart = 0LL;
+        pInfo->AllocationSize.QuadPart = 0LL;
+      }
+    else
+      {
+        pInfo->EndOfFile.u.HighPart = 0;
+        pInfo->EndOfFile.u.LowPart = DirContext->DirEntry.Fat.FileSize;
+        /* Make allocsize a rounded up multiple of BytesPerCluster */
+        pInfo->AllocationSize.u.HighPart = 0;
+        pInfo->AllocationSize.u.LowPart = ROUND_UP(DirContext->DirEntry.Fat.FileSize, DeviceExt->FatInfo.BytesPerCluster);
+      }
+    pInfo->FileAttributes = DirContext->DirEntry.Fat.Attrib & 0x3f;
+  }
 
   return STATUS_SUCCESS;
 }
 
 NTSTATUS
-VfatGetFileFullDirectoryInformation (PVFATFCB pFcb,
-                                   PDEVICE_EXTENSION DeviceExt,
-                                   PFILE_FULL_DIRECTORY_INFORMATION pInfo,
-                                   ULONG BufferLength)
+VfatGetFileFullDirectoryInformation (PVFAT_DIRENTRY_CONTEXT DirContext,
+                                    PDEVICE_EXTENSION DeviceExt,
+                                    PFILE_FULL_DIR_INFORMATION pInfo,
+                                    ULONG BufferLength)
 {
-  unsigned long long AllocSize;
-  ULONG Length;
-  Length = vfat_wstrlen (pFcb->ObjectName) * sizeof(WCHAR);
-  if ((sizeof (FILE_FULL_DIRECTORY_INFORMATION) + Length) > BufferLength)
+  if ((sizeof (FILE_FULL_DIR_INFORMATION) + DirContext->LongNameU.Length) > BufferLength)
     return STATUS_BUFFER_OVERFLOW;
-  pInfo->FileNameLength = Length;
+  pInfo->FileNameLength = DirContext->LongNameU.Length;
   pInfo->NextEntryOffset =
-    DWORD_ROUND_UP (sizeof (FILE_FULL_DIRECTORY_INFORMATION) + Length);
-  memcpy (pInfo->FileName, pFcb->ObjectName, Length);
+    ULONG_ROUND_UP (sizeof (FILE_FULL_DIR_INFORMATION) + DirContext->LongNameU.Length);
+  RtlCopyMemory (pInfo->FileName, DirContext->LongNameU.Buffer, DirContext->LongNameU.Length);
 //      pInfo->FileIndex=;
-  FsdDosDateTimeToFileTime (pFcb->entry.CreationDate,
-                           pFcb->entry.CreationTime, &pInfo->CreationTime);
-  FsdDosDateTimeToFileTime (pFcb->entry.AccessDate, 0,
-                           &pInfo->LastAccessTime);
-  FsdDosDateTimeToFileTime (pFcb->entry.UpdateDate, pFcb->entry.UpdateTime,
-                           &pInfo->LastWriteTime);
-  FsdDosDateTimeToFileTime (pFcb->entry.UpdateDate, pFcb->entry.UpdateTime,
-                           &pInfo->ChangeTime);
-  pInfo->EndOfFile = RtlConvertUlongToLargeInteger (pFcb->entry.FileSize);
-  /* Make allocsize a rounded up multiple of BytesPerCluster */
-  AllocSize = ((pFcb->entry.FileSize + DeviceExt->BytesPerCluster - 1) /
-              DeviceExt->BytesPerCluster) * DeviceExt->BytesPerCluster;
-  pInfo->AllocationSize.QuadPart = AllocSize;
-  pInfo->FileAttributes = pFcb->entry.Attrib;
+  if (DeviceExt->Flags & VCB_IS_FATX)
+  {
+    FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.FatX.CreationDate,
+                             DirContext->DirEntry.FatX.CreationTime,
+                             &pInfo->CreationTime);
+    FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.FatX.AccessDate,
+                              DirContext->DirEntry.FatX.AccessTime,
+                              &pInfo->LastAccessTime);
+    FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.FatX.UpdateDate,
+                              DirContext->DirEntry.FatX.UpdateTime,
+                              &pInfo->LastWriteTime);
+    pInfo->ChangeTime = pInfo->LastWriteTime;
+    pInfo->EndOfFile.u.HighPart = 0;
+    pInfo->EndOfFile.u.LowPart = DirContext->DirEntry.FatX.FileSize;
+    /* Make allocsize a rounded up multiple of BytesPerCluster */
+    pInfo->AllocationSize.u.HighPart = 0;
+    pInfo->AllocationSize.u.LowPart = ROUND_UP(DirContext->DirEntry.FatX.FileSize, DeviceExt->FatInfo.BytesPerCluster);
+    pInfo->FileAttributes = DirContext->DirEntry.FatX.Attrib & 0x3f;
+  }
+  else
+  {
+    FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.Fat.CreationDate,
+                             DirContext->DirEntry.Fat.CreationTime,
+                             &pInfo->CreationTime);
+    FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.Fat.AccessDate,
+                              0, &pInfo->LastAccessTime);
+    FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.Fat.UpdateDate,
+                              DirContext->DirEntry.Fat.UpdateTime,
+                              &pInfo->LastWriteTime);
+    pInfo->ChangeTime = pInfo->LastWriteTime;
+    pInfo->EndOfFile.u.HighPart = 0;
+    pInfo->EndOfFile.u.LowPart = DirContext->DirEntry.Fat.FileSize;
+    /* Make allocsize a rounded up multiple of BytesPerCluster */
+    pInfo->AllocationSize.u.HighPart = 0;
+    pInfo->AllocationSize.u.LowPart = ROUND_UP(DirContext->DirEntry.Fat.FileSize, DeviceExt->FatInfo.BytesPerCluster);
+    pInfo->FileAttributes = DirContext->DirEntry.Fat.Attrib & 0x3f;
+  }
 //      pInfo->EaSize=;
   return STATUS_SUCCESS;
 }
 
 NTSTATUS
-VfatGetFileBothInformation (PVFATFCB pFcb,
-                          PDEVICE_EXTENSION DeviceExt,
-                          PFILE_BOTH_DIRECTORY_INFORMATION pInfo,
-                          ULONG BufferLength)
+VfatGetFileBothInformation (PVFAT_DIRENTRY_CONTEXT DirContext,
+                           PDEVICE_EXTENSION DeviceExt,
+                           PFILE_BOTH_DIR_INFORMATION pInfo,
+                           ULONG BufferLength)
 {
-  short i;
-  unsigned long long AllocSize;
-  ULONG Length;
-  Length = vfat_wstrlen (pFcb->ObjectName) * sizeof(WCHAR);
-  if ((sizeof (FILE_BOTH_DIRECTORY_INFORMATION) + Length) > BufferLength)
+  if ((sizeof (FILE_BOTH_DIR_INFORMATION) + DirContext->LongNameU.Length) > BufferLength)
     return STATUS_BUFFER_OVERFLOW;
-  pInfo->FileNameLength = Length;
-  pInfo->NextEntryOffset =
-    DWORD_ROUND_UP (sizeof (FILE_BOTH_DIRECTORY_INFORMATION) + Length);
-  memcpy (pInfo->FileName, pFcb->ObjectName, Length);
-//      pInfo->FileIndex=;
-  FsdDosDateTimeToFileTime (pFcb->entry.CreationDate,
-                           pFcb->entry.CreationTime, &pInfo->CreationTime);
-  FsdDosDateTimeToFileTime (pFcb->entry.AccessDate, 0,
-                           &pInfo->LastAccessTime);
-  FsdDosDateTimeToFileTime (pFcb->entry.UpdateDate, pFcb->entry.UpdateTime,
-                           &pInfo->LastWriteTime);
-  FsdDosDateTimeToFileTime (pFcb->entry.UpdateDate, pFcb->entry.UpdateTime,
-                           &pInfo->ChangeTime);
-  pInfo->EndOfFile = RtlConvertUlongToLargeInteger (pFcb->entry.FileSize);
-  /* Make allocsize a rounded up multiple of BytesPerCluster */
-  AllocSize = ((pFcb->entry.FileSize + DeviceExt->BytesPerCluster - 1) /
-              DeviceExt->BytesPerCluster) * DeviceExt->BytesPerCluster;
-  pInfo->AllocationSize.QuadPart = AllocSize;
-  pInfo->FileAttributes = pFcb->entry.Attrib;
-//      pInfo->EaSize=;
-  for (i = 0; i < 8 && (pFcb->entry.Filename[i] != ' '); i++)
-    pInfo->ShortName[i] = pFcb->entry.Filename[i];
-  pInfo->ShortNameLength = i;
-  pInfo->ShortName[i] = '.';
-  for (i = 0; i < 3 && (pFcb->entry.Ext[i] != ' '); i++)
-    pInfo->ShortName[i + 1 + pInfo->ShortNameLength] = pFcb->entry.Ext[i];
-  if (i)
-    pInfo->ShortNameLength += (i + 1);
-  pInfo->ShortNameLength *= sizeof(WCHAR);
+
+  if (DeviceExt->Flags & VCB_IS_FATX)
+  {
+    pInfo->FileNameLength = DirContext->LongNameU.Length;
+    RtlCopyMemory(pInfo->FileName, DirContext->LongNameU.Buffer, DirContext->LongNameU.Length);
+    pInfo->NextEntryOffset =
+      ULONG_ROUND_UP (sizeof (FILE_BOTH_DIR_INFORMATION) + DirContext->LongNameU.Length);
+    pInfo->ShortName[0] = 0;
+    pInfo->ShortNameLength = 0;
+    //      pInfo->FileIndex=;
+    FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.FatX.CreationDate,
+                              DirContext->DirEntry.FatX.CreationTime,
+                              &pInfo->CreationTime);
+    FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.FatX.AccessDate,
+                              DirContext->DirEntry.FatX.AccessTime,
+                              &pInfo->LastAccessTime);
+    FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.FatX.UpdateDate,
+                              DirContext->DirEntry.FatX.UpdateTime,
+                              &pInfo->LastWriteTime);
+    pInfo->ChangeTime = pInfo->LastWriteTime;
+    if (DirContext->DirEntry.FatX.Attrib & FILE_ATTRIBUTE_DIRECTORY)
+      {
+        pInfo->EndOfFile.QuadPart = 0LL;
+        pInfo->AllocationSize.QuadPart = 0LL;
+      }
+    else
+      {
+        pInfo->EndOfFile.u.HighPart = 0;
+        pInfo->EndOfFile.u.LowPart = DirContext->DirEntry.FatX.FileSize;
+        /* Make allocsize a rounded up multiple of BytesPerCluster */
+        pInfo->AllocationSize.u.HighPart = 0;
+        pInfo->AllocationSize.u.LowPart = ROUND_UP(DirContext->DirEntry.FatX.FileSize, DeviceExt->FatInfo.BytesPerCluster);
+      }
+    pInfo->FileAttributes = DirContext->DirEntry.FatX.Attrib & 0x3f;
+  }
+  else
+  {
+    pInfo->FileNameLength = DirContext->LongNameU.Length;
+    pInfo->NextEntryOffset =
+      ULONG_ROUND_UP (sizeof (FILE_BOTH_DIR_INFORMATION) + DirContext->LongNameU.Length);
+    RtlCopyMemory(pInfo->ShortName, DirContext->ShortNameU.Buffer, DirContext->ShortNameU.Length);
+    pInfo->ShortNameLength = (CCHAR)DirContext->ShortNameU.Length;
+    RtlCopyMemory (pInfo->FileName, DirContext->LongNameU.Buffer, DirContext->LongNameU.Length);
+  //      pInfo->FileIndex=;
+    FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.Fat.CreationDate,
+                              DirContext->DirEntry.Fat.CreationTime,
+                              &pInfo->CreationTime);
+    FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.Fat.AccessDate, 0,
+                              &pInfo->LastAccessTime);
+    FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.Fat.UpdateDate,
+                              DirContext->DirEntry.Fat.UpdateTime,
+                              &pInfo->LastWriteTime);
+    pInfo->ChangeTime = pInfo->LastWriteTime;
+    if (DirContext->DirEntry.Fat.Attrib & FILE_ATTRIBUTE_DIRECTORY)
+      {
+        pInfo->EndOfFile.QuadPart = 0LL;
+        pInfo->AllocationSize.QuadPart = 0LL;
+      }
+    else
+      {
+        pInfo->EndOfFile.u.HighPart = 0;
+        pInfo->EndOfFile.u.LowPart = DirContext->DirEntry.Fat.FileSize;
+        /* Make allocsize a rounded up multiple of BytesPerCluster */
+        pInfo->AllocationSize.u.HighPart = 0;
+        pInfo->AllocationSize.u.LowPart = ROUND_UP(DirContext->DirEntry.Fat.FileSize, DeviceExt->FatInfo.BytesPerCluster);
+      }
+    pInfo->FileAttributes = DirContext->DirEntry.Fat.Attrib & 0x3f;
+  }
+  pInfo->EaSize=0;
   return STATUS_SUCCESS;
 }
 
@@ -228,128 +298,178 @@ NTSTATUS DoQuery (PVFAT_IRP_CONTEXT IrpContext)
   long BufferLength = 0;
   PUNICODE_STRING pSearchPattern = NULL;
   FILE_INFORMATION_CLASS FileInformationClass;
-  unsigned long FileIndex = 0;
   unsigned char *Buffer = NULL;
   PFILE_NAMES_INFORMATION Buffer0 = NULL;
   PVFATFCB pFcb;
-  VFATFCB tmpFcb;
   PVFATCCB pCcb;
-  WCHAR pCharPattern[MAX_PATH];
-  unsigned long OldEntry, OldSector;
+  BOOLEAN FirstQuery = FALSE;
+  BOOLEAN FirstCall = TRUE;
+  VFAT_DIRENTRY_CONTEXT DirContext;
+  WCHAR LongNameBuffer[LONGNAME_MAX_LENGTH + 1];
+  WCHAR ShortNameBuffer[13];
+
+  PIO_STACK_LOCATION Stack = IrpContext->Stack;
 
   pCcb = (PVFATCCB) IrpContext->FileObject->FsContext2;
-  pFcb = pCcb->pFcb;
+  pFcb = (PVFATFCB) IrpContext->FileObject->FsContext;
 
-  if (!ExAcquireResourceSharedLite(&pFcb->MainResource, IrpContext->Flags & IRPCONTEXT_CANWAIT))
-  {
-     return STATUS_PENDING;
-  }
+  // determine Buffer for result :
+  BufferLength = Stack->Parameters.QueryDirectory.Length;
+#if 0
+  /* Do not probe the user buffer until SEH is available */
+  if (IrpContext->Irp->RequestorMode != KernelMode &&
+      IrpContext->Irp->MdlAddress == NULL &&
+      IrpContext->Irp->UserBuffer != NULL)
+    {
+      ProbeForWrite(IrpContext->Irp->UserBuffer, BufferLength, 1);
+    }
+#endif
+  Buffer = VfatGetUserBuffer(IrpContext->Irp);
 
-  // Obtain the callers parameters
-  BufferLength = IrpContext->Stack->Parameters.QueryDirectory.Length;
-  pSearchPattern = IrpContext->Stack->Parameters.QueryDirectory.FileName;
+  if (!ExAcquireResourceSharedLite(&pFcb->MainResource,
+                                   (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT)))
+    {
+      RC = VfatLockUserBuffer(IrpContext->Irp, BufferLength, IoWriteAccess);
+      if (NT_SUCCESS(RC))
+        {
+          RC = STATUS_PENDING;
+        }
+      return RC;
+    }
+
+  /* Obtain the callers parameters */
+#ifdef _MSC_VER
+  /* HACKHACK: Bug in the MS ntifs.h header:
+   * FileName is really a PUNICODE_STRING, not a PSTRING */
+  pSearchPattern = (PUNICODE_STRING)Stack->Parameters.QueryDirectory.FileName;
+#else
+  pSearchPattern = Stack->Parameters.QueryDirectory.FileName;
+#endif
   FileInformationClass =
-    IrpContext->Stack->Parameters.QueryDirectory.FileInformationClass;
-  FileIndex = IrpContext->Stack->Parameters.QueryDirectory.FileIndex;
-  if (IrpContext->Stack->Flags & SL_RESTART_SCAN)
-    {                          //FIXME : what is really use of RestartScan ?
-      pCcb->StartEntry = pCcb->StartSector = 0;
+    Stack->Parameters.QueryDirectory.FileInformationClass;
+  if (pSearchPattern)
+    {
+      if (!pCcb->SearchPattern.Buffer)
+        {
+          FirstQuery = TRUE;
+          pCcb->SearchPattern.MaximumLength = pSearchPattern->Length + sizeof(WCHAR);
+          pCcb->SearchPattern.Buffer = ExAllocatePool(NonPagedPool, pCcb->SearchPattern.MaximumLength);
+          if (!pCcb->SearchPattern.Buffer)
+            {
+              ExReleaseResourceLite(&pFcb->MainResource);
+              return STATUS_INSUFFICIENT_RESOURCES;
+            }
+          RtlCopyUnicodeString(&pCcb->SearchPattern, pSearchPattern);
+          pCcb->SearchPattern.Buffer[pCcb->SearchPattern.Length / sizeof(WCHAR)] = 0;
+       }
     }
-  // determine Buffer for result :
-  if (IrpContext->Irp->MdlAddress)
-    Buffer = MmGetSystemAddressForMdl (IrpContext->Irp->MdlAddress);
-  else
-    Buffer = IrpContext->Irp->UserBuffer;
-  DPRINT ("Buffer=%x tofind=%S\n", Buffer, pSearchPattern->Buffer);
-  if (pSearchPattern == NULL)
+  else if (!pCcb->SearchPattern.Buffer)
     {
-      pCharPattern[0] = L'*';
-      pCharPattern[1] = 0;
+      FirstQuery = TRUE;
+      pCcb->SearchPattern.MaximumLength = 2 * sizeof(WCHAR);
+      pCcb->SearchPattern.Buffer = ExAllocatePool(NonPagedPool, 2 * sizeof(WCHAR));
+      if (!pCcb->SearchPattern.Buffer)
+        {
+          ExReleaseResourceLite(&pFcb->MainResource);
+          return STATUS_INSUFFICIENT_RESOURCES;
+        }
+      pCcb->SearchPattern.Buffer[0] = L'*';
+      pCcb->SearchPattern.Buffer[1] = 0;
+      pCcb->SearchPattern.Length = sizeof(WCHAR);
+    }
+
+  if (IrpContext->Stack->Flags & SL_INDEX_SPECIFIED)
+    {
+      DirContext.DirIndex = pCcb->Entry = Stack->Parameters.QueryDirectory.FileIndex;
+    }
+  else if (FirstQuery || (IrpContext->Stack->Flags & SL_RESTART_SCAN))
+    {
+      DirContext.DirIndex = pCcb->Entry = 0;
     }
   else
     {
-      memcpy (pCharPattern, pSearchPattern->Buffer, pSearchPattern->Length);
-      pCharPattern[pSearchPattern->Length / sizeof(WCHAR)] = 0;
+      DirContext.DirIndex = pCcb->Entry;
     }
-  tmpFcb.ObjectName = tmpFcb.PathName;
+
+  DPRINT ("Buffer=%x tofind=%wZ\n", Buffer, &pCcb->SearchPattern);
+
+  DirContext.LongNameU.Buffer = LongNameBuffer;
+  DirContext.LongNameU.MaximumLength = sizeof(LongNameBuffer);
+  DirContext.ShortNameU.Buffer = ShortNameBuffer;
+  DirContext.ShortNameU.MaximumLength = sizeof(ShortNameBuffer);
+
   while (RC == STATUS_SUCCESS && BufferLength > 0)
     {
-      OldSector = pCcb->StartSector;
-      OldEntry = pCcb->StartEntry;
-      if (OldSector)
-       pCcb->StartEntry++;
-      RC =
-       FindFile (IrpContext->DeviceExt, &tmpFcb, pFcb, pCharPattern, &pCcb->StartEntry, NULL);
-    pCcb->StartSector = 1;
-      DPRINT ("Found %S,RC=%x, sector %x entry %x\n", tmpFcb.ObjectName, RC,
-             pCcb->StartSector, pCcb->StartEntry);
+      RC = FindFile (IrpContext->DeviceExt, pFcb,
+                     &pCcb->SearchPattern, &DirContext, FirstCall);
+      pCcb->Entry = DirContext.DirIndex;
+      DPRINT ("Found %wZ, RC=%x, entry %x\n", &DirContext.LongNameU, RC, pCcb->Entry);
+      FirstCall = FALSE;
       if (NT_SUCCESS (RC))
-       {
-         switch (FileInformationClass)
-           {
-           case FileNameInformation:
-             RC =
-               VfatGetFileNameInformation (&tmpFcb,
-                                          (PFILE_NAMES_INFORMATION) Buffer,
-                                          BufferLength);
-             break;
-           case FileDirectoryInformation:
-             RC =
-               VfatGetFileDirectoryInformation (&tmpFcb, IrpContext->DeviceExt,
-                                               (PFILE_DIRECTORY_INFORMATION)
-                                               Buffer, BufferLength);
-             break;
-           case FileFullDirectoryInformation:
-             RC =
-               VfatGetFileFullDirectoryInformation (&tmpFcb, IrpContext->DeviceExt,
-                                                   (PFILE_FULL_DIRECTORY_INFORMATION)
-                                                   Buffer, BufferLength);
-             break;
-           case FileBothDirectoryInformation:
-             RC =
-               VfatGetFileBothInformation (&tmpFcb, IrpContext->DeviceExt,
-                                          (PFILE_BOTH_DIRECTORY_INFORMATION)
-                                          Buffer, BufferLength);
-             break;
-           default:
-             RC = STATUS_INVALID_INFO_CLASS;
+        {
+          switch (FileInformationClass)
+            {
+              case FileNameInformation:
+                RC = VfatGetFileNameInformation (&DirContext,
+                                                 (PFILE_NAMES_INFORMATION) Buffer,
+                                                BufferLength);
+                break;
+              case FileDirectoryInformation:
+                RC = VfatGetFileDirectoryInformation (&DirContext,
+                                                     IrpContext->DeviceExt,
+                                                     (PFILE_DIRECTORY_INFORMATION) Buffer,
+                                                     BufferLength);
+                break;
+             case FileFullDirectoryInformation:
+               RC = VfatGetFileFullDirectoryInformation (&DirContext,
+                                                        IrpContext->DeviceExt,
+                                                        (PFILE_FULL_DIR_INFORMATION) Buffer,
+                                                        BufferLength);
+               break;
+             case FileBothDirectoryInformation:
+               RC = VfatGetFileBothInformation (&DirContext,
+                                               IrpContext->DeviceExt,
+                                               (PFILE_BOTH_DIR_INFORMATION) Buffer,
+                                               BufferLength);
+               break;
+             default:
+               RC = STATUS_INVALID_INFO_CLASS;
            }
+          if (RC == STATUS_BUFFER_OVERFLOW)
+            {
+              break;
+            }
        }
       else
-       {
-         if (Buffer0)
-           Buffer0->NextEntryOffset = 0;
-          if (OldSector)
-            RC = STATUS_NO_MORE_FILES;
+        {
+          if (FirstQuery)
+            {
+              RC = STATUS_NO_SUCH_FILE;
+            }
           else
-            RC = STATUS_NO_SUCH_FILE;
-         break;
-       }
-      if (RC == STATUS_BUFFER_OVERFLOW)
-       {
-         if (Buffer0)
-           Buffer0->NextEntryOffset = 0;
-         pCcb->StartSector = OldSector;
-         pCcb->StartEntry = OldEntry;
-         break;
+            {
+              RC = STATUS_NO_MORE_FILES;
+            }
+          break;
        }
       Buffer0 = (PFILE_NAMES_INFORMATION) Buffer;
-      Buffer0->FileIndex = FileIndex++;
-      if (IrpContext->Stack->Flags & SL_RETURN_SINGLE_ENTRY)
-       break;
+      Buffer0->FileIndex = DirContext.DirIndex;
+      pCcb->Entry = ++DirContext.DirIndex;
       BufferLength -= Buffer0->NextEntryOffset;
+      if (IrpContext->Stack->Flags & SL_RETURN_SINGLE_ENTRY)
+        {
+          break;
+        }
       Buffer += Buffer0->NextEntryOffset;
     }
   if (Buffer0)
-    Buffer0->NextEntryOffset = 0;
-  if (FileIndex > 0)
-    RC = STATUS_SUCCESS;
-
-  if (IrpContext->Flags & IRPCONTEXT_CANWAIT)
-  {
-     ExReleaseResourceLite(&pFcb->MainResource);
-  }
+    {
+      Buffer0->NextEntryOffset = 0;
+      RC = STATUS_SUCCESS;
+      IrpContext->Irp->IoStatus.Information = Stack->Parameters.QueryDirectory.Length - BufferLength;
 
+    }
+  ExReleaseResourceLite(&pFcb->MainResource);
   return RC;
 }
 
@@ -361,6 +481,7 @@ NTSTATUS VfatDirectoryControl (PVFAT_IRP_CONTEXT IrpContext)
 {
   NTSTATUS RC = STATUS_SUCCESS;
   CHECKPOINT;
+  IrpContext->Irp->IoStatus.Information = 0;
   switch (IrpContext->MinorFunction)
     {
     case IRP_MN_QUERY_DIRECTORY:
@@ -384,7 +505,6 @@ NTSTATUS VfatDirectoryControl (PVFAT_IRP_CONTEXT IrpContext)
   else
   {
     IrpContext->Irp->IoStatus.Status = RC;
-    IrpContext->Irp->IoStatus.Information = 0;
     IoCompleteRequest (IrpContext->Irp, IO_NO_INCREMENT);
     VfatFreeIrpContext(IrpContext);
   }