[fastfat_new]
[reactos.git] / reactos / drivers / filesystems / fastfat_new / create.c
index 8f169cc..a01cece 100644 (file)
@@ -1,26 +1,9 @@
 /*
- *  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.
- *
- *  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:             drivers/fs/vfat/create.c
- * PURPOSE:          VFAT Filesystem
- * PROGRAMMER:       Jason Filby (jasonfilby@yahoo.com)
+ * PROJECT:         ReactOS FAT file system driver
+ * LICENSE:         GNU GPLv3 as published by the Free Software Foundation
+ * FILE:            drivers/filesystems/fastfat/create.c
+ * PURPOSE:         Create routines
+ * PROGRAMMERS:     Aleksey Bragin (aleksey@reactos.org)
  */
 
 /* INCLUDES *****************************************************************/
 
 /* FUNCTIONS *****************************************************************/
 
-void
-vfat8Dot3ToString (PFAT_DIR_ENTRY pEntry, PUNICODE_STRING NameU)
+IO_STATUS_BLOCK
+NTAPI
+FatiOpenRootDcb(IN PFAT_IRP_CONTEXT IrpContext,
+                IN PFILE_OBJECT FileObject,
+                IN PVCB Vcb,
+                IN PACCESS_MASK DesiredAccess,
+                IN USHORT ShareAccess,
+                IN ULONG CreateDisposition)
 {
-       OEM_STRING StringA;
-       USHORT Length;
-       CHAR  cString[12];
-
-       RtlCopyMemory(cString, pEntry->ShortName, 11);
-       cString[11] = 0;
-       if (cString[0] == 0x05)
-       {
-               cString[0] = 0xe5;
-       }
-
-       StringA.Buffer = cString;
-       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)
-       {
-               RtlDowncaseUnicodeString(NameU, NameU, FALSE);
-       }
-       if (cString[8] != ' ')
-       {
-               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;
-       }
-       NameU->Buffer[NameU->Length / sizeof(WCHAR)] = 0;
-       DPRINT("'%wZ'\n", NameU);
+    IO_STATUS_BLOCK Iosb;
+
+    DPRINT1("Opening root directory\n");
+
+    Iosb.Status = STATUS_NOT_IMPLEMENTED;
+
+    return Iosb;
 }
 
-NTSTATUS
-ReadVolumeLabel (PDEVICE_EXTENSION DeviceExt, PVPB Vpb)
-/*
- * FUNCTION: Read the volume label
- */
+FF_ERROR
+NTAPI
+FatiTryToOpen(IN PFILE_OBJECT FileObject,
+              IN PVCB Vcb)
 {
-       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;
-
-       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);
-
-       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 STATUS_SUCCESS;
+    OEM_STRING AnsiName;
+    CHAR AnsiNameBuf[512];
+    FF_ERROR Error;
+    NTSTATUS Status;
+    FF_FILE *FileHandle;
+
+    /* Convert the name to ANSI */
+    AnsiName.Buffer = AnsiNameBuf;
+    AnsiName.Length = 0;
+    AnsiName.MaximumLength = sizeof(AnsiNameBuf);
+    RtlZeroMemory(AnsiNameBuf, sizeof(AnsiNameBuf));
+    Status = RtlUpcaseUnicodeStringToCountedOemString(&AnsiName, &FileObject->FileName, FALSE);
+    if (!NT_SUCCESS(Status))
+    {
+        ASSERT(FALSE);
+    }
+
+    /* Open the file with FullFAT */
+    FileHandle = FF_Open(Vcb->Ioman, AnsiName.Buffer, FF_MODE_READ, &Error);
+
+    /* Close the handle */
+    if (FileHandle) FF_Close(FileHandle);
+
+    /* Return status */
+    return Error;
 }
 
-NTSTATUS
-FindFile (
-       PDEVICE_EXTENSION DeviceExt,
-       PVFATFCB Parent,
-       PUNICODE_STRING FileToFindU,
-       PVFAT_DIRENTRY_CONTEXT DirContext,
-       BOOLEAN First)
-/*
- * FUNCTION: Find a file
- */
+IO_STATUS_BLOCK
+NTAPI
+FatiOpenExistingDir(IN PFAT_IRP_CONTEXT IrpContext,
+                     IN PFILE_OBJECT FileObject,
+                     IN PVCB Vcb,
+                     IN PFCB ParentDcb,
+                     IN PACCESS_MASK DesiredAccess,
+                     IN USHORT ShareAccess,
+                     IN ULONG AllocationSize,
+                     IN PFILE_FULL_EA_INFORMATION EaBuffer,
+                     IN ULONG EaLength,
+                     IN UCHAR FileAttributes,
+                     IN ULONG CreateDisposition,
+                     IN BOOLEAN DeleteOnClose)
 {
-       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 %p, FileToFind '%wZ', DirIndex: %d)\n",
-               Parent, FileToFindU, DirContext->DirIndex);
-       DPRINT ("FindFile: Path %wZ\n",&Parent->PathNameU);
-
-       PathNameBufferLength = LONGNAME_MAX_LENGTH * sizeof(WCHAR);
-       PathNameBuffer = ExAllocatePoolWithTag(NonPagedPool, PathNameBufferLength + sizeof(WCHAR), TAG_VFAT);
-       if (!PathNameBuffer)
-       {
-               return STATUS_INSUFFICIENT_RESOURCES;
-       }
-
-       PathNameU.Buffer = PathNameBuffer;
-       PathNameU.Length = 0;
-       PathNameU.MaximumLength = PathNameBufferLength;
-
-       DirContext->LongNameU.Length = 0;
-       DirContext->ShortNameU.Length = 0;
-
-       WildCard = FsRtlDoesNameContainWildCards(FileToFindU);
-
-       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(startIndex >= DirContext->DirIndex)
-                       {
-                               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;
-                       }
-                       else
-                       {
-                               DPRINT("FCB not found for %wZ\n", &PathNameU);
-                               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))
-       {
-               ExFreePool(PathNameBuffer);
-               return Status;
-       }
-
-       while(TRUE)
-       {
-               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
-               {
-                       Found = FsRtlAreNamesEqual(&DirContext->LongNameU, FileToFindU, TRUE, NULL) ||
-                               FsRtlAreNamesEqual(&DirContext->ShortNameU, FileToFindU, TRUE, NULL);
-               }
-
-               if (Found)
-               {
-                       if (WildCard)
-                       {
-                               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);
-                               }
-                       }
-                       DPRINT("%d\n", DirContext->LongNameU.Length);
-                       DPRINT("FindFile: new Name %wZ, DirIndex %d\n",
-                               &DirContext->LongNameU, DirContext->DirIndex);
-
-                       if (Context)
-                       {
-                               CcUnpinData(Context);
-                       }
-                       RtlFreeUnicodeString(&FileToFindUpcase);
-                       ExFreePool(PathNameBuffer);
-                       return STATUS_SUCCESS;
-               }
-               DirContext->DirIndex++;
-       }
-
-       if (Context)
-       {
-               CcUnpinData(Context);
-       }
-
-       RtlFreeUnicodeString(&FileToFindUpcase);
-       ExFreePool(PathNameBuffer);
-       return Status;
+    IO_STATUS_BLOCK Iosb = {{0}};
+    OEM_STRING AnsiName;
+    CHAR AnsiNameBuf[512];
+    PFCB Fcb;
+    NTSTATUS Status;
+    FF_FILE *FileHandle;
+
+    /* Only open is permitted */
+    if (CreateDisposition != FILE_OPEN &&
+        CreateDisposition != FILE_OPEN_IF)
+    {
+        Iosb.Status = STATUS_OBJECT_NAME_COLLISION;
+        return Iosb;
+    }
+
+    // TODO: Check dir access
+
+    /* Convert the name to ANSI */
+    AnsiName.Buffer = AnsiNameBuf;
+    AnsiName.Length = 0;
+    AnsiName.MaximumLength = sizeof(AnsiNameBuf);
+    RtlZeroMemory(AnsiNameBuf, sizeof(AnsiNameBuf));
+    Status = RtlUpcaseUnicodeStringToCountedOemString(&AnsiName, &FileObject->FileName, FALSE);
+    if (!NT_SUCCESS(Status))
+    {
+        ASSERT(FALSE);
+    }
+
+    /* Open the dir with FullFAT */
+    FileHandle = FF_Open(Vcb->Ioman, AnsiName.Buffer, FF_MODE_DIR, NULL);
+
+    if (!FileHandle)
+    {
+        Iosb.Status = STATUS_OBJECT_NAME_NOT_FOUND; // FIXME: A shortcut for now
+        return Iosb;
+    }
+
+    /* Create a new DCB for this directory */
+    Fcb = FatCreateDcb(IrpContext, Vcb, ParentDcb, FileHandle);
+
+    /* Set share access */
+    IoSetShareAccess(*DesiredAccess, ShareAccess, FileObject, &Fcb->ShareAccess);
+
+    /* Set context and section object pointers */
+    FatSetFileObject(FileObject,
+                     UserDirectoryOpen,
+                     Fcb,
+                     FatCreateCcb());
+
+    Iosb.Status = STATUS_SUCCESS;
+    Iosb.Information = FILE_OPENED;
+
+    DPRINT1("Successfully opened dir %s\n", AnsiNameBuf);
+
+    return Iosb;
 }
 
