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