Reworked code for handling of asynchonous i/o requests.
[reactos.git] / reactos / drivers / fs / vfat / iface.c
index ad3b38f..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>
+#define NDEBUG
+#include <debug.h>
 
 #include "vfat.h"
 
-
 /* GLOBALS *****************************************************************/
 
-static PDRIVER_OBJECT DriverObject;
+#define  CACHEPAGESIZE(pDeviceExt) ((pDeviceExt)->BytesPerCluster > PAGESIZE ? \
+                  (pDeviceExt)->BytesPerCluster : PAGESIZE)
+
+static PDRIVER_OBJECT VfatDriverObject;
 
 /* FUNCTIONS ****************************************************************/
 
-ULONG Fat32GetNextCluster(PDEVICE_EXTENSION DeviceExt, ULONG CurrentCluster)
+static NTSTATUS
+VfatHasFileSystem(PDEVICE_OBJECT DeviceToMount,
+                 PBOOLEAN RecognizedFS)
 /*
- * FUNCTION: Retrieve the next FAT32 cluster from the FAT table via a physical
- *           disk read
+ * FUNCTION: Tests if the device contains a filesystem that can be mounted
+ *           by this fsd
  */
 {
-   ULONG FATsector;
-   ULONG FATeis;
-   PULONG Block;
-   Block = ExAllocatePool(NonPagedPool,1024);
-   FATsector=CurrentCluster/(512/sizeof(ULONG));
-   FATeis=CurrentCluster-(FATsector*(512/sizeof(ULONG)));
-   VFATReadSectors(DeviceExt->StorageDevice
-        ,(ULONG)(DeviceExt->FATStart+FATsector), 1,(UCHAR*) Block);
-   CurrentCluster = Block[FATeis];
-   if (CurrentCluster >= 0xffffff8 && CurrentCluster <= 0xfffffff)
-       CurrentCluster = 0;
-   ExFreePool(Block);
-   return(CurrentCluster);
-}
+   BootSector *Boot;
+   NTSTATUS Status;
 
-ULONG Fat16GetNextCluster(PDEVICE_EXTENSION DeviceExt, ULONG CurrentCluster)
-/*
- * FUNCTION: Retrieve the next FAT16 cluster from the FAT table from the
- *           in-memory FAT
- */
-{
-   ULONG FATsector;
-   ULONG FATeis;
-   PUSHORT Block;
-   Block = ExAllocatePool(NonPagedPool,BLOCKSIZE);
-   FATsector=CurrentCluster/(512/sizeof(USHORT));
-   FATeis=CurrentCluster-(FATsector*256);
-   memcpy(Block,DeviceExt->FAT+FATsector*BLOCKSIZE, BLOCKSIZE);
-   CurrentCluster = Block[FATeis];
-   if (CurrentCluster >= 0xfff8 && CurrentCluster <= 0xffff)
-       CurrentCluster = 0;
-   ExFreePool(Block);
-   DPRINT("Returning %x\n",CurrentCluster);
-   return(CurrentCluster);
-}
+   Boot = ExAllocatePool(NonPagedPool, 512);
 
