Reworked code for handling of asynchonous i/o requests.
[reactos.git] / reactos / drivers / fs / vfat / iface.c
index 5b34a68..efd37ce 100644 (file)
-/*
+/* $Id: iface.c,v 1.59 2001/11/02 22:47:36 hbirr Exp $
+ *
  * COPYRIGHT:        See COPYING in the top level directory
  * PROJECT:          ReactOS kernel
  * FILE:             services/fs/vfat/iface.c
  * PURPOSE:          VFAT Filesystem
  * PROGRAMMER:       Jason Filby (jasonfilby@yahoo.com)
  * UPDATE HISTORY:
-     ??           Created
-     24-10-1998   Fixed bugs in long filename support
-                  Fixed a bug that prevented unsuccessful file open requests being reported
-                  Now works with long filenames that span over a sector boundary
-     28-10-1998   Reads entire FAT into memory
-                  VFatReadSector modified to read in more than one sector at a time
-     7-11-1998    Fixed bug that assumed that directory data could be fragmented
-     8-12-1998    Added FAT32 support
-                  Added initial writability functions
-                  WARNING: DO NOT ATTEMPT TO TEST WRITABILITY FUNCTIONS!!!
-     12-12-1998   Added basic support for FILE_STANDARD_INFORMATION request
-
-*/
+ *    ??           Created
+ *   24-10-1998   Fixed bugs in long filename support
+ *                Fixed a bug that prevented unsuccessful file open requests
+ *                being reported
+ *                Now works with long filenames that span over a sector
+ *                boundary
+ *   28-10-1998   Reads entire FAT into memory
+ *                VFatReadSector modified to read in more than one sector at a
+ *                time
+ *   7-11-1998    Fixed bug that assumed that directory data could be
+ *                fragmented
+ *   8-12-1998    Added FAT32 support
+ *                Added initial writability functions
+ *                WARNING: DO NOT ATTEMPT TO TEST WRITABILITY FUNCTIONS!!!
+ *   12-12-1998   Added basic support for FILE_STANDARD_INFORMATION request
+ *
+ */
 
 /* INCLUDES *****************************************************************/
 
 #include <ddk/ntddk.h>
-#include <internal/string.h>
-#include <wstring.h>
-#include <ddk/cctypes.h>
 
 #define NDEBUG
-#include <internal/debug.h>
+#include <debug.h>
 
 #include "vfat.h"
 
-#define FAT16 (1)
-#define FAT12 (2)
-#define FAT32 (3)
-
-typedef struct
-{
-   PDEVICE_OBJECT StorageDevice;
-   BootSector *Boot;
-   int rootDirectorySectors, FATStart, rootStart, dataStart;
-   int FATEntriesPerSector, FATUnit;
-   ULONG BytesPerCluster;
-   ULONG FatType;
-   unsigned char* FAT;
-} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
-
-typedef struct
-{
-   FATDirEntry entry;
-} FCB, *PFCB;
-
-#define ENTRIES_PER_SECTOR (BLOCKSIZE / sizeof(FATDirEntry))
-
 /* GLOBALS *****************************************************************/
 
-static PDRIVER_OBJECT DriverObject;
-
-/* FUNCTIONS ****************************************************************/
-
-ULONG Fat32GetNextCluster(PDEVICE_EXTENSION DeviceExt, ULONG CurrentCluster)
-{
-   ULONG FATsector;
-   ULONG FATeis;
-   PULONG Block;
-   Block = ExAllocatePool(NonPagedPool,1024);
-   FATsector=CurrentCluster/(512/sizeof(ULONG));
-   FATeis=CurrentCluster-(FATsector*(512/sizeof(ULONG)));
-   VFATReadSectors(DeviceExt->StorageDevice,DeviceExt->FATStart+FATsector, 1,
-                 Block);
-   CurrentCluster = Block[FATeis];
-   if (CurrentCluster >= 0xffffff8 && CurrentCluster <= 0xfffffff)
-       CurrentCluster = 0;
-   ExFreePool(Block);
-   return(CurrentCluster);
-}
-
-ULONG Fat16GetNextCluster(PDEVICE_EXTENSION DeviceExt, ULONG CurrentCluster)
-{
-   ULONG FATsector;
-   ULONG FATeis;
-   PUSHORT Block;
-   
-   FATsector=CurrentCluster/(512/sizeof(USHORT));
-   FATeis=CurrentCluster-(FATsector*256);
-   
-   
-//   VFATReadSectors(DeviceExt->StorageDevice,DeviceExt->FATStart+FATsector, 1,
-//               (UCHAR *)Block);
-   
-   Block = (PUSHORT)(DeviceExt->FAT + (FATsector * BLOCKSIZE));
-   
-   CurrentCluster = Block[FATeis];
-   if (CurrentCluster >= 0xfff8 && CurrentCluster <= 0xffff)
-       CurrentCluster = 0;
-  
-   DPRINT("Returning %x\n",CurrentCluster);
-   return(CurrentCluster);
-}
-
-ULONG Fat12GetNextCluster(PDEVICE_EXTENSION DeviceExt, ULONG CurrentCluster)
-{
-   unsigned char* CBlock;
-   ULONG FATsector;
-   ULONG FATOffset;
-   ULONG Entry;
-
-   
-   FATsector = (CurrentCluster * 12) / (512 * 8);
-       
-//   VFATReadSectors(DeviceExt->StorageDevice,DeviceExt->FATStart
-//               +FATsector,1,CBlock);
-
-   CBlock = (unsigned char *)(DeviceExt->FAT + (FATsector * BLOCKSIZE));
-   
-   FATOffset = (CurrentCluster * 12) % (512 * 8);
-   DPRINT("FATSector %d FATOffset %d\n",FATsector,FATOffset);
-   if ((CurrentCluster % 2) == 0)
-     {
-       Entry = CBlock[((FATOffset / 24)*3)];
-       Entry |= (CBlock[((FATOffset / 24)*3) + 1] & 0xf);
-     }
-   else
-     {
-       Entry = (CBlock[((FATOffset / 24)*3) + 1] >> 4);
-       Entry |= (CBlock[((FATOffset / 24)*3) + 2] << 4);
-     }
-   DPRINT("Entry %x\n",Entry);
-   if (Entry >= 0xff8 && Entry <= 0xfff)
-       Entry = 0;
-   CurrentCluster = Entry;
-
-   DPRINT("Returning %x\n",CurrentCluster);
-   return(CurrentCluster);
-}
-
-ULONG GetNextCluster(PDEVICE_EXTENSION DeviceExt, ULONG CurrentCluster)
-{
-   
-   DPRINT("GetNextCluster(DeviceExt %x, CurrentCluster %x)\n",
-           DeviceExt,CurrentCluster);
-   if (DeviceExt->FatType == FAT16)
-     {
-       return(Fat16GetNextCluster(DeviceExt, CurrentCluster));
-     }
-   else if (DeviceExt->FatType == FAT32)
-     {
-       return(Fat32GetNextCluster(DeviceExt, CurrentCluster));
-     }
-   else
-     {
-       return(Fat12GetNextCluster(DeviceExt, CurrentCluster));
-     }
-}
-
-ULONG FAT16FindAvailableCluster(PDEVICE_EXTENSION DeviceExt)
-{
-   ULONG sector;
-   PUSHORT Block;
-   int i;
-
-   sector = 0;
-   Block = ExAllocatePool(NonPagedPool,BLOCKSIZE);
-
-   while(sector<DeviceExt->Boot->FATSectors) {
-     memcpy(Block, DeviceExt->FAT+sector*BLOCKSIZE, BLOCKSIZE);
-
-     for(i=0; i<512; i++) {
-       if(Block[i]==0) {
-         ExFreePool(Block);
-         return i;
-       }
-     }
+#define  CACHEPAGESIZE(pDeviceExt) ((pDeviceExt)->BytesPerCluster > PAGESIZE ? \
+                  (pDeviceExt)->BytesPerCluster : PAGESIZE)
 
-     sector++;
-   }
+static PDRIVER_OBJECT VfatDriverObject;
 
