Don't check the share access for directories.
[reactos.git] / reactos / drivers / fs / vfat / create.c
index 268bbef..dbcef14 100644 (file)
-/* $Id: create.c,v 1.26 2001/06/14 21:05:08 jfilby Exp $
+/*
+ *  ReactOS kernel
+ *  Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
  *
- * COPYRIGHT:        See COPYING in the top level directory
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
  * PROJECT:          ReactOS kernel
- * FILE:             services/fs/vfat/create.c
+ * FILE:             drivers/fs/vfat/create.c
  * PURPOSE:          VFAT Filesystem
  * PROGRAMMER:       Jason Filby (jasonfilby@yahoo.com)
-
+ *                   Hartmut Birr
  */
 
 /* INCLUDES *****************************************************************/
 
-#include <ddk/ntddk.h>
-#include <wchar.h>
-#include <limits.h>
-
 #define NDEBUG
-#include <debug.h>
-
 #include "vfat.h"
 
-/* GLOBALS *******************************************************************/
-
-#define TAG(A, B, C, D) (ULONG)(((A)<<0) + ((B)<<8) + ((C)<<16) + ((D)<<24))
-
-#define TAG_CCB TAG('V', 'C', 'C', 'B')
-
 /* FUNCTIONS *****************************************************************/
 
-BOOLEAN
-IsLastEntry (PVOID Block, ULONG Offset)
-/*
- * FUNCTION: Determine if the given directory entry is the last
- */
-{
-  return (((FATDirEntry *) Block)[Offset].Filename[0] == 0);
-}
-
-BOOLEAN
-IsVolEntry (PVOID Block, ULONG Offset)
-/*
- * FUNCTION: Determine if the given directory entry is a vol entry
- */
+void  vfat8Dot3ToString (PFAT_DIR_ENTRY pEntry, PUNICODE_STRING NameU)
 {
-  if ((((FATDirEntry *) Block)[Offset].Attrib) == 0x28)
-    return TRUE;
-  else
-    return FALSE;
-}
+  OEM_STRING StringA;
+  USHORT Length;
+  CHAR  cString[12];
 
-BOOLEAN
-IsDeletedEntry (PVOID Block, ULONG Offset)
-/*
- * FUNCTION: Determines if the given entry is a deleted one
- */
-{
-  /* Checks special character */
+  RtlCopyMemory(cString, pEntry->ShortName, 11);
+  cString[11] = 0;
+  if (cString[0] == 0x05)
+    {
+      cString[0] = 0xe5;
+    }
 
-  return ((((FATDirEntry *) Block)[Offset].Filename[0] == 0xe5) ||
-         (((FATDirEntry *) Block)[Offset].Filename[0] == 0));
-}
+  StringA.Buffer = cString;
+  for (StringA.Length = 0;
+       StringA.Length < 8 && StringA.Buffer[StringA.Length] != ' ';
+       StringA.Length++);
+  StringA.MaximumLength = StringA.Length;
 
-static void  vfat8Dot3ToString (PCHAR pBasename, PCHAR pExtension, PWSTR pName)
-{
-  int  fromIndex, toIndex;
+  RtlOemStringToUnicodeString(NameU, &StringA, FALSE);
 
-  fromIndex = toIndex = 0; 
-  while (fromIndex < 8 && pBasename [fromIndex] != ' ')
-  {
-    pName [toIndex++] = pBasename [fromIndex++];
-  }
-  if (pExtension [0] != ' ')
-  {
-    pName [toIndex++] = L'.';
-    fromIndex = 0;
-    while (fromIndex < 3 && pBasename [fromIndex] != ' ')
+  if (pEntry->lCase & VFAT_CASE_LOWER_BASE)
     {
-      pName [toIndex++] = pExtension [fromIndex++];
+      RtlDowncaseUnicodeString(NameU, NameU, FALSE);
     }
-  }
-  pName [toIndex] = L'\0';
-}
-
-static void  vfat8Dot3ToVolumeLabel (PCHAR pBasename, PCHAR pExtension, PWSTR pName)
-{
-  int  fromIndex, toIndex;
-
-  fromIndex = toIndex = 0; 
-  while (fromIndex < 8 && pBasename [fromIndex] != ' ')
-  {
-    pName [toIndex++] = pBasename [fromIndex++];
-  }
-  if (pExtension [0] != ' ')
-  {
-    fromIndex = 0;
-    while (fromIndex < 3 && pBasename [fromIndex] != ' ')
+  if (cString[8] != ' ')
     {
-      pName [toIndex++] = pExtension [fromIndex++];
+      Length = NameU->Length;
+      NameU->Buffer += Length / sizeof(WCHAR);
+      if (!FAT_ENTRY_VOLUME(pEntry))
+        {
+         Length += sizeof(WCHAR);
+          NameU->Buffer[0] = L'.';
+          NameU->Buffer++;
+       }
+      NameU->Length = 0;
+      NameU->MaximumLength -= Length;
+
+      StringA.Buffer = &cString[8];
+      for (StringA.Length = 0;
+           StringA.Length < 3 && StringA.Buffer[StringA.Length] != ' ';
+           StringA.Length++);
+      StringA.MaximumLength = StringA.Length;
+      RtlOemStringToUnicodeString(NameU, &StringA, FALSE);
+      if (pEntry->lCase & VFAT_CASE_LOWER_EXT)
+        {
+          RtlDowncaseUnicodeString(NameU, NameU, FALSE);
+        }
+      NameU->Buffer -= Length / sizeof(WCHAR);
+      NameU->Length += Length;
+      NameU->MaximumLength += Length;
     }
-  }
-  pName [toIndex] = L'\0';
+  NameU->Buffer[NameU->Length / sizeof(WCHAR)] = 0;
+  DPRINT("'%wZ'\n", NameU);
 }
 
