[FASTFAT] Finally drop the FileNameInformation class for directories.
[reactos.git] / drivers / filesystems / fastfat / dir.c
index bf7dd13..51359c4 100644 (file)
@@ -88,23 +88,46 @@ FsdSystemTimeToDosDateTime(
 
 static
 NTSTATUS
-VfatGetFileNameInformation(
+VfatGetFileNamesInformation(
     PVFAT_DIRENTRY_CONTEXT DirContext,
     PFILE_NAMES_INFORMATION pInfo,
-    ULONG BufferLength)
+    ULONG BufferLength,
+    PULONG Written,
+    BOOLEAN First)
 {
-    if ((sizeof(FILE_DIRECTORY_INFORMATION) + DirContext->LongNameU.Length) > BufferLength)
-        return STATUS_BUFFER_OVERFLOW;
+    NTSTATUS Status;
+    ULONG BytesToCopy = 0;
 
-    pInfo->FileNameLength = DirContext->LongNameU.Length;
-    pInfo->NextEntryOffset = ULONG_ROUND_UP(sizeof(FILE_DIRECTORY_INFORMATION) +
-                                            DirContext->LongNameU.Length);
+    *Written = 0;
+    Status = STATUS_BUFFER_OVERFLOW;
 
-    RtlCopyMemory(pInfo->FileName,
-                  DirContext->LongNameU.Buffer,
-                  DirContext->LongNameU.Length);
+    if (FIELD_OFFSET(FILE_NAMES_INFORMATION, FileName) > BufferLength)
+        return Status;
+
+    if (First || (BufferLength >= FIELD_OFFSET(FILE_NAMES_INFORMATION, FileName) + DirContext->LongNameU.Length))
+    {
+        pInfo->FileNameLength = DirContext->LongNameU.Length;
+
+        *Written = FIELD_OFFSET(FILE_NAMES_INFORMATION, FileName);
+        pInfo->NextEntryOffset = 0;
+        if (BufferLength > FIELD_OFFSET(FILE_NAMES_INFORMATION, FileName))
+        {
+            BytesToCopy = min(DirContext->LongNameU.Length, BufferLength - FIELD_OFFSET(FILE_NAMES_INFORMATION, FileName));
+            RtlCopyMemory(pInfo->FileName,
+                         DirContext->LongNameU.Buffer,
+                         BytesToCopy);
+            *Written += BytesToCopy;
+
+            if (BytesToCopy == DirContext->LongNameU.Length)
+            {
+                pInfo->NextEntryOffset = ULONG_ROUND_UP(sizeof(FILE_NAMES_INFORMATION) +
+                                                        BytesToCopy);
+                Status = STATUS_SUCCESS;
+            }
+        }
+    }
 
-    return STATUS_SUCCESS;
+    return Status;
 }
 
 static
@@ -113,90 +136,115 @@ VfatGetFileDirectoryInformation(
     PVFAT_DIRENTRY_CONTEXT DirContext,
     PDEVICE_EXTENSION DeviceExt,
     PFILE_DIRECTORY_INFORMATION pInfo,
-    ULONG BufferLength)
+    ULONG BufferLength,
+    PULONG Written,
+    BOOLEAN First)
 {
-    if ((sizeof(FILE_DIRECTORY_INFORMATION) + DirContext->LongNameU.Length) > BufferLength)
-        return STATUS_BUFFER_OVERFLOW;
+    NTSTATUS Status;
+    ULONG BytesToCopy = 0;
 
-    pInfo->FileNameLength = DirContext->LongNameU.Length;
-    pInfo->NextEntryOffset = ULONG_ROUND_UP(sizeof(FILE_DIRECTORY_INFORMATION) +
-                                            DirContext->LongNameU.Length);
-    /* pInfo->FileIndex = ; */
+    *Written = 0;
+    Status = STATUS_BUFFER_OVERFLOW;
 
-    RtlCopyMemory(pInfo->FileName,
-                  DirContext->LongNameU.Buffer,
-                  DirContext->LongNameU.Length);
+    if (FIELD_OFFSET(FILE_DIRECTORY_INFORMATION, FileName) > BufferLength)
+        return Status;
 
-    if (DeviceExt->Flags & VCB_IS_FATX)
+    if (First || (BufferLength >= FIELD_OFFSET(FILE_DIRECTORY_INFORMATION, FileName) + DirContext->LongNameU.Length))
     {
-        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 = 0;
-            pInfo->AllocationSize.QuadPart = 0;
-        }
-        else
+        pInfo->FileNameLength = DirContext->LongNameU.Length;
+        /* pInfo->FileIndex = ; */
+
+        *Written = FIELD_OFFSET(FILE_DIRECTORY_INFORMATION, FileName);
+        pInfo->NextEntryOffset = 0;
+        if (BufferLength > FIELD_OFFSET(FILE_DIRECTORY_INFORMATION, FileName))
         {
-            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);
+            BytesToCopy = min(DirContext->LongNameU.Length, BufferLength - FIELD_OFFSET(FILE_DIRECTORY_INFORMATION, FileName));
+            RtlCopyMemory(pInfo->FileName,
+                         DirContext->LongNameU.Buffer,
+                         BytesToCopy);
+            *Written += BytesToCopy;
+
+            if (BytesToCopy == DirContext->LongNameU.Length)
+            {
+                pInfo->NextEntryOffset = ULONG_ROUND_UP(sizeof(FILE_DIRECTORY_INFORMATION) +
+                                                        BytesToCopy);
+                Status = STATUS_SUCCESS;
+            }
         }
