Don't check the share access for directories.
[reactos.git] / reactos / drivers / fs / vfat / create.c
index 11c7a0e..dbcef14 100644 (file)
@@ -16,8 +16,7 @@
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
-/* $Id: create.c,v 1.64 2003/10/11 17:51:56 hbirr Exp $
- *
+/*
  * PROJECT:          ReactOS kernel
  * FILE:             drivers/fs/vfat/create.c
  * PURPOSE:          VFAT Filesystem
 
 /* INCLUDES *****************************************************************/
 
-#include <ddk/ntddk.h>
-#include <wchar.h>
-#include <limits.h>
-
 #define NDEBUG
-#include <debug.h>
-
 #include "vfat.h"
 
-/* GLOBALS *******************************************************************/
-
-#define ENTRIES_PER_PAGE   (PAGE_SIZE / sizeof (FATDirEntry))
-
 /* FUNCTIONS *****************************************************************/
 
 void  vfat8Dot3ToString (PFAT_DIR_ENTRY pEntry, PUNICODE_STRING NameU)
 {
   OEM_STRING StringA;
-  ULONG Length;
+  USHORT Length;
   CHAR  cString[12];
-  
-  memcpy(cString, pEntry->Filename, 11);
+
+  RtlCopyMemory(cString, pEntry->ShortName, 11);
   cString[11] = 0;
   if (cString[0] == 0x05)
     {
       cString[0] = 0xe5;
-    }      
+    }
 
   StringA.Buffer = cString;