-static
-NTSTATUS
-VfatOpenFile (
-       PDEVICE_EXTENSION DeviceExt,
-        PUNICODE_STRING PathNameU,
-       PFILE_OBJECT FileObject,
-       PVFATFCB* ParentFcb )
-/*
- * FUNCTION: Opens a file
- */
+IO_STATUS_BLOCK
+NTAPI
+FatiOpenExistingFile(IN PFAT_IRP_CONTEXT IrpContext,
+                     IN PFILE_OBJECT FileObject,
+                     IN PVCB Vcb,
+                     IN PFCB ParentDcb,
+                     IN PACCESS_MASK DesiredAccess,
+                     IN USHORT ShareAccess,
+                     IN ULONG AllocationSize,
+                     IN PFILE_FULL_EA_INFORMATION EaBuffer,
+                     IN ULONG EaLength,
+                     IN UCHAR FileAttributes,
+                     IN ULONG CreateDisposition,
+                     IN BOOLEAN IsPagingFile,
+                     IN BOOLEAN DeleteOnClose,
+                     IN BOOLEAN IsDosName)
 {
-       PVFATFCB Fcb;
-       NTSTATUS Status;
-
-       DPRINT ("VfatOpenFile(%p, '%wZ', %p, %p)\n", DeviceExt, PathNameU, FileObject, ParentFcb);
-
-       if (FileObject->RelatedFileObject)
-       {
-               DPRINT ("'%wZ'\n", &FileObject->RelatedFileObject->FileName);
-
-               *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)
-
-               {
-                       PDEVICE_OBJECT DeviceToVerify;
-
-                       DPRINT ("Media change detected!\n");
-                       DPRINT ("Device %p\n", DeviceExt->StorageDevice);
-
-                        /* Find the device to verify and reset the thread field to empty value again. */
-                       DeviceToVerify = IoGetDeviceToVerify (PsGetCurrentThread ());
-                       IoSetDeviceToVerify (PsGetCurrentThread (), NULL);
-                       Status = IoVerifyVolume (DeviceToVerify,
-                               FALSE);
-               }
-               if (!NT_SUCCESS(Status))
-               {
-                       DPRINT ("Status %lx\n", Status);
-                       *ParentFcb = NULL;
-                       return Status;
-               }
-       }
-
-       if (*ParentFcb)
-       {
-               (*ParentFcb)->RefCount++;
-       }
-
-       /*  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;
-       }
-       DPRINT ("Attaching FCB to fileObject\n");
-       Status = vfatAttachFCBToFileObject (DeviceExt, Fcb, FileObject);
-       if (!NT_SUCCESS(Status))
-       {
-               vfatReleaseFCB (DeviceExt, Fcb);
-       }
-       return  Status;
+    IO_STATUS_BLOCK Iosb = {{0}};
+    OEM_STRING AnsiName;
+    CHAR AnsiNameBuf[512];
+    PFCB Fcb;
+    NTSTATUS Status;
+    FF_FILE *FileHandle;
+
+    /* Check for create file option and fail */
+    if (CreateDisposition == FILE_CREATE)
+    {
+        Iosb.Status = STATUS_OBJECT_NAME_COLLISION;
+        return Iosb;
+    }
+
+    // TODO: Check more params
+
+    /* Convert the name to ANSI */
+    AnsiName.Buffer = AnsiNameBuf;
+    AnsiName.Length = 0;
+    AnsiName.MaximumLength = sizeof(AnsiNameBuf);
+    RtlZeroMemory(AnsiNameBuf, sizeof(AnsiNameBuf));
+    Status = RtlUpcaseUnicodeStringToCountedOemString(&AnsiName, &FileObject->FileName, FALSE);
+    if (!NT_SUCCESS(Status))
+    {
+        ASSERT(FALSE);
+    }
+
+    /* Open the file with FullFAT */
+    FileHandle = FF_Open(Vcb->Ioman, AnsiName.Buffer, FF_MODE_READ, NULL);
+
+    if (!FileHandle)
+    {
+        Iosb.Status = STATUS_OBJECT_NAME_NOT_FOUND; // FIXME: A shortcut for now
+        return Iosb;
+    }
+
+    /* Create a new FCB for this file */
+    Fcb = FatCreateFcb(IrpContext, Vcb, ParentDcb, FileHandle);
+
+    // TODO: Check if overwrite is needed
+
+    // This is usual file open branch, without overwriting!
+    /* Set context and section object pointers */
+    FatSetFileObject(FileObject,
+                     UserFileOpen,
+                     Fcb,
+                     FatCreateCcb());
+    FileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
+
+    Iosb.Status = STATUS_SUCCESS;
+    Iosb.Information = FILE_OPENED;
+
+    return Iosb;
 }
 
