Sync with trunk (r48008)
[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 PFILE_OBJECT FileObject = NULL;
316 PAGED_CODE();
317
318 /* Remember our owner */
319 DeviceObject = IoStackLocation->Parameters.MountVolume.DeviceObject;
320
321 /* Create the volume */
322 Status = IoCreateDevice(RawDiskDeviceObject->DriverObject,
323 sizeof(VOLUME_DEVICE_OBJECT) -
324 sizeof(DEVICE_OBJECT),
325 NULL,
326 FILE_DEVICE_DISK_FILE_SYSTEM,
327 0,
328 FALSE,
329 (PDEVICE_OBJECT*)&Volume);
330 if (!NT_SUCCESS(Status)) return Status;
331
332 /* Use highest alignment requirement */
333 Volume->DeviceObject.AlignmentRequirement = max(DeviceObject->
334 AlignmentRequirement,
335 Volume->DeviceObject.
336 AlignmentRequirement);
337
338 /* Setup the VCB */
339 RawInitializeVcb(&Volume->Vcb,
340 IoStackLocation->Parameters.MountVolume.DeviceObject,
341 IoStackLocation->Parameters.MountVolume.Vpb);
342
343 /* Set dummy label and serial number */
344 Volume->Vcb.Vpb->SerialNumber = 0xFFFFFFFF;
345 Volume->Vcb.Vpb->VolumeLabelLength = 0;
346
347 /* Setup the DO */
348 Volume->Vcb.Vpb->DeviceObject = &Volume->DeviceObject;
349 Volume->DeviceObject.StackSize = DeviceObject->StackSize + 1;
350 Volume->DeviceObject.SectorSize = DeviceObject->SectorSize;
351 Volume->DeviceObject.Flags |= DO_DIRECT_IO;
352 Volume->DeviceObject.Flags &= ~DO_DEVICE_INITIALIZING;
353
354 /* Try to get associated FO (for notification) */
355 _SEH2_TRY
356 {
357 FileObject = IoCreateStreamFileObjectLite(NULL,
358 &(Volume->DeviceObject));
359 }
360 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
361 {
362 /* Get the exception code */
363 Status = _SEH2_GetExceptionCode();
364 }
365 _SEH2_END;
366
367 /* If failed, delete devive */
368 if (!NT_SUCCESS(Status))
369 {
370 IoDeleteDevice((PDEVICE_OBJECT)Volume);
371 return Status;
372 }
373
374 /* Increment OpenCount by two to avoid dismount when RawClose() will be called on ObDereferenceObject() */
375 Volume->Vcb.OpenCount += 2;
376 /* Notify for sucessful mount */
377 FsRtlNotifyVolumeEvent(FileObject, FSRTL_VOLUME_MOUNT);
378 /* Decrease refcount to 0 to make FileObject being released */
379 ObDereferenceObject(FileObject);
380 /* It's not open anymore, go back to 0 */
381 Volume->Vcb.OpenCount -= 2;
382
383 return Status;
384 }
385
386 NTSTATUS
387 NTAPI
388 RawUserFsCtrl(IN PIO_STACK_LOCATION IoStackLocation,
389 IN PVCB Vcb)
390 {
391 NTSTATUS Status;
392 PAGED_CODE();
393
394 /* Lock the device */
395 Status = KeWaitForSingleObject(&Vcb->Mutex,
396 Executive,
397 KernelMode,
398 FALSE,
399 NULL);
400 ASSERT(NT_SUCCESS(Status));
401
402 /* Check what kind of request this is */
403 switch (IoStackLocation->Parameters.FileSystemControl.FsControlCode)
404 {
405 /* Oplock requests */
406 case FSCTL_REQUEST_OPLOCK_LEVEL_1:
407 case FSCTL_REQUEST_OPLOCK_LEVEL_2:
408 case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
409 case FSCTL_OPLOCK_BREAK_NOTIFY:
410
411 /* We don't handle them */
412 Status = STATUS_NOT_IMPLEMENTED;
413 break;
414
415 /* Lock request */
416 case FSCTL_LOCK_VOLUME:
417
418 /* Make sure we're not locked, and that we're alone */
419 if (!(Vcb->VcbState & 1) && (Vcb->OpenCount == 1))
420 {
421 /* Lock the VCB */
422 Vcb->VcbState |= 1;
423 Status = STATUS_SUCCESS;
424 }
425 else
426 {
427 /* Otherwise, we can't do this */
428 Status = STATUS_ACCESS_DENIED;
429 }
430 break;
431
432 /* Unlock request */
433 case FSCTL_UNLOCK_VOLUME:
434
435 /* Make sure we're locked */
436 if (!(Vcb->VcbState & 1))
437 {
438 /* Let caller know we're not */
439 Status = STATUS_NOT_LOCKED;
440 }
441 else
442 {
443 /* Unlock the VCB */
444 Vcb->VcbState &= ~1;
445 Status = STATUS_SUCCESS;
446 }
447 break;
448
449 /* Dismount request */
450 case FSCTL_DISMOUNT_VOLUME:
451
452 /* Make sure we're locked */
453 if (Vcb->VcbState & 1)
454 {
455 /* Do nothing, just return success */
456 Status = STATUS_SUCCESS;
457 }
458 else
459 {
460 /* We can't dismount, device not locked */
461 Status = STATUS_ACCESS_DENIED;
462 }
463 break;
464
465 /* Unknown request */
466 default:
467
468 /* Fail */
469 Status = STATUS_INVALID_PARAMETER;
470 break;
471 }
472
473 /* Unlock device */
474 KeReleaseMutex(&Vcb->Mutex, FALSE);
475
476 /* In case of status change, notify */
477 switch (IoStackLocation->Parameters.FileSystemControl.FsControlCode)
478 {
479 case FSCTL_LOCK_VOLUME:
480 FsRtlNotifyVolumeEvent(IoStackLocation->FileObject, (NT_SUCCESS(Status) ? FSRTL_VOLUME_LOCK : FSRTL_VOLUME_LOCK_FAILED));
481 break;
482 case FSCTL_UNLOCK_VOLUME:
483 if (NT_SUCCESS(Status))
484 {
485 FsRtlNotifyVolumeEvent(IoStackLocation->FileObject, FSRTL_VOLUME_UNLOCK);
486 }
487 break;
488 case FSCTL_DISMOUNT_VOLUME:
489 FsRtlNotifyVolumeEvent(IoStackLocation->FileObject, (NT_SUCCESS(Status) ? FSRTL_VOLUME_DISMOUNT : FSRTL_VOLUME_DISMOUNT_FAILED));
490 break;
491 }
492
493 return Status;
494 }
495
496 NTSTATUS
497 NTAPI
498 RawFileSystemControl(IN PVCB Vcb,
499 IN PIRP Irp,
500 IN PIO_STACK_LOCATION IoStackLocation)
501 {
502 NTSTATUS Status;
503 PAGED_CODE();
504
505 /* Check the kinds of FSCTLs that we support */
506 switch (IoStackLocation->MinorFunction)
507 {
508 /* User-mode request */
509 case IRP_MN_USER_FS_REQUEST:
510
511 /* Handle it */
512 Status = RawUserFsCtrl(IoStackLocation, Vcb);
513 break;
514
515 /* Mount request */
516 case IRP_MN_MOUNT_VOLUME:
517
518 /* Mount the volume */
519 Status = RawMountVolume(IoStackLocation);
520 break;
521
522 case IRP_MN_VERIFY_VOLUME:
523
524 /* We don't do verifies */
525 Status = STATUS_WRONG_VOLUME;
526 Vcb->Vpb->RealDevice->Flags &= ~DO_VERIFY_VOLUME;
527
528 /* Check if we should delete the device */
529 if (RawCheckForDismount(Vcb, FALSE))
530 {
531 /* Do it */
532 IoDeleteDevice((PDEVICE_OBJECT)
533 CONTAINING_RECORD(Vcb,
534 VOLUME_DEVICE_OBJECT,
535 Vcb));
536 }
537
538 /* We're done */
539 break;
540
541 /* Invalid request */
542 default:
543
544 /* Fail it */
545 Status = STATUS_INVALID_DEVICE_REQUEST;
546 break;
547 }
548
549 /* Complete the request */
550 Irp->IoStatus.Status = Status;
551 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
552 return Status;
553 }
554
555 NTSTATUS
556 NTAPI
557 RawQueryInformation(IN PVCB Vcb,
558 IN PIRP Irp,
559 IN PIO_STACK_LOCATION IoStackLocation)
560 {
561 NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST;
562 PULONG Length;
563 PFILE_POSITION_INFORMATION Buffer;
564 PAGED_CODE();
565
566 /* Get information from the IRP */
567 Length = &IoStackLocation->Parameters.QueryFile.Length;
568 Buffer = Irp->AssociatedIrp.SystemBuffer;
569
570 /* We only handle this request */
571 if (IoStackLocation->Parameters.QueryFile.FileInformationClass ==
572 FilePositionInformation)
573 {
574 /* Validate buffer size */
575 if (*Length < sizeof(FILE_POSITION_INFORMATION))
576 {
577 /* Invalid, fail */
578 Irp->IoStatus.Information = 0;
579 Status = STATUS_BUFFER_OVERFLOW;
580 }
581 else
582 {
583 /* Get offset and update length */
584 Buffer->CurrentByteOffset = IoStackLocation->FileObject->
585 CurrentByteOffset;
586 *Length -= sizeof(FILE_POSITION_INFORMATION);
587
588 /* Set IRP Status information */
589 Irp->IoStatus.Information = sizeof(FILE_POSITION_INFORMATION);
590 Status = STATUS_SUCCESS;
591 }
592 }
593
594 /* Complete it */
595 Irp->IoStatus.Status = Status;
596 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
597 return Status;
598 }
599
600 NTSTATUS
601 NTAPI
602 RawSetInformation(IN PVCB Vcb,
603 IN PIRP Irp,
604 IN PIO_STACK_LOCATION IoStackLocation)
605 {
606 NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST;
607 PULONG Length;
608 PFILE_POSITION_INFORMATION Buffer;
609 PDEVICE_OBJECT DeviceObject;
610 PAGED_CODE();
611
612 /* Get information from the IRP */
613 Length = &IoStackLocation->Parameters.QueryFile.Length;
614 Buffer = Irp->AssociatedIrp.SystemBuffer;
615
616 /* We only handle this request */
617 if (IoStackLocation->Parameters.QueryFile.FileInformationClass ==
618 FilePositionInformation)
619 {
620 /* Get the DO */
621 DeviceObject = IoGetRelatedDeviceObject(IoStackLocation->FileObject);
622
623 /* Make sure the offset is aligned */
624 if ((Buffer->CurrentByteOffset.LowPart &
625 DeviceObject->AlignmentRequirement))
626 {
627 /* It's not, fail */
628 Status = STATUS_INVALID_PARAMETER;
629 }
630 else
631 {
632 /* Otherwise, set offset */
633 IoStackLocation->FileObject->CurrentByteOffset = Buffer->
634 CurrentByteOffset;
635
636 /* Set IRP Status information */
637 Status = STATUS_SUCCESS;
638 }
639 }
640
641 /* Complete it */
642 Irp->IoStatus.Status = Status;
643 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
644 return Status;
645 }
646
647 NTSTATUS
648 NTAPI
649 RawQueryFsVolumeInfo(IN PVCB Vcb,
650 IN PFILE_FS_VOLUME_INFORMATION Buffer,
651 IN OUT PULONG Length)
652 {
653 PAGED_CODE();
654
655 /* Clear the buffer and stub it out */
656 RtlZeroMemory( Buffer, sizeof(FILE_FS_VOLUME_INFORMATION));
657 Buffer->VolumeSerialNumber = Vcb->Vpb->SerialNumber;
658 Buffer->SupportsObjects = FALSE;
659 Buffer->VolumeLabelLength = 0;
660
661 /* Return length and success */
662 *Length -= FIELD_OFFSET(FILE_FS_VOLUME_INFORMATION, VolumeLabel[0]);
663 return STATUS_SUCCESS;
664 }
665
666 NTSTATUS
667 NTAPI
668 RawQueryFsSizeInfo(IN PVCB Vcb,
669 IN PFILE_FS_SIZE_INFORMATION Buffer,
670 IN OUT PULONG Length)
671 {
672 PIRP Irp;
673 KEVENT Event;
674 NTSTATUS Status;
675 IO_STATUS_BLOCK IoStatusBlock;
676 PDEVICE_OBJECT RealDevice;
677 DISK_GEOMETRY DiskGeometry;
678 PARTITION_INFORMATION PartitionInformation;
679 BOOLEAN DiskHasPartitions;
680 PAGED_CODE();
681
682 /* Validate the buffer */
683 if (*Length < sizeof(FILE_FS_SIZE_INFORMATION))
684 {
685 /* Fail */
686 return STATUS_BUFFER_OVERFLOW;
687 }
688
689 /* Clear the buffer, initialize the event and set the DO */
690 RtlZeroMemory(Buffer, sizeof(FILE_FS_SIZE_INFORMATION));
691 KeInitializeEvent(&Event, NotificationEvent, FALSE);
692 RealDevice = Vcb->Vpb->RealDevice;
693
694 /* Build query IRP */
695 Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY,
696 RealDevice,
697 NULL,
698 0,
699 &DiskGeometry,
700 sizeof(DISK_GEOMETRY),
701 FALSE,
702 &Event,
703 &IoStatusBlock);
704 if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
705
706 /* Call driver and check if we're pending */
707 Status = IoCallDriver(RealDevice, Irp);
708 if (Status == STATUS_PENDING)
709 {
710 /* Wait on driver to finish */
711 KeWaitForSingleObject(&Event,
712 Executive,
713 KernelMode,
714 FALSE,
715 NULL);
716 Status = IoStatusBlock.Status;
717 }
718
719 /* Fail if we couldn't get CHS data */
720 if (!NT_SUCCESS(Status))
721 {
722 *Length = 0;
723 return Status;
724 }
725
726 /* Check if this is a floppy */
727 if (FlagOn(RealDevice->Characteristics, FILE_FLOPPY_DISKETTE))
728 {
729 /* Floppies don't have partitions */
730 DiskHasPartitions = FALSE;
731 }
732 else
733 {
734 /* Setup query IRP */
735 KeResetEvent(&Event);
736 Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO,
737 RealDevice,
738 NULL,
739 0,
740 &PartitionInformation,
741 sizeof(PARTITION_INFORMATION),
742 FALSE,
743 &Event,
744 &IoStatusBlock);
745 if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
746
747 /* Call driver and check if we're pending */
748 Status = IoCallDriver(RealDevice, Irp);
749 if (Status == STATUS_PENDING)
750 {
751 /* Wait on driver to finish */
752 KeWaitForSingleObject(&Event,
753 Executive,
754 KernelMode,
755 FALSE,
756 NULL);
757 Status = IoStatusBlock.Status;
758 }
759
760 /* If this was an invalid request, then the disk is not partitioned */
761 if (Status == STATUS_INVALID_DEVICE_REQUEST)
762 {
763 DiskHasPartitions = FALSE;
764 }
765 else
766 {
767 /* Otherwise, it must be */
768 ASSERT(NT_SUCCESS(Status));
769 DiskHasPartitions = TRUE;
770 }
771 }
772
773 /* Set sector data */
774 Buffer->BytesPerSector = DiskGeometry.BytesPerSector;
775 Buffer->SectorsPerAllocationUnit = 1;
776
777 /* Calculate allocation units */
778 if (DiskHasPartitions)
779 {
780 /* Use partition data */
781 Buffer->TotalAllocationUnits =
782 RtlExtendedLargeIntegerDivide(PartitionInformation.PartitionLength,
783 DiskGeometry.BytesPerSector,
784 NULL);
785 }
786 else
787 {
788 /* Use CHS */
789 Buffer->TotalAllocationUnits =
790 RtlExtendedIntegerMultiply(DiskGeometry.Cylinders,
791 DiskGeometry.TracksPerCylinder *
792 DiskGeometry.SectorsPerTrack);
793 }
794
795 /* Set available units */
796 Buffer->AvailableAllocationUnits = Buffer->TotalAllocationUnits;
797
798 /* Return length and success */
799 *Length -= sizeof(FILE_FS_SIZE_INFORMATION);
800 return STATUS_SUCCESS;
801 }
802
803 NTSTATUS
804 NTAPI
805 RawQueryFsDeviceInfo(IN PVCB Vcb,
806 IN PFILE_FS_DEVICE_INFORMATION Buffer,
807 IN OUT PULONG Length)
808 {
809 PAGED_CODE();
810
811 /* Validate buffer */
812 if (*Length < sizeof(FILE_FS_DEVICE_INFORMATION))
813 {
814 /* Fail */
815 return STATUS_BUFFER_OVERFLOW;
816 }
817
818 /* Clear buffer and write information */
819 RtlZeroMemory(Buffer, sizeof(FILE_FS_DEVICE_INFORMATION));
820 Buffer->DeviceType = FILE_DEVICE_DISK;
821 Buffer->Characteristics = Vcb->TargetDeviceObject->Characteristics;
822
823 /* Return length and success */
824 *Length -= sizeof(FILE_FS_DEVICE_INFORMATION);
825 return STATUS_SUCCESS;
826 }
827
828 NTSTATUS
829 NTAPI
830 RawQueryFsAttributeInfo(IN PVCB Vcb,
831 IN PFILE_FS_ATTRIBUTE_INFORMATION Buffer,
832 IN OUT PULONG Length)
833 {
834 const WCHAR szRawFSName[] = L"RAW";
835 ULONG ReturnLength;
836 PAGED_CODE();
837
838 /* Check if the buffer is large enough for our name ("RAW") */
839 ReturnLength = FIELD_OFFSET(FILE_FS_ATTRIBUTE_INFORMATION,
840 FileSystemName[sizeof(szRawFSName) / sizeof(szRawFSName[0])]);
841 if (*Length < ReturnLength) return STATUS_BUFFER_OVERFLOW;
842
843 /* Output the data */
844 Buffer->FileSystemAttributes = 0;
845 Buffer->MaximumComponentNameLength = 0;
846 Buffer->FileSystemNameLength = 6;
847 RtlCopyMemory(&Buffer->FileSystemName[0], szRawFSName, sizeof(szRawFSName));
848
849 /* Return length and success */
850 *Length -= ReturnLength;
851 return STATUS_SUCCESS;
852 }
853
854 NTSTATUS
855 NTAPI
856 RawQueryVolumeInformation(IN PVCB Vcb,
857 IN PIRP Irp,
858 IN PIO_STACK_LOCATION IoStackLocation)
859 {
860 NTSTATUS Status;
861 ULONG Length;
862 PVOID Buffer;
863 PAGED_CODE();
864
865 /* Get IRP Data */
866 Length = IoStackLocation->Parameters.QueryVolume.Length;
867 Buffer = Irp->AssociatedIrp.SystemBuffer;
868
869 /* Check the kind of request */
870 switch (IoStackLocation->Parameters.QueryVolume.FsInformationClass)
871 {
872 /* Volume information request */
873 case FileFsVolumeInformation:
874
875 Status = RawQueryFsVolumeInfo(Vcb, Buffer, &Length);
876 break;
877
878 /* File system size invormation */
879 case FileFsSizeInformation:
880
881 Status = RawQueryFsSizeInfo(Vcb, Buffer, &Length);
882 break;
883
884 /* Device information */
885 case FileFsDeviceInformation:
886
887 Status = RawQueryFsDeviceInfo(Vcb, Buffer, &Length);
888 break;
889
890 /* Attribute information */
891 case FileFsAttributeInformation:
892
893 Status = RawQueryFsAttributeInfo(Vcb, Buffer, &Length);
894 break;
895
896 /* Invalid request */
897 default:
898
899 /* Fail it */
900 Status = STATUS_INVALID_PARAMETER;
901 break;
902 }
903
904 /* Set status and complete the request */
905 Irp->IoStatus.Information = IoStackLocation->
906 Parameters.QueryVolume.Length - Length;
907 Irp->IoStatus.Status = Status;
908 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
909 return Status;
910 }
911
912 NTSTATUS
913 NTAPI
914 RawCleanup(IN PVCB Vcb,
915 IN PIRP Irp,
916 IN PIO_STACK_LOCATION IoStackLocation)
917 {
918 NTSTATUS Status;
919 PAGED_CODE();
920
921 /* Make sure we can clean up */
922 Status = KeWaitForSingleObject(&Vcb->Mutex,
923 Executive,
924 KernelMode,
925 FALSE,
926 NULL);
927 ASSERT(NT_SUCCESS(Status));
928
929 /* Remove shared access and complete the request */
930 IoRemoveShareAccess(IoStackLocation->FileObject, &Vcb->ShareAccess);
931 KeReleaseMutex(&Vcb->Mutex, FALSE);
932 Irp->IoStatus.Status = STATUS_SUCCESS;
933 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
934 return STATUS_SUCCESS;
935 }
936
937 NTSTATUS
938 NTAPI
939 RawDispatch(IN PVOLUME_DEVICE_OBJECT DeviceObject,
940 IN PIRP Irp)
941 {
942 NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST;
943 PIO_STACK_LOCATION IoStackLocation;
944 PVCB Vcb;
945 PAGED_CODE();
946
947 /* Get the stack location */
948 IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
949
950 /* Differentiate between Volume DO and FS DO */
951 if ((((PDEVICE_OBJECT)DeviceObject)->Size == sizeof(DEVICE_OBJECT)) &&
952 !((IoStackLocation->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) &&
953 (IoStackLocation->MinorFunction == IRP_MN_MOUNT_VOLUME)))
954 {
955 /* This is an FS DO. Stub out the common calls */
956 if ((IoStackLocation->MajorFunction == IRP_MJ_CREATE) ||
957 (IoStackLocation->MajorFunction == IRP_MJ_CLEANUP) ||
958 (IoStackLocation->MajorFunction == IRP_MJ_CLOSE))
959 {
960 /* Return success for them */
961 Status = STATUS_SUCCESS;
962 }
963 else
964 {
965 /* Anything else, we don't support */
966 Status = STATUS_INVALID_DEVICE_REQUEST;
967 }
968
969 /* Complete the request */
970 Irp->IoStatus.Status = Status;
971 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
972 return Status;
973 }
974
975 /* Otherwise, get our VCB and start handling the IRP */
976 FsRtlEnterFileSystem();
977 Vcb = &DeviceObject->Vcb;
978
979 /* Check what kind of IRP this is */
980 switch (IoStackLocation->MajorFunction)
981 {
982 /* Cleanup request */
983 case IRP_MJ_CLEANUP:
984
985 Status = RawCleanup(Vcb, Irp, IoStackLocation);
986 break;
987
988 /* Close request */
989 case IRP_MJ_CLOSE:
990
991 Status = RawClose(Vcb, Irp, IoStackLocation);
992 break;
993
994 /* Create request */
995 case IRP_MJ_CREATE:
996
997 Status = RawCreate(Vcb, Irp, IoStackLocation);
998 break;
999
1000 /* FSCTL request */
1001 case IRP_MJ_FILE_SYSTEM_CONTROL:
1002
1003 Status = RawFileSystemControl(Vcb, Irp, IoStackLocation);
1004 break;
1005
1006 /* R/W or IOCTL request */
1007 case IRP_MJ_READ:
1008 case IRP_MJ_WRITE:
1009 case IRP_MJ_DEVICE_CONTROL:
1010
1011 Status = RawReadWriteDeviceControl(Vcb, Irp, IoStackLocation);
1012 break;
1013
1014 /* Information query request */
1015 case IRP_MJ_QUERY_INFORMATION:
1016
1017 Status = RawQueryInformation(Vcb, Irp, IoStackLocation);
1018 break;
1019
1020 /* Information set request */
1021 case IRP_MJ_SET_INFORMATION:
1022
1023 Status = RawSetInformation(Vcb, Irp, IoStackLocation);
1024 break;
1025
1026 /* Volume information request */
1027 case IRP_MJ_QUERY_VOLUME_INFORMATION:
1028
1029 Status = RawQueryVolumeInformation(Vcb, Irp, IoStackLocation);
1030 break;
1031
1032 /* Unexpected request */
1033 default:
1034
1035 /* Anything else is pretty bad */
1036 KeBugCheck(FILE_SYSTEM);
1037 }
1038
1039 /* Return the status */
1040 FsRtlExitFileSystem();
1041 return Status;
1042 }
1043
1044 NTSTATUS
1045 NTAPI
1046 RawShutdown(IN PDEVICE_OBJECT DeviceObject,
1047 IN PIRP Irp)
1048 {
1049 /* Unregister file systems */
1050 #if 0 // FIXME: This freezes ROS at shutdown. PnP Problem?
1051 IoUnregisterFileSystem(RawDiskDeviceObject);
1052 IoUnregisterFileSystem(RawCdromDeviceObject);
1053 IoUnregisterFileSystem(RawTapeDeviceObject);
1054
1055 /* Delete the devices */
1056 IoDeleteDevice(RawDiskDeviceObject);
1057 IoDeleteDevice(RawCdromDeviceObject);
1058 IoDeleteDevice(RawTapeDeviceObject);
1059 #endif
1060
1061 /* Complete the request */
1062 Irp->IoStatus.Status = STATUS_SUCCESS;
1063 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1064 return STATUS_SUCCESS;
1065 }
1066
1067 VOID
1068 NTAPI
1069 RawUnload(IN PDRIVER_OBJECT DriverObject)
1070 {
1071 #if 0 // FIXME: DriverUnload is never called
1072 /* Dereference device objects */
1073 ObDereferenceObject(RawDiskDeviceObject);
1074 ObDereferenceObject(RawCdromDeviceObject);
1075 ObDereferenceObject(RawTapeDeviceObject);
1076 #endif
1077 }
1078
1079 NTSTATUS
1080 NTAPI
1081 RawFsDriverEntry(IN PDRIVER_OBJECT DriverObject,
1082 IN PUNICODE_STRING RegistryPath)
1083 {
1084 UNICODE_STRING DeviceName;
1085 NTSTATUS Status;
1086
1087 /* Create the raw disk device */
1088 RtlInitUnicodeString(&DeviceName, L"\\Device\\RawDisk");
1089 Status = IoCreateDevice(DriverObject,
1090 0,
1091 NULL,
1092 FILE_DEVICE_DISK_FILE_SYSTEM,
1093 0,
1094 FALSE,
1095 &RawDiskDeviceObject);
1096 if (!NT_SUCCESS(Status)) return Status;
1097
1098 /* Create the raw CDROM device */
1099 RtlInitUnicodeString(&DeviceName, L"\\Device\\RawCdRom");
1100 Status = IoCreateDevice(DriverObject,
1101 0,
1102 NULL,
1103 FILE_DEVICE_CD_ROM_FILE_SYSTEM,
1104 0,
1105 FALSE,
1106 &RawCdromDeviceObject);
1107 if (!NT_SUCCESS(Status)) return Status;
1108
1109 /* Create the raw tape device */
1110 RtlInitUnicodeString(&DeviceName, L"\\Device\\RawTape");
1111 Status = IoCreateDevice(DriverObject,
1112 0,
1113 NULL,
1114 FILE_DEVICE_TAPE_FILE_SYSTEM,
1115 0,
1116 FALSE,
1117 &RawTapeDeviceObject);
1118 if (!NT_SUCCESS(Status)) return Status;
1119
1120 /* Set Direct I/O for all devices */
1121 RawDiskDeviceObject->Flags |= DO_DIRECT_IO;
1122 RawCdromDeviceObject->Flags |= DO_DIRECT_IO;
1123 RawTapeDeviceObject->Flags |= DO_DIRECT_IO;
1124
1125 /* Set generic stubs */
1126 DriverObject->MajorFunction[IRP_MJ_CREATE] =
1127 DriverObject->MajorFunction[IRP_MJ_CLEANUP] =
1128 DriverObject->MajorFunction[IRP_MJ_CLOSE] =
1129 DriverObject->MajorFunction[IRP_MJ_READ] =
1130 DriverObject->MajorFunction[IRP_MJ_WRITE] =
1131 DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] =
1132 DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] =
1133 DriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] =
1134 DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] =
1135 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = (PDRIVER_DISPATCH)RawDispatch;
1136
1137 /* Shutdown and unload */
1138 DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = RawShutdown;
1139 DriverObject->DriverUnload = RawUnload;
1140
1141 /* Register the file systems */
1142 IoRegisterFileSystem(RawDiskDeviceObject);
1143 IoRegisterFileSystem(RawCdromDeviceObject);
1144 IoRegisterFileSystem(RawTapeDeviceObject);
1145
1146 #if 0 // FIXME: DriverUnload is never called
1147 /* Reference device objects */
1148 ObReferenceObject(RawDiskDeviceObject);
1149 ObReferenceObject(RawCdromDeviceObject);
1150 ObReferenceObject(RawTapeDeviceObject);
1151 #endif
1152 return STATUS_SUCCESS;
1153 }
1154
1155 /* EOF */