-BOOLEAN
-GetEntryName (PVOID Block, PULONG _Offset, PWSTR Name, PULONG _jloop,
-             PDEVICE_EXTENSION DeviceExt, ULONG * _StartingSector)
+NTSTATUS
+ReadVolumeLabel (PDEVICE_EXTENSION DeviceExt, PVPB Vpb)
 /*
- * FUNCTION: Retrieves the file name, be it in short or long file name format
+ * FUNCTION: Read the volume label
  */
 {
-  FATDirEntry *test;
-  slot *test2;
-  ULONG Offset = *_Offset;
-  ULONG StartingSector = *_StartingSector;
-  ULONG jloop = *_jloop;
-  ULONG cpos;
-
-  test = (FATDirEntry *) Block;
-  test2 = (slot *) Block;
-
-  *Name = 0;
-
-  if (IsDeletedEntry (Block, Offset))
-    {
-      return (FALSE);
-    }
-
-  if (test2[Offset].attr == 0x0f)
-    {
-      vfat_initstr (Name, 256);
-      vfat_wcsncpy (Name, test2[Offset].name0_4, 5);
-      vfat_wcsncat (Name, test2[Offset].name5_10, 5, 6);
-      vfat_wcsncat (Name, test2[Offset].name11_12, 11, 2);
-
-      cpos = 0;
-      while ((test2[Offset].id != 0x41) && (test2[Offset].id != 0x01) &&
-            (test2[Offset].attr > 0))
-       {
-         Offset++;
-         if (Offset == ENTRIES_PER_SECTOR)
-           {
-             Offset = 0;
-              /* FIXME: Check status */
-              GetNextSector (DeviceExt, StartingSector, &StartingSector, FALSE);
-             jloop++;
-             /* FIXME: Check status */
-             VfatReadSectors (DeviceExt->StorageDevice,
-                              StartingSector, 1, Block);
-             test2 = (slot *) Block;
-           }
-         cpos++;
-         vfat_movstr (Name, 13, 0, cpos * 13);
-         vfat_wcsncpy (Name, test2[Offset].name0_4, 5);
-         vfat_wcsncat (Name, test2[Offset].name5_10, 5, 6);
-         vfat_wcsncat (Name, test2[Offset].name11_12, 11, 2);
-
-       }
-
-      if (IsDeletedEntry (Block, Offset + 1))
-       {
-         Offset++;
-         *_Offset = Offset;
-         *_jloop = jloop;
-         *_StartingSector = StartingSector;
-         return (FALSE);
-       }
-
-      *_Offset = Offset;
-      *_jloop = jloop;
-      *_StartingSector = StartingSector;
+  PVOID Context = NULL;
+  ULONG DirIndex = 0;
+  PDIR_ENTRY Entry;
+  PVFATFCB pFcb;
+  LARGE_INTEGER FileOffset;
+  UNICODE_STRING NameU;
+  ULONG SizeDirEntry;
+  ULONG EntriesPerPage;
+  OEM_STRING StringO;
+
+  NameU.Buffer = Vpb->VolumeLabel;
+  NameU.Length = 0;
+  NameU.MaximumLength = sizeof(Vpb->VolumeLabel);
+  *(Vpb->VolumeLabel) = 0;
+  Vpb->VolumeLabelLength = 0;
 
-      return (TRUE);
-    }
+  if (DeviceExt->Flags & VCB_IS_FATX)
+  {
+    SizeDirEntry = sizeof(FATX_DIR_ENTRY);
+    EntriesPerPage = FATX_ENTRIES_PER_PAGE;
+  }
+  else
+  {
+    SizeDirEntry = sizeof(FAT_DIR_ENTRY);
+    EntriesPerPage = FAT_ENTRIES_PER_PAGE;
+  }
 
-  vfat8Dot3ToString (test[Offset].Filename, test[Offset].Ext, Name);
+  ExAcquireResourceExclusiveLite (&DeviceExt->DirResource, TRUE);
+  pFcb = vfatOpenRootFCB (DeviceExt);
+  ExReleaseResourceLite (&DeviceExt->DirResource);
 
-  *_Offset = Offset;
+  FileOffset.QuadPart = 0;
+  if (CcMapData(pFcb->FileObject, &FileOffset, PAGE_SIZE, TRUE, &Context, (PVOID*)&Entry))
+  {
+     while (TRUE)
+     {
+       if (ENTRY_VOLUME(DeviceExt, Entry))
+       {
+          /* copy volume label */
+          if (DeviceExt->Flags & VCB_IS_FATX)
+          {
+            StringO.Buffer = (PCHAR)Entry->FatX.Filename;
+            StringO.MaximumLength = StringO.Length = Entry->FatX.FilenameLength;
+            RtlOemStringToUnicodeString(&NameU, &StringO, FALSE);
+          }
+          else
+          {
+            vfat8Dot3ToString (&Entry->Fat, &NameU);
+          }
+          Vpb->VolumeLabelLength = NameU.Length;
+          break;
+       }
+       if (ENTRY_END(DeviceExt, Entry))
+       {
+          break;
+       }
+       DirIndex++;
+       Entry = (PDIR_ENTRY)((ULONG_PTR)Entry + SizeDirEntry);
+       if ((DirIndex % EntriesPerPage) == 0)
+       {
+         CcUnpinData(Context);
+         FileOffset.u.LowPart += PAGE_SIZE;
+         if (!CcMapData(pFcb->FileObject, &FileOffset, PAGE_SIZE, TRUE, &Context, (PVOID*)&Entry))
+         {
+            Context = NULL;
+            break;
+         }
+       }
+     }
+     if (Context)
+     {
+       CcUnpinData(Context);
+     }
+  }
+  ExAcquireResourceExclusiveLite (&DeviceExt->DirResource, TRUE);
+  vfatReleaseFCB (DeviceExt, pFcb);
+  ExReleaseResourceLite (&DeviceExt->DirResource);
 
-  return (TRUE);
+  return STATUS_SUCCESS;
 }
 
 NTSTATUS
