[FASTFAT]
[reactos.git] / reactos / drivers / filesystems / fastfat / create.c
index 154bd30..05069df 100644 (file)
  */
 /*
  * PROJECT:          ReactOS kernel
- * FILE:             drivers/fs/vfat/create.c
+ * FILE:             drivers/filesystems/fastfat/create.c
  * PURPOSE:          VFAT Filesystem
  * PROGRAMMER:       Jason Filby (jasonfilby@yahoo.com)
+ *                   Pierre Schweitzer (pierre@reactos.org)
  */
 
 /* INCLUDES *****************************************************************/
@@ -352,7 +353,6 @@ VfatOpenFile(
     PUNICODE_STRING PathNameU,
     PFILE_OBJECT FileObject,
     ULONG RequestedDisposition,
-    BOOLEAN OpenTargetDir,
     PVFATFCB *ParentFcb)
 {
     PVFATFCB Fcb;
@@ -365,7 +365,6 @@ VfatOpenFile(
         DPRINT("'%wZ'\n", &FileObject->RelatedFileObject->FileName);
 
         *ParentFcb = FileObject->RelatedFileObject->FsContext;
-        (*ParentFcb)->RefCount++;
     }
     else
     {
@@ -391,7 +390,7 @@ VfatOpenFile(
 
     if (*ParentFcb)
     {
-        (*ParentFcb)->RefCount++;
+        vfatGrabFCB(DeviceExt, *ParentFcb);
     }
 
     /*  try first to find an existing FCB in memory  */
@@ -404,13 +403,6 @@ VfatOpenFile(
         return  Status;
     }
 
-    /* In case we're to open target, just check whether file exist, but don't open it */
-    if (OpenTargetDir)
-    {
-        vfatReleaseFCB(DeviceExt, Fcb);
-        return STATUS_OBJECT_NAME_COLLISION;
-    }
-
     if (Fcb->Flags & FCB_DELETE_PENDING)
     {
         vfatReleaseFCB(DeviceExt, Fcb);
@@ -450,9 +442,9 @@ VfatCreateFile(
     PVFATFCB pFcb = NULL;
     PVFATFCB ParentFcb = NULL;
     PWCHAR c, last;
-    BOOLEAN PagingFileCreate = FALSE;
+    BOOLEAN PagingFileCreate;
     BOOLEAN Dots;
-    BOOLEAN OpenTargetDir = FALSE;
+    BOOLEAN OpenTargetDir;
     UNICODE_STRING FileNameU;
     UNICODE_STRING PathNameU;
     ULONG Attributes;
@@ -463,6 +455,7 @@ VfatCreateFile(
     RequestedOptions = Stack->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS;
     PagingFileCreate = (Stack->Flags & SL_OPEN_PAGING_FILE) ? TRUE : FALSE;
     OpenTargetDir = (Stack->Flags & SL_OPEN_TARGET_DIRECTORY) ? TRUE : FALSE;
+
     FileObject = Stack->FileObject;
     DeviceExt = DeviceObject->DeviceExtension;
 
@@ -479,10 +472,18 @@ VfatCreateFile(
         return STATUS_INVALID_PARAMETER;
     }
 
+    /* Deny create if the volume is locked */
+    if (DeviceExt->Flags & VCB_VOLUME_LOCKED)
+    {
+        return STATUS_ACCESS_DENIED;
+    }
+
     /* This a open operation for the volume itself */
     if (FileObject->FileName.Length == 0 &&
         (FileObject->RelatedFileObject == NULL || FileObject->RelatedFileObject->FsContext2 != NULL))
     {
+        DPRINT("Volume opening\n");
+
         if (RequestedDisposition != FILE_OPEN &&
             RequestedDisposition != FILE_OPEN_IF)
         {
@@ -502,8 +503,29 @@ VfatCreateFile(
         }
 
         pFcb = DeviceExt->VolumeFcb;
+
+        if (pFcb->OpenHandleCount == 0)
+        {
+            IoSetShareAccess(Stack->Parameters.Create.SecurityContext->DesiredAccess,
+                             Stack->Parameters.Create.ShareAccess,
+                             FileObject,
+                             &pFcb->FCBShareAccess);
+        }
+        else
+        {
+            Status = IoCheckShareAccess(Stack->Parameters.Create.SecurityContext->DesiredAccess,
+                                        Stack->Parameters.Create.ShareAccess,
+                                        FileObject,
+                                        &pFcb->FCBShareAccess,
+                                        FALSE);
+            if (!NT_SUCCESS(Status))
+            {
+                return Status;
+            }
+        }
+
         vfatAttachFCBToFileObject(DeviceExt, pFcb, FileObject);
-        pFcb->RefCount++;
+        DeviceExt->OpenHandleCount++;
 
         Irp->IoStatus.Information = FILE_OPENED;
         return STATUS_SUCCESS;
@@ -554,14 +576,25 @@ VfatCreateFile(
     }
 
     /* Try opening the file. */
-    Status = VfatOpenFile(DeviceExt, &PathNameU, FileObject, RequestedDisposition, OpenTargetDir, &ParentFcb);
-
-    if (OpenTargetDir)
+    if (!OpenTargetDir)
     {
+        Status = VfatOpenFile(DeviceExt, &PathNameU, FileObject, RequestedDisposition, &ParentFcb);
+    }
+    else
+    {
+        PVFATFCB TargetFcb;
         LONG idx, FileNameLen;
 
-        if (Status == STATUS_OBJECT_NAME_COLLISION)
+        ParentFcb = (FileObject->RelatedFileObject != NULL) ? FileObject->RelatedFileObject->FsContext : NULL;
+        if (ParentFcb)
+        {
+            vfatGrabFCB(DeviceExt, ParentFcb);
+        }
+        Status = vfatGetFCBForFile(DeviceExt, &ParentFcb, &TargetFcb, &PathNameU);
+
+        if (NT_SUCCESS(Status))
         {
+            vfatReleaseFCB(DeviceExt, TargetFcb);
             Irp->IoStatus.Information = FILE_EXISTS;
         }
         else
@@ -571,7 +604,7 @@ VfatCreateFile(
 
         idx = FileObject->FileName.Length / sizeof(WCHAR) - 1;
 
-        /* Skip tailing \ - if any */
+        /* Skip trailing \ - if any */
         if (PathNameU.Buffer[idx] == L'\\')
         {
             --idx;
@@ -589,10 +622,6 @@ VfatCreateFile(
             /* We don't want to include / in the name */
             FileNameLen = PathNameU.Length - ((idx + 1) * sizeof(WCHAR));
 
-            /* Try to open parent */
-            PathNameU.Length -= (PathNameU.Length - idx * sizeof(WCHAR));
-            Status = VfatOpenFile(DeviceExt, &PathNameU, FileObject, RequestedDisposition, FALSE, &ParentFcb);
-
             /* Update FO just to keep file name */
             /* Skip first slash */
             ++idx;
@@ -604,32 +633,49 @@ VfatCreateFile(
             /* This is a relative open and we have only the filename, so open the parent directory
              * It is in RelatedFileObject
              */
-            BOOLEAN Chomp = FALSE;
-            PFILE_OBJECT RelatedFileObject = FileObject->RelatedFileObject;
+            ASSERT(FileObject->RelatedFileObject != NULL);
 
-            DPRINT("%wZ\n", &PathNameU);
+            /* No need to modify the FO, it already has the name */
+        }
 
-            ASSERT(RelatedFileObject != NULL);
+        /* We're done with opening! */
+        if (ParentFcb != NULL)
+        {
+            Status = vfatAttachFCBToFileObject(DeviceExt, ParentFcb, FileObject);
+        }
 
-            DPRINT("Relative opening\n");
-            DPRINT("FileObject->RelatedFileObject->FileName: %wZ\n", &RelatedFileObject->FileName);
+        if (NT_SUCCESS(Status))
+        {
+            pFcb = FileObject->FsContext;
+            ASSERT(pFcb == ParentFcb);
 
-            /* VfatOpenFile() doesn't like our name ends with \, so chomp it if there's one */
-            if (RelatedFileObject->FileName.Buffer[RelatedFileObject->FileName.Length / sizeof(WCHAR) - 1] == L'\\')
+            if (pFcb->OpenHandleCount == 0)
             {
-                Chomp = TRUE;
-                RelatedFileObject->FileName.Length -= sizeof(WCHAR);
+                IoSetShareAccess(Stack->Parameters.Create.SecurityContext->DesiredAccess,
+                                 Stack->Parameters.Create.ShareAccess,
+                                 FileObject,
+                                 &pFcb->FCBShareAccess);
+            }
+            else
+            {
+                Status = IoCheckShareAccess(Stack->Parameters.Create.SecurityContext->DesiredAccess,
+                                            Stack->Parameters.Create.ShareAccess,
+                                            FileObject,
+                                            &pFcb->FCBShareAccess,
+                                            FALSE);
+                if (!NT_SUCCESS(Status))
+                {
+                    VfatCloseFile(DeviceExt, FileObject);
+                    return Status;
+                }
             }
 
-            /* Tricky part - fake our FO. It's NOT relative, we want to open the complete file path */
-            FileObject->RelatedFileObject = NULL;
-            Status = VfatOpenFile(DeviceExt, &RelatedFileObject->FileName, FileObject, RequestedDisposition, FALSE, &ParentFcb);
-
-            /* We're done opening, restore what we broke */
-            FileObject->RelatedFileObject = RelatedFileObject;
-            if (Chomp) RelatedFileObject->FileName.Length += sizeof(WCHAR);
-
-            /* No need to modify the FO, it already has the name */
+            pFcb->OpenHandleCount++;
+            DeviceExt->OpenHandleCount++;
+        }
+        else if (ParentFcb != NULL)
+        {
+            vfatReleaseFCB(DeviceExt, ParentFcb);
         }
 
         return Status;
@@ -669,7 +715,7 @@ VfatCreateFile(
                 Attributes |= FILE_ATTRIBUTE_ARCHIVE;
             vfatSplitPathName(&PathNameU, NULL, &FileNameU);
             Status = VfatAddEntry(DeviceExt, &FileNameU, &pFcb, ParentFcb, RequestedOptions,
-                                  (UCHAR)(Attributes & FILE_ATTRIBUTE_VALID_FLAGS));
+                                  (UCHAR)(Attributes & FILE_ATTRIBUTE_VALID_FLAGS), NULL);
             vfatReleaseFCB(DeviceExt, ParentFcb);
             if (NT_SUCCESS(Status))
             {
@@ -871,6 +917,7 @@ VfatCreateFile(
     }
 
     pFcb->OpenHandleCount++;
+    DeviceExt->OpenHandleCount++;
 
     /* FIXME : test write access if requested */