143f486977c5e6b3b0a7c87df95ae47a90219f6f
[reactos.git] / reactos / 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 PFILE_POSITION_INFORMATION Buffer;
608 PDEVICE_OBJECT DeviceObject;
609 PAGED_CODE();
610
611 /* Get information from the IRP */
612 Buffer = Irp->AssociatedIrp.SystemBuffer;
613
614 /* We only handle this request */
615 if (IoStackLocation->Parameters.QueryFile.FileInformationClass ==
616 FilePositionInformation)
617 {
618 /* Get the DO */
619 DeviceObject = IoGetRelatedDeviceObject(IoStackLocation->FileObject);
620
621 /* Make sure the offset is aligned */
622 if ((Buffer->CurrentByteOffset.LowPart &
623 DeviceObject->AlignmentRequirement))
624 {
625 /* It's not, fail */
626 Status = STATUS_INVALID_PARAMETER;
627 }
628 else
629 {
630 /* Otherwise, set offset */
631 IoStackLocation->FileObject->CurrentByteOffset = Buffer->
632 CurrentByteOffset;
633
634 /* Set IRP Status information */
635 Status = STATUS_SUCCESS;
636 }
637 }
638
639 /* Complete it */
640 Irp->IoStatus.Status = Status;
641 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
642 return Status;
643 }
644
645 NTSTATUS
646 NTAPI
647 RawQueryFsVolumeInfo(IN PVCB Vcb,
648 IN PFILE_FS_VOLUME_INFORMATION Buffer,
649 IN OUT PULONG Length)
650 {
651 PAGED_CODE();
652
653 /* Clear the buffer and stub it out */
654 RtlZeroMemory( Buffer, sizeof(FILE_FS_VOLUME_INFORMATION));
655 Buffer->VolumeSerialNumber = Vcb->Vpb->SerialNumber;
656 Buffer->SupportsObjects = FALSE;
657 Buffer->VolumeLabelLength = 0;
658
659 /* Return length and success */
660 *Length -= FIELD_OFFSET(FILE_FS_VOLUME_INFORMATION, VolumeLabel[0]);
661 return STATUS_SUCCESS;
662 }
663
664 NTSTATUS
665 NTAPI
666 RawQueryFsSizeInfo(IN PVCB Vcb,
667 IN PFILE_FS_SIZE_INFORMATION Buffer,
668 IN OUT PULONG Length)
669 {
670 PIRP Irp;
671 KEVENT Event;
672 NTSTATUS Status;
673 IO_STATUS_BLOCK IoStatusBlock;
674 PDEVICE_OBJECT RealDevice;
675 DISK_GEOMETRY DiskGeometry;
676 PARTITION_INFORMATION PartitionInformation;
677 BOOLEAN DiskHasPartitions;
678 PAGED_CODE();
679
680 /* Validate the buffer */
681 if (*Length < sizeof(FILE_FS_SIZE_INFORMATION))
682 {
683 /* Fail */
684 return STATUS_BUFFER_OVERFLOW;
685 }
686
687 /* Clear the buffer, initialize the event and set the DO */
688 RtlZeroMemory(Buffer, sizeof(FILE_FS_SIZE_INFORMATION));
689 KeInitializeEvent(&Event, NotificationEvent, FALSE);
690 RealDevice = Vcb->Vpb->RealDevice;
691
692 /* Build query IRP */
693 Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY,
694 RealDevice,
695 NULL,
696 0,
697 &DiskGeometry,
698 sizeof(DISK_GEOMETRY),
699 FALSE,
700 &Event,
701 &IoStatusBlock);
702 if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
703
704 /* Call driver and check if we're pending */
705 Status = IoCallDriver(RealDevice, Irp);
706 if (Status == STATUS_PENDING)
707 {
708 /* Wait on driver to finish */
709 KeWaitForSingleObject(&Event,
710 Executive,
711 KernelMode,
712 FALSE,
713 NULL);
714 Status = IoStatusBlock.Status;
715 }
716
717 /* Fail if we couldn't get CHS data */
718 if (!NT_SUCCESS(Status))
719 {
720 *Length = 0;
721 return Status;
722 }
723
724 /* Check if this is a floppy */
725 if (FlagOn(RealDevice->Characteristics, FILE_FLOPPY_DISKETTE))
726 {
727 /* Floppies don't have partitions */
728 DiskHasPartitions = FALSE;
729 }
730 else
731 {
732 /* Setup query IRP */
733 KeResetEvent(&Event);
734 Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO,
735 RealDevice,
736 NULL,
737 0,
738 &PartitionInformation,
739 sizeof(PARTITION_INFORMATION),
740 FALSE,
741 &Event,
742 &IoStatusBlock);
743 if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
744
745 /* Call driver and check if we're pending */
746 Status = IoCallDriver(RealDevice, Irp);
747 if (Status == STATUS_PENDING)
748 {
749 /* Wait on driver to finish */
750 KeWaitForSingleObject(&Event,
751 Executive,
752 KernelMode,
753 FALSE,
754 NULL);
755 Status = IoStatusBlock.Status;
756 }
757
758 /* If this was an invalid request, then the disk is not partitioned */
759 if (Status == STATUS_INVALID_DEVICE_REQUEST)
760 {
761 DiskHasPartitions = FALSE;
762 }
763 else
764 {
765 /* Otherwise, it must be */
766 ASSERT(NT_SUCCESS(Status));
767 DiskHasPartitions = TRUE;
768 }
769 }
770
771 /* Set sector data */
772 Buffer->BytesPerSector = DiskGeometry.BytesPerSector;
773 Buffer->SectorsPerAllocationUnit = 1;
774
775 /* Calculate allocation units */
776 if (DiskHasPartitions)
777 {
778 /* Use partition data */
779 Buffer->TotalAllocationUnits =
780 RtlExtendedLargeIntegerDivide(PartitionInformation.PartitionLength,
781 DiskGeometry.BytesPerSector,
782 NULL);
783 }
784 else
785 {
786 /* Use CHS */
787 Buffer->TotalAllocationUnits =
788 RtlExtendedIntegerMultiply(DiskGeometry.Cylinders,
789 DiskGeometry.TracksPerCylinder *
790 DiskGeometry.SectorsPerTrack);
791 }
792
793 /* Set available units */
794 Buffer->AvailableAllocationUnits = Buffer->TotalAllocationUnits;
795
796 /* Return length and success */
797 *Length -= sizeof(FILE_FS_SIZE_INFORMATION);
798 return STATUS_SUCCESS;
799 }
800
801 NTSTATUS
802 NTAPI
803 RawQueryFsDeviceInfo(IN PVCB Vcb,
804 IN PFILE_FS_DEVICE_INFORMATION Buffer,
805 IN OUT PULONG Length)
806 {
807 PAGED_CODE();
808
809 /* Validate buffer */
810 if (*Length < sizeof(FILE_FS_DEVICE_INFORMATION))
811 {
812 /* Fail */
813 return STATUS_BUFFER_OVERFLOW;
814 }
815
816 /* Clear buffer and write information */
817 RtlZeroMemory(Buffer, sizeof(FILE_FS_DEVICE_INFORMATION));
818 Buffer->DeviceType = FILE_DEVICE_DISK;
819 Buffer->Characteristics = Vcb->TargetDeviceObject->Characteristics;
820
821 /* Return length and success */
822 *Length -= sizeof(FILE_FS_DEVICE_INFORMATION);
823 return STATUS_SUCCESS;
824 }
825
826 NTSTATUS
827 NTAPI
828 RawQueryFsAttributeInfo(IN PVCB Vcb,
829 IN PFILE_FS_ATTRIBUTE_INFORMATION Buffer,
830 IN OUT PULONG Length)
831 {
832 const WCHAR szRawFSName[] = L"RAW";
833 ULONG ReturnLength;
834 PAGED_CODE();
835
836 /* Check if the buffer is large enough for our name ("RAW") */
837 ReturnLength = FIELD_OFFSET(FILE_FS_ATTRIBUTE_INFORMATION,
838 FileSystemName[sizeof(szRawFSName) / sizeof(szRawFSName[0])]);
839 if (*Length < ReturnLength) return STATUS_BUFFER_OVERFLOW;
840
841 /* Output the data */
842 Buffer->FileSystemAttributes = 0;
843 Buffer->MaximumComponentNameLength = 0;
844 Buffer->FileSystemNameLength = 6;
845 RtlCopyMemory(&Buffer->FileSystemName[0], szRawFSName, sizeof(szRawFSName));
846
847 /* Return length and success */
848 *Length -= ReturnLength;
849 return STATUS_SUCCESS;
850 }
851
852 NTSTATUS
853 NTAPI
854 RawQueryVolumeInformation(IN PVCB Vcb,
855 IN PIRP Irp,
856 IN PIO_STACK_LOCATION IoStackLocation)
857 {
858 NTSTATUS Status;
859 ULONG Length;
860 PVOID Buffer;
861 PAGED_CODE();
862
863 /* Get IRP Data */
864 Length = IoStackLocation->Parameters.QueryVolume.Length;
865 Buffer = Irp->AssociatedIrp.SystemBuffer;
866
867 /* Check the kind of request */
868 switch (IoStackLocation->Parameters.QueryVolume.FsInformationClass)
869 {
870 /* Volume information request */
871 case FileFsVolumeInformation:
872
873 Status = RawQueryFsVolumeInfo(Vcb, Buffer, &Length);
874 break;
875
876 /* File system size invormation */
877 case FileFsSizeInformation:
878
879 Status = RawQueryFsSizeInfo(Vcb, Buffer, &Length);
880 break;
881
882 /* Device information */
883 case FileFsDeviceInformation:
884
885 Status = RawQueryFsDeviceInfo(Vcb, Buffer, &Length);
886 break;
887
888 /* Attribute information */
889 case FileFsAttributeInformation:
890
891 Status = RawQueryFsAttributeInfo(Vcb, Buffer, &Length);
892 break;
893
894 /* Invalid request */
895 default:
896
897 /* Fail it */
898 Status = STATUS_INVALID_PARAMETER;
899 break;
900 }
901
902 /* Set status and complete the request */
903 Irp->IoStatus.Information = IoStackLocation->
904 Parameters.QueryVolume.Length - Length;
905 Irp->IoStatus.Status = Status;
906 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
907 return Status;
908 }
909
910 NTSTATUS
911 NTAPI
912 RawCleanup(IN PVCB Vcb,
913 IN PIRP Irp,
914 IN PIO_STACK_LOCATION IoStackLocation)
915 {
916 NTSTATUS Status;
917 PAGED_CODE();
918
919 /* Make sure we can clean up */
920 Status = KeWaitForSingleObject(&Vcb->Mutex,
921 Executive,
922 KernelMode,
923 FALSE,
924 NULL);
925 ASSERT(NT_SUCCESS(Status));
926
927 /* Remove shared access and complete the request */
928 IoRemoveShareAccess(IoStackLocation->FileObject, &Vcb->ShareAccess);
929 KeReleaseMutex(&Vcb->Mutex, FALSE);
930 Irp->IoStatus.Status = STATUS_SUCCESS;
931 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
932 return STATUS_SUCCESS;
933 }
934
935 NTSTATUS
936 NTAPI
937 RawDispatch(IN PVOLUME_DEVICE_OBJECT DeviceObject,
938 IN PIRP Irp)
939 {
940 NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST;
941 PIO_STACK_LOCATION IoStackLocation;
942 PVCB Vcb;
943 PAGED_CODE();
944
945 /* Get the stack location */
946 IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
947
948 /* Differentiate between Volume DO and FS DO */
949 if ((((PDEVICE_OBJECT)DeviceObject)->Size == sizeof(DEVICE_OBJECT)) &&
950 !((IoStackLocation->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) &&
951 (IoStackLocation->MinorFunction == IRP_MN_MOUNT_VOLUME)))
952 {
953 /* This is an FS DO. Stub out the common calls */
954 if ((IoStackLocation->MajorFunction == IRP_MJ_CREATE) ||
955 (IoStackLocation->MajorFunction == IRP_MJ_CLEANUP) ||
956 (IoStackLocation->MajorFunction == IRP_MJ_CLOSE))
957 {
958 /* Return success for them */
959 Status = STATUS_SUCCESS;
960 }
961 else
962 {
963 /* Anything else, we don't support */
964 Status = STATUS_INVALID_DEVICE_REQUEST;
965 }
966
967 /* Complete the request */
968 Irp->IoStatus.Status = Status;
969 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
970 return Status;
971 }
972
973 /* Otherwise, get our VCB and start handling the IRP */
974 FsRtlEnterFileSystem();
975 Vcb = &DeviceObject->Vcb;
976
977 /* Check what kind of IRP this is */
978 switch (IoStackLocation->MajorFunction)
979 {
980 /* Cleanup request */
981 case IRP_MJ_CLEANUP:
982
983 Status = RawCleanup(Vcb, Irp, IoStackLocation);
984 break;
985
986 /* Close request */
987 case IRP_MJ_CLOSE:
988
989 Status = RawClose(Vcb, Irp, IoStackLocation);
990 break;
991
992 /* Create request */
993 case IRP_MJ_CREATE:
994
995 Status = RawCreate(Vcb, Irp, IoStackLocation);
996 break;
997
998 /* FSCTL request */
999 case IRP_MJ_FILE_SYSTEM_CONTROL:
1000
1001 Status = RawFileSystemControl(Vcb, Irp, IoStackLocation);
1002 break;
1003
1004 /* R/W or IOCTL request */
1005 case IRP_MJ_READ:
1006 case IRP_MJ_WRITE:
1007 case IRP_MJ_DEVICE_CONTROL:
1008
1009 Status = RawReadWriteDeviceControl(Vcb, Irp, IoStackLocation);
1010 break;
1011
1012 /* Information query request */
1013 case IRP_MJ_QUERY_INFORMATION:
1014
1015 Status = RawQueryInformation(Vcb, Irp, IoStackLocation);
1016 break;
1017
1018 /* Information set request */
1019 case IRP_MJ_SET_INFORMATION:
1020
1021 Status = RawSetInformation(Vcb, Irp, IoStackLocation);
1022 break;
1023
1024 /* Volume information request */
1025 case IRP_MJ_QUERY_VOLUME_INFORMATION:
1026
1027 Status = RawQueryVolumeInformation(Vcb, Irp, IoStackLocation);
1028 break;
1029
1030 /* Unexpected request */
1031 default:
1032
1033 /* Anything else is pretty bad */
1034 KeBugCheck(FILE_SYSTEM);
1035 }
1036
1037 /* Return the status */
1038 FsRtlExitFileSystem();
1039 return Status;
1040 }
1041
1042 NTSTATUS
1043 NTAPI
1044 RawShutdown(IN PDEVICE_OBJECT DeviceObject,
1045 IN PIRP Irp)
1046 {
1047 /* Unregister file systems */
1048 #if 0 // FIXME: This freezes ROS at shutdown. PnP Problem?
1049 IoUnregisterFileSystem(RawDiskDeviceObject);
1050 IoUnregisterFileSystem(RawCdromDeviceObject);
1051 IoUnregisterFileSystem(RawTapeDeviceObject);
1052
1053 /* Delete the devices */
1054 IoDeleteDevice(RawDiskDeviceObject);
1055 IoDeleteDevice(RawCdromDeviceObject);
1056 IoDeleteDevice(RawTapeDeviceObject);
1057 #endif
1058
1059 /* Complete the request */
1060 Irp->IoStatus.Status = STATUS_SUCCESS;
1061 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1062 return STATUS_SUCCESS;
1063 }
1064
1065 VOID
1066 NTAPI
1067 RawUnload(IN PDRIVER_OBJECT DriverObject)
1068 {
1069 #if 0 // FIXME: DriverUnload is never called
1070 /* Dereference device objects */
1071 ObDereferenceObject(RawDiskDeviceObject);
1072 ObDereferenceObject(RawCdromDeviceObject);
1073 ObDereferenceObject(RawTapeDeviceObject);
1074 #endif
1075 }
1076
1077 NTSTATUS
1078 NTAPI
1079 INIT_FUNCTION
1080 RawFsDriverEntry(IN PDRIVER_OBJECT DriverObject,
1081 IN PUNICODE_STRING RegistryPath)
1082 {
1083 UNICODE_STRING DeviceName;
1084 NTSTATUS Status;
1085
1086 /* Create the raw disk device */
1087 RtlInitUnicodeString(&DeviceName, L"\\Device\\RawDisk");
1088 Status = IoCreateDevice(DriverObject,
1089 0,
1090 NULL,
1091 FILE_DEVICE_DISK_FILE_SYSTEM,
1092 0,
1093 FALSE,
1094 &RawDiskDeviceObject);
1095 if (!NT_SUCCESS(Status)) return Status;
1096
1097 /* Create the raw CDROM device */
1098 RtlInitUnicodeString(&DeviceName, L"\\Device\\RawCdRom");
1099 Status = IoCreateDevice(DriverObject,
1100 0,
1101 NULL,
1102 FILE_DEVICE_CD_ROM_FILE_SYSTEM,
1103 0,
1104 FALSE,
1105 &RawCdromDeviceObject);
1106 if (!NT_SUCCESS(Status)) return Status;
1107
1108 /* Create the raw tape device */
1109 RtlInitUnicodeString(&DeviceName, L"\\Device\\RawTape");
1110 Status = IoCreateDevice(DriverObject,
1111 0,
1112 NULL,
1113 FILE_DEVICE_TAPE_FILE_SYSTEM,
1114 0,
1115 FALSE,
1116 &RawTapeDeviceObject);
1117 if (!NT_SUCCESS(Status)) return Status;
1118
1119 /* Set Direct I/O for all devices */
1120 RawDiskDeviceObject->Flags |= DO_DIRECT_IO;
1121 RawCdromDeviceObject->Flags |= DO_DIRECT_IO;
1122 RawTapeDeviceObject->Flags |= DO_DIRECT_IO;
1123
1124 /* Set generic stubs */
1125 DriverObject->MajorFunction[IRP_MJ_CREATE] =
1126 DriverObject->MajorFunction[IRP_MJ_CLEANUP] =
1127 DriverObject->MajorFunction[IRP_MJ_CLOSE] =
1128 DriverObject->MajorFunction[IRP_MJ_READ] =
1129 DriverObject->MajorFunction[IRP_MJ_WRITE] =
1130 DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] =
1131 DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] =
1132 DriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] =
1133 DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] =
1134 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = (PDRIVER_DISPATCH)RawDispatch;
1135
1136 /* Shutdown and unload */
1137 DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = RawShutdown;
1138 DriverObject->DriverUnload = RawUnload;
1139
1140 /* Register the file systems */
1141 IoRegisterFileSystem(RawDiskDeviceObject);
1142 IoRegisterFileSystem(RawCdromDeviceObject);
1143 IoRegisterFileSystem(RawTapeDeviceObject);
1144
1145 #if 0 // FIXME: DriverUnload is never called
1146 /* Reference device objects */
1147 ObReferenceObject(RawDiskDeviceObject);
1148 ObReferenceObject(RawCdromDeviceObject);
1149 ObReferenceObject(RawTapeDeviceObject);
1150 #endif
1151 return STATUS_SUCCESS;
1152 }
1153
1154 /* EOF */