8ade9a7db5c695306bd088f62cdf5e67ee314224
[reactos.git] / ntoskrnl / io / iomgr / rawfs.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/iomgr/rawfs.c
5 * PURPOSE: Raw File System Driver
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES *****************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* TYPES *******************************************************************/
16
17 typedef struct _VCB
18 {
19 USHORT NodeTypeCode;
20 USHORT NodeByteSize;
21 PDEVICE_OBJECT TargetDeviceObject;
22 PVPB Vpb;
23 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 KeResetEvent(&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 */