USHORT NodeByteSize;
PDEVICE_OBJECT TargetDeviceObject;
PVPB Vpb;
+ PVPB LocalVpb;
ULONG VcbState;
KMUTEX Mutex;
CLONG OpenCount;
VCB Vcb;
} VOLUME_DEVICE_OBJECT, *PVOLUME_DEVICE_OBJECT;
+#define VCB_STATE_LOCKED 0x00000001
+#define VCB_STATE_DISMOUNTED 0x00000002
+
/* GLOBALS *******************************************************************/
PDEVICE_OBJECT RawDiskDeviceObject, RawCdromDeviceObject, RawTapeDeviceObject;
/* FUNCTIONS *****************************************************************/
-VOID
+NTSTATUS
NTAPI
RawInitializeVcb(IN OUT PVCB Vcb,
IN PDEVICE_OBJECT TargetDeviceObject,
IN PVPB Vpb)
{
+ NTSTATUS Status = STATUS_SUCCESS;
+
PAGED_CODE();
+ DPRINT("RawInitializeVcb(%p, %p, %p)\n", Vcb, TargetDeviceObject, Vpb);
+
/* Clear it */
RtlZeroMemory(Vcb, sizeof(VCB));
/* Initialize the lock */
KeInitializeMutex(&Vcb->Mutex, 0);
+
+ Vcb->LocalVpb = ExAllocatePoolWithTag(NonPagedPool, sizeof(VPB), ' waR');
+ if (Vcb->LocalVpb == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ return Status;
}
BOOLEAN
PVPB Vpb;
BOOLEAN Delete;
+ DPRINT("RawCheckForDismount(%p, %lu)\n", Vcb, CreateOperation);
+
+ ASSERT(KeReadStateMutant(&Vcb->Mutex) == 0);
+
/* Lock VPB */
IoAcquireVpbSpinLock(&OldIrql);
Vpb = Vcb->Vpb;
if (Vcb->Vpb->ReferenceCount != CreateOperation)
{
+ /* Copy the VPB to our local own to prepare later dismount */
+ if (Vcb->LocalVpb != NULL)
+ {
+ RtlZeroMemory(Vcb->LocalVpb, sizeof(VPB));
+ Vcb->LocalVpb->Type = IO_TYPE_VPB;
+ Vcb->LocalVpb->Size = sizeof(VPB);
+ Vcb->LocalVpb->RealDevice = Vcb->Vpb->RealDevice;
+ Vcb->LocalVpb->DeviceObject = NULL;
+ Vcb->LocalVpb->Flags = Vcb->Vpb->Flags & VPB_REMOVE_PENDING;
+ Vcb->Vpb->RealDevice->Vpb = Vcb->LocalVpb;
+ Vcb->LocalVpb = NULL;
+ Vcb->Vpb->Flags |= VPB_PERSISTENT;
+ }
/* Don't do anything */
Delete = FALSE;
}
/* Release lock and return status */
IoReleaseVpbSpinLock(OldIrql);
+
+ /* If we were to delete, delete volume */
+ if (Delete)
+ {
+ PVPB DelVpb;
+
+ /* Release our Vcb lock to be able delete us */
+ KeReleaseMutex(&Vcb->Mutex, 0);
+
+ /* If we have a local VPB, we'll have to delete it
+ * but we won't dismount us - something went bad before
+ */
+ if (Vcb->LocalVpb)
+ {
+ DelVpb = Vcb->LocalVpb;
+ }
+ /* Otherwise, dismount our device if possible */
+ else
+ {
+ if (Vcb->Vpb->ReferenceCount)
+ {
+ ObfDereferenceObject(Vcb->TargetDeviceObject);
+ IoDeleteDevice((PDEVICE_OBJECT)CONTAINING_RECORD(Vcb,
+ VOLUME_DEVICE_OBJECT,
+ Vcb));
+ return Delete;
+ }
+
+ DelVpb = Vcb->Vpb;
+ }
+
+ /* Delete any of the available VPB and dismount */
+ ExFreePool(DelVpb);
+ ObfDereferenceObject(Vcb->TargetDeviceObject);
+ IoDeleteDevice((PDEVICE_OBJECT)CONTAINING_RECORD(Vcb,
+ VOLUME_DEVICE_OBJECT,
+ Vcb));
+
+ return Delete;
+ }
+
return Delete;
}
{
PIO_STACK_LOCATION IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
+ DPRINT("RawCompletionRoutine(%p, %p, %p)\n", DeviceObject, Irp, Context);
+
/* Check if this was a valid sync R/W request */
if (((IoStackLocation->MajorFunction == IRP_MJ_READ) ||
(IoStackLocation->MajorFunction == IRP_MJ_WRITE)) &&
IN PIO_STACK_LOCATION IoStackLocation)
{
NTSTATUS Status;
- BOOLEAN Deleted = FALSE;
PAGED_CODE();
+ DPRINT("RawClose(%p, %p, %p)\n", Vcb, Irp, IoStackLocation);
+
+ /* If its a stream, not much to do */
+ if (IoStackLocation->FileObject->Flags & FO_STREAM_FILE)
+ {
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+ return STATUS_SUCCESS;
+ }
+
/* Make sure we can clean up */
Status = KeWaitForSingleObject(&Vcb->Mutex,
Executive,
/* Decrease the open count and check if this is a dismount */
Vcb->OpenCount--;
- if (!Vcb->OpenCount) Deleted = RawCheckForDismount(Vcb, FALSE);
-
- /* Check if we should delete the device */
- KeReleaseMutex(&Vcb->Mutex, FALSE);
- if (Deleted)
+ if (!Vcb->OpenCount || !RawCheckForDismount(Vcb, FALSE))
{
- /* Delete it */
- IoDeleteDevice((PDEVICE_OBJECT)CONTAINING_RECORD(Vcb,
- VOLUME_DEVICE_OBJECT,
- Vcb));
+ KeReleaseMutex(&Vcb->Mutex, FALSE);
}
/* Complete the request */
IN PIO_STACK_LOCATION IoStackLocation)
{
NTSTATUS Status;
- BOOLEAN Deleted = FALSE;
USHORT ShareAccess;
ACCESS_MASK DesiredAccess;
+ BOOLEAN Deleted = FALSE;
PAGED_CODE();
+ DPRINT("RawCreate(%p, %p, %p)\n", Vcb, Irp, IoStackLocation);
+
/* Make sure we can clean up */
Status = KeWaitForSingleObject(&Vcb->Mutex,
Executive,
(!(IoStackLocation->Parameters.Create.Options & FILE_DIRECTORY_FILE)))
{
/* Make sure the VCB isn't locked */
- if (Vcb->VcbState & 1)
+ if (Vcb->VcbState & VCB_STATE_LOCKED)
{
/* Refuse the operation */
Status = STATUS_ACCESS_DENIED;
Irp->IoStatus.Information = 0;
}
+ else if (Vcb->VcbState & VCB_STATE_DISMOUNTED)
+ {
+ /* Refuse the operation */
+ Status = STATUS_VOLUME_DISMOUNTED;
+ Irp->IoStatus.Information = 0;
+ }
else
{
/* Setup share access */
if (!(NT_SUCCESS(Status)) && !(Vcb->OpenCount))
{
/* Check if we can dismount the device */
- Deleted = RawCheckForDismount(Vcb, FALSE);
+ Deleted = RawCheckForDismount(Vcb, TRUE);
}
- /* Check if we should delete the device */
- KeReleaseMutex(&Vcb->Mutex, FALSE);
- if (Deleted)
+ /* In case of deletion, the mutex is already released */
+ if (!Deleted)
{
- /* Delete it */
- IoDeleteDevice((PDEVICE_OBJECT)CONTAINING_RECORD(Vcb,
- VOLUME_DEVICE_OBJECT,
- Vcb));
+ KeReleaseMutex(&Vcb->Mutex, FALSE);
}
/* Complete the request */
- Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_DISK_INCREMENT);
- return STATUS_SUCCESS;
+ return Status;
}
NTSTATUS
NTSTATUS Status;
PAGED_CODE();
+ DPRINT("RawReadWriteDeviceControl(%p, %p, %p)\n", Vcb, Irp, IoStackLocation);
+
/* Don't do anything if the request was 0 bytes */
if (((IoStackLocation->MajorFunction == IRP_MJ_READ) ||
(IoStackLocation->MajorFunction == IRP_MJ_WRITE)) &&
PFILE_OBJECT FileObject = NULL;
PAGED_CODE();
+ DPRINT("RawMountVolume(%p)\n", IoStackLocation);
+
/* Remember our owner */
DeviceObject = IoStackLocation->Parameters.MountVolume.DeviceObject;
AlignmentRequirement);
/* Setup the VCB */
- RawInitializeVcb(&Volume->Vcb,
- IoStackLocation->Parameters.MountVolume.DeviceObject,
- IoStackLocation->Parameters.MountVolume.Vpb);
+ Status = RawInitializeVcb(&Volume->Vcb,
+ IoStackLocation->Parameters.MountVolume.DeviceObject,
+ IoStackLocation->Parameters.MountVolume.Vpb);
+ if (!NT_SUCCESS(Status))
+ {
+ IoDeleteDevice((PDEVICE_OBJECT)Volume);
+ return Status;
+ }
/* Set dummy label and serial number */
Volume->Vcb.Vpb->SerialNumber = 0xFFFFFFFF;
NTSTATUS Status;
PAGED_CODE();
+ DPRINT("RawUserFsCtrl(%p, %p)\n", IoStackLocation, Vcb);
+
/* Lock the device */
Status = KeWaitForSingleObject(&Vcb->Mutex,
Executive,
NTSTATUS Status;
PAGED_CODE();
+ DPRINT("RawFileSystemControl(%p, %p, %p)\n", Vcb, Irp, IoStackLocation);
+
/* Check the kinds of FSCTLs that we support */
switch (IoStackLocation->MinorFunction)
{
PFILE_POSITION_INFORMATION Buffer;
PAGED_CODE();
+ DPRINT("RawQueryInformation(%p, %p, %p)\n", Vcb, Irp, IoStackLocation);
+
/* Get information from the IRP */
Length = &IoStackLocation->Parameters.QueryFile.Length;
Buffer = Irp->AssociatedIrp.SystemBuffer;
PDEVICE_OBJECT DeviceObject;
PAGED_CODE();
+ DPRINT("RawSetInformation(%p, %p, %p)\n", Vcb, Irp, IoStackLocation);
+
/* Get information from the IRP */
Buffer = Irp->AssociatedIrp.SystemBuffer;
{
PAGED_CODE();
+ DPRINT("RawQueryFsVolumeInfo(%p, %p, %p)\n", Vcb, Buffer, Length);
+
/* Clear the buffer and stub it out */
RtlZeroMemory( Buffer, sizeof(FILE_FS_VOLUME_INFORMATION));
Buffer->VolumeSerialNumber = Vcb->Vpb->SerialNumber;
BOOLEAN DiskHasPartitions;
PAGED_CODE();
+ DPRINT("RawQueryFsSizeInfo(%p, %p, %p)\n", Vcb, Buffer, Length);
+
/* Validate the buffer */
if (*Length < sizeof(FILE_FS_SIZE_INFORMATION))
{
{
PAGED_CODE();
+ DPRINT("RawQueryFsDeviceInfo(%p, %p, %p)\n", Vcb, Buffer, Length);
+
/* Validate buffer */
if (*Length < sizeof(FILE_FS_DEVICE_INFORMATION))
{
ULONG ReturnLength;
PAGED_CODE();
+ DPRINT("RawQueryFsAttributeInfo(%p, %p, %p)\n", Vcb, Buffer, Length);
+
/* Check if the buffer is large enough for our name ("RAW") */
ReturnLength = FIELD_OFFSET(FILE_FS_ATTRIBUTE_INFORMATION,
FileSystemName[sizeof(szRawFSName) / sizeof(szRawFSName[0])]);
PVOID Buffer;
PAGED_CODE();
+ DPRINT("RawQueryVolumeInformation(%p, %p, %p)\n", Vcb, Irp, IoStackLocation);
+
/* Get IRP Data */
Length = IoStackLocation->Parameters.QueryVolume.Length;
Buffer = Irp->AssociatedIrp.SystemBuffer;
NTSTATUS Status;
PAGED_CODE();
+ DPRINT("RawCleanup(%p, %p, %p)\n", Vcb, Irp, IoStackLocation);
+
/* Make sure we can clean up */
Status = KeWaitForSingleObject(&Vcb->Mutex,
Executive,
NULL);
ASSERT(NT_SUCCESS(Status));
- /* Remove shared access and complete the request */
+ /* Remove shared access */
IoRemoveShareAccess(IoStackLocation->FileObject, &Vcb->ShareAccess);
+
+ /* Check if we're to dismount */
+ if (Vcb->VcbState & VCB_STATE_DISMOUNTED)
+ {
+ ASSERT(Vcb->OpenCount == 1);
+ RawCheckForDismount(Vcb, FALSE);
+ }
+
KeReleaseMutex(&Vcb->Mutex, FALSE);
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(Irp, IO_DISK_INCREMENT);
PVCB Vcb;
PAGED_CODE();
+ DPRINT("RawDispatch(%p, %p)\n", DeviceObject, Irp);
+
/* Get the stack location */
IoStackLocation = IoGetCurrentIrpStackLocation(Irp);