Commit in reactos/drivers/fs/vfat on MAIN
cleanup.c+2-21.15 -> 1.16
create.c+58-301.75 -> 1.76
dir.c+155-671.35 -> 1.36
direntry.c+201-381.17 -> 1.18
dirwr.c+274-821.42 -> 1.43
fat.c+3-31.46 -> 1.47
fcb.c+65-331.42 -> 1.43
finfo.c+146-821.38 -> 1.39
fsctl.c+175-811.36 -> 1.37
misc.c+2-21.14 -> 1.15
rw.c+19-71.71 -> 1.72
shutdown.c+3-31.8 -> 1.9
vfat.h+94-171.69 -> 1.70
volume.c+141-91.27 -> 1.28
+1338-456
14 modified files
hpoussin <poussine@freesurf.fr>:
- Add full FATX support
- Add volume label setting to FAT volumes
- Change all ANSI_STRING to OEM_STRING (thanks Filip!)
- Correct one bug in VfatUpdateEntry
- Correct one bug in VfatShutdown
Fixes bugs 286, 434 and 442

reactos/drivers/fs/vfat
cleanup.c 1.15 -> 1.16
diff -u -r1.15 -r1.16
--- cleanup.c	28 Aug 2004 22:19:12 -0000	1.15
+++ cleanup.c	5 Dec 2004 16:31:50 -0000	1.16
@@ -1,4 +1,4 @@
-/* $Id: cleanup.c,v 1.15 2004/08/28 22:19:12 navaraf Exp $
+/* $Id: cleanup.c,v 1.16 2004/12/05 16:31:50 gvg Exp $
  *
  * COPYRIGHT:        See COPYING in the top level directory
  * PROJECT:          ReactOS kernel
@@ -35,7 +35,7 @@
   pFcb = (PVFATFCB) FileObject->FsContext;
   if (pFcb)
     {
-      if (!(pFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY) &&
+      if (!(*pFcb->Attributes & FILE_ATTRIBUTE_DIRECTORY) &&
           FsRtlAreThereCurrentFileLocks(&pFcb->FileLock))
        {
          /* remove all locks this process have on this file */

reactos/drivers/fs/vfat
create.c 1.75 -> 1.76
diff -u -r1.75 -r1.76
--- create.c	6 Nov 2004 13:44:56 -0000	1.75
+++ create.c	5 Dec 2004 16:31:50 -0000	1.76
@@ -16,7 +16,7 @@
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
-/* $Id: create.c,v 1.75 2004/11/06 13:44:56 ekohl Exp $
+/* $Id: create.c,v 1.76 2004/12/05 16:31:50 gvg Exp $
  *
  * PROJECT:          ReactOS kernel
  * FILE:             drivers/fs/vfat/create.c
@@ -36,10 +36,6 @@
 
 #include "vfat.h"
 
-/* GLOBALS *******************************************************************/
-
-#define ENTRIES_PER_PAGE   (PAGE_SIZE / sizeof (FATDirEntry))
-
 /* FUNCTIONS *****************************************************************/
 
 void  vfat8Dot3ToString (PFAT_DIR_ENTRY pEntry, PUNICODE_STRING NameU)
@@ -48,7 +44,7 @@
   ULONG Length;
   CHAR  cString[12];
   