-    
-        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)
+
+
+
+        if (vfatVolumeIsFatX(DeviceExt))
         {
-            pInfo->EndOfFile.QuadPart = 0;
-            pInfo->AllocationSize.QuadPart = 0;
+            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 (BooleanFlagOn(DirContext->DirEntry.FatX.Attrib, FILE_ATTRIBUTE_DIRECTORY))
+            {
+                pInfo->EndOfFile.QuadPart = 0;
+                pInfo->AllocationSize.QuadPart = 0;
+            }
+            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->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);
-        }
+            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 (BooleanFlagOn(DirContext->DirEntry.Fat.Attrib, FILE_ATTRIBUTE_DIRECTORY))
+            {
+                pInfo->EndOfFile.QuadPart = 0;
+                pInfo->AllocationSize.QuadPart = 0;
+            }
+            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->FileAttributes = DirContext->DirEntry.Fat.Attrib & 0x3f;
+        }
     }
 
-    return STATUS_SUCCESS;
+    return Status;
 }
 
 static
@@ -205,183 +253,220 @@ VfatGetFileFullDirectoryInformation(
     PVFAT_DIRENTRY_CONTEXT DirContext,
     PDEVICE_EXTENSION DeviceExt,
     PFILE_FULL_DIR_INFORMATION pInfo,
-    ULONG BufferLength)
+    ULONG BufferLength,
+    PULONG Written,
+    BOOLEAN First)
 {
-    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);
-    /* pInfo->FileIndex = ; */
-    /* pInfo->EaSize = ; */
-
-    RtlCopyMemory(pInfo->FileName,
-                  DirContext->LongNameU.Buffer,
-                  DirContext->LongNameU.Length);
-
-    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;
-    }
+    NTSTATUS Status;
+    ULONG BytesToCopy = 0;
 
-    return STATUS_SUCCESS;
-}
+    *Written = 0;
+    Status = STATUS_BUFFER_OVERFLOW;
 