-ULONG Fat12GetNextCluster(PDEVICE_EXTENSION DeviceExt, ULONG CurrentCluster)
-/*
- * FUNCTION: Retrieve the next FAT12 cluster from the FAT table from the
- *           in-memory FAT
- */
-{
-   unsigned char* CBlock;
-   ULONG FATsector;
-   ULONG FATOffset;
-   ULONG Entry;
-   CBlock = ExAllocatePool(NonPagedPool,1024);
-   FATsector = (CurrentCluster * 12) / (512 * 8);
-   memcpy(CBlock,DeviceExt->FAT+FATsector*BLOCKSIZE, 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
+   Status = VfatReadSectors(DeviceToMount, 0, 1, (UCHAR *) Boot);
+   if (!NT_SUCCESS(Status))
      {
-       Entry = (CBlock[((FATOffset / 24)*3) + 1] >> 4);
-       Entry |= (CBlock[((FATOffset / 24)*3) + 2] << 4);
+       return(Status);
      }
-   DPRINT("Entry %x\n",Entry);
-   if (Entry >= 0xff8 && Entry <= 0xfff)
-       Entry = 0;
-   CurrentCluster = Entry;
-   ExFreePool(CBlock);
-   DPRINT("Returning %x\n",CurrentCluster);
-   return(CurrentCluster);
-}
 
-ULONG GetNextCluster(PDEVICE_EXTENSION DeviceExt, ULONG CurrentCluster)
-/*
- * FUNCTION: Retrieve the next cluster depending on the FAT type
- */
-{
-   
-   DPRINT("GetNextCluster(DeviceExt %x, CurrentCluster %x)\n",
-           DeviceExt,CurrentCluster);
-   if (DeviceExt->FatType == FAT16)
-     {
-       return(Fat16GetNextCluster(DeviceExt, CurrentCluster));
-     }
-   else if (DeviceExt->FatType == FAT32)
+   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)
      {
-       return(Fat32GetNextCluster(DeviceExt, CurrentCluster));
+       *RecognizedFS = TRUE;
      }
    else
      {
-       return(Fat12GetNextCluster(DeviceExt, CurrentCluster));
-     }
-}
-
-ULONG FAT16FindAvailableCluster(PDEVICE_EXTENSION DeviceExt)
-/*
- * FUNCTION: Finds the first available cluster in a FAT16 table
- */
-{
-   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;
-       }
-     }
-
-     sector++;
-   }
-
-   /* 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)
-/*
- * FUNCTION: Writes a cluster to the FAT16 physical and in-memory tables
- */
-{
-   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);
-}
-
-void  WriteCluster(PDEVICE_EXTENSION DeviceExt, ULONG ClusterToWrite,
-                   ULONG NewValue)
-/*
- * FUNCTION: Write a changed FAT entry
- */
-{
-   if (DeviceExt->FatType == FAT16) {
-     FAT16WriteCluster(DeviceExt, ClusterToWrite, NewValue);
-   }
-}
-
-ULONG GetNextWriteCluster(PDEVICE_EXTENSION DeviceExt, ULONG CurrentCluster)
-/*
- * FUNCTION: Determines the next cluster to be written
- */
-{
-   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)
-     {
-       LastCluster = Fat16GetNextCluster(DeviceExt, CurrentCluster);
-        if(LastCluster == 0xFFFF) {
-          EOF = 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 {
-//FIXME           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;
-
-   }
-}
-
-ULONG ClusterToSector(PDEVICE_EXTENSION DeviceExt,
-                             unsigned long Cluster)
-/*
- * FUNCTION: Converts the cluster number to a sector number for this physical
- *           device
- */
-{
-  return DeviceExt->dataStart+((Cluster-2)*DeviceExt->Boot->SectorsPerCluster);
-}
-
-void RtlAnsiToUnicode(PWSTR Dest, PCH Source, ULONG Length)
-/*
- * FUNCTION: Convert an ANSI string to it's Unicode equivalent
- */
-{
-   int i;
-   
-   for (i=0; (i<Length && Source[i] != ' '); i++)
-     {
-       Dest[i] = Source[i];
+       *RecognizedFS = FALSE;
      }
-   Dest[i]=0;
-}
-
-void RtlCatAnsiToUnicode(PWSTR Dest, PCH Source, ULONG Length)
-/*
- * FUNCTION: Appends a converted ANSI to Unicode string to the end of an
- *           existing Unicode string
- */
-{
-   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)
-/*
- * FUNCTION: Initialize a string for use with a long file name
- */
-{
-  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)
-/*
- * FUNCTION: Append a string for use with a long file name
- */
-{
-   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)
-/*
- * FUNCTION: Copy a string for use with long file names
- */
-{
-   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)
-/*
- * FUNCTION: Move the characters in a string to a new position in the same
- *           string
- */
-{
-  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)
-/*
- * FUNCTION: Determine if the given directory entry is the last
- */
-{
-   return(((FATDirEntry *)Block)[Offset].Filename[0] == 0);
-}
-
-BOOLEAN IsDeletedEntry(PVOID Block, ULONG Offset)
-/*
- * FUNCTION: Determines if the given entry is a deleted one
- */
-{
-   /* Checks special character (short names) or attrib=0 (long names) */
+   ExFreePool(Boot);
 
-   return ((((FATDirEntry *)Block)[Offset].Filename[0] == 0xe5) ||
-           (((FATDirEntry *)Block)[Offset].Attrib == 0x00));
+   return(STATUS_SUCCESS);
 }
 
-BOOLEAN GetEntryName(PVOID Block, PULONG _Offset, PWSTR Name, PULONG _jloop,
-  PDEVICE_EXTENSION DeviceExt, ULONG * _StartingSector)
-/*
- * 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;
-   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)
+static NTSTATUS
+VfatMountDevice(PDEVICE_EXTENSION DeviceExt,
+               PDEVICE_OBJECT DeviceToMount)
 /*
- * FUNCTION: Compare to wide character strings
- * return TRUE if s1==s2
- */
-{
-   while (wtolower(*s1)==wtolower(*s2))
-     {
-       if ((*s1)==0 && (*s2)==0)
-         {
-            return(TRUE);
-         }
-       
-       s1++;
-       s2++;   
-     }
-   return(FALSE);
-}
-BOOLEAN wstrcmpjoki(PWSTR s1, PWSTR s2)
-/*
- * FUNCTION: Compare to wide character strings, s2 with jokers (* or ?)
- * return TRUE if s1 like s2
+ * FUNCTION: Mounts the device
  */
 {
-   while ((*s2=='?')||(wtolower(*s1)==wtolower(*s2)))
-   {
-      if ((*s1)==0 && (*s2)==0)
-        return(TRUE);
-      s1++;
-      s2++;    
-   }
-   if(*s2=='*')
-   {
-     s2++;
-     while (*s1)
-       if (wstrcmpjoki(s1,s2)) return TRUE;
-       else s1++;
-   }
-   if ((*s1)==0 && (*s2)==0)
-        return(TRUE);
-   return(FALSE);
-}
+   NTSTATUS Status;
 
-NTSTATUS FindFile(PDEVICE_EXTENSION DeviceExt, PFCB Fcb,
-          PFCB Parent, PWSTR FileToFind,ULONG *StartSector,ULONG *Entry)
-/*
- * FUNCTION: Find a file
- */
-{
- ULONG i, j;
- ULONG Size;
- char* block;
- WCHAR name[256];
- ULONG StartingSector;
- ULONG NextCluster;
-   DPRINT("FindFile(Parent %x, FileToFind %w)\n",Parent,FileToFind);
-   
-   if (Parent == NULL)
-   {
-     Size = DeviceExt->rootDirectorySectors;//FIXME : in fat32, no limit
-     StartingSector = DeviceExt->rootStart;
-     if(FileToFind[0]==0 ||(FileToFind[0]=='\\' && FileToFind[1]==0))
-     {// it's root !
-       memset(Fcb,0,sizeof(FCB));
-       memset(Fcb->entry.Filename,' ',11);
-       if (DeviceExt->FatType == FAT32)
-         Fcb->entry.FirstCluster=2;
-       else Fcb->entry.FirstCluster=1;
-       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);
-   }
-   block = ExAllocatePool(NonPagedPool,BLOCKSIZE);
-   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 (IsLastEntry((PVOID)block,i))
-       {
-         ExFreePool(block);
-         return(STATUS_UNSUCCESSFUL);
-       }
-       if (GetEntryName((PVOID)block,&i,name,&j,DeviceExt,&StartingSector))
-       {
-//               DPRINT("Comparing %w %w\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(DeviceExt->FatType==FAT32)
-//           {
-//             if(((FATDirEntry *)block)[i].FirstCluster==0
-//                   &&((FATDirEntry *)block)[i].FirstClusterHigh==0
-//                       ) i++;
-//           }
-//           else
-//              if(((FATDirEntry *)block)[i].FirstCluster==0) i++;
-           if( i==(ENTRIES_PER_SECTOR))
-           {// entry is in next sector
-             StartingSector++;
-             VFATReadSectors(DeviceExt->StorageDevice,StartingSector,1,block);
-             i=0;
-           }
-           memcpy(&Fcb->entry,&((FATDirEntry *)block)[i],
-                          sizeof(FATDirEntry));
-           vfat_wcsncpy(Fcb->ObjectName,name,251);
-           ExFreePool(block);
-           if(StartSector) *StartSector=StartingSector;
-           if(Entry) *Entry=i;
-           return(STATUS_SUCCESS);
-         }
-       }
-     }
-     if(Entry) *Entry=0;
-     // not found in this sector, try next :
+   DPRINT("Mounting VFAT device...");
+   DPRINT("DeviceExt %x\n", DeviceExt);
 