-   /* Give an error message (out of disk space) if we reach here) */
-
-   ExFreePool(Block);
-   return 0;
-}
-
-void  FAT16WriteCluster(PDEVICE_EXTENSION DeviceExt, ULONG ClusterToWrite,
-                        ULONG NewValue)
-{
-   ULONG FATsector;
-   ULONG FATeis;
-   PUSHORT Block;
-
-   Block = ExAllocatePool(NonPagedPool,BLOCKSIZE);
-   
-   FATsector=ClusterToWrite/(512/sizeof(USHORT));
-   FATeis=ClusterToWrite-(FATsector*256);
-
-   /* Update the in-memory FAT */
-   memcpy(Block, DeviceExt->FAT+FATsector*BLOCKSIZE, BLOCKSIZE);
-   Block[FATeis] = NewValue;
-   memcpy(DeviceExt->FAT+FATsector*BLOCKSIZE, Block, BLOCKSIZE);
-
-   /* Write the changed FAT sector to disk */
-   VFATWriteSectors(DeviceExt->StorageDevice,
-                   DeviceExt->FATStart+FATsector,
-                    DeviceExt->Boot->SectorsPerCluster,
-                   (UCHAR *)Block);
-   
-   ExFreePool(Block);
-}
+/* FUNCTIONS ****************************************************************/
 
-void  FAT12WriteCluster(PDEVICE_EXTENSION DeviceExt, ULONG ClusterToWrite,
-                        ULONG NewValue)
+static NTSTATUS
+VfatHasFileSystem(PDEVICE_OBJECT DeviceToMount,
+                 PBOOLEAN RecognizedFS)
+/*
+ * FUNCTION: Tests if the device contains a filesystem that can be mounted
+ *           by this fsd
+ */
 {
-   unsigned char* CBlock;
-   ULONG FATsector;
-   ULONG FATOffset;
-   ULONG Entry;
-
-   CBlock = ExAllocatePool(NonPagedPool,1024);
-   FATsector = (ClusterToWrite * 12) / (512 * 8);
-       
-   memcpy(CBlock,DeviceExt->FAT+FATsector*BLOCKSIZE, BLOCKSIZE);
-   FATOffset = (ClusterToWrite * 12) % (512 * 8);
-   
-   DPRINT("FATSector %d FATOffset %d\n",FATsector,FATOffset);
-
-   /*
+   BootSector *Boot;
+   NTSTATUS Status;
 
-   Write 12-bit entry
+   Boot = ExAllocatePool(NonPagedPool, 512);
 
-   if ((CurrentCluster % 2) == 0)
+   Status = VfatReadSectors(DeviceToMount, 0, 1, (UCHAR *) Boot);
+   if (!NT_SUCCESS(Status))
      {
-       Entry = CBlock[((FATOffset / 24)*3)];
-       Entry |= (CBlock[((FATOffset / 24)*3) + 1] & 0xf);
+       return(Status);
      }
-   else
-     {
-       Entry = (CBlock[((FATOffset / 24)*3) + 1] >> 4);
-       Entry |= (CBlock[((FATOffset / 24)*3) + 2] << 4);
-     } */
-       
-   ExFreePool(CBlock);
-}
-
-void  WriteCluster(PDEVICE_EXTENSION DeviceExt, ULONG ClusterToWrite,
-                   ULONG NewValue)
-{
-   if (DeviceExt->FatType == FAT16) {
-     FAT16WriteCluster(DeviceExt, ClusterToWrite, NewValue);
-   } else {
-     FAT12WriteCluster(DeviceExt, ClusterToWrite, NewValue);
-   }
-}
-
-ULONG GetNextWriteCluster(PDEVICE_EXTENSION DeviceExt, ULONG CurrentCluster)
-{
-   ULONG LastCluster, NewCluster;
-   BOOLEAN EOF = FALSE;
-
-   DPRINT("GetNextWriteCluster(DeviceExt %x, CurrentCluster %x)\n",
-           DeviceExt,CurrentCluster);
-
-   /* Find out what was happening in the last cluster's AU */
 
-   if (DeviceExt->FatType == FAT16)
+   DPRINT1("Boot->SysType %.5s\n", Boot->SysType);
+   if (strncmp(Boot->SysType, "FAT12", 5) == 0 ||
+       strncmp(Boot->SysType, "FAT16", 5) == 0 ||
+       strncmp(((struct _BootSector32 *) (Boot))->SysType, "FAT32", 5) == 0)
      {
-       LastCluster = Fat16GetNextCluster(DeviceExt, CurrentCluster);
-        if(LastCluster == 0xFFFF) {
-          EOF = TRUE;
-        }
+       *RecognizedFS = TRUE;
      }
    else
-     { 
-       LastCluster = Fat12GetNextCluster(DeviceExt, CurrentCluster);
-        if(LastCluster == 0xFFF) {
-          EOF = TRUE;
-        }
-     }
-
-   /* Check to see if we must append or overwrite */
-
-   if (EOF == TRUE) {
-
-        /* Append */
-
-        /* Firstly, find the next available open allocation unit */
-        NewCluster = FAT16FindAvailableCluster(DeviceExt);
-
-        /* Mark the new AU as the EOF */
-        if(DeviceExt->FatType == FAT16) {
-           FAT16WriteCluster(DeviceExt, NewCluster, 0xFFFF);
-        } else {
-           FAT12WriteCluster(DeviceExt, NewCluster, 0xFFF);
-        }
-
-        /* Now, write the AU of the LastCluster with the value of the newly
-           found AU */
-        WriteCluster(DeviceExt, LastCluster, NewCluster);
-
-        /* Return NewCluster as CurrentCluster */
-        return NewCluster;
-
-   } else {
-
-        /* Overwrite: Return LastCluster as CurrentCluster */
-        return LastCluster;
-
-   }
-}
-
-unsigned long ClusterToSector(PDEVICE_EXTENSION DeviceExt, 
-                             unsigned long Cluster)
-{
-  return DeviceExt->dataStart+((Cluster-2)*DeviceExt->Boot->SectorsPerCluster);
-}
-
-void RtlAnsiToUnicode(PWSTR Dest, PCH Source, ULONG Length)
-{
-   int i;
-   
-   for (i=0; (i<Length && Source[i] != ' '); i++)
-     {
-       Dest[i] = Source[i];
-     }
-   Dest[i]=0;
-}
-
-void RtlCatAnsiToUnicode(PWSTR Dest, PCH Source, ULONG Length)
-{
-   ULONG i;
-   
-   while((*Dest)!=0)
-     {
-       Dest++;
-     }
-   for (i=0; (i<Length && Source[i] != ' '); i++)
-     {
-       Dest[i] = Source[i];
-     }
-   Dest[i]=0;
-}
-
-void vfat_initstr(wchar_t *wstr, ULONG wsize)
-{
-  int i;
-  wchar_t nc=0;
-  for(i=0; i<wsize; i++)
-  {
-    *wstr=nc;
-    wstr++;
-  }
-  wstr=wstr-wsize;
-}
-
-wchar_t * vfat_wcsncat(wchar_t * dest, const wchar_t * src,size_t wstart, size_t wcount)
-{
-   int i;
-
-   dest+=wstart;
-   for(i=0; i<wcount; i++)
-   {
-     *dest=src[i];
-     dest++;
-   }
-   dest=dest-(wcount+wstart);
-
-   return dest;
-}
-
-wchar_t * vfat_wcsncpy(wchar_t * dest, const wchar_t *src,size_t wcount)
-{
-   int i;
-   
-   for (i=0;i<wcount;i++)
-     {
-       *dest=src[i];
-       dest++;
-     }
-   dest=dest-wcount;
-
-   return(dest);
-}
-
-wchar_t * vfat_movstr(wchar_t * dest, const wchar_t *src, ULONG dpos,
-                      ULONG spos, ULONG len)
-{
-  int i;
-
-  dest+=dpos;
-  for(i=spos; i<spos+len; i++)
-  {
-    *dest=src[i];
-    dest++;
-  }
-  dest-=(dpos+len);
-
-  return(dest);
-}
-
-BOOLEAN IsLastEntry(PVOID Block, ULONG Offset)
-{
-   return(((FATDirEntry *)Block)[Offset].Filename[0] == 0);
-}
-
-BOOLEAN IsDeletedEntry(PVOID Block, ULONG Offset)
-{
-   /* Checks special character (short names) or attrib=0 (long names) */
-
-   return ((((FATDirEntry *)Block)[Offset].Filename[0] == 0xe5) ||
-           (((FATDirEntry *)Block)[Offset].Attrib == 0x00));
-}
-
-BOOLEAN GetEntryName(PVOID Block, PULONG _Offset, PWSTR Name, PULONG _jloop,
-  PDEVICE_EXTENSION DeviceExt, PULONG _StartingSector)
-{
-   FATDirEntry* test;
-   slot* test2;
-   ULONG Offset = *_Offset;
-   ULONG StartingSector = *_StartingSector;
-   ULONG jloop = *_jloop;
-   ULONG cpos;
-   WCHAR tmp[256];
-   
-   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)) 
-         {
-            Offset++;
-             if(Offset==ENTRIES_PER_SECTOR) {
-               Offset=0;
-               StartingSector++;
-               jloop++;
-               VFATReadSectors(DeviceExt->StorageDevice,StartingSector,1,Block);
-               test2 = (slot *)Block;
-             }
-             cpos++;
-
-             vfat_initstr(tmp, 256);
-             vfat_movstr(tmp, Name, 13, 0, cpos*13);
-             vfat_wcsncpy(Name, tmp, 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);
-
-          }
-
-       if (IsDeletedEntry(Block,Offset+1))
-         {
-            Offset++;
-            *_Offset = Offset;
-             *_jloop = jloop;
-             *_StartingSector = StartingSector;
-            return(FALSE);
-         }
-       
-       *_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);
-}
-
-BOOLEAN wstrcmpi(PWSTR s1, PWSTR s2)
-{
-   DPRINT("s1 '%w' s2 '%w'\n",s1,s2);
-   while (wtolower(*s1)==wtolower(*s2))
      {
-       if ((*s1)==0 && (*s2)==0)
-         {
-            return(TRUE);
-         }
-       
-       s1++;
-       s2++;   
+       *RecognizedFS = FALSE;
      }
-   return(FALSE);
-}
 
