569be1a1bf39f0039ccfa67a2cd11a647ec85f53
[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
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 ObfDereferenceObject(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 NTSTATUS
1191 NTAPI
1192 INIT_FUNCTION
1193 RawFsDriverEntry(IN PDRIVER_OBJECT DriverObject,
1194 IN PUNICODE_STRING RegistryPath)
1195 {
1196 UNICODE_STRING DeviceName;
1197 NTSTATUS Status;
1198
1199 /* Create the raw disk device */
1200 RtlInitUnicodeString(&DeviceName, L"\\Device\\RawDisk");
1201 Status = IoCreateDevice(DriverObject,
1202 0,
1203 NULL,
1204 FILE_DEVICE_DISK_FILE_SYSTEM,
1205 0,
1206 FALSE,
1207 &RawDiskDeviceObject);
1208 if (!NT_SUCCESS(Status)) return Status;
1209
1210 /* Create the raw CDROM device */
1211 RtlInitUnicodeString(&DeviceName, L"\\Device\\RawCdRom");
1212 Status = IoCreateDevice(DriverObject,
1213 0,
1214 NULL,
1215 FILE_DEVICE_CD_ROM_FILE_SYSTEM,
1216 0,
1217 FALSE,
1218 &RawCdromDeviceObject);
1219 if (!NT_SUCCESS(Status)) return Status;
1220
1221 /* Create the raw tape device */
1222 RtlInitUnicodeString(&DeviceName, L"\\Device\\RawTape");
1223 Status = IoCreateDevice(DriverObject,
1224 0,
1225 NULL,
1226 FILE_DEVICE_TAPE_FILE_SYSTEM,
1227 0,
1228 FALSE,
1229 &RawTapeDeviceObject);
1230 if (!NT_SUCCESS(Status)) return Status;
1231
1232 /* Set Direct I/O for all devices */
1233 RawDiskDeviceObject->Flags |= DO_DIRECT_IO;
1234 RawCdromDeviceObject->Flags |= DO_DIRECT_IO;
1235 RawTapeDeviceObject->Flags |= DO_DIRECT_IO;
1236
1237 /* Set generic stubs */
1238 DriverObject->MajorFunction[IRP_MJ_CREATE] =
1239 DriverObject->MajorFunction[IRP_MJ_CLEANUP] =
1240 DriverObject->MajorFunction[IRP_MJ_CLOSE] =
1241 DriverObject->MajorFunction[IRP_MJ_READ] =
1242 DriverObject->MajorFunction[IRP_MJ_WRITE] =
1243 DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] =
1244 DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] =
1245 DriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] =
1246 DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] =
1247 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = RawDispatch;
1248
1249 /* Shutdown and unload */
1250 DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = RawShutdown;
1251 DriverObject->DriverUnload = RawUnload;
1252
1253 /* Register the file systems */
1254 IoRegisterFileSystem(RawDiskDeviceObject);
1255 IoRegisterFileSystem(RawCdromDeviceObject);
1256 IoRegisterFileSystem(RawTapeDeviceObject);
1257
1258 #if 0 // FIXME: DriverUnload is never called
1259 /* Reference device objects */
1260 ObReferenceObject(RawDiskDeviceObject);
1261 ObReferenceObject(RawCdromDeviceObject);
1262 ObReferenceObject(RawTapeDeviceObject);
1263 #endif
1264 return STATUS_SUCCESS;
1265 }
1266
1267 /* EOF */