-  for (StringA.Length = 0; 
+  for (StringA.Length = 0;
        StringA.Length < 8 && StringA.Buffer[StringA.Length] != ' ';
        StringA.Length++);
   StringA.MaximumLength = StringA.Length;
-  
+
   RtlOemStringToUnicodeString(NameU, &StringA, FALSE);
 
   if (pEntry->lCase & VFAT_CASE_LOWER_BASE)
@@ -71,7 +60,7 @@ void  vfat8Dot3ToString (PFAT_DIR_ENTRY pEntry, PUNICODE_STRING NameU)
     {
       Length = NameU->Length;
       NameU->Buffer += Length / sizeof(WCHAR);
-      if (!ENTRY_VOLUME(pEntry))
+      if (!FAT_ENTRY_VOLUME(pEntry))
         {
          Length += sizeof(WCHAR);
           NameU->Buffer[0] = L'.';
@@ -79,9 +68,9 @@ void  vfat8Dot3ToString (PFAT_DIR_ENTRY pEntry, PUNICODE_STRING NameU)
        }
       NameU->Length = 0;
       NameU->MaximumLength -= Length;
-      
+
       StringA.Buffer = &cString[8];
-      for (StringA.Length = 0; 
+      for (StringA.Length = 0;
            StringA.Length < 3 && StringA.Buffer[StringA.Length] != ' ';
            StringA.Length++);
       StringA.MaximumLength = StringA.Length;
@@ -106,10 +95,13 @@ ReadVolumeLabel (PDEVICE_EXTENSION DeviceExt, PVPB Vpb)
 {
   PVOID Context = NULL;
   ULONG DirIndex = 0;
-  FATDirEntry* Entry;
+  PDIR_ENTRY Entry;
   PVFATFCB pFcb;
   LARGE_INTEGER FileOffset;
   UNICODE_STRING NameU;
+  ULONG SizeDirEntry;
+  ULONG EntriesPerPage;
+  OEM_STRING StringO;
 
   NameU.Buffer = Vpb->VolumeLabel;
   NameU.Length = 0;
@@ -117,6 +109,17 @@ ReadVolumeLabel (PDEVICE_EXTENSION DeviceExt, PVPB Vpb)
   *(Vpb->VolumeLabel) = 0;
   Vpb->VolumeLabelLength = 0;
 
+  if (DeviceExt->Flags & VCB_IS_FATX)
+  {
+    SizeDirEntry = sizeof(FATX_DIR_ENTRY);
+    EntriesPerPage = FATX_ENTRIES_PER_PAGE;
+  }
+  else
+  {
+    SizeDirEntry = sizeof(FAT_DIR_ENTRY);
+    EntriesPerPage = FAT_ENTRIES_PER_PAGE;
+  }
+
   ExAcquireResourceExclusiveLite (&DeviceExt->DirResource, TRUE);
   pFcb = vfatOpenRootFCB (DeviceExt);
   ExReleaseResourceLite (&DeviceExt->DirResource);
@@ -126,20 +129,29 @@ ReadVolumeLabel (PDEVICE_EXTENSION DeviceExt, PVPB Vpb)
   {
      while (TRUE)
      {
-       if (ENTRY_VOLUME(Entry))
+       if (ENTRY_VOLUME(DeviceExt, Entry))
        {
           /* copy volume label */
-          vfat8Dot3ToString (Entry, &NameU);
+          if (DeviceExt->Flags & VCB_IS_FATX)
+          {
+            StringO.Buffer = (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(Entry))
+       if (ENTRY_END(DeviceExt, Entry))
        {
           break;
        }
-       DirIndex++;       
-       Entry++;
-       if ((DirIndex % ENTRIES_PER_PAGE) == 0)
+       DirIndex++;
+       Entry = (PDIR_ENTRY)((ULONG_PTR)Entry + SizeDirEntry);
+       if ((DirIndex % EntriesPerPage) == 0)
        {
          CcUnpinData(Context);
          FileOffset.u.LowPart += PAGE_SIZE;
@@ -172,41 +184,37 @@ FindFile (PDEVICE_EXTENSION DeviceExt,
  * FUNCTION: Find a file
  */
 {
-  WCHAR PathNameBuffer[MAX_PATH];
+  PWCHAR PathNameBuffer;
+  USHORT PathNameBufferLength;
   NTSTATUS Status;
   PVOID Context = NULL;
   PVOID Page;
   PVFATFCB rcFcb;
-  BOOLEAN FoundLong;
-  BOOLEAN FoundShort;
+  BOOLEAN Found;
   UNICODE_STRING PathNameU;
+  UNICODE_STRING FileToFindUpcase;
   BOOLEAN WildCard;
-  PWCHAR curr, last;
 
-  DPRINT ("FindFile(Parent %x, FileToFind '%wZ', DirIndex: %d)\n", 
+  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;
+  }
+
   PathNameU.Buffer = PathNameBuffer;
   PathNameU.Length = 0;
-  PathNameU.MaximumLength = sizeof(PathNameBuffer);
+  PathNameU.MaximumLength = PathNameBufferLength;
 
   DirContext->LongNameU.Length = 0;
   DirContext->ShortNameU.Length = 0;
 
-  /* FIXME: Use FsRtlDoesNameContainWildCards */
-  WildCard = FALSE;
-  curr = FileToFindU->Buffer;
-  last = FileToFindU->Buffer + FileToFindU->Length / sizeof(WCHAR);
-  while (curr < last)
-    {
-      if (*curr == L'?' || *curr == L'*')
-        {
-         WildCard = TRUE;
-         break;
-       }
-      curr++;
-    }
+  WildCard = FsRtlDoesNameContainWildCards(FileToFindU);
 
   if (WildCard == FALSE)
     {
@@ -222,15 +230,20 @@ FindFile (PDEVICE_EXTENSION DeviceExt,
       rcFcb = vfatGrabFCBFromTable(DeviceExt, &PathNameU);
       if (rcFcb)
         {
-         if(rcFcb->startIndex >= DirContext->DirIndex)
+         ULONG startIndex = rcFcb->startIndex;
+         if ((rcFcb->Flags & FCB_IS_FATX_ENTRY) && !vfatFCBIsRoot(Parent))
+           {
+             startIndex += 2;
+           }
+         if(startIndex >= DirContext->DirIndex)
            {
              RtlCopyUnicodeString(&DirContext->LongNameU, &rcFcb->LongNameU);
              RtlCopyUnicodeString(&DirContext->ShortNameU, &rcFcb->ShortNameU);
-             memcpy(&DirContext->FatDirEntry, &rcFcb->entry, sizeof(FATDirEntry));
+             RtlCopyMemory(&DirContext->DirEntry, &rcFcb->entry, sizeof(DIR_ENTRY));
              DirContext->StartIndex = rcFcb->startIndex;
              DirContext->DirIndex = rcFcb->dirIndex;
               DPRINT("FindFile: new Name %wZ, DirIndex %d (%d)\n",
-                    &DirContext->LongNameU, DirContext->DirIndex, DirContext->StartIndex);
+                    &DirContext->LongNameU, DirContext->DirIndex, DirContext->StartIndex);
              Status = STATUS_SUCCESS;
            }
           else
@@ -239,57 +252,46 @@ FindFile (PDEVICE_EXTENSION DeviceExt,
              Status = STATUS_UNSUCCESSFUL;
            }
           vfatReleaseFCB(DeviceExt, rcFcb);
+         ExFreePool(PathNameBuffer);
          return Status;
        }
     }
 
+  /* 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;
+  }
+
   while(TRUE)
     {
-      Status = vfatGetNextDirEntry(&Context, &Page, Parent, DirContext, First);
+      Status = DeviceExt->GetNextDirEntry(&Context, &Page, Parent, DirContext, First);
       First = FALSE;
       if (Status == STATUS_NO_MORE_ENTRIES)
         {
          break;
         }
-      if (ENTRY_VOLUME(&DirContext->FatDirEntry))
+      if (ENTRY_VOLUME(DeviceExt, &DirContext->DirEntry))
         {
           DirContext->DirIndex++;
           continue;
         }
-      DirContext->LongNameU.Buffer[DirContext->LongNameU.Length / sizeof(WCHAR)] = 0;
-      DirContext->ShortNameU.Buffer[DirContext->ShortNameU.Length / sizeof(WCHAR)] = 0;
       if (WildCard)
         {
-         /* FIXME: Use FsRtlIsNameInExpression */
-          if (DirContext->LongNameU.Length > 0 && 
-             wstrcmpjoki (DirContext->LongNameU.Buffer, FileToFindU->Buffer))
-            {
-             FoundLong = TRUE;
-           }
-          else
-            {
-             FoundLong = FALSE;
-           }
-          if (FoundLong == FALSE)
-            {
-             /* FIXME: Use FsRtlIsNameInExpression */
-             FoundShort = wstrcmpjoki (DirContext->ShortNameU.Buffer, FileToFindU->Buffer);
-           }
-          else
-            {
-             FoundShort = FALSE;
-           }
+          Found = FsRtlIsNameInExpression(&FileToFindUpcase, &DirContext->LongNameU, TRUE, NULL) ||
+                  FsRtlIsNameInExpression(&FileToFindUpcase, &DirContext->ShortNameU, TRUE, NULL);
        }
       else
         {
-         FoundLong = RtlEqualUnicodeString(&DirContext->LongNameU, FileToFindU, TRUE);
-         if (FoundLong == FALSE)
-           {
-             FoundShort = RtlEqualUnicodeString(&DirContext->ShortNameU, FileToFindU, TRUE);
-           }
+          Found = FsRtlAreNamesEqual(&DirContext->LongNameU, FileToFindU, TRUE, NULL) ||
+                 FsRtlAreNamesEqual(&DirContext->ShortNameU, FileToFindU, TRUE, NULL);
        }
 
-      if (FoundLong || FoundShort)
+      if (Found)
         {
          if (WildCard)
            {
@@ -304,7 +306,7 @@ FindFile (PDEVICE_EXTENSION DeviceExt,
               rcFcb = vfatGrabFCBFromTable(DeviceExt, &PathNameU);
              if (rcFcb != NULL)
                {
-                 memcpy(&DirContext->FatDirEntry, &rcFcb->entry, sizeof(FATDirEntry));
+                 RtlCopyMemory(&DirContext->DirEntry, &rcFcb->entry, sizeof(DIR_ENTRY));
                   vfatReleaseFCB(DeviceExt, rcFcb);
                }
            }
@@ -316,6 +318,8 @@ FindFile (PDEVICE_EXTENSION DeviceExt,
            {
               CcUnpinData(Context);
            }
+          RtlFreeUnicodeString(&FileToFindUpcase);
+          ExFreePool(PathNameBuffer);
           return STATUS_SUCCESS;
        }
       DirContext->DirIndex++;
@@ -326,113 +330,108 @@ FindFile (PDEVICE_EXTENSION DeviceExt,
       CcUnpinData(Context);
     }
 
+  RtlFreeUnicodeString(&FileToFindUpcase);
+  ExFreePool(PathNameBuffer);
   return Status;
 }
 
 NTSTATUS
-VfatOpenFile (PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject,
-             PUNICODE_STRING FileNameU)
+VfatOpenFile (PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject, PVFATFCB* ParentFcb)
 /*
  * FUNCTION: Opens a file
  */
 {
-  PVFATFCB ParentFcb;
   PVFATFCB Fcb;
   NTSTATUS Status;
-  UNICODE_STRING NameU;
-  WCHAR Name[MAX_PATH];
+  UNICODE_STRING PathNameU;
+  WCHAR Buffer[260];
 
-  DPRINT ("VfatOpenFile(%08lx, %08lx, '%wZ')\n", DeviceExt, FileObject, FileNameU);
+  DPRINT ("VfatOpenFile(%08lx, %08lx, '%wZ')\n", DeviceExt, FileObject, &FileObject->FileName);
 
   if (FileObject->RelatedFileObject)
     {
-      DPRINT ("Converting relative filename to absolute filename\n");
+      DPRINT ("'%wZ'\n", &FileObject->RelatedFileObject->FileName);
 
-      NameU.Buffer = Name;
-      NameU.Length = 0;
-      NameU.MaximumLength = sizeof(Name);
+      *ParentFcb = FileObject->RelatedFileObject->FsContext;
+      (*ParentFcb)->RefCount++;
+    }
+  else
+    {
+      *ParentFcb = NULL;
+    }
+
+  if (!DeviceExt->FatInfo.FixedMedia)
+    {
+      Status = VfatBlockDeviceIoControl (DeviceExt->StorageDevice,
+                                        IOCTL_DISK_CHECK_VERIFY,
+                                        NULL,
+                                        0,
+                                        NULL,
+                                        0,
+                                        FALSE);
+
+      if (Status == STATUS_VERIFY_REQUIRED)
 
-      Fcb = FileObject->RelatedFileObject->FsContext;
-      RtlCopyUnicodeString(&NameU, &Fcb->PathNameU);
-      if (!vfatFCBIsRoot(Fcb))
         {
-         NameU.Buffer[NameU.Length / sizeof(WCHAR)] = L'\\';
-         NameU.Length += sizeof(WCHAR);
+          PDEVICE_OBJECT DeviceToVerify;
+
+          DPRINT ("Media change detected!\n");
+          DPRINT ("Device %p\n", DeviceExt->StorageDevice);
+
+         DeviceToVerify = IoGetDeviceToVerify (PsGetCurrentThread ());
+
+         IoSetDeviceToVerify (PsGetCurrentThread (),
+                              NULL);
+          Status = IoVerifyVolume (DeviceExt->StorageDevice,
+                                  FALSE);
+       }
+      if (!NT_SUCCESS(Status))
+       {
+         DPRINT ("Status %lx\n", Status);
+         *ParentFcb = NULL;
+         return Status;
        }
-      RtlAppendUnicodeStringToString(&NameU, FileNameU);
-      NameU.Buffer[NameU.Length / sizeof(WCHAR)] = 0;
-      FileNameU = &NameU;
     }
 
-  DPRINT ("PathName to open: '%wZ'\n", FileNameU);
+  if (*ParentFcb)
+  {
+     (*ParentFcb)->RefCount++;
+  }
 
-  /*  try first to find an existing FCB in memory  */
-  DPRINT ("Checking for existing FCB in memory\n");
-  Fcb = vfatGrabFCBFromTable (DeviceExt, FileNameU);
-  if (Fcb == NULL)
+  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'\\')
     {
-      DPRINT ("No existing FCB found, making a new one if file exists.\n");
-      Status = vfatGetFCBForFile (DeviceExt, &ParentFcb, &Fcb, FileNameU);
-      if (ParentFcb != NULL)
-        {
-          vfatReleaseFCB (DeviceExt, ParentFcb);
-        }
-      if (!NT_SUCCESS (Status))
-        {
-          DPRINT ("Could not make a new FCB, status: %x\n", Status);
-          return  Status;
-       }
+      PathNameU.Length -= sizeof(WCHAR);
     }
+  PathNameU.Buffer[PathNameU.Length / sizeof(WCHAR)] = 0;
+
+  /*  try first to find an existing FCB in memory  */
+  DPRINT ("Checking for existing FCB in memory\n");
+
+  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;
-    }
+  {
+     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;
 }
 
-VOID STATIC
-VfatSupersedeFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject,
-                 PVFATFCB Fcb)
-{
-  ULONG Cluster, NextCluster;
-  NTSTATUS Status;
-  
-  Fcb->entry.FileSize = 0;
-  if (DeviceExt->FatInfo.FatType == FAT32)
-    {
-      Cluster = Fcb->entry.FirstCluster + Fcb->entry.FirstClusterHigh * 65536;
-    }
-  else
-    {
-      Cluster = Fcb->entry.FirstCluster;
-    }
-  Fcb->entry.FirstCluster = 0;
-  Fcb->entry.FirstClusterHigh = 0;
-  VfatUpdateEntry (Fcb);
-  if (Fcb->RFCB.FileSize.QuadPart > 0)
-    {
-      Fcb->RFCB.AllocationSize.QuadPart = 0;
-      Fcb->RFCB.FileSize.QuadPart = 0;
-      Fcb->RFCB.ValidDataLength.QuadPart = 0;
-      /* Notify cache manager about the change in file size if caching is
-         initialized on the file stream */
-      if (FileObject->SectionObjectPointer->SharedCacheMap != NULL)
-        {
-          CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->RFCB.AllocationSize);
-        }
-    }
-  while (Cluster != 0xffffffff && Cluster > 1)
-    {
-      Status = GetNextCluster (DeviceExt, Cluster, &NextCluster, FALSE);
-      WriteCluster (DeviceExt, Cluster, 0);
-      Cluster = NextCluster;
-    }
-}
-
 NTSTATUS
 VfatCreateFile (PDEVICE_OBJECT DeviceObject, PIRP Irp)
 /*
@@ -446,10 +445,13 @@ 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);
   RequestedDisposition = ((Stack->Parameters.Create.Options >> 24) & 0xff);
@@ -467,9 +469,9 @@ VfatCreateFile (PDEVICE_OBJECT DeviceObject, PIRP Irp)
     }
 
   /* This a open operation for the volume itself */
-  if (FileObject->FileName.Length == 0 && 
+  if (FileObject->FileName.Length == 0 &&
       FileObject->RelatedFileObject == NULL)
-    {      
+    {
       if (RequestedDisposition == FILE_CREATE ||
          RequestedDisposition == FILE_OVERWRITE_IF ||
          RequestedDisposition == FILE_SUPERSEDE)
@@ -486,8 +488,7 @@ VfatCreateFile (PDEVICE_OBJECT DeviceObject, PIRP Irp)
        {
          return (STATUS_INSUFFICIENT_RESOURCES);
        }
-      memset(pCcb, 0, sizeof(VFATCCB));
-      FileObject->Flags |= FO_FCB_IS_VALID;
+      RtlZeroMemory(pCcb, sizeof(VFATCCB));
       FileObject->SectionObjectPointer = &pFcb->SectionObjectPointers;
       FileObject->FsContext = pFcb;
       FileObject->FsContext2 = pCcb;
@@ -498,11 +499,27 @@ VfatCreateFile (PDEVICE_OBJECT DeviceObject, PIRP Irp)
     }
 
   /*
-   * Check for illegal characters in the file name
+   * Check for illegal characters and illegale dot sequences in the file name
    */
   c = FileObject->FileName.Buffer + FileObject->FileName.Length / sizeof(WCHAR);
+  last = c - 1;
+  Dots = TRUE;
   while (c-- > FileObject->FileName.Buffer)
     {
+      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);
@@ -510,7 +527,7 @@ VfatCreateFile (PDEVICE_OBJECT DeviceObject, PIRP Irp)
     }
 
   /* Try opening the file. */
-  Status = VfatOpenFile (DeviceExt, FileObject, &FileObject->FileName);
+  Status = VfatOpenFile (DeviceExt, FileObject, &ParentFcb);
 
   /*
    * If the directory containing the file to open doesn't exist then
@@ -520,6 +537,10 @@ VfatCreateFile (PDEVICE_OBJECT DeviceObject, PIRP Irp)
       Status == STATUS_INVALID_PARAMETER ||
       Status == STATUS_DELETE_PENDING)
     {
+      if (ParentFcb)
+      {
+         vfatReleaseFCB (DeviceExt, ParentFcb);
+      }
       return(Status);
     }
 
@@ -535,23 +556,29 @@ VfatCreateFile (PDEVICE_OBJECT DeviceObject, PIRP Irp)
        {
          ULONG Attributes;
          Attributes = Stack->Parameters.Create.FileAttributes;
-         Status = VfatAddEntry (DeviceExt, &FileObject->FileName, FileObject, RequestedOptions, 
+
+          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))
            {
-             pFcb = FileObject->FsContext;
+              Status = vfatAttachFCBToFileObject (DeviceExt, pFcb, FileObject);
+              if ( !NT_SUCCESS(Status) )
+              {
+                 vfatReleaseFCB (DeviceExt, pFcb);
+                 return Status;
+              }
+
              Irp->IoStatus.Information = FILE_CREATED;
-             VfatSetAllocationSizeInformation(FileObject, 
+
+             VfatSetAllocationSizeInformation(FileObject,
                                               pFcb,
                                               DeviceExt,
                                               &Irp->Overlay.AllocationSize);
-             VfatSetExtendedAttributes(FileObject, 
+             VfatSetExtendedAttributes(FileObject,
                                        Irp->AssociatedIrp.SystemBuffer,
                                        Stack->Parameters.Create.EaLength);
-             IoSetShareAccess(0 /*DesiredAccess*/,
-                              Stack->Parameters.Create.ShareAccess,
-                              FileObject,
-                              &pFcb->FCBShareAccess);
 
              if (PagingFileCreate)
                 {
@@ -565,11 +592,16 @@ VfatCreateFile (PDEVICE_OBJECT DeviceObject, PIRP Irp)
        }
       else
        {
+          vfatReleaseFCB (DeviceExt, ParentFcb);
          return(Status);
        }
     }
   else
     {
+      if (ParentFcb)
+      {
+         vfatReleaseFCB (DeviceExt, ParentFcb);
+      }
       /* Otherwise fail if the caller wanted to create a new file  */
       if (RequestedDisposition == FILE_CREATE)
        {
@@ -580,17 +612,32 @@ VfatCreateFile (PDEVICE_OBJECT DeviceObject, PIRP Irp)
 
       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);
+            }
+        }
+
       /*
        * Check the file has the requested attributes
        */
-      if (RequestedOptions & FILE_NON_DIRECTORY_FILE && 
-         pFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY)
+      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->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
+      if (RequestedOptions & FILE_DIRECTORY_FILE &&
+         !(*pFcb->Attributes & FILE_ATTRIBUTE_DIRECTORY))
        {
          VfatCloseFile (DeviceExt, FileObject);
          return(STATUS_NOT_A_DIRECTORY);
@@ -599,11 +646,11 @@ VfatCreateFile (PDEVICE_OBJECT DeviceObject, PIRP Irp)
       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 
+          *   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)
@@ -627,7 +674,7 @@ VfatCreateFile (PDEVICE_OBJECT DeviceObject, PIRP Irp)
              return(STATUS_INVALID_PARAMETER);
            }
        }
-        
+
 
       if (RequestedDisposition == FILE_OVERWRITE ||
           RequestedDisposition == FILE_OVERWRITE_IF)
@@ -643,21 +690,44 @@ VfatCreateFile (PDEVICE_OBJECT DeviceObject, PIRP Irp)
              return(Status);
            }
        }
-       
-      
+
+
       /* Supersede the file */
       if (RequestedDisposition == FILE_SUPERSEDE)
        {
-         VfatSupersedeFile(DeviceExt, FileObject, pFcb);
+         AllocationSize.QuadPart = 0;
+          VfatSetAllocationSizeInformation(FileObject, pFcb, DeviceExt, &AllocationSize);
          Irp->IoStatus.Information = FILE_SUPERSEDED;
        }
+      else if (RequestedDisposition == FILE_OVERWRITE || RequestedDisposition == FILE_OVERWRITE_IF)
+        {
+          Irp->IoStatus.Information = FILE_OVERWRITTEN;
+        }
       else
-       {
+        {
          Irp->IoStatus.Information = FILE_OPENED;
        }
     }
-  
-  /* FIXME : test share access */
+
+  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
+         );
+
+   }
+
+  pFcb->OpenHandleCount++;
+
   /* FIXME : test write access if requested */
 
   return(Status);