-NTSTATUS FindFile(PDEVICE_EXTENSION DeviceExt, PFCB Fcb,
-                 PFCB Parent, PWSTR FileToFind)
-{
-   ULONG i, j;
-   ULONG Size;
-   char* block;
-   WCHAR name[256];
-   ULONG StartingSector;
-   ULONG NextCluster;
-   DPRINT("FileFile(Parent %x, FileToFind %w)\n",Parent,FileToFind);
-   
-   if (Parent == NULL)
-     {
-       Size = DeviceExt->rootDirectorySectors;//FIXME : in fat32, no limit
-       StartingSector = DeviceExt->rootStart;
-     }
-   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);
-     }
-   block = ExAllocatePool(NonPagedPool,BLOCKSIZE);
+   ExFreePool(Boot);
 
-   for (j=0; j<Size; j++)
-     {
-       VFATReadSectors(DeviceExt->StorageDevice,StartingSector,1,block);
-
-       for (i=0; i<ENTRIES_PER_SECTOR; i++)
-         {
-            if (IsLastEntry((PVOID)block,i))
-              {
-                 ExFreePool(block);
-                 return(STATUS_UNSUCCESSFUL);
-              }
-            if (GetEntryName((PVOID)block,&i,name,&j,DeviceExt,&StartingSector))
-              {
-                 DPRINT("Scanning %w\n",name);
-                 DPRINT("Comparing %w %w\n",name,FileToFind);
-                 if (wstrcmpi(name,FileToFind))
-                   {
-                       /* In the case of a long filename, the firstcluster is stored in
-                          the next record -- where it's short name is */
-                  if(DeviceExt->FatType==FAT32)
-                       if(((FATDirEntry *)block)[i].FirstCluster==0
-                         &&((FATDirEntry *)block)[i].FirstClusterHigh==0
-                       ) i++;
-                  else
-                       if(((FATDirEntry *)block)[i].FirstCluster==0) i++;
-                       DPRINT("Found it at cluster %u\n", ((FATDirEntry *)block)[i].FirstCluster);
-    if( i==ENTRIES_PER_SECTOR)
-    {
-      VFATReadSectors(DeviceExt->StorageDevice,StartingSector+1,1,block);
-      i=0;
-   }
-
-                      memcpy(&Fcb->entry,&((FATDirEntry *)block)[i],
-                             sizeof(FATDirEntry));
-
-                              ExFreePool(block);
-                      return(STATUS_SUCCESS);
-                   }
-              }
-
-       }
-
-
-       /* It seems that directory sectors cannot be fragmented and therefore,
-          they only have a first cluster, but the one's after it are marked
-          with 0xffff. This theory is still not 100% certain, so the following
-          lines are commented and not removed */
-
-       StartingSector++;
-       /*      if (Parent == NULL)
-         {
-            StartingSector++;
-         }
-       else
-         {
-            NextCluster = GetNextCluster(DeviceExt,NextCluster);
-            if (NextCluster == 0)
-              {
-                  ExFreePool(block);
-                 return(STATUS_UNSUCCESSFUL);
-              }
-            StartingSector = ClusterToSector(DeviceExt,NextCluster);
-         } */
-     }
-   ExFreePool(block);
-   return(STATUS_UNSUCCESSFUL);
+   return(STATUS_SUCCESS);
 }
 
 
