Added some fixes for accessing the page file.
[reactos.git] / reactos / drivers / fs / vfat / create.c
index 65a865c..aa67ad5 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: create.c,v 1.6 2000/07/07 02:14:14 ekohl Exp $
+/* $Id: create.c,v 1.36 2002/01/15 21:54:51 hbirr Exp $
  *
  * COPYRIGHT:        See COPYING in the top level directory
  * PROJECT:          ReactOS kernel
@@ -11,7 +11,6 @@
 /* INCLUDES *****************************************************************/
 
 #include <ddk/ntddk.h>
-#include <ddk/cctypes.h>
 #include <wchar.h>
 #include <limits.h>
 
 
 #include "vfat.h"
 
-/* FUNCTIONS ****************************************************************/
+/* GLOBALS *******************************************************************/
 
-BOOLEAN IsLastEntry(PVOID Block, ULONG Offset)
+#define ENTRIES_PER_PAGE   (PAGESIZE / sizeof (FATDirEntry))
+
+/* FUNCTIONS *****************************************************************/
+
+BOOLEAN
+IsLastEntry (PVOID Block, ULONG Offset)
 /*
  * FUNCTION: Determine if the given directory entry is the last
  */
 {
-   return(((FATDirEntry *)Block)[Offset].Filename[0] == 0);
+  return (((FATDirEntry *) Block)[Offset].Filename[0] == 0);
 }
 
-BOOLEAN IsVolEntry(PVOID Block, ULONG Offset)
+BOOLEAN
+IsVolEntry (PVOID Block, ULONG Offset)
 /*
  * FUNCTION: Determine if the given directory entry is a vol entry
  */
 {
-   if( (((FATDirEntry *)Block)[Offset].Attrib)==0x28 ) return TRUE;
-   else return FALSE;
+  if ((((FATDirEntry *) Block)[Offset].Attrib) == 0x28)
+    return TRUE;
+  else
+    return FALSE;
 }
 
-BOOLEAN IsDeletedEntry(PVOID Block, ULONG Offset)
+BOOLEAN
+IsDeletedEntry (PVOID Block, ULONG Offset)
 /*
  * FUNCTION: Determines if the given entry is a deleted one
  */
 {
-   /* Checks special character */
+  /* Checks special character */
+
+  return ((((FATDirEntry *) Block)[Offset].Filename[0] == 0xe5) ||
+         (((FATDirEntry *) Block)[Offset].Filename[0] == 0));
+}
+
+void  vfat8Dot3ToString (PCHAR pBasename, PCHAR pExtension, PWSTR pName)
+{
+  int  fromIndex, toIndex;
+
+  fromIndex = toIndex = 0; 
+  while (fromIndex < 8 && pBasename [fromIndex] != ' ')
+  {
+    pName [toIndex++] = pBasename [fromIndex++];
+  }
+  if (pExtension [0] != ' ')
+  {
+    pName [toIndex++] = L'.';
+    fromIndex = 0;
+    while (fromIndex < 3 && pExtension [fromIndex] != ' ')
+    {
+      pName [toIndex++] = pExtension [fromIndex++];
+    }
+  }
+  pName [toIndex] = L'\0';
+}
 
-   return ((((FATDirEntry *)Block)[Offset].Filename[0] == 0xe5) || (((FATDirEntry *)Block)[Offset].Filename[0] == 0));
+static void  vfat8Dot3ToVolumeLabel (PCHAR pBasename, PCHAR pExtension, PWSTR pName)
+{
+  int  fromIndex, toIndex;
+
+  fromIndex = toIndex = 0;
+  while (fromIndex < 8 && pBasename [fromIndex] != ' ')
+  {
+    pName [toIndex++] = pBasename [fromIndex++];
+  }
+  if (pExtension [0] != ' ')
+  {
+    fromIndex = 0;
+    while (fromIndex < 3 && pBasename [fromIndex] != ' ')
+    {
+      pName [toIndex++] = pExtension [fromIndex++];
+    }
+  }
+  pName [toIndex] = L'\0';
 }
 