-static NTSTATUS
-VfatCreateFile ( PDEVICE_OBJECT DeviceObject, PIRP Irp )
-/*
- * FUNCTION: Create or open a file
- */
+IO_STATUS_BLOCK
+NTAPI
+FatiOpenVolume(IN PFAT_IRP_CONTEXT IrpContext,
+               IN PFILE_OBJECT FileObject,
+               IN PVCB Vcb,
+               IN PACCESS_MASK DesiredAccess,
+               IN USHORT ShareAccess,
+               IN ULONG CreateDisposition)
 {
-       PIO_STACK_LOCATION Stack;
-       PFILE_OBJECT FileObject;
-       NTSTATUS Status = STATUS_SUCCESS;
-       PDEVICE_EXTENSION DeviceExt;
-       ULONG RequestedDisposition, RequestedOptions;
-       PVFATCCB pCcb;
-       PVFATFCB pFcb = NULL;
-       PVFATFCB ParentFcb = NULL;
-       PWCHAR c, last;
-       BOOLEAN PagingFileCreate = FALSE;
-       BOOLEAN Dots;
-       UNICODE_STRING FileNameU;
-        UNICODE_STRING PathNameU;
-
-       /* Unpack the various parameters. */
-       Stack = IoGetCurrentIrpStackLocation (Irp);
-       RequestedDisposition = ((Stack->Parameters.Create.Options >> 24) & 0xff);
-       RequestedOptions =
-               Stack->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS;
-       PagingFileCreate = (Stack->Flags & SL_OPEN_PAGING_FILE) ? TRUE : FALSE;
-       FileObject = Stack->FileObject;
-       DeviceExt = DeviceObject->DeviceExtension;
-
-       /* Check their validity. */
-       if (RequestedOptions & FILE_DIRECTORY_FILE &&
-               RequestedDisposition == FILE_SUPERSEDE)
-       {
-               return(STATUS_INVALID_PARAMETER);
-       }
-
-        if (RequestedOptions & FILE_DIRECTORY_FILE &&
-            RequestedOptions & FILE_NON_DIRECTORY_FILE)
+    PCCB Ccb;
+    IO_STATUS_BLOCK Iosb = {{0}};
+    BOOLEAN VolumeFlushed = FALSE;
+
+    /* Check parameters */
+    if (CreateDisposition != FILE_OPEN &&
+        CreateDisposition != FILE_OPEN_IF)
+    {
+        /* Deny access */
+        Iosb.Status = STATUS_ACCESS_DENIED;
+    }
+
+    /* Check if it's exclusive open */
+    if (!FlagOn(ShareAccess, FILE_SHARE_WRITE) &&
+        !FlagOn(ShareAccess, FILE_SHARE_DELETE))
+    {
+        // TODO: Check if exclusive read access requested
+        // and opened handles count is not 0
+        //if (!FlagOn(ShareAccess, FILE_SHARE_READ)
+
+        DPRINT1("Exclusive voume open\n");
+
+        // TODO: Flush the volume
+        VolumeFlushed = TRUE;
+    }
+    else if (FlagOn(*DesiredAccess, FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA))
+    {
+        DPRINT1("Shared open\n");
+
+        // TODO: Flush the volume
+        VolumeFlushed = TRUE;
+    }
+
+    if (VolumeFlushed &&
+        !FlagOn(Vcb->State, VCB_STATE_MOUNTED_DIRTY) &&
+        FlagOn(Vcb->State, VCB_STATE_FLAG_DIRTY) &&
+        CcIsThereDirtyData(Vcb->Vpb))
+    {
+        UNIMPLEMENTED;
+    }
+
+    /* Set share access */
+    if (Vcb->DirectOpenCount > 0)
+    {
+        /* This volume has already been opened */
+        Iosb.Status = IoCheckShareAccess(*DesiredAccess,
+                                         ShareAccess,
+                                         FileObject,
+                                         &Vcb->ShareAccess,
+                                         TRUE);
+
+        if (!NT_SUCCESS(Iosb.Status))
         {
-               return(STATUS_INVALID_PARAMETER);
+            ASSERT(FALSE);
         }
+    }
+    else
+    {
+        /* This is the first time open */
+        IoSetShareAccess(*DesiredAccess,
+                         ShareAccess,
+                         FileObject,
+                         &Vcb->ShareAccess);
+    }
+
+    /* Set file object pointers */
+    Ccb = FatCreateCcb(IrpContext);
+    FatSetFileObject(FileObject, UserVolumeOpen, Vcb, Ccb);
+    FileObject->SectionObjectPointer = &Vcb->SectionObjectPointers;
+
+    /* Increase direct open count */
+    Vcb->DirectOpenCount++;
+    Vcb->OpenFileCount++;
+
+    /* Set no buffering flag */
+    FileObject->Flags |= FO_NO_INTERMEDIATE_BUFFERING;
+
+    // TODO: User's access check
+
+    Iosb.Status = STATUS_SUCCESS;
+    Iosb.Information = FILE_OPENED;
+
+    return Iosb;
+}
 
