[FASTFAT]
[reactos.git] / reactos / drivers / filesystems / fastfat / create.c
index fbd5231..0859762 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 *****************************************************************/
@@ -364,7 +365,6 @@ VfatOpenFile(
         DPRINT("'%wZ'\n", &FileObject->RelatedFileObject->FileName);
 
         *ParentFcb = FileObject->RelatedFileObject->FsContext;
-        (*ParentFcb)->RefCount++;
     }
     else
     {
@@ -390,7 +390,7 @@ VfatOpenFile(
 
     if (*ParentFcb)
     {
-        (*ParentFcb)->RefCount++;
+        vfatGrabFCB(DeviceExt, *ParentFcb);
     }
 
     /*  try first to find an existing FCB in memory  */
@@ -402,6 +402,7 @@ VfatOpenFile(
         DPRINT ("Could not make a new FCB, status: %x\n", Status);
         return  Status;
     }
+
     if (Fcb->Flags & FCB_DELETE_PENDING)
     {
         vfatReleaseFCB(DeviceExt, Fcb);
@@ -441,8 +442,9 @@ VfatCreateFile(
     PVFATFCB pFcb = NULL;
     PVFATFCB ParentFcb = NULL;
     PWCHAR c, last;
-    BOOLEAN PagingFileCreate = FALSE;
+    BOOLEAN PagingFileCreate;
     BOOLEAN Dots;
+    BOOLEAN OpenTargetDir;
     UNICODE_STRING FileNameU;
     UNICODE_STRING PathNameU;
     ULONG Attributes;
@@ -452,6 +454,8 @@ VfatCreateFile(
     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;
+    OpenTargetDir = (Stack->Flags & SL_OPEN_TARGET_DIRECTORY) ? TRUE : FALSE;
+
     FileObject = Stack->FileObject;
     DeviceExt = DeviceObject->DeviceExtension;
 
@@ -468,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)
         {
@@ -485,9 +497,36 @@ VfatCreateFile(
         }
 #endif
 
+        if (OpenTargetDir)
+        {
+            return STATUS_INVALID_PARAMETER;
+        }
+
         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++;
+        pFcb->OpenHandleCount++;
 
         Irp->IoStatus.Information = FILE_OPENED;
         return STATUS_SUCCESS;
@@ -520,6 +559,13 @@ VfatCreateFile(
         }
     }
 
+    /* Check if we try to open target directory of root dir */
+    if (OpenTargetDir && FileObject->RelatedFileObject == NULL && PathNameU.Length == sizeof(WCHAR) &&
+        PathNameU.Buffer[0] == L'\\')
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
     if (FileObject->RelatedFileObject && PathNameU.Length >= sizeof(WCHAR) && PathNameU.Buffer[0] == L'\\')
     {
         return STATUS_OBJECT_NAME_INVALID;
@@ -531,7 +577,110 @@ VfatCreateFile(
     }
 
     /* Try opening the file. */
-    Status = VfatOpenFile(DeviceExt, &PathNameU, FileObject, RequestedDisposition, &ParentFcb);
+    if (!OpenTargetDir)
+    {
+        Status = VfatOpenFile(DeviceExt, &PathNameU, FileObject, RequestedDisposition, &ParentFcb);
+    }
+    else
+    {
+        PVFATFCB TargetFcb;
+        LONG idx, FileNameLen;
+
+        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
+        {
+            Irp->IoStatus.Information = FILE_DOES_NOT_EXIST;
+        }
+
+        idx = FileObject->FileName.Length / sizeof(WCHAR) - 1;
+
+        /* Skip trailing \ - if any */
+        if (PathNameU.Buffer[idx] == L'\\')
+        {
+            --idx;
+            PathNameU.Length -= sizeof(WCHAR);
+        }
+
+        /* Get file name */
+        while (idx >= 0 && PathNameU.Buffer[idx] != L'\\')
+        {
+            --idx;
+        }
+
+        if (idx > 0 || PathNameU.Buffer[0] == L'\\')
+        {
+            /* We don't want to include / in the name */
+            FileNameLen = PathNameU.Length - ((idx + 1) * sizeof(WCHAR));
+
+            /* Update FO just to keep file name */
+            /* Skip first slash */
+            ++idx;
+            FileObject->FileName.Length = FileNameLen;
+            RtlMoveMemory(&PathNameU.Buffer[0], &PathNameU.Buffer[idx], FileObject->FileName.Length);
+        }
+        else
+        {
+            /* This is a relative open and we have only the filename, so open the parent directory
+             * It is in RelatedFileObject
+             */
+            ASSERT(FileObject->RelatedFileObject != NULL);
+
+            /* No need to modify the FO, it already has the name */
+        }
+
+        /* We're done with opening! */
+        if (ParentFcb != NULL)
+        {
+            Status = vfatAttachFCBToFileObject(DeviceExt, ParentFcb, FileObject);
+        }
+
+        if (NT_SUCCESS(Status))
+        {
+            pFcb = FileObject->FsContext;
+            ASSERT(pFcb == ParentFcb);
+
+            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))
+                {
+                    VfatCloseFile(DeviceExt, FileObject);
+                    return Status;
+                }
+            }
+
+            pFcb->OpenHandleCount++;
+            DeviceExt->OpenHandleCount++;
+        }
+        else if (ParentFcb != NULL)
+        {
+            vfatReleaseFCB(DeviceExt, ParentFcb);
+        }
+
+        return Status;
+    }
 
     /*
      * If the directory containing the file to open doesn't exist then
@@ -550,7 +699,7 @@ VfatCreateFile(
 
     if (!NT_SUCCESS(Status) && ParentFcb == NULL)
     {
-        DPRINT1("VfatOpenFile faild for '%wZ', status %x\n", &PathNameU, Status);
+        DPRINT1("VfatOpenFile failed for '%wZ', status %x\n", &PathNameU, Status);
         return Status;
     }
 
@@ -567,7 +716,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))
             {
@@ -754,7 +903,22 @@ VfatCreateFile(
                             &pFcb->FCBShareAccess);
     }
 
+    if (Irp->IoStatus.Information == FILE_CREATED)
+    {
+        FsRtlNotifyFullReportChange(DeviceExt->NotifySync,
+                                    &(DeviceExt->NotifyList),
+                                    (PSTRING)&pFcb->PathNameU,
+                                    pFcb->PathNameU.Length - pFcb->LongNameU.Length,
+                                    NULL,
+                                    NULL,
+                                    ((*pFcb->Attributes & FILE_ATTRIBUTE_DIRECTORY) ?
+                                    FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME),
+                                    FILE_ACTION_ADDED,
+                                    NULL);
+    }
+
     pFcb->OpenHandleCount++;
+    DeviceExt->OpenHandleCount++;
 
     /* FIXME : test write access if requested */