[FASTFAT]
[reactos.git] / reactos / drivers / filesystems / fastfat / misc.c
index b48ac90..39e5896 100644 (file)
@@ -51,6 +51,10 @@ const char* MajorFunctionNames[] =
 
 static LONG QueueCount = 0;
 
+static VOID VfatFreeIrpContext(PVFAT_IRP_CONTEXT);
+static PVFAT_IRP_CONTEXT VfatAllocateIrpContext(PDEVICE_OBJECT, PIRP);
+static NTSTATUS VfatQueueRequest(PVFAT_IRP_CONTEXT);
+
 /* FUNCTIONS ****************************************************************/
 
 static
@@ -69,28 +73,31 @@ VfatLockControl(
 
     if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject)
     {
-        Status = STATUS_INVALID_DEVICE_REQUEST;
-        goto Fail;
+        return STATUS_INVALID_DEVICE_REQUEST;
     }
 
     if (*Fcb->Attributes & FILE_ATTRIBUTE_DIRECTORY)
     {
-        Status = STATUS_INVALID_PARAMETER;
-        goto Fail;
+        return STATUS_INVALID_PARAMETER;
     }
 
+    IrpContext->Flags &= ~IRPCONTEXT_COMPLETE;
     Status = FsRtlProcessFileLock(&Fcb->FileLock,
                                   IrpContext->Irp,
                                   NULL);
-
-    VfatFreeIrpContext(IrpContext);
     return Status;
+}
 
-Fail:
-    IrpContext->Irp->IoStatus.Status = Status;
-    IoCompleteRequest(IrpContext->Irp, (CCHAR)(NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT));
-    VfatFreeIrpContext(IrpContext);
-    return Status;
+static
+NTSTATUS
+VfatDeviceControl(
+    IN PVFAT_IRP_CONTEXT IrpContext)
+{
+    IoSkipCurrentIrpStackLocation(IrpContext->Irp);
+
+    IrpContext->Flags &= ~IRPCONTEXT_COMPLETE;
+
+    return IoCallDriver(IrpContext->DeviceExt->StorageDevice, IrpContext->Irp);
 }
 
 static
@@ -98,48 +105,108 @@ NTSTATUS
 VfatDispatchRequest(
     IN PVFAT_IRP_CONTEXT IrpContext)
 {
+    NTSTATUS Status;
+
     DPRINT("VfatDispatchRequest (IrpContext %p), is called for %s\n", IrpContext,
            IrpContext->MajorFunction >= IRP_MJ_MAXIMUM_FUNCTION ? "????" : MajorFunctionNames[IrpContext->MajorFunction]);
 
     ASSERT(IrpContext);
 
+    FsRtlEnterFileSystem();
+
     switch (IrpContext->MajorFunction)
     {
         case IRP_MJ_CLOSE:
-            return VfatClose(IrpContext);
+            Status = VfatClose(IrpContext);
+            break;
+
         case IRP_MJ_CREATE:
-         return VfatCreate(IrpContext);
+            Status = VfatCreate(IrpContext);
+            break;
+
         case IRP_MJ_READ:
-            return VfatRead (IrpContext);
+            Status = VfatRead(IrpContext);
+            break;
+
         case IRP_MJ_WRITE:
-            return VfatWrite (IrpContext);
+            Status = VfatWrite (IrpContext);
+            break;
+
         case IRP_MJ_FILE_SYSTEM_CONTROL:
-            return VfatFileSystemControl(IrpContext);
+            Status = VfatFileSystemControl(IrpContext);
+            break;
+
         case IRP_MJ_QUERY_INFORMATION:
-            return VfatQueryInformation (IrpContext);
+            Status = VfatQueryInformation (IrpContext);
+            break;
+
         case IRP_MJ_SET_INFORMATION:
-            return VfatSetInformation (IrpContext);
+            Status = VfatSetInformation (IrpContext);
+            break;
+
         case IRP_MJ_DIRECTORY_CONTROL:
-            return VfatDirectoryControl(IrpContext);
+            Status = VfatDirectoryControl(IrpContext);
+            break;
+
         case IRP_MJ_QUERY_VOLUME_INFORMATION:
-            return VfatQueryVolumeInformation(IrpContext);
+            Status = VfatQueryVolumeInformation(IrpContext);
+            break;
+
         case IRP_MJ_SET_VOLUME_INFORMATION:
-            return VfatSetVolumeInformation(IrpContext);
+            Status = VfatSetVolumeInformation(IrpContext);
+            break;
+
         case IRP_MJ_LOCK_CONTROL:
-            return VfatLockControl(IrpContext);
+            Status = VfatLockControl(IrpContext);
+            break;
+
+        case IRP_MJ_DEVICE_CONTROL:
+            Status = VfatDeviceControl(IrpContext);
+            break;
+
         case IRP_MJ_CLEANUP:
-            return VfatCleanup(IrpContext);
+            Status = VfatCleanup(IrpContext);
+            break;
+
         case IRP_MJ_FLUSH_BUFFERS:
-            return VfatFlush(IrpContext);
+            Status = VfatFlush(IrpContext);
+            break;
+
         case IRP_MJ_PNP:
-            return VfatPnp(IrpContext);
+            Status = VfatPnp(IrpContext);
+            break;
+
         default:
             DPRINT1("Unexpected major function %x\n", IrpContext->MajorFunction);
-            IrpContext->Irp->IoStatus.Status = STATUS_DRIVER_INTERNAL_ERROR;
-            IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT);
-            VfatFreeIrpContext(IrpContext);
-            return STATUS_DRIVER_INTERNAL_ERROR;
+            Status = STATUS_DRIVER_INTERNAL_ERROR;
+    }
+
+    ASSERT((!(IrpContext->Flags & IRPCONTEXT_COMPLETE) && !(IrpContext->Flags & IRPCONTEXT_QUEUE)) ||
+           ((IrpContext->Flags & IRPCONTEXT_COMPLETE) && !(IrpContext->Flags & IRPCONTEXT_QUEUE)) ||
+           (!(IrpContext->Flags & IRPCONTEXT_COMPLETE) && (IrpContext->Flags & IRPCONTEXT_QUEUE)));
+
+    if (IrpContext->Flags & IRPCONTEXT_COMPLETE)
+    {
+        IrpContext->Irp->IoStatus.Status = Status;
+        IoCompleteRequest(IrpContext->Irp, IrpContext->PriorityBoost);
+    }
+
+    if (IrpContext->Flags & IRPCONTEXT_QUEUE)
+    {
+        /* Reset our status flags before queueing the IRP */
+        IrpContext->Flags |= IRPCONTEXT_COMPLETE;
+        IrpContext->Flags &= ~IRPCONTEXT_QUEUE;
+        Status = VfatQueueRequest(IrpContext);
+    }
+    else
+    {
+        /* Unless the IRP was queued, always free the IRP context */
+        VfatFreeIrpContext(IrpContext);
     }