@@ -670,9 +740,9 @@ NTSTATUS VfatCreate (PVFAT_IRP_CONTEXT IrpContext)
  */
 {
   NTSTATUS Status;
-  
-  assert (IrpContext);
-  
+
+  ASSERT(IrpContext);
+
   if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject)
     {
       /* DeviceObject represents FileSystem instead of logical volume */
@@ -683,19 +753,19 @@ NTSTATUS VfatCreate (PVFAT_IRP_CONTEXT IrpContext)
       VfatFreeIrpContext(IrpContext);
       return(STATUS_SUCCESS);
     }
-  
+
   if (!(IrpContext->Flags & IRPCONTEXT_CANWAIT))
     {
       return(VfatQueueRequest (IrpContext));
     }
-  
+
   IrpContext->Irp->IoStatus.Information = 0;
   ExAcquireResourceExclusiveLite (&IrpContext->DeviceExt->DirResource, TRUE);
   Status = VfatCreateFile (IrpContext->DeviceObject, IrpContext->Irp);
   ExReleaseResourceLite (&IrpContext->DeviceExt->DirResource);
 
   IrpContext->Irp->IoStatus.Status = Status;
-  IoCompleteRequest (IrpContext->Irp, 
+  IoCompleteRequest (IrpContext->Irp,
                     (CCHAR)(NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT));
   VfatFreeIrpContext(IrpContext);
   return(Status);