-     /* 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 */
+   DeviceExt->Boot = ExAllocatePool(NonPagedPool, 512);
 
-     StartingSector++;
-     /*   if (Parent == NULL)
+   Status = VfatReadSectors(DeviceToMount, 0, 1, (UCHAR *) DeviceExt->Boot);
+   if (!NT_SUCCESS(Status))
      {
-            StartingSector++;
+       return(Status);
      }
-     else
-     {
-       NextCluster = GetNextCluster(DeviceExt,NextCluster);
-       if (NextCluster == 0)
-       {
-         ExFreePool(block);
-         return(STATUS_UNSUCCESSFUL);
-       }
-       StartingSector = ClusterToSector(DeviceExt,NextCluster);
-     } */
-   }
-   ExFreePool(block);
-   return(STATUS_UNSUCCESSFUL);
-}
 
+   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;
 
-NTSTATUS FsdCloseFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject)
-/*
- * FUNCTION: Closes a file
- */
-{
-   /* NOP */
-   return STATUS_SUCCESS;
-}
-
-NTSTATUS FsdOpenFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject, 
-                    PWSTR FileName)
-/*
- * FUNCTION: Opens a file
- */
-{
-   PWSTR current;
-   PWSTR next;
-   PWSTR string;
-   PFCB ParentFcb;
-   PFCB Fcb;
-   PFCB Temp;
-   NTSTATUS Status;
-
-   DPRINT("FsdOpenFile(%08lx, %08lx, %08lx)\n", 
-          DeviceExt,
-          FileObject,
-          FileName);
-
-CHECKPOINT;
-   string = FileName;
-CHECKPOINT;
-   ParentFcb = NULL;
-CHECKPOINT;
-   Fcb = ExAllocatePool(NonPagedPool, sizeof(FCB));
-CHECKPOINT;
-   next = &string[0];
-CHECKPOINT;
-   current = next+1;
-   
-CHECKPOINT;
-   while (next!=NULL)
+   if (DeviceExt->BytesPerCluster >= PAGESIZE && 
+       (DeviceExt->BytesPerCluster % PAGESIZE) != 0)
      {
-       DPRINT("current %w next %x\n",current,next);
-       
-       *next = '\\';
-       current = next+1;
-       next = wcschr(next+1,'\\');
-       if (next!=NULL)
-         {
-            *next=0;
-         }
-       
-CHECKPOINT;
-      Status = FindFile(DeviceExt,Fcb,ParentFcb,current,NULL,NULL);
-       if (Status != STATUS_SUCCESS)
-         {
-             /* FIXME: should the FCB be freed here?  */
-            return(Status);
-         }
-       Temp = Fcb;
-       if (ParentFcb == NULL)
-         {
-            Fcb = ExAllocatePool(NonPagedPool,sizeof(FCB));
-         }
-       else
-         {
-            Fcb = ParentFcb;
-         }
-       ParentFcb = Temp;
-CHECKPOINT;
+       DbgPrint("Invalid cluster size\n");
+       KeBugCheck(0);
      }
-   FileObject->FsContext = ParentFcb;
-   DPRINT("file opn, fcb=%x\n",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);
-
-   VFATReadSectors(DeviceToMount, 0, 1, (UCHAR *)Boot);
-
-   if (strncmp(Boot->SysType,"FAT12",5)==0 ||
-       strncmp(Boot->SysType,"FAT16",5)==0 ||
-       strncmp(((struct _BootSector32 *)(Boot))->SysType,"FAT32",5)==0)
+   else if (DeviceExt->BytesPerCluster < PAGESIZE &&
+           (PAGESIZE % DeviceExt->BytesPerCluster) != 0)
      {
-       ExFreePool(Boot);
-       return(TRUE);
+       DbgPrint("Invalid cluster size2\n");
+       KeBugCheck(0);
      }
-   ExFreePool(Boot);
-   return(FALSE);
-}
 