-NTSTATUS FsdCloseFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject)
+static NTSTATUS
+VfatMountDevice(PDEVICE_EXTENSION DeviceExt,
+               PDEVICE_OBJECT DeviceToMount)
 /*
- * FUNCTION: Closes a file
- */
-{
-   /* NOP */
-}
-
-NTSTATUS FsdOpenFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject, 
-                    PWSTR FileName)
-/*
- * FUNCTION: Opens a file
+ * FUNCTION: Mounts the device
  */
 {
-   PWSTR current;
-   PWSTR next;
-   PWSTR string = FileName;
-   PFCB ParentFcb = NULL;
-   PFCB Fcb = ExAllocatePool(NonPagedPool,sizeof(FCB));
-   PFCB Temp;
    NTSTATUS Status;
-   
-   next = &string[0];
-   current = next+1;
-   
-   while (next!=NULL)
-     { 
-       DPRINT("current %w next %x\n",current,next);
-       
-       *next = '\\';
-       current = next+1;
-       next = wcschr(next+1,'\\');
-       if (next!=NULL)
-         {
-            *next=0;
-         }
-       
-        Status = FindFile(DeviceExt,Fcb,ParentFcb,current);
-       if (Status != STATUS_SUCCESS)
-         {
-            return(Status);
-         }
-       Temp = Fcb;
-       if (ParentFcb == NULL)
-         {
-            Fcb = ExAllocatePool(NonPagedPool,sizeof(FCB));
-            ParentFcb = Temp;
-         }
-       else
-         {
-            Fcb = ParentFcb;
-            ParentFcb = Temp;
-         }
-     }
-   FileObject->FsContext = ParentFcb;
-   DPRINT("ParentFcb->entry.FileSize %d\n",ParentFcb->entry.FileSize);
-
-   return(STATUS_SUCCESS);
-}
-
-BOOLEAN FsdHasFileSystem(PDEVICE_OBJECT DeviceToMount)
-/*
- * FUNCTION: Tests if the device contains a filesystem that can be mounted 
- * by this fsd
- */
-{
-   BootSector* Boot;
 
-   Boot = ExAllocatePool(NonPagedPool,512);
+   DPRINT("Mounting VFAT device...");
+   DPRINT("DeviceExt %x\n", DeviceExt);
 
-   VFATReadSectors(DeviceToMount, 0, 1, (UCHAR *)Boot);
+   DeviceExt->Boot = ExAllocatePool(NonPagedPool, 512);
 
-   if (strncmp(Boot->SysType,"FAT12",5)==0 ||
-       strncmp(Boot->SysType,"FAT16",5)==0 ||
-       strncmp(((struct _BootSector32 *)(Boot))->SysType,"FAT32",5)==0)
+   Status = VfatReadSectors(DeviceToMount, 0, 1, (UCHAR *) DeviceExt->Boot);
+   if (!NT_SUCCESS(Status))
      {
-       ExFreePool(Boot);
-       return(TRUE);
+       return(Status);
      }
-   ExFreePool(Boot);
-   return(FALSE);
-}
-
-NTSTATUS FsdMountDevice(PDEVICE_EXTENSION DeviceExt,
-                       PDEVICE_OBJECT DeviceToMount)
-/*
- * FUNCTION: Mounts the device
- */
-{
-   int i;
 
-   DPRINT("Mounting VFAT device...");
-   DPRINT("DeviceExt %x\n",DeviceExt);
-
-   DeviceExt->Boot = ExAllocatePool(NonPagedPool,512);
-   VFATReadSectors(DeviceToMount, 0, 1, (UCHAR *)DeviceExt->Boot);
-   
-   DPRINT("DeviceExt->Boot->BytesPerSector %x\n",
-         DeviceExt->Boot->BytesPerSector);
-   
-   DeviceExt->FATStart=DeviceExt->Boot->ReservedSectors;
-   DeviceExt->rootDirectorySectors=
-     (DeviceExt->Boot->RootEntries*32)/DeviceExt->Boot->BytesPerSector;
-   DeviceExt->rootStart=
-     DeviceExt->FATStart+DeviceExt->Boot->FATCount*DeviceExt->Boot->FATSectors;
-   DeviceExt->dataStart=DeviceExt->rootStart+DeviceExt->rootDirectorySectors;
-   DeviceExt->FATEntriesPerSector=DeviceExt->Boot->BytesPerSector/32;
+   DeviceExt->FATStart = DeviceExt->Boot->ReservedSectors;
+   DeviceExt->rootDirectorySectors =
+     (DeviceExt->Boot->RootEntries * 32) / DeviceExt->Boot->BytesPerSector;
+   DeviceExt->rootStart =
+     DeviceExt->FATStart +
+     DeviceExt->Boot->FATCount * DeviceExt->Boot->FATSectors;
+   DeviceExt->dataStart =
+     DeviceExt->rootStart + DeviceExt->rootDirectorySectors;
+   DeviceExt->BytesPerSector = DeviceExt->Boot->BytesPerSector;
+   DeviceExt->FATEntriesPerSector = DeviceExt->Boot->BytesPerSector / 32;
    DeviceExt->BytesPerCluster = DeviceExt->Boot->SectorsPerCluster *
-                                DeviceExt->Boot->BytesPerSector;
-   
-   if (strncmp(DeviceExt->Boot->SysType,"FAT12",5)==0)
-     {
-       DeviceExt->FatType = FAT12;
-     }
-   else if (strncmp(((struct _BootSector32 *)(DeviceExt->Boot))->SysType,"FAT32",5)==0)
-     {
-      DeviceExt->FatType = FAT32;
-      DeviceExt->rootDirectorySectors=DeviceExt->Boot->SectorsPerCluster;
-      DeviceExt->rootStart=
-             DeviceExt->FATStart+DeviceExt->Boot->FATCount
-             * ((struct _BootSector32 *)( DeviceExt->Boot))->FATSectors32;
-      DeviceExt->dataStart=DeviceExt->rootStart;
-        }
-   else
-     {
-       DeviceExt->FatType = FAT16;
-     }
-
-   // with FAT32 it's not a good idea to load always fat in memory
-   // because on a 8GB partition with 2 KO clusters, the fat = 8 MO
-   if(DeviceExt->FatType!=FAT32)
-   {
-    DeviceExt->FAT = ExAllocatePool(NonPagedPool, BLOCKSIZE*DeviceExt->Boot->FATSectors);
-    VFATReadSectors(DeviceToMount, DeviceExt->FATStart, DeviceExt->Boot->FATSectors, (UCHAR *)DeviceExt->FAT);
-   }
-}
-
-void VFATLoadCluster(PDEVICE_EXTENSION DeviceExt, PVOID Buffer, ULONG Cluster)
-{
-   ULONG Sector;
-
-   DPRINT("VFATLoadCluster(DeviceExt %x, Buffer %x, Cluster %d)\n",
-         DeviceExt,Buffer,Cluster);
-
-   Sector = ClusterToSector(DeviceExt, Cluster);
-
-   VFATReadSectors(DeviceExt->StorageDevice,
-                  Sector,
-                   DeviceExt->Boot->SectorsPerCluster,
-                  Buffer);
-}
+     DeviceExt->Boot->BytesPerSector;
 
