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
;
111 /* Don't do anything */
116 /* Otherwise, delete the volume */
119 /* Check if it has a VPB and unmount it */
120 if (Vpb
->RealDevice
->Vpb
== Vpb
)
122 Vpb
->DeviceObject
= NULL
;
123 Vpb
->Flags
&= ~VPB_MOUNTED
;
127 /* Release lock and return status */
128 IoReleaseVpbSpinLock(OldIrql
);
130 /* If we were to delete, delete volume */
135 /* Release our Vcb lock to be able delete us */
136 KeReleaseMutex(&Vcb
->Mutex
, 0);
138 /* If we have a local VPB, we'll have to delete it
139 * but we won't dismount us - something went bad before
143 DelVpb
= Vcb
->LocalVpb
;
145 /* Otherwise, dismount our device if possible */
148 if (Vcb
->Vpb
->ReferenceCount
)
150 ObfDereferenceObject(Vcb
->TargetDeviceObject
);
151 IoDeleteDevice((PDEVICE_OBJECT
)CONTAINING_RECORD(Vcb
,
152 VOLUME_DEVICE_OBJECT
,
160 /* Delete any of the available VPB and dismount */
162 ObfDereferenceObject(Vcb
->TargetDeviceObject
);
163 IoDeleteDevice((PDEVICE_OBJECT
)CONTAINING_RECORD(Vcb
,
164 VOLUME_DEVICE_OBJECT
,
175 RawCompletionRoutine(IN PDEVICE_OBJECT DeviceObject
,
179 PIO_STACK_LOCATION IoStackLocation
= IoGetCurrentIrpStackLocation(Irp
);
181 DPRINT("RawCompletionRoutine(%p, %p, %p)\n", DeviceObject
, Irp
, Context
);
183 /* Check if this was a valid sync R/W request */
184 if (((IoStackLocation
->MajorFunction
== IRP_MJ_READ
) ||
185 (IoStackLocation
->MajorFunction
== IRP_MJ_WRITE
)) &&
186 ((IoStackLocation
->FileObject
)) &&
187 (FlagOn(IoStackLocation
->FileObject
->Flags
, FO_SYNCHRONOUS_IO
)) &&
188 (NT_SUCCESS(Irp
->IoStatus
.Status
)))
190 /* Update byte offset */
191 IoStackLocation
->FileObject
->CurrentByteOffset
.QuadPart
+=
192 Irp
->IoStatus
.Information
;
195 /* Mark the IRP Pending if it was */
196 if (Irp
->PendingReturned
) IoMarkIrpPending(Irp
);
197 return STATUS_SUCCESS
;
202 RawClose(IN PVCB Vcb
,
204 IN PIO_STACK_LOCATION IoStackLocation
)
209 DPRINT("RawClose(%p, %p, %p)\n", Vcb
, Irp
, IoStackLocation
);
211 /* If its a stream, not much to do */
212 if (IoStackLocation
->FileObject
->Flags
& FO_STREAM_FILE
)
214 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
215 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
216 return STATUS_SUCCESS
;
219 /* Make sure we can clean up */
220 Status
= KeWaitForSingleObject(&Vcb
->Mutex
,
225 ASSERT(NT_SUCCESS(Status
));
227 /* Decrease the open count and check if this is a dismount */
229 if (!Vcb
->OpenCount
|| !RawCheckForDismount(Vcb
, FALSE
))
231 KeReleaseMutex(&Vcb
->Mutex
, FALSE
);
234 /* Complete the request */
235 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
236 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
237 return STATUS_SUCCESS
;
242 RawCreate(IN PVCB Vcb
,
244 IN PIO_STACK_LOCATION IoStackLocation
)
248 ACCESS_MASK DesiredAccess
;
249 BOOLEAN Deleted
= FALSE
;
252 DPRINT("RawCreate(%p, %p, %p)\n", Vcb
, Irp
, IoStackLocation
);
254 /* Make sure we can clean up */
255 Status
= KeWaitForSingleObject(&Vcb
->Mutex
,
260 ASSERT(NT_SUCCESS(Status
));
262 /* Check if this is a valid non-directory file open */
263 if ((!(IoStackLocation
->FileObject
) ||
264 !(IoStackLocation
->FileObject
->FileName
.Length
)) &&
265 ((IoStackLocation
->Parameters
.Create
.Options
>> 24) == FILE_OPEN
) &&
266 (!(IoStackLocation
->Parameters
.Create
.Options
& FILE_DIRECTORY_FILE
)))
268 /* Make sure the VCB isn't locked */
269 if (Vcb
->VcbState
& VCB_STATE_LOCKED
)
271 /* Refuse the operation */
272 Status
= STATUS_ACCESS_DENIED
;
273 Irp
->IoStatus
.Information
= 0;
275 else if (Vcb
->VcbState
& VCB_STATE_DISMOUNTED
)
277 /* Refuse the operation */
278 Status
= STATUS_VOLUME_DISMOUNTED
;
279 Irp
->IoStatus
.Information
= 0;
283 /* Setup share access */
284 ShareAccess
= IoStackLocation
->Parameters
.Create
.ShareAccess
;
285 DesiredAccess
= IoStackLocation
->Parameters
.Create
.
286 SecurityContext
->DesiredAccess
;
288 /* Check if this VCB was already opened */
289 if (Vcb
->OpenCount
> 0)
291 /* Try to see if we have access to it */
292 Status
= IoCheckShareAccess(DesiredAccess
,
294 IoStackLocation
->FileObject
,
297 if (!NT_SUCCESS(Status
)) Irp
->IoStatus
.Information
= 0;
300 /* Make sure we have access */
301 if (NT_SUCCESS(Status
))
303 /* Check if this is the first open */
306 /* Set the share access */
307 IoSetShareAccess(DesiredAccess
,
309 IoStackLocation
->FileObject
,
313 /* Increase the open count and set the VPB */
315 IoStackLocation
->FileObject
->Vpb
= Vcb
->Vpb
;
317 /* Set IRP status and disable intermediate buffering */
318 Status
= STATUS_SUCCESS
;
319 Irp
->IoStatus
.Information
= FILE_OPENED
;
320 IoStackLocation
->FileObject
->Flags
|=
321 FO_NO_INTERMEDIATE_BUFFERING
;
327 /* Invalid create request */
328 Status
= STATUS_INVALID_PARAMETER
;
329 Irp
->IoStatus
.Information
= 0;
332 /* Check if the request failed */
333 if (!(NT_SUCCESS(Status
)) && !(Vcb
->OpenCount
))
335 /* Check if we can dismount the device */
336 Deleted
= RawCheckForDismount(Vcb
, TRUE
);
339 /* In case of deletion, the mutex is already released */
342 KeReleaseMutex(&Vcb
->Mutex
, FALSE
);
345 /* Complete the request */
346 Irp
->IoStatus
.Status
= Status
;
347 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
353 RawReadWriteDeviceControl(IN PVCB Vcb
,
355 IN PIO_STACK_LOCATION IoStackLocation
)
360 DPRINT("RawReadWriteDeviceControl(%p, %p, %p)\n", Vcb
, Irp
, IoStackLocation
);
362 /* Don't do anything if the request was 0 bytes */
363 if (((IoStackLocation
->MajorFunction
== IRP_MJ_READ
) ||
364 (IoStackLocation
->MajorFunction
== IRP_MJ_WRITE
)) &&
365 !(IoStackLocation
->Parameters
.Read
.Length
))
368 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
369 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
370 return STATUS_SUCCESS
;
373 /* Copy the IRP stack location */
374 IoCopyCurrentIrpStackLocationToNext(Irp
);
376 /* Disable verifies */
377 IoGetNextIrpStackLocation(Irp
)->Flags
|= SL_OVERRIDE_VERIFY_VOLUME
;
379 /* Setup a completion routine */
380 IoSetCompletionRoutine(Irp
,
381 RawCompletionRoutine
,
387 /* Call the next driver and exit */
388 Status
= IoCallDriver(Vcb
->TargetDeviceObject
, Irp
);
394 RawMountVolume(IN PIO_STACK_LOCATION IoStackLocation
)
397 PDEVICE_OBJECT DeviceObject
;
398 PVOLUME_DEVICE_OBJECT Volume
;
399 PFILE_OBJECT FileObject
= NULL
;
402 DPRINT("RawMountVolume(%p)\n", IoStackLocation
);
404 /* Remember our owner */
405 DeviceObject
= IoStackLocation
->Parameters
.MountVolume
.DeviceObject
;
407 /* Create the volume */
408 Status
= IoCreateDevice(RawDiskDeviceObject
->DriverObject
,
409 sizeof(VOLUME_DEVICE_OBJECT
) -
410 sizeof(DEVICE_OBJECT
),
412 FILE_DEVICE_DISK_FILE_SYSTEM
,
415 (PDEVICE_OBJECT
*)&Volume
);
416 if (!NT_SUCCESS(Status
)) return Status
;
418 /* Use highest alignment requirement */
419 Volume
->DeviceObject
.AlignmentRequirement
= max(DeviceObject
->
420 AlignmentRequirement
,
421 Volume
->DeviceObject
.
422 AlignmentRequirement
);
425 Status
= RawInitializeVcb(&Volume
->Vcb
,
426 IoStackLocation
->Parameters
.MountVolume
.DeviceObject
,
427 IoStackLocation
->Parameters
.MountVolume
.Vpb
);
428 if (!NT_SUCCESS(Status
))
430 IoDeleteDevice((PDEVICE_OBJECT
)Volume
);
434 /* Set dummy label and serial number */
435 Volume
->Vcb
.Vpb
->SerialNumber
= 0xFFFFFFFF;
436 Volume
->Vcb
.Vpb
->VolumeLabelLength
= 0;
439 Volume
->Vcb
.Vpb
->DeviceObject
= &Volume
->DeviceObject
;
440 Volume
->DeviceObject
.StackSize
= DeviceObject
->StackSize
+ 1;
441 Volume
->DeviceObject
.SectorSize
= DeviceObject
->SectorSize
;
442 Volume
->DeviceObject
.Flags
|= DO_DIRECT_IO
;
443 Volume
->DeviceObject
.Flags
&= ~DO_DEVICE_INITIALIZING
;
445 /* Try to get associated FO (for notification) */
448 FileObject
= IoCreateStreamFileObjectLite(NULL
,
449 &(Volume
->DeviceObject
));
451 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
453 /* Get the exception code */
454 Status
= _SEH2_GetExceptionCode();
458 /* If failed, delete devive */
459 if (!NT_SUCCESS(Status
))
461 IoDeleteDevice((PDEVICE_OBJECT
)Volume
);
465 /* Increment OpenCount by two to avoid dismount when RawClose() will be called on ObDereferenceObject() */
466 Volume
->Vcb
.OpenCount
+= 2;
467 /* Notify for sucessful mount */
468 FsRtlNotifyVolumeEvent(FileObject
, FSRTL_VOLUME_MOUNT
);
469 /* Decrease refcount to 0 to make FileObject being released */
470 ObDereferenceObject(FileObject
);
471 /* It's not open anymore, go back to 0 */
472 Volume
->Vcb
.OpenCount
-= 2;
479 RawUserFsCtrl(IN PIO_STACK_LOCATION IoStackLocation
,
485 DPRINT("RawUserFsCtrl(%p, %p)\n", IoStackLocation
, Vcb
);
487 /* Lock the device */
488 Status
= KeWaitForSingleObject(&Vcb
->Mutex
,
493 ASSERT(NT_SUCCESS(Status
));
495 /* Check what kind of request this is */
496 switch (IoStackLocation
->Parameters
.FileSystemControl
.FsControlCode
)
498 /* Oplock requests */
499 case FSCTL_REQUEST_OPLOCK_LEVEL_1
:
500 case FSCTL_REQUEST_OPLOCK_LEVEL_2
:
501 case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE
:
502 case FSCTL_OPLOCK_BREAK_NOTIFY
:
504 /* We don't handle them */
505 Status
= STATUS_NOT_IMPLEMENTED
;
509 case FSCTL_LOCK_VOLUME
:
511 /* Make sure we're not locked, and that we're alone */
512 if (!(Vcb
->VcbState
& 1) && (Vcb
->OpenCount
== 1))
516 Status
= STATUS_SUCCESS
;
520 /* Otherwise, we can't do this */
521 Status
= STATUS_ACCESS_DENIED
;
526 case FSCTL_UNLOCK_VOLUME
:
528 /* Make sure we're locked */
529 if (!(Vcb
->VcbState
& 1))
531 /* Let caller know we're not */
532 Status
= STATUS_NOT_LOCKED
;
538 Status
= STATUS_SUCCESS
;
542 /* Dismount request */
543 case FSCTL_DISMOUNT_VOLUME
:
545 /* Make sure we're locked */
546 if (Vcb
->VcbState
& 1)
548 /* Do nothing, just return success */
549 Status
= STATUS_SUCCESS
;
553 /* We can't dismount, device not locked */
554 Status
= STATUS_ACCESS_DENIED
;
558 /* Unknown request */
562 Status
= STATUS_INVALID_PARAMETER
;
567 KeReleaseMutex(&Vcb
->Mutex
, FALSE
);
569 /* In case of status change, notify */
570 switch (IoStackLocation
->Parameters
.FileSystemControl
.FsControlCode
)
572 case FSCTL_LOCK_VOLUME
:
573 FsRtlNotifyVolumeEvent(IoStackLocation
->FileObject
, (NT_SUCCESS(Status
) ? FSRTL_VOLUME_LOCK
: FSRTL_VOLUME_LOCK_FAILED
));
575 case FSCTL_UNLOCK_VOLUME
:
576 if (NT_SUCCESS(Status
))
578 FsRtlNotifyVolumeEvent(IoStackLocation
->FileObject
, FSRTL_VOLUME_UNLOCK
);
581 case FSCTL_DISMOUNT_VOLUME
:
582 FsRtlNotifyVolumeEvent(IoStackLocation
->FileObject
, (NT_SUCCESS(Status
) ? FSRTL_VOLUME_DISMOUNT
: FSRTL_VOLUME_DISMOUNT_FAILED
));
591 RawFileSystemControl(IN PVCB Vcb
,
593 IN PIO_STACK_LOCATION IoStackLocation
)
598 DPRINT("RawFileSystemControl(%p, %p, %p)\n", Vcb
, Irp
, IoStackLocation
);
600 /* Check the kinds of FSCTLs that we support */
601 switch (IoStackLocation
->MinorFunction
)
603 /* User-mode request */
604 case IRP_MN_USER_FS_REQUEST
:
607 Status
= RawUserFsCtrl(IoStackLocation
, Vcb
);
611 case IRP_MN_MOUNT_VOLUME
:
613 /* Mount the volume */
614 Status
= RawMountVolume(IoStackLocation
);
617 case IRP_MN_VERIFY_VOLUME
:
619 /* We don't do verifies */
620 Status
= STATUS_WRONG_VOLUME
;
621 Vcb
->Vpb
->RealDevice
->Flags
&= ~DO_VERIFY_VOLUME
;
623 /* Check if we should delete the device */
624 if (RawCheckForDismount(Vcb
, FALSE
))
627 IoDeleteDevice((PDEVICE_OBJECT
)
628 CONTAINING_RECORD(Vcb
,
629 VOLUME_DEVICE_OBJECT
,
636 /* Invalid request */
640 Status
= STATUS_INVALID_DEVICE_REQUEST
;
644 /* Complete the request */
645 Irp
->IoStatus
.Status
= Status
;
646 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
652 RawQueryInformation(IN PVCB Vcb
,
654 IN PIO_STACK_LOCATION IoStackLocation
)
656 NTSTATUS Status
= STATUS_INVALID_DEVICE_REQUEST
;
658 PFILE_POSITION_INFORMATION Buffer
;
661 DPRINT("RawQueryInformation(%p, %p, %p)\n", Vcb
, Irp
, IoStackLocation
);
663 /* Get information from the IRP */
664 Length
= &IoStackLocation
->Parameters
.QueryFile
.Length
;
665 Buffer
= Irp
->AssociatedIrp
.SystemBuffer
;
667 /* We only handle this request */
668 if (IoStackLocation
->Parameters
.QueryFile
.FileInformationClass
==
669 FilePositionInformation
)
671 /* Validate buffer size */
672 if (*Length
< sizeof(FILE_POSITION_INFORMATION
))
675 Irp
->IoStatus
.Information
= 0;
676 Status
= STATUS_BUFFER_OVERFLOW
;
680 /* Get offset and update length */
681 Buffer
->CurrentByteOffset
= IoStackLocation
->FileObject
->
683 *Length
-= sizeof(FILE_POSITION_INFORMATION
);
685 /* Set IRP Status information */
686 Irp
->IoStatus
.Information
= sizeof(FILE_POSITION_INFORMATION
);
687 Status
= STATUS_SUCCESS
;
692 Irp
->IoStatus
.Status
= Status
;
693 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
699 RawSetInformation(IN PVCB Vcb
,
701 IN PIO_STACK_LOCATION IoStackLocation
)
703 NTSTATUS Status
= STATUS_INVALID_DEVICE_REQUEST
;
704 PFILE_POSITION_INFORMATION Buffer
;
705 PDEVICE_OBJECT DeviceObject
;
708 DPRINT("RawSetInformation(%p, %p, %p)\n", Vcb
, Irp
, IoStackLocation
);
710 /* Get information from the IRP */
711 Buffer
= Irp
->AssociatedIrp
.SystemBuffer
;
713 /* We only handle this request */
714 if (IoStackLocation
->Parameters
.QueryFile
.FileInformationClass
==
715 FilePositionInformation
)
718 DeviceObject
= IoGetRelatedDeviceObject(IoStackLocation
->FileObject
);
720 /* Make sure the offset is aligned */
721 if ((Buffer
->CurrentByteOffset
.LowPart
&
722 DeviceObject
->AlignmentRequirement
))
725 Status
= STATUS_INVALID_PARAMETER
;
729 /* Otherwise, set offset */
730 IoStackLocation
->FileObject
->CurrentByteOffset
= Buffer
->
733 /* Set IRP Status information */
734 Status
= STATUS_SUCCESS
;
739 Irp
->IoStatus
.Status
= Status
;
740 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
746 RawQueryFsVolumeInfo(IN PVCB Vcb
,
747 IN PFILE_FS_VOLUME_INFORMATION Buffer
,
748 IN OUT PULONG Length
)
752 DPRINT("RawQueryFsVolumeInfo(%p, %p, %p)\n", Vcb
, Buffer
, Length
);
754 /* Clear the buffer and stub it out */
755 RtlZeroMemory( Buffer
, sizeof(FILE_FS_VOLUME_INFORMATION
));
756 Buffer
->VolumeSerialNumber
= Vcb
->Vpb
->SerialNumber
;
757 Buffer
->SupportsObjects
= FALSE
;
758 Buffer
->VolumeLabelLength
= 0;
760 /* Return length and success */
761 *Length
-= FIELD_OFFSET(FILE_FS_VOLUME_INFORMATION
, VolumeLabel
[0]);
762 return STATUS_SUCCESS
;
767 RawQueryFsSizeInfo(IN PVCB Vcb
,
768 IN PFILE_FS_SIZE_INFORMATION Buffer
,
769 IN OUT PULONG Length
)
774 IO_STATUS_BLOCK IoStatusBlock
;
775 PDEVICE_OBJECT RealDevice
;
776 DISK_GEOMETRY DiskGeometry
;
777 PARTITION_INFORMATION PartitionInformation
;
778 BOOLEAN DiskHasPartitions
;
781 DPRINT("RawQueryFsSizeInfo(%p, %p, %p)\n", Vcb
, Buffer
, Length
);
783 /* Validate the buffer */
784 if (*Length
< sizeof(FILE_FS_SIZE_INFORMATION
))
787 return STATUS_BUFFER_OVERFLOW
;
790 /* Clear the buffer, initialize the event and set the DO */
791 RtlZeroMemory(Buffer
, sizeof(FILE_FS_SIZE_INFORMATION
));
792 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
793 RealDevice
= Vcb
->Vpb
->RealDevice
;
795 /* Build query IRP */
796 Irp
= IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY
,
801 sizeof(DISK_GEOMETRY
),
805 if (!Irp
) return STATUS_INSUFFICIENT_RESOURCES
;
807 /* Call driver and check if we're pending */
808 Status
= IoCallDriver(RealDevice
, Irp
);
809 if (Status
== STATUS_PENDING
)
811 /* Wait on driver to finish */
812 KeWaitForSingleObject(&Event
,
817 Status
= IoStatusBlock
.Status
;
820 /* Fail if we couldn't get CHS data */
821 if (!NT_SUCCESS(Status
))
827 /* Check if this is a floppy */
828 if (FlagOn(RealDevice
->Characteristics
, FILE_FLOPPY_DISKETTE
))
830 /* Floppies don't have partitions */
831 DiskHasPartitions
= FALSE
;
835 /* Setup query IRP */
836 KeResetEvent(&Event
);
837 Irp
= IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO
,
841 &PartitionInformation
,
842 sizeof(PARTITION_INFORMATION
),
846 if (!Irp
) return STATUS_INSUFFICIENT_RESOURCES
;
848 /* Call driver and check if we're pending */
849 Status
= IoCallDriver(RealDevice
, Irp
);
850 if (Status
== STATUS_PENDING
)
852 /* Wait on driver to finish */
853 KeWaitForSingleObject(&Event
,
858 Status
= IoStatusBlock
.Status
;
861 /* If this was an invalid request, then the disk is not partitioned */
862 if (Status
== STATUS_INVALID_DEVICE_REQUEST
)
864 DiskHasPartitions
= FALSE
;
868 /* Otherwise, it must be */
869 ASSERT(NT_SUCCESS(Status
));
870 DiskHasPartitions
= TRUE
;
874 /* Set sector data */
875 Buffer
->BytesPerSector
= DiskGeometry
.BytesPerSector
;
876 Buffer
->SectorsPerAllocationUnit
= 1;
878 /* Calculate allocation units */
879 if (DiskHasPartitions
)
881 /* Use partition data */
882 Buffer
->TotalAllocationUnits
=
883 RtlExtendedLargeIntegerDivide(PartitionInformation
.PartitionLength
,
884 DiskGeometry
.BytesPerSector
,
890 Buffer
->TotalAllocationUnits
=
891 RtlExtendedIntegerMultiply(DiskGeometry
.Cylinders
,
892 DiskGeometry
.TracksPerCylinder
*
893 DiskGeometry
.SectorsPerTrack
);
896 /* Set available units */
897 Buffer
->AvailableAllocationUnits
= Buffer
->TotalAllocationUnits
;
899 /* Return length and success */
900 *Length
-= sizeof(FILE_FS_SIZE_INFORMATION
);
901 return STATUS_SUCCESS
;
906 RawQueryFsDeviceInfo(IN PVCB Vcb
,
907 IN PFILE_FS_DEVICE_INFORMATION Buffer
,
908 IN OUT PULONG Length
)
912 DPRINT("RawQueryFsDeviceInfo(%p, %p, %p)\n", Vcb
, Buffer
, Length
);
914 /* Validate buffer */
915 if (*Length
< sizeof(FILE_FS_DEVICE_INFORMATION
))
918 return STATUS_BUFFER_OVERFLOW
;
921 /* Clear buffer and write information */
922 RtlZeroMemory(Buffer
, sizeof(FILE_FS_DEVICE_INFORMATION
));
923 Buffer
->DeviceType
= FILE_DEVICE_DISK
;
924 Buffer
->Characteristics
= Vcb
->TargetDeviceObject
->Characteristics
;
926 /* Return length and success */
927 *Length
-= sizeof(FILE_FS_DEVICE_INFORMATION
);
928 return STATUS_SUCCESS
;
933 RawQueryFsAttributeInfo(IN PVCB Vcb
,
934 IN PFILE_FS_ATTRIBUTE_INFORMATION Buffer
,
935 IN OUT PULONG Length
)
937 const WCHAR szRawFSName
[] = L
"RAW";
941 DPRINT("RawQueryFsAttributeInfo(%p, %p, %p)\n", Vcb
, Buffer
, Length
);
943 /* Check if the buffer is large enough for our name ("RAW") */
944 ReturnLength
= FIELD_OFFSET(FILE_FS_ATTRIBUTE_INFORMATION
,
945 FileSystemName
[sizeof(szRawFSName
) / sizeof(szRawFSName
[0])]);
946 if (*Length
< ReturnLength
) return STATUS_BUFFER_OVERFLOW
;
948 /* Output the data */
949 Buffer
->FileSystemAttributes
= 0;
950 Buffer
->MaximumComponentNameLength
= 0;
951 Buffer
->FileSystemNameLength
= 6;
952 RtlCopyMemory(&Buffer
->FileSystemName
[0], szRawFSName
, sizeof(szRawFSName
));
954 /* Return length and success */
955 *Length
-= ReturnLength
;
956 return STATUS_SUCCESS
;
961 RawQueryVolumeInformation(IN PVCB Vcb
,
963 IN PIO_STACK_LOCATION IoStackLocation
)
970 DPRINT("RawQueryVolumeInformation(%p, %p, %p)\n", Vcb
, Irp
, IoStackLocation
);
973 Length
= IoStackLocation
->Parameters
.QueryVolume
.Length
;
974 Buffer
= Irp
->AssociatedIrp
.SystemBuffer
;
976 /* Check the kind of request */
977 switch (IoStackLocation
->Parameters
.QueryVolume
.FsInformationClass
)
979 /* Volume information request */
980 case FileFsVolumeInformation
:
982 Status
= RawQueryFsVolumeInfo(Vcb
, Buffer
, &Length
);
985 /* File system size invormation */
986 case FileFsSizeInformation
:
988 Status
= RawQueryFsSizeInfo(Vcb
, Buffer
, &Length
);
991 /* Device information */
992 case FileFsDeviceInformation
:
994 Status
= RawQueryFsDeviceInfo(Vcb
, Buffer
, &Length
);
997 /* Attribute information */
998 case FileFsAttributeInformation
:
1000 Status
= RawQueryFsAttributeInfo(Vcb
, Buffer
, &Length
);
1003 /* Invalid request */
1007 Status
= STATUS_INVALID_PARAMETER
;
1011 /* Set status and complete the request */
1012 Irp
->IoStatus
.Information
= IoStackLocation
->
1013 Parameters
.QueryVolume
.Length
- Length
;
1014 Irp
->IoStatus
.Status
= Status
;
1015 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1021 RawCleanup(IN PVCB Vcb
,
1023 IN PIO_STACK_LOCATION IoStackLocation
)
1028 DPRINT("RawCleanup(%p, %p, %p)\n", Vcb
, Irp
, IoStackLocation
);
1030 /* Make sure we can clean up */
1031 Status
= KeWaitForSingleObject(&Vcb
->Mutex
,
1036 ASSERT(NT_SUCCESS(Status
));
1038 /* Remove shared access */
1039 IoRemoveShareAccess(IoStackLocation
->FileObject
, &Vcb
->ShareAccess
);
1041 /* Check if we're to dismount */
1042 if (Vcb
->VcbState
& VCB_STATE_DISMOUNTED
)
1044 ASSERT(Vcb
->OpenCount
== 1);
1045 RawCheckForDismount(Vcb
, FALSE
);
1048 KeReleaseMutex(&Vcb
->Mutex
, FALSE
);
1049 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1050 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1051 return STATUS_SUCCESS
;
1056 RawDispatch(IN PDEVICE_OBJECT DeviceObject
,
1059 PVOLUME_DEVICE_OBJECT VolumeDeviceObject
= (PVOLUME_DEVICE_OBJECT
)DeviceObject
;
1060 NTSTATUS Status
= STATUS_INVALID_DEVICE_REQUEST
;
1061 PIO_STACK_LOCATION IoStackLocation
;
1065 DPRINT("RawDispatch(%p, %p)\n", DeviceObject
, Irp
);
1067 /* Get the stack location */
1068 IoStackLocation
= IoGetCurrentIrpStackLocation(Irp
);
1070 /* Differentiate between Volume DO and FS DO */
1071 if ((DeviceObject
->Size
== sizeof(DEVICE_OBJECT
)) &&
1072 !((IoStackLocation
->MajorFunction
== IRP_MJ_FILE_SYSTEM_CONTROL
) &&
1073 (IoStackLocation
->MinorFunction
== IRP_MN_MOUNT_VOLUME
)))
1075 /* This is an FS DO. Stub out the common calls */
1076 if ((IoStackLocation
->MajorFunction
== IRP_MJ_CREATE
) ||
1077 (IoStackLocation
->MajorFunction
== IRP_MJ_CLEANUP
) ||
1078 (IoStackLocation
->MajorFunction
== IRP_MJ_CLOSE
))
1080 /* Return success for them */
1081 Status
= STATUS_SUCCESS
;
1085 /* Anything else, we don't support */
1086 Status
= STATUS_INVALID_DEVICE_REQUEST
;
1089 /* Complete the request */
1090 Irp
->IoStatus
.Status
= Status
;
1091 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1095 /* Otherwise, get our VCB and start handling the IRP */
1096 FsRtlEnterFileSystem();
1097 Vcb
= &VolumeDeviceObject
->Vcb
;
1099 /* Check what kind of IRP this is */
1100 switch (IoStackLocation
->MajorFunction
)
1102 /* Cleanup request */
1103 case IRP_MJ_CLEANUP
:
1105 Status
= RawCleanup(Vcb
, Irp
, IoStackLocation
);
1111 Status
= RawClose(Vcb
, Irp
, IoStackLocation
);
1114 /* Create request */
1117 Status
= RawCreate(Vcb
, Irp
, IoStackLocation
);
1121 case IRP_MJ_FILE_SYSTEM_CONTROL
:
1123 Status
= RawFileSystemControl(Vcb
, Irp
, IoStackLocation
);
1126 /* R/W or IOCTL request */
1129 case IRP_MJ_DEVICE_CONTROL
:
1131 Status
= RawReadWriteDeviceControl(Vcb
, Irp
, IoStackLocation
);
1134 /* Information query request */
1135 case IRP_MJ_QUERY_INFORMATION
:
1137 Status
= RawQueryInformation(Vcb
, Irp
, IoStackLocation
);
1140 /* Information set request */
1141 case IRP_MJ_SET_INFORMATION
:
1143 Status
= RawSetInformation(Vcb
, Irp
, IoStackLocation
);
1146 /* Volume information request */
1147 case IRP_MJ_QUERY_VOLUME_INFORMATION
:
1149 Status
= RawQueryVolumeInformation(Vcb
, Irp
, IoStackLocation
);
1152 /* Unexpected request */
1155 /* Anything else is pretty bad */
1156 KeBugCheck(FILE_SYSTEM
);
1159 /* Return the status */
1160 FsRtlExitFileSystem();
1166 RawShutdown(IN PDEVICE_OBJECT DeviceObject
,
1169 /* Unregister file systems */
1170 #if 0 // FIXME: This freezes ROS at shutdown. PnP Problem?
1171 IoUnregisterFileSystem(RawDiskDeviceObject
);
1172 IoUnregisterFileSystem(RawCdromDeviceObject
);
1173 IoUnregisterFileSystem(RawTapeDeviceObject
);
1175 /* Delete the devices */
1176 IoDeleteDevice(RawDiskDeviceObject
);
1177 IoDeleteDevice(RawCdromDeviceObject
);
1178 IoDeleteDevice(RawTapeDeviceObject
);
1181 /* Complete the request */
1182 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1183 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1184 return STATUS_SUCCESS
;
1189 RawUnload(IN PDRIVER_OBJECT DriverObject
)
1191 #if 0 // FIXME: DriverUnload is never called
1192 /* Dereference device objects */
1193 ObDereferenceObject(RawDiskDeviceObject
);
1194 ObDereferenceObject(RawCdromDeviceObject
);
1195 ObDereferenceObject(RawTapeDeviceObject
);
1202 RawFsDriverEntry(IN PDRIVER_OBJECT DriverObject
,
1203 IN PUNICODE_STRING RegistryPath
)
1205 UNICODE_STRING DeviceName
;
1208 /* Create the raw disk device */
1209 RtlInitUnicodeString(&DeviceName
, L
"\\Device\\RawDisk");
1210 Status
= IoCreateDevice(DriverObject
,
1213 FILE_DEVICE_DISK_FILE_SYSTEM
,
1216 &RawDiskDeviceObject
);
1217 if (!NT_SUCCESS(Status
)) return Status
;
1219 /* Create the raw CDROM device */
1220 RtlInitUnicodeString(&DeviceName
, L
"\\Device\\RawCdRom");
1221 Status
= IoCreateDevice(DriverObject
,
1224 FILE_DEVICE_CD_ROM_FILE_SYSTEM
,
1227 &RawCdromDeviceObject
);
1228 if (!NT_SUCCESS(Status
)) return Status
;
1230 /* Create the raw tape device */
1231 RtlInitUnicodeString(&DeviceName
, L
"\\Device\\RawTape");
1232 Status
= IoCreateDevice(DriverObject
,
1235 FILE_DEVICE_TAPE_FILE_SYSTEM
,
1238 &RawTapeDeviceObject
);
1239 if (!NT_SUCCESS(Status
)) return Status
;
1241 /* Set Direct I/O for all devices */
1242 RawDiskDeviceObject
->Flags
|= DO_DIRECT_IO
;
1243 RawCdromDeviceObject
->Flags
|= DO_DIRECT_IO
;
1244 RawTapeDeviceObject
->Flags
|= DO_DIRECT_IO
;
1246 /* Set generic stubs */
1247 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] =
1248 DriverObject
->MajorFunction
[IRP_MJ_CLEANUP
] =
1249 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] =
1250 DriverObject
->MajorFunction
[IRP_MJ_READ
] =
1251 DriverObject
->MajorFunction
[IRP_MJ_WRITE
] =
1252 DriverObject
->MajorFunction
[IRP_MJ_QUERY_INFORMATION
] =
1253 DriverObject
->MajorFunction
[IRP_MJ_SET_INFORMATION
] =
1254 DriverObject
->MajorFunction
[IRP_MJ_QUERY_VOLUME_INFORMATION
] =
1255 DriverObject
->MajorFunction
[IRP_MJ_FILE_SYSTEM_CONTROL
] =
1256 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = RawDispatch
;
1258 /* Shutdown and unload */
1259 DriverObject
->MajorFunction
[IRP_MJ_SHUTDOWN
] = RawShutdown
;
1260 DriverObject
->DriverUnload
= RawUnload
;
1262 /* Register the file systems */
1263 IoRegisterFileSystem(RawDiskDeviceObject
);
1264 IoRegisterFileSystem(RawCdromDeviceObject
);
1265 IoRegisterFileSystem(RawTapeDeviceObject
);
1267 #if 0 // FIXME: DriverUnload is never called
1268 /* Reference device objects */
1269 ObReferenceObject(RawDiskDeviceObject
);
1270 ObReferenceObject(RawCdromDeviceObject
);
1271 ObReferenceObject(RawTapeDeviceObject
);
1273 return STATUS_SUCCESS
;