-NTSTATUS FsdMountDevice(PDEVICE_EXTENSION DeviceExt,
-                       PDEVICE_OBJECT DeviceToMount)
-/*
- * FUNCTION: Mounts the device
- */
-{
-   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->BytesPerCluster = DeviceExt->Boot->SectorsPerCluster *
-                                DeviceExt->Boot->BytesPerSector;
-   
-   if (strncmp(DeviceExt->Boot->SysType,"FAT12",5)==0)
+   if (strncmp (DeviceExt->Boot->SysType, "FAT12", 5) == 0)
      {
+       DbgPrint("FAT12\n");
        DeviceExt->FatType = FAT12;
      }
-   else if (strncmp(((struct _BootSector32 *)(DeviceExt->Boot))->SysType,"FAT32",5)==0)
+   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;
-        }
+       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);
+     }
    else
      {
+       DbgPrint("FAT16\n");
        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);
-   }
-   return STATUS_SUCCESS;
-}
-
-void VFATLoadCluster(PDEVICE_EXTENSION DeviceExt, PVOID Buffer, ULONG Cluster)
-/*
- * FUNCTION: Load a cluster from the physical device
- */
-{
-   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);
-}
-
-void VFATWriteCluster(PDEVICE_EXTENSION DeviceExt, PVOID Buffer, ULONG Cluster)
-/*
- * FUNCTION: Write a cluster to the physical device
- */
-{
-   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 (CurrentCluster<2)
-     return STATUS_UNSUCCESSFUL;// FIXME : root of FAT16 ?
-   DPRINT("DeviceExt->BytesPerCluster %x\n",DeviceExt->BytesPerCluster);
-   
-   if (ReadOffset >= Fcb->entry.FileSize)
-     {
-       return(STATUS_END_OF_FILE);
-     }
-   if ((ReadOffset + Length) > Fcb->entry.FileSize)
-     {
-       Length = Fcb->entry.FileSize - ReadOffset;
-     }
-   *LengthRead = 0;
-   Temp = ExAllocatePool(NonPagedPool,DeviceExt->BytesPerCluster);
-   for (FileOffset=0; FileOffset < FirstCluster; FileOffset++)
-   {
-     CurrentCluster = GetNextCluster(DeviceExt,CurrentCluster);
-   }
-   CHECKPOINT;
-   if ((ReadOffset % DeviceExt->BytesPerCluster)!=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;        
-     }
-   CHECKPOINT;
-   while (Length > DeviceExt->BytesPerCluster)
-     {
-       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;
-     }
-   CHECKPOINT;
-   if (Length > 0)
-     {
-       (*LengthRead) = (*LengthRead) + Length;
-       VFATLoadCluster(DeviceExt, Temp, CurrentCluster);
-       memcpy(Buffer, Temp, Length);
-     }
-   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;
+  PDEVICE_OBJECT DeviceObject = NULL;
+  PDEVICE_EXTENSION DeviceExt = NULL;
+  BOOLEAN RecognizedFS;
+  NTSTATUS Status;
+  PVFATFCB Fcb = NULL;
+  PVFATCCB Ccb = NULL;
 
-   /* Allocate a buffer to hold 1 cluster of data */
+  DPRINT1("VfatMount(IrpContext %x)\n", IrpContext);
 
-   Temp = ExAllocatePool(NonPagedPool,DeviceExt->BytesPerCluster);
+  assert (IrpContext);
 
-   /* Find the cluster according to the offset in the file */
+  if (IrpContext->DeviceObject != VfatDriverObject->DeviceObject)
+  {
+     // Only allowed on the main device object
+     Status = STATUS_INVALID_DEVICE_REQUEST;
+     goto ByeBye;
+  }
 
-   for (FileOffset=0; FileOffset < FirstCluster; FileOffset++)
-     {
-       CurrentCluster = GetNextCluster(DeviceExt,CurrentCluster);
-     }
-   CHECKPOINT;
+  Status = VfatHasFileSystem (IrpContext->Stack->Parameters.Mount.DeviceObject, &RecognizedFS);
+  if (!NT_SUCCESS(Status))
+  {
+     goto ByeBye;
+  }
 
-   /*
-      If the offset in the cluster doesn't fall on the cluster boundary then
-      we have to write only from the specified offset
-   */
+  if (RecognizedFS == FALSE)
+  {
+     DPRINT("VFAT: Unrecognized Volume\n");
+     Status = STATUS_UNRECOGNIZED_VOLUME;
+     goto ByeBye;
+  }
 
-   if ((WriteOffset % DeviceExt->BytesPerCluster)!=0)
-     {
-       TempLength = min(Length,DeviceExt->BytesPerCluster -
-                        (WriteOffset % DeviceExt->BytesPerCluster));
+  DPRINT("VFAT: Recognized volume\n");
 
-        /* Read in the existing cluster data */
-        VFATLoadCluster(DeviceExt,Temp,CurrentCluster);
+  Status = IoCreateDevice(VfatDriverObject,
+                         sizeof (DEVICE_EXTENSION),
+                         NULL,
+                         FILE_DEVICE_FILE_SYSTEM,
+                         0,
+                         FALSE,
+                         &DeviceObject);
+  if (!NT_SUCCESS(Status))
+  {
+    goto ByeBye;
+  }
 
-        /* Overwrite the last parts of the data as necessary */
-       memcpy(Temp + WriteOffset % DeviceExt->BytesPerCluster, Buffer,
-              TempLength);
+  DeviceObject->Flags = DeviceObject->Flags | DO_DIRECT_IO;
+  DeviceExt = (PVOID) DeviceObject->DeviceExtension;
+  RtlZeroMemory(DeviceExt, sizeof(DEVICE_EXTENSION));
 
-        /* Write the cluster back */
-        VFATWriteCluster(DeviceExt,Temp,CurrentCluster);
+  /* 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;
+  }
 
-        /* Next write cluster */
-       CurrentCluster = GetNextWriteCluster(DeviceExt, CurrentCluster);
+#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;
+  }
 
-       Length = Length - TempLength;
-       Buffer = Buffer + TempLength;        
-     }
-   CHECKPOINT;
+  DeviceExt->LastAvailableCluster = 0;
+  ExInitializeResourceLite(&DeviceExt->DirResource);
+  ExInitializeResourceLite(&DeviceExt->FatResource);
 