-void VFATWriteCluster(PDEVICE_EXTENSION DeviceExt, PVOID Buffer, ULONG Cluster)
-{
-   ULONG Sector;
-   
-   DPRINT("VFATWriteCluster(DeviceExt %x, Buffer %x, Cluster %d)\n",
-         DeviceExt,Buffer,Cluster);
-   
-   Sector = ClusterToSector(DeviceExt, Cluster);
-   
-   VFATWriteSectors(DeviceExt->StorageDevice,
-                   Sector,
-                    DeviceExt->Boot->SectorsPerCluster,
-                   Buffer);
-}
-
-NTSTATUS FsdReadFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject,
-                    PVOID Buffer, ULONG Length, ULONG ReadOffset,
-                    PULONG LengthRead)
-/*
- * FUNCTION: Reads data from a file
- */
-{
-   ULONG CurrentCluster;
-   ULONG FileOffset;
-   ULONG FirstCluster;
-   PFCB  Fcb;
-   PVOID Temp;
-   ULONG TempLength;
-   
-   DPRINT("FsdReadFile(DeviceExt %x, FileObject %x, Buffer %x, "
-           "Length %d, ReadOffset %d)\n",DeviceExt,FileObject,Buffer,
-           Length,ReadOffset);
-   
-   FirstCluster = ReadOffset / DeviceExt->BytesPerCluster;
-   Fcb = FileObject->FsContext;
-   if (DeviceExt->FatType == FAT32)
-       CurrentCluster = Fcb->entry.FirstCluster+Fcb->entry.FirstClusterHigh*65536;
-   else
-       CurrentCluster = Fcb->entry.FirstCluster;
-   
-   if (ReadOffset >= Fcb->entry.FileSize)
-     {
-       return(STATUS_END_OF_FILE);
-     }
-   if ((ReadOffset + Length) > Fcb->entry.FileSize)
+   if (DeviceExt->BytesPerCluster >= PAGESIZE && 
+       (DeviceExt->BytesPerCluster % PAGESIZE) != 0)
      {
-       Length = Fcb->entry.FileSize - ReadOffset;
+       DbgPrint("Invalid cluster size\n");
+       KeBugCheck(0);
      }
-   *LengthRead = 0;
-   
-   DPRINT("DeviceExt->BytesPerCluster %x\n",DeviceExt->BytesPerCluster);
-   
-   Temp = ExAllocatePool(NonPagedPool,DeviceExt->BytesPerCluster);
-   
-   for (FileOffset=0; FileOffset < FirstCluster; FileOffset++)
+   else if (DeviceExt->BytesPerCluster < PAGESIZE &&
+           (PAGESIZE % DeviceExt->BytesPerCluster) != 0)
      {
-       CurrentCluster = GetNextCluster(DeviceExt,CurrentCluster);
+       DbgPrint("Invalid cluster size2\n");
+       KeBugCheck(0);
      }
-   CHECKPOINT;
-   if ((ReadOffset % DeviceExt->BytesPerCluster)!=0)
+
+   if (strncmp (DeviceExt->Boot->SysType, "FAT12", 5) == 0)
      {
-       VFATLoadCluster(DeviceExt,Temp,CurrentCluster);
-       CurrentCluster = GetNextCluster(DeviceExt, CurrentCluster);
-       
-       TempLength = min(Length,DeviceExt->BytesPerCluster -
-                        (ReadOffset % DeviceExt->BytesPerCluster));
-       
-       memcpy(Buffer, Temp + ReadOffset % DeviceExt->BytesPerCluster,
-              TempLength);
-       
-       (*LengthRead) = (*LengthRead) + TempLength;
-       Length = Length - TempLength;
-       Buffer = Buffer + TempLength;        
+       DbgPrint("FAT12\n");
+       DeviceExt->FatType = FAT12;
      }
-   CHECKPOINT;
-   while (Length > DeviceExt->BytesPerCluster)
+   else if (strncmp
+           (((struct _BootSector32 *) (DeviceExt->Boot))->SysType, "FAT32",
+           5) == 0)
      {
-       VFATLoadCluster(DeviceExt, Buffer, CurrentCluster);
-       CurrentCluster = GetNextCluster(DeviceExt, CurrentCluster);
-       
-       if (CurrentCluster == 0)
-         {
-             ExFreePool(Temp);
-            return(STATUS_SUCCESS);
-         }
-       
-       (*LengthRead) = (*LengthRead) + DeviceExt->BytesPerCluster;
-       Buffer = Buffer + DeviceExt->BytesPerCluster;
-       Length = Length - DeviceExt->BytesPerCluster;
+       DbgPrint("FAT32\n");
+       DeviceExt->FatType = FAT32;
+       DeviceExt->rootDirectorySectors = DeviceExt->Boot->SectorsPerCluster;
+       DeviceExt->dataStart = DeviceExt->FATStart + DeviceExt->Boot->FATCount
+         * ((struct _BootSector32 *) (DeviceExt->Boot))->FATSectors32;
+       DeviceExt->rootStart = ClusterToSector (DeviceExt,
+         ((struct _BootSector32 *)(DeviceExt->Boot))->RootCluster);
      }
-   CHECKPOINT;
-   if (Length > 0)
+   else
      {
-       (*LengthRead) = (*LengthRead) + Length;
-       VFATLoadCluster(DeviceExt, Temp, CurrentCluster);
-       memcpy(Buffer, Temp, Length);
+       DbgPrint("FAT16\n");
+       DeviceExt->FatType = FAT16;
      }
-   ExFreePool(Temp);
+
    return(STATUS_SUCCESS);
 }
 
