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