Fixed some problems if special parameters are delivered like SL_RESTART_SCAN, SL_INDE...
[reactos.git] / reactos / drivers / fs / vfat / dir.c
index b471484..8a87c39 100644 (file)
-       
 /*
+ * $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 <internal/string.h>
-#include <wstring.h>
-#include <ddk/cctypes.h>
-#include <ddk/zwtypes.h>
 
 #define NDEBUG
-#include <internal/debug.h>
-
 #include "vfat.h"
 
-// buggy function, waiting the real function
-BOOL fsdDosDateTimeToFileTime(WORD wDosDate,WORD wDosTime, TIME *FileTime)
+
+// function like DosDateTimeToFileTime
+BOOLEAN
+FsdDosDateTimeToSystemTime (PDEVICE_EXTENSION DeviceExt, USHORT DosDate, USHORT DosTime, PLARGE_INTEGER SystemTime)
 {
- WORD Day,Month,Year,Second,Minute,Hour;
- long long int *pTime=(long long int *)FileTime;
- long long int mult;
-  Day=wDosDate&0x001f;
-  Month= (wDosDate&0x00e0)>>5;//1=January
-  Year= ((wDosDate&0xff00)>>8)+1980;
-  Second=(wDosTime&0x001f)<<1;
-  Minute=(wDosTime&0x07e0)>>5;
-  Hour=  (wDosTime&0xf100)>>11;
-  mult=10000000;
-  *pTime=Second*mult;
-  mult *=60;
-  *pTime +=Minute*mult;
-  mult *=60;
-  *pTime +=Hour*mult;
-  mult *=24;
-  *pTime +=(Day-1)*mult;
-  *pTime +=(Month-1)*mult*30;//FIXME : not always 30 days in a month
-  *pTime +=(Year-1601)*mult*365;//FIXME : not always 365 days in a year
+  PDOSTIME pdtime = (PDOSTIME) &DosTime;
+  PDOSDATE pddate = (PDOSDATE) &DosDate;
+  TIME_FIELDS TimeFields;
+  LARGE_INTEGER LocalTime;
+
+  if (SystemTime == NULL)
+    return FALSE;
+
+  TimeFields.Milliseconds = 0;
+  TimeFields.Second = pdtime->Second * 2;
+  TimeFields.Minute = pdtime->Minute;
+  TimeFields.Hour = pdtime->Hour;
+
+  TimeFields.Day = pddate->Day;
+  TimeFields.Month = pddate->Month;
+  TimeFields.Year = (CSHORT)(DeviceExt->BaseDateYear + pddate->Year);
+
+  RtlTimeFieldsToTime (&TimeFields, &LocalTime);
+  ExLocalTimeToSystemTime(&LocalTime, SystemTime);
+
   return TRUE;
 }
-#define DosDateTimeToFileTime fsdDosDateTimeToFileTime
 
+// function like FileTimeToDosDateTime
+BOOLEAN
+FsdSystemTimeToDosDateTime (PDEVICE_EXTENSION DeviceExt, PLARGE_INTEGER SystemTime, USHORT *pDosDate, USHORT *pDosTime)
+{
+  PDOSTIME pdtime = (PDOSTIME) pDosTime;
+  PDOSDATE pddate = (PDOSDATE) pDosDate;
+  TIME_FIELDS TimeFields;
+  LARGE_INTEGER LocalTime;
 
+  if (SystemTime == NULL)
+    return FALSE;
 
+  ExSystemTimeToLocalTime (SystemTime, &LocalTime);
+  RtlTimeToTimeFields (&LocalTime, &TimeFields);
 
-unsigned long vfat_wstrlen(PWSTR s)
-{
-        WCHAR c=' ';
-        unsigned int len=0;
+  if (pdtime)
+    {
+      pdtime->Second = TimeFields.Second / 2;
+      pdtime->Minute = TimeFields.Minute;
+      pdtime->Hour = TimeFields.Hour;
+    }
 
-        while(c!=0) {
-                c=*s;
-                s++;
-                len++;
-        };
-        s-=len;
+  if (pddate)
+    {
+      pddate->Day = TimeFields.Day;
+      pddate->Month = TimeFields.Month;
+      pddate->Year = (USHORT) (TimeFields.Year - DeviceExt->BaseDateYear);
+    }
 
-        return len-1;
+  return TRUE;
 }
-#define DWORD_ROUND_UP(x) ( (((ULONG)(x))%32) ? ((((ULONG)x)&(~0x1f))+0x20) : ((ULONG)x) )
 
-NTSTATUS FsdGetFileNameInformation(PFCB pFcb,
-         PFILE_NAMES_INFORMATION pInfo,ULONG BufferLength)
+#define ULONG_ROUND_UP(x)   ROUND_UP((x), (sizeof(ULONG)))
+
+NTSTATUS
+VfatGetFileNameInformation (PVFAT_DIRENTRY_CONTEXT DirContext,
+                           PFILE_NAMES_INFORMATION pInfo, ULONG BufferLength)
 {
- ULONG Length;
-  Length=vfat_wstrlen(pFcb->ObjectName);
-  if( (sizeof(FILE_DIRECTORY_INFORMATION)+Length) >BufferLength)
-     return STATUS_BUFFER_OVERFLOW;
-  pInfo->FileNameLength=Length;
-  pInfo->NextEntryOffset=DWORD_ROUND_UP(sizeof(FILE_DIRECTORY_INFORMATION)+Length);
-  memcpy(pInfo->FileName,pFcb->ObjectName
-     ,sizeof(WCHAR)*(pInfo->FileNameLength));
+  if ((sizeof (FILE_DIRECTORY_INFORMATION) + DirContext->LongNameU.Length) > BufferLength)
+    return STATUS_BUFFER_OVERFLOW;
+  pInfo->FileNameLength = DirContext->LongNameU.Length;
+  pInfo->NextEntryOffset =
+    ULONG_ROUND_UP (sizeof (FILE_DIRECTORY_INFORMATION) + DirContext->LongNameU.Length);
+  RtlCopyMemory (pInfo->FileName, DirContext->LongNameU.Buffer, DirContext->LongNameU.Length);
   return STATUS_SUCCESS;
 }
 
-NTSTATUS FsdGetFileDirectoryInformation(PFCB pFcb,
-          PDEVICE_EXTENSION DeviceExt,
-          PFILE_DIRECTORY_INFORMATION pInfo,ULONG BufferLength)
+NTSTATUS
+VfatGetFileDirectoryInformation (PVFAT_DIRENTRY_CONTEXT DirContext,
+                                PDEVICE_EXTENSION DeviceExt,
+                                PFILE_DIRECTORY_INFORMATION pInfo,
+                                ULONG BufferLength)
 {
-   unsigned long long AllocSize;
-   ULONG Length;
-   
-   DPRINT("BufferLength %d\n",BufferLength);
-   
-   Length=vfat_wstrlen(pFcb->ObjectName);
-   if( (sizeof(FILE_DIRECTORY_INFORMATION)+Length) >BufferLength)
-     return STATUS_BUFFER_OVERFLOW;
-   pInfo->FileNameLength=Length;
-   pInfo->NextEntryOffset=DWORD_ROUND_UP(sizeof(FILE_DIRECTORY_INFORMATION)+Length);
-   memcpy(pInfo->FileName,pFcb->ObjectName
-         ,sizeof(WCHAR)*(pInfo->FileNameLength));
-   DPRINT("pInfo->FileName %w\n",pInfo->FileName);
+  if ((sizeof (FILE_DIRECTORY_INFORMATION) + DirContext->LongNameU.Length) > BufferLength)
+    return STATUS_BUFFER_OVERFLOW;
+  pInfo->FileNameLength = DirContext->LongNameU.Length;
+  pInfo->NextEntryOffset =
+    ULONG_ROUND_UP (sizeof (FILE_DIRECTORY_INFORMATION) + DirContext->LongNameU.Length);
+  RtlCopyMemory (pInfo->FileName, DirContext->LongNameU.Buffer, DirContext->LongNameU.Length);
 //      pInfo->FileIndex=;
-  DosDateTimeToFileTime(pFcb->entry.CreationDate,pFcb->entry.CreationTime
-      ,&pInfo->CreationTime);
-  DosDateTimeToFileTime(pFcb->entry.AccessDate,0
-      ,&pInfo->LastAccessTime);
-  DosDateTimeToFileTime(pFcb->entry.UpdateDate,pFcb->entry.UpdateTime
-      ,&pInfo->LastWriteTime);
-  DosDateTimeToFileTime(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;
-  LARGE_INTEGER_QUAD_PART(pInfo->AllocationSize) = 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 FsdGetFileFullDirectoryInformation(PFCB pFcb,
-          PDEVICE_EXTENSION DeviceExt,
-          PFILE_FULL_DIRECTORY_INFORMATION pInfo,ULONG BufferLength)
+NTSTATUS
+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);
-  if( (sizeof(FILE_FULL_DIRECTORY_INFORMATION)+Length) >BufferLength)
-     return STATUS_BUFFER_OVERFLOW;
-  pInfo->FileNameLength=Length;
-  pInfo->NextEntryOffset=DWORD_ROUND_UP(sizeof(FILE_FULL_DIRECTORY_INFORMATION)+Length);
-  memcpy(pInfo->FileName,pFcb->ObjectName
-     ,sizeof(WCHAR)*(pInfo->FileNameLength));
+  if ((sizeof (FILE_FULL_DIR_INFORMATION) + DirContext->LongNameU.Length) > BufferLength)
+    return STATUS_BUFFER_OVERFLOW;
+  pInfo->FileNameLength = DirContext->LongNameU.Length;
+  pInfo->NextEntryOffset =
+    ULONG_ROUND_UP (sizeof (FILE_FULL_DIR_INFORMATION) + DirContext->LongNameU.Length);
+  RtlCopyMemory (pInfo->FileName, DirContext->LongNameU.Buffer, DirContext->LongNameU.Length);
 //      pInfo->FileIndex=;
-  DosDateTimeToFileTime(pFcb->entry.CreationDate,pFcb->entry.CreationTime
-      ,&pInfo->CreationTime);
-  DosDateTimeToFileTime(pFcb->entry.AccessDate,0
-      ,&pInfo->LastAccessTime);
-  DosDateTimeToFileTime(pFcb->entry.UpdateDate,pFcb->entry.UpdateTime
-      ,&pInfo->LastWriteTime);
-  DosDateTimeToFileTime(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;
-  LARGE_INTEGER_QUAD_PART(pInfo->AllocationSize) = 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 FsdGetFileBothInformation(PFCB pFcb,
-          PDEVICE_EXTENSION DeviceExt,
-          PFILE_BOTH_DIRECTORY_INFORMATION pInfo,ULONG BufferLength)
+NTSTATUS
+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);
-  if( (sizeof(FILE_BOTH_DIRECTORY_INFORMATION)+Length) >BufferLength)
-     return STATUS_BUFFER_OVERFLOW;
-  pInfo->FileNameLength=Length;
-  pInfo->NextEntryOffset=DWORD_ROUND_UP(sizeof(FILE_BOTH_DIRECTORY_INFORMATION)+Length);
-DPRINT("sizeof %d,Length %d, BufLength %d, Next %d\n"
-     ,sizeof(FILE_BOTH_DIRECTORY_INFORMATION),Length,BufferLength
-     ,pInfo->NextEntryOffset);
-  memcpy(pInfo->FileName,pFcb->ObjectName
-     ,sizeof(WCHAR)*(pInfo->FileNameLength));
-//      pInfo->FileIndex=;
-  DosDateTimeToFileTime(pFcb->entry.CreationDate,pFcb->entry.CreationTime
-      ,&pInfo->CreationTime);
-  DosDateTimeToFileTime(pFcb->entry.AccessDate,0
-      ,&pInfo->LastAccessTime);
-  DosDateTimeToFileTime(pFcb->entry.UpdateDate,pFcb->entry.UpdateTime
-      ,&pInfo->LastWriteTime);
-  DosDateTimeToFileTime(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;
-  LARGE_INTEGER_QUAD_PART(pInfo->AllocationSize) = 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);
+  if ((sizeof (FILE_BOTH_DIR_INFORMATION) + DirContext->LongNameU.Length) > BufferLength)
+    return STATUS_BUFFER_OVERFLOW;
+
+  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;
 }
 
-NTSTATUS DoQuery(PDEVICE_OBJECT DeviceObject, 
-                PIRP Irp,
-                PIO_STACK_LOCATION Stack)
+NTSTATUS DoQuery (PVFAT_IRP_CONTEXT IrpContext)
 {
-   NTSTATUS RC=STATUS_SUCCESS;
-   long BufferLength = 0;
-   PUNICODE_STRING pSearchPattern = NULL;
-   FILE_INFORMATION_CLASS FileInformationClass;
-   unsigned long FileIndex = 0;
-   unsigned char *Buffer = NULL;
-   PFILE_NAMES_INFORMATION Buffer0 = NULL;
-   PFILE_OBJECT pFileObject = NULL;
-   PFCB pFcb;
-   FCB tmpFcb;
-   PDEVICE_EXTENSION DeviceExt;
-   WCHAR star[5],*pCharPattern;
-   unsigned long OldEntry,OldSector;
-   BOOLEAN RestartScan;
-   
-   DeviceExt = DeviceObject->DeviceExtension;
-   // Obtain the callers parameters
-   BufferLength = Stack->Parameters.QueryDirectory.Length;
-   pSearchPattern = Stack->Parameters.QueryDirectory.FileName;
-   FileInformationClass = Stack->Parameters.QueryDirectory.FileInformationClass;
-   FileIndex = Stack->Parameters.QueryDirectory.FileIndex;
-   pFileObject = Stack->FileObject;
-   pFcb=(PFCB)(pFileObject->FsContext);
-  
-   
-   if(Stack->Flags & SL_RESTART_SCAN)
-     {
-       pFcb->StartEntry=pFcb->StartSector=0;
-     }
-   
-   // determine Buffer for result :
-   if (Irp->MdlAddress) 
-     Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
-   else
-     Buffer = Irp->UserBuffer;
-   
-   if (pSearchPattern==NULL)
-     {
-       star[0]='*';
-       star[1]=0;
-       pCharPattern=star;
-     }
-   else pCharPattern=pSearchPattern->Buffer;
-   
-  while(RC==STATUS_SUCCESS && BufferLength >0)
-  {
-     OldSector=pFcb->StartSector;
-     OldEntry=pFcb->StartEntry;
-     if(OldSector)pFcb->StartEntry++;
-     RC=FindFile(DeviceExt,
-                &tmpFcb,
-                pFcb,
-                pCharPattern,
-                &pFcb->StartSector,
-                &pFcb->StartEntry);
-     DPRINT("Found %w\n",tmpFcb.ObjectName);
-     if (NT_SUCCESS(RC))
-       {
-         switch(FileInformationClass)
-           {
-            case FileNameInformation:
-              RC=FsdGetFileNameInformation(&tmpFcb
-                              ,(PFILE_NAMES_INFORMATION)Buffer,BufferLength);
-              break;
-            case FileDirectoryInformation:
-              RC= FsdGetFileDirectoryInformation(&tmpFcb,
-                                                 DeviceExt,
-                                      (PFILE_DIRECTORY_INFORMATION)Buffer,
-                                                 BufferLength);
-              break;
-            case FileFullDirectoryInformation :
-              RC= FsdGetFileFullDirectoryInformation(&tmpFcb
-            ,DeviceExt,(PFILE_FULL_DIRECTORY_INFORMATION)Buffer,BufferLength);
-              break;
-            case FileBothDirectoryInformation :
-              RC=FsdGetFileBothInformation(&tmpFcb
-            ,DeviceExt,(PFILE_BOTH_DIRECTORY_INFORMATION)Buffer,BufferLength);
-              break;
-            default:
-              RC=STATUS_INVALID_INFO_CLASS;
-      }
+  NTSTATUS RC = STATUS_SUCCESS;
+  long BufferLength = 0;
+  PUNICODE_STRING pSearchPattern = NULL;
+  FILE_INFORMATION_CLASS FileInformationClass;
+  unsigned char *Buffer = NULL;
+  PFILE_NAMES_INFORMATION Buffer0 = NULL;
+  PVFATFCB pFcb;
+  PVFATCCB pCcb;
+  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 = (PVFATFCB) IrpContext->FileObject->FsContext;
+
+  // 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);
     }
-    else
+#endif
+  Buffer = VfatGetUserBuffer(IrpContext->Irp);
+
+  if (!ExAcquireResourceSharedLite(&pFcb->MainResource,
+                                   (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT)))
     {
-      if(Buffer0) Buffer0->NextEntryOffset=0;
-      break;
+      RC = VfatLockUserBuffer(IrpContext->Irp, BufferLength, IoWriteAccess);
+      if (NT_SUCCESS(RC))
+        {
+          RC = STATUS_PENDING;
+        }
+      return RC;
     }
-    if(RC==STATUS_BUFFER_OVERFLOW)
+
+  /* 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 =
+    Stack->Parameters.QueryDirectory.FileInformationClass;
+  if (pSearchPattern)
     {
-      if(Buffer0) Buffer0->NextEntryOffset=0;
-      pFcb->StartSector=OldSector;
-      pFcb->StartEntry=OldEntry;
-      break;
+      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;
+       }
     }
-    Buffer0=(PFILE_NAMES_INFORMATION)Buffer;
-    Buffer0->FileIndex=FileIndex++;
-     DPRINT("Stack->Flags %x\n",Stack->Flags);
-    if(Stack->Flags & SL_RETURN_SINGLE_ENTRY) break;
-    BufferLength -= Buffer0->NextEntryOffset;
-    Buffer += Buffer0->NextEntryOffset;
-  }
-  if(Buffer0) Buffer0->NextEntryOffset=0;
-  if(FileIndex>0) return STATUS_SUCCESS;
+  else if (!pCcb->SearchPattern.Buffer)
+    {
+      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
+    {
+      DirContext.DirIndex = pCcb->Entry;
+    }
+
+  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)
+    {
+      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 (&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 (FirstQuery)
+            {
+              RC = STATUS_NO_SUCH_FILE;
+            }
+          else
+            {
+              RC = STATUS_NO_MORE_FILES;
+            }
+          break;
+       }
+      Buffer0 = (PFILE_NAMES_INFORMATION) Buffer;
+      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;
+      RC = STATUS_SUCCESS;
+      IrpContext->Irp->IoStatus.Information = Stack->Parameters.QueryDirectory.Length - BufferLength;
+
+    }
+  ExReleaseResourceLite(&pFcb->MainResource);
   return RC;
 }
 
 
-NTSTATUS FsdDirectoryControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+NTSTATUS VfatDirectoryControl (PVFAT_IRP_CONTEXT IrpContext)
 /*
  * FUNCTION: directory control : read/write directory informations
  */
 {
-   NTSTATUS RC = STATUS_SUCCESS;
-   PFILE_OBJECT FileObject = NULL;
-   PIO_STACK_LOCATION Stack;
-   
-   DPRINT("FsdDirectoryControl(DeviceObject %x, Irp %x)\n",
-         DeviceObject,Irp);
-   
-   Stack = IoGetCurrentIrpStackLocation(Irp);
-   FileObject = Stack->FileObject;
-   
-   switch (Stack->MinorFunction)
-   {
+  NTSTATUS RC = STATUS_SUCCESS;
+  CHECKPOINT;
+  IrpContext->Irp->IoStatus.Information = 0;
+  switch (IrpContext->MinorFunction)
+    {
     case IRP_MN_QUERY_DIRECTORY:
-      RC=DoQuery(DeviceObject,Irp,Stack);
+      RC = DoQuery (IrpContext);
       break;
     case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
-      DPRINT(" vfat, dir : change\n");
+      DPRINT (" vfat, dir : change\n");
+      RC = STATUS_NOT_IMPLEMENTED;
       break;
     default:
       // error
-      DbgPrint("unexpected minor function %x in VFAT driver\n",Stack->MinorFunction);
-       RC = STATUS_INVALID_DEVICE_REQUEST;
-       break;
-   }
-   Irp->IoStatus.Status = RC;
-   Irp->IoStatus.Information = 0;
-   
-   IoCompleteRequest(Irp, IO_NO_INCREMENT);
-   return RC;
+      DbgPrint ("unexpected minor function %x in VFAT driver\n",
+               IrpContext->MinorFunction);
+      RC = STATUS_INVALID_DEVICE_REQUEST;
+      break;
+    }
+  if (RC == STATUS_PENDING)
+  {
+     RC = VfatQueueRequest(IrpContext);
+  }
+  else
+  {
+    IrpContext->Irp->IoStatus.Status = RC;
+    IoCompleteRequest (IrpContext->Irp, IO_NO_INCREMENT);
+    VfatFreeIrpContext(IrpContext);
+  }
+  return RC;
 }
 
+