-NTSTATUS FsdWriteFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject,
-                     PVOID Buffer, ULONG Length, ULONG WriteOffset)
+
+static NTSTATUS
+VfatMount (PVFAT_IRP_CONTEXT IrpContext)
 /*
- * FUNCTION: Writes data to file
+ * FUNCTION: Mount the filesystem
  */
 {
-   ULONG CurrentCluster;
-   ULONG FileOffset;
-   ULONG FirstCluster;
-   PFCB  Fcb;
-   PVOID Temp;
-   ULONG TempLength;
-
-   /* Locate the first cluster of the file */
-
-   FirstCluster = WriteOffset / DeviceExt->BytesPerCluster;
-   Fcb = FileObject->FsContext;
-   if (DeviceExt->FatType == FAT32)
-       CurrentCluster = Fcb->entry.FirstCluster+Fcb->entry.FirstClusterHigh*65536;
-   else
-       CurrentCluster = Fcb->entry.FirstCluster;
-
-   /* Allocate a buffer to hold 1 cluster of data */
+  PDEVICE_OBJECT DeviceObject = NULL;
+  PDEVICE_EXTENSION DeviceExt = NULL;
+  BOOLEAN RecognizedFS;
+  NTSTATUS Status;
+  PVFATFCB Fcb = NULL;
+  PVFATCCB Ccb = NULL;
 
-   Temp = ExAllocatePool(NonPagedPool,DeviceExt->BytesPerCluster);
+  DPRINT1("VfatMount(IrpContext %x)\n", IrpContext);
 
-   /* Find the cluster according to the offset in the file */
+  assert (IrpContext);
 
-   for (FileOffset=0; FileOffset < FirstCluster; FileOffset++)
-     {
-       CurrentCluster = GetNextCluster(DeviceExt,CurrentCluster);
-     }
-   CHECKPOINT;
-
-   /*
-      If the offset in the cluster doesn't fall on the cluster boundary then
-      we have to write only from the specified offset
-   */
-
-   if ((WriteOffset % DeviceExt->BytesPerCluster)!=0)
-     {
-       TempLength = min(Length,DeviceExt->BytesPerCluster -
-                        (WriteOffset % DeviceExt->BytesPerCluster));
-
-        /* Read in the existing cluster data */
-        VFATLoadCluster(DeviceExt,Temp,CurrentCluster);
+  if (IrpContext->DeviceObject != VfatDriverObject->DeviceObject)
+  {
+     // Only allowed on the main device object
+     Status = STATUS_INVALID_DEVICE_REQUEST;
+     goto ByeBye;
+  }
 
-        /* Overwrite the last parts of the data as necessary */
-       memcpy(Temp + WriteOffset % DeviceExt->BytesPerCluster, Buffer,
-              TempLength);
+  Status = VfatHasFileSystem (IrpContext->Stack->Parameters.Mount.DeviceObject, &RecognizedFS);
+  if (!NT_SUCCESS(Status))
+  {
+     goto ByeBye;
+  }
 
-        /* Write the cluster back */
-        VFATWriteCluster(DeviceExt,Temp,CurrentCluster);
+  if (RecognizedFS == FALSE)
+  {
+     DPRINT("VFAT: Unrecognized Volume\n");
+     Status = STATUS_UNRECOGNIZED_VOLUME;
+     goto ByeBye;
+  }
 
-        /* Next write cluster */
-       CurrentCluster = GetNextWriteCluster(DeviceExt, CurrentCluster);
+  DPRINT("VFAT: Recognized volume\n");
 
-       Length = Length - TempLength;
-       Buffer = Buffer + TempLength;        
-     }
-   CHECKPOINT;
+  Status = IoCreateDevice(VfatDriverObject,
+                         sizeof (DEVICE_EXTENSION),
+                         NULL,
+                         FILE_DEVICE_FILE_SYSTEM,
+                         0,
+                         FALSE,
+                         &DeviceObject);
+  if (!NT_SUCCESS(Status))
+  {
+    goto ByeBye;
+  }
 
-   /* Write the buffer in chunks of 1 cluster */
+  DeviceObject->Flags = DeviceObject->Flags | DO_DIRECT_IO;
+  DeviceExt = (PVOID) DeviceObject->DeviceExtension;
+  RtlZeroMemory(DeviceExt, sizeof(DEVICE_EXTENSION));
 
-   while (Length > DeviceExt->BytesPerCluster)
-     {
-       VFATWriteCluster(DeviceExt, Buffer, CurrentCluster);
-       CurrentCluster = GetNextWriteCluster(DeviceExt, CurrentCluster);
-       
-       if (CurrentCluster == 0)
-         {
-             ExFreePool(Temp);
-            return(STATUS_SUCCESS);
-         }
-       
-       Buffer = Buffer + DeviceExt->BytesPerCluster;
-       Length = Length - DeviceExt->BytesPerCluster;
-     }
-   CHECKPOINT;
+  /* use same vpb as device disk */
+  DeviceObject->Vpb = IrpContext->Stack->Parameters.Mount.DeviceObject->Vpb;
+  Status = VfatMountDevice(DeviceExt, IrpContext->Stack->Parameters.Mount.DeviceObject);
+  if (!NT_SUCCESS(Status))
+  {
+    /* FIXME: delete device object */
+    goto ByeBye;
+  }
 
-   /* Write the remainder */
+#if 1
+  DbgPrint("BytesPerSector:     %d\n", DeviceExt->Boot->BytesPerSector);
+  DbgPrint("SectorsPerCluster:  %d\n", DeviceExt->Boot->SectorsPerCluster);
+  DbgPrint("ReservedSectors:    %d\n", DeviceExt->Boot->ReservedSectors);
+  DbgPrint("FATCount:           %d\n", DeviceExt->Boot->FATCount);
+  DbgPrint("RootEntries:        %d\n", DeviceExt->Boot->RootEntries);
+  DbgPrint("Sectors:            %d\n", DeviceExt->Boot->Sectors);
+  DbgPrint("FATSectors:         %d\n", DeviceExt->Boot->FATSectors);
+  DbgPrint("SectorsPerTrack:    %d\n", DeviceExt->Boot->SectorsPerTrack);
+  DbgPrint("Heads:              %d\n", DeviceExt->Boot->Heads);
+  DbgPrint("HiddenSectors:      %d\n", DeviceExt->Boot->HiddenSectors);
+  DbgPrint("SectorsHuge:        %d\n", DeviceExt->Boot->SectorsHuge);
+  DbgPrint("RootStart:          %d\n", DeviceExt->rootStart);
+  DbgPrint("DataStart:          %d\n", DeviceExt->dataStart);
+  if (DeviceExt->FatType == FAT32)
+    {
+      DbgPrint("FATSectors32:       %d\n",
+              ((struct _BootSector32*)(DeviceExt->Boot))->FATSectors32);
+      DbgPrint("RootCluster:        %d\n",
+              ((struct _BootSector32*)(DeviceExt->Boot))->RootCluster);
+      DbgPrint("FSInfoSector:       %d\n",
+              ((struct _BootSector32*)(DeviceExt->Boot))->FSInfoSector);
+      DbgPrint("BootBackup:         %d\n",
+              ((struct _BootSector32*)(DeviceExt->Boot))->BootBackup);
+    }
+#endif
+  DeviceObject->Vpb->Flags |= VPB_MOUNTED;
+  DeviceExt->StorageDevice = IoAttachDeviceToDeviceStack(DeviceObject, IrpContext->Stack->Parameters.Mount.DeviceObject);
+
+  DeviceExt->FATFileObject = IoCreateStreamFileObject(NULL, DeviceExt->StorageDevice);
+  Fcb = vfatNewFCB(NULL);
+  if (Fcb == NULL)
+  {
+    Status = STATUS_INSUFFICIENT_RESOURCES;
+    goto ByeBye;
+  }
+  Ccb = ExAllocatePoolWithTag (NonPagedPool, sizeof (VFATCCB), TAG_CCB);
+  if (Ccb == NULL)
+  {
+    Status =  STATUS_INSUFFICIENT_RESOURCES;
+    goto ByeBye;
+  }
+  memset(Ccb, 0, sizeof (VFATCCB));
+  DeviceExt->FATFileObject->Flags = DeviceExt->FATFileObject->Flags | FO_FCB_IS_VALID | FO_DIRECT_CACHE_PAGING_READ;
+  DeviceExt->FATFileObject->FsContext = (PVOID) &Fcb->RFCB;
+  DeviceExt->FATFileObject->FsContext2 = Ccb;
+  DeviceExt->FATFileObject->SectionObjectPointers = &Fcb->SectionObjectPointers;
+  Ccb->pFcb = Fcb;
+  Ccb->PtrFileObject = DeviceExt->FATFileObject;
+  Fcb->FileObject = DeviceExt->FATFileObject;
+  Fcb->pDevExt = (PDEVICE_EXTENSION)DeviceExt->StorageDevice;
+
+  Fcb->Flags = FCB_IS_FAT;
+
+  if (DeviceExt->Boot->Sectors != 0)
+  {
+    DeviceExt->NumberOfClusters = (DeviceExt->Boot->Sectors - DeviceExt->dataStart)
+                                    / DeviceExt->Boot->SectorsPerCluster + 2;
+  }
+  else
+  {
+    DeviceExt->NumberOfClusters = (DeviceExt->Boot->SectorsHuge - DeviceExt->dataStart)
+                                    / DeviceExt->Boot->SectorsPerCluster + 2;
+  }
+  if (DeviceExt->FatType == FAT32)
+  {
+    Fcb->RFCB.FileSize.QuadPart = ((struct _BootSector32 *)DeviceExt->Boot)->FATSectors32 * BLOCKSIZE;
+    Fcb->RFCB.ValidDataLength.QuadPart = ((struct _BootSector32 *)DeviceExt->Boot)->FATSectors32 * BLOCKSIZE;
+    Fcb->RFCB.AllocationSize.QuadPart = ROUND_UP(((struct _BootSector32 *)DeviceExt->Boot)->FATSectors32 * BLOCKSIZE, CACHEPAGESIZE(DeviceExt));
+    Status = CcRosInitializeFileCache(DeviceExt->FATFileObject, &Fcb->RFCB.Bcb, CACHEPAGESIZE(DeviceExt));
+  }
+  else
+  {
+    if (DeviceExt->FatType == FAT16)
+    {
+      Fcb->RFCB.FileSize.QuadPart = DeviceExt->Boot->FATSectors * BLOCKSIZE;
+      Fcb->RFCB.ValidDataLength.QuadPart = DeviceExt->Boot->FATSectors * BLOCKSIZE;
+      Fcb->RFCB.AllocationSize.QuadPart = ROUND_UP(DeviceExt->Boot->FATSectors * BLOCKSIZE, CACHEPAGESIZE(DeviceExt));
+      Status = CcRosInitializeFileCache(DeviceExt->FATFileObject, &Fcb->RFCB.Bcb, CACHEPAGESIZE(DeviceExt));
+    }
+    else
+    {
+      Fcb->RFCB.FileSize.QuadPart = DeviceExt->Boot->FATSectors * BLOCKSIZE;
+      Fcb->RFCB.ValidDataLength.QuadPart = DeviceExt->Boot->FATSectors * BLOCKSIZE;
+      Fcb->RFCB.AllocationSize.QuadPart = 2 * PAGESIZE;
+      Status = CcRosInitializeFileCache(DeviceExt->FATFileObject, &Fcb->RFCB.Bcb, 2 * PAGESIZE);
+    }
+  }
+  if (!NT_SUCCESS (Status))
+  {
+     DbgPrint ("CcRosInitializeFileCache failed\n");
+     goto ByeBye;
+  }
 
-   if (Length > 0)
-     {
-       memcpy(Temp, Buffer, Length);
-       VFATWriteCluster(DeviceExt, Temp, CurrentCluster);
-     }
+  DeviceExt->LastAvailableCluster = 0;
+  ExInitializeResourceLite(&DeviceExt->DirResource);
+  ExInitializeResourceLite(&DeviceExt->FatResource);
 
-   ExFreePool(Temp);
-   return(STATUS_SUCCESS);
-}
+  KeInitializeSpinLock(&DeviceExt->FcbListLock);
+  InitializeListHead(&DeviceExt->FcbListHead);
 