-   /* Write the buffer in chunks of 1 cluster */
+  KeInitializeSpinLock(&DeviceExt->FcbListLock);
+  InitializeListHead(&DeviceExt->FcbListHead);
 
-   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;
+  /* 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;
 
-   /* Write the remainder */
+  /* read volume label */
+  ReadVolumeLabel(DeviceExt,  DeviceObject->Vpb);
+  Status = STATUS_SUCCESS;
 
-   if (Length > 0)
-     {
-       memcpy(Temp, Buffer, Length);
-       VFATWriteCluster(DeviceExt, Temp, CurrentCluster);
-     }
+ByeBye:
 
-   ExFreePool(Temp);
-   return(STATUS_SUCCESS);
+  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 FsdClose(PDEVICE_OBJECT DeviceObject, PIRP Irp)
-/*
- * FUNCTION: Close a file
- */
-{
-   PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
-   PFILE_OBJECT FileObject = Stack->FileObject;
-   PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
-   NTSTATUS Status;
-
-   Status = FsdCloseFile(DeviceExtension,FileObject);
-
-   Irp->IoStatus.Status = Status;
-   Irp->IoStatus.Information = 0;
-   
-   IoCompleteRequest(Irp, IO_NO_INCREMENT);
-   return(Status);
-}
 