-static
-NTSTATUS
-VfatGetFileBothInformation(
-    PVFAT_DIRENTRY_CONTEXT DirContext,
-    PDEVICE_EXTENSION DeviceExt,
-    PFILE_BOTH_DIR_INFORMATION pInfo,
-    ULONG BufferLength)
-{
-    if ((sizeof(FILE_BOTH_DIR_INFORMATION) + DirContext->LongNameU.Length) > BufferLength)
-        return STATUS_BUFFER_OVERFLOW;
-
-    pInfo->EaSize = 0;
+    if (FIELD_OFFSET(FILE_FULL_DIR_INFORMATION, FileName) > BufferLength)
+        return Status;
 
-    if (DeviceExt->Flags & VCB_IS_FATX)
+    if (First || (BufferLength >= FIELD_OFFSET(FILE_FULL_DIR_INFORMATION, FileName) + DirContext->LongNameU.Length))
     {
         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 = ; */
+        pInfo->EaSize = 0;
 
-        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)
+        *Written = FIELD_OFFSET(FILE_FULL_DIR_INFORMATION, FileName);
+        pInfo->NextEntryOffset = 0;
+        if (BufferLength > FIELD_OFFSET(FILE_FULL_DIR_INFORMATION, FileName))
         {
-            pInfo->EndOfFile.QuadPart = 0;
-            pInfo->AllocationSize.QuadPart = 0;
+            BytesToCopy = min(DirContext->LongNameU.Length, BufferLength - FIELD_OFFSET(FILE_FULL_DIR_INFORMATION, FileName));
+            RtlCopyMemory(pInfo->FileName,
+                         DirContext->LongNameU.Buffer,
+                         BytesToCopy);
+            *Written += BytesToCopy;
+
+            if (BytesToCopy == DirContext->LongNameU.Length)
+            {
+                pInfo->NextEntryOffset = ULONG_ROUND_UP(sizeof(FILE_FULL_DIR_INFORMATION) +
+                                                        BytesToCopy);
+                Status = STATUS_SUCCESS;
+            }
         }
-        else
+
+        if (vfatVolumeIsFatX(DeviceExt))
         {
+            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->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);
+    return Status;
+}
+
+static
+NTSTATUS
+VfatGetFileBothInformation(
+    PVFAT_DIRENTRY_CONTEXT DirContext,
+    PDEVICE_EXTENSION DeviceExt,
+    PFILE_BOTH_DIR_INFORMATION pInfo,
+    ULONG BufferLength,
+    PULONG Written,
+    BOOLEAN First)
+{
+    NTSTATUS Status;
+    ULONG BytesToCopy = 0;
 
-        pInfo->ShortNameLength = (CCHAR)DirContext->ShortNameU.Length;
+    *Written = 0;
+    Status = STATUS_BUFFER_OVERFLOW;
 
-        RtlCopyMemory(pInfo->FileName,
-                      DirContext->LongNameU.Buffer,
-                      DirContext->LongNameU.Length);
+    if (FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileName) > BufferLength)
+        return Status;
 
-        /* pInfo->FileIndex = ; */
+    if (First || (BufferLength >= FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileName) + DirContext->LongNameU.Length))
+    {
+        pInfo->FileNameLength = DirContext->LongNameU.Length;
+        pInfo->EaSize = 0;
 
-        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)
+        *Written = FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileName);
+        pInfo->NextEntryOffset = 0;
+        if (BufferLength > FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileName))
         {
-            pInfo->EndOfFile.QuadPart = 0;
-            pInfo->AllocationSize.QuadPart = 0;
+            BytesToCopy = min(DirContext->LongNameU.Length, BufferLength - FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileName));
+            RtlCopyMemory(pInfo->FileName,
+                         DirContext->LongNameU.Buffer,
+                         BytesToCopy);
+            *Written += BytesToCopy;
+
+            if (BytesToCopy == DirContext->LongNameU.Length)
+            {
+                pInfo->NextEntryOffset = ULONG_ROUND_UP(sizeof(FILE_BOTH_DIR_INFORMATION) +
+                                                        BytesToCopy);
+                Status = STATUS_SUCCESS;
+            }
         }
-        else
+
+        if (vfatVolumeIsFatX(DeviceExt))
         {
-            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->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 (BooleanFlagOn(DirContext->DirEntry.FatX.Attrib, FILE_ATTRIBUTE_DIRECTORY))
+            {
+                pInfo->EndOfFile.QuadPart = 0;
+                pInfo->AllocationSize.QuadPart = 0;
+            }
+            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->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 (BooleanFlagOn(DirContext->DirEntry.Fat.Attrib, FILE_ATTRIBUTE_DIRECTORY))
+            {
+                pInfo->EndOfFile.QuadPart = 0;
+                pInfo->AllocationSize.QuadPart = 0;
+            }
+            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->FileAttributes = DirContext->DirEntry.Fat.Attrib & 0x3f;
+        }
     }
 
-    return STATUS_SUCCESS;
+    return Status;
 }
 
 static