-NTSTATUS FsdClose(PDEVICE_OBJECT DeviceObject, PIRP Irp)
-{
-   PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
-   PFILE_OBJECT FileObject = Stack->FileObject;
-   PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
-   NTSTATUS Status;
+  /* read serial number */
+  if (DeviceExt->FatType == FAT12 || DeviceExt->FatType == FAT16)
+    DeviceObject->Vpb->SerialNumber =
+      ((struct _BootSector *) (DeviceExt->Boot))->VolumeID;
+  else if (DeviceExt->FatType == FAT32)
+    DeviceObject->Vpb->SerialNumber =
+      ((struct _BootSector32 *) (DeviceExt->Boot))->VolumeID;
 
-   Status = FsdCloseFile(DeviceExtension,FileObject);
+  /* read volume label */
+  ReadVolumeLabel(DeviceExt,  DeviceObject->Vpb);
+  Status = STATUS_SUCCESS;
 
-   Irp->IoStatus.Status = Status;
-   Irp->IoStatus.Information = 0;
-   
-   IoCompleteRequest(Irp, IO_NO_INCREMENT);
-   return(Status);
-}
+ByeBye:
 
-NTSTATUS FsdCreate(PDEVICE_OBJECT DeviceObject, PIRP Irp)
-{
-   PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
-   PFILE_OBJECT FileObject = Stack->FileObject;
-   NTSTATUS Status;
-   PDEVICE_EXTENSION DeviceExt;
-
-   DPRINT("VFAT FsdCreate...\n");
-
-   DeviceExt = DeviceObject->DeviceExtension;
-   Status = FsdOpenFile(DeviceExt,FileObject,FileObject->FileName.Buffer);
-   
-   Irp->IoStatus.Status = Status;
-   Irp->IoStatus.Information = 0;
-   
-   IoCompleteRequest(Irp, IO_NO_INCREMENT);
-   return(Status);
+  if (!NT_SUCCESS(Status))
+  {
+     // cleanup
+     if (DeviceExt && DeviceExt->FATFileObject)
+        ObDereferenceObject (DeviceExt->FATFileObject);
+     if (Fcb)
+        ExFreePool(Fcb);
+     if (Ccb)
+        ExFreePool(Ccb);
+     if (DeviceObject)
+       IoDeleteDevice(DeviceObject);
+  }
+  return Status;
 }
 
 
-NTSTATUS FsdWrite(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+NTSTATUS VfatFileSystemControl(PVFAT_IRP_CONTEXT IrpContext)
+/*
+ * FUNCTION: File system control
+ */
 {
-   ULONG Length;
-   PVOID Buffer;
-   ULONG Offset;
-   PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
-   PFILE_OBJECT FileObject = Stack->FileObject;
-   PDEVICE_EXTENSION DeviceExt = DeviceObject->DeviceExtension;
-   NTSTATUS Status;
-   
-   DPRINT("FsdWrite(DeviceObject %x Irp %x)\n",DeviceObject,Irp);
 
-   Length = Stack->Parameters.Write.Length;
-   Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
-   Offset = GET_LARGE_INTEGER_LOW_PART(Stack->Parameters.Write.ByteOffset);
-
-   Status = FsdWriteFile(DeviceExt,FileObject,Buffer,Length,Offset);
-
-   Irp->IoStatus.Status = Status;
-   Irp->IoStatus.Information = Length;
-   IoCompleteRequest(Irp,IO_NO_INCREMENT);
-
-   return(Status);
-}
-
-NTSTATUS FsdRead(PDEVICE_OBJECT DeviceObject, PIRP Irp)
-{
-   ULONG Length;
-   PVOID Buffer;
-   ULONG Offset;
-   PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
-   PFILE_OBJECT FileObject = Stack->FileObject;
-   PDEVICE_EXTENSION DeviceExt = DeviceObject->DeviceExtension;
    NTSTATUS Status;
-   ULONG LengthRead;
-   
-   DPRINT("FsdRead(DeviceObject %x, Irp %x)\n",DeviceObject,Irp);
-   
-   Length = Stack->Parameters.Read.Length;
-   Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
-   Offset = GET_LARGE_INTEGER_LOW_PART(Stack->Parameters.Read.ByteOffset);
-   
-   Status = FsdReadFile(DeviceExt,FileObject,Buffer,Length,Offset,
-                       &LengthRead);
-   
-   Irp->IoStatus.Status = Status;
-   Irp->IoStatus.Information = LengthRead;
-   
-   IoCompleteRequest(Irp,IO_NO_INCREMENT);
-
-   return(Status);
-}
-
-
-NTSTATUS FsdMount(PDEVICE_OBJECT DeviceToMount)
-{
-   PDEVICE_OBJECT DeviceObject;
-   PDEVICE_EXTENSION DeviceExt;
-      
-   IoCreateDevice(DriverObject,
-                 sizeof(DEVICE_EXTENSION),
-                 NULL,
-                 FILE_DEVICE_FILE_SYSTEM,
-                 0,
-                 FALSE,
-                 &DeviceObject);
-   DeviceObject->Flags = DeviceObject->Flags | DO_DIRECT_IO;
-   DeviceExt = (PVOID)DeviceObject->DeviceExtension;
-   
-   FsdMountDevice(DeviceExt,DeviceToMount);
-   
-   DeviceExt->StorageDevice = IoAttachDeviceToDeviceStack(DeviceObject,
-                                                         DeviceToMount);
-   return(STATUS_SUCCESS);
-}
 
-NTSTATUS FsdFileSystemControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
-{
-   PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
-//   PVPB      vpb = Stack->Parameters.Mount.Vpb;
-   PDEVICE_OBJECT DeviceToMount = Stack->Parameters.Mount.DeviceObject;
-   NTSTATUS Status;
+   DPRINT1("VfatFileSystemControl(IrpContext %x)\n", IrpContext);
 
-   DPRINT("VFAT FSC\n");
+   assert (IrpContext);
 
-   if (FsdHasFileSystem(DeviceToMount))
-     {
-       Status = FsdMount(DeviceToMount);
-     }
-   else
+   switch (IrpContext->MinorFunction)
      {
-        DPRINT("VFAT: Unrecognized Volume\n");
-       Status = STATUS_UNRECOGNIZED_VOLUME;
-     }
-   DPRINT("VFAT File system successfully mounted\n");
-
-   Irp->IoStatus.Status = Status;
-   Irp->IoStatus.Information = 0;
+       case IRP_MN_USER_FS_REQUEST:
+          DPRINT1("VFAT FSC: IRP_MN_USER_FS_REQUEST\n");
+          Status = STATUS_INVALID_DEVICE_REQUEST;
+          break;
 
-   IoCompleteRequest(Irp, IO_NO_INCREMENT);
-   return(Status);
-}
+       case IRP_MN_MOUNT_VOLUME:
+          Status = VfatMount(IrpContext);
+          break;
 
-NTSTATUS FsdGetStandardInformation(PFCB FCB, PDEVICE_OBJECT DeviceObject,
-  PFILE_STANDARD_INFORMATION StandardInfo)
-{
-  PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
-  unsigned long AllocSize;
+       case IRP_MN_VERIFY_VOLUME:
+          DPRINT1("VFAT FSC: IRP_MN_VERIFY_VOLUME\n");
+          Status = STATUS_INVALID_DEVICE_REQUEST;
+          break;
 
-  RtlZeroMemory(StandardInfo, sizeof(FILE_STANDARD_INFORMATION));
+       default:
+          DPRINT1("VFAT FSC: MinorFunction %d\n", IrpContext->MinorFunction);
+          Status = STATUS_INVALID_DEVICE_REQUEST;
+          break;
+     }
 
-  /* Make allocsize a rounded up multiple of BytesPerCluster */
-  AllocSize = 0;
-  while(AllocSize<FCB->entry.FileSize) {
-    AllocSize+=DeviceExtension->BytesPerCluster;
-  }
+   IrpContext->Irp->IoStatus.Status = Status;
+   IrpContext->Irp->IoStatus.Information = 0;
 
-  StandardInfo->AllocationSize = RtlConvertUlongToLargeInteger(AllocSize);
-  StandardInfo->EndOfFile      = RtlConvertUlongToLargeInteger(FCB->entry.FileSize);
-  StandardInfo->NumberOfLinks  = 0;
-  StandardInfo->DeletePending  = FALSE;
-  if((FCB->entry.Attrib & 0x10)>0) {
-    StandardInfo->Directory    = TRUE;
-  } else {
-    StandardInfo->Directory    = FALSE;
-  }
-
-  return STATUS_SUCCESS;
+   IoCompleteRequest (IrpContext->Irp, IO_NO_INCREMENT);
+   return (Status);
 }
 
