[fastfat_new]
[reactos.git] / reactos / drivers / filesystems / fastfat_new / create.c
index 0aec637..61cb5bf 100644 (file)
@@ -41,6 +41,110 @@ FatiOpenRootDcb(IN PFAT_IRP_CONTEXT IrpContext,
     return Iosb;
 }
 
+FF_ERROR
+NTAPI
+FatiTryToOpen(IN PFILE_OBJECT FileObject,
+              IN PVCB Vcb)
+{
+    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;
+}
+
+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)
+{
+    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;
+}
+
 IO_STATUS_BLOCK
 NTAPI
 FatiOpenExistingFile(IN PFAT_IRP_CONTEXT IrpContext,
@@ -63,6 +167,7 @@ FatiOpenExistingFile(IN PFAT_IRP_CONTEXT IrpContext,
     CHAR AnsiNameBuf[512];
     PFCB Fcb;
     NTSTATUS Status;
+    FF_FILE *FileHandle;
 
     /* Check for create file option and fail */
     if (CreateDisposition == FILE_CREATE)
@@ -73,9 +178,6 @@ FatiOpenExistingFile(IN PFAT_IRP_CONTEXT IrpContext,
 
     // TODO: Check more params
 
-    /* Create a new FCB for this file */
-    Fcb = FatCreateFcb(IrpContext, Vcb, ParentDcb);
-
     /* Convert the name to ANSI */
     AnsiName.Buffer = AnsiNameBuf;
     AnsiName.Length = 0;
@@ -88,7 +190,16 @@ FatiOpenExistingFile(IN PFAT_IRP_CONTEXT IrpContext,
     }
 
     /* Open the file with FullFAT */
-    Fcb->FatHandle = FF_Open(Vcb->Ioman, AnsiName.Buffer, FF_MODE_READ, NULL);
+    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
 
@@ -106,6 +217,100 @@ FatiOpenExistingFile(IN PFAT_IRP_CONTEXT IrpContext,
     return Iosb;
 }
 
+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)
+{
+    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))
+        {
+            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;
+}
+
 NTSTATUS
 NTAPI
 FatiCreate(IN PFAT_IRP_CONTEXT IrpContext,
@@ -126,9 +331,9 @@ FatiCreate(IN PFAT_IRP_CONTEXT IrpContext,
     ULONG CreateDisposition;
 
     /* Control blocks */
-    PVCB Vcb, DecodedVcb;
-    PFCB Fcb, NextFcb;
-    PCCB Ccb;
+    PVCB Vcb, DecodedVcb, RelatedVcb;
+    PFCB Fcb, NextFcb, RelatedDcb;
+    PCCB Ccb, RelatedCcb;
     PFCB ParentDcb;
 
     /* IRP data */
@@ -150,26 +355,28 @@ FatiCreate(IN PFAT_IRP_CONTEXT IrpContext,
     BOOLEAN EndBackslash = FALSE, OpenedAsDos;
     UNICODE_STRING RemainingPart, FirstName, NextName;
     OEM_STRING AnsiFirstName;
+    FF_ERROR FfError;
+    TYPE_OF_OPEN TypeOfOpen;
 
     Iosb.Status = STATUS_SUCCESS;
 
     /* Get current IRP stack location */
     IrpSp = IoGetCurrentIrpStackLocation(Irp);
 
-    DPRINT1("FatCommonCreate\n", 0 );
-    DPRINT1("Irp                       = %08lx\n",   Irp );
-    DPRINT1("\t->Flags                   = %08lx\n", Irp->Flags );
-    DPRINT1("\t->FileObject              = %08lx\n", IrpSp->FileObject );
-    DPRINT1("\t->RelatedFileObject       = %08lx\n", IrpSp->FileObject->RelatedFileObject );
-    DPRINT1("\t->FileName                = %wZ\n",   &IrpSp->FileObject->FileName );
-    DPRINT1("\t->AllocationSize.LowPart  = %08lx\n", Irp->Overlay.AllocationSize.LowPart );
-    DPRINT1("\t->AllocationSize.HighPart = %08lx\n", Irp->Overlay.AllocationSize.HighPart );
-    DPRINT1("\t->SystemBuffer            = %08lx\n", Irp->AssociatedIrp.SystemBuffer );
-    DPRINT1("\t->DesiredAccess           = %08lx\n", IrpSp->Parameters.Create.SecurityContext->DesiredAccess );
-    DPRINT1("\t->Options                 = %08lx\n", IrpSp->Parameters.Create.Options );
-    DPRINT1("\t->FileAttributes          = %04x\n",  IrpSp->Parameters.Create.FileAttributes );
-    DPRINT1("\t->ShareAccess             = %04x\n",  IrpSp->Parameters.Create.ShareAccess );
-    DPRINT1("\t->EaLength                = %08lx\n", IrpSp->Parameters.Create.EaLength );
+    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)) &&
@@ -290,17 +497,78 @@ FatiCreate(IN PFAT_IRP_CONTEXT IrpContext,
         if (!RelatedFO ||
             FatDecodeFileObject(RelatedFO, &DecodedVcb, &Fcb, &Ccb) == UserVolumeOpen)
         {
+            /* 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 */
-            DPRINT1("Volume open request, not implemented now!\n");
-            UNIMPLEMENTED;
+            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;
         }
     }
 
     /* Check if this is a relative open */
     if (RelatedFO)
     {
-        // RelatedFO will be a parent directory
-        UNIMPLEMENTED;
+        /* Decode the file object */
+        TypeOfOpen = FatDecodeFileObject(RelatedFO,
+                                         &RelatedVcb,
+                                         &RelatedDcb,
+                                         &RelatedCcb);
+
+        /* Check open type */
+        if (TypeOfOpen != UserFileOpen &&
+            TypeOfOpen != UserDirectoryOpen)
+        {
+            DPRINT1("Invalid file object!\n");
+
+            /* Cleanup and return */
+            FatReleaseVcb(IrpContext, Vcb);
+            return STATUS_OBJECT_PATH_NOT_FOUND;
+        }
+
+        /* File path must be relative */
+        if (FileName.Length != 0 &&
+            FileName.Buffer[0] == L'\\')
+        {
+            /* The name is absolute, fail */
+            FatReleaseVcb(IrpContext, Vcb);
+            return STATUS_OBJECT_NAME_INVALID;
+        }
+
+        /* 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
     {
@@ -344,7 +612,7 @@ FatiCreate(IN PFAT_IRP_CONTEXT IrpContext,
         {
             /* Not a root dir */
             ParentDcb = Vcb->RootDcb;
-            DPRINT1("ParentDcb %p\n", ParentDcb);
+            DPRINT("ParentDcb %p\n", ParentDcb);
         }
 
         /* Check for backslash at the end */
@@ -361,7 +629,8 @@ FatiCreate(IN PFAT_IRP_CONTEXT IrpContext,
         /* Ensure the name is set */
         if (!ParentDcb->FullFileName.Buffer)
         {
-            DPRINT1("ParentDcb->FullFileName.Buffer is NULL\n");
+            /* Set it if it's missing */
+            FatSetFullFileNameInFcb(IrpContext, ParentDcb);
         }
 
         /* Check max path length */
@@ -500,20 +769,79 @@ FatiCreate(IN PFAT_IRP_CONTEXT IrpContext,
                 ASSERT(FALSE);
             }
 
-            DPRINT1("FirstName %wZ, RemainingPart %wZ\n", &FirstName, &RemainingPart);
+            DPRINT("FirstName %wZ, RemainingPart %wZ\n", &FirstName, &RemainingPart);
 
             /* Break if came to the end */
             if (!RemainingPart.Length) break;
 
-            // TODO: Create a DCB for this entry
+            /* Create a DCB for this entry */
+            ParentDcb = FatCreateDcb(IrpContext,
+                                     Vcb,
+                                     ParentDcb,
+                                     NULL);
+
+            /* Set its name */
+            FatSetFullNameInFcb(ParentDcb, &FirstName);
         }
 
-        // TODO: Try to open directory
+        /* 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);
@@ -539,6 +867,9 @@ FatiCreate(IN PFAT_IRP_CONTEXT IrpContext,
         Irp->IoStatus.Information = Iosb.Information;
     }
 
+    /* Unlock VCB */
+    FatReleaseVcb(IrpContext, Vcb);
+
     /* Complete the request */
     FatCompleteRequest(IrpContext, Irp, Iosb.Status);
 
@@ -551,9 +882,6 @@ FatCreate(PDEVICE_OBJECT DeviceObject, PIRP Irp)
 {
     PFAT_IRP_CONTEXT IrpContext;
     NTSTATUS Status;
-    //PVOLUME_DEVICE_OBJECT VolumeDO = (PVOLUME_DEVICE_OBJECT)DeviceObject;
-
-    DPRINT1("FatCreate()\n");
 
     /* If it's called with our Disk FS device object - it's always open */
     // TODO: Add check for CDROM FS device object