@@ -402,6 +487,7 @@ DoQuery(
     VFAT_DIRENTRY_CONTEXT DirContext;
     WCHAR LongNameBuffer[LONGNAME_MAX_LENGTH + 1];
     WCHAR ShortNameBuffer[13];
+    ULONG Written;
 
     PIO_STACK_LOCATION Stack = IrpContext->Stack;
 
@@ -419,11 +505,22 @@ DoQuery(
         ProbeForWrite(IrpContext->Irp->UserBuffer, BufferLength, 1);
     }
 #endif
-    Buffer = VfatGetUserBuffer(IrpContext->Irp);
+    Buffer = VfatGetUserBuffer(IrpContext->Irp, FALSE);
+
+    if (!ExAcquireResourceExclusiveLite(&IrpContext->DeviceExt->DirResource,
+                                        BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
+    {
+        Status = VfatLockUserBuffer(IrpContext->Irp, BufferLength, IoWriteAccess);
+        if (NT_SUCCESS(Status))
+            Status = STATUS_PENDING;
+
+        return Status;
+    }
 
     if (!ExAcquireResourceSharedLite(&pFcb->MainResource,
-                                     (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT)))
+                                     BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
     {
+        ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource);
         Status = VfatLockUserBuffer(IrpContext->Irp, BufferLength, IoWriteAccess);
         if (NT_SUCCESS(Status))
             Status = STATUS_PENDING;
@@ -447,7 +544,7 @@ DoQuery(
      * -> The pattern length is not null
      * -> The pattern buffer is not null
      * Otherwise, we'll fall later and allocate a match all (*) pattern
-     */ 
+     */
     if (pSearchPattern &&
         pSearchPattern->Length != 0 && pSearchPattern->Buffer != NULL)
     {
@@ -461,6 +558,7 @@ DoQuery(
             if (!pCcb->SearchPattern.Buffer)
             {
                 ExReleaseResourceLite(&pFcb->MainResource);
+                ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource);
                 return STATUS_INSUFFICIENT_RESOURCES;
             }
             RtlCopyUnicodeString(&pCcb->SearchPattern, pSearchPattern);
@@ -477,6 +575,7 @@ DoQuery(
         if (!pCcb->SearchPattern.Buffer)
         {
             ExReleaseResourceLite(&pFcb->MainResource);
+            ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource);
             return STATUS_INSUFFICIENT_RESOURCES;
         }
         pCcb->SearchPattern.Buffer[0] = L'*';
@@ -484,11 +583,11 @@ DoQuery(
         pCcb->SearchPattern.Length = sizeof(WCHAR);
     }
 
-    if (IrpContext->Stack->Flags & SL_INDEX_SPECIFIED)
+    if (BooleanFlagOn(IrpContext->Stack->Flags, SL_INDEX_SPECIFIED))
     {
         DirContext.DirIndex = pCcb->Entry = Stack->Parameters.QueryDirectory.FileIndex;
     }
-    else if (FirstQuery || (IrpContext->Stack->Flags & SL_RESTART_SCAN))
+    else if (FirstQuery || BooleanFlagOn(IrpContext->Stack->Flags, SL_RESTART_SCAN))
     {
         DirContext.DirIndex = pCcb->Entry = 0;
     }
@@ -504,13 +603,7 @@ DoQuery(
     DirContext.ShortNameU.Buffer = ShortNameBuffer;
     DirContext.ShortNameU.MaximumLength = sizeof(ShortNameBuffer);
 
-    if (!ExAcquireResourceExclusiveLite(&IrpContext->DeviceExt->DirResource,
-                                        (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT)))
-    {
-        ExReleaseResourceLite(&pFcb->MainResource);
-        return VfatQueueRequest(IrpContext);
-    }
-
+    Written = 0;
     while ((Status == STATUS_SUCCESS) && (BufferLength > 0))
     {
         Status = FindFile(IrpContext->DeviceExt,
@@ -527,33 +620,41 @@ DoQuery(
         {
             switch (FileInformationClass)
             {
-                case FileNameInformation:
-                    Status = VfatGetFileNameInformation(&DirContext,
-                                                        (PFILE_NAMES_INFORMATION)Buffer,
-                                                        BufferLength);
-                    break;
-
                 case FileDirectoryInformation:
                     Status = VfatGetFileDirectoryInformation(&DirContext,
                                                              IrpContext->DeviceExt,
                                                              (PFILE_DIRECTORY_INFORMATION)Buffer,
-                                                             BufferLength);
+                                                             BufferLength,
+                                                             &Written,
+                                                             Buffer0 == NULL);
                     break;
 
                 case FileFullDirectoryInformation:
                     Status = VfatGetFileFullDirectoryInformation(&DirContext,
                                                                  IrpContext->DeviceExt,
                                                                  (PFILE_FULL_DIR_INFORMATION)Buffer,
-                                                                 BufferLength);
+                                                                 BufferLength,
+                                                                 &Written,
+                                                                 Buffer0 == NULL);
                     break;
 
                 case FileBothDirectoryInformation:
                     Status = VfatGetFileBothInformation(&DirContext,
                                                         IrpContext->DeviceExt,
                                                         (PFILE_BOTH_DIR_INFORMATION)Buffer,
-                                                        BufferLength);
+                                                        BufferLength,
+                                                        &Written,
+                                                        Buffer0 == NULL);
                     break;
 
+                case FileNamesInformation:
+                    Status = VfatGetFileNamesInformation(&DirContext,
+                                                         (PFILE_NAMES_INFORMATION)Buffer,
+                                                         BufferLength,
+                                                         &Written,
+                                                         Buffer0 == NULL);
+                     break;
+
                 default:
                     Status = STATUS_INVALID_INFO_CLASS;
                     break;
@@ -573,7 +674,7 @@ DoQuery(
         pCcb->Entry = ++DirContext.DirIndex;
         BufferLength -= Buffer0->NextEntryOffset;
 
-        if (IrpContext->Stack->Flags & SL_RETURN_SINGLE_ENTRY)
+        if (BooleanFlagOn(IrpContext->Stack->Flags, SL_RETURN_SINGLE_ENTRY))
             break;
 
         Buffer += Buffer0->NextEntryOffset;
@@ -585,36 +686,41 @@ DoQuery(
         Status = STATUS_SUCCESS;
         IrpContext->Irp->IoStatus.Information = Stack->Parameters.QueryDirectory.Length - BufferLength;
     }
+    else
+    {
+        ASSERT(Status != STATUS_SUCCESS || BufferLength == 0);
+        ASSERT(Written <= Stack->Parameters.QueryDirectory.Length);
+        IrpContext->Irp->IoStatus.Information = Written;
+    }
 
-    ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource);
     ExReleaseResourceLite(&pFcb->MainResource);
+    ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource);
 
     return Status;
 }
 
-NTSTATUS VfatNotifyChangeDirectory(PVFAT_IRP_CONTEXT IrpContext)
+NTSTATUS VfatNotifyChangeDirectory(PVFAT_IRP_CONTEXT IrpContext)
 {
     PVCB pVcb;
     PVFATFCB pFcb;
     PIO_STACK_LOCATION Stack;
-    Stack = (*IrpContext)->Stack;
-    pVcb = (*IrpContext)->DeviceExt;
-    pFcb = (PVFATFCB) (*IrpContext)->FileObject->FsContext;
+    Stack = IrpContext->Stack;
+    pVcb = IrpContext->DeviceExt;
+    pFcb = (PVFATFCB) IrpContext->FileObject->FsContext;
+
     FsRtlNotifyFullChangeDirectory(pVcb->NotifySync,
                                    &(pVcb->NotifyList),
-                                   (*IrpContext)->FileObject->FsContext2,
+                                   IrpContext->FileObject->FsContext2,
                                    (PSTRING)&(pFcb->PathNameU),
                                    BooleanFlagOn(Stack->Flags, SL_WATCH_TREE),
                                    FALSE,
                                    Stack->Parameters.NotifyDirectory.CompletionFilter,
-                                   (*IrpContext)->Irp,
+                                   IrpContext->Irp,
                                    NULL,
                                    NULL);
 
-    /* We don't need the IRP context as we won't handle IRP completion */
-    VfatFreeIrpContext(*IrpContext);
-    *IrpContext = NULL;
+    /* We won't handle IRP completion */
+    IrpContext->Flags &= ~IRPCONTEXT_COMPLETE;
 
     return STATUS_PENDING;
 }
@@ -637,7 +743,7 @@ VfatDirectoryControl(
             break;
 
         case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
-            Status = VfatNotifyChangeDirectory(&IrpContext);
+            Status = VfatNotifyChangeDirectory(IrpContext);
             break;
 
         default:
@@ -648,19 +754,9 @@ VfatDirectoryControl(
             break;
     }
 
-    if (Status == STATUS_PENDING)
-    {
-        /* Only queue if there's IRP context */
-        if (IrpContext)
-        {
-            Status = VfatQueueRequest(IrpContext);
-        }
-    }
-    else
+    if (Status == STATUS_PENDING && BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_COMPLETE))
     {
-        IrpContext->Irp->IoStatus.Status = Status;
-        IoCompleteRequest (IrpContext->Irp, IO_NO_INCREMENT);
-        VfatFreeIrpContext(IrpContext);
+        return VfatMarkIrpContextForQueue(IrpContext);
     }
 
     return Status;