2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/iomgr/rawfs.c
5 * PURPOSE: Raw File System Driver
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES *****************************************************************/
15 /* TYPES *******************************************************************/
21 PDEVICE_OBJECT TargetDeviceObject
;
27 SHARE_ACCESS ShareAccess
;
29 LARGE_INTEGER SectorsOnDisk
;
32 typedef struct _VOLUME_DEVICE_OBJECT
34 DEVICE_OBJECT DeviceObject
;
36 } VOLUME_DEVICE_OBJECT
, *PVOLUME_DEVICE_OBJECT
;
38 #define VCB_STATE_LOCKED 0x00000001
39 #define VCB_STATE_DISMOUNTED 0x00000002
41 /* GLOBALS *******************************************************************/
43 PDEVICE_OBJECT RawDiskDeviceObject
, RawCdromDeviceObject
, RawTapeDeviceObject
;
45 /* FUNCTIONS *****************************************************************/
49 RawInitializeVcb(IN OUT PVCB Vcb
,
50 IN PDEVICE_OBJECT TargetDeviceObject
,
53 NTSTATUS Status
= STATUS_SUCCESS
;
57 DPRINT("RawInitializeVcb(%p, %p, %p)\n", Vcb
, TargetDeviceObject
, Vpb
);
60 RtlZeroMemory(Vcb
, sizeof(VCB
));
62 /* Associate to system objects */
63 Vcb
->TargetDeviceObject
= TargetDeviceObject
;
66 /* Initialize the lock */
67 KeInitializeMutex(&Vcb
->Mutex
, 0);
69 Vcb
->LocalVpb
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(VPB
), ' waR');
70 if (Vcb
->LocalVpb
== NULL
)
72 Status
= STATUS_INSUFFICIENT_RESOURCES
;
80 RawCheckForDismount(IN PVCB Vcb
,
81 IN BOOLEAN CreateOperation
)
87 DPRINT("RawCheckForDismount(%p, %lu)\n", Vcb
, CreateOperation
);
89 ASSERT(KeReadStateMutant(&Vcb
->Mutex
) == 0);
92 IoAcquireVpbSpinLock(&OldIrql
);
94 /* Reference it and check if a create is being done */
96 if (Vcb
->Vpb
->ReferenceCount
!= CreateOperation
)
98 /* Copy the VPB to our local own to prepare later dismount */
99 if (Vcb
->LocalVpb
!= NULL
)
101 RtlZeroMemory(Vcb
->LocalVpb
, sizeof(VPB
));
102 Vcb
->LocalVpb
->Type
= IO_TYPE_VPB
;
103 Vcb
->LocalVpb
->Size
= sizeof(VPB
);
104 Vcb
->LocalVpb
->RealDevice
= Vcb
->Vpb
->RealDevice
;
105 Vcb
->LocalVpb
->DeviceObject
= NULL
;
106 Vcb
->LocalVpb
->Flags
= Vcb
->Vpb
->Flags
& VPB_REMOVE_PENDING
;
107 Vcb
->Vpb
->RealDevice
->Vpb
= Vcb
->LocalVpb
;
108 Vcb
->LocalVpb
= NULL
;
109 Vcb
->Vpb
->Flags
|= VPB_PERSISTENT
;
112 /* Don't do anything */
117 /* Otherwise, delete the volume */
120 /* Check if it has a VPB and unmount it */
121 if (Vpb
->RealDevice
->Vpb
== Vpb
)
123 Vpb
->DeviceObject
= NULL
;
124 Vpb
->Flags
&= ~VPB_MOUNTED
;
128 /* Release the VPB lock */
129 IoReleaseVpbSpinLock(OldIrql
);
131 /* If we were to delete, delete the volume */
134 /* Release our Vcb lock to be able delete us */
135 KeReleaseMutex(&Vcb
->Mutex
, FALSE
);
137 /* If we have a local VPB, we'll have to delete it
138 * but we won't dismount us - something went bad before
142 ExFreePool(Vcb
->LocalVpb
);
144 /* Otherwise, delete any of the available VPB if its reference count is zero */
145 else if (Vcb
->Vpb
->ReferenceCount
== 0)
147 ExFreePool(Vcb
->Vpb
);
150 /* Dismount our device if possible */
151 ObfDereferenceObject(Vcb
->TargetDeviceObject
);
152 IoDeleteDevice((PDEVICE_OBJECT
)CONTAINING_RECORD(Vcb
,
153 VOLUME_DEVICE_OBJECT
,
162 RawCompletionRoutine(IN PDEVICE_OBJECT DeviceObject
,
166 PIO_STACK_LOCATION IoStackLocation
= IoGetCurrentIrpStackLocation(Irp
);
168 DPRINT("RawCompletionRoutine(%p, %p, %p)\n", DeviceObject
, Irp
, Context
);
170 /* Check if this was a valid sync R/W request */
171 if (((IoStackLocation
->MajorFunction
== IRP_MJ_READ
) ||
172 (IoStackLocation
->MajorFunction
== IRP_MJ_WRITE
)) &&
173 ((IoStackLocation
->FileObject
)) &&
174 (FlagOn(IoStackLocation
->FileObject
->Flags
, FO_SYNCHRONOUS_IO
)) &&
175 (NT_SUCCESS(Irp
->IoStatus
.Status
)))
177 /* Update byte offset */
178 IoStackLocation
->FileObject
->CurrentByteOffset
.QuadPart
+=
179 Irp
->IoStatus
.Information
;
182 /* Mark the IRP Pending if it was */
183 if (Irp
->PendingReturned
) IoMarkIrpPending(Irp
);
184 return STATUS_SUCCESS
;
189 RawClose(IN PVCB Vcb
,
191 IN PIO_STACK_LOCATION IoStackLocation
)
196 DPRINT("RawClose(%p, %p, %p)\n", Vcb
, Irp
, IoStackLocation
);
198 /* If its a stream, not much to do */
199 if (IoStackLocation
->FileObject
->Flags
& FO_STREAM_FILE
)
201 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
202 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
203 return STATUS_SUCCESS
;
206 /* Make sure we can clean up */
207 Status
= KeWaitForSingleObject(&Vcb
->Mutex
,
212 ASSERT(NT_SUCCESS(Status
));
214 /* Decrease the open count and check if this is a dismount */
216 if (Vcb
->OpenCount
!= 0 || !RawCheckForDismount(Vcb
, FALSE
))
218 KeReleaseMutex(&Vcb
->Mutex
, FALSE
);
221 /* Complete the request */
222 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
223 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
224 return STATUS_SUCCESS
;
229 RawCreate(IN PVCB Vcb
,
231 IN PIO_STACK_LOCATION IoStackLocation
)
235 ACCESS_MASK DesiredAccess
;
236 BOOLEAN Deleted
= FALSE
;
239 DPRINT("RawCreate(%p, %p, %p)\n", Vcb
, Irp
, IoStackLocation
);
241 /* Make sure we can clean up */
242 Status
= KeWaitForSingleObject(&Vcb
->Mutex
,
247 ASSERT(NT_SUCCESS(Status
));
249 /* Check if this is a valid non-directory file open */
250 if ((!(IoStackLocation
->FileObject
) ||
251 !(IoStackLocation
->FileObject
->FileName
.Length
)) &&
252 ((IoStackLocation
->Parameters
.Create
.Options
>> 24) == FILE_OPEN
) &&
253 (!(IoStackLocation
->Parameters
.Create
.Options
& FILE_DIRECTORY_FILE
)))
255 /* Make sure the VCB isn't locked */
256 if (Vcb
->VcbState
& VCB_STATE_LOCKED
)
258 /* Refuse the operation */
259 Status
= STATUS_ACCESS_DENIED
;
260 Irp
->IoStatus
.Information
= 0;
262 else if (Vcb
->VcbState
& VCB_STATE_DISMOUNTED
)
264 /* Refuse the operation */
265 Status
= STATUS_VOLUME_DISMOUNTED
;
266 Irp
->IoStatus
.Information
= 0;
270 /* Setup share access */
271 ShareAccess
= IoStackLocation
->Parameters
.Create
.ShareAccess
;
272 DesiredAccess
= IoStackLocation
->Parameters
.Create
.
273 SecurityContext
->DesiredAccess
;
275 /* Check if this VCB was already opened */
276 if (Vcb
->OpenCount
> 0)
278 /* Try to see if we have access to it */
279 Status
= IoCheckShareAccess(DesiredAccess
,
281 IoStackLocation
->FileObject
,
284 if (!NT_SUCCESS(Status
)) Irp
->IoStatus
.Information
= 0;
287 /* Make sure we have access */
288 if (NT_SUCCESS(Status
))
290 /* Check if this is the first open */
293 /* Set the share access */
294 IoSetShareAccess(DesiredAccess
,
296 IoStackLocation
->FileObject
,
300 /* Increase the open count and set the VPB */
302 IoStackLocation
->FileObject
->Vpb
= Vcb
->Vpb
;
304 /* Set IRP status and disable intermediate buffering */
305 Status
= STATUS_SUCCESS
;
306 Irp
->IoStatus
.Information
= FILE_OPENED
;
307 IoStackLocation
->FileObject
->Flags
|=
308 FO_NO_INTERMEDIATE_BUFFERING
;
314 /* Invalid create request */
315 Status
= STATUS_INVALID_PARAMETER
;
316 Irp
->IoStatus
.Information
= 0;
319 /* Check if the request failed */
320 if (!NT_SUCCESS(Status
) && !Vcb
->OpenCount
)
322 /* Check if we can dismount the device */
323 Deleted
= RawCheckForDismount(Vcb
, TRUE
);
326 /* In case of deletion, the mutex is already released */
329 KeReleaseMutex(&Vcb
->Mutex
, FALSE
);
332 /* Complete the request */
333 Irp
->IoStatus
.Status
= Status
;
334 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
340 RawReadWriteDeviceControl(IN PVCB Vcb
,
342 IN PIO_STACK_LOCATION IoStackLocation
)
347 DPRINT("RawReadWriteDeviceControl(%p, %p, %p)\n", Vcb
, Irp
, IoStackLocation
);
349 /* Don't do anything if the request was 0 bytes */
350 if (((IoStackLocation
->MajorFunction
== IRP_MJ_READ
) ||
351 (IoStackLocation
->MajorFunction
== IRP_MJ_WRITE
)) &&
352 !(IoStackLocation
->Parameters
.Read
.Length
))
355 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
356 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
357 return STATUS_SUCCESS
;
360 /* Copy the IRP stack location */
361 IoCopyCurrentIrpStackLocationToNext(Irp
);
363 /* Disable verifies */
364 IoGetNextIrpStackLocation(Irp
)->Flags
|= SL_OVERRIDE_VERIFY_VOLUME
;
366 /* Setup a completion routine */
367 IoSetCompletionRoutine(Irp
,
368 RawCompletionRoutine
,
374 /* Call the next driver and exit */
375 Status
= IoCallDriver(Vcb
->TargetDeviceObject
, Irp
);
381 RawMountVolume(IN PIO_STACK_LOCATION IoStackLocation
)
384 PDEVICE_OBJECT DeviceObject
;
385 PVOLUME_DEVICE_OBJECT Volume
;
386 PFILE_OBJECT FileObject
= NULL
;
389 DPRINT("RawMountVolume(%p)\n", IoStackLocation
);
391 /* Remember our owner */
392 DeviceObject
= IoStackLocation
->Parameters
.MountVolume
.DeviceObject
;
394 /* Create the volume */
395 Status
= IoCreateDevice(RawDiskDeviceObject
->DriverObject
,
396 sizeof(VOLUME_DEVICE_OBJECT
) -
397 sizeof(DEVICE_OBJECT
),
399 FILE_DEVICE_DISK_FILE_SYSTEM
,
402 (PDEVICE_OBJECT
*)&Volume
);
403 if (!NT_SUCCESS(Status
)) return Status
;
405 /* Use highest alignment requirement */
406 Volume
->DeviceObject
.AlignmentRequirement
= max(DeviceObject
->
407 AlignmentRequirement
,
408 Volume
->DeviceObject
.
409 AlignmentRequirement
);
412 Status
= RawInitializeVcb(&Volume
->Vcb
,
413 IoStackLocation
->Parameters
.MountVolume
.DeviceObject
,
414 IoStackLocation
->Parameters
.MountVolume
.Vpb
);
415 if (!NT_SUCCESS(Status
))
417 IoDeleteDevice((PDEVICE_OBJECT
)Volume
);
421 /* Set dummy label and serial number */
422 Volume
->Vcb
.Vpb
->SerialNumber
= 0xFFFFFFFF;
423 Volume
->Vcb
.Vpb
->VolumeLabelLength
= 0;
426 Volume
->Vcb
.Vpb
->DeviceObject
= &Volume
->DeviceObject
;
427 Volume
->DeviceObject
.StackSize
= DeviceObject
->StackSize
+ 1;
428 Volume
->DeviceObject
.SectorSize
= DeviceObject
->SectorSize
;
429 Volume
->DeviceObject
.Flags
|= DO_DIRECT_IO
;
430 Volume
->DeviceObject
.Flags
&= ~DO_DEVICE_INITIALIZING
;
432 /* Try to get associated FO (for notification) */
435 FileObject
= IoCreateStreamFileObjectLite(NULL
,
436 &(Volume
->DeviceObject
));
438 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
440 /* Get the exception code */
441 Status
= _SEH2_GetExceptionCode();
445 /* If failed, delete devive */
446 if (!NT_SUCCESS(Status
))
448 IoDeleteDevice((PDEVICE_OBJECT
)Volume
);
452 /* Increment OpenCount by two to avoid dismount when RawClose() will be called on ObDereferenceObject() */
453 Volume
->Vcb
.OpenCount
+= 2;
454 /* Notify for successful mount */
455 FsRtlNotifyVolumeEvent(FileObject
, FSRTL_VOLUME_MOUNT
);
456 /* It's not opened anymore, decrease the reference count to 0 to make FileObject being released */
457 ObDereferenceObject(FileObject
);
458 Volume
->Vcb
.OpenCount
-= 2;
465 RawUserFsCtrl(IN PIO_STACK_LOCATION IoStackLocation
,
471 DPRINT("RawUserFsCtrl(%p, %p)\n", IoStackLocation
, Vcb
);
473 /* Lock the device */
474 Status
= KeWaitForSingleObject(&Vcb
->Mutex
,
479 ASSERT(NT_SUCCESS(Status
));
481 /* Check what kind of request this is */
482 switch (IoStackLocation
->Parameters
.FileSystemControl
.FsControlCode
)
484 /* Oplock requests */
485 case FSCTL_REQUEST_OPLOCK_LEVEL_1
:
486 case FSCTL_REQUEST_OPLOCK_LEVEL_2
:
487 case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE
:
488 case FSCTL_OPLOCK_BREAK_NOTIFY
:
490 /* We don't handle them */
491 Status
= STATUS_NOT_IMPLEMENTED
;
495 case FSCTL_LOCK_VOLUME
:
497 /* Make sure we're not locked, and that we're alone */
498 if (!(Vcb
->VcbState
& VCB_STATE_LOCKED
) && (Vcb
->OpenCount
== 1))
501 Vcb
->VcbState
|= VCB_STATE_LOCKED
;
502 Status
= STATUS_SUCCESS
;
506 /* Otherwise, we can't do this */
507 Status
= STATUS_ACCESS_DENIED
;
512 case FSCTL_UNLOCK_VOLUME
:
514 /* Make sure we're locked */
515 if (!(Vcb
->VcbState
& VCB_STATE_LOCKED
))
517 /* Let caller know we're not */
518 Status
= STATUS_NOT_LOCKED
;
523 Vcb
->VcbState
&= ~VCB_STATE_LOCKED
;
524 Status
= STATUS_SUCCESS
;
528 /* Dismount request */
529 case FSCTL_DISMOUNT_VOLUME
:
531 /* Make sure we're locked */
532 if (Vcb
->VcbState
& VCB_STATE_LOCKED
)
534 /* Do nothing, just return success */
535 Status
= STATUS_SUCCESS
;
539 /* We can't dismount, device not locked */
540 Status
= STATUS_ACCESS_DENIED
;
544 /* Unknown request */
548 Status
= STATUS_INVALID_PARAMETER
;
553 KeReleaseMutex(&Vcb
->Mutex
, FALSE
);
555 /* In case of status change, notify */
556 switch (IoStackLocation
->Parameters
.FileSystemControl
.FsControlCode
)
558 case FSCTL_LOCK_VOLUME
:
559 FsRtlNotifyVolumeEvent(IoStackLocation
->FileObject
, (NT_SUCCESS(Status
) ? FSRTL_VOLUME_LOCK
: FSRTL_VOLUME_LOCK_FAILED
));
561 case FSCTL_UNLOCK_VOLUME
:
562 if (NT_SUCCESS(Status
))
564 FsRtlNotifyVolumeEvent(IoStackLocation
->FileObject
, FSRTL_VOLUME_UNLOCK
);
567 case FSCTL_DISMOUNT_VOLUME
:
568 FsRtlNotifyVolumeEvent(IoStackLocation
->FileObject
, (NT_SUCCESS(Status
) ? FSRTL_VOLUME_DISMOUNT
: FSRTL_VOLUME_DISMOUNT_FAILED
));
577 RawFileSystemControl(IN PVCB Vcb
,
579 IN PIO_STACK_LOCATION IoStackLocation
)
584 DPRINT("RawFileSystemControl(%p, %p, %p)\n", Vcb
, Irp
, IoStackLocation
);
586 /* Check the kinds of FSCTLs that we support */
587 switch (IoStackLocation
->MinorFunction
)
589 /* User-mode request */
590 case IRP_MN_USER_FS_REQUEST
:
593 Status
= RawUserFsCtrl(IoStackLocation
, Vcb
);
597 case IRP_MN_MOUNT_VOLUME
:
599 /* Mount the volume */
600 Status
= RawMountVolume(IoStackLocation
);
603 case IRP_MN_VERIFY_VOLUME
:
605 /* Lock the device */
606 Status
= KeWaitForSingleObject(&Vcb
->Mutex
,
611 ASSERT(NT_SUCCESS(Status
));
613 /* We don't do verifies */
614 Status
= STATUS_WRONG_VOLUME
;
615 Vcb
->Vpb
->RealDevice
->Flags
&= ~DO_VERIFY_VOLUME
;
617 /* Check if we should delete the device */
618 if (Vcb
->OpenCount
!= 0 || !RawCheckForDismount(Vcb
, FALSE
))
620 /* In case of deletion, the mutex is already released */
621 KeReleaseMutex(&Vcb
->Mutex
, FALSE
);
627 /* Invalid request */
631 Status
= STATUS_INVALID_DEVICE_REQUEST
;
635 /* Complete the request */
636 Irp
->IoStatus
.Status
= Status
;
637 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
643 RawQueryInformation(IN PVCB Vcb
,
645 IN PIO_STACK_LOCATION IoStackLocation
)
647 NTSTATUS Status
= STATUS_INVALID_DEVICE_REQUEST
;
649 PFILE_POSITION_INFORMATION Buffer
;
652 DPRINT("RawQueryInformation(%p, %p, %p)\n", Vcb
, Irp
, IoStackLocation
);
654 /* Get information from the IRP */
655 Length
= &IoStackLocation
->Parameters
.QueryFile
.Length
;
656 Buffer
= Irp
->AssociatedIrp
.SystemBuffer
;
658 /* We only handle this request */
659 if (IoStackLocation
->Parameters
.QueryFile
.FileInformationClass
==
660 FilePositionInformation
)
662 /* Validate buffer size */
663 if (*Length
< sizeof(FILE_POSITION_INFORMATION
))
666 Irp
->IoStatus
.Information
= 0;
667 Status
= STATUS_BUFFER_OVERFLOW
;
671 /* Get offset and update length */
672 Buffer
->CurrentByteOffset
= IoStackLocation
->FileObject
->
674 *Length
-= sizeof(FILE_POSITION_INFORMATION
);
676 /* Set IRP Status information */
677 Irp
->IoStatus
.Information
= sizeof(FILE_POSITION_INFORMATION
);
678 Status
= STATUS_SUCCESS
;
683 Irp
->IoStatus
.Status
= Status
;
684 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
690 RawSetInformation(IN PVCB Vcb
,
692 IN PIO_STACK_LOCATION IoStackLocation
)
694 NTSTATUS Status
= STATUS_INVALID_DEVICE_REQUEST
;
695 PFILE_POSITION_INFORMATION Buffer
;
696 PDEVICE_OBJECT DeviceObject
;
699 DPRINT("RawSetInformation(%p, %p, %p)\n", Vcb
, Irp
, IoStackLocation
);
701 /* Get information from the IRP */
702 Buffer
= Irp
->AssociatedIrp
.SystemBuffer
;
704 /* We only handle this request */
705 if (IoStackLocation
->Parameters
.QueryFile
.FileInformationClass
==
706 FilePositionInformation
)
709 DeviceObject
= IoGetRelatedDeviceObject(IoStackLocation
->FileObject
);
711 /* Make sure the offset is aligned */
712 if ((Buffer
->CurrentByteOffset
.LowPart
&
713 DeviceObject
->AlignmentRequirement
))
716 Status
= STATUS_INVALID_PARAMETER
;
720 /* Otherwise, set offset */
721 IoStackLocation
->FileObject
->CurrentByteOffset
= Buffer
->
724 /* Set IRP Status information */
725 Status
= STATUS_SUCCESS
;
730 Irp
->IoStatus
.Status
= Status
;
731 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
737 RawQueryFsVolumeInfo(IN PVCB Vcb
,
738 IN PFILE_FS_VOLUME_INFORMATION Buffer
,
739 IN OUT PULONG Length
)
743 DPRINT("RawQueryFsVolumeInfo(%p, %p, %p)\n", Vcb
, Buffer
, Length
);
745 /* Clear the buffer and stub it out */
746 RtlZeroMemory(Buffer
, sizeof(FILE_FS_VOLUME_INFORMATION
));
747 Buffer
->VolumeSerialNumber
= Vcb
->Vpb
->SerialNumber
;
748 Buffer
->SupportsObjects
= FALSE
;
749 Buffer
->VolumeLabelLength
= 0;
751 /* Return length and success */
752 *Length
-= FIELD_OFFSET(FILE_FS_VOLUME_INFORMATION
, VolumeLabel
[0]);
753 return STATUS_SUCCESS
;
758 RawQueryFsSizeInfo(IN PVCB Vcb
,
759 IN PFILE_FS_SIZE_INFORMATION Buffer
,
760 IN OUT PULONG Length
)
765 IO_STATUS_BLOCK IoStatusBlock
;
766 PDEVICE_OBJECT RealDevice
;
767 DISK_GEOMETRY DiskGeometry
;
768 PARTITION_INFORMATION PartitionInformation
;
769 BOOLEAN DiskHasPartitions
;
772 DPRINT("RawQueryFsSizeInfo(%p, %p, %p)\n", Vcb
, Buffer
, Length
);
774 /* Validate the buffer */
775 if (*Length
< sizeof(FILE_FS_SIZE_INFORMATION
))
778 return STATUS_BUFFER_OVERFLOW
;
781 /* Clear the buffer, initialize the event and set the DO */
782 RtlZeroMemory(Buffer
, sizeof(FILE_FS_SIZE_INFORMATION
));
783 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
784 RealDevice
= Vcb
->Vpb
->RealDevice
;
786 /* Build query IRP */
787 Irp
= IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY
,
792 sizeof(DISK_GEOMETRY
),
796 if (!Irp
) return STATUS_INSUFFICIENT_RESOURCES
;
798 /* Call driver and check if we're pending */
799 Status
= IoCallDriver(RealDevice
, Irp
);
800 if (Status
== STATUS_PENDING
)
802 /* Wait on driver to finish */
803 KeWaitForSingleObject(&Event
,
808 Status
= IoStatusBlock
.Status
;
811 /* Fail if we couldn't get CHS data */
812 if (!NT_SUCCESS(Status
))
818 /* Check if this is a floppy */
819 if (FlagOn(RealDevice
->Characteristics
, FILE_FLOPPY_DISKETTE
))
821 /* Floppies don't have partitions */
822 DiskHasPartitions
= FALSE
;
826 /* Setup query IRP */
827 KeClearEvent(&Event
);
828 Irp
= IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO
,
832 &PartitionInformation
,
833 sizeof(PARTITION_INFORMATION
),
837 if (!Irp
) return STATUS_INSUFFICIENT_RESOURCES
;
839 /* Call driver and check if we're pending */
840 Status
= IoCallDriver(RealDevice
, Irp
);
841 if (Status
== STATUS_PENDING
)
843 /* Wait on driver to finish */
844 KeWaitForSingleObject(&Event
,
849 Status
= IoStatusBlock
.Status
;
852 /* If this was an invalid request, then the disk is not partitioned */
853 if (Status
== STATUS_INVALID_DEVICE_REQUEST
)
855 DiskHasPartitions
= FALSE
;
859 /* Otherwise, it must be */
860 ASSERT(NT_SUCCESS(Status
));
861 DiskHasPartitions
= TRUE
;
865 /* Set sector data */
866 Buffer
->BytesPerSector
= DiskGeometry
.BytesPerSector
;
867 Buffer
->SectorsPerAllocationUnit
= 1;
869 /* Calculate allocation units */
870 if (DiskHasPartitions
)
872 /* Use partition data */
873 Buffer
->TotalAllocationUnits
=
874 RtlExtendedLargeIntegerDivide(PartitionInformation
.PartitionLength
,
875 DiskGeometry
.BytesPerSector
,
881 Buffer
->TotalAllocationUnits
=
882 RtlExtendedIntegerMultiply(DiskGeometry
.Cylinders
,
883 DiskGeometry
.TracksPerCylinder
*
884 DiskGeometry
.SectorsPerTrack
);
887 /* Set available units */
888 Buffer
->AvailableAllocationUnits
= Buffer
->TotalAllocationUnits
;
890 /* Return length and success */
891 *Length
-= sizeof(FILE_FS_SIZE_INFORMATION
);
892 return STATUS_SUCCESS
;
897 RawQueryFsDeviceInfo(IN PVCB Vcb
,
898 IN PFILE_FS_DEVICE_INFORMATION Buffer
,
899 IN OUT PULONG Length
)
903 DPRINT("RawQueryFsDeviceInfo(%p, %p, %p)\n", Vcb
, Buffer
, Length
);
905 /* Validate buffer */
906 if (*Length
< sizeof(FILE_FS_DEVICE_INFORMATION
))
909 return STATUS_BUFFER_OVERFLOW
;
912 /* Clear buffer and write information */
913 RtlZeroMemory(Buffer
, sizeof(FILE_FS_DEVICE_INFORMATION
));
914 Buffer
->DeviceType
= FILE_DEVICE_DISK
;
915 Buffer
->Characteristics
= Vcb
->TargetDeviceObject
->Characteristics
;
917 /* Return length and success */
918 *Length
-= sizeof(FILE_FS_DEVICE_INFORMATION
);
919 return STATUS_SUCCESS
;
924 RawQueryFsAttributeInfo(IN PVCB Vcb
,
925 IN PFILE_FS_ATTRIBUTE_INFORMATION Buffer
,
926 IN OUT PULONG Length
)
928 const WCHAR szRawFSName
[] = L
"RAW";
932 DPRINT("RawQueryFsAttributeInfo(%p, %p, %p)\n", Vcb
, Buffer
, Length
);
934 /* Check if the buffer is large enough for our name ("RAW") */
935 ReturnLength
= FIELD_OFFSET(FILE_FS_ATTRIBUTE_INFORMATION
,
936 FileSystemName
[sizeof(szRawFSName
) / sizeof(szRawFSName
[0])]);
937 if (*Length
< ReturnLength
) return STATUS_BUFFER_OVERFLOW
;
939 /* Output the data */
940 Buffer
->FileSystemAttributes
= 0;
941 Buffer
->MaximumComponentNameLength
= 0;
942 Buffer
->FileSystemNameLength
= 6;
943 RtlCopyMemory(&Buffer
->FileSystemName
[0], szRawFSName
, sizeof(szRawFSName
));
945 /* Return length and success */
946 *Length
-= ReturnLength
;
947 return STATUS_SUCCESS
;
952 RawQueryVolumeInformation(IN PVCB Vcb
,
954 IN PIO_STACK_LOCATION IoStackLocation
)
961 DPRINT("RawQueryVolumeInformation(%p, %p, %p)\n", Vcb
, Irp
, IoStackLocation
);
964 Length
= IoStackLocation
->Parameters
.QueryVolume
.Length
;
965 Buffer
= Irp
->AssociatedIrp
.SystemBuffer
;
967 /* Check the kind of request */
968 switch (IoStackLocation
->Parameters
.QueryVolume
.FsInformationClass
)
970 /* Volume information request */
971 case FileFsVolumeInformation
:
973 Status
= RawQueryFsVolumeInfo(Vcb
, Buffer
, &Length
);
976 /* File system size invormation */
977 case FileFsSizeInformation
:
979 Status
= RawQueryFsSizeInfo(Vcb
, Buffer
, &Length
);
982 /* Device information */
983 case FileFsDeviceInformation
:
985 Status
= RawQueryFsDeviceInfo(Vcb
, Buffer
, &Length
);
988 /* Attribute information */
989 case FileFsAttributeInformation
:
991 Status
= RawQueryFsAttributeInfo(Vcb
, Buffer
, &Length
);
994 /* Invalid request */
998 Status
= STATUS_INVALID_PARAMETER
;
1002 /* Set status and complete the request */
1003 Irp
->IoStatus
.Information
= IoStackLocation
->
1004 Parameters
.QueryVolume
.Length
- Length
;
1005 Irp
->IoStatus
.Status
= Status
;
1006 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1012 RawCleanup(IN PVCB Vcb
,
1014 IN PIO_STACK_LOCATION IoStackLocation
)
1019 DPRINT("RawCleanup(%p, %p, %p)\n", Vcb
, Irp
, IoStackLocation
);
1021 /* Make sure we can clean up */
1022 Status
= KeWaitForSingleObject(&Vcb
->Mutex
,
1027 ASSERT(NT_SUCCESS(Status
));
1029 /* Remove shared access */
1030 IoRemoveShareAccess(IoStackLocation
->FileObject
, &Vcb
->ShareAccess
);
1032 /* Check if we're to dismount */
1033 if (Vcb
->VcbState
& VCB_STATE_DISMOUNTED
)
1035 ASSERT(Vcb
->OpenCount
== 1);
1036 RawCheckForDismount(Vcb
, FALSE
);
1039 KeReleaseMutex(&Vcb
->Mutex
, FALSE
);
1040 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1041 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1042 return STATUS_SUCCESS
;
1047 RawDispatch(IN PDEVICE_OBJECT DeviceObject
,
1050 PVOLUME_DEVICE_OBJECT VolumeDeviceObject
= (PVOLUME_DEVICE_OBJECT
)DeviceObject
;
1051 NTSTATUS Status
= STATUS_INVALID_DEVICE_REQUEST
;
1052 PIO_STACK_LOCATION IoStackLocation
;
1056 DPRINT("RawDispatch(%p, %p)\n", DeviceObject
, Irp
);
1058 /* Get the stack location */
1059 IoStackLocation
= IoGetCurrentIrpStackLocation(Irp
);
1061 /* Differentiate between Volume DO and FS DO */
1062 if ((DeviceObject
->Size
== sizeof(DEVICE_OBJECT
)) &&
1063 !((IoStackLocation
->MajorFunction
== IRP_MJ_FILE_SYSTEM_CONTROL
) &&
1064 (IoStackLocation
->MinorFunction
== IRP_MN_MOUNT_VOLUME
)))
1066 /* This is an FS DO. Stub out the common calls */
1067 if ((IoStackLocation
->MajorFunction
== IRP_MJ_CREATE
) ||
1068 (IoStackLocation
->MajorFunction
== IRP_MJ_CLEANUP
) ||
1069 (IoStackLocation
->MajorFunction
== IRP_MJ_CLOSE
))
1071 /* Return success for them */
1072 Status
= STATUS_SUCCESS
;
1076 /* Anything else, we don't support */
1077 Status
= STATUS_INVALID_DEVICE_REQUEST
;
1080 /* Complete the request */
1081 Irp
->IoStatus
.Status
= Status
;
1082 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1086 /* Otherwise, get our VCB and start handling the IRP */
1087 FsRtlEnterFileSystem();
1088 Vcb
= &VolumeDeviceObject
->Vcb
;
1090 /* Check what kind of IRP this is */
1091 switch (IoStackLocation
->MajorFunction
)
1093 /* Cleanup request */
1094 case IRP_MJ_CLEANUP
:
1096 Status
= RawCleanup(Vcb
, Irp
, IoStackLocation
);
1102 Status
= RawClose(Vcb
, Irp
, IoStackLocation
);
1105 /* Create request */
1108 Status
= RawCreate(Vcb
, Irp
, IoStackLocation
);
1112 case IRP_MJ_FILE_SYSTEM_CONTROL
:
1114 Status
= RawFileSystemControl(Vcb
, Irp
, IoStackLocation
);
1117 /* R/W or IOCTL request */
1120 case IRP_MJ_DEVICE_CONTROL
:
1122 Status
= RawReadWriteDeviceControl(Vcb
, Irp
, IoStackLocation
);
1125 /* Information query request */
1126 case IRP_MJ_QUERY_INFORMATION
:
1128 Status
= RawQueryInformation(Vcb
, Irp
, IoStackLocation
);
1131 /* Information set request */
1132 case IRP_MJ_SET_INFORMATION
:
1134 Status
= RawSetInformation(Vcb
, Irp
, IoStackLocation
);
1137 /* Volume information request */
1138 case IRP_MJ_QUERY_VOLUME_INFORMATION
:
1140 Status
= RawQueryVolumeInformation(Vcb
, Irp
, IoStackLocation
);
1143 /* Unexpected request */
1146 /* Anything else is pretty bad */
1147 KeBugCheck(FILE_SYSTEM
);
1150 /* Return the status */
1151 FsRtlExitFileSystem();
1157 RawShutdown(IN PDEVICE_OBJECT DeviceObject
,
1160 /* Unregister file systems */
1161 #if 0 // FIXME: This freezes ROS at shutdown. PnP Problem?
1162 IoUnregisterFileSystem(RawDiskDeviceObject
);
1163 IoUnregisterFileSystem(RawCdromDeviceObject
);
1164 IoUnregisterFileSystem(RawTapeDeviceObject
);
1166 /* Delete the devices */
1167 IoDeleteDevice(RawDiskDeviceObject
);
1168 IoDeleteDevice(RawCdromDeviceObject
);
1169 IoDeleteDevice(RawTapeDeviceObject
);
1172 /* Complete the request */
1173 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1174 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1175 return STATUS_SUCCESS
;
1180 RawUnload(IN PDRIVER_OBJECT DriverObject
)
1182 #if 0 // FIXME: DriverUnload is never called
1183 /* Dereference device objects */
1184 ObDereferenceObject(RawDiskDeviceObject
);
1185 ObDereferenceObject(RawCdromDeviceObject
);
1186 ObDereferenceObject(RawTapeDeviceObject
);
1193 RawFsDriverEntry(IN PDRIVER_OBJECT DriverObject
,
1194 IN PUNICODE_STRING RegistryPath
)
1196 UNICODE_STRING DeviceName
;
1199 /* Create the raw disk device */
1200 RtlInitUnicodeString(&DeviceName
, L
"\\Device\\RawDisk");
1201 Status
= IoCreateDevice(DriverObject
,
1204 FILE_DEVICE_DISK_FILE_SYSTEM
,
1207 &RawDiskDeviceObject
);
1208 if (!NT_SUCCESS(Status
)) return Status
;
1210 /* Create the raw CDROM device */
1211 RtlInitUnicodeString(&DeviceName
, L
"\\Device\\RawCdRom");
1212 Status
= IoCreateDevice(DriverObject
,
1215 FILE_DEVICE_CD_ROM_FILE_SYSTEM
,
1218 &RawCdromDeviceObject
);
1219 if (!NT_SUCCESS(Status
)) return Status
;
1221 /* Create the raw tape device */
1222 RtlInitUnicodeString(&DeviceName
, L
"\\Device\\RawTape");
1223 Status
= IoCreateDevice(DriverObject
,
1226 FILE_DEVICE_TAPE_FILE_SYSTEM
,
1229 &RawTapeDeviceObject
);
1230 if (!NT_SUCCESS(Status
)) return Status
;
1232 /* Set Direct I/O for all devices */
1233 RawDiskDeviceObject
->Flags
|= DO_DIRECT_IO
;
1234 RawCdromDeviceObject
->Flags
|= DO_DIRECT_IO
;
1235 RawTapeDeviceObject
->Flags
|= DO_DIRECT_IO
;
1237 /* Set generic stubs */
1238 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] =
1239 DriverObject
->MajorFunction
[IRP_MJ_CLEANUP
] =
1240 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] =
1241 DriverObject
->MajorFunction
[IRP_MJ_READ
] =
1242 DriverObject
->MajorFunction
[IRP_MJ_WRITE
] =
1243 DriverObject
->MajorFunction
[IRP_MJ_QUERY_INFORMATION
] =
1244 DriverObject
->MajorFunction
[IRP_MJ_SET_INFORMATION
] =
1245 DriverObject
->MajorFunction
[IRP_MJ_QUERY_VOLUME_INFORMATION
] =
1246 DriverObject
->MajorFunction
[IRP_MJ_FILE_SYSTEM_CONTROL
] =
1247 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = RawDispatch
;
1249 /* Shutdown and unload */
1250 DriverObject
->MajorFunction
[IRP_MJ_SHUTDOWN
] = RawShutdown
;
1251 DriverObject
->DriverUnload
= RawUnload
;
1253 /* Register the file systems */
1254 IoRegisterFileSystem(RawDiskDeviceObject
);
1255 IoRegisterFileSystem(RawCdromDeviceObject
);
1256 IoRegisterFileSystem(RawTapeDeviceObject
);
1258 #if 0 // FIXME: DriverUnload is never called
1259 /* Reference device objects */
1260 ObReferenceObject(RawDiskDeviceObject
);
1261 ObReferenceObject(RawCdromDeviceObject
);
1262 ObReferenceObject(RawTapeDeviceObject
);
1264 return STATUS_SUCCESS
;