-ReadVolumeLabel (PDEVICE_EXTENSION DeviceExt, PVPB Vpb)
+FindFile (PDEVICE_EXTENSION DeviceExt,
+          PVFATFCB Parent,
+          PUNICODE_STRING FileToFindU,
+         PVFAT_DIRENTRY_CONTEXT DirContext,
+         BOOLEAN First)
 /*
- * FUNCTION: Read the volume label
+ * FUNCTION: Find a file
  */
 {
-  ULONG i = 0;
-  ULONG j;
-  ULONG Size;
-  char *block;
-  ULONG StartingSector;
-  ULONG NextCluster;
+  PWCHAR PathNameBuffer;
+  USHORT PathNameBufferLength;
   NTSTATUS Status;
+  PVOID Context = NULL;
+  PVOID Page;
+  PVFATFCB rcFcb;
+  BOOLEAN Found;
+  UNICODE_STRING PathNameU;
+  UNICODE_STRING FileToFindUpcase;
+  BOOLEAN WildCard;
+
+  DPRINT ("FindFile(Parent %x, FileToFind '%wZ', DirIndex: %d)\n",
+          Parent, FileToFindU, DirContext->DirIndex);
+  DPRINT ("FindFile: Path %wZ)\n",&Parent->PathNameU);
+
+  PathNameBufferLength = LONGNAME_MAX_LENGTH * sizeof(WCHAR);
+  PathNameBuffer = ExAllocatePool(NonPagedPool, PathNameBufferLength + sizeof(WCHAR));
+  if (!PathNameBuffer)
+  {
+    CHECKPOINT1;
+    return STATUS_INSUFFICIENT_RESOURCES;
+  }
 
-  Size = DeviceExt->rootDirectorySectors;      /* FIXME : in fat32, no limit */
-  StartingSector = DeviceExt->rootStart;
-  NextCluster = 0;
+  PathNameU.Buffer = PathNameBuffer;
+  PathNameU.Length = 0;
+  PathNameU.MaximumLength = PathNameBufferLength;
 
-  block = ExAllocatePool (NonPagedPool, BLOCKSIZE);
-  DPRINT ("FindFile : start at sector %lx, entry %ld\n", StartingSector, i);
-  for (j = 0; j < Size; j++)
-    {
-      /* FIXME: Check status */
-      VfatReadSectors (DeviceExt->StorageDevice, StartingSector, 1, block);
+  DirContext->LongNameU.Length = 0;
+  DirContext->ShortNameU.Length = 0;
 
-      for (i = 0; i < ENTRIES_PER_SECTOR; i++)
-       {
-         if (IsVolEntry ((PVOID) block, i))
-           {
-             FATDirEntry *test = (FATDirEntry *) block;
-
-             /* copy volume label */
-              vfat8Dot3ToVolumeLabel (test[i].Filename, test[i].Ext, Vpb->VolumeLabel);
-             Vpb->VolumeLabelLength = wcslen (Vpb->VolumeLabel);
+  WildCard = FsRtlDoesNameContainWildCards(FileToFindU);
 
-             ExFreePool (block);
-             return (STATUS_SUCCESS);
+  if (WildCard == FALSE)
+    {
+      /* if there is no '*?' in the search name, than look first for an existing fcb */
+      RtlCopyUnicodeString(&PathNameU, &Parent->PathNameU);
+      if (!vfatFCBIsRoot(Parent))
+        {
+          PathNameU.Buffer[PathNameU.Length / sizeof(WCHAR)] = L'\\';
+         PathNameU.Length += sizeof(WCHAR);
+        }
+      RtlAppendUnicodeStringToString(&PathNameU, FileToFindU);
+      PathNameU.Buffer[PathNameU.Length / sizeof(WCHAR)] = 0;
+      rcFcb = vfatGrabFCBFromTable(DeviceExt, &PathNameU);
+      if (rcFcb)
+        {
+         ULONG startIndex = rcFcb->startIndex;
+         if ((rcFcb->Flags & FCB_IS_FATX_ENTRY) && !vfatFCBIsRoot(Parent))
+           {
+             startIndex += 2;
            }
-         if (IsLastEntry ((PVOID) block, i))
+         if(startIndex >= DirContext->DirIndex)
            {
-             *(Vpb->VolumeLabel) = 0;
-             Vpb->VolumeLabelLength = 0;
-             ExFreePool (block);
-             return (STATUS_UNSUCCESSFUL);
+             RtlCopyUnicodeString(&DirContext->LongNameU, &rcFcb->LongNameU);
+             RtlCopyUnicodeString(&DirContext->ShortNameU, &rcFcb->ShortNameU);
+             RtlCopyMemory(&DirContext->DirEntry, &rcFcb->entry, sizeof(DIR_ENTRY));
+             DirContext->StartIndex = rcFcb->startIndex;
+             DirContext->DirIndex = rcFcb->dirIndex;
+              DPRINT("FindFile: new Name %wZ, DirIndex %d (%d)\n",
+                    &DirContext->LongNameU, DirContext->DirIndex, DirContext->StartIndex);
+             Status = STATUS_SUCCESS;
            }
-       }
-      /* not found in this sector, try next : */
-
-      /* directory can be fragmented although it is best to keep them
-         unfragmented.*/
-      StartingSector++;
-
-      if (DeviceExt->FatType == FAT32)
-       {
-         if (StartingSector == ClusterToSector (DeviceExt, NextCluster + 1))
+          else
            {
-             Status = GetNextCluster (DeviceExt, NextCluster, &NextCluster,
-                                      FALSE);
-             if (NextCluster == 0 || NextCluster == 0xffffffff)
-               {
-                 *(Vpb->VolumeLabel) = 0;
-                 Vpb->VolumeLabelLength = 0;
-                 ExFreePool (block);
-                 return (STATUS_UNSUCCESSFUL);
-               }
-             StartingSector = ClusterToSector (DeviceExt, NextCluster);
+             CHECKPOINT1;
+             Status = STATUS_UNSUCCESSFUL;
            }
+          vfatReleaseFCB(DeviceExt, rcFcb);
+         ExFreePool(PathNameBuffer);
+         return Status;
        }
     }
-  *(Vpb->VolumeLabel) = 0;
-  Vpb->VolumeLabelLength = 0;
-  ExFreePool (block);
-  return (STATUS_UNSUCCESSFUL);
-}
-
-
-NTSTATUS
-FindFile (PDEVICE_EXTENSION DeviceExt, PVFATFCB Fcb,
-         PVFATFCB Parent, PWSTR FileToFind, ULONG * StartSector,
-         ULONG * Entry)
-/*
- * FUNCTION: Find a file
- */
-{
-  ULONG i, j;
-  ULONG Size;
-  char *block;
-  WCHAR name[256];
-  ULONG StartingSector;
-  ULONG NextCluster;
-  WCHAR TempStr[2];
-  NTSTATUS Status;
-  ULONG len;
 
-//  DPRINT ("FindFile(Parent %x, FileToFind '%S')\n", Parent, FileToFind);
-  DPRINT("FindFile: old Pathname %x, old Objectname %x)\n",Fcb->PathName, Fcb->ObjectName);
-
-  if (wcslen (FileToFind) == 0)
-    {
-      CHECKPOINT;
-      TempStr[0] = (WCHAR) '.';
-      TempStr[1] = 0;
-      FileToFind = (PWSTR)&TempStr;
-    }
+  /* FsRtlIsNameInExpression need the searched string to be upcase,
+   * even if IgnoreCase is specified */
+  Status = RtlUpcaseUnicodeString(&FileToFindUpcase, FileToFindU, TRUE);
+  if (!NT_SUCCESS(Status))
+  {
+    CHECKPOINT;
+    ExFreePool(PathNameBuffer);
+    return Status;
+  }
 
-  if (Parent == NULL || Parent->entry.FirstCluster == 1)
+  while(TRUE)
     {
-      Size = DeviceExt->rootDirectorySectors;  /* FIXME : in fat32, no limit */
-      StartingSector = DeviceExt->rootStart;
-      NextCluster = 0;
-      if (FileToFind[0] == 0 || (FileToFind[0] == '\\' && FileToFind[1] == 0)
-         || (FileToFind[0] == '.' && FileToFind[1] == 0))
-       {
-         /* it's root : complete essentials fields then return ok */
-         CHECKPOINT;
-         memset (Fcb, 0, sizeof (VFATFCB));
-         memset (Fcb->entry.Filename, ' ', 11);
-         CHECKPOINT;
-         Fcb->PathName[0]='\\';
-         Fcb->ObjectName = &Fcb->PathName[1];
-         Fcb->entry.FileSize = DeviceExt->rootDirectorySectors * BLOCKSIZE;
-         Fcb->entry.Attrib = FILE_ATTRIBUTE_DIRECTORY;
-         if (DeviceExt->FatType == FAT32)
-           Fcb->entry.FirstCluster = 2;
-         else
-           Fcb->entry.FirstCluster = 1;    
-         if (StartSector)
-           *StartSector = StartingSector;
-         if (Entry)
-           *Entry = 0;
-           DPRINT("FindFile: new Pathname %S, new Objectname %S)\n",Fcb->PathName, Fcb->ObjectName);
-         return (STATUS_SUCCESS);
+      Status = DeviceExt->GetNextDirEntry(&Context, &Page, Parent, DirContext, First);
+      First = FALSE;
+      if (Status == STATUS_NO_MORE_ENTRIES)
+        {
+         break;
+        }
+      if (ENTRY_VOLUME(DeviceExt, &DirContext->DirEntry))
+        {
+          DirContext->DirIndex++;
+          continue;
+        }
+      if (WildCard)
+        {
+          Found = FsRtlIsNameInExpression(&FileToFindUpcase, &DirContext->LongNameU, TRUE, NULL) ||
+                  FsRtlIsNameInExpression(&FileToFindUpcase, &DirContext->ShortNameU, TRUE, NULL);
        }
-    }
-  else
-    {
-      DPRINT ("Parent->entry.FileSize %x\n", Parent->entry.FileSize);
-
-      Size = ULONG_MAX;
-      if (DeviceExt->FatType == FAT32)
-       NextCluster = Parent->entry.FirstCluster
-         + Parent->entry.FirstClusterHigh * 65536;
       else
-       NextCluster = Parent->entry.FirstCluster;
-      StartingSector = ClusterToSector (DeviceExt, NextCluster);
-      if (Parent->entry.FirstCluster == 1 && DeviceExt->FatType != FAT32)
-       {
-         /* read of root directory in FAT16 or FAT12 */
-         StartingSector = DeviceExt->rootStart;
+        {
+          Found = FsRtlAreNamesEqual(&DirContext->LongNameU, FileToFindU, TRUE, NULL) ||
+                 FsRtlAreNamesEqual(&DirContext->ShortNameU, FileToFindU, TRUE, NULL);
        }
-    }
-  block = ExAllocatePool (NonPagedPool, BLOCKSIZE);
-  if (StartSector && (*StartSector))
-    StartingSector = *StartSector;
-  i = (Entry) ? (*Entry) : 0;
-  for (j = 0; j < Size; j++)
-    {
-      /* FIXME: Check status */
-      VfatReadSectors (DeviceExt->StorageDevice, StartingSector, 1, block);
 
-      for (i = (Entry) ? (*Entry) : 0; i < ENTRIES_PER_SECTOR; i++)
-       {
-         if (IsVolEntry ((PVOID) block, i))
-           continue;
-         if (IsLastEntry ((PVOID) block, i))
-           {
-             if (StartSector)
-               *StartSector = StartingSector;
-             if (Entry)
-               *Entry = i;
-             ExFreePool (block);
-             return (STATUS_UNSUCCESSFUL);
-           }
-         if (GetEntryName
-             ((PVOID) block, &i, name, &j, DeviceExt, &StartingSector))
+      if (Found)
+        {
+         if (WildCard)
            {
-             if (wstrcmpjoki (name, FileToFind))
-               {
-                 /* In the case of a long filename, the firstcluster is 
-                    stored in the next record -- where it's short name is */
-                 if (((FATDirEntry *) block)[i].Attrib == 0x0f)
-                   i++;
-                 if (i == (ENTRIES_PER_SECTOR))
-                   {
-                      /* FIXME: Check status */
-                     GetNextSector (DeviceExt, StartingSector, &StartingSector, FALSE);
-
-                     /* FIXME: Check status */
-                     VfatReadSectors (DeviceExt->StorageDevice,
-                                      StartingSector, 1, block);
-                     i = 0;
-                   }
-                 if (Parent && Parent->PathName)
-                 {
-                   len = wcslen(Parent->PathName);
-                   CHECKPOINT;
-                   memcpy(Fcb->PathName, Parent->PathName, len*sizeof(WCHAR));
-                   Fcb->ObjectName=&Fcb->PathName[len];
-                 }
-                 else
-                       Fcb->ObjectName=Fcb->PathName;
-
-                 Fcb->ObjectName[0]='\\';
-                 Fcb->ObjectName=&Fcb->ObjectName[1];
-
-                 memcpy (&Fcb->entry, &((FATDirEntry *) block)[i],
-                         sizeof (FATDirEntry));
-                 vfat_wcsncpy (Fcb->ObjectName, name, MAX_PATH);
-                 if (StartSector)
-                   *StartSector = StartingSector;
-                 if (Entry)
-                   *Entry = i;
-                 ExFreePool (block);
-           DPRINT("FindFile: new Pathname %S, new Objectname %S)\n",Fcb->PathName, Fcb->ObjectName);
-                 return (STATUS_SUCCESS);
+              RtlCopyUnicodeString(&PathNameU, &Parent->PathNameU);
+              if (!vfatFCBIsRoot(Parent))
+                {
+                  PathNameU.Buffer[PathNameU.Length / sizeof(WCHAR)] = L'\\';
+                 PathNameU.Length += sizeof(WCHAR);
+                }
+              RtlAppendUnicodeStringToString(&PathNameU, &DirContext->LongNameU);
+              PathNameU.Buffer[PathNameU.Length / sizeof(WCHAR)] = 0;
+              rcFcb = vfatGrabFCBFromTable(DeviceExt, &PathNameU);
+             if (rcFcb != NULL)
+               {
+                 RtlCopyMemory(&DirContext->DirEntry, &rcFcb->entry, sizeof(DIR_ENTRY));
+                  vfatReleaseFCB(DeviceExt, rcFcb);
                }
            }
-       }
-      /* not found in this sector, try next : */
-
-      /* directory can be fragmented although it is best to keep them
-         unfragmented. Should we change this to also use GetNextSector?
-         GetNextSector was originally implemented to handle the case above */
-      if (Entry)
-       *Entry = 0;
-      StartingSector++;
-      if ((Parent != NULL && Parent->entry.FirstCluster != 1)
-         || DeviceExt->FatType == FAT32)
-       {
-         if (StartingSector == ClusterToSector (DeviceExt, NextCluster + 1))
+          DPRINT("%d\n", DirContext->LongNameU.Length);
+          DPRINT("FindFile: new Name %wZ, DirIndex %d\n",
+                &DirContext->LongNameU, DirContext->DirIndex);
+
+          if (Context)
            {
-             Status = GetNextCluster (DeviceExt, NextCluster, &NextCluster,
-                                      FALSE);
-             if (NextCluster == 0 || NextCluster == 0xffffffff)
-               {
-                 if (StartSector)
-                   *StartSector = StartingSector;
-                 if (Entry)
-                   *Entry = i;
-                 ExFreePool (block);
-                 return (STATUS_UNSUCCESSFUL);
-               }
-             StartingSector = ClusterToSector (DeviceExt, NextCluster);
+              CcUnpinData(Context);
            }
+          RtlFreeUnicodeString(&FileToFindUpcase);
+          ExFreePool(PathNameBuffer);
+          return STATUS_SUCCESS;
        }
+      DirContext->DirIndex++;
     }
-  if (StartSector)
-    *StartSector = StartingSector;
-  if (Entry)
-    *Entry = i;
-  ExFreePool (block);
-  return (STATUS_UNSUCCESSFUL);
-}
-
-NTSTATUS 
-vfatMakeAbsoluteFilename (PFILE_OBJECT pFileObject, 
-                          PWSTR pRelativeFileName,
-                          PWSTR *pAbsoluteFilename)
-{
-  PWSTR  rcName;
-  PVFATFCB  fcb;
-  PVFATCCB  ccb;
-
-  DbgPrint ("try related for %S\n", pRelativeFileName);
-  ccb = pFileObject->FsContext2;
-  assert (ccb);
-  fcb = ccb->pFcb;
-  assert (fcb);
-
-  /* verify related object is a directory and target name 
-     don't start with \. */
-  if (!(fcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY) 
-      || (pRelativeFileName[0] != '\\'))
-  {
-    return  STATUS_INVALID_PARAMETER;
-  }
 
-  /* construct absolute path name */
-  assert (wcslen (fcb->PathName) + 1 + wcslen (pRelativeFileName) + 1 
-          <= MAX_PATH);
-  rcName = ExAllocatePool (NonPagedPool, MAX_PATH);
-  wcscpy (rcName, fcb->PathName);
-  wcscat (rcName, L"\\");
-  wcscat (rcName, pRelativeFileName);
-  *pAbsoluteFilename = rcName;
+  if (Context)
+    {
+      CcUnpinData(Context);
+    }
 
-  return  STATUS_SUCCESS;
+  RtlFreeUnicodeString(&FileToFindUpcase);
+  ExFreePool(PathNameBuffer);
+  return Status;
 }
 
 NTSTATUS
-VfatOpenFile (PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject,
-            PWSTR FileName)
+VfatOpenFile (PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject, PVFATFCB* ParentFcb)
 /*
  * FUNCTION: Opens a file
  */
 {
-  PWSTR current = NULL;
-  PWSTR next;
-  PWSTR string;
-//  PWSTR buffer; // used to store a pointer while checking MAX_PATH conformance
-  PVFATFCB ParentFcb;
   PVFATFCB Fcb;
-  PVFATFCB Temp;
-  PVFATCCB newCCB;
   NTSTATUS Status;
-  PWSTR AbsFileName = NULL;
-  ULONG BytesPerCluster, FileCacheQuantum;
+  UNICODE_STRING PathNameU;
+  WCHAR Buffer[260];
 
-  DPRINT ("VfatOpenFile(%08lx, %08lx, %S)\n", DeviceExt, FileObject, FileName);
+  DPRINT ("VfatOpenFile(%08lx, %08lx, '%wZ')\n", DeviceExt, FileObject, &FileObject->FileName);
 
-  /* FIXME : treat relative name */
   if (FileObject->RelatedFileObject)
     {
-      Status = vfatMakeAbsoluteFilename (FileObject->RelatedFileObject,
-                                         FileName,
-                                         &AbsFileName);
-      FileName = AbsFileName;
-    }
-
-  /*
-   * try first to find an existing FCB in memory
-   */
-  CHECKPOINT;
-
-  Fcb = vfatGrabFCBFromTable (DeviceExt, FileName);
-  if (Fcb != NULL)
-  {
-    FileObject->FsContext = (PVOID)&Fcb->RFCB;
-    newCCB = ExAllocatePoolWithTag (NonPagedPool, sizeof (VFATCCB), TAG_CCB);
-    memset (newCCB, 0, sizeof (VFATCCB));
-    FileObject->Flags = FileObject->Flags | 
-        FO_FCB_IS_VALID | FO_DIRECT_CACHE_PAGING_READ;
-    FileObject->SectionObjectPointers = &Fcb->SectionObjectPointers;
-    FileObject->FsContext2 = newCCB;
-    newCCB->pFcb = Fcb;
-    newCCB->PtrFileObject = FileObject;
-    if (AbsFileName)
-      ExFreePool (AbsFileName);
-    return  STATUS_SUCCESS;
-  }
-
-  DPRINT ("FileName %S\n", FileName);
+      DPRINT ("'%wZ'\n", &FileObject->RelatedFileObject->FileName);
 
-  string = FileName;
-  ParentFcb = NULL;
-  Fcb = vfatNewFCB (L"\\");
-  next = &string[0];
-
-  CHECKPOINT;
-  if (*next == 0 || *(next+1) == 0)            // root
-    {
-      memset (Fcb->entry.Filename, ' ', 11);
-      Fcb->entry.FileSize = DeviceExt->rootDirectorySectors * BLOCKSIZE;
-      Fcb->entry.Attrib = FILE_ATTRIBUTE_DIRECTORY;
-      if (DeviceExt->FatType == FAT32)
-       Fcb->entry.FirstCluster = 2;
-      else
-       Fcb->entry.FirstCluster = 1;
-      /* FIXME : is 1 the good value for mark root? */
-      ParentFcb = Fcb;
-      DPRINT("%S filename, PathName: %S\n",FileName, ParentFcb->PathName);
-      Fcb = NULL;
+      *ParentFcb = FileObject->RelatedFileObject->FsContext;
+      (*ParentFcb)->RefCount++;
     }
   else
     {
-      while (TRUE)
-       {
-         CHECKPOINT;
-         *next = '\\';
-         current = next + 1;
-         next = wcschr (next + 1, '\\');
-         if (next != NULL)
-           {
-             *next = 0;
-           }
-         else
-           {
-             /* reached the last path component */
-             DPRINT ("exiting: current '%S'\n", current);
-             break;
-           }
+      *ParentFcb = NULL;
+    }
 
-         DPRINT ("search for (%S) in (%S)\n", current, ParentFcb ? ParentFcb->PathName : L"");
-         Status = FindFile (DeviceExt, Fcb, ParentFcb, current, NULL, NULL);
-         if (Status != STATUS_SUCCESS)
-           {
-             CHECKPOINT;
-             if (Fcb != NULL)
-               ExFreePool (Fcb);
-             if (ParentFcb != NULL)
-               ExFreePool (ParentFcb);
-             if (AbsFileName)
-               ExFreePool (AbsFileName);
-
-             DPRINT ("error STATUS_OBJECT_PATH_NOT_FOUND\n");
-             return STATUS_OBJECT_PATH_NOT_FOUND;
-           }
-         Temp = Fcb;
-         CHECKPOINT;
-         if (ParentFcb == NULL)
-           {
-             CHECKPOINT;
-             Fcb = vfatNewFCB (L"\\");
-           }
-         else
-             Fcb = ParentFcb;
+  if (!DeviceExt->FatInfo.FixedMedia)
+    {
+      Status = VfatBlockDeviceIoControl (DeviceExt->StorageDevice,
+                                        IOCTL_DISK_CHECK_VERIFY,
+                                        NULL,
+                                        0,
+                                        NULL,
+                                        0,
+                                        FALSE);
 
-         if (*(Temp->ObjectName))
-         {
-           vfat_wcsncpy(Fcb->PathName+(Fcb->ObjectName-Fcb->PathName),Temp->PathName+(Fcb->ObjectName-Fcb->PathName), MAX_PATH);
+      if (Status == STATUS_VERIFY_REQUIRED)
 
-           Fcb->ObjectName = &Fcb->PathName[wcslen(Fcb->PathName)];
-           Fcb->ObjectName[0]='\\';
-           Fcb->ObjectName=&Fcb->ObjectName[1];
-           Fcb->ObjectName[0]=0;
-         }
-         CHECKPOINT;
-         ParentFcb = Temp;
-       }
-       
-       if( *current != L'\0' ){ //the file name is directory. there will be no last part.
-      /* searching for last path component */
-      DPRINT ("search for (%S) in (%S)\n", current, Fcb ? Fcb->PathName : L"");
-      Status = FindFile (DeviceExt, Fcb, ParentFcb, current, NULL, NULL);
-      if (Status != STATUS_SUCCESS)
         {
-         /* file does not exist */
-         CHECKPOINT;
-         if (Fcb != NULL)
-           ExFreePool (Fcb);
-         if (ParentFcb != NULL)
-           ExFreePool (ParentFcb);
-         if (AbsFileName)
-           ExFreePool (AbsFileName);
-
-          return STATUS_OBJECT_NAME_NOT_FOUND;
-       }
+          PDEVICE_OBJECT DeviceToVerify;
 
-      Temp = Fcb;
+          DPRINT ("Media change detected!\n");
+          DPRINT ("Device %p\n", DeviceExt->StorageDevice);
 
-      Fcb = ParentFcb;
-      ParentFcb = Temp;
-      ParentFcb->ObjectName = &(wcschr (ParentFcb->ObjectName, '\\'))[1];
-      }
+         DeviceToVerify = IoGetDeviceToVerify (PsGetCurrentThread ());
+
+         IoSetDeviceToVerify (PsGetCurrentThread (),
+                              NULL);
+          Status = IoVerifyVolume (DeviceExt->StorageDevice,
+                                  FALSE);
+       }
+      if (!NT_SUCCESS(Status))
+       {
+         DPRINT ("Status %lx\n", Status);
+         *ParentFcb = NULL;
+         return Status;
+       }
     }
 
-    FileObject->Flags = FileObject->Flags | 
-    FO_FCB_IS_VALID | FO_DIRECT_CACHE_PAGING_READ;
-  FileObject->SectionObjectPointers = &ParentFcb->SectionObjectPointers;
-  memset(FileObject->SectionObjectPointers, 0, 
-        sizeof(SECTION_OBJECT_POINTERS));
-  FileObject->FsContext = (PVOID)&ParentFcb->RFCB;
-  newCCB = ExAllocatePoolWithTag (NonPagedPool, sizeof (VFATCCB), TAG_CCB);
-  memset (newCCB, 0, sizeof (VFATCCB));
-  FileObject->FsContext2 = newCCB;
-  newCCB->pFcb = ParentFcb;
-  newCCB->PtrFileObject = FileObject;
-  ParentFcb->RefCount++;
-  ParentFcb->pDevExt = DeviceExt;
-  /* FIXME : initialize all fields in FCB and CCB */
-
-  BytesPerCluster = DeviceExt->Boot->SectorsPerCluster * BLOCKSIZE;
-  FileCacheQuantum = (BytesPerCluster >= PAGESIZE) ? BytesPerCluster : PAGESIZE;
-  Status = CcRosInitializeFileCache(FileObject, 
-                                 &ParentFcb->RFCB.Bcb,
-                                 FileCacheQuantum);
-  if (!NT_SUCCESS(Status))
+  if (*ParentFcb)
+  {
+     (*ParentFcb)->RefCount++;
+  }
+
+  PathNameU.Buffer = Buffer;
+  PathNameU.Length = 0;
+  PathNameU.MaximumLength = sizeof(Buffer);
+  RtlCopyUnicodeString(&PathNameU, &FileObject->FileName);
+  if (PathNameU.Length > sizeof(WCHAR) &&
+      PathNameU.Buffer[PathNameU.Length / sizeof(WCHAR) - 1] == L'\\')
     {
-      DbgPrint("CcRosInitializeFileCache failed\n");
-      KeBugCheck(0);
+      PathNameU.Length -= sizeof(WCHAR);
     }
-  DPRINT ("file open, fcb=%x\n", ParentFcb);
-  DPRINT ("FileSize %d\n", ParentFcb->entry.FileSize);
-
-  vfatAddFCBToTable (DeviceExt, ParentFcb);
+  PathNameU.Buffer[PathNameU.Length / sizeof(WCHAR)] = 0;
 
-  if (Fcb)
-    ExFreePool (Fcb);
-  if (AbsFileName)
-    ExFreePool (AbsFileName);
-  CHECKPOINT;
+  /*  try first to find an existing FCB in memory  */
+  DPRINT ("Checking for existing FCB in memory\n");
 
-  return (STATUS_SUCCESS);
+  Status = vfatGetFCBForFile (DeviceExt, ParentFcb, &Fcb, &PathNameU);
+  if (!NT_SUCCESS (Status))
+  {
+     DPRINT ("Could not make a new FCB, status: %x\n", Status);
+     return  Status;
+  }
+  if (Fcb->Flags & FCB_DELETE_PENDING)
+  {
+     vfatReleaseFCB (DeviceExt, Fcb);
+     return STATUS_DELETE_PENDING;
+  }
+  DPRINT ("Attaching FCB to fileObject\n");
+  Status = vfatAttachFCBToFileObject (DeviceExt, Fcb, FileObject);
+  if (!NT_SUCCESS(Status))
+  {
+     vfatReleaseFCB (DeviceExt, Fcb);
+  }
+  return  Status;
 }
 
-
 NTSTATUS
 VfatCreateFile (PDEVICE_OBJECT DeviceObject, PIRP Irp)
 /*
@@ -678,172 +445,330 @@ VfatCreateFile (PDEVICE_OBJECT DeviceObject, PIRP Irp)
   ULONG RequestedDisposition, RequestedOptions;
   PVFATCCB pCcb;
   PVFATFCB pFcb;
-  PWCHAR c;
+  PVFATFCB ParentFcb;
+  PWCHAR c, last;
+  BOOLEAN PagingFileCreate = FALSE;
+  LARGE_INTEGER AllocationSize;
+  BOOLEAN Dots;
+  UNICODE_STRING FileNameU;
 
+  /* Unpack the various parameters. */
   Stack = IoGetCurrentIrpStackLocation (Irp);
-  assert (Stack);
   RequestedDisposition = ((Stack->Parameters.Create.Options >> 24) & 0xff);
   RequestedOptions =
     Stack->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS;
-  if ((RequestedOptions & FILE_DIRECTORY_FILE)
-      && RequestedDisposition == FILE_SUPERSEDE)
-    return STATUS_INVALID_PARAMETER;
+  PagingFileCreate = (Stack->Flags & SL_OPEN_PAGING_FILE) ? TRUE : FALSE;
   FileObject = Stack->FileObject;
   DeviceExt = DeviceObject->DeviceExtension;
-  assert (DeviceExt);
-  
+
+  /* Check their validity. */
+  if (RequestedOptions & FILE_DIRECTORY_FILE &&
+      RequestedDisposition == FILE_SUPERSEDE)
+    {
+      return(STATUS_INVALID_PARAMETER);
+    }
+
+  /* This a open operation for the volume itself */
+  if (FileObject->FileName.Length == 0 &&
+      FileObject->RelatedFileObject == NULL)
+    {
+      if (RequestedDisposition == FILE_CREATE ||
+         RequestedDisposition == FILE_OVERWRITE_IF ||
+         RequestedDisposition == FILE_SUPERSEDE)
+       {
+         return(STATUS_ACCESS_DENIED);
+       }
+      if (RequestedOptions & FILE_DIRECTORY_FILE)
+       {
+         return(STATUS_NOT_A_DIRECTORY);
+       }
+      pFcb = DeviceExt->VolumeFcb;
+      pCcb = ExAllocateFromNPagedLookasideList(&VfatGlobalData->CcbLookasideList);
+      if (pCcb == NULL)
+       {
+         return (STATUS_INSUFFICIENT_RESOURCES);
+       }
+      RtlZeroMemory(pCcb, sizeof(VFATCCB));
+      FileObject->SectionObjectPointer = &pFcb->SectionObjectPointers;
+      FileObject->FsContext = pFcb;
+      FileObject->FsContext2 = pCcb;
+      pFcb->RefCount++;
+
+      Irp->IoStatus.Information = FILE_OPENED;
+      return(STATUS_SUCCESS);
+    }
+
   /*
-   * Check for illegal characters in the file name
+   * Check for illegal characters and illegale dot sequences in the file name
    */
-  c = FileObject->FileName.Buffer;
-  while (*c != 0)
+  c = FileObject->FileName.Buffer + FileObject->FileName.Length / sizeof(WCHAR);
+  last = c - 1;
+  Dots = TRUE;
+  while (c-- > FileObject->FileName.Buffer)
     {
-      if (*c == L'*' || *c == L'?')
-       {
-         Irp->IoStatus.Information = 0;
-         Irp->IoStatus.Status = STATUS_OBJECT_NAME_INVALID;
-         return(STATUS_OBJECT_NAME_INVALID);
+      if (*c == L'\\' || c == FileObject->FileName.Buffer)
+        {
+         if (Dots && last > c)
+           {
+              return(STATUS_OBJECT_NAME_INVALID);
+           }
+         last = c - 1;
+         Dots = TRUE;
+       }
+      else if (*c != L'.')
+        {
+         Dots = FALSE;
+       }
+
+      if (*c != '\\' && vfatIsLongIllegal(*c))
+        {
+          return(STATUS_OBJECT_NAME_INVALID);
        }
-      c++;
     }
 
-  Status = VfatOpenFile (DeviceExt, FileObject, FileObject->FileName.Buffer);
+  /* Try opening the file. */
+  Status = VfatOpenFile (DeviceExt, FileObject, &ParentFcb);
 
   /*
    * If the directory containing the file to open doesn't exist then
    * fail immediately
    */
-  Irp->IoStatus.Information = 0;
-  if (Status == STATUS_OBJECT_PATH_NOT_FOUND)
+  if (Status == STATUS_OBJECT_PATH_NOT_FOUND ||
+      Status == STATUS_INVALID_PARAMETER ||
+      Status == STATUS_DELETE_PENDING)
     {
-      Irp->IoStatus.Status = Status;
-      return Status;
+      if (ParentFcb)
+      {
+         vfatReleaseFCB (DeviceExt, ParentFcb);
+      }
+      return(Status);
     }
 
+  /*
+   * If the file open failed then create the required file
+   */
   if (!NT_SUCCESS (Status))
     {
-      /*
-       * If the file open failed then create the required file
-       */
-      if (RequestedDisposition == FILE_CREATE || 
-         RequestedDisposition == FILE_OPEN_IF || 
-         RequestedDisposition == FILE_OVERWRITE_IF || 
+      if (RequestedDisposition == FILE_CREATE ||
+         RequestedDisposition == FILE_OPEN_IF ||
+         RequestedDisposition == FILE_OVERWRITE_IF ||
          RequestedDisposition == FILE_SUPERSEDE)
        {
-         CHECKPOINT;
-         Status = 
-           addEntry (DeviceExt, FileObject, RequestedOptions,
-                     (Stack->Parameters.
-                      Create.FileAttributes & FILE_ATTRIBUTE_VALID_FLAGS));
+         ULONG Attributes;
+         Attributes = Stack->Parameters.Create.FileAttributes;
+
+          vfatSplitPathName(&FileObject->FileName, NULL, &FileNameU);
+         Status = VfatAddEntry (DeviceExt, &FileNameU, &pFcb, ParentFcb, RequestedOptions,
+                                (UCHAR)(Attributes & FILE_ATTRIBUTE_VALID_FLAGS));
+          vfatReleaseFCB (DeviceExt, ParentFcb);
          if (NT_SUCCESS (Status))
-           Irp->IoStatus.Information = FILE_CREATED;
-         /* FIXME set size if AllocationSize requested */
-         /* FIXME set extended attributes? */
-         /* FIXME set share access */
-         /* IoSetShareAccess(DesiredAccess,ShareAccess,FileObject,
-          * ((PVfatCCB)(FileObject->FsContext2))->pFcb->FCBShareAccess);
-          */
+           {
+              Status = vfatAttachFCBToFileObject (DeviceExt, pFcb, FileObject);
+              if ( !NT_SUCCESS(Status) )
+              {
+                 vfatReleaseFCB (DeviceExt, pFcb);
+                 return Status;
+              }
+
+             Irp->IoStatus.Information = FILE_CREATED;
+
+             VfatSetAllocationSizeInformation(FileObject,
+                                              pFcb,
+                                              DeviceExt,
+                                              &Irp->Overlay.AllocationSize);
+             VfatSetExtendedAttributes(FileObject,
+                                       Irp->AssociatedIrp.SystemBuffer,
+                                       Stack->Parameters.Create.EaLength);
+
+             if (PagingFileCreate)
+                {
+                  pFcb->Flags |= FCB_IS_PAGE_FILE;
+                }
+           }
+         else
+           {
+             return(Status);
+           }
+       }
+      else
+       {
+          vfatReleaseFCB (DeviceExt, ParentFcb);
+         return(Status);
        }
     }
   else
     {
-      /*
-       * Otherwise fail if the caller wanted to create a new file
-       */
+      if (ParentFcb)
+      {
+         vfatReleaseFCB (DeviceExt, ParentFcb);
+      }
+      /* Otherwise fail if the caller wanted to create a new file  */
       if (RequestedDisposition == FILE_CREATE)
        {
          Irp->IoStatus.Information = FILE_EXISTS;
-         Status = STATUS_OBJECT_NAME_COLLISION;
-       }      
-      pCcb = FileObject->FsContext2;
-      pFcb = pCcb->pFcb;
+         VfatCloseFile (DeviceExt, FileObject);
+         return(STATUS_OBJECT_NAME_COLLISION);
+       }
+
+      pFcb = FileObject->FsContext;
+
+      if (pFcb->OpenHandleCount != 0 &&
+          !(*pFcb->Attributes & FILE_ATTRIBUTE_DIRECTORY))
+        {
+          Status = IoCheckShareAccess(Stack->Parameters.Create.SecurityContext->DesiredAccess,
+                                      Stack->Parameters.Create.ShareAccess,
+                                      FileObject,
+                                      &pFcb->FCBShareAccess,
+                                      FALSE);
+          if (!NT_SUCCESS(Status))
+            {
+              VfatCloseFile (DeviceExt, FileObject);
+              return(Status);
+            }
+        }
+
       /*
-       * If requested then delete the file and create a new one with the
-       * same name
+       * Check the file has the requested attributes
        */
-      if (RequestedDisposition == FILE_SUPERSEDE)
+      if (RequestedOptions & FILE_NON_DIRECTORY_FILE &&
+         *pFcb->Attributes & FILE_ATTRIBUTE_DIRECTORY)
+       {
+         VfatCloseFile (DeviceExt, FileObject);
+         return(STATUS_FILE_IS_A_DIRECTORY);
+       }
+      if (RequestedOptions & FILE_DIRECTORY_FILE &&
+         !(*pFcb->Attributes & FILE_ATTRIBUTE_DIRECTORY))
        {
-         ULONG Cluster, NextCluster;
-         /* FIXME set size to 0 and free clusters */
-         pFcb->entry.FileSize = 0;
-         if (DeviceExt->FatType == FAT32)
-           Cluster = pFcb->entry.FirstCluster
-             + pFcb->entry.FirstClusterHigh * 65536;
+         VfatCloseFile (DeviceExt, FileObject);
+         return(STATUS_NOT_A_DIRECTORY);
+       }
+
+      if (PagingFileCreate)
+        {
+         /* FIXME:
+          *   Do more checking for page files. It is possible,
+          *   that the file was opened and closed previously
+          *   as a normal cached file. In this case, the cache
+          *   manager has referenced the fileobject and the fcb
+          *   is held in memory. Try to remove the fileobject
+          *   from cache manager and use the fcb.
+          */
+          if (pFcb->RefCount > 1)
+           {
+             if(!(pFcb->Flags & FCB_IS_PAGE_FILE))
+               {
+                 VfatCloseFile(DeviceExt, FileObject);
+                 return(STATUS_INVALID_PARAMETER);
+               }
+           }
          else
-           Cluster = pFcb->entry.FirstCluster;
-         pFcb->entry.FirstCluster = 0;
-         pFcb->entry.FirstClusterHigh = 0;
-         updEntry (DeviceExt, FileObject);
-         while (Cluster != 0xffffffff && Cluster > 1)
            {
-             Status = GetNextCluster (DeviceExt, Cluster, &NextCluster, TRUE);
-             WriteCluster (DeviceExt, Cluster, 0);
-             Cluster = NextCluster;
+             pFcb->Flags |= FCB_IS_PAGE_FILE;
+           }
+       }
+      else
+        {
+         if (pFcb->Flags & FCB_IS_PAGE_FILE)
+           {
+             VfatCloseFile(DeviceExt, FileObject);
+             return(STATUS_INVALID_PARAMETER);
            }
        }
 
-      /*
-       * Check the file has the requested attributes
-       */
-      if ((RequestedOptions & FILE_NON_DIRECTORY_FILE)
-         && (pFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
+
+      if (RequestedDisposition == FILE_OVERWRITE ||
+          RequestedDisposition == FILE_OVERWRITE_IF)
        {
-         Status = STATUS_FILE_IS_A_DIRECTORY;
+         AllocationSize.QuadPart = 0;
+         Status = VfatSetAllocationSizeInformation (FileObject,
+                                                    pFcb,
+                                                    DeviceExt,
+                                                    &AllocationSize);
+         if (!NT_SUCCESS (Status))
+           {
+             VfatCloseFile (DeviceExt, FileObject);
+             return(Status);
+           }
        }
-      if ((RequestedOptions & FILE_DIRECTORY_FILE)
-         && !(pFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
+
+
+      /* Supersede the file */
+      if (RequestedDisposition == FILE_SUPERSEDE)
        {
-         Status = STATUS_NOT_A_DIRECTORY;
+         AllocationSize.QuadPart = 0;
+          VfatSetAllocationSizeInformation(FileObject, pFcb, DeviceExt, &AllocationSize);
+         Irp->IoStatus.Information = FILE_SUPERSEDED;
        }
-      /* FIXME : test share access */
-      /* FIXME : test write access if requested */
-      if (!NT_SUCCESS (Status))
-       VfatCloseFile (DeviceExt, FileObject);
+      else if (RequestedDisposition == FILE_OVERWRITE || RequestedDisposition == FILE_OVERWRITE_IF)
+        {
+          Irp->IoStatus.Information = FILE_OVERWRITTEN;
+        }
       else
-       Irp->IoStatus.Information = FILE_OPENED;
-      /* FIXME : make supersed or overwrite if requested */
+        {
+         Irp->IoStatus.Information = FILE_OPENED;
+       }
     }
 
-  Irp->IoStatus.Status = Status;
+  if (pFcb->OpenHandleCount == 0 &&
+      !(*pFcb->Attributes & FILE_ATTRIBUTE_DIRECTORY))
+  {
+      IoSetShareAccess(Stack->Parameters.Create.SecurityContext->DesiredAccess,
+                   Stack->Parameters.Create.ShareAccess,
+                   FileObject,
+                   &pFcb->FCBShareAccess);
+   }
+   else
+   {
+      IoUpdateShareAccess(
+          FileObject,
+          &pFcb->FCBShareAccess
+         );
 
-  return Status;
+   }
+
+  pFcb->OpenHandleCount++;
+
+  /* FIXME : test write access if requested */
+
+  return(Status);
 }
 
 
-NTSTATUS STDCALL
-VfatCreate (PDEVICE_OBJECT DeviceObject, PIRP Irp)
+NTSTATUS VfatCreate (PVFAT_IRP_CONTEXT IrpContext)
 /*
  * FUNCTION: Create or open a file
  */
 {
-  NTSTATUS Status = STATUS_SUCCESS;
-  PDEVICE_EXTENSION DeviceExt;
+  NTSTATUS Status;
 
-  assert (DeviceObject);
-  assert (Irp);
-  
-  if (DeviceObject->Size == sizeof (DEVICE_OBJECT))
+  ASSERT(IrpContext);
+
+  if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject)
     {
       /* DeviceObject represents FileSystem instead of logical volume */
-      DbgPrint ("FsdCreate called with file system\n");
-      Irp->IoStatus.Status = Status;
-      Irp->IoStatus.Information = FILE_OPENED;
-      IoCompleteRequest (Irp, IO_NO_INCREMENT);
-      return (Status);
+      DPRINT ("FsdCreate called with file system\n");
+      IrpContext->Irp->IoStatus.Information = FILE_OPENED;
+      IrpContext->Irp->IoStatus.Status = STATUS_SUCCESS;
+      IoCompleteRequest (IrpContext->Irp, IO_DISK_INCREMENT);
+      VfatFreeIrpContext(IrpContext);
+      return(STATUS_SUCCESS);
     }
 
-  DeviceExt = DeviceObject->DeviceExtension;
-  assert (DeviceExt);
-  ExAcquireResourceExclusiveLite (&DeviceExt->DirResource, TRUE);
+  if (!(IrpContext->Flags & IRPCONTEXT_CANWAIT))
+    {
+      return(VfatQueueRequest (IrpContext));
+    }
 
-  Status = VfatCreateFile (DeviceObject, Irp);
-  
-  ExReleaseResourceLite (&DeviceExt->DirResource);
-  
-  Irp->IoStatus.Status = Status;
-  IoCompleteRequest (Irp, IO_NO_INCREMENT);
+  IrpContext->Irp->IoStatus.Information = 0;
+  ExAcquireResourceExclusiveLite (&IrpContext->DeviceExt->DirResource, TRUE);
+  Status = VfatCreateFile (IrpContext->DeviceObject, IrpContext->Irp);
+  ExReleaseResourceLite (&IrpContext->DeviceExt->DirResource);
 
-  return Status;
+  IrpContext->Irp->IoStatus.Status = Status;
+  IoCompleteRequest (IrpContext->Irp,
+                    (CCHAR)(NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT));
+  VfatFreeIrpContext(IrpContext);
+  return(Status);
 }
 
 /* EOF */