-BOOLEAN GetEntryName(PVOID Block, PULONG _Offset, PWSTR Name, PULONG _jloop,
-  PDEVICE_EXTENSION DeviceExt, ULONG * _StartingSector)
+NTSTATUS
+GetEntryName(PVOID *pContext,
+             PVOID *Block,
+             PFILE_OBJECT FileObject,
+             PWSTR Name,
+             PULONG pIndex,
+             PULONG pIndex2)
 /*
  * FUNCTION: Retrieves the file name, be it in short or long file name format
  */
 {
-   FATDirEntry* test;
-   slot* test2;
-   ULONG Offset = *_Offset;
-   ULONG StartingSector = *_StartingSector;
-   ULONG jloop = *_jloop;
-   ULONG cpos;
-   
-   test = (FATDirEntry *)Block;
-   test2 = (slot *)Block;
-   
-   *Name = 0;
-
-   if (IsDeletedEntry(Block,Offset))
-     {
-       return(FALSE);
-     }
-   
-   if(test2[Offset].attr == 0x0f) 
-     {
-        vfat_initstr(Name, 256);
-       vfat_wcsncpy(Name,test2[Offset].name0_4,5);
-       vfat_wcsncat(Name,test2[Offset].name5_10,5,6);
-       vfat_wcsncat(Name,test2[Offset].name11_12,11,2);
-
-        cpos=0;
-        while((test2[Offset].id!=0x41) && (test2[Offset].id!=0x01) &&
-             (test2[Offset].attr>0)) 
+  NTSTATUS Status;
+  FATDirEntry * test;
+  slot * test2;
+  ULONG cpos;
+  ULONG Offset = *pIndex % ENTRIES_PER_PAGE;
+  ULONG Read;
+  LARGE_INTEGER FileOffset;
+
+  *Name = 0;
+  while (TRUE)
+  {
+    test = (FATDirEntry *) *Block;
+    test2 = (slot *) *Block;
+    if (vfatIsDirEntryEndMarker(&test[Offset]))
+    {
+      return STATUS_NO_MORE_ENTRIES;
+    }
+    if (test2[Offset].attr == 0x0f && !vfatIsDirEntryDeleted(&test[Offset]))
+    {
+      *Name = 0;
+      if (pIndex2)
+        *pIndex2 = *pIndex; // start of dir entry
+
+      DPRINT ("  long name entry found at %d\n", *pIndex);
+
+      DPRINT ("  name chunk1:[%.*S] chunk2:[%.*S] chunk3:[%.*S]\n",
+              5, test2 [Offset].name0_4,
+              6, test2 [Offset].name5_10,
+              2, test2 [Offset].name11_12);
+
+      vfat_initstr (Name, 255);
+      vfat_wcsncpy (Name, test2[Offset].name0_4, 5);
+      vfat_wcsncat (Name, test2[Offset].name5_10, 5, 6);
+      vfat_wcsncat (Name, test2[Offset].name11_12, 11, 2);
+
+      DPRINT ("  longName: [%S]\n", Name);
+      cpos = 0;
+      while ((test2[Offset].id != 0x41) && (test2[Offset].id != 0x01) &&
+        (test2[Offset].attr > 0))
          {
-            Offset++;
-             if(Offset==ENTRIES_PER_SECTOR) {
-               Offset=0;
-               StartingSector++;//FIXME : nor always the next sector
-               jloop++;
-               VFATReadSectors(DeviceExt->StorageDevice,StartingSector,1,Block);
-               test2 = (slot *)Block;
-             }
-             cpos++;
-             vfat_movstr(Name, 13, 0, cpos*13);
-             vfat_wcsncpy(Name, test2[Offset].name0_4, 5);
-             vfat_wcsncat(Name,test2[Offset].name5_10,5,6);
-             vfat_wcsncat(Name,test2[Offset].name11_12,11,2);
-
+           (*pIndex)++;
+        Offset++;
+
+           if (Offset == ENTRIES_PER_PAGE)
+        {
+          Offset = 0;
+          CcUnpinData(*pContext);
+          FileOffset.QuadPart = *pIndex * sizeof(FATDirEntry);
+          if(!CcMapData(FileObject, &FileOffset, PAGESIZE, TRUE, pContext, Block))
+          {
+            *pContext = NULL;
+            return STATUS_NO_MORE_ENTRIES;
           }
-
-       if (IsDeletedEntry(Block,Offset+1))
-         {
-            Offset++;
-            *_Offset = Offset;
-             *_jloop = jloop;
-             *_StartingSector = StartingSector;
-            return(FALSE);
+             test2 = (slot *) *Block;
+        }
+        DPRINT ("  long name entry found at %d\n", *pIndex);
+
+        DPRINT ("  name chunk1:[%.*S] chunk2:[%.*S] chunk3:[%.*S]\n",
+                 5, test2 [Offset].name0_4,
+                 6, test2 [Offset].name5_10,
+                 2, test2 [Offset].name11_12);
+
+           cpos++;
+           vfat_movstr (Name, 13, 0, cpos * 13);
+           vfat_wcsncpy (Name, test2[Offset].name0_4, 5);
+           vfat_wcsncat (Name, test2[Offset].name5_10, 5, 6);
+           vfat_wcsncat (Name, test2[Offset].name11_12, 11, 2);
+
+        DPRINT ("  longName: [%S]\n", Name);
          }
-       
-       *_Offset = Offset;
-        *_jloop = jloop;
-        *_StartingSector = StartingSector;
-       
-       return(TRUE);
-     }   
-      
-   RtlAnsiToUnicode(Name,test[Offset].Filename,8);
-   if (test[Offset].Ext[0]!=' ')
-     {
-       RtlCatAnsiToUnicode(Name,".",1);
-     }
-   RtlCatAnsiToUnicode(Name,test[Offset].Ext,3);
-      
-   *_Offset = Offset;
-   
-   return(TRUE);
+      (*pIndex)++;
+      Offset++;
+         if (Offset == ENTRIES_PER_PAGE)
+      {
+        Offset = 0;
+        CcUnpinData(*pContext);
+        FileOffset.QuadPart = *pIndex * sizeof(FATDirEntry);
+        if(!CcMapData(FileObject, &FileOffset, PAGESIZE, TRUE, pContext, Block))
+         {
+          *pContext = NULL;
+          return STATUS_NO_MORE_ENTRIES;
+        }
+           test2 = (slot *) *Block;
+        test = (FATDirEntry*) *Block;
+      }
+    }
+    else
+    {
+      if (vfatIsDirEntryEndMarker(&test[Offset]))
+        return STATUS_NO_MORE_ENTRIES;
+      if (vfatIsDirEntryDeleted(&test[Offset]))
+        return STATUS_UNSUCCESSFUL;
+      if (*Name == 0)
+      {
+        vfat8Dot3ToString (test[Offset].Filename, test[Offset].Ext, Name);
+        if (pIndex2)
+          *pIndex2 = *pIndex;
+      }
+      break;
+    }
+  }
+  return STATUS_SUCCESS;
 }
 
-NTSTATUS ReadVolumeLabel(PDEVICE_EXTENSION DeviceExt, PVPB Vpb)
+NTSTATUS
+ReadVolumeLabel (PDEVICE_EXTENSION DeviceExt, PVPB Vpb)
 /*
  * FUNCTION: Read the volume label
  */
 {
-   ULONG i = 0;
-   ULONG j;
-   ULONG Size;
-   char* block;
-   ULONG StartingSector;
-   ULONG NextCluster;
-
-   Size = DeviceExt->rootDirectorySectors;//FIXME : in fat32, no limit
-   StartingSector = DeviceExt->rootStart;
-   NextCluster=0;
-
-   block = ExAllocatePool(NonPagedPool,BLOCKSIZE);
-   DPRINT("FindFile : start at sector %lx, entry %ld\n",StartingSector,i);
-   for (j=0; j<Size; j++)
-   {
-     VFATReadSectors(DeviceExt->StorageDevice,StartingSector,1,block);
-
-     for (i=0; i<ENTRIES_PER_SECTOR; i++)
-     {
-       if (IsVolEntry((PVOID)block,i))
-       {
-         FATDirEntry *test = (FATDirEntry *)block;
+  ULONG i = 0;
+  ULONG j;
+  ULONG Size;
+  char *block;
+  ULONG StartingSector;
+  ULONG NextCluster;
+  NTSTATUS Status;
+
+  Size = DeviceExt->rootDirectorySectors;      /* FIXME : in fat32, no limit */
+  StartingSector = DeviceExt->rootStart;
+  NextCluster = 0;
+
+  block = ExAllocatePool (NonPagedPool, BLOCKSIZE);
+  DPRINT ("ReadVolumeLabel : start at sector %lx, entry %ld\n", StartingSector, i);
+  for (j = 0; j < Size; j++)
+    {
+      /* FIXME: Check status */
+      Status = VfatReadSectors (DeviceExt->StorageDevice, StartingSector, 1, block);
+      if (!NT_SUCCESS(Status))
+       {
+         *(Vpb->VolumeLabel) = 0;
+         Vpb->VolumeLabelLength = 0;
+         ExFreePool(block);
+         return(Status);
+       }
 
-         /* copy volume label */
-         RtlAnsiToUnicode(Vpb->VolumeLabel,test[i].Filename,8);
-         RtlCatAnsiToUnicode(Vpb->VolumeLabel,test[i].Ext,3);
-         Vpb->VolumeLabelLength = wcslen(Vpb->VolumeLabel);
+      for (i = 0; i < ENTRIES_PER_SECTOR; i++)
+       {
+         if (IsVolEntry ((PVOID) block, i))
+           {
+             FATDirEntry *test = (FATDirEntry *) block;
+
+             /* copy volume label */
+             vfat8Dot3ToVolumeLabel (test[i].Filename, test[i].Ext, Vpb->VolumeLabel);
+             Vpb->VolumeLabelLength = wcslen (Vpb->VolumeLabel);
+
+             ExFreePool (block);
+             return (STATUS_SUCCESS);
+           }
+         if (IsLastEntry ((PVOID) block, i))
+           {
+             *(Vpb->VolumeLabel) = 0;
+             Vpb->VolumeLabelLength = 0;
+             ExFreePool (block);
+             return (STATUS_UNSUCCESSFUL);
+           }
+       }
+      /* not found in this sector, try next : */
 
-         ExFreePool(block);
-         return(STATUS_SUCCESS);
-       }
-       if (IsLastEntry((PVOID)block,i))
-       {
-         *(Vpb->VolumeLabel) = 0;
-         Vpb->VolumeLabelLength = 0;
-         ExFreePool(block);
-         return(STATUS_UNSUCCESSFUL);
-       }
-     }
-     // not found in this sector, try next :
-
-     /* directory can be fragmented although it is best to keep them
-        unfragmented */
-     StartingSector++;
-     if (DeviceExt->FatType ==FAT32)
-     {
-       if(StartingSector==ClusterToSector(DeviceExt,NextCluster+1))
-       {
-         NextCluster = GetNextCluster(DeviceExt,NextCluster);
-         if (NextCluster == 0||NextCluster==0xffffffff)
-         {
-           *(Vpb->VolumeLabel) = 0;
-           Vpb->VolumeLabelLength = 0;
-           ExFreePool(block);
-           return(STATUS_UNSUCCESSFUL);
-         }
-         StartingSector = ClusterToSector(DeviceExt,NextCluster);
-       }
-     }
-   }
-   *(Vpb->VolumeLabel) = 0;
-   Vpb->VolumeLabelLength = 0;
-   ExFreePool(block);
-   return(STATUS_UNSUCCESSFUL);
-}
+      /* directory can be fragmented although it is best to keep them
+         unfragmented.*/
+      StartingSector++;
 
+      if (DeviceExt->FatType == FAT32)
+       {
+         if (StartingSector == ClusterToSector (DeviceExt, NextCluster + 1))
+           {
+             Status = GetNextCluster (DeviceExt, NextCluster, &NextCluster,
+                                      FALSE);
+             if (NextCluster == 0 || NextCluster == 0xffffffff)
+               {
+                 *(Vpb->VolumeLabel) = 0;
+                 Vpb->VolumeLabelLength = 0;
+                 ExFreePool (block);
+                 return (STATUS_UNSUCCESSFUL);
+               }
+             StartingSector = ClusterToSector (DeviceExt, NextCluster);
+           }
+       }
+    }
+  *(Vpb->VolumeLabel) = 0;
+  Vpb->VolumeLabelLength = 0;
+  ExFreePool (block);
+  return (STATUS_UNSUCCESSFUL);
+}
 