+
+    FsRtlExitFileSystem();
+
+    return Status;
 }
 
 NTSTATUS
@@ -165,13 +232,12 @@ VfatBuildRequest(
     }
     else
     {
-        FsRtlEnterFileSystem();
         Status = VfatDispatchRequest(IrpContext);
-        FsRtlExitFileSystem();
     }
     return Status;
 }
 
+static
 VOID
 VfatFreeIrpContext(
     PVFAT_IRP_CONTEXT IrpContext)
@@ -180,6 +246,7 @@ VfatFreeIrpContext(
     ExFreeToNPagedLookasideList(&VfatGlobalData->IrpContextLookasideList, IrpContext);
 }
 
+static
 PVFAT_IRP_CONTEXT
 VfatAllocateIrpContext(
     PDEVICE_OBJECT DeviceObject,
@@ -206,7 +273,7 @@ VfatAllocateIrpContext(
         MajorFunction = IrpContext->MajorFunction = IrpContext->Stack->MajorFunction;
         IrpContext->MinorFunction = IrpContext->Stack->MinorFunction;
         IrpContext->FileObject = IrpContext->Stack->FileObject;
-        IrpContext->Flags = 0;
+        IrpContext->Flags = IRPCONTEXT_COMPLETE;
         if (MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL ||
             MajorFunction == IRP_MJ_DEVICE_CONTROL ||
             MajorFunction == IRP_MJ_SHUTDOWN)
@@ -221,6 +288,7 @@ VfatAllocateIrpContext(
         }
         KeInitializeEvent(&IrpContext->Event, NotificationEvent, FALSE);
         IrpContext->RefCount = 0;
+        IrpContext->PriorityBoost = IO_NO_INCREMENT;
     }
     return IrpContext;
 }
@@ -236,11 +304,10 @@ VfatDoRequest(
     InterlockedDecrement(&QueueCount);
     DPRINT("VfatDoRequest(IrpContext %p), MajorFunction %x, %d\n",
            IrpContext, ((PVFAT_IRP_CONTEXT)IrpContext)->MajorFunction, QueueCount);
-    FsRtlEnterFileSystem();
     VfatDispatchRequest((PVFAT_IRP_CONTEXT)IrpContext);
-    FsRtlExitFileSystem();
 }
 
