- Merge from trunk up to r45543
[reactos.git] / ntoskrnl / io / iomgr / rawfs.c
1 /*
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)
7 */
8
9 /* INCLUDES *****************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* TYPES *******************************************************************/
16
17 typedef struct _VCB
18 {
19 USHORT NodeTypeCode;
20 USHORT NodeByteSize;
21 PDEVICE_OBJECT TargetDeviceObject;
22 PVPB Vpb;
23 ULONG VcbState;
24 KMUTEX Mutex;
25 CLONG OpenCount;
26 SHARE_ACCESS ShareAccess;
27 ULONG BytesPerSector;
28 LARGE_INTEGER SectorsOnDisk;
29 } VCB, *PVCB;
30
31 typedef struct _VOLUME_DEVICE_OBJECT
32 {
33 DEVICE_OBJECT DeviceObject;
34 VCB Vcb;
35 } VOLUME_DEVICE_OBJECT, *PVOLUME_DEVICE_OBJECT;
36
37 /* GLOBALS *******************************************************************/
38
39 PDEVICE_OBJECT RawDiskDeviceObject, RawCdromDeviceObject, RawTapeDeviceObject;
40
41 /* FUNCTIONS *****************************************************************/
42
43 VOID
44 NTAPI
45 RawInitializeVcb(IN OUT PVCB Vcb,
46 IN PDEVICE_OBJECT TargetDeviceObject,
47 IN PVPB Vpb)
48 {
49 PAGED_CODE();
50
51 /* Clear it */
52 RtlZeroMemory(Vcb, sizeof(VCB));
53
54 /* Associate to system objects */
55 Vcb->TargetDeviceObject = TargetDeviceObject;
56 Vcb->Vpb = Vpb;
57
58 /* Initialize the lock */
59 KeInitializeMutex(&Vcb->Mutex, 0);
60 }
61
62 BOOLEAN
63 NTAPI
64 RawCheckForDismount(IN PVCB Vcb,
65 IN BOOLEAN CreateOperation)
66 {
67 KIRQL OldIrql;
68 PVPB Vpb;
69 BOOLEAN Delete;
70
71 /* Lock VPB */
72 IoAcquireVpbSpinLock(&OldIrql);
73
74 /* Reference it and check if a create is being done */
75 Vpb = Vcb->Vpb;
76 if (Vcb->Vpb->ReferenceCount != CreateOperation)
77 {
78 /* Don't do anything */
79 Delete = FALSE;
80 }
81 else
82 {
83 /* Otherwise, delete the volume */
84 Delete = TRUE;
85
86 /* Check if it has a VPB and unmount it */
87 if (Vpb->RealDevice->Vpb == Vpb)
88 {
89 Vpb->DeviceObject = NULL;
90 Vpb->Flags &= ~VPB_MOUNTED;
91 }
92 }
93
94 /* Release lock and return status */
95 IoReleaseVpbSpinLock(OldIrql);
96 return Delete;
97 }
98
99 NTSTATUS
100 NTAPI
101 RawCompletionRoutine(IN PDEVICE_OBJECT DeviceObject,
102 IN PIRP Irp,
103 IN PVOID Context)
104 {
105 PIO_STACK_LOCATION IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
106
107 /* Check if this was a valid sync R/W request */
108 if (((IoStackLocation->MajorFunction == IRP_MJ_READ) ||
109 (IoStackLocation->MajorFunction == IRP_MJ_WRITE)) &&
110 ((IoStackLocation->FileObject)) &&
111 (FlagOn(IoStackLocation->FileObject->Flags, FO_SYNCHRONOUS_IO)) &&
112 (NT_SUCCESS(Irp->IoStatus.Status)))
113 {
114 /* Update byte offset */
115 IoStackLocation->FileObject->CurrentByteOffset.QuadPart +=
116 Irp->IoStatus.Information;
117 }
118
119 /* Mark the IRP Pending if it was */
120 if (Irp->PendingReturned) IoMarkIrpPending(Irp);
121 return STATUS_SUCCESS;
122 }
123
124 NTSTATUS
125 NTAPI
126 RawClose(IN PVCB Vcb,
127 IN PIRP Irp,
128 IN PIO_STACK_LOCATION IoStackLocation)
129 {
130 NTSTATUS Status;
131 BOOLEAN Deleted = FALSE;
132 PAGED_CODE();
133
134 /* Make sure we can clean up */
135 Status = KeWaitForSingleObject(&Vcb->Mutex,
136 Executive,
137 KernelMode,
138 FALSE,
139 NULL);
140 ASSERT(NT_SUCCESS(Status));
141
142 /* Decrease the open count and check if this is a dismount */
143 Vcb->OpenCount--;
144 if (!Vcb->OpenCount) Deleted = RawCheckForDismount(Vcb, FALSE);
145
146 /* Check if we should delete the device */
147 KeReleaseMutex(&Vcb->Mutex, FALSE);
148 if (Deleted)
149 {
150 /* Delete it */
151 IoDeleteDevice((PDEVICE_OBJECT)CONTAINING_RECORD(Vcb,
152 VOLUME_DEVICE_OBJECT,
153 Vcb));
154 }
155
156 /* Complete the request */
157 Irp->IoStatus.Status = STATUS_SUCCESS;
158 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
159 return STATUS_SUCCESS;
160 }
161
162 NTSTATUS
163 NTAPI
164 RawCreate(IN PVCB Vcb,
165 IN PIRP Irp,
166 IN PIO_STACK_LOCATION IoStackLocation)
167 {
168 NTSTATUS Status;
169 BOOLEAN Deleted = FALSE;
170 USHORT ShareAccess;
171 ACCESS_MASK DesiredAccess;
172 PAGED_CODE();
173
174 /* Make sure we can clean up */
175 Status = KeWaitForSingleObject(&Vcb->Mutex,
176 Executive,
177 KernelMode,
178 FALSE,
179 NULL);
180 ASSERT(NT_SUCCESS(Status));
181
182 /* Check if this is a valid non-directory file open */
183 if ((!(IoStackLocation->FileObject) ||
184 !(IoStackLocation->FileObject->FileName.Length)) &&
185 ((IoStackLocation->Parameters.Create.Options >> 24) == FILE_OPEN) &&
186 (!(IoStackLocation->Parameters.Create.Options & FILE_DIRECTORY_FILE)))
187 {
188 /* Make sure the VCB isn't locked */
189 if (Vcb->VcbState & 1)
190 {
191 /* Refuse the operation */
192 Status = STATUS_ACCESS_DENIED;
193 Irp->IoStatus.Information = 0;
194 }
195 else
196 {
197 /* Setup share access */
198 ShareAccess = IoStackLocation->Parameters.Create.ShareAccess;
199 DesiredAccess = IoStackLocation->Parameters.Create.
200 SecurityContext->DesiredAccess;
201
202 /* Check if this VCB was already opened */
203 if (Vcb->OpenCount > 0)
204 {
205 /* Try to see if we have access to it */
206 Status = IoCheckShareAccess(DesiredAccess,
207 ShareAccess,
208 IoStackLocation->FileObject,
209 &Vcb->ShareAccess,
210 TRUE);
211 if (!NT_SUCCESS(Status)) Irp->IoStatus.Information = 0;
212 }
213
214 /* Make sure we have access */
215 if (NT_SUCCESS(Status))
216 {
217 /* Check if this is the first open */
218 if (!Vcb->OpenCount)
219 {
220 /* Set the share access */
221 IoSetShareAccess(DesiredAccess,
222 ShareAccess,
223 IoStackLocation->FileObject,
224 &Vcb->ShareAccess);
225 }
226
227 /* Increase the open count and set the VPB */
228 Vcb->OpenCount += 1;
229 IoStackLocation->FileObject->Vpb = Vcb->Vpb;
230
231 /* Set IRP status and disable intermediate buffering */
232 Status = STATUS_SUCCESS;
233 Irp->IoStatus.Information = FILE_OPENED;
234 IoStackLocation->FileObject->Flags |=
235 FO_NO_INTERMEDIATE_BUFFERING;
236 }
237 }
238 }
239 else
240 {
241 /* Invalid create request */
242 Status = STATUS_INVALID_PARAMETER;
243 Irp->IoStatus.Information = 0;
244 }
245
246 /* Check if the request failed */
247 if (!(NT_SUCCESS(Status)) && !(Vcb->OpenCount))
248 {
249 /* Check if we can dismount the device */
250 Deleted = RawCheckForDismount(Vcb, FALSE);
251 }
252
253 /* Check if we should delete the device */
254 KeReleaseMutex(&Vcb->Mutex, FALSE);
255 if (Deleted)
256 {
257 /* Delete it */
258 IoDeleteDevice((PDEVICE_OBJECT)CONTAINING_RECORD(Vcb,
259 VOLUME_DEVICE_OBJECT,
260 Vcb));
261 }
262
263 /* Complete the request */
264 Irp->IoStatus.Status = STATUS_SUCCESS;
265 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
266 return STATUS_SUCCESS;
267 }
268
269 NTSTATUS
270 NTAPI
271 RawReadWriteDeviceControl(IN PVCB Vcb,
272 IN PIRP Irp,
273 IN PIO_STACK_LOCATION IoStackLocation)
274 {
275 NTSTATUS Status;
276 PAGED_CODE();
277
278 /* Don't do anything if the request was 0 bytes */
279 if (((IoStackLocation->MajorFunction == IRP_MJ_READ) ||
280 (IoStackLocation->MajorFunction == IRP_MJ_WRITE)) &&
281 !(IoStackLocation->Parameters.Read.Length))
282 {
283 /* Complete it */
284 Irp->IoStatus.Status = STATUS_SUCCESS;
285 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
286 return STATUS_SUCCESS;
287 }
288
289 /* Copy the IRP stack location */
290 IoCopyCurrentIrpStackLocationToNext(Irp);
291
292 /* Disable verifies */
293 IoGetNextIrpStackLocation(Irp)->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
294
295 /* Setup a completion routine */
296 IoSetCompletionRoutine(Irp,
297 RawCompletionRoutine,
298 NULL,
299 TRUE,
300 TRUE,
301 TRUE);
302
303 /* Call the next driver and exit */
304 Status = IoCallDriver(Vcb->TargetDeviceObject, Irp);
305 return Status;
306 }
307
308 NTSTATUS
309 NTAPI
310 RawMountVolume(IN PIO_STACK_LOCATION IoStackLocation)
311 {
312 NTSTATUS Status;
313 PDEVICE_OBJECT DeviceObject;
314 PVOLUME_DEVICE_OBJECT Volume;
315 PAGED_CODE();
316
317 /* Remember our owner */
318 DeviceObject = IoStackLocation->Parameters.MountVolume.DeviceObject;
319
320 /* Create the volume */
321 Status = IoCreateDevice(RawDiskDeviceObject->DriverObject,
322 sizeof(VOLUME_DEVICE_OBJECT) -
323 sizeof(DEVICE_OBJECT),
324 NULL,
325 FILE_DEVICE_DISK_FILE_SYSTEM,
326 0,
327 FALSE,
328 (PDEVICE_OBJECT*)&Volume);
329 if (!NT_SUCCESS(Status)) return Status;
330
331 /* Use highest alignment requirement */
332 Volume->DeviceObject.AlignmentRequirement = max(DeviceObject->
333 AlignmentRequirement,
334 Volume->DeviceObject.
335 AlignmentRequirement);
336
337 /* Setup the VCB */
338 RawInitializeVcb(&Volume->Vcb,
339 IoStackLocation->Parameters.MountVolume.DeviceObject,
340 IoStackLocation->Parameters.MountVolume.Vpb);
341
342 /* Set dummy label and serial number */
343 Volume->Vcb.Vpb->SerialNumber = 0xFFFFFFFF;
344 Volume->Vcb.Vpb->VolumeLabelLength = 0;
345
346 /* Setup the DO */
347 Volume->Vcb.Vpb->DeviceObject = &Volume->DeviceObject;
348 Volume->DeviceObject.StackSize = DeviceObject->StackSize + 1;
349 Volume->DeviceObject.SectorSize = DeviceObject->SectorSize;
350 Volume->DeviceObject.Flags |= DO_DIRECT_IO;
351 Volume->DeviceObject.Flags &= ~DO_DEVICE_INITIALIZING;
352 return Status;
353 }
354
355 NTSTATUS
356 NTAPI
357 RawUserFsCtrl(IN PIO_STACK_LOCATION IoStackLocation,
358 IN PVCB Vcb)
359 {
360 NTSTATUS Status;
361 PAGED_CODE();
362
363 /* Lock the device */
364 Status = KeWaitForSingleObject(&Vcb->Mutex,
365 Executive,
366 KernelMode,
367 FALSE,
368 NULL);
369 ASSERT(NT_SUCCESS(Status));
370
371 /* Check what kind of request this is */
372 switch (IoStackLocation->Parameters.FileSystemControl.FsControlCode)
373 {
374 /* Oplock requests */
375 case FSCTL_REQUEST_OPLOCK_LEVEL_1:
376 case FSCTL_REQUEST_OPLOCK_LEVEL_2:
377 case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
378 case FSCTL_OPLOCK_BREAK_NOTIFY:
379
380 /* We don't handle them */
381 Status = STATUS_NOT_IMPLEMENTED;
382 break;
383
384 /* Lock request */
385 case FSCTL_LOCK_VOLUME:
386
387 /* Make sure we're not locked, and that we're alone */
388 if (!(Vcb->VcbState & 1) && (Vcb->OpenCount == 1))
389 {
390 /* Lock the VCB */
391 Vcb->VcbState |= 1;
392 Status = STATUS_SUCCESS;
393 }
394 else
395 {
396 /* Otherwise, we can't do this */
397 Status = STATUS_ACCESS_DENIED;
398 }
399 break;
400
401 /* Unlock request */
402 case FSCTL_UNLOCK_VOLUME:
403
404 /* Make sure we're locked */
405 if (!(Vcb->VcbState & 1))
406 {
407 /* Let caller know we're not */
408 Status = STATUS_NOT_LOCKED;
409 }
410 else
411 {
412 /* Unlock the VCB */
413 Vcb->VcbState &= ~1;
414 Status = STATUS_SUCCESS;
415 }
416 break;
417
418 /* Dismount request */
419 case FSCTL_DISMOUNT_VOLUME:
420
421 /* Make sure we're locked */
422 if (Vcb->VcbState & 1)
423 {
424 /* Do nothing, just return success */
425 Status = STATUS_SUCCESS;
426 }
427 else
428 {
429 /* We can't dismount, device not locked */
430 Status = STATUS_ACCESS_DENIED;
431 }
432 break;
433
434 /* Unknown request */
435 default:
436
437 /* Fail */
438 Status = STATUS_INVALID_PARAMETER;
439 break;
440 }
441
442 /* Unlock device and return */
443 KeReleaseMutex(&Vcb->Mutex, FALSE);
444 return Status;
445 }
446
447 NTSTATUS
448 NTAPI
449 RawFileSystemControl(IN PVCB Vcb,
450 IN PIRP Irp,
451 IN PIO_STACK_LOCATION IoStackLocation)
452 {
453 NTSTATUS Status;
454 PAGED_CODE();
455
456 /* Check the kinds of FSCTLs that we support */
457 switch (IoStackLocation->MinorFunction)
458 {
459 /* User-mode request */
460 case IRP_MN_USER_FS_REQUEST:
461
462 /* Handle it */
463 Status = RawUserFsCtrl(IoStackLocation, Vcb);
464 break;
465
466 /* Mount request */
467 case IRP_MN_MOUNT_VOLUME:
468
469 /* Mount the volume */
470 Status = RawMountVolume(IoStackLocation);
471 break;
472
473 case IRP_MN_VERIFY_VOLUME:
474
475 /* We don't do verifies */
476 Status = STATUS_WRONG_VOLUME;
477 Vcb->Vpb->RealDevice->Flags &= ~DO_VERIFY_VOLUME;
478
479 /* Check if we should delete the device */
480 if (RawCheckForDismount(Vcb, FALSE))
481 {
482 /* Do it */
483 IoDeleteDevice((PDEVICE_OBJECT)
484 CONTAINING_RECORD(Vcb,
485 VOLUME_DEVICE_OBJECT,
486 Vcb));
487 }
488
489 /* We're done */
490 break;
491
492 /* Invalid request */
493 default:
494
495 /* Fail it */
496 Status = STATUS_INVALID_DEVICE_REQUEST;
497 break;
498 }
499
500 /* Complete the request */
501 Irp->IoStatus.Status = Status;
502 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
503 return Status;
504 }
505
506 NTSTATUS
507 NTAPI
508 RawQueryInformation(IN PVCB Vcb,
509 IN PIRP Irp,
510 IN PIO_STACK_LOCATION IoStackLocation)
511 {
512 NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST;
513 PULONG Length;
514 PFILE_POSITION_INFORMATION Buffer;
515 PAGED_CODE();
516
517 /* Get information from the IRP */
518 Length = &IoStackLocation->Parameters.QueryFile.Length;
519 Buffer = Irp->AssociatedIrp.SystemBuffer;
520
521 /* We only handle this request */
522 if (IoStackLocation->Parameters.QueryFile.FileInformationClass ==
523 FilePositionInformation)
524 {
525 /* Validate buffer size */
526 if (*Length < sizeof(FILE_POSITION_INFORMATION))
527 {
528 /* Invalid, fail */
529 Irp->IoStatus.Information = 0;
530 Status = STATUS_BUFFER_OVERFLOW;
531 }
532 else
533 {
534 /* Get offset and update length */
535 Buffer->CurrentByteOffset = IoStackLocation->FileObject->
536 CurrentByteOffset;
537 *Length -= sizeof(FILE_POSITION_INFORMATION);
538
539 /* Set IRP Status information */
540 Irp->IoStatus.Information = sizeof(FILE_POSITION_INFORMATION);
541 Status = STATUS_SUCCESS;
542 }
543 }
544
545 /* Complete it */
546 Irp->IoStatus.Status = Status;
547 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
548 return Status;
549 }
550
551 NTSTATUS
552 NTAPI
553 RawSetInformation(IN PVCB Vcb,
554 IN PIRP Irp,
555 IN PIO_STACK_LOCATION IoStackLocation)
556 {
557 NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST;
558 PULONG Length;
559 PFILE_POSITION_INFORMATION Buffer;
560 PDEVICE_OBJECT DeviceObject;
561 PAGED_CODE();
562
563 /* Get information from the IRP */
564 Length = &IoStackLocation->Parameters.QueryFile.Length;
565 Buffer = Irp->AssociatedIrp.SystemBuffer;
566
567 /* We only handle this request */
568 if (IoStackLocation->Parameters.QueryFile.FileInformationClass ==
569 FilePositionInformation)
570 {
571 /* Get the DO */
572 DeviceObject = IoGetRelatedDeviceObject(IoStackLocation->FileObject);
573
574 /* Make sure the offset is aligned */
575 if ((Buffer->CurrentByteOffset.LowPart &
576 DeviceObject->AlignmentRequirement))
577 {
578 /* It's not, fail */
579 Status = STATUS_INVALID_PARAMETER;
580 }
581 else
582 {
583 /* Otherwise, set offset */
584 IoStackLocation->FileObject->CurrentByteOffset = Buffer->
585 CurrentByteOffset;
586
587 /* Set IRP Status information */
588 Status = STATUS_SUCCESS;
589 }
590 }
591
592 /* Complete it */
593 Irp->IoStatus.Status = Status;
594 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
595 return Status;
596 }
597
598 NTSTATUS
599 NTAPI
600 RawQueryFsVolumeInfo(IN PVCB Vcb,
601 IN PFILE_FS_VOLUME_INFORMATION Buffer,
602 IN OUT PULONG Length)
603 {
604 PAGED_CODE();
605
606 /* Clear the buffer and stub it out */
607 RtlZeroMemory( Buffer, sizeof(FILE_FS_VOLUME_INFORMATION));
608 Buffer->VolumeSerialNumber = Vcb->Vpb->SerialNumber;
609 Buffer->SupportsObjects = FALSE;
610 Buffer->VolumeLabelLength = 0;
611
612 /* Return length and success */
613 *Length -= FIELD_OFFSET(FILE_FS_VOLUME_INFORMATION, VolumeLabel[0]);
614 return STATUS_SUCCESS;
615 }
616
617 NTSTATUS
618 NTAPI
619 RawQueryFsSizeInfo(IN PVCB Vcb,
620 IN PFILE_FS_SIZE_INFORMATION Buffer,
621 IN OUT PULONG Length)
622 {
623 PIRP Irp;
624 KEVENT Event;
625 NTSTATUS Status;
626 IO_STATUS_BLOCK IoStatusBlock;
627 PDEVICE_OBJECT RealDevice;
628 DISK_GEOMETRY DiskGeometry;
629 PARTITION_INFORMATION PartitionInformation;
630 BOOLEAN DiskHasPartitions;
631 PAGED_CODE();
632
633 /* Validate the buffer */
634 if (*Length < sizeof(FILE_FS_SIZE_INFORMATION))
635 {
636 /* Fail */
637 return STATUS_BUFFER_OVERFLOW;
638 }
639
640 /* Clear the buffer, initialize the event and set the DO */
641 RtlZeroMemory(Buffer, sizeof(FILE_FS_SIZE_INFORMATION));
642 KeInitializeEvent(&Event, NotificationEvent, FALSE);
643 RealDevice = Vcb->Vpb->RealDevice;
644
645 /* Build query IRP */
646 Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY,
647 RealDevice,
648 NULL,
649 0,
650 &DiskGeometry,
651 sizeof(DISK_GEOMETRY),
652 FALSE,
653 &Event,
654 &IoStatusBlock);
655 if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
656
657 /* Call driver and check if we're pending */
658 Status = IoCallDriver(RealDevice, Irp);
659 if (Status == STATUS_PENDING)
660 {
661 /* Wait on driver to finish */
662 KeWaitForSingleObject(&Event,
663 Executive,
664 KernelMode,
665 FALSE,
666 NULL);
667 Status = IoStatusBlock.Status;
668 }
669
670 /* Fail if we couldn't get CHS data */
671 if (!NT_SUCCESS(Status))
672 {
673 *Length = 0;
674 return Status;
675 }
676
677 /* Check if this is a floppy */
678 if (FlagOn(RealDevice->Characteristics, FILE_FLOPPY_DISKETTE))
679 {
680 /* Floppies don't have partitions */
681 DiskHasPartitions = FALSE;
682 }
683 else
684 {
685 /* Setup query IRP */
686 KeResetEvent(&Event);
687 Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO,
688 RealDevice,
689 NULL,
690 0,
691 &PartitionInformation,
692 sizeof(PARTITION_INFORMATION),
693 FALSE,
694 &Event,
695 &IoStatusBlock);
696 if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
697
698 /* Call driver and check if we're pending */
699 Status = IoCallDriver(RealDevice, Irp);
700 if (Status == STATUS_PENDING)
701 {
702 /* Wait on driver to finish */
703 KeWaitForSingleObject(&Event,
704 Executive,
705 KernelMode,
706 FALSE,
707 NULL);
708 Status = IoStatusBlock.Status;
709 }
710
711 /* If this was an invalid request, then the disk is not partitioned */
712 if (Status == STATUS_INVALID_DEVICE_REQUEST)
713 {
714 DiskHasPartitions = FALSE;
715 }
716 else
717 {
718 /* Otherwise, it must be */
719 ASSERT(NT_SUCCESS(Status));
720 DiskHasPartitions = TRUE;
721 }
722 }
723
724 /* Set sector data */
725 Buffer->BytesPerSector = DiskGeometry.BytesPerSector;
726 Buffer->SectorsPerAllocationUnit = 1;
727
728 /* Calculate allocation units */
729 if (DiskHasPartitions)
730 {
731 /* Use partition data */
732 Buffer->TotalAllocationUnits =
733 RtlExtendedLargeIntegerDivide(PartitionInformation.PartitionLength,
734 DiskGeometry.BytesPerSector,
735 NULL);
736 }
737 else
738 {
739 /* Use CHS */
740 Buffer->TotalAllocationUnits =
741 RtlExtendedIntegerMultiply(DiskGeometry.Cylinders,
742 DiskGeometry.TracksPerCylinder *
743 DiskGeometry.SectorsPerTrack);
744 }
745
746 /* Set available units */
747 Buffer->AvailableAllocationUnits = Buffer->TotalAllocationUnits;
748
749 /* Return length and success */
750 *Length -= sizeof(FILE_FS_SIZE_INFORMATION);
751 return STATUS_SUCCESS;
752 }
753
754 NTSTATUS
755 NTAPI
756 RawQueryFsDeviceInfo(IN PVCB Vcb,
757 IN PFILE_FS_DEVICE_INFORMATION Buffer,
758 IN OUT PULONG Length)
759 {
760 PAGED_CODE();
761
762 /* Validate buffer */
763 if (*Length < sizeof(FILE_FS_DEVICE_INFORMATION))
764 {
765 /* Fail */
766 return STATUS_BUFFER_OVERFLOW;
767 }
768
769 /* Clear buffer and write information */
770 RtlZeroMemory(Buffer, sizeof(FILE_FS_DEVICE_INFORMATION));
771 Buffer->DeviceType = FILE_DEVICE_DISK;
772 Buffer->Characteristics = Vcb->TargetDeviceObject->Characteristics;
773
774 /* Return length and success */
775 *Length -= sizeof(FILE_FS_DEVICE_INFORMATION);
776 return STATUS_SUCCESS;
777 }
778
779 NTSTATUS
780 NTAPI
781 RawQueryFsAttributeInfo(IN PVCB Vcb,
782 IN PFILE_FS_ATTRIBUTE_INFORMATION Buffer,
783 IN OUT PULONG Length)
784 {
785 const WCHAR szRawFSName[] = L"RAW";
786 ULONG ReturnLength;
787 PAGED_CODE();
788
789 /* Check if the buffer is large enough for our name ("RAW") */
790 ReturnLength = FIELD_OFFSET(FILE_FS_ATTRIBUTE_INFORMATION,
791 FileSystemName[sizeof(szRawFSName) / sizeof(szRawFSName[0])]);
792 if (*Length < ReturnLength) return STATUS_BUFFER_OVERFLOW;
793
794 /* Output the data */
795 Buffer->FileSystemAttributes = 0;
796 Buffer->MaximumComponentNameLength = 0;
797 Buffer->FileSystemNameLength = 6;
798 RtlCopyMemory(&Buffer->FileSystemName[0], szRawFSName, sizeof(szRawFSName));
799
800 /* Return length and success */
801 *Length -= ReturnLength;
802 return STATUS_SUCCESS;
803 }
804
805 NTSTATUS
806 NTAPI
807 RawQueryVolumeInformation(IN PVCB Vcb,
808 IN PIRP Irp,
809 IN PIO_STACK_LOCATION IoStackLocation)
810 {
811 NTSTATUS Status;
812 ULONG Length;
813 PVOID Buffer;
814 PAGED_CODE();
815
816 /* Get IRP Data */
817 Length = IoStackLocation->Parameters.QueryVolume.Length;
818 Buffer = Irp->AssociatedIrp.SystemBuffer;
819
820 /* Check the kind of request */
821 switch (IoStackLocation->Parameters.QueryVolume.FsInformationClass)
822 {
823 /* Volume information request */
824 case FileFsVolumeInformation:
825
826 Status = RawQueryFsVolumeInfo(Vcb, Buffer, &Length);
827 break;
828
829 /* File system size invormation */
830 case FileFsSizeInformation:
831
832 Status = RawQueryFsSizeInfo(Vcb, Buffer, &Length);
833 break;
834
835 /* Device information */
836 case FileFsDeviceInformation:
837
838 Status = RawQueryFsDeviceInfo(Vcb, Buffer, &Length);
839 break;
840
841 /* Attribute information */
842 case FileFsAttributeInformation:
843
844 Status = RawQueryFsAttributeInfo(Vcb, Buffer, &Length);
845 break;
846
847 /* Invalid request */
848 default:
849
850 /* Fail it */
851 Status = STATUS_INVALID_PARAMETER;
852 break;
853 }
854
855 /* Set status and complete the request */
856 Irp->IoStatus.Information = IoStackLocation->
857 Parameters.QueryVolume.Length - Length;
858 Irp->IoStatus.Status = Status;
859 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
860 return Status;
861 }
862
863 NTSTATUS
864 NTAPI
865 RawCleanup(IN PVCB Vcb,
866 IN PIRP Irp,
867 IN PIO_STACK_LOCATION IoStackLocation)
868 {
869 NTSTATUS Status;
870 PAGED_CODE();
871
872 /* Make sure we can clean up */
873 Status = KeWaitForSingleObject(&Vcb->Mutex,
874 Executive,
875 KernelMode,
876 FALSE,
877 NULL);
878 ASSERT(NT_SUCCESS(Status));
879
880 /* Remove shared access and complete the request */
881 IoRemoveShareAccess(IoStackLocation->FileObject, &Vcb->ShareAccess);
882 KeReleaseMutex(&Vcb->Mutex, FALSE);
883 Irp->IoStatus.Status = STATUS_SUCCESS;
884 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
885 return STATUS_SUCCESS;
886 }
887
888 NTSTATUS
889 NTAPI
890 RawDispatch(IN PVOLUME_DEVICE_OBJECT DeviceObject,
891 IN PIRP Irp)
892 {
893 NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST;
894 PIO_STACK_LOCATION IoStackLocation;
895 PVCB Vcb;
896 PAGED_CODE();
897
898 /* Get the stack location */
899 IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
900
901 /* Differentiate between Volume DO and FS DO */
902 if ((((PDEVICE_OBJECT)DeviceObject)->Size == sizeof(DEVICE_OBJECT)) &&
903 !((IoStackLocation->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) &&
904 (IoStackLocation->MinorFunction == IRP_MN_MOUNT_VOLUME)))
905 {
906 /* This is an FS DO. Stub out the common calls */
907 if ((IoStackLocation->MajorFunction == IRP_MJ_CREATE) ||
908 (IoStackLocation->MajorFunction == IRP_MJ_CLEANUP) ||
909 (IoStackLocation->MajorFunction == IRP_MJ_CLOSE))
910 {
911 /* Return success for them */
912 Status = STATUS_SUCCESS;
913 }
914 else
915 {
916 /* Anything else, we don't support */
917 Status = STATUS_INVALID_DEVICE_REQUEST;
918 }
919
920 /* Complete the request */
921 Irp->IoStatus.Status = Status;
922 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
923 return Status;
924 }
925
926 /* Otherwise, get our VCB and start handling the IRP */
927 FsRtlEnterFileSystem();
928 Vcb = &DeviceObject->Vcb;
929
930 /* Check what kind of IRP this is */
931 switch (IoStackLocation->MajorFunction)
932 {
933 /* Cleanup request */
934 case IRP_MJ_CLEANUP:
935
936 Status = RawCleanup(Vcb, Irp, IoStackLocation);
937 break;
938
939 /* Close request */
940 case IRP_MJ_CLOSE:
941
942 Status = RawClose(Vcb, Irp, IoStackLocation);
943 break;
944
945 /* Create request */
946 case IRP_MJ_CREATE:
947
948 Status = RawCreate(Vcb, Irp, IoStackLocation);
949 break;
950
951 /* FSCTL request */
952 case IRP_MJ_FILE_SYSTEM_CONTROL:
953
954 Status = RawFileSystemControl(Vcb, Irp, IoStackLocation);
955 break;
956
957 /* R/W or IOCTL request */
958 case IRP_MJ_READ:
959 case IRP_MJ_WRITE:
960 case IRP_MJ_DEVICE_CONTROL:
961
962 Status = RawReadWriteDeviceControl(Vcb, Irp, IoStackLocation);
963 break;
964
965 /* Information query request */
966 case IRP_MJ_QUERY_INFORMATION:
967
968 Status = RawQueryInformation(Vcb, Irp, IoStackLocation);
969 break;
970
971 /* Information set request */
972 case IRP_MJ_SET_INFORMATION:
973
974 Status = RawSetInformation(Vcb, Irp, IoStackLocation);
975 break;
976
977 /* Volume information request */
978 case IRP_MJ_QUERY_VOLUME_INFORMATION:
979
980 Status = RawQueryVolumeInformation(Vcb, Irp, IoStackLocation);
981 break;
982
983 /* Unexpected request */
984 default:
985
986 /* Anything else is pretty bad */
987 KeBugCheck(FILE_SYSTEM);
988 }
989
990 /* Return the status */
991 FsRtlExitFileSystem();
992 return Status;
993 }
994
995 NTSTATUS
996 NTAPI
997 RawShutdown(IN PDEVICE_OBJECT DeviceObject,
998 IN PIRP Irp)
999 {
1000 /* Unregister file systems */
1001 #if 0 // FIXME: This freezes ROS at shutdown. PnP Problem?
1002 IoUnregisterFileSystem(RawDiskDeviceObject);
1003 IoUnregisterFileSystem(RawCdromDeviceObject);
1004 IoUnregisterFileSystem(RawTapeDeviceObject);
1005
1006 /* Delete the devices */
1007 IoDeleteDevice(RawDiskDeviceObject);
1008 IoDeleteDevice(RawCdromDeviceObject);
1009 IoDeleteDevice(RawTapeDeviceObject);
1010 #endif
1011
1012 /* Complete the request */
1013 Irp->IoStatus.Status = STATUS_SUCCESS;
1014 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1015 return STATUS_SUCCESS;
1016 }
1017
1018 VOID
1019 NTAPI
1020 RawUnload(IN PDRIVER_OBJECT DriverObject)
1021 {
1022 #if 0 // FIXME: DriverUnload is never called
1023 /* Dereference device objects */
1024 ObDereferenceObject(RawDiskDeviceObject);
1025 ObDereferenceObject(RawCdromDeviceObject);
1026 ObDereferenceObject(RawTapeDeviceObject);
1027 #endif
1028 }
1029
1030 NTSTATUS
1031 NTAPI
1032 RawFsDriverEntry(IN PDRIVER_OBJECT DriverObject,
1033 IN PUNICODE_STRING RegistryPath)
1034 {
1035 UNICODE_STRING DeviceName;
1036 NTSTATUS Status;
1037
1038 /* Create the raw disk device */
1039 RtlInitUnicodeString(&DeviceName, L"\\Device\\RawDisk");
1040 Status = IoCreateDevice(DriverObject,
1041 0,
1042 NULL,
1043 FILE_DEVICE_DISK_FILE_SYSTEM,
1044 0,
1045 FALSE,
1046 &RawDiskDeviceObject);
1047 if (!NT_SUCCESS(Status)) return Status;
1048
1049 /* Create the raw CDROM device */
1050 RtlInitUnicodeString(&DeviceName, L"\\Device\\RawCdRom");
1051 Status = IoCreateDevice(DriverObject,
1052 0,
1053 NULL,
1054 FILE_DEVICE_CD_ROM_FILE_SYSTEM,
1055 0,
1056 FALSE,
1057 &RawCdromDeviceObject);
1058 if (!NT_SUCCESS(Status)) return Status;
1059
1060 /* Create the raw tape device */
1061 RtlInitUnicodeString(&DeviceName, L"\\Device\\RawTape");
1062 Status = IoCreateDevice(DriverObject,
1063 0,
1064 NULL,
1065 FILE_DEVICE_TAPE_FILE_SYSTEM,
1066 0,
1067 FALSE,
1068 &RawTapeDeviceObject);
1069 if (!NT_SUCCESS(Status)) return Status;
1070
1071 /* Set Direct I/O for all devices */
1072 RawDiskDeviceObject->Flags |= DO_DIRECT_IO;
1073 RawCdromDeviceObject->Flags |= DO_DIRECT_IO;
1074 RawTapeDeviceObject->Flags |= DO_DIRECT_IO;
1075
1076 /* Set generic stubs */
1077 DriverObject->MajorFunction[IRP_MJ_CREATE] =
1078 DriverObject->MajorFunction[IRP_MJ_CLEANUP] =
1079 DriverObject->MajorFunction[IRP_MJ_CLOSE] =
1080 DriverObject->MajorFunction[IRP_MJ_READ] =
1081 DriverObject->MajorFunction[IRP_MJ_WRITE] =
1082 DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] =
1083 DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] =
1084 DriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] =
1085 DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] =
1086 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = (PDRIVER_DISPATCH)RawDispatch;
1087
1088 /* Shutdown and unload */
1089 DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = RawShutdown;
1090 DriverObject->DriverUnload = RawUnload;
1091
1092 /* Register the file systems */
1093 IoRegisterFileSystem(RawDiskDeviceObject);
1094 IoRegisterFileSystem(RawCdromDeviceObject);
1095 IoRegisterFileSystem(RawTapeDeviceObject);
1096
1097 #if 0 // FIXME: DriverUnload is never called
1098 /* Reference device objects */
1099 ObReferenceObject(RawDiskDeviceObject);
1100 ObReferenceObject(RawCdromDeviceObject);
1101 ObReferenceObject(RawTapeDeviceObject);
1102 #endif
1103 return STATUS_SUCCESS;
1104 }
1105
1106 /* EOF */