-  memcpy(cString, pEntry->Filename, 11);
+  RtlCopyMemory(cString, pEntry->Filename, 11);
   cString[11] = 0;
   if (cString[0] == 0x05)
     {
@@ -71,7 +67,7 @@
     {
       Length = NameU->Length;
       NameU->Buffer += Length / sizeof(WCHAR);
-      if (!ENTRY_VOLUME(pEntry))
+      if (!FAT_ENTRY_VOLUME(pEntry))
         {
 	  Length += sizeof(WCHAR);
           NameU->Buffer[0] = L'.';
@@ -106,16 +102,30 @@
 {
   PVOID Context = NULL;
   ULONG DirIndex = 0;
-  FATDirEntry* Entry;
+  PDIR_ENTRY Entry;
   PVFATFCB pFcb;
   LARGE_INTEGER FileOffset;
   UNICODE_STRING NameU;
+  ULONG SizeDirEntry;
+  ULONG EntriesPerPage;
+  OEM_STRING StringO;
 
   NameU.Buffer = Vpb->VolumeLabel;
   NameU.Length = 0;
   NameU.MaximumLength = sizeof(Vpb->VolumeLabel);
   *(Vpb->VolumeLabel) = 0;
   Vpb->VolumeLabelLength = 0;
+  
+  if (DeviceExt->Flags & VCB_IS_FATX)
+  {
+    SizeDirEntry = sizeof(FATX_DIR_ENTRY);
+    EntriesPerPage = FATX_ENTRIES_PER_PAGE;
+  }
+  else
+  {
+    SizeDirEntry = sizeof(FAT_DIR_ENTRY);
+    EntriesPerPage = FAT_ENTRIES_PER_PAGE;
+  }
 
   ExAcquireResourceExclusiveLite (&DeviceExt->DirResource, TRUE);
   pFcb = vfatOpenRootFCB (DeviceExt);
@@ -126,20 +136,29 @@
   {
      while (TRUE)
      {
-       if (ENTRY_VOLUME(Entry))
+       if (ENTRY_VOLUME(DeviceExt, Entry))
        {
           /* copy volume label */
-          vfat8Dot3ToString (Entry, &NameU);
+          if (DeviceExt->Flags & VCB_IS_FATX)
+          {
+            StringO.Buffer = Entry->FatX.Filename;
+            StringO.MaximumLength = StringO.Length = Entry->FatX.FilenameLength;
+            RtlOemStringToUnicodeString(&NameU, &StringO, FALSE);
+          }
+          else
+          {
+            vfat8Dot3ToString (&Entry->Fat, &NameU);
+          }
           Vpb->VolumeLabelLength = NameU.Length;
           break;
        }
-       if (ENTRY_END(Entry))
+       if (ENTRY_END(DeviceExt, Entry))
        {
           break;
        }
        DirIndex++;       
-       Entry++;
-       if ((DirIndex % ENTRIES_PER_PAGE) == 0)
+       Entry = (PDIR_ENTRY)((ULONG_PTR)Entry + SizeDirEntry);
+       if ((DirIndex % EntriesPerPage) == 0)
        {
 	  CcUnpinData(Context);
 	  FileOffset.u.LowPart += PAGE_SIZE;
@@ -212,7 +231,7 @@
 	    {
 	      RtlCopyUnicodeString(&DirContext->LongNameU, &rcFcb->LongNameU);
 	      RtlCopyUnicodeString(&DirContext->ShortNameU, &rcFcb->ShortNameU);
-	      memcpy(&DirContext->FatDirEntry, &rcFcb->entry, sizeof(FATDirEntry));
+	      RtlCopyMemory(&DirContext->DirEntry, &rcFcb->entry, sizeof(DIR_ENTRY));
 	      DirContext->StartIndex = rcFcb->startIndex;
 	      DirContext->DirIndex = rcFcb->dirIndex;
               DPRINT("FindFile: new Name %wZ, DirIndex %d (%d)\n",
@@ -231,13 +250,13 @@
 
   while(TRUE)
     {
-      Status = vfatGetNextDirEntry(&Context, &Page, Parent, DirContext, First);
+      Status = DeviceExt->GetNextDirEntry(&Context, &Page, Parent, DirContext, First);
       First = FALSE;
       if (Status == STATUS_NO_MORE_ENTRIES)
         {
 	  break;
         }
-      if (ENTRY_VOLUME(&DirContext->FatDirEntry))
+      if (ENTRY_VOLUME(DeviceExt, &DirContext->DirEntry))
         {
           DirContext->DirIndex++;
           continue;
@@ -269,7 +288,7 @@
               rcFcb = vfatGrabFCBFromTable(DeviceExt, &PathNameU);
 	      if (rcFcb != NULL)
 	        {
-	          memcpy(&DirContext->FatDirEntry, &rcFcb->entry, sizeof(FATDirEntry));
+	          RtlCopyMemory(&DirContext->DirEntry, &rcFcb->entry, sizeof(DIR_ENTRY));
                   vfatReleaseFCB(DeviceExt, rcFcb);
 		}
 	    }
@@ -407,17 +426,26 @@
   ULONG Cluster, NextCluster;
   NTSTATUS Status;
   
-  Fcb->entry.FileSize = 0;
-  if (DeviceExt->FatInfo.FatType == FAT32)
-    {
-      Cluster = Fcb->entry.FirstCluster + Fcb->entry.FirstClusterHigh * 65536;
-    }
+  if (Fcb->Flags & FCB_IS_FATX_ENTRY)
+  {
+    Fcb->entry.FatX.FileSize = 0;
+    Cluster = Fcb->entry.FatX.FirstCluster;
+    Fcb->entry.FatX.FirstCluster = 0;
+  }
   else
-    {
-      Cluster = Fcb->entry.FirstCluster;
-    }
-  Fcb->entry.FirstCluster = 0;
-  Fcb->entry.FirstClusterHigh = 0;
+  {
+    Fcb->entry.Fat.FileSize = 0;
+    if (DeviceExt->FatInfo.FatType == FAT32)
+      {
+        Cluster = Fcb->entry.Fat.FirstCluster + Fcb->entry.Fat.FirstClusterHigh * 65536;
+      }
+    else
+      {
+        Cluster = Fcb->entry.Fat.FirstCluster;
+      }
+    Fcb->entry.Fat.FirstCluster = 0;
+    Fcb->entry.Fat.FirstClusterHigh = 0;
+  }
   Fcb->LastOffset = Fcb->LastCluster = 0;
   VfatUpdateEntry (Fcb);
   if (Fcb->RFCB.FileSize.QuadPart > 0)
@@ -496,7 +524,7 @@
 	{
 	  return (STATUS_INSUFFICIENT_RESOURCES);
 	}
-      memset(pCcb, 0, sizeof(VFATCCB));
+      RtlZeroMemory(pCcb, sizeof(VFATCCB));
       FileObject->Flags |= FO_FCB_IS_VALID;
       FileObject->SectionObjectPointer = &pFcb->SectionObjectPointers;
       FileObject->FsContext = pFcb;
@@ -626,13 +654,13 @@
        * Check the file has the requested attributes
        */
       if (RequestedOptions & FILE_NON_DIRECTORY_FILE && 
-	  pFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY)
+	  *pFcb->Attributes & FILE_ATTRIBUTE_DIRECTORY)
 	{
 	  VfatCloseFile (DeviceExt, FileObject);
 	  return(STATUS_FILE_IS_A_DIRECTORY);
 	}
       if (RequestedOptions & FILE_DIRECTORY_FILE && 
-	  !(pFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
+	  !(*pFcb->Attributes & FILE_ATTRIBUTE_DIRECTORY))
 	{
 	  VfatCloseFile (DeviceExt, FileObject);
 	  return(STATUS_NOT_A_DIRECTORY);

reactos/drivers/fs/vfat
dir.c 1.35 -> 1.36
diff -u -r1.35 -r1.36
--- dir.c	6 Nov 2004 13:44:57 -0000	1.35
+++ dir.c	5 Dec 2004 16:31:50 -0000	1.36
@@ -1,5 +1,5 @@
 /*
- * $Id: dir.c,v 1.35 2004/11/06 13:44:57 ekohl Exp $
+ * $Id: dir.c,v 1.36 2004/12/05 16:31:50 gvg Exp $
  *
  * COPYRIGHT:        See COPYING in the top level directory
  * PROJECT:          ReactOS kernel
@@ -21,7 +21,7 @@
 
 // function like DosDateTimeToFileTime
 BOOL
-FsdDosDateTimeToSystemTime (WORD wDosDate, WORD wDosTime, PLARGE_INTEGER SystemTime)
+FsdDosDateTimeToSystemTime (PDEVICE_EXTENSION DeviceExt, WORD wDosDate, WORD wDosTime, PLARGE_INTEGER SystemTime)
 {
   PDOSTIME pdtime = (PDOSTIME) & wDosTime;
   PDOSDATE pddate = (PDOSDATE) & wDosDate;
@@ -38,7 +38,7 @@
 
   TimeFields.Day = pddate->Day;
   TimeFields.Month = pddate->Month;
-  TimeFields.Year = 1980 + pddate->Year;
+  TimeFields.Year = DeviceExt->BaseDateYear + pddate->Year;
 
   RtlTimeFieldsToTime (&TimeFields, &LocalTime);
   ExLocalTimeToSystemTime(&LocalTime, SystemTime);
@@ -46,10 +46,9 @@
   return TRUE;
 }
 
-
 // function like FileTimeToDosDateTime
 BOOL
-FsdSystemTimeToDosDateTime (PLARGE_INTEGER SystemTime, WORD * pwDosDate, WORD * pwDosTime)
+FsdSystemTimeToDosDateTime (PDEVICE_EXTENSION DeviceExt, PLARGE_INTEGER SystemTime, WORD * pwDosDate, WORD * pwDosTime)
 {
   PDOSTIME pdtime = (PDOSTIME) pwDosTime;
   PDOSDATE pddate = (PDOSDATE) pwDosDate;
@@ -73,13 +72,12 @@
     {
       pddate->Day = TimeFields.Day;
       pddate->Month = TimeFields.Month;
-      pddate->Year = TimeFields.Year - 1980;
+      pddate->Year = TimeFields.Year - DeviceExt->BaseDateYear;
     }
 
   return TRUE;
 }
 
-
 #define DWORD_ROUND_UP(x)   ROUND_UP((x), (sizeof(DWORD)))
 
 NTSTATUS
@@ -91,7 +89,7 @@
   pInfo->FileNameLength = DirContext->LongNameU.Length;
   pInfo->NextEntryOffset =
     DWORD_ROUND_UP (sizeof (FILE_DIRECTORY_INFORMATION) + DirContext->LongNameU.Length);
-  memcpy (pInfo->FileName, DirContext->LongNameU.Buffer, DirContext->LongNameU.Length);
+  RtlCopyMemory (pInfo->FileName, DirContext->LongNameU.Buffer, DirContext->LongNameU.Length);
   return STATUS_SUCCESS;
 }
 
@@ -106,31 +104,61 @@
   pInfo->FileNameLength = DirContext->LongNameU.Length;
   pInfo->NextEntryOffset =
     DWORD_ROUND_UP (sizeof (FILE_DIRECTORY_INFORMATION) + DirContext->LongNameU.Length);
-  memcpy (pInfo->FileName, DirContext->LongNameU.Buffer, DirContext->LongNameU.Length);
+  RtlCopyMemory (pInfo->FileName, DirContext->LongNameU.Buffer, DirContext->LongNameU.Length);
 //      pInfo->FileIndex=;
-  FsdDosDateTimeToSystemTime (DirContext->FatDirEntry.CreationDate,
-			      DirContext->FatDirEntry.CreationTime,
+  if (DeviceExt->Flags & VCB_IS_FATX)
+  {
+    FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.FatX.CreationDate,
+			      DirContext->DirEntry.FatX.CreationTime,
 			      &pInfo->CreationTime);
-  FsdDosDateTimeToSystemTime (DirContext->FatDirEntry.AccessDate, 0,
+    FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.FatX.AccessDate,
+               DirContext->DirEntry.FatX.AccessTime,
 			      &pInfo->LastAccessTime);
-  FsdDosDateTimeToSystemTime (DirContext->FatDirEntry.UpdateDate,
-			      DirContext->FatDirEntry.UpdateTime,
+    FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.FatX.UpdateDate,
+			      DirContext->DirEntry.FatX.UpdateTime,
 			      &pInfo->LastWriteTime);
-  pInfo->ChangeTime = pInfo->LastWriteTime;
-  if (DirContext->FatDirEntry.Attrib & FILE_ATTRIBUTE_DIRECTORY)
-    {
-      pInfo->EndOfFile.QuadPart = 0LL;
-      pInfo->AllocationSize.QuadPart = 0LL;
-    }
+    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->EndOfFile.u.HighPart = 0;
-      pInfo->EndOfFile.u.LowPart = DirContext->FatDirEntry.FileSize;
-      /* Make allocsize a rounded up multiple of BytesPerCluster */
-      pInfo->AllocationSize.u.HighPart = 0;
-      pInfo->AllocationSize.u.LowPart = ROUND_UP(DirContext->FatDirEntry.FileSize, DeviceExt->FatInfo.BytesPerCluster);
-    }
-  pInfo->FileAttributes = DirContext->FatDirEntry.Attrib & 0x3f;
+  {
+    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;
 }
@@ -146,23 +174,45 @@
   pInfo->FileNameLength = DirContext->LongNameU.Length;
   pInfo->NextEntryOffset =
     DWORD_ROUND_UP (sizeof (FILE_FULL_DIRECTORY_INFORMATION) + DirContext->LongNameU.Length);
-  memcpy (pInfo->FileName, DirContext->LongNameU.Buffer, DirContext->LongNameU.Length);
+  RtlCopyMemory (pInfo->FileName, DirContext->LongNameU.Buffer, DirContext->LongNameU.Length);
 //      pInfo->FileIndex=;
-  FsdDosDateTimeToSystemTime (DirContext->FatDirEntry.CreationDate,
-			      DirContext->FatDirEntry.CreationTime,
+  if (DeviceExt->Flags & VCB_IS_FATX)
+  {
+    FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.FatX.CreationDate,
+			      DirContext->DirEntry.FatX.CreationTime,
 			      &pInfo->CreationTime);
-  FsdDosDateTimeToSystemTime (DirContext->FatDirEntry.AccessDate,
+    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 (DirContext->FatDirEntry.UpdateDate,
-                              DirContext->FatDirEntry.UpdateTime,
+    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->FatDirEntry.FileSize;
-  /* Make allocsize a rounded up multiple of BytesPerCluster */
-  pInfo->AllocationSize.u.HighPart = 0;
-  pInfo->AllocationSize.u.LowPart = ROUND_UP(DirContext->FatDirEntry.FileSize, DeviceExt->FatInfo.BytesPerCluster);
-  pInfo->FileAttributes = DirContext->FatDirEntry.Attrib & 0x3f;
+    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;
 }
@@ -175,36 +225,74 @@
 {
   if ((sizeof (FILE_BOTH_DIRECTORY_INFORMATION) + DirContext->LongNameU.Length) > BufferLength)
     return STATUS_BUFFER_OVERFLOW;
-  pInfo->FileNameLength = DirContext->LongNameU.Length;
-  pInfo->NextEntryOffset = 
-    DWORD_ROUND_UP (sizeof (FILE_BOTH_DIRECTORY_INFORMATION) + DirContext->LongNameU.Length);
-  memcpy(pInfo->ShortName, DirContext->ShortNameU.Buffer, DirContext->ShortNameU.Length);
-  pInfo->ShortNameLength = DirContext->ShortNameU.Length;
-  memcpy (pInfo->FileName, DirContext->LongNameU.Buffer, DirContext->LongNameU.Length);
-//      pInfo->FileIndex=;
-  FsdDosDateTimeToSystemTime (DirContext->FatDirEntry.CreationDate,
-                              DirContext->FatDirEntry.CreationDate,
+  
+  if (DeviceExt->Flags & VCB_IS_FATX)
+  {
+    pInfo->FileNameLength = DirContext->LongNameU.Length;
+    RtlCopyMemory(pInfo->FileName, DirContext->LongNameU.Buffer, DirContext->LongNameU.Length);
+    pInfo->NextEntryOffset = 
+      DWORD_ROUND_UP (sizeof (FILE_BOTH_DIRECTORY_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 (DirContext->FatDirEntry.AccessDate, 0,
+    FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.FatX.AccessDate,
+                              DirContext->DirEntry.FatX.AccessTime,
                               &pInfo->LastAccessTime);
-  FsdDosDateTimeToSystemTime (DirContext->FatDirEntry.UpdateDate,
-                              DirContext->FatDirEntry.UpdateTime,
+    FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.FatX.UpdateDate,
+                              DirContext->DirEntry.FatX.UpdateTime,
                               &pInfo->LastWriteTime);
-  pInfo->ChangeTime = pInfo->LastWriteTime;
-  if (DirContext->FatDirEntry.Attrib & FILE_ATTRIBUTE_DIRECTORY)
-    {
-      pInfo->EndOfFile.QuadPart = 0LL;
-      pInfo->AllocationSize.QuadPart = 0LL;
-    }
+    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->EndOfFile.u.HighPart = 0;
-      pInfo->EndOfFile.u.LowPart = DirContext->FatDirEntry.FileSize;
-      /* Make allocsize a rounded up multiple of BytesPerCluster */
-      pInfo->AllocationSize.u.HighPart = 0;
-      pInfo->AllocationSize.u.LowPart = ROUND_UP(DirContext->FatDirEntry.FileSize, DeviceExt->FatInfo.BytesPerCluster);
-    }
-  pInfo->FileAttributes = DirContext->FatDirEntry.Attrib & 0x3f;
+  {
+    pInfo->FileNameLength = DirContext->LongNameU.Length;
+    pInfo->NextEntryOffset = 
+      DWORD_ROUND_UP (sizeof (FILE_BOTH_DIRECTORY_INFORMATION) + DirContext->LongNameU.Length);
+    RtlCopyMemory(pInfo->ShortName, DirContext->ShortNameU.Buffer, DirContext->ShortNameU.Length);
+    pInfo->ShortNameLength = 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;
 }

reactos/drivers/fs/vfat
direntry.c 1.17 -> 1.18
diff -u -r1.17 -r1.18
--- direntry.c	1 Aug 2004 21:57:17 -0000	1.17
+++ direntry.c	5 Dec 2004 16:31:50 -0000	1.18
@@ -1,4 +1,4 @@
-/* $Id: direntry.c,v 1.17 2004/08/01 21:57:17 navaraf Exp $
+/* $Id: direntry.c,v 1.18 2004/12/05 16:31:50 gvg Exp $
  *
  *
  * FILE:             DirEntry.c
@@ -8,6 +8,7 @@
  * PROGRAMMER:       Jason Filby (jasonfilby@yahoo.com)
  *                   Rex Jolliff (rex@lvcablemodem.com)
  *                   Hartmut Birr
+ *                   Herve Poussineau (reactos@poussine.freesurf.fr)
  */
 
 /*  -------------------------------------------------------  INCLUDES  */
@@ -21,28 +22,30 @@
 
 #include "vfat.h"
 
-#define ENTRIES_PER_PAGE   (PAGE_SIZE / sizeof (FATDirEntry))
-
 ULONG 
 vfatDirEntryGetFirstCluster (PDEVICE_EXTENSION  pDeviceExt,
-                             PFAT_DIR_ENTRY  pFatDirEntry)
+                             PDIR_ENTRY  pFatDirEntry)
 {
   ULONG  cluster;
 
   if (pDeviceExt->FatInfo.FatType == FAT32)
   {
-    cluster = pFatDirEntry->FirstCluster + 
-      pFatDirEntry->FirstClusterHigh * 65536;
+    cluster = pFatDirEntry->Fat.FirstCluster + 
+      pFatDirEntry->Fat.FirstClusterHigh * 65536;
+  }
+  else if (pDeviceExt->Flags & VCB_IS_FATX)
+  {
+    cluster = pFatDirEntry->FatX.FirstCluster;
   }
   else
   {
-    cluster = pFatDirEntry->FirstCluster;
+    cluster = pFatDirEntry->Fat.FirstCluster;
   }
 
   return  cluster;
 }
 
-BOOL VfatIsDirectoryEmpty(PVFATFCB Fcb)
+BOOL FATIsDirectoryEmpty(PVFATFCB Fcb)
 {
    LARGE_INTEGER FileOffset;
    PVOID Context = NULL;
@@ -63,7 +66,7 @@
 
    while (Index < MaxIndex)
      {
-       if (Context == NULL || (Index % ENTRIES_PER_PAGE) == 0)
+       if (Context == NULL || (Index % FAT_ENTRIES_PER_PAGE) == 0)
          {
 	   if (Context != NULL)
 	     {
@@ -73,14 +76,14 @@
 	      {
 		return TRUE;
 	      }
-	    FatDirEntry += Index % ENTRIES_PER_PAGE;
+	    FatDirEntry += Index % FAT_ENTRIES_PER_PAGE;
 	 }
-       if (ENTRY_END(FatDirEntry))
+       if (FAT_ENTRY_END(FatDirEntry))
 	  {
 	    CcUnpinData(Context);
 	    return TRUE;
 	  }
-       if (!ENTRY_DELETED(FatDirEntry))
+       if (!FAT_ENTRY_DELETED(FatDirEntry))
          {
 	   CcUnpinData(Context);
 	   return FALSE;
@@ -95,7 +98,61 @@
    return TRUE;
 }
 
-NTSTATUS vfatGetNextDirEntry(PVOID * pContext,
+BOOL FATXIsDirectoryEmpty(PVFATFCB Fcb)
+{
+   LARGE_INTEGER FileOffset;
+   PVOID Context = NULL;
+   PFATX_DIR_ENTRY FatXDirEntry;
+   ULONG Index, MaxIndex;
+
+   Index = 0;
+
+   FileOffset.QuadPart = 0LL;
+   MaxIndex = Fcb->RFCB.FileSize.u.LowPart / sizeof(FATX_DIR_ENTRY);
+
+   while (Index < MaxIndex)
+   {
+      if (Context == NULL || (Index % FATX_ENTRIES_PER_PAGE) == 0)
+      {
+         if (Context != NULL)
+         {
+            CcUnpinData(Context);
+         }
+         if (!CcMapData(Fcb->FileObject, &FileOffset, PAGE_SIZE, TRUE, &Context, (PVOID*)&FatXDirEntry))
+         {
+            return TRUE;
+         }
+         FatXDirEntry += Index % FATX_ENTRIES_PER_PAGE;
+      }
+      if (FATX_ENTRY_END(FatXDirEntry))
+      {
+         CcUnpinData(Context);
+         return TRUE;
+      }
+      if (!FATX_ENTRY_DELETED(FatXDirEntry))
+      {
+         CcUnpinData(Context);
+         return FALSE;
+      }
+      Index++;
+      FatXDirEntry++;
+   }
+   if (Context)
+   {
+      CcUnpinData(Context);
+   }
+   return TRUE;
+}
+
+BOOL VfatIsDirectoryEmpty(PVFATFCB Fcb)
+{
+   if (Fcb->Flags & FCB_IS_FATX_ENTRY)
+      return FATXIsDirectoryEmpty(Fcb);
+   else
+      return FATIsDirectoryEmpty(Fcb);
+}
+
+NTSTATUS FATGetNextDirEntry(PVOID * pContext,
 			     PVOID * pPage,
                              IN PVFATFCB pDirFcb,
 			     PVFAT_DIRENTRY_CONTEXT DirContext,
@@ -104,7 +161,7 @@
     ULONG dirMap;
     PWCHAR pName;
     LARGE_INTEGER FileOffset;
-    FATDirEntry * fatDirEntry;
+    PFAT_DIR_ENTRY fatDirEntry;
     slot * longNameEntry;
     ULONG index;
     
@@ -116,9 +173,9 @@
     DirContext->LongNameU.Buffer[0] = 0;
 
     FileOffset.u.HighPart = 0;
-    FileOffset.u.LowPart = ROUND_DOWN(DirContext->DirIndex * sizeof(FATDirEntry), PAGE_SIZE);
+    FileOffset.u.LowPart = ROUND_DOWN(DirContext->DirIndex * sizeof(FAT_DIR_ENTRY), PAGE_SIZE);
 
-    if (*pContext == NULL || (DirContext->DirIndex % ENTRIES_PER_PAGE) == 0)
+    if (*pContext == NULL || (DirContext->DirIndex % FAT_ENTRIES_PER_PAGE) == 0)
     {
        if (*pContext != NULL)
        {
@@ -132,7 +189,7 @@
     }
 
 
-    fatDirEntry = (FATDirEntry*)(*pPage) + DirContext->DirIndex % ENTRIES_PER_PAGE;
+    fatDirEntry = (PFAT_DIR_ENTRY)(*pPage) + DirContext->DirIndex % FAT_ENTRIES_PER_PAGE;
     longNameEntry = (slot*) fatDirEntry;
     dirMap = 0;
 
@@ -142,14 +199,14 @@
 	 * into a long name or points to a short name with an assigned long name. 
 	 * We must go back to the real start of the entry */
         while (DirContext->DirIndex > 0 && 
-	       !ENTRY_END(fatDirEntry) && 
-	       !ENTRY_DELETED(fatDirEntry) && 
-	       ((!ENTRY_LONG(fatDirEntry) && !Back) || 
-	        (ENTRY_LONG(fatDirEntry) && !(longNameEntry->id & 0x40))))
+	       !FAT_ENTRY_END(fatDirEntry) && 
+	       !FAT_ENTRY_DELETED(fatDirEntry) && 
+	       ((!FAT_ENTRY_LONG(fatDirEntry) && !Back) || 
+	        (FAT_ENTRY_LONG(fatDirEntry) && !(longNameEntry->id & 0x40))))
           {
             DirContext->DirIndex--;
 	    Back = TRUE;
-            if ((DirContext->DirIndex % ENTRIES_PER_PAGE) == ENTRIES_PER_PAGE - 1)
+            if ((DirContext->DirIndex % FAT_ENTRIES_PER_PAGE) == FAT_ENTRIES_PER_PAGE - 1)
               {
                 CcUnpinData(*pContext);
                 FileOffset.u.LowPart -= PAGE_SIZE;
@@ -159,7 +216,7 @@
 	            *pContext = NULL;
 	            return STATUS_NO_MORE_ENTRIES;
 		  }
-                fatDirEntry = (FATDirEntry*)(*pPage) + DirContext->DirIndex % ENTRIES_PER_PAGE;
+                fatDirEntry = (PFAT_DIR_ENTRY)(*pPage) + DirContext->DirIndex % FAT_ENTRIES_PER_PAGE;
                 longNameEntry = (slot*) fatDirEntry;
               }
 	    else
@@ -169,11 +226,11 @@
 	      }
           }
 
-        if (Back && !ENTRY_END(fatDirEntry) && 
-	    (ENTRY_DELETED(fatDirEntry) || !ENTRY_LONG(fatDirEntry)))
+        if (Back && !FAT_ENTRY_END(fatDirEntry) && 
+	    (FAT_ENTRY_DELETED(fatDirEntry) || !FAT_ENTRY_LONG(fatDirEntry)))
           {
             DirContext->DirIndex++;
-	    if ((DirContext->DirIndex % ENTRIES_PER_PAGE) == 0)
+	    if ((DirContext->DirIndex % FAT_ENTRIES_PER_PAGE) == 0)
 	      {
 	        CcUnpinData(*pContext);
 	        FileOffset.u.LowPart += PAGE_SIZE;
@@ -183,7 +240,7 @@
 		    *pContext = NULL;
 		    return STATUS_NO_MORE_ENTRIES;
 	          }
-	        fatDirEntry = (FATDirEntry*)*pPage;
+	        fatDirEntry = (PFAT_DIR_ENTRY)*pPage;
 	        longNameEntry = (slot*) *pPage;
 	      }
 	    else
@@ -199,14 +256,14 @@
 
     while (TRUE)
       {
-	if (ENTRY_END(fatDirEntry))
+	if (FAT_ENTRY_END(fatDirEntry))
 	  {
 	    CcUnpinData(*pContext);
 	    *pContext = NULL;
 	    return STATUS_NO_MORE_ENTRIES;
 	  }
 
-	if (ENTRY_DELETED(fatDirEntry))
+	if (FAT_ENTRY_DELETED(fatDirEntry))
 	  {
 	    dirMap = 0;
 	    DirContext->LongNameU.Buffer[0] = 0;
@@ -214,12 +271,12 @@
 	  }
 	else
 	  {
-	    if (ENTRY_LONG(fatDirEntry))
+	    if (FAT_ENTRY_LONG(fatDirEntry))
 	      {
 		if (dirMap == 0)
 		  {
 		    DPRINT ("  long name entry found at %d\n", DirContext->DirIndex);
-                    memset(DirContext->LongNameU.Buffer, 0, DirContext->LongNameU.MaximumLength);
+		    RtlZeroMemory(DirContext->LongNameU.Buffer, DirContext->LongNameU.MaximumLength);
 		    CheckSum = longNameEntry->alias_checksum;
 		    Valid = TRUE;
 		  }
@@ -233,9 +290,9 @@
 		dirMap |= 1 << index;
 		pName = DirContext->LongNameU.Buffer + 13 * index;
 
-		memcpy(pName, longNameEntry->name0_4, 5 * sizeof(WCHAR));
-		memcpy(pName + 5, longNameEntry->name5_10, 6 * sizeof(WCHAR));
-		memcpy(pName + 11, longNameEntry->name11_12, 2 * sizeof(WCHAR));
+		RtlCopyMemory(pName, longNameEntry->name0_4, 5 * sizeof(WCHAR));
+		RtlCopyMemory(pName + 5, longNameEntry->name5_10, 6 * sizeof(WCHAR));
+		RtlCopyMemory(pName + 11, longNameEntry->name11_12, 2 * sizeof(WCHAR));
       
 		DPRINT ("  longName: [%S]\n", DirContext->LongNameU.Buffer);
 		if (CheckSum != longNameEntry->alias_checksum)
@@ -265,12 +322,12 @@
 		    DirContext->LongNameU.Buffer[0] = 0;
 		  }
     
-	        memcpy (&DirContext->FatDirEntry, fatDirEntry, sizeof (FAT_DIR_ENTRY));
+	        RtlCopyMemory (&DirContext->DirEntry.Fat, fatDirEntry, sizeof (FAT_DIR_ENTRY));
 		break;
 	      }
 	   }
 	DirContext->DirIndex++;
-	if ((DirContext->DirIndex % ENTRIES_PER_PAGE) == 0)
+	if ((DirContext->DirIndex % FAT_ENTRIES_PER_PAGE) == 0)
 	  {
 	    CcUnpinData(*pContext);
 	    FileOffset.u.LowPart += PAGE_SIZE;
@@ -280,7 +337,7 @@
 		*pContext = NULL;
 		return STATUS_NO_MORE_ENTRIES;
 	      }
-	    fatDirEntry = (FATDirEntry*)*pPage;
+	    fatDirEntry = (PFAT_DIR_ENTRY)*pPage;
 	    longNameEntry = (slot*) *pPage;
 	  }
 	else
@@ -290,10 +347,116 @@
 	  }
       }
     DirContext->LongNameU.Length = wcslen(DirContext->LongNameU.Buffer) * sizeof(WCHAR);
-    vfat8Dot3ToString(&DirContext->FatDirEntry, &DirContext->ShortNameU);
+    vfat8Dot3ToString(&DirContext->DirEntry.Fat, &DirContext->ShortNameU);
     if (DirContext->LongNameU.Length == 0)
       {
         RtlCopyUnicodeString(&DirContext->LongNameU, &DirContext->ShortNameU);
       }
     return STATUS_SUCCESS;
 }
+
+NTSTATUS FATXGetNextDirEntry(PVOID * pContext,
+			     PVOID * pPage,
+                             IN PVFATFCB pDirFcb,
+			     PVFAT_DIRENTRY_CONTEXT DirContext,
+			     BOOLEAN First)
+{
+   LARGE_INTEGER FileOffset;
+   PFATX_DIR_ENTRY fatxDirEntry;
+   OEM_STRING StringO;
+   ULONG DirIndex = DirContext->DirIndex;
+
+   FileOffset.u.HighPart = 0;
+   FileOffset.u.LowPart = ROUND_DOWN(DirContext->DirIndex * sizeof(FATX_DIR_ENTRY), PAGE_SIZE);
+   
+   if (!vfatFCBIsRoot(pDirFcb))
+   {
+      /* need to add . and .. entries */
+      switch (DirContext->DirIndex)
+      {
+         case 0: /* entry . */
+         {
+            DirContext->ShortNameU.Buffer[0] = 0;
+            DirContext->ShortNameU.Length = 0;
+            DirContext->LongNameU.Buffer[0] = L'.';
+            DirContext->LongNameU.Length = sizeof(WCHAR);
+            RtlCopyMemory(&DirContext->DirEntry.FatX, &pDirFcb->entry.FatX, sizeof(FATX_DIR_ENTRY));
+            DirContext->DirEntry.FatX.Filename[0] = '.';
+            DirContext->DirEntry.FatX.FilenameLength = 1;
+            DirContext->StartIndex = 0;
+            return STATUS_SUCCESS;
+         }
+         case 1: /* entry .. */
+         {
+            DirContext->ShortNameU.Buffer[0] = 0;
+            DirContext->ShortNameU.Length = 0;
+            DirContext->LongNameU.Buffer[0] = DirContext->LongNameU.Buffer[1] = L'.';
+            DirContext->LongNameU.Length = 2 * sizeof(WCHAR);
+            RtlCopyMemory(&DirContext->DirEntry.FatX, &pDirFcb->entry.FatX, sizeof(FATX_DIR_ENTRY));
+            DirContext->DirEntry.FatX.Filename[0] = DirContext->DirEntry.FatX.Filename[1] = '.';
+            DirContext->DirEntry.FatX.FilenameLength = 2;
+            DirContext->StartIndex = 1;
+            return STATUS_SUCCESS;
+         }
+         default:
+            DirIndex -= 2;
+      }
+   }
+
+   if (*pContext == NULL || (DirIndex % FATX_ENTRIES_PER_PAGE) == 0)
+   {
+      if (*pContext != NULL)
+      {
+         CcUnpinData(*pContext);
+      }
+      if (!CcMapData(pDirFcb->FileObject, &FileOffset, PAGE_SIZE, TRUE, pContext, pPage))
+      {
+         *pContext = NULL;
+         return STATUS_NO_MORE_ENTRIES;
+      }
+   }
+
+   fatxDirEntry = (PFATX_DIR_ENTRY)(*pPage) + DirIndex % FATX_ENTRIES_PER_PAGE;
+
+   DirContext->StartIndex = DirIndex;
+
+   while (TRUE)
+   {
+	   if (FATX_ENTRY_END(fatxDirEntry))
+	   {
+	      CcUnpinData(*pContext);
+	      *pContext = NULL;
+	      return STATUS_NO_MORE_ENTRIES;
+	   }
+
+	   if (!FATX_ENTRY_DELETED(fatxDirEntry))
+	   {
+         RtlCopyMemory(&DirContext->DirEntry.FatX, fatxDirEntry, sizeof(FATX_DIR_ENTRY));
+		   break;
+      }
+   	DirContext->DirIndex++;
+   	DirContext->StartIndex++;
+   	if ((DirContext->DirIndex % FATX_ENTRIES_PER_PAGE) == 0)
+      {
+         CcUnpinData(*pContext);
+         FileOffset.u.LowPart += PAGE_SIZE;
+         if (!CcMapData(pDirFcb->FileObject, &FileOffset, PAGE_SIZE, TRUE, pContext, pPage))
+         {
+            CHECKPOINT;
+   		   *pContext = NULL;
+   		   return STATUS_NO_MORE_ENTRIES;
+         }
+         fatxDirEntry = (PFATX_DIR_ENTRY)*pPage;
+      }
+      else
+      {
+         fatxDirEntry++;
+      }
+   }
+   DirContext->ShortNameU.Buffer[0] = 0;
+   DirContext->ShortNameU.Length = 0;
+   StringO.Buffer = fatxDirEntry->Filename;
+   StringO.Length = StringO.MaximumLength = fatxDirEntry->FilenameLength;
+   RtlOemStringToUnicodeString(&DirContext->LongNameU, &StringO, FALSE);
+   return STATUS_SUCCESS;
+}

reactos/drivers/fs/vfat
dirwr.c 1.42 -> 1.43
diff -u -r1.42 -r1.43
--- dirwr.c	6 Nov 2004 13:44:57 -0000	1.42
+++ dirwr.c	5 Dec 2004 16:31:50 -0000	1.43
@@ -1,4 +1,4 @@
-/* $Id: dirwr.c,v 1.42 2004/11/06 13:44:57 ekohl Exp $
+/* $Id: dirwr.c,v 1.43 2004/12/05 16:31:50 gvg Exp $
  *
  * COPYRIGHT:        See COPYING in the top level directory
  * PROJECT:          ReactOS kernel
@@ -26,21 +26,34 @@
  */
 {
   PVOID Context;
-  PFAT_DIR_ENTRY PinEntry;
+  PDIR_ENTRY PinEntry;
   LARGE_INTEGER Offset;
+  ULONG SizeDirEntry;
+  ULONG dirIndex;
 
   ASSERT(pFcb);
   ASSERT(pFcb->parentFcb);
+  
+  if (pFcb->Flags & FCB_IS_FATX_ENTRY)
+  {
+    SizeDirEntry = sizeof(FATX_DIR_ENTRY);
+    dirIndex = pFcb->startIndex;
+  }
+  else
+  {
+    SizeDirEntry = sizeof(FAT_DIR_ENTRY);
+    dirIndex = pFcb->dirIndex;
+  }
 
-  DPRINT ("updEntry PathName \'%wZ\'\n", &pFcb->PathNameU);
+  DPRINT ("updEntry dirIndex %d, PathName \'%wZ\'\n", dirIndex, &pFcb->PathNameU);
 
   Offset.u.HighPart = 0;
-  Offset.u.LowPart = pFcb->dirIndex * sizeof(FATDirEntry);
-  if (CcMapData (pFcb->parentFcb->FileObject, &Offset, sizeof(FATDirEntry),
+  Offset.u.LowPart = dirIndex * SizeDirEntry;
+  if (CcMapData (pFcb->parentFcb->FileObject, &Offset, SizeDirEntry,
       TRUE, &Context, (PVOID*)&PinEntry))
     {
       pFcb->Flags &= ~FCB_IS_DIRTY;
-      *PinEntry = pFcb->entry;
+      RtlCopyMemory(PinEntry, &pFcb->entry, SizeDirEntry);
       CcSetDirtyPinnedData(Context, NULL);
       CcUnpinData(Context);
       return STATUS_SUCCESS;
@@ -64,13 +77,20 @@
  */
   LARGE_INTEGER FileOffset;
   ULONG i, count, size, nbFree = 0;
-  FATDirEntry* pFatEntry;
+  PDIR_ENTRY pFatEntry;
   PVOID Context = NULL;
   NTSTATUS Status;
+  ULONG SizeDirEntry;
   FileOffset.QuadPart = 0;
-  count = pDirFcb->RFCB.FileSize.u.LowPart / sizeof(FATDirEntry);
-  size = DeviceExt->FatInfo.BytesPerCluster / sizeof(FATDirEntry);
-  for (i = 0; i < count; i++, pFatEntry++)
+  
+  if (DeviceExt->Flags & VCB_IS_FATX)
+    SizeDirEntry = sizeof(FATX_DIR_ENTRY);
+  else
+    SizeDirEntry = sizeof(FAT_DIR_ENTRY);
+  
+  count = pDirFcb->RFCB.FileSize.u.LowPart / SizeDirEntry;
+  size = DeviceExt->FatInfo.BytesPerCluster / SizeDirEntry;
+  for (i = 0; i < count; i++, pFatEntry = (PDIR_ENTRY)((ULONG_PTR)pFatEntry + SizeDirEntry))
   {
     if (Context == NULL || (i % size) == 0)
     {
@@ -83,11 +103,11 @@
                  TRUE, &Context, (PVOID*)&pFatEntry);
       FileOffset.u.LowPart += DeviceExt->FatInfo.BytesPerCluster;
     }
-    if (ENTRY_END(pFatEntry))
+    if (ENTRY_END(DeviceExt, pFatEntry))
     {
       break;
     }
-    if (ENTRY_DELETED(pFatEntry))
+    if (ENTRY_DELETED(DeviceExt, pFatEntry))
     {
       nbFree++;
     }
@@ -120,7 +140,7 @@
       // extend the directory
       if (vfatFCBIsRoot(pDirFcb) && DeviceExt->FatInfo.FatType != FAT32)
       {
-        // We can't extend a root directory on a FAT12/FAT16 partition
+        // We can't extend a root directory on a FAT12/FAT16/FATX partition
         return FALSE;
       }
       AllocationSize.QuadPart = pDirFcb->RFCB.FileSize.u.LowPart + DeviceExt->FatInfo.BytesPerCluster;
@@ -135,15 +155,21 @@
                                      DeviceExt->FatInfo.BytesPerCluster);
       CcMapData (pDirFcb->FileObject, &FileOffset, DeviceExt->FatInfo.BytesPerCluster,
                  TRUE, &Context, (PVOID*)&pFatEntry);
-      RtlZeroMemory(pFatEntry, DeviceExt->FatInfo.BytesPerCluster);
+      if (DeviceExt->Flags & VCB_IS_FATX)
+        memset(pFatEntry, 0xff, DeviceExt->FatInfo.BytesPerCluster);
+      else
+        RtlZeroMemory(pFatEntry, DeviceExt->FatInfo.BytesPerCluster);
     }
     else if (*start + nbSlots < count)
     {
       // clear the entry after the last new entry
-      FileOffset.u.LowPart = (*start + nbSlots) * sizeof(FATDirEntry);
-      CcMapData (pDirFcb->FileObject, &FileOffset, sizeof(FATDirEntry),
+      FileOffset.u.LowPart = (*start + nbSlots) * SizeDirEntry;
+      CcMapData (pDirFcb->FileObject, &FileOffset, SizeDirEntry,
                  TRUE, &Context, (PVOID*)&pFatEntry);
-      RtlZeroMemory(pFatEntry, sizeof(FATDirEntry));
+      if (DeviceExt->Flags & VCB_IS_FATX)
+        memset(pFatEntry, 0xff, SizeDirEntry);
+      else
+        RtlZeroMemory(pFatEntry, SizeDirEntry);
     }
     if (Context)
     {
@@ -156,7 +182,7 @@
 }
 
 NTSTATUS
-VfatAddEntry (PDEVICE_EXTENSION DeviceExt,
+FATAddEntry (PDEVICE_EXTENSION DeviceExt,
 	      PUNICODE_STRING PathNameU,
 	      PFILE_OBJECT pFileObject,
 	      ULONG RequestedOptions,
@@ -166,7 +192,7 @@
 */
 {
   PVOID Context = NULL;
-  FATDirEntry *pFatEntry;
+  PFAT_DIR_ENTRY pFatEntry;
   slot *pSlots;
   short nbSlots = 0, j, posCar;
   PUCHAR Buffer;
@@ -180,7 +206,7 @@
   ULONG size;
   long i;
   
-  ANSI_STRING NameA;
+  OEM_STRING NameA;
   CHAR aName[13];
   BOOLEAN IsNameLegal;
   BOOLEAN SpacesFound;
@@ -212,8 +238,8 @@
   
   nbSlots = (DirContext.LongNameU.Length / sizeof(WCHAR) + 12) / 13 + 1;	//nb of entry needed for long name+normal entry
   DPRINT ("NameLen= %d, nbSlots =%d\n", DirContext.LongNameU.Length / sizeof(WCHAR), nbSlots);
-  Buffer = ExAllocatePool (NonPagedPool, (nbSlots - 1) * sizeof (FATDirEntry));
-  RtlZeroMemory (Buffer, (nbSlots - 1) * sizeof (FATDirEntry));
+  Buffer = ExAllocatePool (NonPagedPool, (nbSlots - 1) * sizeof (FAT_DIR_ENTRY));
+  RtlZeroMemory (Buffer, (nbSlots - 1) * sizeof (FAT_DIR_ENTRY));
   pSlots = (slot *) Buffer;
 
   NameA.Buffer = aName;
@@ -224,7 +250,7 @@
   DirContext.ShortNameU.Length = 0;
   DirContext.ShortNameU.MaximumLength = sizeof(ShortNameBuffer);
 
-  memset(&DirContext.FatDirEntry, 0, sizeof(FATDirEntry));
+  RtlZeroMemory(&DirContext.DirEntry.Fat, sizeof(FAT_DIR_ENTRY));
 
   IsNameLegal = RtlIsNameLegalDOS8Dot3(&DirContext.LongNameU, &NameA, &SpacesFound);
 
@@ -235,7 +261,7 @@
       WCHAR ShortSearchName[13];
       needTilde = TRUE;
       needLong = TRUE;
-      memset(&NameContext, 0, sizeof(GENERATE_NAME_CONTEXT));
+      RtlZeroMemory(&NameContext, sizeof(GENERATE_NAME_CONTEXT));
       SearchContext.LongNameU.Buffer = LongNameBuffer;
       SearchContext.LongNameU.MaximumLength = sizeof(LongNameBuffer);
       SearchContext.ShortNameU.Buffer = ShortSearchName;
@@ -257,7 +283,7 @@
           ExReleaseResourceLite(&pDirFcb->MainResource);
           vfatReleaseFCB(DeviceExt, pDirFcb);
           ExFreePool (Buffer);
-	  CHECKPOINT;
+          CHECKPOINT;
           return STATUS_UNSUCCESSFUL;
         }
       IsNameLegal = RtlIsNameLegalDOS8Dot3(&DirContext.ShortNameU, &NameA, &SpacesFound);
@@ -310,27 +336,27 @@
     }
   DPRINT ("'%s', '%wZ', needTilde=%d, needLong=%d\n", 
           aName, &DirContext.LongNameU, needTilde, needLong);
-  memset(DirContext.FatDirEntry.Filename, ' ', 11);
+  memset(DirContext.DirEntry.Fat.Filename, ' ', 11);
   for (i = 0; i < 8 && aName[i] && aName[i] != '.'; i++)
     {
-      DirContext.FatDirEntry.Filename[i] = aName[i];
+      DirContext.DirEntry.Fat.Filename[i] = aName[i];
     }
   if (aName[i] == '.')
     {
       i++;
       for (j = 8; j < 11 && aName[i]; j++, i++)
         {
-          DirContext.FatDirEntry.Filename[j] = aName[i];
+          DirContext.DirEntry.Fat.Filename[j] = aName[i];
         }
     }
-  if (DirContext.FatDirEntry.Filename[0] == 0xe5)
+  if (DirContext.DirEntry.Fat.Filename[0] == 0xe5)
     {
-      DirContext.FatDirEntry.Filename[0] = 0x05;
+      DirContext.DirEntry.Fat.Filename[0] = 0x05;
     }
 
   if (needLong)
     {
-      memcpy(LongNameBuffer, DirContext.LongNameU.Buffer, DirContext.LongNameU.Length);
+      RtlCopyMemory(LongNameBuffer, DirContext.LongNameU.Buffer, DirContext.LongNameU.Length);
       DirContext.LongNameU.Buffer = LongNameBuffer;
       DirContext.LongNameU.MaximumLength = sizeof(LongNameBuffer);
       DirContext.LongNameU.Buffer[DirContext.LongNameU.Length / sizeof(WCHAR)] = 0;
@@ -342,39 +368,29 @@
       nbSlots = 1;
       if (lCaseBase)
         {
-	  DirContext.FatDirEntry.lCase |= VFAT_CASE_LOWER_BASE;
+	  DirContext.DirEntry.Fat.lCase |= VFAT_CASE_LOWER_BASE;
         }
       if (lCaseExt)
         {
-	  DirContext.FatDirEntry.lCase |= VFAT_CASE_LOWER_EXT;
+	  DirContext.DirEntry.Fat.lCase |= VFAT_CASE_LOWER_EXT;
         }
     }
 
-  DPRINT ("dos name=%11.11s\n", DirContext.FatDirEntry.Filename);
+  DPRINT ("dos name=%11.11s\n", DirContext.DirEntry.Fat.Filename);
 
   /* set attributes */
-  DirContext.FatDirEntry.Attrib = ReqAttr;
+  DirContext.DirEntry.Fat.Attrib = ReqAttr;
   if (RequestedOptions & FILE_DIRECTORY_FILE)
     {
-      DirContext.FatDirEntry.Attrib |= FILE_ATTRIBUTE_DIRECTORY;
+      DirContext.DirEntry.Fat.Attrib |= FILE_ATTRIBUTE_DIRECTORY;
     }
   /* set dates and times */
   KeQuerySystemTime (&SystemTime);
-#if 0
-  {
-    TIME_FIELDS tf;
-    RtlTimeToTimeFields (&SystemTime, &tf);
-    DPRINT1("%d.%d.%d %02d:%02d:%02d.%03d '%S'\n", 
-	    tf.Day, tf.Month, tf.Year, tf.Hour, 
-	    tf.Minute, tf.Second, tf.Milliseconds,
-	    pFileObject->FileName.Buffer);
-  }
-#endif
-  FsdSystemTimeToDosDateTime (&SystemTime, &DirContext.FatDirEntry.CreationDate,
-                              &DirContext.FatDirEntry.CreationTime);
-  DirContext.FatDirEntry.UpdateDate = DirContext.FatDirEntry.CreationDate;
-  DirContext.FatDirEntry.UpdateTime = DirContext.FatDirEntry.CreationTime;
-  DirContext.FatDirEntry.AccessDate = DirContext.FatDirEntry.CreationDate;
+  FsdSystemTimeToDosDateTime (DeviceExt, &SystemTime, &DirContext.DirEntry.Fat.CreationDate,
+                              &DirContext.DirEntry.Fat.CreationTime);
+  DirContext.DirEntry.Fat.UpdateDate = DirContext.DirEntry.Fat.CreationDate;
+  DirContext.DirEntry.Fat.UpdateTime = DirContext.DirEntry.Fat.CreationTime;
+  DirContext.DirEntry.Fat.AccessDate = DirContext.DirEntry.Fat.CreationDate;
 
   if (needLong)
     {
@@ -383,7 +399,7 @@
         {
           pSlots[0].alias_checksum = (((pSlots[0].alias_checksum & 1) << 7
                                    | ((pSlots[0].alias_checksum & 0xfe) >> 1))
-                                   + DirContext.FatDirEntry.Filename[i]);
+                                   + DirContext.DirEntry.Fat.Filename[i]);
         }
       /* construct slots and entry */
       for (i = nbSlots - 2; i >= 0; i--)
@@ -399,9 +415,9 @@
               pSlots[i].id = nbSlots - i - 1 + 0x40;
             }
           pSlots[i].alias_checksum = pSlots[0].alias_checksum;
-          memcpy (pSlots[i].name0_4, DirContext.LongNameU.Buffer + (nbSlots - i - 2) * 13, 10);
-          memcpy (pSlots[i].name5_10, DirContext.LongNameU.Buffer + (nbSlots - i - 2) * 13 + 5, 12);
-          memcpy (pSlots[i].name11_12, DirContext.LongNameU.Buffer + (nbSlots - i - 2) * 13 + 11, 4);
+          RtlCopyMemory (pSlots[i].name0_4, DirContext.LongNameU.Buffer + (nbSlots - i - 2) * 13, 10);
+          RtlCopyMemory (pSlots[i].name5_10, DirContext.LongNameU.Buffer + (nbSlots - i - 2) * 13 + 5, 12);
+          RtlCopyMemory (pSlots[i].name11_12, DirContext.LongNameU.Buffer + (nbSlots - i - 2) * 13 + 11, 4);
 	}
     }
   /* try to find nbSlots contiguous entries frees in directory */
@@ -430,47 +446,47 @@
         }
       if (DeviceExt->FatInfo.FatType == FAT32)
         {
-          DirContext.FatDirEntry.FirstClusterHigh = (unsigned short)(CurrentCluster >> 16);
+          DirContext.DirEntry.Fat.FirstClusterHigh = (unsigned short)(CurrentCluster >> 16);
         }
-      DirContext.FatDirEntry.FirstCluster = (unsigned short)CurrentCluster;
+      DirContext.DirEntry.Fat.FirstCluster = (unsigned short)CurrentCluster;
     }
 
-  i = DeviceExt->FatInfo.BytesPerCluster / sizeof(FATDirEntry);
+  i = DeviceExt->FatInfo.BytesPerCluster / sizeof(FAT_DIR_ENTRY);
   FileOffset.u.HighPart = 0;
-  FileOffset.u.LowPart = DirContext.StartIndex * sizeof(FATDirEntry);
+  FileOffset.u.LowPart = DirContext.StartIndex * sizeof(FAT_DIR_ENTRY);
   if (DirContext.StartIndex / i == DirContext.DirIndex / i)
     {
       /* one cluster */
       CHECKPOINT;
-      CcMapData (pDirFcb->FileObject, &FileOffset, nbSlots * sizeof(FATDirEntry),
+      CcMapData (pDirFcb->FileObject, &FileOffset, nbSlots * sizeof(FAT_DIR_ENTRY),
                  TRUE, &Context, (PVOID*)&pFatEntry);
       if (nbSlots > 1)
         {
-          memcpy(pFatEntry, Buffer, (nbSlots - 1) * sizeof(FATDirEntry));
+          RtlCopyMemory(pFatEntry, Buffer, (nbSlots - 1) * sizeof(FAT_DIR_ENTRY));
         }
-      memcpy(pFatEntry + (nbSlots - 1), &DirContext.FatDirEntry, sizeof(FATDirEntry));
+      RtlCopyMemory(pFatEntry + (nbSlots - 1), &DirContext.DirEntry.Fat, sizeof(FAT_DIR_ENTRY));
     }
   else
     {
       /* two clusters */
       CHECKPOINT;
       size = DeviceExt->FatInfo.BytesPerCluster -
-             (DirContext.StartIndex * sizeof(FATDirEntry)) % DeviceExt->FatInfo.BytesPerCluster;
-      i = size / sizeof(FATDirEntry);
+             (DirContext.StartIndex * sizeof(FAT_DIR_ENTRY)) % DeviceExt->FatInfo.BytesPerCluster;
+      i = size / sizeof(FAT_DIR_ENTRY);
       CcMapData (pDirFcb->FileObject, &FileOffset, size, TRUE,
                  &Context, (PVOID*)&pFatEntry);
-      memcpy(pFatEntry, Buffer, size);
+      RtlCopyMemory(pFatEntry, Buffer, size);
       CcSetDirtyPinnedData(Context, NULL);
       CcUnpinData(Context);
       FileOffset.u.LowPart += size;
       CcMapData (pDirFcb->FileObject, &FileOffset,
-                 nbSlots * sizeof(FATDirEntry) - size,
+                 nbSlots * sizeof(FAT_DIR_ENTRY) - size,
                  TRUE, &Context, (PVOID*)&pFatEntry);
       if (nbSlots - 1 > i)
         {
-          memcpy(pFatEntry, (PVOID)(Buffer + size), (nbSlots - 1 - i) * sizeof(FATDirEntry));
+          RtlCopyMemory(pFatEntry, (PVOID)(Buffer + size), (nbSlots - 1 - i) * sizeof(FAT_DIR_ENTRY));
         }
-      memcpy(pFatEntry + nbSlots - 1 - i, &DirContext.FatDirEntry, sizeof(FATDirEntry));
+      RtlCopyMemory(pFatEntry + nbSlots - 1 - i, &DirContext.DirEntry.Fat, sizeof(FAT_DIR_ENTRY));
     }
   CcSetDirtyPinnedData(Context, NULL);
   CcUnpinData(Context);
@@ -479,8 +495,8 @@
   vfatMakeFCBFromDirEntry (DeviceExt, pDirFcb, &DirContext, &newFCB);
   vfatAttachFCBToFileObject (DeviceExt, newFCB, pFileObject);
 
-  DPRINT ("new : entry=%11.11s\n", newFCB->entry.Filename);
-  DPRINT ("new : entry=%11.11s\n", DirContext.FatDirEntry.Filename);
+  DPRINT ("new : entry=%11.11s\n", newFCB->entry.Fat.Filename);
+  DPRINT ("new : entry=%11.11s\n", DirContext.DirEntry.Fat.Filename);
 
   if (RequestedOptions & FILE_DIRECTORY_FILE)
     {
@@ -490,12 +506,12 @@
       /* clear the new directory cluster */
       RtlZeroMemory (pFatEntry, DeviceExt->FatInfo.BytesPerCluster);
       /* create '.' and '..' */
-      memcpy (&pFatEntry[0].Attrib, &DirContext.FatDirEntry.Attrib, sizeof(FATDirEntry) - 11);
-      memcpy (pFatEntry[0].Filename, ".          ", 11);
-      memcpy (&pFatEntry[1].Attrib, &DirContext.FatDirEntry.Attrib, sizeof(FATDirEntry) - 11);
-      memcpy (pFatEntry[1].Filename, "..         ", 11);
-      pFatEntry[1].FirstCluster = pDirFcb->entry.FirstCluster;
-      pFatEntry[1].FirstClusterHigh = pDirFcb->entry.FirstClusterHigh;
+      RtlCopyMemory (&pFatEntry[0].Attrib, &DirContext.DirEntry.Fat.Attrib, sizeof(FAT_DIR_ENTRY) - 11);
+      RtlCopyMemory (pFatEntry[0].Filename, ".          ", 11);
+      RtlCopyMemory (&pFatEntry[1].Attrib, &DirContext.DirEntry.Fat.Attrib, sizeof(FAT_DIR_ENTRY) - 11);
+      RtlCopyMemory (pFatEntry[1].Filename, "..         ", 11);
+      pFatEntry[1].FirstCluster = pDirFcb->entry.Fat.FirstCluster;
+      pFatEntry[1].FirstClusterHigh = pDirFcb->entry.Fat.FirstClusterHigh;
       if (vfatFCBIsRoot(pDirFcb))
         {
           pFatEntry[1].FirstCluster = 0;
@@ -512,7 +528,129 @@
 }
 
 NTSTATUS
-VfatDelEntry (PDEVICE_EXTENSION DeviceExt, PVFATFCB pFcb)
+FATXAddEntry (PDEVICE_EXTENSION DeviceExt,
+	      PUNICODE_STRING PathNameU,
+	      PFILE_OBJECT pFileObject,
+	      ULONG RequestedOptions,
+	      UCHAR ReqAttr)
+/*
+  create a new FAT entry
+*/
+{
+   PVOID Context = NULL;
+   PVFATFCB newFCB;
+   LARGE_INTEGER SystemTime, FileOffset;
+   PVFATFCB pDirFcb;
+   OEM_STRING NameA;
+   VFAT_DIRENTRY_CONTEXT DirContext;
+   PFATX_DIR_ENTRY pFatXDirEntry;
+   UNICODE_STRING DirNameU;
+   
+   DPRINT ("addEntry: Pathname='%wZ'\n", PathNameU);
+   
+   vfatSplitPathName(PathNameU, &DirNameU, &DirContext.LongNameU);
+   if (DirNameU.Length > sizeof(WCHAR))
+   {
+      DirNameU.Length -= sizeof(WCHAR);
+   }
+   
+   if (DirContext.LongNameU.Length / sizeof(WCHAR) > 42)
+   {
+      /* name too long */
+      CHECKPOINT;
+      return STATUS_NAME_TOO_LONG;
+   }
+   
+   pDirFcb = vfatGrabFCBFromTable(DeviceExt, &DirNameU);
+   if (pDirFcb == NULL)
+   {
+      return STATUS_UNSUCCESSFUL;
+   }
+   
+   if (!ExAcquireResourceExclusiveLite(&pDirFcb->MainResource, TRUE))
+   {
+      DPRINT("Failed acquiring lock\n");
+      return STATUS_UNSUCCESSFUL;
+   }
+   
+   /* try to find 1 entry free in directory */
+   if (!vfatFindDirSpace(DeviceExt, pDirFcb, 1, &DirContext.StartIndex))
+   {
+      ExReleaseResourceLite(&pDirFcb->MainResource);
+      vfatReleaseFCB(DeviceExt, pDirFcb);
+      return STATUS_DISK_FULL;
+   }
+   DirContext.DirIndex = DirContext.StartIndex;
+   if (!vfatFCBIsRoot(pDirFcb))
+   {
+      DirContext.DirIndex += 2;
+   }
+  
+   DirContext.ShortNameU.Buffer = 0;
+   DirContext.ShortNameU.Length = 0;
+   DirContext.ShortNameU.MaximumLength = 0;
+   RtlZeroMemory(&DirContext.DirEntry.FatX, sizeof(FATX_DIR_ENTRY));
+   memset(DirContext.DirEntry.FatX.Filename, 0xff, 42);
+   DirContext.DirEntry.FatX.FirstCluster = 0;
+   DirContext.DirEntry.FatX.FileSize = 0;
+   
+   /* set file name */
+   NameA.Buffer = DirContext.DirEntry.FatX.Filename;
+   NameA.Length = 0;
+   NameA.MaximumLength = 42;
+   RtlUnicodeStringToOemString(&NameA, &DirContext.LongNameU, FALSE);
+   DirContext.DirEntry.FatX.FilenameLength = NameA.Length;
+   
+   /* set attributes */
+   DirContext.DirEntry.FatX.Attrib = ReqAttr;
+   if (RequestedOptions & FILE_DIRECTORY_FILE)
+   {
+      DirContext.DirEntry.FatX.Attrib |= FILE_ATTRIBUTE_DIRECTORY;
+   }
+   
+   /* set dates and times */
+   KeQuerySystemTime (&SystemTime);
+   FsdSystemTimeToDosDateTime(DeviceExt, &SystemTime, &DirContext.DirEntry.FatX.CreationDate,
+                              &DirContext.DirEntry.FatX.CreationTime);
+   DirContext.DirEntry.FatX.UpdateDate = DirContext.DirEntry.FatX.CreationDate;
+   DirContext.DirEntry.FatX.UpdateTime = DirContext.DirEntry.FatX.CreationTime;
+   DirContext.DirEntry.FatX.AccessDate = DirContext.DirEntry.FatX.CreationDate;
+   DirContext.DirEntry.FatX.AccessTime = DirContext.DirEntry.FatX.CreationTime;
+   
+   /* add entry into parent directory */
+   FileOffset.u.HighPart = 0;
+   FileOffset.u.LowPart = DirContext.StartIndex * sizeof(FATX_DIR_ENTRY);
+   CcMapData(pDirFcb->FileObject, &FileOffset, sizeof(FATX_DIR_ENTRY),
+                 TRUE, &Context, (PVOID*)&pFatXDirEntry);
+   RtlCopyMemory(pFatXDirEntry, &DirContext.DirEntry.FatX, sizeof(FATX_DIR_ENTRY));
+   CcSetDirtyPinnedData(Context, NULL);
+   CcUnpinData(Context);
+   
+   /* FIXME: check status */
+   vfatMakeFCBFromDirEntry(DeviceExt, pDirFcb, &DirContext, &newFCB);
+   vfatAttachFCBToFileObject(DeviceExt, newFCB, pFileObject);
+   
+   ExReleaseResourceLite(&pDirFcb->MainResource);
+   vfatReleaseFCB(DeviceExt, pDirFcb);
+   DPRINT("addentry ok\n");
+   return STATUS_SUCCESS;
+}
+
+NTSTATUS
+VfatAddEntry (PDEVICE_EXTENSION DeviceExt,
+	      PUNICODE_STRING PathNameU,
+	      PFILE_OBJECT pFileObject,
+	      ULONG RequestedOptions,
+	      UCHAR ReqAttr)
+{
+   if (DeviceExt->Flags & VCB_IS_FATX)
+      return FATXAddEntry(DeviceExt, PathNameU, pFileObject, RequestedOptions, ReqAttr);
+   else
+      return FATAddEntry(DeviceExt, PathNameU, pFileObject, RequestedOptions, ReqAttr);
+}
+
+NTSTATUS
+FATDelEntry (PDEVICE_EXTENSION DeviceExt, PVFATFCB pFcb)
 /*
  * deleting an existing FAT entry
  */
@@ -520,7 +658,7 @@
   ULONG CurrentCluster = 0, NextCluster, i;
   PVOID Context = NULL;
   LARGE_INTEGER Offset;
-  FATDirEntry* pDirEntry;
+  PFAT_DIR_ENTRY pDirEntry;
 
   ASSERT(pFcb);
   ASSERT(pFcb->parentFcb);
@@ -530,23 +668,23 @@
   Offset.u.HighPart = 0;
   for (i = pFcb->startIndex; i <= pFcb->dirIndex; i++)
     {
-      if (Context == NULL || ((i * sizeof(FATDirEntry)) % PAGE_SIZE) == 0)
+      if (Context == NULL || ((i * sizeof(FAT_DIR_ENTRY)) % PAGE_SIZE) == 0)
         {
           if (Context)
           {
             CcSetDirtyPinnedData(Context, NULL);
             CcUnpinData(Context);
           }
-          Offset.u.LowPart = (i * sizeof(FATDirEntry) / PAGE_SIZE) * PAGE_SIZE;
+          Offset.u.LowPart = (i * sizeof(FAT_DIR_ENTRY) / PAGE_SIZE) * PAGE_SIZE;
           CcMapData (pFcb->parentFcb->FileObject, &Offset, PAGE_SIZE, TRUE,
                      &Context, (PVOID*)&pDirEntry);
         }
-      pDirEntry[i % (PAGE_SIZE / sizeof(FATDirEntry))].Filename[0] = 0xe5;
+      pDirEntry[i % (PAGE_SIZE / sizeof(FAT_DIR_ENTRY))].Filename[0] = 0xe5;
       if (i == pFcb->dirIndex)
         {
           CurrentCluster =
           vfatDirEntryGetFirstCluster (DeviceExt,
-            &pDirEntry[i % (PAGE_SIZE / sizeof(FATDirEntry))]);
+            (PDIR_ENTRY)&pDirEntry[i % (PAGE_SIZE / sizeof(FAT_DIR_ENTRY))]);
         }
     }
   if (Context)
@@ -565,4 +703,58 @@
   return STATUS_SUCCESS;
 }
 
+NTSTATUS
+FATXDelEntry (PDEVICE_EXTENSION DeviceExt, PVFATFCB pFcb)
+/*
+ * deleting an existing FAT entry
+ */
+{
+  ULONG CurrentCluster = 0, NextCluster;
+  PVOID Context = NULL;
+  LARGE_INTEGER Offset;
+  PFATX_DIR_ENTRY pDirEntry;
+  ULONG StartIndex; 
+
+  ASSERT(pFcb);
+  ASSERT(pFcb->parentFcb);
+  ASSERT(pFcb->Flags & FCB_IS_FATX_ENTRY);
+  
+  StartIndex = pFcb->startIndex;
+
+  DPRINT ("delEntry PathName \'%wZ\'\n", &pFcb->PathNameU);
+  DPRINT ("delete entry: %d\n", StartIndex);
+  Offset.u.HighPart = 0;
+  Offset.u.LowPart = (StartIndex * sizeof(FATX_DIR_ENTRY) / PAGE_SIZE) * PAGE_SIZE;
+  if (!CcMapData (pFcb->parentFcb->FileObject, &Offset, PAGE_SIZE, TRUE,
+                     &Context, (PVOID*)&pDirEntry))
+  {
+    DPRINT1("CcMapData(Offset %x:%x, Length %d) failed\n", Offset.u.HighPart, Offset.u.LowPart, PAGE_SIZE);
+    return STATUS_UNSUCCESSFUL;
+  }
+  pDirEntry = &pDirEntry[StartIndex % (PAGE_SIZE / sizeof(FATX_DIR_ENTRY))];
+  pDirEntry->FilenameLength = 0xe5;
+  CurrentCluster = vfatDirEntryGetFirstCluster (DeviceExt,
+            (PDIR_ENTRY)pDirEntry);
+  CcSetDirtyPinnedData(Context, NULL);
+  CcUnpinData(Context);
+  
+  while (CurrentCluster && CurrentCluster != 0xffffffff)
+    {
+      GetNextCluster (DeviceExt, CurrentCluster, &NextCluster);
+      /* FIXME: check status */
+      WriteCluster(DeviceExt, CurrentCluster, 0);
+      CurrentCluster = NextCluster;
+    }
+  return STATUS_SUCCESS;
+}
+
+NTSTATUS
+VfatDelEntry (PDEVICE_EXTENSION DeviceExt, PVFATFCB pFcb)
+{
+   if (DeviceExt->Flags & VCB_IS_FATX)
+      return FATXDelEntry(DeviceExt, pFcb);
+   else
+      return FATDelEntry(DeviceExt, pFcb);
+}
+
 /* EOF */

reactos/drivers/fs/vfat
fat.c 1.46 -> 1.47
diff -u -r1.46 -r1.47
--- fat.c	5 Aug 2004 02:48:18 -0000	1.46
+++ fat.c	5 Dec 2004 16:31:50 -0000	1.47
@@ -1,5 +1,5 @@
 /*
- * $Id: fat.c,v 1.46 2004/08/05 02:48:18 navaraf Exp $
+ * $Id: fat.c,v 1.47 2004/12/05 16:31:50 gvg Exp $
  *
  * COPYRIGHT:        See COPYING in the top level directory
  * PROJECT:          ReactOS kernel
@@ -459,7 +459,7 @@
   {
 	if (DeviceExt->FatInfo.FatType == FAT12)
 	  Status = FAT12CountAvailableClusters(DeviceExt);
-	else if (DeviceExt->FatInfo.FatType == FAT16)
+	else if (DeviceExt->FatInfo.FatType == FAT16 || DeviceExt->FatInfo.FatType == FATX16)
 	  Status = FAT16CountAvailableClusters(DeviceExt);
 	else
 	  Status = FAT32CountAvailableClusters(DeviceExt);
@@ -641,7 +641,7 @@
 	  DeviceExt, CurrentCluster);
 
   if (CurrentCluster == 0)
-     return(STATUS_UNSUCCESSFUL);
+     return(STATUS_INVALID_PARAMETER);
 
   ExAcquireResourceSharedLite(&DeviceExt->FatResource, TRUE);
   Status = DeviceExt->GetNextCluster(DeviceExt, CurrentCluster, NextCluster);

reactos/drivers/fs/vfat
fcb.c 1.42 -> 1.43
diff -u -r1.42 -r1.43
--- fcb.c	6 Nov 2004 13:44:57 -0000	1.42
+++ fcb.c	5 Dec 2004 16:31:51 -0000	1.43
@@ -1,4 +1,4 @@
-/* $Id: fcb.c,v 1.42 2004/11/06 13:44:57 ekohl Exp $
+/* $Id: fcb.c,v 1.43 2004/12/05 16:31:51 gvg Exp $
  *
  *
  * FILE:             drivers/fs/vfat/fcb.c
@@ -8,6 +8,7 @@
  * PROGRAMMER:       Jason Filby (jasonfilby@yahoo.com)
  *                   Rex Jolliff (rex@lvcablemodem.com)
  *                   Hartmut Birr
+ *                   Herve Poussineau (reactos@poussine.freesurf.fr)
  */
 
 /*  -------------------------------------------------------  INCLUDES  */
@@ -38,6 +39,7 @@
   PWCHAR curr;
   register WCHAR c;
 
+  ASSERT(NameU->Buffer[0] != L'.');
   curr = NameU->Buffer;
   last = NameU->Buffer + NameU->Length / sizeof(WCHAR);
 
@@ -93,7 +95,7 @@
 }  
 
 PVFATFCB
-vfatNewFCB(PUNICODE_STRING pFileNameU)
+vfatNewFCB(PDEVICE_EXTENSION  pVCB, PUNICODE_STRING pFileNameU)
 {
   PVFATFCB  rcFCB;
 
@@ -104,8 +106,15 @@
     {
       return NULL;
     }
-  memset(rcFCB, 0, sizeof(VFATFCB));
+  RtlZeroMemory(rcFCB, sizeof(VFATFCB));
   vfatInitFcb(rcFCB, pFileNameU);
+  if (pVCB->Flags & VCB_IS_FATX)
+  {
+    rcFCB->Flags |= FCB_IS_FATX_ENTRY;
+    rcFCB->Attributes = &rcFCB->entry.FatX.Attrib;
+  }
+  else
+    rcFCB->Attributes = &rcFCB->entry.Fat.Attrib;
   rcFCB->Hash.Hash = vfatNameHash(0, &rcFCB->PathNameU);
   rcFCB->Hash.self = rcFCB;
   rcFCB->ShortHash.self = rcFCB;
@@ -138,7 +147,7 @@
 BOOL
 vfatFCBIsDirectory(PVFATFCB FCB)
 {
-  return  FCB->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY;
+  return  *FCB->Attributes & FILE_ATTRIBUTE_DIRECTORY;
 }
 
 BOOL
@@ -312,7 +321,7 @@
   {
     return  STATUS_INSUFFICIENT_RESOURCES;
   }
-  memset (newCCB, 0, sizeof (VFATCCB));
+  RtlZeroMemory(newCCB, sizeof (VFATCCB));
 
   fileObject->Flags |= FO_FCB_IS_VALID | FO_DIRECT_CACHE_PAGING_READ;
   fileObject->SectionObjectPointer = &fcb->SectionObjectPointers;
@@ -347,28 +356,39 @@
 
   RtlRosInitUnicodeStringFromLiteral(&NameU, L"\\");
 
-  FCB = vfatNewFCB(&NameU);
-  memset(FCB->entry.Filename, ' ', 11);
-  FCB->ShortHash.Hash = FCB->Hash.Hash;
-  FCB->entry.FileSize = pVCB->FatInfo.rootDirectorySectors * pVCB->FatInfo.BytesPerSector;
-  FCB->entry.Attrib = FILE_ATTRIBUTE_DIRECTORY;
-  if (pVCB->FatInfo.FatType == FAT32)
-  {
-    CurrentCluster = FirstCluster = pVCB->FatInfo.RootCluster;
-    FCB->entry.FirstCluster = (unsigned short)(FirstCluster & 0xffff);
-    FCB->entry.FirstClusterHigh = (unsigned short)(FirstCluster >> 16);
-
-    while (CurrentCluster != 0xffffffff && NT_SUCCESS(Status))
-    {
-      Size += pVCB->FatInfo.BytesPerCluster;
-      Status = NextCluster (pVCB, FirstCluster, &CurrentCluster, FALSE);
-    }
+  FCB = vfatNewFCB(pVCB, &NameU);
+  if (FCB->Flags & FCB_IS_FATX_ENTRY)
+  {
+    memset(FCB->entry.FatX.Filename, ' ', 42);
+    FCB->entry.FatX.FileSize = pVCB->FatInfo.rootDirectorySectors * pVCB->FatInfo.BytesPerSector;
+    FCB->entry.FatX.Attrib = FILE_ATTRIBUTE_DIRECTORY;
+    FCB->entry.FatX.FirstCluster = 1;
+    Size = pVCB->FatInfo.rootDirectorySectors * pVCB->FatInfo.BytesPerSector;
   }
   else
   {
-    FCB->entry.FirstCluster = 1;
-    Size = pVCB->FatInfo.rootDirectorySectors * pVCB->FatInfo.BytesPerSector;
+    memset(FCB->entry.Fat.Filename, ' ', 11);
+    FCB->entry.Fat.FileSize = pVCB->FatInfo.rootDirectorySectors * pVCB->FatInfo.BytesPerSector;
+    FCB->entry.Fat.Attrib = FILE_ATTRIBUTE_DIRECTORY;
+    if (pVCB->FatInfo.FatType == FAT32)
+    {
+      CurrentCluster = FirstCluster = pVCB->FatInfo.RootCluster;
+      FCB->entry.Fat.FirstCluster = (unsigned short)(FirstCluster & 0xffff);
+      FCB->entry.Fat.FirstClusterHigh = (unsigned short)(FirstCluster >> 16);
+
+      while (CurrentCluster != 0xffffffff && NT_SUCCESS(Status))
+      {
+        Size += pVCB->FatInfo.BytesPerCluster;
+        Status = NextCluster (pVCB, FirstCluster, &CurrentCluster, FALSE);
+      }
+    }
+    else
+    {
+      FCB->entry.Fat.FirstCluster = 1;
+      Size = pVCB->FatInfo.rootDirectorySectors * pVCB->FatInfo.BytesPerSector;
+    }
   }
+  FCB->ShortHash.Hash = FCB->Hash.Hash;
   FCB->RefCount = 2;
   FCB->dirIndex = 0;
   FCB->RFCB.FileSize.QuadPart = Size;
@@ -435,10 +455,18 @@
     RtlAppendUnicodeStringToString(&NameU, &DirContext->ShortNameU);
   }
   NameU.Buffer[NameU.Length / sizeof(WCHAR)] = 0;
-  rcFCB = vfatNewFCB (&NameU);
-  memcpy (&rcFCB->entry, &DirContext->FatDirEntry, sizeof (FAT_DIR_ENTRY));
+  
+  rcFCB = vfatNewFCB (vcb, &NameU);
+  RtlCopyMemory (&rcFCB->entry, &DirContext->DirEntry, sizeof (DIR_ENTRY));
   RtlCopyUnicodeString(&rcFCB->ShortNameU, &DirContext->ShortNameU);
-  rcFCB->ShortHash.Hash = vfatNameHash(hash, &rcFCB->ShortNameU);
+  if (vcb->Flags & VCB_IS_FATX)
+  {
+    rcFCB->ShortHash.Hash = rcFCB->Hash.Hash;
+  }
+  else
+  {
+    rcFCB->ShortHash.Hash = vfatNameHash(hash, &rcFCB->ShortNameU);
+  }
 
   if (vfatFCBIsDirectory(rcFCB))
   {
@@ -450,7 +478,7 @@
     {
       Size = vcb->FatInfo.rootDirectorySectors * vcb->FatInfo.BytesPerSector;
     }
-    else
+    else if (FirstCluster != 0)
     {
       CurrentCluster = FirstCluster;
       while (CurrentCluster != 0xffffffff)
@@ -460,9 +488,13 @@
       }
     }
   }
+  else if (rcFCB->Flags & FCB_IS_FATX_ENTRY)
+  {
+    Size = rcFCB->entry.FatX.FileSize;
+  }
   else
   {
-    Size = rcFCB->entry.FileSize;
+    Size = rcFCB->entry.Fat.FileSize;
   }
   rcFCB->dirIndex = DirContext->DirIndex;
   rcFCB->startIndex = DirContext->StartIndex;
@@ -494,7 +526,7 @@
     CHECKPOINT;
     return  STATUS_INSUFFICIENT_RESOURCES;
   }
-  memset (newCCB, 0, sizeof (VFATCCB));
+  RtlZeroMemory (newCCB, sizeof (VFATCCB));
 
   fileObject->Flags = fileObject->Flags | FO_FCB_IS_VALID |
       FO_DIRECT_CACHE_PAGING_READ;
@@ -542,7 +574,7 @@
 
   while (TRUE)
     {
-      status = vfatGetNextDirEntry(&Context,
+      status = pDeviceExt->GetNextDirEntry(&Context,
 	                           &Page, 
 	                           pDirectoryFCB,
 				   &DirContext,
@@ -562,7 +594,7 @@
               &DirContext.LongNameU);
       DirContext.LongNameU.Buffer[DirContext.LongNameU.Length / sizeof(WCHAR)] = 0;
       DirContext.ShortNameU.Buffer[DirContext.ShortNameU.Length / sizeof(WCHAR)] = 0;
-      if (!ENTRY_VOLUME(&DirContext.FatDirEntry))
+      if (!ENTRY_VOLUME(pDeviceExt, &DirContext.DirEntry))
         {
 	  FoundLong = RtlEqualUnicodeString(FileToFindU, &DirContext.LongNameU, TRUE);
 	  if (FoundLong == FALSE)
@@ -646,7 +678,7 @@
 	      curr = pFileNameU->Buffer + FCB->PathNameU.Length / sizeof(WCHAR);
               last = pFileNameU->Buffer + pFileNameU->Length / sizeof(WCHAR) - 1;
 	    }
-	  memcpy(pFileNameU->Buffer, FCB->PathNameU.Buffer, FCB->PathNameU.Length);
+	  RtlCopyMemory(pFileNameU->Buffer, FCB->PathNameU.Buffer, FCB->PathNameU.Length);
 	}
     }
   else
@@ -699,7 +731,7 @@
 	      curr = prev + parentFCB->LongNameU.Length / sizeof(WCHAR);
               last = pFileNameU->Buffer + pFileNameU->Length / sizeof(WCHAR) - 1;
 	    }
-	  memcpy(prev, parentFCB->LongNameU.Buffer, parentFCB->LongNameU.Length);
+	  RtlCopyMemory(prev, parentFCB->LongNameU.Buffer, parentFCB->LongNameU.Length);
 	}
       curr++;      
       prev = curr;

reactos/drivers/fs/vfat
finfo.c 1.38 -> 1.39
diff -u -r1.38 -r1.39
--- finfo.c	6 Nov 2004 13:44:57 -0000	1.38
+++ finfo.c	5 Dec 2004 16:31:51 -0000	1.39
@@ -1,4 +1,4 @@
-/* $Id: finfo.c,v 1.38 2004/11/06 13:44:57 ekohl Exp $
+/* $Id: finfo.c,v 1.39 2004/12/05 16:31:51 gvg Exp $
  *
  * COPYRIGHT:        See COPYING in the top level directory
  * PROJECT:          ReactOS kernel
@@ -6,6 +6,7 @@
  * PURPOSE:          VFAT Filesystem
  * PROGRAMMER:       Jason Filby (jasonfilby@yahoo.com)
  *                   Hartmut Birr
+ *                   Herve Poussineau (reactos@poussine.freesurf.fr)
  *
  */
 
@@ -106,26 +107,47 @@
   ASSERT(NULL != DeviceExt);
   ASSERT(NULL != BasicInfo);
   /* Check volume label bit */
-  ASSERT(0 == (FCB->entry.Attrib & 0x08));
+  ASSERT(0 == (*FCB->Attributes & 0x08));
 
-  FsdSystemTimeToDosDateTime(&BasicInfo->CreationTime,
-                             &FCB->entry.CreationDate,
-                             &FCB->entry.CreationTime);
-  FsdSystemTimeToDosDateTime(&BasicInfo->LastAccessTime,
-                             &FCB->entry.AccessDate,
+  if (FCB->Flags & FCB_IS_FATX_ENTRY)
+  {
+    FsdSystemTimeToDosDateTime(DeviceExt,
+                             &BasicInfo->CreationTime,
+                             &FCB->entry.FatX.CreationDate,
+                             &FCB->entry.FatX.CreationTime);
+    FsdSystemTimeToDosDateTime(DeviceExt,
+                             &BasicInfo->LastAccessTime,
+                             &FCB->entry.FatX.AccessDate,
+                             &FCB->entry.FatX.AccessTime);
+    FsdSystemTimeToDosDateTime(DeviceExt,
+                             &BasicInfo->LastWriteTime,
+                             &FCB->entry.FatX.UpdateDate,
+                             &FCB->entry.FatX.UpdateTime);
+  }
+  else
+  {
+    FsdSystemTimeToDosDateTime(DeviceExt,
+                             &BasicInfo->CreationTime,
+                             &FCB->entry.Fat.CreationDate,
+                             &FCB->entry.Fat.CreationTime);
+    FsdSystemTimeToDosDateTime(DeviceExt,
+                             &BasicInfo->LastAccessTime,
+                             &FCB->entry.Fat.AccessDate,
                              NULL);
-  FsdSystemTimeToDosDateTime(&BasicInfo->LastWriteTime,
-                             &FCB->entry.UpdateDate,
-                             &FCB->entry.UpdateTime);
+    FsdSystemTimeToDosDateTime(DeviceExt,
+                             &BasicInfo->LastWriteTime,
+                             &FCB->entry.Fat.UpdateDate,
+                             &FCB->entry.Fat.UpdateTime);
+  }
 
-  FCB->entry.Attrib = (unsigned char)((FCB->entry.Attrib &
+  *FCB->Attributes = (unsigned char)((*FCB->Attributes &
                        (FILE_ATTRIBUTE_DIRECTORY | 0x48)) |
                       (BasicInfo->FileAttributes &
                        (FILE_ATTRIBUTE_ARCHIVE |
                         FILE_ATTRIBUTE_SYSTEM |
                         FILE_ATTRIBUTE_HIDDEN |
                         FILE_ATTRIBUTE_READONLY)));
-  DPRINT("Setting attributes 0x%02x\n", FCB->entry.Attrib);
+  DPRINT("Setting attributes 0x%02x\n", *FCB->Attributes);
 
   VfatUpdateEntry(FCB);
 
@@ -139,23 +161,48 @@
 			PFILE_BASIC_INFORMATION BasicInfo,
 			PULONG BufferLength)
 {
+  PDEVICE_EXTENSION DeviceExt;
   DPRINT("VfatGetBasicInformation()\n");
+  
+  DeviceExt = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
 
   if (*BufferLength < sizeof(FILE_BASIC_INFORMATION))
     return STATUS_BUFFER_OVERFLOW;
 
-  FsdDosDateTimeToSystemTime(FCB->entry.CreationDate,
-			     FCB->entry.CreationTime,
+  if (FCB->Flags & FCB_IS_FATX_ENTRY)
+  {
+    FsdDosDateTimeToSystemTime(DeviceExt,
+			     FCB->entry.FatX.CreationDate,
+			     FCB->entry.FatX.CreationTime,
 			     &BasicInfo->CreationTime);
-  FsdDosDateTimeToSystemTime(FCB->entry.AccessDate,
+    FsdDosDateTimeToSystemTime(DeviceExt,
+			     FCB->entry.FatX.AccessDate,
+			     FCB->entry.FatX.AccessTime,
+			     &BasicInfo->LastAccessTime);
+    FsdDosDateTimeToSystemTime(DeviceExt,
+			     FCB->entry.FatX.UpdateDate,
+			     FCB->entry.FatX.UpdateTime,
+			     &BasicInfo->LastWriteTime);
+    BasicInfo->ChangeTime = BasicInfo->LastWriteTime;
+  }
+  else
+  {
+    FsdDosDateTimeToSystemTime(DeviceExt,
+			     FCB->entry.Fat.CreationDate,
+			     FCB->entry.Fat.CreationTime,
+			     &BasicInfo->CreationTime);
+    FsdDosDateTimeToSystemTime(DeviceExt,
+			     FCB->entry.Fat.AccessDate,
 			     0,
 			     &BasicInfo->LastAccessTime);
-  FsdDosDateTimeToSystemTime(FCB->entry.UpdateDate,
-			     FCB->entry.UpdateTime,
+    FsdDosDateTimeToSystemTime(DeviceExt,
+			     FCB->entry.Fat.UpdateDate,
+			     FCB->entry.Fat.UpdateTime,
 			     &BasicInfo->LastWriteTime);
-  BasicInfo->ChangeTime = BasicInfo->LastWriteTime;
+    BasicInfo->ChangeTime = BasicInfo->LastWriteTime;
+  }
 
-  BasicInfo->FileAttributes = FCB->entry.Attrib & 0x3f;
+  BasicInfo->FileAttributes = *FCB->Attributes & 0x3f;
   /* Synthesize FILE_ATTRIBUTE_NORMAL */
   if (0 == (BasicInfo->FileAttributes & (FILE_ATTRIBUTE_DIRECTORY |
                                          FILE_ATTRIBUTE_ARCHIVE |
@@ -188,7 +235,7 @@
   ASSERT(DeviceExt->FatInfo.BytesPerCluster != 0);
   ASSERT(FCB != NULL);
 
-  if (FCB->entry.Attrib & FILE_ATTRIBUTE_READONLY) 
+  if (*FCB->Attributes & FILE_ATTRIBUTE_READONLY) 
     {
       return STATUS_CANNOT_DELETE;
     }
@@ -259,7 +306,7 @@
     return STATUS_BUFFER_OVERFLOW;
 
   NameInfo->FileNameLength = FCB->PathNameU.Length;
-  memcpy(NameInfo->FileName, FCB->PathNameU.Buffer, FCB->PathNameU.Length);
+  RtlCopyMemory(NameInfo->FileName, FCB->PathNameU.Buffer, FCB->PathNameU.Length);
   NameInfo->FileName[FCB->PathNameU.Length / sizeof(WCHAR)] = 0;
 
   *BufferLength -= (sizeof(FILE_NAME_INFORMATION) + FCB->PathNameU.Length + sizeof(WCHAR));
@@ -286,6 +333,7 @@
 
 static NTSTATUS
 VfatGetNetworkOpenInformation(PVFATFCB Fcb,
+			      PDEVICE_EXTENSION DeviceExt,
 			      PFILE_NETWORK_OPEN_INFORMATION NetworkInfo,
 			      PULONG BufferLength)
 /*
@@ -298,16 +346,38 @@
   if (*BufferLength < sizeof(FILE_NETWORK_OPEN_INFORMATION))
     return(STATUS_BUFFER_OVERFLOW);
 
-  FsdDosDateTimeToSystemTime(Fcb->entry.CreationDate,
-			     Fcb->entry.CreationTime,
+  if (Fcb->Flags & FCB_IS_FATX_ENTRY)
+  {
+    FsdDosDateTimeToSystemTime(DeviceExt,
+			     Fcb->entry.FatX.CreationDate,
+			     Fcb->entry.FatX.CreationTime,
+			     &NetworkInfo->CreationTime);
+    FsdDosDateTimeToSystemTime(DeviceExt,
+			     Fcb->entry.FatX.AccessDate,
+			     Fcb->entry.FatX.AccessTime,
+			     &NetworkInfo->LastAccessTime);
+    FsdDosDateTimeToSystemTime(DeviceExt,
+			     Fcb->entry.FatX.UpdateDate,
+			     Fcb->entry.FatX.UpdateTime,
+			     &NetworkInfo->LastWriteTime);
+    NetworkInfo->ChangeTime.QuadPart = NetworkInfo->LastWriteTime.QuadPart;
+  }
+  else
+  {
+    FsdDosDateTimeToSystemTime(DeviceExt,
+			     Fcb->entry.Fat.CreationDate,
+			     Fcb->entry.Fat.CreationTime,
 			     &NetworkInfo->CreationTime);
-  FsdDosDateTimeToSystemTime(Fcb->entry.AccessDate,
+    FsdDosDateTimeToSystemTime(DeviceExt,
+			     Fcb->entry.Fat.AccessDate,
 			     0,
 			     &NetworkInfo->LastAccessTime);
-  FsdDosDateTimeToSystemTime(Fcb->entry.UpdateDate,
-			     Fcb->entry.UpdateTime,
+    FsdDosDateTimeToSystemTime(DeviceExt,
+			     Fcb->entry.Fat.UpdateDate,
+			     Fcb->entry.Fat.UpdateTime,
 			     &NetworkInfo->LastWriteTime);
-  NetworkInfo->ChangeTime.QuadPart = NetworkInfo->LastWriteTime.QuadPart;
+    NetworkInfo->ChangeTime.QuadPart = NetworkInfo->LastWriteTime.QuadPart;
+  }
   if (vfatFCBIsDirectory(Fcb))
     {
       NetworkInfo->EndOfFile.QuadPart = 0L;
@@ -318,7 +388,7 @@
       NetworkInfo->AllocationSize = Fcb->RFCB.AllocationSize;
       NetworkInfo->EndOfFile = Fcb->RFCB.FileSize;
     }
-  NetworkInfo->FileAttributes = Fcb->entry.Attrib & 0x3f;
+  NetworkInfo->FileAttributes = *Fcb->Attributes & 0x3f;
 
   *BufferLength -= sizeof(FILE_NETWORK_OPEN_INFORMATION);
   return STATUS_SUCCESS;
@@ -328,12 +398,16 @@
 static NTSTATUS
 VfatGetAllInformation(PFILE_OBJECT FileObject,
 		      PVFATFCB Fcb,
+		      PDEVICE_OBJECT DeviceObject,
 		      PFILE_ALL_INFORMATION Info,
 		      PULONG BufferLength)
 /*
  * FUNCTION: Retrieve the all file information
  */
 {
+  NTSTATUS Status;
+  ULONG InitialBufferLength = *BufferLength;
+  
   ASSERT(Info);
   ASSERT(Fcb);
 
@@ -341,60 +415,28 @@
     return(STATUS_BUFFER_OVERFLOW);
 
   /* Basic Information */
-  FsdDosDateTimeToSystemTime(Fcb->entry.CreationDate,
-			     Fcb->entry.CreationTime,
-			     &Info->BasicInformation.CreationTime);
-  FsdDosDateTimeToSystemTime(Fcb->entry.AccessDate,
-			     0,
-			     &Info->BasicInformation.LastAccessTime);
-  FsdDosDateTimeToSystemTime(Fcb->entry.UpdateDate,
-			     Fcb->entry.UpdateTime,
-			     &Info->BasicInformation.LastWriteTime);
-  Info->BasicInformation.ChangeTime.QuadPart = Info->BasicInformation.LastWriteTime.QuadPart;
-  Info->BasicInformation.FileAttributes = Fcb->entry.Attrib & 0x3f;
-
+  Status = VfatGetBasicInformation(FileObject, Fcb, DeviceObject, &Info->BasicInformation, BufferLength);
+  if (!NT_SUCCESS(Status)) return Status;
   /* Standard Information */
-  if (vfatFCBIsDirectory(Fcb))
-    {
-      Info->StandardInformation.AllocationSize.QuadPart = 0LL;
-      Info->StandardInformation.EndOfFile.QuadPart = 0LL;
-      Info->StandardInformation.Directory = TRUE;
-    }
-  else
-    {
-      Info->StandardInformation.AllocationSize = Fcb->RFCB.AllocationSize;
-      Info->StandardInformation.EndOfFile = Fcb->RFCB.FileSize;
-      Info->StandardInformation.Directory = FALSE;
-    }
-  Info->StandardInformation.NumberOfLinks = 0;
-  Info->StandardInformation.DeletePending = Fcb->Flags & FCB_DELETE_PENDING ? TRUE : FALSE;
-
+  Status = VfatGetStandardInformation(Fcb, &Info->StandardInformation, BufferLength);
+  if (!NT_SUCCESS(Status)) return Status;
   /* Internal Information */
-  /* FIXME: get a real index, that can be used in a create operation */
-  Info->InternalInformation.IndexNumber.QuadPart = 0;
-
+  Status = VfatGetInternalInformation(Fcb, &Info->InternalInformation, BufferLength);
+  if (!NT_SUCCESS(Status)) return Status;
   /* EA Information */
   Info->EaInformation.EaSize = 0;
-
-  /* Access Information */
-  /* The IO-Manager adds this information */
-
+  /* Access Information: The IO-Manager adds this information */
   /* Position Information */
-  Info->PositionInformation.CurrentByteOffset.QuadPart = FileObject->CurrentByteOffset.QuadPart;
-
-  /* Mode Information */
-  /* The IO-Manager adds this information */
-
-  /* Alignment Information */
-  /* The IO-Manager adds this information */
-
+  Status = VfatGetPositionInformation(FileObject, Fcb, DeviceObject, &Info->PositionInformation, BufferLength);
+  if (!NT_SUCCESS(Status)) return Status;
+  /* Mode Information: The IO-Manager adds this information */
+  /* Alignment Information: The IO-Manager adds this information */
   /* Name Information */
-  Info->NameInformation.FileNameLength = Fcb->PathNameU.Length;
-  RtlCopyMemory(Info->NameInformation.FileName, Fcb->PathNameU.Buffer, Fcb->PathNameU.Length);
-  Info->NameInformation.FileName[Fcb->PathNameU.Length / sizeof(WCHAR)] = 0;
-
-  *BufferLength -= (sizeof(FILE_ALL_INFORMATION) + Fcb->PathNameU.Length + sizeof(WCHAR));
-
+  Status = VfatGetNameInformation(FileObject, Fcb, DeviceObject, &Info->NameInformation, BufferLength);
+  if (!NT_SUCCESS(Status)) return Status;
+  
+  *BufferLength = InitialBufferLength - (sizeof(FILE_ALL_INFORMATION) + Fcb->PathNameU.Length + sizeof(WCHAR));
+  
   return STATUS_SUCCESS;
 }
 
@@ -410,7 +452,10 @@
    }
    if (!vfatFCBIsDirectory(Fcb))
    {
-      Fcb->entry.FileSize = Size;  
+      if (Fcb->Flags & FCB_IS_FATX_ENTRY)
+         Fcb->entry.FatX.FileSize = Size;  
+      else
+         Fcb->entry.Fat.FileSize = Size;  
    }
    Fcb->RFCB.FileSize.QuadPart = Size;
    Fcb->RFCB.ValidDataLength.QuadPart = Size;
@@ -438,7 +483,10 @@
 
   DPRINT("VfatSetAllocationSizeInformation()\n");
 
-  OldSize = Fcb->entry.FileSize;
+  if (Fcb->Flags & FCB_IS_FATX_ENTRY)
+    OldSize = Fcb->entry.FatX.FileSize;
+  else
+    OldSize = Fcb->entry.Fat.FileSize;
   if (AllocationSize->u.HighPart > 0)
   {
     return STATUS_INVALID_PARAMETER;
@@ -482,8 +530,15 @@
          }
          return STATUS_DISK_FULL;
       }
-      Fcb->entry.FirstCluster = (unsigned short)(FirstCluster & 0x0000FFFF);
-      Fcb->entry.FirstClusterHigh = (unsigned short)((FirstCluster & 0xFFFF0000) >> 16);
+      if (Fcb->Flags & FCB_IS_FATX_ENTRY)
+      {
+         Fcb->entry.FatX.FirstCluster = FirstCluster;
+      }
+      else
+      {
+        Fcb->entry.Fat.FirstCluster = (unsigned short)(FirstCluster & 0x0000FFFF);
+        Fcb->entry.Fat.FirstClusterHigh = (unsigned short)((FirstCluster & 0xFFFF0000) >> 16);
+      }
     }
     else
     {
@@ -547,8 +602,15 @@
     }
     else
     {
-      Fcb->entry.FirstCluster = 0;
-      Fcb->entry.FirstClusterHigh = 0;
+      if (Fcb->Flags & FCB_IS_FATX_ENTRY)
+      {
+         Fcb->entry.FatX.FirstCluster = 0;
+      }
+      else
+      {
+        Fcb->entry.Fat.FirstCluster = 0;
+        Fcb->entry.Fat.FirstClusterHigh = 0;
+      }
 
       NCluster = Cluster = FirstCluster;
       Status = STATUS_SUCCESS;
@@ -640,12 +702,14 @@
       break;
     case FileNetworkOpenInformation:
       RC = VfatGetNetworkOpenInformation(FCB,
+					 IrpContext->DeviceExt,
 					 SystemBuffer,
 					 &BufferLength);
       break;
     case FileAllInformation:
       RC = VfatGetAllInformation(IrpContext->FileObject,
 				 FCB,
+				 IrpContext->DeviceObject,
 				 SystemBuffer,
 				 &BufferLength);
       break;

reactos/drivers/fs/vfat
fsctl.c 1.36 -> 1.37
diff -u -r1.36 -r1.37
--- fsctl.c	6 Nov 2004 13:44:57 -0000	1.36
+++ fsctl.c	5 Dec 2004 16:31:51 -0000	1.37
@@ -16,7 +16,7 @@
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
-/* $Id: fsctl.c,v 1.36 2004/11/06 13:44:57 ekohl Exp $
+/* $Id: fsctl.c,v 1.37 2004/12/05 16:31:51 gvg Exp $
  *
  * COPYRIGHT:        See COPYING in the top level directory
  * PROJECT:          ReactOS kernel
@@ -55,6 +55,7 @@
    ULONG Sectors;
    LARGE_INTEGER Offset;
    struct _BootSector* Boot;
+   struct _BootSectorFatX* BootFatX;
    BOOL PartitionInfoIsValid = FALSE;
 
    DPRINT("VfatHasFileSystem\n");
@@ -92,17 +93,15 @@
          return Status;
       }
       PartitionInfoIsValid = TRUE;
-#if defined(DBG) && !defined(NDEBUG)
-      DbgPrint("Partition Information:\n");
-      DbgPrint("StartingOffset      %u\n", PartitionInfo.StartingOffset.QuadPart  / 512);
-      DbgPrint("PartitionLength     %u\n", PartitionInfo.PartitionLength.QuadPart / 512);
-      DbgPrint("HiddenSectors       %u\n", PartitionInfo.HiddenSectors);
-      DbgPrint("PartitionNumber     %u\n", PartitionInfo.PartitionNumber);
-      DbgPrint("PartitionType       %u\n", PartitionInfo.PartitionType);
-      DbgPrint("BootIndicator       %u\n", PartitionInfo.BootIndicator);
-      DbgPrint("RecognizedPartition %u\n", PartitionInfo.RecognizedPartition);
-      DbgPrint("RewritePartition    %u\n", PartitionInfo.RewritePartition);
-#endif
+      DPRINT("Partition Information:\n");
+      DPRINT("StartingOffset      %u\n", PartitionInfo.StartingOffset.QuadPart  / 512);
+      DPRINT("PartitionLength     %u\n", PartitionInfo.PartitionLength.QuadPart / 512);
+      DPRINT("HiddenSectors       %u\n", PartitionInfo.HiddenSectors);
+      DPRINT("PartitionNumber     %u\n", PartitionInfo.PartitionNumber);
+      DPRINT("PartitionType       %u\n", PartitionInfo.PartitionType);
+      DPRINT("BootIndicator       %u\n", PartitionInfo.BootIndicator);
+      DPRINT("RecognizedPartition %u\n", PartitionInfo.RecognizedPartition);
+      DPRINT("RewritePartition    %u\n", PartitionInfo.RewritePartition);
       if (PartitionInfo.PartitionType)
       {
          if (PartitionInfo.PartitionType == PARTITION_FAT_12       ||
@@ -151,20 +150,28 @@
    }
 
    Offset.QuadPart = 0;
-
+   
+   /* Try to recognize FAT12/FAT16/FAT32 partitions */
    Status = VfatReadDisk(DeviceToMount, &Offset, DiskGeometry.BytesPerSector, (PUCHAR) Boot, FALSE);
    if (NT_SUCCESS(Status))
    {
       if (Boot->Signatur1 != 0xaa55)
       {
-         DPRINT1("Signature %04x\n", Boot->Signatur1);
+         BootFatX = (struct _BootSectorFatX *) Boot;
+         if (BootFatX->SysType[0] != 'F' ||
+             BootFatX->SysType[1] != 'A' ||
+             BootFatX->SysType[2] != 'T' ||
+             BootFatX->SysType[3] != 'X')
+         {
+            DPRINT1("Signature %04x\n", Boot->Signatur1);
+         }
          *RecognizedFS=FALSE;
       }
       if (*RecognizedFS &&
-	  Boot->BytesPerSector != 512 &&
-	  Boot->BytesPerSector != 1024 &&
+	       Boot->BytesPerSector != 512 &&
+	       Boot->BytesPerSector != 1024 &&
           Boot->BytesPerSector != 2048 && 
-	  Boot->BytesPerSector != 4096)
+	       Boot->BytesPerSector != 4096)
       {
          DPRINT1("BytesPerSector %d\n", Boot->BytesPerSector);
          *RecognizedFS=FALSE;
@@ -172,7 +179,7 @@
 
       if (*RecognizedFS &&
           Boot->FATCount != 1 && 
-	  Boot->FATCount != 2)
+	       Boot->FATCount != 2)
       {
          DPRINT1("FATCount %d\n", Boot->FATCount);
          *RecognizedFS=FALSE;
@@ -180,28 +187,28 @@
 
       if (*RecognizedFS &&
           Boot->Media != 0xf0 && 
-	  Boot->Media != 0xf8 &&
-	  Boot->Media != 0xf9 &&
-	  Boot->Media != 0xfa && 
-	  Boot->Media != 0xfb &&
-	  Boot->Media != 0xfc &&
-	  Boot->Media != 0xfd &&
-	  Boot->Media != 0xfe && 
-	  Boot->Media != 0xff)
+          Boot->Media != 0xf8 &&
+          Boot->Media != 0xf9 &&
+          Boot->Media != 0xfa && 
+          Boot->Media != 0xfb &&
+          Boot->Media != 0xfc &&
+          Boot->Media != 0xfd &&
+          Boot->Media != 0xfe && 
+          Boot->Media != 0xff)
       {
          DPRINT1("Media             %02x\n", Boot->Media);
          *RecognizedFS=FALSE;
       }
 
       if (*RecognizedFS &&
-	  Boot->SectorsPerCluster != 1 &&
-	  Boot->SectorsPerCluster != 2 &&
+          Boot->SectorsPerCluster != 1 &&
+          Boot->SectorsPerCluster != 2 &&
           Boot->SectorsPerCluster != 4 && 
-	  Boot->SectorsPerCluster != 8 &&
+          Boot->SectorsPerCluster != 8 &&
           Boot->SectorsPerCluster != 16 &&
-	  Boot->SectorsPerCluster != 32 && 
+          Boot->SectorsPerCluster != 32 && 
           Boot->SectorsPerCluster != 64 &&
-	  Boot->SectorsPerCluster != 128)
+          Boot->SectorsPerCluster != 128)
       {
          DPRINT1("SectorsPerCluster %02x\n", Boot->SectorsPerCluster);
          *RecognizedFS=FALSE;
@@ -247,12 +254,12 @@
             DPRINT("FAT16\n");
             FatInfo.FatType = FAT16;
          }
-	 if (PartitionInfoIsValid &&
-	     FatInfo.Sectors > PartitionInfo.PartitionLength.QuadPart / FatInfo.BytesPerSector)
-	 {
-	    CHECKPOINT1;
-	    *RecognizedFS = FALSE;
-	 }
+         if (PartitionInfoIsValid &&
+	         FatInfo.Sectors > PartitionInfo.PartitionLength.QuadPart / FatInfo.BytesPerSector)
+         {
+	         CHECKPOINT1;
+            *RecognizedFS = FALSE;
+         }
 	    
          if (pFatInfo && *RecognizedFS)
          {
@@ -262,6 +269,81 @@
    }
 
    ExFreePool(Boot);
+   
+   if (!*RecognizedFS && PartitionInfoIsValid)
+   {
+      BootFatX = ExAllocatePool(NonPagedPool, sizeof(struct _BootSectorFatX));
+      if (BootFatX == NULL)
+      {
+         *RecognizedFS=FALSE;
+         return STATUS_INSUFFICIENT_RESOURCES;
+      }
+
+      Offset.QuadPart = 0;
+   
+      /* Try to recognize FATX16/FATX32 partitions (Xbox) */
+      Status = VfatReadDisk(DeviceToMount, &Offset, sizeof(struct _BootSectorFatX), (PUCHAR) BootFatX, FALSE);
+      if (NT_SUCCESS(Status))
+      {
+         *RecognizedFS = TRUE;
+         if (BootFatX->SysType[0] != 'F' ||
+             BootFatX->SysType[1] != 'A' ||
+             BootFatX->SysType[2] != 'T' ||
+             BootFatX->SysType[3] != 'X')
+         {
+            DPRINT1("SysType %c%c%c%c\n", BootFatX->SysType[0], BootFatX->SysType[1], BootFatX->SysType[2], BootFatX->SysType[3]);
+            *RecognizedFS=FALSE;
+         }
+         
+         if (*RecognizedFS &&
+            BootFatX->SectorsPerCluster != 1 &&
+            BootFatX->SectorsPerCluster != 2 &&
+            BootFatX->SectorsPerCluster != 4 && 
+            BootFatX->SectorsPerCluster != 8 &&
+            BootFatX->SectorsPerCluster != 16 &&
+            BootFatX->SectorsPerCluster != 32 && 
+            BootFatX->SectorsPerCluster != 64 &&
+            BootFatX->SectorsPerCluster != 128)
+         {
+            DPRINT1("SectorsPerCluster %lu\n", BootFatX->SectorsPerCluster);
+            *RecognizedFS=FALSE;
+         }
+         
+         if (*RecognizedFS)
+         {
+            FatInfo.BytesPerSector = DiskGeometry.BytesPerSector;
+            FatInfo.SectorsPerCluster = BootFatX->SectorsPerCluster;
+            FatInfo.rootDirectorySectors = BootFatX->SectorsPerCluster;
+            FatInfo.BytesPerCluster = BootFatX->SectorsPerCluster * DiskGeometry.BytesPerSector;
+            FatInfo.NumberOfClusters = PartitionInfo.PartitionLength.QuadPart / FatInfo.BytesPerCluster;
+            if (FatInfo.NumberOfClusters < 65525)
+            {
+               DPRINT("FATX16\n");
+               FatInfo.FatType = FATX16;
+            }
+            else
+            {
+               DPRINT("FATX32\n");
+               FatInfo.FatType = FATX32;
+            }
+            FatInfo.VolumeID = BootFatX->VolumeID;
+            FatInfo.FATStart = sizeof(struct _BootSectorFatX) / DiskGeometry.BytesPerSector;
+            FatInfo.FATCount = BootFatX->FATCount;
+            FatInfo.FATSectors =
+                  ROUND_UP(FatInfo.NumberOfClusters * (FatInfo.FatType == FATX16 ? 2 : 4), 4096) /
+                  FatInfo.BytesPerSector;
+            FatInfo.rootStart = FatInfo.FATStart + FatInfo.FATCount * FatInfo.FATSectors;
+            FatInfo.dataStart = FatInfo.rootStart + FatInfo.rootDirectorySectors;
+            FatInfo.Sectors = PartitionInfo.PartitionLength.QuadPart / FatInfo.BytesPerSector;
+            if (pFatInfo && *RecognizedFS)
+            {
+               *pFatInfo = FatInfo;
+            }
+         }
+      }
+      ExFreePool(BootFatX);
+   }
+      
    DPRINT("VfatHasFileSystem done\n");
    return Status;
 }
@@ -357,31 +439,65 @@
       goto ByeBye;
    }
 
-#ifndef NDEBUG
-   DbgPrint("BytesPerSector:     %d\n", DeviceExt->FatInfo.BytesPerSector);
-   DbgPrint("SectorsPerCluster:  %d\n", DeviceExt->FatInfo.SectorsPerCluster);
-   DbgPrint("FATCount:           %d\n", DeviceExt->FatInfo.FATCount);
-   DbgPrint("FATSectors:         %d\n", DeviceExt->FatInfo.FATSectors);
-   DbgPrint("RootStart:          %d\n", DeviceExt->FatInfo.rootStart);
-   DbgPrint("DataStart:          %d\n", DeviceExt->FatInfo.dataStart);
+   DPRINT("BytesPerSector:     %d\n", DeviceExt->FatInfo.BytesPerSector);
+   DPRINT("SectorsPerCluster:  %d\n", DeviceExt->FatInfo.SectorsPerCluster);
+   DPRINT("FATCount:           %d\n", DeviceExt->FatInfo.FATCount);
+   DPRINT("FATSectors:         %d\n", DeviceExt->FatInfo.FATSectors);
+   DPRINT("RootStart:          %d\n", DeviceExt->FatInfo.rootStart);
+   DPRINT("DataStart:          %d\n", DeviceExt->FatInfo.dataStart);
    if (DeviceExt->FatInfo.FatType == FAT32)
    {
-      DbgPrint("RootCluster:        %d\n", DeviceExt->FatInfo.RootCluster);
+      DPRINT("RootCluster:        %d\n", DeviceExt->FatInfo.RootCluster);
    }
-#endif
 
-  DeviceExt->StorageDevice = DeviceToMount;
-  DeviceExt->StorageDevice->Vpb->DeviceObject = DeviceObject;
-  DeviceExt->StorageDevice->Vpb->RealDevice = DeviceExt->StorageDevice;
-  DeviceExt->StorageDevice->Vpb->Flags |= VPB_MOUNTED;
-  DeviceObject->StackSize = DeviceExt->StorageDevice->StackSize + 1;
-  DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
+   switch (DeviceExt->FatInfo.FatType)
+   {
+      case FAT12:
+         DeviceExt->GetNextCluster = FAT12GetNextCluster;
+         DeviceExt->FindAndMarkAvailableCluster = FAT12FindAndMarkAvailableCluster;
+         DeviceExt->WriteCluster = FAT12WriteCluster;
+         break;
 
-  DPRINT("FsDeviceObject %lx\n", DeviceObject);
+      case FAT16:
+      case FATX16:
+         DeviceExt->GetNextCluster = FAT16GetNextCluster;
+         DeviceExt->FindAndMarkAvailableCluster = FAT16FindAndMarkAvailableCluster;
+         DeviceExt->WriteCluster = FAT16WriteCluster;
+         break;
+
+      case FAT32:
+      case FATX32:
+         DeviceExt->GetNextCluster = FAT32GetNextCluster;
+         DeviceExt->FindAndMarkAvailableCluster = FAT32FindAndMarkAvailableCluster;
+         DeviceExt->WriteCluster = FAT32WriteCluster;
+         break;
+   }
+   
+   if (DeviceExt->FatInfo.FatType == FATX16
+      || DeviceExt->FatInfo.FatType == FATX32)
+   {
+      DeviceExt->Flags |= VCB_IS_FATX;
+      DeviceExt->GetNextDirEntry = FATXGetNextDirEntry;
+      DeviceExt->BaseDateYear = 2000;
+   }
+   else
+   {
+      DeviceExt->GetNextDirEntry = FATGetNextDirEntry;
+      DeviceExt->BaseDateYear = 1980;
+   }
+
+   DeviceExt->StorageDevice = DeviceToMount;
+   DeviceExt->StorageDevice->Vpb->DeviceObject = DeviceObject;
+   DeviceExt->StorageDevice->Vpb->RealDevice = DeviceExt->StorageDevice;
+   DeviceExt->StorageDevice->Vpb->Flags |= VPB_MOUNTED;
+   DeviceObject->StackSize = DeviceExt->StorageDevice->StackSize + 1;
+   DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
+
+   DPRINT("FsDeviceObject %lx\n", DeviceObject);
 
    DeviceExt->FATFileObject = IoCreateStreamFileObject(NULL, DeviceExt->StorageDevice);
    RtlRosInitUnicodeStringFromLiteral(&NameU, L"\\$$Fat$$");
-   Fcb = vfatNewFCB(&NameU);
+   Fcb = vfatNewFCB(DeviceExt, &NameU);
    if (Fcb == NULL)
    {
       Status = STATUS_INSUFFICIENT_RESOURCES;
@@ -394,7 +510,7 @@
       goto ByeBye;
    }
 
-   memset(Ccb, 0, sizeof (VFATCCB));
+   RtlZeroMemory(Ccb, sizeof (VFATCCB));
    DeviceExt->FATFileObject->Flags = DeviceExt->FATFileObject->Flags | FO_FCB_IS_VALID | FO_DIRECT_CACHE_PAGING_READ;
    DeviceExt->FATFileObject->FsContext = Fcb;
    DeviceExt->FATFileObject->FsContext2 = Ccb;
@@ -403,7 +519,7 @@
    DeviceExt->FATFileObject->Vpb = DeviceObject->Vpb;
    Fcb->FileObject = DeviceExt->FATFileObject;
 
-   Fcb->Flags = FCB_IS_FAT;
+   Fcb->Flags |= FCB_IS_FAT;
 
    Fcb->RFCB.FileSize.QuadPart = DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector;
    Fcb->RFCB.ValidDataLength = Fcb->RFCB.FileSize;
@@ -419,38 +535,17 @@
    }
    if (!NT_SUCCESS (Status))
    {
-      DbgPrint ("CcRosInitializeFileCache failed\n");
+      DPRINT1 ("CcRosInitializeFileCache failed\n");
       goto ByeBye;
    }
    DeviceExt->LastAvailableCluster = 2;
    ExInitializeResourceLite(&DeviceExt->DirResource);
    ExInitializeResourceLite(&DeviceExt->FatResource);
 
-   switch (DeviceExt->FatInfo.FatType)
-   {
-      case FAT12:
-         DeviceExt->GetNextCluster = FAT12GetNextCluster;
-         DeviceExt->FindAndMarkAvailableCluster = FAT12FindAndMarkAvailableCluster;
-         DeviceExt->WriteCluster = FAT12WriteCluster;
-         break;
-
-      case FAT16:
-         DeviceExt->GetNextCluster = FAT16GetNextCluster;
-         DeviceExt->FindAndMarkAvailableCluster = FAT16FindAndMarkAvailableCluster;
-         DeviceExt->WriteCluster = FAT16WriteCluster;
-         break;
-
-      case FAT32:
-         DeviceExt->GetNextCluster = FAT32GetNextCluster;
-         DeviceExt->FindAndMarkAvailableCluster = FAT32FindAndMarkAvailableCluster;
-         DeviceExt->WriteCluster = FAT32WriteCluster;
-         break;
-   }
-
    InitializeListHead(&DeviceExt->FcbListHead);
    RtlRosInitUnicodeStringFromLiteral(&NameU, L"\\$$Volume$$");
 
-   VolumeFcb = vfatNewFCB(&NameU);
+   VolumeFcb = vfatNewFCB(DeviceExt, &NameU);
    if (VolumeFcb == NULL)
    {
       Status = STATUS_INSUFFICIENT_RESOURCES;
@@ -471,7 +566,7 @@
 
    /* read volume label */
    ReadVolumeLabel(DeviceExt,  DeviceObject->Vpb);
-
+   
    Status = STATUS_SUCCESS;
 ByeBye:
 
@@ -737,4 +832,3 @@
    VfatFreeIrpContext(IrpContext);
    return (Status);
 }
-

reactos/drivers/fs/vfat
misc.c 1.14 -> 1.15
diff -u -r1.14 -r1.15
--- misc.c	6 Nov 2004 13:44:57 -0000	1.14
+++ misc.c	5 Dec 2004 16:31:51 -0000	1.15
@@ -1,4 +1,4 @@
-/* $Id: misc.c,v 1.14 2004/11/06 13:44:57 ekohl Exp $
+/* $Id: misc.c,v 1.15 2004/12/05 16:31:51 gvg Exp $
  *
  * COPYRIGHT:        See COPYING in the top level directory
  * PROJECT:          ReactOS kernel
@@ -41,7 +41,7 @@
       goto Fail;
    }
 
-   if (Fcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY)
+   if (*Fcb->Attributes & FILE_ATTRIBUTE_DIRECTORY)
    {
       Status = STATUS_INVALID_PARAMETER;
       goto Fail;

reactos/drivers/fs/vfat
rw.c 1.71 -> 1.72
diff -u -r1.71 -r1.72
--- rw.c	6 Nov 2004 13:44:57 -0000	1.71
+++ rw.c	5 Dec 2004 16:31:51 -0000	1.72
@@ -1,5 +1,5 @@
 
-/* $Id: rw.c,v 1.71 2004/11/06 13:44:57 ekohl Exp $
+/* $Id: rw.c,v 1.72 2004/12/05 16:31:51 gvg Exp $
  *
  * COPYRIGHT:        See COPYING in the top level directory
  * PROJECT:          ReactOS kernel
@@ -592,7 +592,7 @@
    BytesPerSector = IrpContext->DeviceExt->FatInfo.BytesPerSector;
 
    /* fail if file is a directory and no paged read */
-   if (Fcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY && !(IrpContext->Irp->Flags & IRP_PAGING_IO))
+   if (*Fcb->Attributes & FILE_ATTRIBUTE_DIRECTORY && !(IrpContext->Irp->Flags & IRP_PAGING_IO))
    {
       Status = STATUS_INVALID_PARAMETER;
       goto ByeBye;
@@ -821,7 +821,7 @@
    }
 
   /* fail if file is a directory and no paged read */
-   if (Fcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY && !(IrpContext->Irp->Flags & IRP_PAGING_IO))
+   if (*Fcb->Attributes & FILE_ATTRIBUTE_DIRECTORY && !(IrpContext->Irp->Flags & IRP_PAGING_IO))
    {
       Status = STATUS_INVALID_PARAMETER;
       goto ByeBye;
@@ -1020,14 +1020,26 @@
    if (!(IrpContext->Irp->Flags & IRP_PAGING_IO) &&
       !(Fcb->Flags & (FCB_IS_FAT|FCB_IS_VOLUME)))
    {
-      if(!(Fcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
+      if(!(*Fcb->Attributes & FILE_ATTRIBUTE_DIRECTORY))
       {
          LARGE_INTEGER SystemTime;
          // set dates and times
          KeQuerySystemTime (&SystemTime);
-         FsdSystemTimeToDosDateTime (&SystemTime, &Fcb->entry.UpdateDate,
-                                     &Fcb->entry.UpdateTime);
-         Fcb->entry.AccessDate = Fcb->entry.UpdateDate;
+         if (Fcb->Flags & FCB_IS_FATX_ENTRY)
+         {
+            FsdSystemTimeToDosDateTime (IrpContext->DeviceExt,
+                                     &SystemTime, &Fcb->entry.FatX.UpdateDate,
+                                     &Fcb->entry.FatX.UpdateTime);
+            Fcb->entry.FatX.AccessDate = Fcb->entry.FatX.UpdateDate;
+            Fcb->entry.FatX.AccessTime = Fcb->entry.FatX.UpdateTime;
+         }
+         else
+         {
+            FsdSystemTimeToDosDateTime (IrpContext->DeviceExt,
+                                     &SystemTime, &Fcb->entry.Fat.UpdateDate,
+                                     &Fcb->entry.Fat.UpdateTime);
+            Fcb->entry.Fat.AccessDate = Fcb->entry.Fat.UpdateDate;
+         }
          /* set date and times to dirty */
 	 Fcb->Flags |= FCB_IS_DIRTY;
       }

reactos/drivers/fs/vfat
shutdown.c 1.8 -> 1.9
diff -u -r1.8 -r1.9
--- shutdown.c	11 Oct 2003 17:51:56 -0000	1.8
+++ shutdown.c	5 Dec 2004 16:31:51 -0000	1.9
@@ -1,4 +1,4 @@
-/* $Id: shutdown.c,v 1.8 2003/10/11 17:51:56 hbirr Exp $
+/* $Id: shutdown.c,v 1.9 2004/12/05 16:31:51 gvg Exp $
  *
  * COPYRIGHT:        See COPYING in the top level directory
  * PROJECT:          ReactOS kernel
@@ -48,9 +48,9 @@
 	    Irp->IoStatus.Status = Status;
 	 }
          /* FIXME: Unmount the logical volume */
-
-	 ExReleaseResourceLite(&VfatGlobalData->VolumeListLock);
       }
+	 ExReleaseResourceLite(&VfatGlobalData->VolumeListLock);
+      
       /* FIXME: Free all global acquired resources */
 
       Status = Irp->IoStatus.Status;

reactos/drivers/fs/vfat
vfat.h 1.69 -> 1.70
diff -u -r1.69 -r1.70
--- vfat.h	6 Nov 2004 13:44:57 -0000	1.69
+++ vfat.h	5 Dec 2004 16:31:51 -0000	1.70
@@ -1,4 +1,4 @@
-/* $Id: vfat.h,v 1.69 2004/11/06 13:44:57 ekohl Exp $ */
+/* $Id: vfat.h,v 1.70 2004/12/05 16:31:51 gvg Exp $ */
 
 #include <ddk/ntifs.h>
 
@@ -52,6 +52,16 @@
   unsigned short Signature1;				// 510
 } __attribute__((packed));
 
+struct _BootSectorFatX
+{
+   unsigned char SysType[4];        // 0
+   unsigned long VolumeID;          // 4
+   unsigned long SectorsPerCluster; // 8
+   unsigned short FATCount;         // 12
+   unsigned long Unknown;           // 14
+   unsigned char Unused[4078];      // 18
+} __attribute__((packed));
+
 struct _FsInfoSector
 {
   unsigned long  ExtBootSignature2;			// 0
@@ -68,10 +78,22 @@
 #define VFAT_CASE_LOWER_BASE	8			// base is lower case
 #define VFAT_CASE_LOWER_EXT	16			// extension is lower case
 
-#define ENTRY_DELETED(DirEntry)	((DirEntry)->Filename[0] == 0xe5)
-#define ENTRY_END(DirEntry)	((DirEntry)->Filename[0] == 0)
-#define ENTRY_LONG(DirEntry)	(((DirEntry)->Attrib & 0x3f) == 0x0f)
-#define ENTRY_VOLUME(DirEntry)	(((DirEntry)->Attrib & 0x1f) == 0x08)
+#define ENTRY_DELETED(DeviceExt, DirEntry) ((DeviceExt)->Flags & VCB_IS_FATX ? FATX_ENTRY_DELETED(&((DirEntry)->FatX)) : FAT_ENTRY_DELETED(&((DirEntry)->Fat)))
+#define ENTRY_VOLUME(DeviceExt, DirEntry)  ((DeviceExt)->Flags & VCB_IS_FATX ? FATX_ENTRY_VOLUME(&((DirEntry)->FatX)) : FAT_ENTRY_VOLUME(&((DirEntry)->Fat)))
+#define ENTRY_END(DeviceExt, DirEntry)     ((DeviceExt)->Flags & VCB_IS_FATX ? FATX_ENTRY_END(&((DirEntry)->FatX)) : FAT_ENTRY_END(&((DirEntry)->Fat)))
+
+#define FAT_ENTRY_DELETED(DirEntry)  ((DirEntry)->Filename[0] == 0xe5)
+#define FAT_ENTRY_END(DirEntry)      ((DirEntry)->Filename[0] == 0)
+#define FAT_ENTRY_LONG(DirEntry)     (((DirEntry)->Attrib & 0x3f) == 0x0f)
+#define FAT_ENTRY_VOLUME(DirEntry)   (((DirEntry)->Attrib & 0x1f) == 0x08)
+
+#define FATX_ENTRY_DELETED(DirEntry) ((DirEntry)->FilenameLength == 0xe5)
+#define FATX_ENTRY_END(DirEntry)     ((DirEntry)->FilenameLength == 0xff)
+#define FATX_ENTRY_LONG(DirEntry)    (FALSE)
+#define FATX_ENTRY_VOLUME(DirEntry)  (((DirEntry)->Attrib & 0x1f) == 0x08)
+
+#define FAT_ENTRIES_PER_PAGE   (PAGE_SIZE / sizeof (FAT_DIR_ENTRY))
+#define FATX_ENTRIES_PER_PAGE  (PAGE_SIZE / sizeof (FATX_DIR_ENTRY))
 
 struct _FATDirEntry
 {
@@ -87,7 +109,32 @@
   unsigned long  FileSize;
 } __attribute__((packed));
 
-typedef struct _FATDirEntry FATDirEntry, FAT_DIR_ENTRY, *PFAT_DIR_ENTRY;
+typedef struct _FATDirEntry FAT_DIR_ENTRY, *PFAT_DIR_ENTRY;
+
+struct _FATXDirEntry
+{
+   unsigned char FilenameLength; // 0
+   unsigned char Attrib;         // 1
+   unsigned char Filename[42];   // 2
+   unsigned long FirstCluster;   // 44
+   unsigned long FileSize;       // 48
+   unsigned short UpdateTime;    // 52
+   unsigned short UpdateDate;    // 54
+   unsigned short CreationTime;  // 56
+   unsigned short CreationDate;  // 58
+   unsigned short AccessTime;    // 60
+   unsigned short AccessDate;    // 62
+} __attribute__((packed));
+
+typedef struct _FATXDirEntry FATX_DIR_ENTRY, *PFATX_DIR_ENTRY;
+
+union _DIR_ENTRY
+{
+   FAT_DIR_ENTRY Fat;
+   FATX_DIR_ENTRY FatX;
+};
+
+typedef union _DIR_ENTRY DIR_ENTRY, *PDIR_ENTRY;
 
 struct _slot
 {
@@ -106,12 +153,15 @@
 
 #define BLOCKSIZE 512
 
-#define FAT16 (1)
-#define FAT12 (2)
-#define FAT32 (3)
+#define FAT16  (1)
+#define FAT12  (2)
+#define FAT32  (3)
+#define FATX16 (4)
+#define FATX32 (5)
 
 #define VCB_VOLUME_LOCKED       0x0001
 #define VCB_DISMOUNT_PENDING    0x0002
+#define VCB_IS_FATX             0x0004
 
 typedef struct
 {
@@ -133,6 +183,7 @@
 } FATINFO, *PFATINFO;
 
 struct _VFATFCB;
+struct _VFAT_DIRENTRY_CONTEXT;
 
 typedef struct _HASHENTRY
 {
@@ -150,6 +201,8 @@
 typedef NTSTATUS (*PFIND_AND_MARK_AVAILABLE_CLUSTER)(PDEVICE_EXTENSION,PULONG);
 typedef NTSTATUS (*PWRITE_CLUSTER)(PDEVICE_EXTENSION,ULONG,ULONG,PULONG);
 
+typedef NTSTATUS (*PGET_NEXT_DIR_ENTRY)(PVOID*,PVOID*,struct _VFATFCB*,struct _VFAT_DIRENTRY_CONTEXT*,BOOLEAN);
+
 typedef struct DEVICE_EXTENSION
 {
   ERESOURCE DirResource;
@@ -172,6 +225,11 @@
   PGET_NEXT_CLUSTER GetNextCluster;
   PFIND_AND_MARK_AVAILABLE_CLUSTER FindAndMarkAvailableCluster;
   PWRITE_CLUSTER WriteCluster;
+  
+  /* Pointers to functions for manipulating directory entries. */
+  PGET_NEXT_DIR_ENTRY GetNextDirEntry;
+  
+  ULONG BaseDateYear;
 
   LIST_ENTRY VolumeListEntry;
 } DEVICE_EXTENSION, VCB, *PVCB;
@@ -195,7 +253,8 @@
 #define FCB_IS_FAT              0x0004
 #define FCB_IS_PAGE_FILE        0x0008
 #define FCB_IS_VOLUME           0x0010
-#define FCB_IS_DIRTY		0x0020
+#define FCB_IS_DIRTY            0x0020
+#define FCB_IS_FATX_ENTRY       0x0040
 
 typedef struct _VFATFCB
 {
@@ -207,7 +266,10 @@
   /* end FCB header required by ROS/NT */
 
   /* directory entry for this file or directory */
-  FATDirEntry entry;
+  DIR_ENTRY entry;
+  
+  /* Pointer to attributes in entry */
+  PUCHAR Attributes;
 
   /* long file name, points into PathNameBuffer */
   UNICODE_STRING LongNameU;
@@ -330,7 +392,7 @@
 {
   ULONG StartIndex;
   ULONG DirIndex;
-  FAT_DIR_ENTRY FatDirEntry;
+  DIR_ENTRY DirEntry;
   UNICODE_STRING LongNameU;
   UNICODE_STRING ShortNameU;
 } VFAT_DIRENTRY_CONTEXT, *PVFAT_DIRENTRY_CONTEXT;
@@ -379,11 +441,13 @@
 
 NTSTATUS VfatDirectoryControl (PVFAT_IRP_CONTEXT);
 
-BOOL FsdDosDateTimeToSystemTime (WORD wDosDate,
+BOOL FsdDosDateTimeToSystemTime (PDEVICE_EXTENSION DeviceExt,
+                                 WORD wDosDate,
                                  WORD wDosTime,
                                  PLARGE_INTEGER SystemTime);
 
-BOOL FsdSystemTimeToDosDateTime (PLARGE_INTEGER SystemTime,
+BOOL FsdSystemTimeToDosDateTime (PDEVICE_EXTENSION DeviceExt,
+                                 PLARGE_INTEGER SystemTime,
                                  WORD *pwDosDate,
                                  WORD *pwDosTime);
 
@@ -451,6 +515,12 @@
 
 NTSTATUS VfatDelEntry(PDEVICE_EXTENSION, PVFATFCB);
 
+BOOLEAN
+vfatFindDirSpace(PDEVICE_EXTENSION DeviceExt,
+                 PVFATFCB pDirFcb,
+                 ULONG nbSlots,
+                 PULONG start);
+
 /*  --------------------------------------------------------  string.c  */
 
 VOID
@@ -529,11 +599,17 @@
 /*  ------------------------------------------------------  direntry.c  */
 
 ULONG  vfatDirEntryGetFirstCluster (PDEVICE_EXTENSION  pDeviceExt,
-                                    PFAT_DIR_ENTRY  pDirEntry);
+                                    PDIR_ENTRY  pDirEntry);
 
 BOOL VfatIsDirectoryEmpty(PVFATFCB Fcb);
 
-NTSTATUS vfatGetNextDirEntry(PVOID * pContext,
+NTSTATUS FATGetNextDirEntry(PVOID * pContext,
+			     PVOID * pPage,
+			     IN PVFATFCB pDirFcb,
+			     IN PVFAT_DIRENTRY_CONTEXT DirContext,
+			     BOOLEAN First);
+
+NTSTATUS FATXGetNextDirEntry(PVOID * pContext,
 			     PVOID * pPage,
 			     IN PVFATFCB pDirFcb,
 			     IN PVFAT_DIRENTRY_CONTEXT DirContext,
@@ -541,7 +617,8 @@
 
 /*  -----------------------------------------------------------  fcb.c  */
 
-PVFATFCB vfatNewFCB (PUNICODE_STRING pFileNameU);
+PVFATFCB vfatNewFCB (PDEVICE_EXTENSION  pVCB,
+                        PUNICODE_STRING pFileNameU);
 
 VOID vfatDestroyFCB (PVFATFCB  pFCB);
 

reactos/drivers/fs/vfat
volume.c 1.27 -> 1.28
diff -u -r1.27 -r1.28
--- volume.c	6 Nov 2004 13:44:57 -0000	1.27
+++ volume.c	5 Dec 2004 16:31:51 -0000	1.28
@@ -1,4 +1,4 @@
-/* $Id: volume.c,v 1.27 2004/11/06 13:44:57 ekohl Exp $
+/* $Id: volume.c,v 1.28 2004/12/05 16:31:51 gvg Exp $
  *
  * COPYRIGHT:        See COPYING in the top level directory
  * PROJECT:          ReactOS kernel
@@ -6,6 +6,7 @@
  * PURPOSE:          VFAT Filesystem
  * PROGRAMMER:       Jason Filby (jasonfilby@yahoo.com)
  *                   Hartmut Birr
+ *                   Herve Poussineau (reactos@poussine.freesurf.fr)
  */
 
 /* INCLUDES *****************************************************************/
@@ -42,7 +43,7 @@
   /* valid entries */
   FsVolumeInfo->VolumeSerialNumber = DeviceObject->Vpb->SerialNumber;
   FsVolumeInfo->VolumeLabelLength = DeviceObject->Vpb->VolumeLabelLength;
-  memcpy(FsVolumeInfo->VolumeLabel, DeviceObject->Vpb->VolumeLabel, FsVolumeInfo->VolumeLabelLength);
+  RtlCopyMemory(FsVolumeInfo->VolumeLabel, DeviceObject->Vpb->VolumeLabel, FsVolumeInfo->VolumeLabelLength);
 
   /* dummy entries */
   FsVolumeInfo->VolumeCreationTime.QuadPart = 0;
@@ -94,7 +95,7 @@
 
   FsAttributeInfo->FileSystemNameLength = Length;
 
-  memcpy(FsAttributeInfo->FileSystemName, pName, Length );
+  RtlCopyMemory(FsAttributeInfo->FileSystemName, pName, Length );
 
   DPRINT("Finished FsdGetFsAttributeInformation()\n");
 
@@ -162,9 +163,140 @@
 FsdSetFsLabelInformation(PDEVICE_OBJECT DeviceObject,
 			 PFILE_FS_LABEL_INFORMATION FsLabelInfo)
 {
+  PDEVICE_EXTENSION DeviceExt;
+  PVOID Context = NULL;
+  ULONG DirIndex = 0;
+  PDIR_ENTRY Entry;
+  PVFATFCB pRootFcb;
+  LARGE_INTEGER FileOffset;
+  BOOL LabelFound = FALSE;
+  DIR_ENTRY VolumeLabelDirEntry;
+  ULONG VolumeLabelDirIndex;
+  ULONG LabelLen;
+  NTSTATUS Status = STATUS_UNSUCCESSFUL;
+  OEM_STRING StringO;
+  UNICODE_STRING StringW;
+  CHAR cString[43];
+  ULONG SizeDirEntry;
+  ULONG EntriesPerPage;
+  
   DPRINT("FsdSetFsLabelInformation()\n");
-
-  return(STATUS_NOT_IMPLEMENTED);
+  
+  DeviceExt = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
+  
+  if (sizeof(DeviceObject->Vpb->VolumeLabel) < FsLabelInfo->VolumeLabelLength)
+  {
+    CHECKPOINT;
+    return STATUS_NAME_TOO_LONG;
+  }
+  
+  if (DeviceExt->Flags & VCB_IS_FATX)
+  {
+    if (FsLabelInfo->VolumeLabelLength / sizeof(WCHAR) > 42)
+      return STATUS_NAME_TOO_LONG;
+    SizeDirEntry = sizeof(FATX_DIR_ENTRY);
+    EntriesPerPage = FATX_ENTRIES_PER_PAGE;
+  }
+  else
+  {
+    if (FsLabelInfo->VolumeLabelLength / sizeof(WCHAR) > 11)
+      return STATUS_NAME_TOO_LONG;
+    SizeDirEntry = sizeof(FAT_DIR_ENTRY);
+    EntriesPerPage = FAT_ENTRIES_PER_PAGE;
+  }
+  
+  /* Create Volume label dir entry */
+  LabelLen = FsLabelInfo->VolumeLabelLength / sizeof(WCHAR);
+  RtlZeroMemory(&VolumeLabelDirEntry, SizeDirEntry);
+  StringW.Buffer = FsLabelInfo->VolumeLabel;
+  StringW.Length = StringW.MaximumLength = FsLabelInfo->VolumeLabelLength;
+  StringO.Buffer = cString;
+  StringO.Length = 0;
+  StringO.MaximumLength = 42;
+  Status = RtlUnicodeStringToOemString(&StringO, &StringW, FALSE);
+  if (!NT_SUCCESS(Status))
+    return Status;
+  if (DeviceExt->Flags & VCB_IS_FATX)
+  {
+    RtlCopyMemory(VolumeLabelDirEntry.FatX.Filename, cString, LabelLen);
+    memset(&VolumeLabelDirEntry.FatX.Filename[LabelLen], ' ', 42 - LabelLen);
+    VolumeLabelDirEntry.FatX.Attrib = 0x08;
+  }
+  else
+  {
+    RtlCopyMemory(VolumeLabelDirEntry.Fat.Filename, cString, LabelLen);
+    memset(&VolumeLabelDirEntry.Fat.Filename[LabelLen], ' ', 11 - LabelLen);
+    VolumeLabelDirEntry.Fat.Attrib = 0x08;
+  }
+  
+  pRootFcb = vfatOpenRootFCB(DeviceExt);
+   
+  /* Search existing volume entry on disk */
+  FileOffset.QuadPart = 0;
+  if (CcMapData(pRootFcb->FileObject, &FileOffset, PAGE_SIZE, TRUE, &Context, (PVOID*)&Entry))
+  {
+    while (TRUE)
+    {
+      if (ENTRY_VOLUME(DeviceExt, Entry))
+      {
+        /* Update entry */
+        LabelFound = TRUE;
+        RtlCopyMemory(Entry, &VolumeLabelDirEntry, SizeDirEntry);
+        CcSetDirtyPinnedData(Context, NULL);
+        Status = STATUS_SUCCESS;
+        break;
+      }
+      if (ENTRY_END(DeviceExt, Entry))
+      {
+        break;
+      }
+      DirIndex++;
+      Entry = (PDIR_ENTRY)((ULONG_PTR)Entry + SizeDirEntry);
+      if ((DirIndex % EntriesPerPage) == 0)
+      {
+	     CcUnpinData(Context);
+	     FileOffset.u.LowPart += PAGE_SIZE;
+	     if (!CcMapData(pRootFcb->FileObject, &FileOffset, PAGE_SIZE, TRUE, &Context, (PVOID*)&Entry))
+	     {
+	       Context = NULL;
+	       break;
+	     }
+      }
+    }
+    if (Context)
+    {
+      CcUnpinData(Context);
+    }
+  }
+  if (!LabelFound)
+  {
+    /* Add new entry for label */
+    if (!vfatFindDirSpace(DeviceExt, pRootFcb, 1, &VolumeLabelDirIndex))
+      Status = STATUS_DISK_FULL;
+    else
+    {
+      FileOffset.u.HighPart = 0;
+      FileOffset.u.LowPart = VolumeLabelDirIndex * SizeDirEntry;
+      CcMapData(pRootFcb->FileObject, &FileOffset, SizeDirEntry,
+                 TRUE, &Context, (PVOID*)&Entry);
+      RtlCopyMemory(Entry, &VolumeLabelDirEntry, SizeDirEntry);
+      CcSetDirtyPinnedData(Context, NULL);
+      CcUnpinData(Context);
+      Status = STATUS_SUCCESS;
+    }
+  }
+  
+  vfatReleaseFCB(DeviceExt, pRootFcb);
+  if (!NT_SUCCESS(Status))
+  {
+    return Status;
+  }
+  
+  /* Update volume label in memory */
+  DeviceObject->Vpb->VolumeLabelLength = FsLabelInfo->VolumeLabelLength;
+  RtlCopyMemory(DeviceObject->Vpb->VolumeLabel, FsLabelInfo->VolumeLabel, DeviceObject->Vpb->VolumeLabelLength);
+  
+  return Status;
 }
 
 
@@ -255,7 +387,7 @@
   /* PRECONDITION */
   ASSERT(IrpContext);
 
-  DPRINT1("VfatSetVolumeInformation(IrpContext %x)\n", IrpContext);
+  DPRINT ("VfatSetVolumeInformation(IrpContext %x)\n", IrpContext);
 
   if (!ExAcquireResourceExclusiveLite(&((PDEVICE_EXTENSION)IrpContext->DeviceObject->DeviceExtension)->DirResource,
                                       (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT)))
@@ -267,9 +399,9 @@
   BufferLength = Stack->Parameters.SetVolume.Length;
   SystemBuffer = IrpContext->Irp->AssociatedIrp.SystemBuffer;
 
-  DPRINT1("FsInformationClass %d\n", FsInformationClass);
-  DPRINT1("BufferLength %d\n", BufferLength);
-  DPRINT1("SystemBuffer %x\n", SystemBuffer);
+  DPRINT ("FsInformationClass %d\n", FsInformationClass);
+  DPRINT ("BufferLength %d\n", BufferLength);
+  DPRINT ("SystemBuffer %x\n", SystemBuffer);
 
   switch(FsInformationClass)
     {
CVSspam 0.2.8