-NTSTATUS FsdQueryInformation(PDEVICE_OBJECT DeviceObject, PIRP Irp)
-{
-   PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
-   FILE_INFORMATION_CLASS FileInformationClass =
-     Stack->Parameters.QueryFile.FileInformationClass;
-   PFILE_OBJECT FileObject = NULL;
-   PFCB FCB = NULL;
-   PCCB CCB = NULL;
-
-   NTSTATUS RC = STATUS_SUCCESS;
-   void *SystemBuffer;
-
-   FileObject = Stack->FileObject;
-   CCB = (PCCB)(FileObject->FsContext2);
-   FCB = CCB->Buffer; // Should be CCB->FCB???
-
-   SystemBuffer = Irp->AssociatedIrp.SystemBuffer;
-
-   switch(FileInformationClass) {
-      case FileStandardInformation:
-         RC = FsdGetStandardInformation(FCB, DeviceObject, SystemBuffer);
-      break;
 
-      default:
-         RC = STATUS_NOT_IMPLEMENTED;
-   }
-
-   return RC;
-}
-
-NTSTATUS DriverEntry(PDRIVER_OBJECT _DriverObject,
-                    PUNICODE_STRING RegistryPath)
+NTSTATUS STDCALL
+DriverEntry(PDRIVER_OBJECT _DriverObject,
+           PUNICODE_STRING RegistryPath)
 /*
  * FUNCTION: Called by the system to initalize the driver
  * ARGUMENTS:
@@ -1155,36 +401,52 @@ NTSTATUS DriverEntry(PDRIVER_OBJECT _DriverObject,
  */
 {
    PDEVICE_OBJECT DeviceObject;
-   NTSTATUS ret;
-   UNICODE_STRING ustr;
-   ANSI_STRING astr;
-   
-   DbgPrint("VFAT 0.0.4\n");
-          
-   DriverObject = _DriverObject;
-   
-   RtlInitAnsiString(&astr,"\\Device\\VFAT");
-   RtlAnsiStringToUnicodeString(&ustr,&astr,TRUE);
-   ret = IoCreateDevice(DriverObject,0,&ustr,
-                        FILE_DEVICE_FILE_SYSTEM,0,FALSE,&DeviceObject);
-   if (ret!=STATUS_SUCCESS)
-     {
-       return(ret);
-     }
+   UNICODE_STRING DeviceName;
+   NTSTATUS Status;
+
+   DbgPrint("VFAT 0.0.6\n");
+
+   VfatDriverObject = _DriverObject;
+
+   RtlInitUnicodeString(&DeviceName,
+                       L"\\Device\\Vfat");
+   Status = IoCreateDevice(VfatDriverObject,
+                          0,
+                          &DeviceName,
+                          FILE_DEVICE_FILE_SYSTEM,
+                          0,
+                          FALSE,
+                          &DeviceObject);
+   if (!NT_SUCCESS(Status))
+     {
+       return (Status);
+     }
+
+   DeviceObject->Flags = DO_DIRECT_IO;
+   VfatDriverObject->MajorFunction[IRP_MJ_CLOSE] = VfatBuildRequest;
+   VfatDriverObject->MajorFunction[IRP_MJ_CREATE] = VfatBuildRequest;
+   VfatDriverObject->MajorFunction[IRP_MJ_READ] = VfatBuildRequest;
+   VfatDriverObject->MajorFunction[IRP_MJ_WRITE] = VfatBuildRequest;
+   VfatDriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] =
+     VfatBuildRequest;
+   VfatDriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] =
+     VfatBuildRequest;
+   VfatDriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] =
+     VfatBuildRequest;
+   VfatDriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL] =
+     VfatBuildRequest;
+   VfatDriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] =
+     VfatBuildRequest;
+   VfatDriverObject->MajorFunction[IRP_MJ_SET_VOLUME_INFORMATION] =
+     VfatBuildRequest;
+   VfatDriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = VfatShutdown;
+   VfatDriverObject->MajorFunction[IRP_MJ_CLEANUP] = VfatBuildRequest;
+
+   VfatDriverObject->DriverUnload = NULL;
 
-   DeviceObject->Flags=0;
-   DriverObject->MajorFunction[IRP_MJ_CLOSE] = FsdClose;
-   DriverObject->MajorFunction[IRP_MJ_CREATE] = FsdCreate;
-   DriverObject->MajorFunction[IRP_MJ_READ] = FsdRead;
-   DriverObject->MajorFunction[IRP_MJ_WRITE] = FsdWrite;
-   DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] =
-                      FsdFileSystemControl;
-   DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] =
-                      FsdQueryInformation;
-   DriverObject->DriverUnload = NULL;
-   
    IoRegisterFileSystem(DeviceObject);
 
-   return(STATUS_SUCCESS);
+   return STATUS_SUCCESS;
 }
 
+/* EOF */