-NTSTATUS FindFile(PDEVICE_EXTENSION DeviceExt, PVFATFCB Fcb,
-          PVFATFCB Parent, PWSTR FileToFind,ULONG *StartSector,ULONG *Entry)
+NTSTATUS
+FindFile (PDEVICE_EXTENSION DeviceExt,
+          PVFATFCB Fcb,
+          PVFATFCB Parent,
+          PWSTR FileToFind,
+          ULONG *pDirIndex,
+          ULONG *pDirIndex2)
 /*
  * FUNCTION: Find a file
  */
 {
-   ULONG i, j;
-   ULONG Size;
-   char* block;
-   WCHAR name[256];
-   ULONG StartingSector;
-   ULONG NextCluster;
-   WCHAR TempStr[2];
-   
-   DPRINT("FindFile(Parent %x, FileToFind '%S')\n",Parent,FileToFind);
-   
-   if (wcslen(FileToFind)==0)
-     {
-       CHECKPOINT;
-       TempStr[0] = (WCHAR)'.';
-       TempStr[1] = 0;
-       FileToFind=(PWSTR)&TempStr;
-     }
-   if (Parent != NULL)
-     {
-       DPRINT("Parent->entry.FirstCluster %d\n",Parent->entry.FirstCluster);
-     }
-   
-   DPRINT("FindFile '%S'\n", FileToFind);
-   if (Parent == NULL||Parent->entry.FirstCluster==1)
-     {
-       CHECKPOINT;
-       Size = DeviceExt->rootDirectorySectors; /* FIXME : in fat32, no limit */
-       StartingSector = DeviceExt->rootStart;
-       NextCluster=0;
-       if(FileToFind[0]==0 ||(FileToFind[0]=='\\' && FileToFind[1]==0) ||
-          (FileToFind[0]=='.' && FileToFind[1]==0))
-         {
-            /* it's root : complete essentials fields then return ok */
-            CHECKPOINT;
-            memset(Fcb,0,sizeof(VFATFCB));
-            memset(Fcb->entry.Filename,' ',11);
-            Fcb->entry.FileSize=DeviceExt->rootDirectorySectors*BLOCKSIZE;
-            Fcb->entry.Attrib=FILE_ATTRIBUTE_DIRECTORY;
-            if (DeviceExt->FatType == FAT32)
-              Fcb->entry.FirstCluster=2;
-            else
-              Fcb->entry.FirstCluster=1; /* FIXME : is 1 the good value for mark root? */
-            if(StartSector)
-              *StartSector=StartingSector;
-            if(Entry)
-              *Entry=0;
-            return(STATUS_SUCCESS);
-         }
-     }
-   else
-     {
-       DPRINT("Parent->entry.FileSize %x\n",Parent->entry.FileSize);
-       
-       Size = ULONG_MAX;
-       if (DeviceExt->FatType == FAT32)
-         NextCluster = Parent->entry.FirstCluster
-         +Parent->entry.FirstClusterHigh*65536;
-       else
-         NextCluster = Parent->entry.FirstCluster;
-       StartingSector = ClusterToSector(DeviceExt, NextCluster);
-       if(Parent->entry.FirstCluster==1 && DeviceExt->FatType!=FAT32)
-         {
-            /* read of root directory in FAT16 or FAT12 */
-            StartingSector=DeviceExt->rootStart;
-         }
-     }
-   CHECKPOINT;
-   block = ExAllocatePool(NonPagedPool,BLOCKSIZE);
-   CHECKPOINT;
-   if (StartSector && (*StartSector)) StartingSector=*StartSector;
-   i=(Entry)?(*Entry):0;
-   DPRINT("FindFile : start at sector %lx, entry %ld\n",StartingSector,i);
-   for (j=0; j<Size; j++)
-     {
-       VFATReadSectors(DeviceExt->StorageDevice,StartingSector,1,block);
-       
-       for (i=(Entry)?(*Entry):0; i<ENTRIES_PER_SECTOR; i++)
-         {
-            if (IsVolEntry((PVOID)block,i))
-              continue;
-            if (IsLastEntry((PVOID)block,i))
-              {
-                 if(StartSector) *StartSector=StartingSector;
-                 if(Entry) *Entry=i;
-                 ExFreePool(block);
-                 return(STATUS_UNSUCCESSFUL);
-              }
-            if (GetEntryName((PVOID)block,&i,name,&j,DeviceExt,&StartingSector))
-              {
-                 DPRINT("Comparing '%S' '%S'\n",name,FileToFind);
-                 if (wstrcmpjoki(name,FileToFind))
-                   {
-                      /* In the case of a long filename, the firstcluster is stored in
-                       the next record -- where it's short name is */
-                      if(((FATDirEntry *)block)[i].Attrib==0x0f) i++;
-                      if( i==(ENTRIES_PER_SECTOR))
-                        {
-                           /* entry is in next sector */
-                           StartingSector++;
-                           /* FIXME : treat case of next sector fragmented */
-                           VFATReadSectors(DeviceExt->StorageDevice,StartingSector,1,block);
-                           i=0;
-                        }
-                      memcpy(&Fcb->entry,&((FATDirEntry *)block)[i],
-                             sizeof(FATDirEntry));
-                      vfat_wcsncpy(Fcb->ObjectName,name,MAX_PATH);
-                      if(StartSector) *StartSector=StartingSector;
-                      if(Entry) *Entry=i;
-                      ExFreePool(block);
-                      return(STATUS_SUCCESS);
-                   }
-              }
-         }
-       /* not found in this sector, try next : */
-       
-       /* directory can be fragmented although it is best to keep them
-        unfragmented */
-       if(Entry) *Entry=0;
-       StartingSector++;
-       if ((Parent != NULL && Parent->entry.FirstCluster!=1)
-           || DeviceExt->FatType ==FAT32)
+  WCHAR name[256];
+  WCHAR name2[14];
+  char * block;
+  WCHAR TempStr[2];
+  NTSTATUS Status;
+  ULONG len;
+  ULONG DirIndex;
+  ULONG Offset;
+  ULONG FirstCluster;
+  ULONG Read;
+  BOOL isRoot;
+  LARGE_INTEGER FileOffset;
+  PVOID Context = NULL;
+
+  DPRINT ("FindFile(Parent %x, FileToFind '%S', DirIndex: %d)\n", Parent, FileToFind, pDirIndex ? *pDirIndex : 0);
+  DPRINT ("FindFile: old Pathname %x, old Objectname %x)\n",Fcb->PathName, Fcb->ObjectName);
+
+  isRoot = FALSE;
+  DirIndex = 0;
+  if (wcslen (FileToFind) == 0)
+  {
+    CHECKPOINT;
+    TempStr[0] = (WCHAR) '.';
+    TempStr[1] = 0;
+    FileToFind = (PWSTR)&TempStr;
+  }
+  if (Parent)
+  {
+    FirstCluster = vfatDirEntryGetFirstCluster(DeviceExt, &Parent->entry);
+    if (DeviceExt->FatType == FAT32)
+    {
+      if (FirstCluster == ((struct _BootSector32*)(DeviceExt->Boot))->RootCluster)
+        isRoot = TRUE;
+    }
+    else
+    {
+      if (FirstCluster == 1)
+        isRoot = TRUE;
+    }
+  }
+  else
+    isRoot = TRUE;
+  if (isRoot)
+  {
+    if (DeviceExt->FatType == FAT32)
+      FirstCluster = ((struct _BootSector32*)(DeviceExt->Boot))->RootCluster;
+    else
+      FirstCluster = 1;
+
+    if (FileToFind[0] == 0 || (FileToFind[0] == '\\' && FileToFind[1] == 0)
+           || (FileToFind[0] == '.' && FileToFind[1] == 0))
+       {
+         /* it's root : complete essentials fields then return ok */
+         CHECKPOINT;
+         memset (Fcb, 0, sizeof (VFATFCB));
+         memset (Fcb->entry.Filename, ' ', 11);
+         CHECKPOINT;
+         Fcb->PathName[0]='\\';
+         Fcb->ObjectName = &Fcb->PathName[1];
+         Fcb->entry.FileSize = DeviceExt->rootDirectorySectors * BLOCKSIZE;
+         Fcb->entry.Attrib = FILE_ATTRIBUTE_DIRECTORY;
+         if (DeviceExt->FatType == FAT32)
+      {
+           Fcb->entry.FirstCluster = ((PUSHORT)FirstCluster)[0];
+        Fcb->entry.FirstClusterHigh = ((PUSHORT)FirstCluster)[1];
+      }
+         else
+           Fcb->entry.FirstCluster = 1;
+         if (pDirIndex)
+           *pDirIndex = 0;
+      if (pDirIndex2)
+        *pDirIndex2 = 0;
+         DPRINT("FindFile: new Pathname %S, new Objectname %S)\n",Fcb->PathName, Fcb->ObjectName);
+         return (STATUS_SUCCESS);
+       }
+  }
+  else
+  {
+    DPRINT ("Parent->entry.FileSize %x\n", Parent->entry.FileSize);
+    FirstCluster = vfatDirEntryGetFirstCluster (DeviceExt, &Parent->entry);
+  }
+  if (pDirIndex && (*pDirIndex))
+    DirIndex = *pDirIndex;
+
+  Offset = DirIndex % ENTRIES_PER_PAGE;
+  while(TRUE)
+  {
+    if (Context == NULL || Offset == ENTRIES_PER_PAGE)
+    {
+      if (Offset == ENTRIES_PER_PAGE)
+        Offset = 0;
+      if (Context)
+      {
+        CcUnpinData(Context);
+      }
+      FileOffset.QuadPart = (DirIndex - Offset) * sizeof(FATDirEntry);
+      if (!CcMapData(Parent->FileObject, &FileOffset, PAGESIZE, TRUE,
+             &Context, (PVOID*)&block))
+      {
+         Context = NULL;
+         break;
+      }
+    }
+       if (vfatIsDirEntryVolume(&((FATDirEntry*)block)[Offset]))
+    {
+      Offset++;
+      DirIndex++;
+         continue;
+    }
+    Status = GetEntryName (&Context, (PVOID*)&block, Parent->FileObject, name,
+                           &DirIndex, pDirIndex2);
+    if (Status == STATUS_NO_MORE_ENTRIES)
+      break;
+    Offset = DirIndex % ENTRIES_PER_PAGE;
+    if (NT_SUCCESS(Status))
+       {
+      vfat8Dot3ToString(((FATDirEntry *) block)[Offset].Filename,((FATDirEntry *) block)[Offset].Ext, name2);
+         if (wstrcmpjoki (name, FileToFind) || wstrcmpjoki (name2, FileToFind))
          {
-            if(StartingSector==ClusterToSector(DeviceExt,NextCluster+1))
-              {
-                 NextCluster = GetNextCluster(DeviceExt,NextCluster);
-                 if (NextCluster == 0||NextCluster==0xffffffff)
-                   {
-                      if(StartSector) *StartSector=StartingSector;
-                      if(Entry) *Entry=i;
-                      ExFreePool(block);
-                      return(STATUS_UNSUCCESSFUL);
-                   }
-                 StartingSector = ClusterToSector(DeviceExt,NextCluster);
-              }
+           if (Parent && Parent->PathName)
+               {
+                 len = wcslen(Parent->PathName);
+                 CHECKPOINT;
+                 memcpy(Fcb->PathName, Parent->PathName, len*sizeof(WCHAR));
+                 Fcb->ObjectName=&Fcb->PathName[len];
+                 if (len != 1 || Fcb->PathName[0] != '\\')
+                 {
+                   Fcb->ObjectName[0] = '\\';
+                       Fcb->ObjectName = &Fcb->ObjectName[1];
+                 }
+               }
+               else
+               {
+                 Fcb->ObjectName=Fcb->PathName;
+                 Fcb->ObjectName[0]='\\';
+                 Fcb->ObjectName=&Fcb->ObjectName[1];
+               }
+
+               memcpy (&Fcb->entry, &((FATDirEntry *) block)[Offset],
+                            sizeof (FATDirEntry));
+               vfat_wcsncpy (Fcb->ObjectName, name, MAX_PATH);
+               if (pDirIndex)
+                 *pDirIndex = DirIndex;
+         DPRINT("FindFile: new Pathname %S, new Objectname %S, DirIndex %d\n",Fcb->PathName, Fcb->ObjectName, DirIndex);
+               if (Context)
+                 CcUnpinData(Context);
+               return STATUS_SUCCESS;
          }
-     }
-   if(StartSector) *StartSector=StartingSector;
-   if(Entry) *Entry=i;
-   ExFreePool(block);
-   return(STATUS_UNSUCCESSFUL);
+    }
+    Offset++;
+    DirIndex++;
+  }
+  if (pDirIndex)
+       *pDirIndex = DirIndex;
+  if (Context)
+    CcUnpinData(Context);
+  return (STATUS_UNSUCCESSFUL);
 }
 