+static
 NTSTATUS
 VfatQueueRequest(
     PVFAT_IRP_CONTEXT IrpContext)
@@ -250,6 +317,8 @@ VfatQueueRequest(
 
     ASSERT(IrpContext != NULL);
     ASSERT(IrpContext->Irp != NULL);
+    ASSERT(!(IrpContext->Flags & IRPCONTEXT_QUEUE) &&
+           (IrpContext->Flags & IRPCONTEXT_COMPLETE));
 
     IrpContext->Flags |= IRPCONTEXT_CANWAIT;
     IoMarkIrpPending(IrpContext->Irp);
@@ -260,15 +329,14 @@ VfatQueueRequest(
 
 PVOID
 VfatGetUserBuffer(
-    IN PIRP Irp)
+    IN PIRP Irp,
+    IN BOOLEAN Paging)
 {
     ASSERT(Irp);
 
     if (Irp->MdlAddress)
     {
-        /* This call may be in the paging path, so use maximum priority */
-        /* FIXME: call with normal priority in the non-paging path */
-        return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, HighPagePriority);
+        return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, (Paging ? HighPagePriority : NormalPagePriority));
     }
     else
     {
@@ -300,3 +368,90 @@ VfatLockUserBuffer(
 
     return STATUS_SUCCESS;
 }
+
+BOOLEAN
+VfatCheckForDismount(
+    IN PDEVICE_EXTENSION DeviceExt,
+    IN BOOLEAN Create)
+{
+    KIRQL OldIrql;
+    PVPB Vpb;
+    BOOLEAN Delete;
+
+    DPRINT1("VfatCheckForDismount(%p, %u)\n", DeviceExt, Create);
+
+    /* Lock VPB */
+    IoAcquireVpbSpinLock(&OldIrql);
+
+    /* Reference it and check if a create is being done */
+    Vpb = DeviceExt->IoVPB;
+    if (Vpb->ReferenceCount != Create)
+    {
+        /* Copy the VPB to our local own to prepare later dismount */
+        if (DeviceExt->SpareVPB != NULL)
+        {
+            RtlZeroMemory(DeviceExt->SpareVPB, sizeof(VPB));
+            DeviceExt->SpareVPB->Type = IO_TYPE_VPB;
+            DeviceExt->SpareVPB->Size = sizeof(VPB);
+            DeviceExt->SpareVPB->RealDevice = DeviceExt->IoVPB->RealDevice;
+            DeviceExt->SpareVPB->DeviceObject = NULL;
+            DeviceExt->SpareVPB->Flags = DeviceExt->IoVPB->Flags & VPB_REMOVE_PENDING;
+            DeviceExt->IoVPB->RealDevice->Vpb = DeviceExt->SpareVPB;
+            DeviceExt->SpareVPB = NULL;
+            DeviceExt->IoVPB->Flags |= VPB_PERSISTENT;
+        }
+
+        /* Don't do anything */
+        Delete = FALSE;
+    }
+    else
+    {
+        /* Otherwise, delete the volume */
+        Delete = TRUE;
+
+        /* Check if it has a VPB and unmount it */
+        if (Vpb->RealDevice->Vpb == Vpb)
+        {
+            Vpb->DeviceObject = NULL;
+            Vpb->Flags &= ~VPB_MOUNTED;
+        }
+    }
+
+    /* Release lock and return status */
+    IoReleaseVpbSpinLock(OldIrql);
+
+    /* If we were to delete, delete volume */
+    if (Delete)
+    {
+        PVPB DelVpb;
+
+        /* If we have a local VPB, we'll have to delete it
+         * but we won't dismount us - something went bad before
+         */
+        if (DeviceExt->SpareVPB)
+        {
+            DelVpb = DeviceExt->SpareVPB;
+        }
+        /* Otherwise, dismount our device if possible */
+        else
+        {
+            if (DeviceExt->IoVPB->ReferenceCount)
+            {
+                ObfDereferenceObject(DeviceExt->StorageDevice);
+                IoDeleteDevice(DeviceExt->VolumeDevice);
+                return Delete;
+            }
+
+            DelVpb = DeviceExt->IoVPB;
+        }
+
+        /* Delete any of the available VPB and dismount */
+        ExFreePool(DelVpb);
+        ObfDereferenceObject(DeviceExt->StorageDevice);
+        IoDeleteDevice(DeviceExt->VolumeDevice);
+
+        return Delete;
+    }
+
+    return Delete;
+}