-       /* 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 and illegale dot sequences in the file name
-        */
-        PathNameU = FileObject->FileName;
-       c = PathNameU.Buffer + PathNameU.Length / sizeof(WCHAR);
-       last = c - 1;
-       Dots = TRUE;
-       while (c-- > PathNameU.Buffer)
-       {
-               if (*c == L'\\' || c == PathNameU.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);
-               }
-       }
-        if (FileObject->RelatedFileObject && PathNameU.Buffer[0] == L'\\')
+NTSTATUS
+NTAPI
+FatiCreate(IN PFAT_IRP_CONTEXT IrpContext,
+           IN PIRP Irp)
+{
+    /* Boolean options */
+    BOOLEAN CreateDirectory;
+    BOOLEAN SequentialOnly;
+    BOOLEAN NoIntermediateBuffering;
+    BOOLEAN OpenDirectory;
+    BOOLEAN IsPagingFile;
+    BOOLEAN OpenTargetDirectory;
+    BOOLEAN DirectoryFile;
+    BOOLEAN NonDirectoryFile;
+    BOOLEAN NoEaKnowledge;
+    BOOLEAN DeleteOnClose;
+    BOOLEAN TemporaryFile;
+    ULONG CreateDisposition;
+
+    /* Control blocks */
+    PVCB Vcb, DecodedVcb, RelatedVcb;
+    PFCB Fcb, NextFcb, RelatedDcb;
+    PCCB Ccb, RelatedCcb;
+    PFCB ParentDcb;
+
+    /* IRP data */
+    PFILE_OBJECT FileObject;
+    PFILE_OBJECT RelatedFO;
+    UNICODE_STRING FileName;
+    ULONG AllocationSize;
+    PFILE_FULL_EA_INFORMATION EaBuffer;
+    PACCESS_MASK DesiredAccess;
+    ULONG Options;
+    UCHAR FileAttributes;
+    USHORT ShareAccess;
+    ULONG EaLength;
+
+    /* Misc */
+    NTSTATUS Status;
+    IO_STATUS_BLOCK Iosb;
+    PIO_STACK_LOCATION IrpSp;
+    BOOLEAN EndBackslash = FALSE, OpenedAsDos;
+    UNICODE_STRING RemainingPart, FirstName, NextName, FileNameUpcased;
+    OEM_STRING AnsiFirstName;
+    FF_ERROR FfError;
+    TYPE_OF_OPEN TypeOfOpen;
+    BOOLEAN OplockPostIrp = FALSE;
+
+    Iosb.Status = STATUS_SUCCESS;
+
+    /* Get current IRP stack location */
+    IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+    DPRINT("FatCommonCreate\n", 0 );
+    DPRINT("Irp                       = %08lx\n",   Irp );
+    DPRINT("\t->Flags                   = %08lx\n", Irp->Flags );
+    DPRINT("\t->FileObject              = %08lx\n", IrpSp->FileObject );
+    DPRINT("\t->RelatedFileObject       = %08lx\n", IrpSp->FileObject->RelatedFileObject );
+    DPRINT("\t->FileName                = %wZ\n",   &IrpSp->FileObject->FileName );
+    DPRINT("\t->AllocationSize.LowPart  = %08lx\n", Irp->Overlay.AllocationSize.LowPart );
+    DPRINT("\t->AllocationSize.HighPart = %08lx\n", Irp->Overlay.AllocationSize.HighPart );
+    DPRINT("\t->SystemBuffer            = %08lx\n", Irp->AssociatedIrp.SystemBuffer );
+    DPRINT("\t->DesiredAccess           = %08lx\n", IrpSp->Parameters.Create.SecurityContext->DesiredAccess );
+    DPRINT("\t->Options                 = %08lx\n", IrpSp->Parameters.Create.Options );
+    DPRINT("\t->FileAttributes          = %04x\n",  IrpSp->Parameters.Create.FileAttributes );
+    DPRINT("\t->ShareAccess             = %04x\n",  IrpSp->Parameters.Create.ShareAccess );
+    DPRINT("\t->EaLength                = %08lx\n", IrpSp->Parameters.Create.EaLength );
+
+    /* Apply a special hack for Win32, idea taken from FASTFAT reference driver from WDK */
+    if ((IrpSp->FileObject->FileName.Length > sizeof(WCHAR)) &&
+        (IrpSp->FileObject->FileName.Buffer[1] == L'\\') &&
+        (IrpSp->FileObject->FileName.Buffer[0] == L'\\'))
+    {
+        /* Remove a leading slash */
+        IrpSp->FileObject->FileName.Length -= sizeof(WCHAR);
+        RtlMoveMemory(&IrpSp->FileObject->FileName.Buffer[0],
+                      &IrpSp->FileObject->FileName.Buffer[1],
+                      IrpSp->FileObject->FileName.Length );
+
+        /* Check again: if there are still two leading slashes,
+           exit with an error */
+        if ((IrpSp->FileObject->FileName.Length > sizeof(WCHAR)) &&
+            (IrpSp->FileObject->FileName.Buffer[1] == L'\\') &&
+            (IrpSp->FileObject->FileName.Buffer[0] == L'\\'))
+        {
+            FatCompleteRequest( IrpContext, Irp, STATUS_OBJECT_NAME_INVALID );
+
+            DPRINT1("FatiCreate: STATUS_OBJECT_NAME_INVALID\n");
+            return STATUS_OBJECT_NAME_INVALID;
+        }
+    }
+
+    /* Make sure we have SecurityContext */
+    ASSERT(IrpSp->Parameters.Create.SecurityContext != NULL);
+
+    /* Get necessary data out of IRP */
+    FileObject     = IrpSp->FileObject;
+    FileName       = FileObject->FileName;
+    RelatedFO      = FileObject->RelatedFileObject;
+    AllocationSize = Irp->Overlay.AllocationSize.LowPart;
+    EaBuffer       = Irp->AssociatedIrp.SystemBuffer;
+    DesiredAccess  = &IrpSp->Parameters.Create.SecurityContext->DesiredAccess;
+    Options        = IrpSp->Parameters.Create.Options;
+    FileAttributes = (UCHAR)(IrpSp->Parameters.Create.FileAttributes & ~FILE_ATTRIBUTE_NORMAL);
+    ShareAccess    = IrpSp->Parameters.Create.ShareAccess;
+    EaLength       = IrpSp->Parameters.Create.EaLength;
+
+    /* Set VPB to related object's VPB if it exists */
+    if (RelatedFO)
+        FileObject->Vpb = RelatedFO->Vpb;
+
+    /* Prepare file attributes mask */
+    FileAttributes &= (FILE_ATTRIBUTE_READONLY |
+                       FILE_ATTRIBUTE_HIDDEN   |
+                       FILE_ATTRIBUTE_SYSTEM   |
+                       FILE_ATTRIBUTE_ARCHIVE);
+
+    /* Get the volume control object */
+    Vcb = &((PVOLUME_DEVICE_OBJECT)IrpSp->DeviceObject)->Vcb;
+
+    /* Get options */
+    DirectoryFile           = BooleanFlagOn(Options, FILE_DIRECTORY_FILE);
+    NonDirectoryFile        = BooleanFlagOn(Options, FILE_NON_DIRECTORY_FILE);
+    SequentialOnly          = BooleanFlagOn(Options, FILE_SEQUENTIAL_ONLY);
+    NoIntermediateBuffering = BooleanFlagOn(Options, FILE_NO_INTERMEDIATE_BUFFERING);
+    NoEaKnowledge           = BooleanFlagOn(Options, FILE_NO_EA_KNOWLEDGE);
+    DeleteOnClose           = BooleanFlagOn(Options, FILE_DELETE_ON_CLOSE);
+    TemporaryFile           = BooleanFlagOn(IrpSp->Parameters.Create.FileAttributes,
+                                            FILE_ATTRIBUTE_TEMPORARY );
+    IsPagingFile            = BooleanFlagOn(IrpSp->Flags, SL_OPEN_PAGING_FILE);
+    OpenTargetDirectory     = BooleanFlagOn(IrpSp->Flags, SL_OPEN_TARGET_DIRECTORY);
+
+    /* Calculate create disposition */
+    CreateDisposition = (Options >> 24) & 0x000000ff;
+
+    /* Get Create/Open directory flags based on it */
+    CreateDirectory = (BOOLEAN)(DirectoryFile &&
+                                ((CreateDisposition == FILE_CREATE) ||
+                                 (CreateDisposition == FILE_OPEN_IF)));
+
+    OpenDirectory   = (BOOLEAN)(DirectoryFile &&
+                                ((CreateDisposition == FILE_OPEN) ||
+                                 (CreateDisposition == FILE_OPEN_IF)));
+
+    /* Validate parameters: directory/nondirectory mismatch and
+       AllocationSize being more than 4GB */
+    if ((DirectoryFile && NonDirectoryFile) ||
+        Irp->Overlay.AllocationSize.HighPart != 0)
+    {
+        FatCompleteRequest(IrpContext, Irp, STATUS_INVALID_PARAMETER);
+
+        DPRINT1("FatiCreate: STATUS_INVALID_PARAMETER\n", 0);
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    /* Acquire the VCB lock exclusively */
+    if (!FatAcquireExclusiveVcb(IrpContext, Vcb))
+    {
+        // TODO: Postpone the IRP for later processing
+        ASSERT(FALSE);
+        return STATUS_NOT_IMPLEMENTED;
+    }
+
+    // TODO: Verify the VCB
+
+    /* If VCB is locked, then no file openings are possible */
+    if (Vcb->State & VCB_STATE_FLAG_LOCKED)
+    {
+        DPRINT1("This volume is locked\n");
+        Status = STATUS_ACCESS_DENIED;
+
+        /* Cleanup and return */
+        FatReleaseVcb(IrpContext, Vcb);
+        return Status;
+    }
+
+    // TODO: Check if the volume is write protected and disallow DELETE_ON_CLOSE
+
+    // TODO: Make sure EAs aren't supported on FAT32
+
+    /* Check if it's a volume open request */
+    if (FileName.Length == 0)
+    {
+        /* Test related FO to be sure */
+        if (!RelatedFO ||
+            FatDecodeFileObject(RelatedFO, &DecodedVcb, &Fcb, &Ccb) == UserVolumeOpen)
         {
-            return(STATUS_OBJECT_NAME_INVALID);
+            /* Check parameters */
+            if (DirectoryFile || OpenTargetDirectory)
+            {
+                Status = DirectoryFile ? STATUS_NOT_A_DIRECTORY : STATUS_INVALID_PARAMETER;
+
+                /* Unlock VCB */
+                FatReleaseVcb(IrpContext, Vcb);
+
+                /* Complete the request and return */
+                FatCompleteRequest(IrpContext, Irp, Status);
+                return Status;
+            }
+
+            /* It is indeed a volume open request */
+            Iosb = FatiOpenVolume(IrpContext,
+                                  FileObject,
+                                  Vcb,
+                                  DesiredAccess,
+                                  ShareAccess,
+                                  CreateDisposition);
+
+            /* Set resulting information */
+            Irp->IoStatus.Information = Iosb.Information;
+
+            /* Unlock VCB */
+            FatReleaseVcb(IrpContext, Vcb);
+
+            /* Complete the request and return */
+            FatCompleteRequest(IrpContext, Irp, Iosb.Status);
+            return Iosb.Status;
         }
-        if (PathNameU.Length > sizeof(WCHAR) && PathNameU.Buffer[PathNameU.Length/sizeof(WCHAR)-1] == L'\\')
+    }
+
+    /* Check if this is a relative open */
+    if (RelatedFO)
+    {
+        /* Decode the file object */
+        TypeOfOpen = FatDecodeFileObject(RelatedFO,
+                                         &RelatedVcb,
+                                         &RelatedDcb,
+                                         &RelatedCcb);
+
+        /* Check open type */
+        if (TypeOfOpen != UserFileOpen &&
+            TypeOfOpen != UserDirectoryOpen)
         {
-            PathNameU.Length -= sizeof(WCHAR);
+            DPRINT1("Invalid file object!\n");
+
+            /* Cleanup and return */
+            FatReleaseVcb(IrpContext, Vcb);
+            return STATUS_OBJECT_PATH_NOT_FOUND;
         }
 
-       /* Try opening the file. */
-       Status = VfatOpenFile (DeviceExt, &PathNameU, FileObject, &ParentFcb);
-
-       /*
-        * If the directory containing the file to open doesn't exist then
-        * fail immediately
-        */
-       if (Status == STATUS_OBJECT_PATH_NOT_FOUND ||
-            Status == STATUS_INVALID_PARAMETER ||
-           Status == STATUS_DELETE_PENDING)
-       {
-               if (ParentFcb)
-               {
-                       vfatReleaseFCB (DeviceExt, ParentFcb);
-               }
-               return(Status);
-       }
-        if (!NT_SUCCESS(Status) && ParentFcb == NULL)
+        /* File path must be relative */
+        if (FileName.Length != 0 &&
+            FileName.Buffer[0] == L'\\')
         {
-                DPRINT1("VfatOpenFile faild for '%wZ', status %x\n", &PathNameU, Status);
-                return Status;
+            /* The name is absolute, fail */
+            FatReleaseVcb(IrpContext, Vcb);
+            return STATUS_OBJECT_NAME_INVALID;
         }
 
-       /*
-        * If the file open failed then create the required file
-        */
-       if (!NT_SUCCESS (Status))
-       {
-               if (RequestedDisposition == FILE_CREATE ||
-                   RequestedDisposition == FILE_OPEN_IF ||
-                   RequestedDisposition == FILE_OVERWRITE_IF ||
-                   RequestedDisposition == FILE_SUPERSEDE)
-               {
-                       ULONG Attributes;
-                       Attributes = Stack->Parameters.Create.FileAttributes;
-
-                       vfatSplitPathName(&PathNameU, NULL, &FileNameU);
-                       Status = VfatAddEntry (DeviceExt, &FileNameU, &pFcb, ParentFcb, RequestedOptions,
-                               (UCHAR)(Attributes & FILE_ATTRIBUTE_VALID_FLAGS));
-                       vfatReleaseFCB (DeviceExt, ParentFcb);
-                       if (NT_SUCCESS (Status))
-                       {
-                               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
-               {
-                       if (ParentFcb)
-                       {
-                               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)
-               {
-                       Irp->IoStatus.Information = FILE_EXISTS;
-                       VfatCloseFile (DeviceExt, FileObject);
-                       return(STATUS_OBJECT_NAME_COLLISION);
-               }
-
-               pFcb = FileObject->FsContext;
-
-               if (pFcb->OpenHandleCount != 0)
-               {
-                       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->Attributes & FILE_ATTRIBUTE_DIRECTORY)
-               {
-                       VfatCloseFile (DeviceExt, FileObject);
-                       return(STATUS_FILE_IS_A_DIRECTORY);
-               }
-               if (RequestedOptions & FILE_DIRECTORY_FILE &&
-                       !(*pFcb->Attributes & FILE_ATTRIBUTE_DIRECTORY))
-               {
-                       VfatCloseFile (DeviceExt, FileObject);
-                       return(STATUS_NOT_A_DIRECTORY);
-               }
-#ifndef USE_ROS_CC_AND_FS
-               if (!(*pFcb->Attributes & FILE_ATTRIBUTE_DIRECTORY))
-               {
-                       if (Stack->Parameters.Create.SecurityContext->DesiredAccess & FILE_WRITE_DATA ||
-                               RequestedDisposition == FILE_OVERWRITE ||
-                               RequestedDisposition == FILE_OVERWRITE_IF)
-                       {
-                               if (!MmFlushImageSection(&pFcb->SectionObjectPointers, MmFlushForWrite))
-                               {
-                                       DPRINT1("%wZ\n", &pFcb->PathNameU);
-                                       DPRINT1("%d %d %d\n", Stack->Parameters.Create.SecurityContext->DesiredAccess & FILE_WRITE_DATA,
-                                                       RequestedDisposition == FILE_OVERWRITE, RequestedDisposition == FILE_OVERWRITE_IF);
-                                       VfatCloseFile (DeviceExt, FileObject);
-                                       return STATUS_SHARING_VIOLATION;
-                               }
-                       }
-               }
-#endif
-               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
-                       {
-                               pFcb->Flags |= FCB_IS_PAGE_FILE;
-                       }
-               }
-               else
-               {
-                       if (pFcb->Flags & FCB_IS_PAGE_FILE)
-                       {
-                               VfatCloseFile(DeviceExt, FileObject);
-                               return(STATUS_INVALID_PARAMETER);
-                       }
-               }
-
-
-               if (RequestedDisposition == FILE_OVERWRITE ||
-                   RequestedDisposition == FILE_OVERWRITE_IF ||
-                   RequestedDisposition == FILE_SUPERSEDE)
-               {
-                        ExAcquireResourceExclusiveLite(&(pFcb->MainResource), TRUE);
-                       Status = VfatSetAllocationSizeInformation (FileObject,
-                                                                  pFcb,
-                                                                  DeviceExt,
-                                                                  &Irp->Overlay.AllocationSize);
-                        ExReleaseResourceLite(&(pFcb->MainResource));
-                       if (!NT_SUCCESS (Status))
-                       {
-                               VfatCloseFile (DeviceExt, FileObject);
-                               return(Status);
-                       }
-               }
-
-               if (RequestedDisposition == FILE_SUPERSEDE)
-               {
-                       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;
-               }
-       }
-
-       if (pFcb->OpenHandleCount == 0)
-       {
-               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);
-}
+        /* Make sure volume is the same */
+        ASSERT(RelatedVcb == Vcb);
+
+        /* Save VPB */
+        FileObject->Vpb = RelatedFO->Vpb;
 
+        /* Set parent DCB */
+        ParentDcb = RelatedDcb;
+
+        DPRINT1("Opening file '%wZ' relatively to '%wZ'\n", &FileName, &ParentDcb->FullFileName);
+    }
+    else
+    {
+        /* Absolute open */
+        if ((FileName.Length == sizeof(WCHAR)) &&
+            (FileName.Buffer[0] == L'\\'))
+        {
+            /* Check if it's ok to open it */
+            if (NonDirectoryFile)
+            {
+                DPRINT1("Trying to open root dir as a file\n");
+
+                /* Cleanup and return */
+                FatReleaseVcb(IrpContext, Vcb);
+                return STATUS_FILE_IS_A_DIRECTORY;
+            }
+
+            /* Check delete on close on a root dir */
+            if (DeleteOnClose)
+            {
+                /* Cleanup and return */
+                FatReleaseVcb(IrpContext, Vcb);
+                return STATUS_CANNOT_DELETE;
+            }
+
+            /* Call root directory open routine */
+            Iosb = FatiOpenRootDcb(IrpContext,
+                                   FileObject,
+                                   Vcb,
+                                   DesiredAccess,
+                                   ShareAccess,
+                                   CreateDisposition);
+
+            Irp->IoStatus.Information = Iosb.Information;
+
+            /* Cleanup and return */
+            FatReleaseVcb(IrpContext, Vcb);
+            return Iosb.Status;
+        }
+        else
+        {
+            /* Not a root dir */
+            ParentDcb = Vcb->RootDcb;
+            DPRINT("ParentDcb %p\n", ParentDcb);
+        }
+    }
+
+    /* Check for backslash at the end */
+    if (FileName.Length &&
+        FileName.Buffer[FileName.Length / sizeof(WCHAR) - 1] == L'\\')
+    {
+        /* Cut it out */
+        FileName.Length -= sizeof(WCHAR);
+
+        /* Remember we cut it */
+        EndBackslash = TRUE;
+    }
+
+    /* Ensure the name is set */
+    if (!ParentDcb->FullFileName.Buffer)
+    {
+        /* Set it if it's missing */
+        FatSetFullFileNameInFcb(IrpContext, ParentDcb);
+    }
+
+    /* Check max path length */
+    if (ParentDcb->FullFileName.Length + FileName.Length + sizeof(WCHAR) <= FileName.Length)
+    {
+        DPRINT1("Max length is way off\n");
+        Iosb.Status = STATUS_OBJECT_NAME_INVALID;
+        ASSERT(FALSE);
+    }
+
+    /* Loop through FCBs to find a good one */
+    while (TRUE)
+    {
+        Fcb = ParentDcb;
+
+        /* Dissect the name */
+        RemainingPart = FileName;
+        while (RemainingPart.Length)
+        {
+            FsRtlDissectName(RemainingPart, &FirstName, &NextName);
+
+            /* Check for validity */
+            if ((NextName.Length && NextName.Buffer[0] == L'\\') ||
+                (NextName.Length > 255 * sizeof(WCHAR)))
+            {
+                /* The name is invalid */
+                DPRINT1("Invalid name found\n");
+                Iosb.Status = STATUS_OBJECT_NAME_INVALID;
+                ASSERT(FALSE);
+            }
+
+            /* Convert the name to ANSI */
+            AnsiFirstName.Buffer = ExAllocatePool(PagedPool, FirstName.Length);
+            AnsiFirstName.Length = 0;
+            AnsiFirstName.MaximumLength = FirstName.Length;
+            Status = RtlUpcaseUnicodeStringToCountedOemString(&AnsiFirstName, &FirstName, FALSE);
+
+            if (!NT_SUCCESS(Status))
+            {
+                DPRINT1("RtlUpcaseUnicodeStringToCountedOemString() failed with 0x%08x\n", Status);
+                ASSERT(FALSE);
+                NextFcb = NULL;
+                AnsiFirstName.Length = 0;
+            }
+            else
+            {
+                /* Find the coresponding FCB */
+                NextFcb = FatFindFcb(IrpContext,
+                                     &Fcb->Dcb.SplayLinksAnsi,
+                                     (PSTRING)&AnsiFirstName,
+                                     &OpenedAsDos);
+            }
+
+            /* If nothing found - try with unicode */
+            if (!NextFcb && Fcb->Dcb.SplayLinksUnicode)
+            {
+                FileNameUpcased.Buffer = FsRtlAllocatePool(PagedPool, FirstName.Length);
+                FileNameUpcased.Length = 0;
+                FileNameUpcased.MaximumLength = FirstName.Length;
+
+                /* Downcase and then upcase to normalize it */
+                Status = RtlDowncaseUnicodeString(&FileNameUpcased, &FirstName, FALSE);
+                Status = RtlUpcaseUnicodeString(&FileNameUpcased, &FileNameUpcased, FALSE);
+
+                /* Try to find FCB again using unicode name */
+                NextFcb = FatFindFcb(IrpContext,
+                                     &Fcb->Dcb.SplayLinksUnicode,
+                                     (PSTRING)&FileNameUpcased,
+                                     &OpenedAsDos);
+            }
+
+            /* Move to the next FCB */
+            if (NextFcb)
+            {
+                Fcb = NextFcb;
+                RemainingPart = NextName;
+            }
+
+            /* Break out of this loop if nothing can be found */
+            if (!NextFcb ||
+                NextName.Length == 0 ||
+                FatNodeType(NextFcb) == FAT_NTC_FCB)
+            {
+                break;
+            }
+        }
+
+        /* Ensure remaining name doesn't start from a backslash */
+        if (RemainingPart.Length &&
+            RemainingPart.Buffer[0] == L'\\')
+        {
+            /* Cut it */
+            RemainingPart.Buffer++;
+            RemainingPart.Length -= sizeof(WCHAR);
+        }
+
+        if (Fcb->Condition == FcbGood)
+        {
+            /* Good FCB, break out of the loop */
+            break;
+        }
+        else
+        {
+            ASSERT(FALSE);
+        }
+    }
+
+    /* We have a valid FCB now */
+    if (!RemainingPart.Length)
+    {
+        /* Check for target dir open */
+        if (OpenTargetDirectory)
+        {
+            DPRINT1("Opening target dir is missing\n");
+            ASSERT(FALSE);
+        }
+
+        /* Check this FCB's type */
+        if (FatNodeType(Fcb) == FAT_NTC_ROOT_DCB ||
+            FatNodeType(Fcb) == FAT_NTC_DCB)
+        {
+            /* Open a directory */
+            if (NonDirectoryFile)
+            {
+                /* Forbidden */
+                Iosb.Status = STATUS_FILE_IS_A_DIRECTORY;
+                ASSERT(FALSE);
+                return Iosb.Status;
+            }
+
+            /* Open existing DCB */
+            Iosb = FatiOpenExistingDcb(IrpContext,
+                                       FileObject,
+                                       Vcb,
+                                       Fcb,
+                                       DesiredAccess,
+                                       ShareAccess,
+                                       CreateDisposition,
+                                       NoEaKnowledge,
+                                       DeleteOnClose);
+
+            /* Save information */
+            Irp->IoStatus.Information = Iosb.Information;
+
+            /* Unlock VCB */
+            FatReleaseVcb(IrpContext, Vcb);
+
+            /* Complete the request */
+            FatCompleteRequest(IrpContext, Irp, Iosb.Status);
+
+            return Iosb.Status;
+        }
+        else if (FatNodeType(Fcb) == FAT_NTC_FCB)
+        {
+            /* Open a file */
+            if (OpenDirectory)
+            {
+                /* Forbidden */
+                Iosb.Status = STATUS_NOT_A_DIRECTORY;
+                ASSERT(FALSE);
+                return Iosb.Status;
+            }
+
+            /* Check for trailing backslash */
+            if (EndBackslash)
+            {
+                /* Forbidden */
+                Iosb.Status = STATUS_OBJECT_NAME_INVALID;
+                ASSERT(FALSE);
+                return Iosb.Status;
+            }
+
+            Iosb = FatiOpenExistingFcb(IrpContext,
+                                       FileObject,
+                                       Vcb,
+                                       Fcb,
+                                       DesiredAccess,
+                                       ShareAccess,
+                                       AllocationSize,
+                                       EaBuffer,
+                                       EaLength,
+                                       FileAttributes,
+                                       CreateDisposition,
+                                       NoEaKnowledge,
+                                       DeleteOnClose,
+                                       OpenedAsDos,
+                                       &OplockPostIrp);
+
+            /* Check if it's pending */
+            if (Iosb.Status != STATUS_PENDING)
+            {
+                /* In case of success set cache supported flag */
+                if (NT_SUCCESS(Iosb.Status) && !NoIntermediateBuffering)
+                {
+                    SetFlag(FileObject->Flags, FO_CACHE_SUPPORTED);
+                }
+
+                /* Save information */
+                Irp->IoStatus.Information = Iosb.Information;
+
+                /* Unlock VCB */
+                FatReleaseVcb(IrpContext, Vcb);
+
+                /* Complete the request */
+                FatCompleteRequest(IrpContext, Irp, Iosb.Status);
+
+                return Iosb.Status;
+            }
+            else
+            {
+                /* Queue this IRP */
+                UNIMPLEMENTED;
+                ASSERT(FALSE);
+            }
+        }
+        else
+        {
+            /* Unexpected FCB type */
+            KeBugCheckEx(/*FAT_FILE_SYSTEM*/0x23, __LINE__, (ULONG_PTR)Fcb, 0, 0);
+        }
+    }
+
+    /* During parsing we encountered a part which has no attached FCB/DCB.
+    Check that the parent is really DCB and not FCB */
+    if (FatNodeType(Fcb) != FAT_NTC_ROOT_DCB &&
+        FatNodeType(Fcb) != FAT_NTC_DCB)
+    {
+        DPRINT1("Weird FCB node type %x, expected DCB or root DCB\n", FatNodeType(Fcb));
+        ASSERT(FALSE);
+    }
+
+    /* Create additional DCBs for all path items */
+    ParentDcb = Fcb;
+    while (TRUE)
+    {
+        FsRtlDissectName(RemainingPart, &FirstName, &RemainingPart);
+
+        /* Check for validity */
+        if ((RemainingPart.Length && RemainingPart.Buffer[0] == L'\\') ||
+            (NextName.Length > 255 * sizeof(WCHAR)))
+        {
+            /* The name is invalid */
+            DPRINT1("Invalid name found\n");
+            Iosb.Status = STATUS_OBJECT_NAME_INVALID;
+            ASSERT(FALSE);
+        }
+
+        /* Convert the name to ANSI */
+        AnsiFirstName.Buffer = ExAllocatePool(PagedPool, FirstName.Length);
+        AnsiFirstName.Length = 0;
+        AnsiFirstName.MaximumLength = FirstName.Length;
+        Status = RtlUpcaseUnicodeStringToCountedOemString(&AnsiFirstName, &FirstName, FALSE);
+
+        if (!NT_SUCCESS(Status))
+        {
+            ASSERT(FALSE);
+        }
+
+        DPRINT("FirstName %wZ, RemainingPart %wZ\n", &FirstName, &RemainingPart);
+
+        /* Break if came to the end */
+        if (!RemainingPart.Length) break;
+
+        /* Create a DCB for this entry */
+        ParentDcb = FatCreateDcb(IrpContext,
+                                 Vcb,
+                                 ParentDcb,
+                                 NULL);
+
+        /* Set its name */
+        FatSetFullNameInFcb(ParentDcb, &FirstName);
+    }
+
+    /* Try to open it and get a result, saying if this is a dir or a file */
+    FfError = FatiTryToOpen(FileObject, Vcb);
+
+    /* Check if we need to open target directory */
+    if (OpenTargetDirectory)
+    {
+        // TODO: Open target directory
+        UNIMPLEMENTED;
+    }
+
+    /* Check, if path is a directory or a file */
+    if (FfError == FF_ERR_FILE_OBJECT_IS_A_DIR)
+    {
+        if (NonDirectoryFile)
+        {
+            DPRINT1("Can't open dir as a file\n");
+
+            /* Unlock VCB */
+            FatReleaseVcb(IrpContext, Vcb);
+
+            /* Complete the request */
+            Iosb.Status = STATUS_FILE_IS_A_DIRECTORY;
+            FatCompleteRequest(IrpContext, Irp, Iosb.Status);
+            return Iosb.Status;
+        }
+
+        /* Open this directory */
+        Iosb = FatiOpenExistingDir(IrpContext,
+                                   FileObject,
+                                   Vcb,
+                                   ParentDcb,
+                                   DesiredAccess,
+                                   ShareAccess,
+                                   AllocationSize,
+                                   EaBuffer,
+                                   EaLength,
+                                   FileAttributes,
+                                   CreateDisposition,
+                                   DeleteOnClose);
+
+        Irp->IoStatus.Information = Iosb.Information;
+
+        /* Unlock VCB */
+        FatReleaseVcb(IrpContext, Vcb);
+
+        /* Complete the request */
+        FatCompleteRequest(IrpContext, Irp, Iosb.Status);
+
+        return Iosb.Status;
+    }
+
+    /* If end backslash here, then it's definately not permitted,
+    since we're opening files here */
+    if (EndBackslash)
+    {
+        /* Unlock VCB */
+        FatReleaseVcb(IrpContext, Vcb);
+
+        /* Complete the request */
+        Iosb.Status = STATUS_OBJECT_NAME_INVALID;
+        FatCompleteRequest(IrpContext, Irp, Iosb.Status);
+        return Iosb.Status;
+    }
+
+    /* Try to open the file */
+    Iosb = FatiOpenExistingFile(IrpContext,
+                                FileObject,
+                                Vcb,
+                                ParentDcb,
+                                DesiredAccess,
+                                ShareAccess,
+                                AllocationSize,
+                                EaBuffer,
+                                EaLength,
+                                FileAttributes,
+                                CreateDisposition,
+                                FALSE,
+                                DeleteOnClose,
+                                OpenedAsDos);
+
+    Irp->IoStatus.Information = Iosb.Information;
+
+    /* Unlock VCB */
+    FatReleaseVcb(IrpContext, Vcb);
+
+    /* Complete the request */
+    FatCompleteRequest(IrpContext, Irp, Iosb.Status);
+
+    return Iosb.Status;
+}
 
 NTSTATUS
-VfatCreate (PVFAT_IRP_CONTEXT IrpContext)
-/*
- * FUNCTION: Create or open a file
- */
+NTAPI
+FatCreate(PDEVICE_OBJECT DeviceObject, PIRP Irp)
 {
-       NTSTATUS Status;
-
-       ASSERT(IrpContext);
-
-       if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject)
-       {
-               /* DeviceObject represents FileSystem instead of logical volume */
-               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);
-       }
-
-       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,
-               (CCHAR)(NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT));
-       VfatFreeIrpContext(IrpContext);
-       return(Status);
+    PFAT_IRP_CONTEXT IrpContext;
+    NTSTATUS Status;
+
+    /* If it's called with our Disk FS device object - it's always open */
+    // TODO: Add check for CDROM FS device object
+    if (DeviceObject == FatGlobalData.DiskDeviceObject)
+    {
+        /* Complete the request and return success */
+        Irp->IoStatus.Status = STATUS_SUCCESS;
+        Irp->IoStatus.Information = FILE_OPENED;
+
+        IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+
+        return STATUS_SUCCESS;
+    }
+
+    /* Enter FsRtl critical region */
+    FsRtlEnterFileSystem();
+
+    /* Build an irp context */
+    IrpContext = FatBuildIrpContext(Irp, TRUE);
+
+    /* Call internal function */
+    Status = FatiCreate(IrpContext, Irp);
+
+    /* Leave FsRtl critical region */
+    FsRtlExitFileSystem();
+
+    return Status;
 }
 
 /* EOF */