+NTSTATUS
+vfatMakeAbsoluteFilename (PFILE_OBJECT pFileObject,
+                          PWSTR pRelativeFileName,
+                          PWSTR *pAbsoluteFilename)
+{
+  PWSTR  rcName;
+  PVFATFCB  fcb;
+  PVFATCCB  ccb;
+
+  DbgPrint ("try related for %S\n", pRelativeFileName);
+  ccb = pFileObject->FsContext2;
+  assert (ccb);
+  fcb = ccb->pFcb;
+  assert (fcb);
+
+  /* verify related object is a directory and target name
+     don't start with \. */
+  if (!(fcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY)
+      || (pRelativeFileName[0] != '\\'))
+  {
+    return  STATUS_INVALID_PARAMETER;
+  }
+
+  /* construct absolute path name */
+  assert (wcslen (fcb->PathName) + 1 + wcslen (pRelativeFileName) + 1
+          <= MAX_PATH);
+  rcName = ExAllocatePool (NonPagedPool, MAX_PATH);
+  wcscpy (rcName, fcb->PathName);
+  wcscat (rcName, L"\\");
+  wcscat (rcName, pRelativeFileName);
+  *pAbsoluteFilename = rcName;
+
+  return  STATUS_SUCCESS;
+}
 
-
-NTSTATUS FsdOpenFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject, 
-                    PWSTR FileName)
+NTSTATUS
+VfatOpenFile (PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject,
+            PWSTR FileName)
 /*
  * FUNCTION: Opens a file
  */
 {
-   PWSTR current = NULL;
-   PWSTR next;
-   PWSTR string;
-   PVFATFCB ParentFcb;
-   PVFATFCB Fcb,pRelFcb;
-   PVFATFCB Temp;
-   PVFATCCB newCCB,pRelCcb;
-   NTSTATUS Status;
-   PFILE_OBJECT pRelFileObject;
-   PWSTR AbsFileName=NULL;
-   short i,j;
-   PLIST_ENTRY current_entry;
-   KIRQL oldIrql;
-   
-   DPRINT("FsdOpenFile(%08lx, %08lx, %S)\n", 
-          DeviceExt,
-          FileObject,
-          FileName);
-   
-   /* FIXME : treat relative name */
-   if(FileObject->RelatedFileObject)
-   {
-     DbgPrint("try related for %S\n",FileName);
-     pRelFileObject=FileObject->RelatedFileObject;
-     pRelCcb=pRelFileObject->FsContext2;
-     assert(pRelCcb);
-     pRelFcb=pRelCcb->pFcb;
-     assert(pRelFcb);
-     /*
-      * verify related object is a directory and target name don't start with \.
-      */
-     if( !(pRelFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY)
-         || (FileName[0]!= '\\') )
-     {
-       Status=STATUS_INVALID_PARAMETER;
-       return Status;
-     }
-     /* construct absolute path name */
-     AbsFileName=ExAllocatePool(NonPagedPool,MAX_PATH);
-     for (i=0;pRelFcb->PathName[i];i++)
-       AbsFileName[i]=pRelFcb->PathName[i];
-     AbsFileName[i++]='\\';
-     for (j=0;FileName[j]&&i<MAX_PATH;j++)
-       AbsFileName[i++]=FileName[j];
-     assert(i<MAX_PATH);
-     AbsFileName[i]=0;
-     FileName=AbsFileName;
-   }
-
-   /*
-    * try first to find an existing FCB in memory
-    */
-   CHECKPOINT;
-   
-   KeAcquireSpinLock(&DeviceExt->FcbListLock, &oldIrql);
-   current_entry = DeviceExt->FcbListHead.Flink;
-   while (current_entry != &DeviceExt->FcbListHead)
-     {
-       Fcb = CONTAINING_RECORD(current_entry, VFATFCB, FcbListEntry);
-
-       DPRINT("Scanning %x\n", Fcb);
-       DPRINT("Scanning %S\n", Fcb->PathName);
-       
-       if (DeviceExt==Fcb->pDevExt
-           && wstrcmpi(FileName,Fcb->PathName))
-         {
-            Fcb->RefCount++;
-            KeReleaseSpinLock(&DeviceExt->FcbListLock, oldIrql);
-            FileObject->FsContext =(PVOID) &Fcb->NTRequiredFCB;
-            newCCB = ExAllocatePool(NonPagedPool,sizeof(VFATCCB));
-            memset(newCCB,0,sizeof(VFATCCB));
-            FileObject->FsContext2 = newCCB;
-            newCCB->pFcb=Fcb;
-            newCCB->PtrFileObject=FileObject;
-            if(AbsFileName)ExFreePool(AbsFileName);
-            return(STATUS_SUCCESS);
-         }
-       
-       current_entry = current_entry->Flink;
-     }
-   KeReleaseSpinLock(&DeviceExt->FcbListLock, oldIrql);
-
-CHECKPOINT;
-DPRINT("FileName %S\n", FileName);
-
-   string = FileName;
-   ParentFcb = NULL;
-   Fcb = ExAllocatePool(NonPagedPool, sizeof(VFATFCB));
-   memset(Fcb,0,sizeof(VFATFCB));
-   Fcb->ObjectName=Fcb->PathName;
-   next = &string[0];
-   
-   CHECKPOINT;
-   while (TRUE)
-   {
-      CHECKPOINT;
-      *next = '\\';
-      current = next+1;
-      next = wcschr(next+1,'\\');
-      if (next!=NULL)
+  PVFATFCB ParentFcb;
+  PVFATFCB Fcb;
+  NTSTATUS Status;
+  PWSTR AbsFileName = NULL;
+
+  DPRINT ("VfatOpenFile(%08lx, %08lx, %S)\n", DeviceExt, FileObject, FileName);
+
+  if (FileObject->RelatedFileObject)
+    {
+      DPRINT ("Converting relative filename to absolute filename\n");
+      Status = vfatMakeAbsoluteFilename (FileObject->RelatedFileObject,
+                                         FileName,
+                                         &AbsFileName);
+      FileName = AbsFileName;
+    }
+
+  //FIXME: Get cannonical path name (remove .'s, ..'s and extra separators)
+
+  DPRINT ("PathName to open: %S\n", FileName);
+
+  /*  try first to find an existing FCB in memory  */
+  DPRINT ("Checking for existing FCB in memory\n");
+  Fcb = vfatGrabFCBFromTable (DeviceExt, FileName);
+  if (Fcb == NULL)
+  {
+    DPRINT ("No existing FCB found, making a new one if file exists.\n");
+    Status = vfatGetFCBForFile (DeviceExt, &ParentFcb, &Fcb, FileName);
+    if (ParentFcb != NULL)
+    {
+      vfatReleaseFCB (DeviceExt, ParentFcb);
+    }
+    if (!NT_SUCCESS (Status))
+    {
+      DPRINT ("Could not make a new FCB, status: %x\n", Status);
+
+      if (AbsFileName)
+        ExFreePool (AbsFileName);
+
+      return  Status;
+    }
+  }
+  if (Fcb->Flags & FCB_DELETE_PENDING)
+  {
+    vfatReleaseFCB (DeviceExt, Fcb);
+    if (AbsFileName)
+      ExFreePool (AbsFileName);
+    return STATUS_DELETE_PENDING;
+  }
+  DPRINT ("Attaching FCB to fileObject\n");
+  Status = vfatAttachFCBToFileObject (DeviceExt, Fcb, FileObject);
+
+  if (AbsFileName)
+    ExFreePool (AbsFileName);
+
+  return  Status;
+}
+
+NTSTATUS
+VfatCreateFile (PDEVICE_OBJECT DeviceObject, PIRP Irp)
+/*
+ * FUNCTION: Create or open a file
+ */
+{
+  PIO_STACK_LOCATION Stack;
+  PFILE_OBJECT FileObject;
+  NTSTATUS Status = STATUS_SUCCESS;
+  PDEVICE_EXTENSION DeviceExt;
+  ULONG RequestedDisposition, RequestedOptions;
+  PVFATCCB pCcb;
+  PVFATFCB pFcb;
+  PWCHAR c;
+  BOOLEAN PagingFileCreate = FALSE;
+
+  Stack = IoGetCurrentIrpStackLocation (Irp);
+  assert (Stack);
+  RequestedDisposition = ((Stack->Parameters.Create.Options >> 24) & 0xff);
+  RequestedOptions =
+    Stack->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS;
+  PagingFileCreate = (Stack->Flags & SL_OPEN_PAGING_FILE) ? TRUE : FALSE;
+  if ((RequestedOptions & FILE_DIRECTORY_FILE)
+      && RequestedDisposition == FILE_SUPERSEDE)
+    return STATUS_INVALID_PARAMETER;
+  FileObject = Stack->FileObject;
+  DeviceExt = DeviceObject->DeviceExtension;
+  assert (DeviceExt);
+
+  /*
+   * Check for illegal characters in the file name
+   */
+  c = FileObject->FileName.Buffer;
+  while (*c != 0)
+    {
+      if (*c == L'*' || *c == L'?' || (*c == L'\\' && c[1] == L'\\'))
        {
-          *next=0;
+         Irp->IoStatus.Information = 0;
+         Irp->IoStatus.Status = STATUS_OBJECT_NAME_INVALID;
+         return(STATUS_OBJECT_NAME_INVALID);
        }
-      else
+      c++;
+    }
+
+  Status = VfatOpenFile (DeviceExt, FileObject, FileObject->FileName.Buffer);
+
+  /*
+   * If the directory containing the file to open doesn't exist then
+   * fail immediately
+   */
+  Irp->IoStatus.Information = 0;
+  if (Status == STATUS_OBJECT_PATH_NOT_FOUND)
+    {
+      Irp->IoStatus.Status = Status;
+      return Status;
+    }
+
+  if (Status == STATUS_DELETE_PENDING)
+  {
+    Irp->IoStatus.Status = Status;
+    return Status;
+  }
+  if (!NT_SUCCESS (Status))
+    {
+      /*
+       * If the file open failed then create the required file
+       */
+      if (RequestedDisposition == FILE_CREATE ||
+         RequestedDisposition == FILE_OPEN_IF ||
+         RequestedDisposition == FILE_OVERWRITE_IF ||
+         RequestedDisposition == FILE_SUPERSEDE)
        {
-          /* reached the last path component */
-          DPRINT("exiting: current '%S'\n",current);
-          break;
+         CHECKPOINT;
+         Status =
+           addEntry (DeviceExt, FileObject, RequestedOptions,
+                     (Stack->Parameters.
+                      Create.FileAttributes & FILE_ATTRIBUTE_VALID_FLAGS));
+         if (NT_SUCCESS (Status))
+         {
+               if (PagingFileCreate)
+               {
+                 DPRINT("Creating a new paging file.\n");
+                 pCcb = FileObject->FsContext2;
+                 pFcb = pCcb->pFcb;
+             pFcb->Flags |= FCB_IS_PAGE_FILE;
+             pFcb->FatChainSize = 0;
+                 pFcb->FatChain = NULL;
+               }
+
+           Irp->IoStatus.Information = FILE_CREATED;
+         }
+         /* FIXME set size if AllocationSize requested */
+         /* FIXME set extended attributes? */
+         /* FIXME set share access */
+         /* IoSetShareAccess(DesiredAccess,ShareAccess,FileObject,
+          * ((PVfatCCB)(FileObject->FsContext2))->pFcb->FCBShareAccess);
+          */
        }
-
-      DPRINT("current '%S'\n",current);
-      Status = FindFile(DeviceExt,Fcb,ParentFcb,current,NULL,NULL);
-      if (Status != STATUS_SUCCESS)
+    }
+  else
+  {
+    /*
+     * Otherwise fail if the caller wanted to create a new file
+     */
+    if (RequestedDisposition == FILE_CREATE)
        {
-          CHECKPOINT;
-          if (Fcb != NULL)
-            ExFreePool(Fcb);
-          if (ParentFcb != NULL)
-            ExFreePool(ParentFcb);
-          if(AbsFileName)
-            ExFreePool(AbsFileName);
-
-          DPRINT("error STATUS_OBJECT_PATH_NOT_FOUND\n");
-          return STATUS_OBJECT_PATH_NOT_FOUND;
+         Irp->IoStatus.Information = FILE_EXISTS;
+         Status = STATUS_OBJECT_NAME_COLLISION;
        }
-      Temp = Fcb;
-CHECKPOINT;
-      if (ParentFcb == NULL)
+    pCcb = FileObject->FsContext2;
+    pFcb = pCcb->pFcb;
+    /*
+     * If requested then delete the file and create a new one with the
+     * same name
+     */
+    if (RequestedDisposition == FILE_SUPERSEDE)
+    {
+       ULONG Cluster, NextCluster;
+       /* FIXME set size to 0 and free clusters */
+       pFcb->entry.FileSize = 0;
+       if (DeviceExt->FatType == FAT32)
+           Cluster = pFcb->entry.FirstCluster
+             + pFcb->entry.FirstClusterHigh * 65536;
+       else
+         Cluster = pFcb->entry.FirstCluster;
+       pFcb->entry.FirstCluster = 0;
+       pFcb->entry.FirstClusterHigh = 0;
+       updEntry (DeviceExt, FileObject);
+       if ((ULONG)pFcb->RFCB.FileSize.QuadPart > 0)
+       {
+         pFcb->RFCB.AllocationSize.QuadPart = 0;
+        pFcb->RFCB.FileSize.QuadPart = 0;
+        pFcb->RFCB.ValidDataLength.QuadPart = 0;
+        CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&pFcb->RFCB.AllocationSize);
+       }
+       while (Cluster != 0xffffffff && Cluster > 1)
+       {
+        Status = GetNextCluster (DeviceExt, Cluster, &NextCluster, FALSE);
+        WriteCluster (DeviceExt, Cluster, 0);
+        Cluster = NextCluster;
+       }
+    }
+
+    /*
+     * If this create was for a paging file then make sure all the
+     * information needed to manipulate it is locked in memory.
+     */
+    if (PagingFileCreate)
+      {
+       ULONG CurrentCluster, NextCluster, i;
+       DPRINT("Open an existing paging file\n");
+       pFcb->Flags |= FCB_IS_PAGE_FILE;
+       pFcb->FatChainSize = 
+         ((pFcb->entry.FileSize + DeviceExt->BytesPerCluster - 1) / DeviceExt->BytesPerCluster);
+       if (pFcb->FatChainSize)
        {
-          CHECKPOINT;
-          Fcb = ExAllocatePool(NonPagedPool,sizeof(VFATFCB));
-          memset(Fcb,0,sizeof(VFATFCB));
-          Fcb->ObjectName=Fcb->PathName;
+         pFcb->FatChain = ExAllocatePool(NonPagedPool, 
+                                       pFcb->FatChainSize * sizeof(ULONG));
        }
-      else
-        Fcb = ParentFcb;
-CHECKPOINT;
-      ParentFcb = Temp;
-   }
-
-   /* searching for last path component */
-   DPRINT("current '%S'\n",current);
-   Status = FindFile(DeviceExt,Fcb,ParentFcb,current,NULL,NULL);
-   if (Status != STATUS_SUCCESS)
-     {
-       /* file does not exist */
-       CHECKPOINT;
-       if (Fcb != NULL)
-         ExFreePool(Fcb);
-       if (ParentFcb != NULL)
-         ExFreePool(ParentFcb);
-       if(AbsFileName)
-         ExFreePool(AbsFileName);
-
-       return STATUS_OBJECT_NAME_NOT_FOUND;
-     }
-
-   Temp = Fcb;
-CHECKPOINT;
-   if (ParentFcb == NULL)
-     {
-       CHECKPOINT;
-       Fcb = ExAllocatePool(NonPagedPool,sizeof(VFATFCB));
-       memset(Fcb,0,sizeof(VFATFCB));
-       Fcb->ObjectName=Fcb->PathName;
-     }
-   else
-     Fcb = ParentFcb;
-CHECKPOINT;
-   ParentFcb = Temp;
-
-
-CHECKPOINT;
-   FileObject->FsContext =(PVOID) &ParentFcb->NTRequiredFCB;
-   newCCB = ExAllocatePool(NonPagedPool,sizeof(VFATCCB));
-   memset(newCCB,0,sizeof(VFATCCB));
-   FileObject->FsContext2 = newCCB;
-   newCCB->pFcb=ParentFcb;
-   newCCB->PtrFileObject=FileObject;
-   ParentFcb->RefCount++;
-   //FIXME : initialize all fields in FCB and CCB
-   
-   KeAcquireSpinLock(&DeviceExt->FcbListLock, &oldIrql);
-   InsertTailList(&DeviceExt->FcbListHead, &ParentFcb->FcbListEntry);
-   KeReleaseSpinLock(&DeviceExt->FcbListLock, oldIrql);
-   
-   vfat_wcsncpy(ParentFcb->PathName,FileName,MAX_PATH);
-   ParentFcb->ObjectName=ParentFcb->PathName+(current-FileName);
-   ParentFcb->pDevExt=DeviceExt;
-   DPRINT("file open, fcb=%x\n",ParentFcb);
-   DPRINT("FileSize %d\n",ParentFcb->entry.FileSize);
-   if(Fcb)
-     ExFreePool(Fcb);
-   if(AbsFileName)
-     ExFreePool(AbsFileName);
-   CHECKPOINT;
-
-   return(STATUS_SUCCESS);
-}
 
+       if (DeviceExt->FatType == FAT32)
+         {
+           CurrentCluster = pFcb->entry.FirstCluster + 
+             pFcb->entry.FirstClusterHigh * 65536;
+         }
+       else
+         {
+           CurrentCluster = pFcb->entry.FirstCluster;
+         }
 
-NTSTATUS FsdCreateFile (PDEVICE_OBJECT DeviceObject, PIRP Irp)
-/*
- * FUNCTION: Create or open a file
- */
-{
-   PIO_STACK_LOCATION Stack;
-   PFILE_OBJECT FileObject;
-   NTSTATUS Status=STATUS_SUCCESS;
-   PDEVICE_EXTENSION DeviceExt;
-   ULONG RequestedDisposition,RequestedOptions;
-   PVFATCCB pCcb;
-   PVFATFCB pFcb;
-
-   Stack = IoGetCurrentIrpStackLocation(Irp);
-   assert(Stack);
-   RequestedDisposition = ((Stack->Parameters.Create.Options>>24)&0xff);
-   RequestedOptions=Stack->Parameters.Create.Options&FILE_VALID_OPTION_FLAGS;
-   FileObject = Stack->FileObject;
-   DeviceExt = DeviceObject->DeviceExtension;
-   assert(DeviceExt);
-
-   Status = FsdOpenFile(DeviceExt,FileObject,FileObject->FileName.Buffer);
-
-   CHECKPOINT;
-   Irp->IoStatus.Information = 0;
-   if (Status == STATUS_OBJECT_PATH_NOT_FOUND)
-     {
-       Irp->IoStatus.Status = Status;
-       return Status;
-     }
-
-   CHECKPOINT;
-   if(!NT_SUCCESS(Status))
-     {
-      if(RequestedDisposition==FILE_CREATE
-         ||RequestedDisposition==FILE_OPEN_IF
-         ||RequestedDisposition==FILE_OVERWRITE_IF)
-      {
-CHECKPOINT;
-         Status=addEntry(DeviceExt,FileObject,RequestedOptions
-             ,(Stack->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_VALID_FLAGS));
-         if(NT_SUCCESS(Status))
-           Irp->IoStatus.Information = FILE_CREATED;
-         // FIXME set size if AllocationSize requested
-         // FIXME set extended attributes ?
-         // FIXME set share access
-         // IoSetShareAccess(DesiredAccess,ShareAccess,FileObject
-         //   ,((PVfatCCB)(FileObject->FsContext2))->pFcb->FCBShareAccess);
+       i = 0;
+       if (pFcb->FatChainSize)
+       {
+               while (CurrentCluster != 0xffffffff)
+               {
+                 pFcb->FatChain[i] = CurrentCluster;   
+             Status = GetNextCluster (DeviceExt, CurrentCluster, &NextCluster, 
+                                    FALSE);
+             i++;
+             CurrentCluster = NextCluster;
+               }
       }
-   }
-   else
-   {
-     if(RequestedDisposition==FILE_CREATE)
-     {
-       Irp->IoStatus.Information = FILE_EXISTS;
-       Status=STATUS_OBJECT_NAME_COLLISION;
-     }
-     pCcb=FileObject->FsContext2;
-     pFcb=pCcb->pFcb;
-     if( (RequestedOptions&FILE_NON_DIRECTORY_FILE)
-         && (pFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
-     {
-       Status=STATUS_FILE_IS_A_DIRECTORY;
-     }
-     if( (RequestedOptions&FILE_DIRECTORY_FILE)
-         && !(pFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
-     {
-       Status=STATUS_NOT_A_DIRECTORY;
-     }
-     // FIXME : test share access
-     // FIXME : test write access if requested
-     if(!NT_SUCCESS(Status))
-       FsdCloseFile(DeviceExt,FileObject);
-     else Irp->IoStatus.Information = FILE_OPENED;
-     // FIXME : make supersed or overwrite if requested
-   }
-
-CHECKPOINT;
-   Irp->IoStatus.Status = Status;
-
-   return Status;
+       }
+
+    /*
+     * Check the file has the requested attributes
+     */
+    if ((RequestedOptions & FILE_NON_DIRECTORY_FILE)
+         && (pFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
+       {
+         Status = STATUS_FILE_IS_A_DIRECTORY;
+       }
+    if ((RequestedOptions & FILE_DIRECTORY_FILE)
+         && !(pFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
+       {
+         Status = STATUS_NOT_A_DIRECTORY;
+       }
+    /* FIXME : test share access */
+      /* FIXME : test write access if requested */
+    if (!NT_SUCCESS (Status))
+         VfatCloseFile (DeviceExt, FileObject);
+    else
+         Irp->IoStatus.Information = FILE_OPENED;
+      /* FIXME : make supersed or overwrite if requested */
+  }
+
+  Irp->IoStatus.Status = Status;
+
+  return Status;
 }
 
 
-NTSTATUS FsdCreate(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+NTSTATUS VfatCreate (PVFAT_IRP_CONTEXT IrpContext)
 /*
  * FUNCTION: Create or open a file
  */
 {
-   NTSTATUS Status=STATUS_SUCCESS;
-   PDEVICE_EXTENSION DeviceExt;
-
-   assert(DeviceObject);
-   assert(Irp);
-
-   if (DeviceObject->Size==sizeof(DEVICE_OBJECT))
-   {
-      /* DeviceObject represent FileSystem instead of  logical volume */
-      DbgPrint("FsdCreate called with file system\n");
-      Irp->IoStatus.Status=Status;
-      Irp->IoStatus.Information=FILE_OPENED;
-      IoCompleteRequest(Irp,IO_NO_INCREMENT);
-      return(Status);
-   }
-
-   DeviceExt = DeviceObject->DeviceExtension;
-   assert(DeviceExt);
-   ExAcquireResourceExclusiveLite(&DeviceExt->DirResource, TRUE);
-
-   Status = FsdCreateFile (DeviceObject, Irp);
-
-   ExReleaseResourceLite(&DeviceExt->DirResource);
-
-   Irp->IoStatus.Status = Status;
-   IoCompleteRequest(Irp, IO_NO_INCREMENT);
-
-   return Status;
+  NTSTATUS Status;
+
+  assert (IrpContext);
+
+  if (IrpContext->DeviceObject->Size == sizeof (DEVICE_OBJECT))
+  {
+     /* DeviceObject represents FileSystem instead of logical volume */
+     DbgPrint ("FsdCreate called with file system\n");
+     IrpContext->Irp->IoStatus.Information = FILE_OPENED;
+     Status = STATUS_SUCCESS;
+     goto ByeBye;
+  }
+
+  if (!(IrpContext->Flags & IRPCONTEXT_CANWAIT))
+  {
+     return VfatQueueRequest (IrpContext);
+  }
+
+  ExAcquireResourceExclusiveLite (&IrpContext->DeviceExt->DirResource, TRUE);
+  Status = VfatCreateFile (IrpContext->DeviceObject, IrpContext->Irp);
+  ExReleaseResourceLite (&IrpContext->DeviceExt->DirResource);
+
+ByeBye:
+  IrpContext->Irp->IoStatus.Status = Status;
+  IoCompleteRequest (IrpContext->Irp, NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT);
+  VfatFreeIrpContext(IrpContext);
+  return Status;
 }
 
 /* EOF */