[FASTFAT_NEW]
[reactos.git] / reactos / drivers / filesystems / fastfat_new / create.c
index db9a794..de84dc9 100644 (file)
@@ -72,7 +72,9 @@ FatiOpenRootDcb(IN PFAT_IRP_CONTEXT IrpContext,
 
         /* Increment counters */
         Dcb->OpenCount++;
+        Dcb->UncleanCount++;
         Vcb->OpenFileCount++;
+        if (IsFileObjectReadOnly(FileObject)) Vcb->ReadOnlyCount++;
 
         /* Set success statuses */
         Iosb.Status = STATUS_SUCCESS;
@@ -186,7 +188,7 @@ FatiOverwriteFile(PFAT_IRP_CONTEXT IrpContext,
         CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize);
 
         // TODO: Actually truncate the file
-        DPRINT1("TODO: Actually truncate the file with a fullfat handle %x\n", Fcb->FatHandle);
+        DPRINT1("TODO: Actually truncate file '%wZ' with a fullfat handle %x\n", &Fcb->FullFileName, Fcb->FatHandle);
 
         /* Release the paging resource */
         ExReleaseResourceLite(Fcb->Header.PagingIoResource);
@@ -288,6 +290,12 @@ FatiOpenExistingDir(IN PFAT_IRP_CONTEXT IrpContext,
                      Fcb,
                      FatCreateCcb());
 
+    /* Increase counters */
+    Fcb->UncleanCount++;
+    Fcb->OpenCount++;
+    Vcb->OpenFileCount++;
+    if (IsFileObjectReadOnly(FileObject)) Vcb->ReadOnlyCount++;
+
     Iosb.Status = STATUS_SUCCESS;
     Iosb.Information = FILE_OPENED;
 
@@ -319,6 +327,7 @@ FatiOpenExistingFile(IN PFAT_IRP_CONTEXT IrpContext,
     PFCB Fcb;
     NTSTATUS Status;
     FF_FILE *FileHandle;
+    FF_ERROR FfError;
 
     /* Check for create file option and fail */
     if (CreateDisposition == FILE_CREATE)
@@ -341,20 +350,22 @@ FatiOpenExistingFile(IN PFAT_IRP_CONTEXT IrpContext,
     }
 
     /* Open the file with FullFAT */
-    FileHandle = FF_Open(Vcb->Ioman, AnsiName.Buffer, FF_MODE_READ, NULL);
+    FileHandle = FF_Open(Vcb->Ioman, AnsiName.Buffer, FF_MODE_READ, &FfError);
 
     if (!FileHandle)
     {
+        DPRINT1("Failed to open file '%s', error %ld\n", AnsiName.Buffer, FfError);
         Iosb.Status = STATUS_OBJECT_NAME_NOT_FOUND; // FIXME: A shortcut for now
         return Iosb;
     }
+    DPRINT1("Succeeded opening file '%s'\n", AnsiName.Buffer);
 
     /* 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!
+    // TODO: This is usual file open branch, without overwriting!
     /* Set context and section object pointers */
     FatSetFileObject(FileObject,
                      UserFileOpen,
@@ -365,6 +376,13 @@ FatiOpenExistingFile(IN PFAT_IRP_CONTEXT IrpContext,
     Iosb.Status = STATUS_SUCCESS;
     Iosb.Information = FILE_OPENED;
 
+
+    /* Increase counters */
+    Fcb->UncleanCount++;
+    Fcb->OpenCount++;
+    if (FlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING)) Fcb->NonCachedUncleanCount++;
+    if (IsFileObjectReadOnly(FileObject)) Vcb->ReadOnlyCount++;
+
     return Iosb;
 }
 
@@ -397,7 +415,7 @@ FatiOpenVolume(IN PFAT_IRP_CONTEXT IrpContext,
         // and opened handles count is not 0
         //if (!FlagOn(ShareAccess, FILE_SHARE_READ)
 
-        DPRINT1("Exclusive voume open\n");
+        DPRINT1("Exclusive volume open\n");
 
         // TODO: Flush the volume
         VolumeFlushed = TRUE;
@@ -450,6 +468,7 @@ FatiOpenVolume(IN PFAT_IRP_CONTEXT IrpContext,
     /* Increase direct open count */
     Vcb->DirectOpenCount++;
     Vcb->OpenFileCount++;
+    if (IsFileObjectReadOnly(FileObject)) Vcb->ReadOnlyCount++;
 
     /* Set no buffering flag */
     FileObject->Flags |= FO_NO_INTERMEDIATE_BUFFERING;
@@ -503,7 +522,7 @@ FatiCreate(IN PFAT_IRP_CONTEXT IrpContext,
     NTSTATUS Status;
     IO_STATUS_BLOCK Iosb;
     PIO_STACK_LOCATION IrpSp;
-    BOOLEAN EndBackslash = FALSE, OpenedAsDos;
+    BOOLEAN EndBackslash = FALSE, OpenedAsDos, FirstRun = TRUE;
     UNICODE_STRING RemainingPart, FirstName, NextName, FileNameUpcased;
     OEM_STRING AnsiFirstName;
     FF_ERROR FfError;
@@ -573,6 +592,13 @@ FatiCreate(IN PFAT_IRP_CONTEXT IrpContext,
     if (RelatedFO)
         FileObject->Vpb = RelatedFO->Vpb;
 
+    /* Reject open by id */
+    if (Options & FILE_OPEN_BY_FILE_ID)
+    {
+        FatCompleteRequest(IrpContext, Irp, STATUS_INVALID_PARAMETER);
+        return STATUS_INVALID_PARAMETER;
+    }
+
     /* Prepare file attributes mask */
     FileAttributes &= (FILE_ATTRIBUTE_READONLY |
                        FILE_ATTRIBUTE_HIDDEN   |
@@ -633,12 +659,22 @@ FatiCreate(IN PFAT_IRP_CONTEXT IrpContext,
         DPRINT1("This volume is locked\n");
         Status = STATUS_ACCESS_DENIED;
 
+        /* Set volume dismount status */
+        if (Vcb->Condition != VcbGood)
+            Status = STATUS_VOLUME_DISMOUNTED;
+
         /* Cleanup and return */
         FatReleaseVcb(IrpContext, Vcb);
+        FatCompleteRequest(IrpContext, Irp, Status);
         return Status;
     }
 
-    // TODO: Check if the volume is write protected and disallow DELETE_ON_CLOSE
+    /* Check if the volume is write protected and disallow DELETE_ON_CLOSE */
+    if (DeleteOnClose & FlagOn(Vcb->State, VCB_STATE_FLAG_WRITE_PROTECTED))
+    {
+        ASSERT(FALSE);
+        return STATUS_NOT_IMPLEMENTED;
+    }
 
     // TODO: Make sure EAs aren't supported on FAT32
 
@@ -697,18 +733,24 @@ FatiCreate(IN PFAT_IRP_CONTEXT IrpContext,
         {
             DPRINT1("Invalid file object!\n");
 
+            Status = STATUS_OBJECT_PATH_NOT_FOUND;
+
             /* Cleanup and return */
             FatReleaseVcb(IrpContext, Vcb);
-            return STATUS_OBJECT_PATH_NOT_FOUND;
+            FatCompleteRequest(IrpContext, Irp, Status);
+            return Status;
         }
 
         /* File path must be relative */
         if (FileName.Length != 0 &&
             FileName.Buffer[0] == L'\\')
         {
+            Status = STATUS_OBJECT_NAME_INVALID;
+
             /* The name is absolute, fail */
             FatReleaseVcb(IrpContext, Vcb);
-            return STATUS_OBJECT_NAME_INVALID;
+            FatCompleteRequest(IrpContext, Irp, Status);
+            return Status;
         }
 
         /* Make sure volume is the same */
@@ -720,7 +762,7 @@ FatiCreate(IN PFAT_IRP_CONTEXT IrpContext,
         /* Set parent DCB */
         ParentDcb = RelatedDcb;
 
-        DPRINT1("Opening file '%wZ' relatively to '%wZ'\n", &FileName, &ParentDcb->FullFileName);
+        DPRINT("Opening file '%wZ' relatively to '%wZ'\n", &FileName, &ParentDcb->FullFileName);
     }
     else
     {
@@ -732,18 +774,34 @@ FatiCreate(IN PFAT_IRP_CONTEXT IrpContext,
             if (NonDirectoryFile)
             {
                 DPRINT1("Trying to open root dir as a file\n");
+                Status = STATUS_FILE_IS_A_DIRECTORY;
+
+                /* Cleanup and return */
+                FatReleaseVcb(IrpContext, Vcb);
+                FatCompleteRequest(IrpContext, Irp, Status);
+                return Status;
+            }
+
+            /* Check for target directory on a root dir */
+            if (OpenTargetDirectory)
+            {
+                Status = STATUS_INVALID_PARAMETER;
 
                 /* Cleanup and return */
                 FatReleaseVcb(IrpContext, Vcb);
-                return STATUS_FILE_IS_A_DIRECTORY;
+                FatCompleteRequest(IrpContext, Irp, Status);
+                return Status;
             }
 
             /* Check delete on close on a root dir */
             if (DeleteOnClose)
             {
+                Status = STATUS_CANNOT_DELETE;
+
                 /* Cleanup and return */
                 FatReleaseVcb(IrpContext, Vcb);
-                return STATUS_CANNOT_DELETE;
+                FatCompleteRequest(IrpContext, Irp, Status);
+                return Status;
             }
 
             /* Call root directory open routine */
@@ -758,6 +816,7 @@ FatiCreate(IN PFAT_IRP_CONTEXT IrpContext,
 
             /* Cleanup and return */
             FatReleaseVcb(IrpContext, Vcb);
+            FatCompleteRequest(IrpContext, Irp, Iosb.Status);
             return Iosb.Status;
         }
         else
@@ -891,6 +950,27 @@ FatiCreate(IN PFAT_IRP_CONTEXT IrpContext,
         }
     }
 
+    /* Treat page file in a special way */
+    if (IsPagingFile)
+    {
+        UNIMPLEMENTED;
+        // FIXME: System file too
+    }
+
+    /* Make sure there is no pending delete on a higher-level FCB */
+    if (Fcb->State & FCB_STATE_DELETE_ON_CLOSE)
+    {
+        Iosb.Status = STATUS_DELETE_PENDING;
+
+        /* Cleanup and return */
+        FatReleaseVcb(IrpContext, Vcb);
+
+        /* Complete the request */
+        FatCompleteRequest(IrpContext, Irp, Iosb.Status);
+
+        return Iosb.Status;
+    }
+
     /* We have a valid FCB now */
     if (!RemainingPart.Length)
     {
@@ -1019,23 +1099,34 @@ FatiCreate(IN PFAT_IRP_CONTEXT IrpContext,
     ParentDcb = Fcb;
     while (TRUE)
     {
-        FsRtlDissectName(RemainingPart, &FirstName, &RemainingPart);
-
-        /* Check for validity */
-        if ((RemainingPart.Length && RemainingPart.Buffer[0] == L'\\') ||
-            (NextName.Length > 255 * sizeof(WCHAR)))
+        if (FirstRun)
         {
-            /* The name is invalid */
-            DPRINT1("Invalid name found\n");
-            Iosb.Status = STATUS_OBJECT_NAME_INVALID;
-            ASSERT(FALSE);
+            RemainingPart = NextName;
+            if (AnsiFirstName.Length)
+                Status = STATUS_SUCCESS;
+            else
+                Status = STATUS_UNMAPPABLE_CHARACTER;
         }
+        else
+        {
+            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);
+            /* 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))
         {
@@ -1068,84 +1159,114 @@ FatiCreate(IN PFAT_IRP_CONTEXT IrpContext,
     }
 
     /* Check, if path is a directory or a file */
-    if (FfError == FF_ERR_FILE_OBJECT_IS_A_DIR)
+    if (FfError == FF_ERR_FILE_OBJECT_IS_A_DIR ||
+        FfError == FF_ERR_NONE)
     {
-        if (NonDirectoryFile)
+        if (FfError == FF_ERR_FILE_OBJECT_IS_A_DIR)
         {
-            DPRINT1("Can't open dir as a file\n");
+            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 */
-            Iosb.Status = STATUS_FILE_IS_A_DIRECTORY;
             FatCompleteRequest(IrpContext, Irp, Iosb.Status);
+
             return Iosb.Status;
         }
+        else
+        {
+            /* This is opening an existing file */
+            if (OpenDirectory)
+            {
+                /* But caller wanted a dir */
+                Status = STATUS_NOT_A_DIRECTORY;
 
-        /* Open this directory */
-        Iosb = FatiOpenExistingDir(IrpContext,
-                                   FileObject,
-                                   Vcb,
-                                   ParentDcb,
-                                   DesiredAccess,
-                                   ShareAccess,
-                                   AllocationSize,
-                                   EaBuffer,
-                                   EaLength,
-                                   FileAttributes,
-                                   CreateDisposition,
-                                   DeleteOnClose);
+                /* Unlock VCB */
+                FatReleaseVcb(IrpContext, Vcb);
 
-        Irp->IoStatus.Information = Iosb.Information;
+                /* Complete the request */
+                FatCompleteRequest(IrpContext, Irp, Status);
 
-        /* Unlock VCB */
-        FatReleaseVcb(IrpContext, Vcb);
+                return Status;
+            }
 
-        /* Complete the request */
-        FatCompleteRequest(IrpContext, Irp, 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);
 
-        return Iosb.Status;
-    }
+                /* Complete the request */
+                Iosb.Status = STATUS_OBJECT_NAME_INVALID;
+                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);
+            /* Try to open the file */
+            Iosb = FatiOpenExistingFile(IrpContext,
+                                        FileObject,
+                                        Vcb,
+                                        ParentDcb,
+                                        DesiredAccess,
+                                        ShareAccess,
+                                        AllocationSize,
+                                        EaBuffer,
+                                        EaLength,
+                                        FileAttributes,
+                                        CreateDisposition,
+                                        FALSE,
+                                        DeleteOnClose,
+                                        OpenedAsDos);
+
+            /* In case of success set cache supported flag */
+            if (NT_SUCCESS(Iosb.Status) && !NoIntermediateBuffering)
+            {
+                SetFlag(FileObject->Flags, FO_CACHE_SUPPORTED);
+            }
 
-        /* Complete the request */
-        Iosb.Status = STATUS_OBJECT_NAME_INVALID;
-        FatCompleteRequest(IrpContext, Irp, Iosb.Status);
-        return Iosb.Status;
+            Irp->IoStatus.Information = Iosb.Information;
+
+            /* Unlock VCB */
+            FatReleaseVcb(IrpContext, Vcb);
+
+            /* Complete the request */
+            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;
+    /* We come here only in the case when a new file is created */
+    ASSERT(FALSE);
 }
 
 NTSTATUS