-NTSTATUS FsdCreate(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+NTSTATUS VfatFileSystemControl(PVFAT_IRP_CONTEXT IrpContext)
 /*
- * FUNCTION: Create or open a file
+ * FUNCTION: File system control
  */
 {
-   PIO_STACK_LOCATION Stack;
-   PFILE_OBJECT FileObject;
-   NTSTATUS Status;
-   PDEVICE_EXTENSION DeviceExt;
-
-   DPRINT("FsdCreate(DeviceObject %08lx, Irp %08lx)\n",
-          DeviceObject,
-          Irp);
-
-   Stack = IoGetCurrentIrpStackLocation(Irp);
-CHECKPOINT;
-   FileObject = Stack->FileObject;
-CHECKPOINT;
-   DeviceExt = DeviceObject->DeviceExtension;
-CHECKPOINT;
-   Status = FsdOpenFile(DeviceExt,FileObject,FileObject->FileName.Buffer);
-CHECKPOINT;
-   
-   Irp->IoStatus.Status = Status;
-CHECKPOINT;
-   Irp->IoStatus.Information = 0;
-CHECKPOINT;
-   
-   IoCompleteRequest(Irp, IO_NO_INCREMENT);
-CHECKPOINT;
-
-   return Status;
-}
-
 
-NTSTATUS FsdWrite(PDEVICE_OBJECT DeviceObject, PIRP Irp)
-/*
- * FUNCTION: Write to a file
- */
-{
-   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);
+   DPRINT1("VfatFileSystemControl(IrpContext %x)\n", IrpContext);
 
-   Status = FsdWriteFile(DeviceExt,FileObject,Buffer,Length,Offset);
+   assert (IrpContext);
 
-   Irp->IoStatus.Status = Status;
-   Irp->IoStatus.Information = Length;
-   IoCompleteRequest(Irp,IO_NO_INCREMENT);
-
-   return(Status);
-}
-
-NTSTATUS FsdRead(PDEVICE_OBJECT DeviceObject, PIRP Irp)
-/*
- * FUNCTION: Read from a file
- */
-{
-   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)
-/*
- * FUNCTION: Mount the filesystem
- */
-{
-   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;
-   // use same vpb as device disk
-   DeviceObject->Vpb=DeviceToMount->Vpb;
-   FsdMountDevice(DeviceExt,DeviceToMount);
-   DeviceObject->Vpb->Flags |= VPB_MOUNTED;
-   DeviceExt->StorageDevice = IoAttachDeviceToDeviceStack(DeviceObject,
-                                                         DeviceToMount);
-   return(STATUS_SUCCESS);
-}
+   switch (IrpContext->MinorFunction)
+     {
+       case IRP_MN_USER_FS_REQUEST:
+          DPRINT1("VFAT FSC: IRP_MN_USER_FS_REQUEST\n");
+          Status = STATUS_INVALID_DEVICE_REQUEST;
+          break;
 
-NTSTATUS FsdFileSystemControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
-/*
- * FUNCTION: File system control
- */
-{
-   PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
-//   PVPB      vpb = Stack->Parameters.Mount.Vpb;
-   PDEVICE_OBJECT DeviceToMount = Stack->Parameters.Mount.DeviceObject;
-   NTSTATUS Status;
+       case IRP_MN_MOUNT_VOLUME:
+          Status = VfatMount(IrpContext);
+          break;
 
-   DPRINT("VFAT FSC\n");
+       case IRP_MN_VERIFY_VOLUME:
+          DPRINT1("VFAT FSC: IRP_MN_VERIFY_VOLUME\n");
+          Status = STATUS_INVALID_DEVICE_REQUEST;
+          break;
 
-   if (FsdHasFileSystem(DeviceToMount))
-     {
-       Status = FsdMount(DeviceToMount);
+       default:
+          DPRINT1("VFAT FSC: MinorFunction %d\n", IrpContext->MinorFunction);
+          Status = STATUS_INVALID_DEVICE_REQUEST;
+          break;
      }
-   else
-     {
-        DPRINT("VFAT: Unrecognized Volume\n");
-       Status = STATUS_UNRECOGNIZED_VOLUME;
-     }
-   DPRINT("VFAT File system successfully mounted\n");
 
-   Irp->IoStatus.Status = Status;
-   Irp->IoStatus.Information = 0;
+   IrpContext->Irp->IoStatus.Status = Status;
+   IrpContext->Irp->IoStatus.Information = 0;
 
-   IoCompleteRequest(Irp, IO_NO_INCREMENT);
-   return(Status);
+   IoCompleteRequest (IrpContext->Irp, IO_NO_INCREMENT);
+   return (Status);
 }
 
-NTSTATUS FsdGetStandardInformation(PFCB FCB, PDEVICE_OBJECT DeviceObject,
-                                   PFILE_STANDARD_INFORMATION StandardInfo)
-/*
- * FUNCTION: Retrieve the standard file information
- */
-{
-  PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
-  unsigned long AllocSize;
-
-  RtlZeroMemory(StandardInfo, sizeof(FILE_STANDARD_INFORMATION));
-
-  /* Make allocsize a rounded up multiple of BytesPerCluster */
-  AllocSize = ((FCB->entry.FileSize +  DeviceExtension->BytesPerCluster - 1) /
-              DeviceExtension->BytesPerCluster) *
-              DeviceExtension->BytesPerCluster;
-
-  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;
-}
 
-NTSTATUS FsdQueryInformation(PDEVICE_OBJECT DeviceObject, PIRP Irp)
-/*
- * FUNCTION: Retrieve the specified file information
- */
-{
-   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???
-   FCB=(PFCB)(FileObject->FsContext);
-
-   SystemBuffer = Irp->AssociatedIrp.SystemBuffer;
-
-   switch(FileInformationClass) {
-      case FileStandardInformation:
-         RC = FsdGetStandardInformation(FCB, DeviceObject, SystemBuffer);
-      break;
-   }
-
-   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:
@@ -1247,39 +401,52 @@ NTSTATUS DriverEntry(PDRIVER_OBJECT _DriverObject,
  */
 {
    PDEVICE_OBJECT DeviceObject;
-   NTSTATUS ret;
-   UNICODE_STRING ustr;
-   ANSI_STRING astr;
-   
-   DbgPrint("VFAT 0.0.5\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->MajorFunction[IRP_MJ_DIRECTORY_CONTROL] =
-                      FsdDirectoryControl;
-
-   DriverObject->DriverUnload = NULL;
-   
    IoRegisterFileSystem(DeviceObject);
 
-   return(STATUS_SUCCESS);
+   return STATUS_SUCCESS;
 }
 
+/* EOF */