d08bb22f496b81d7f50a601b0b838f7d00f38fb1
[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 PVPB DelVpb;
135
136 /* Release our Vcb lock to be able delete us */
137 KeReleaseMutex(&Vcb->Mutex, 0);
138
139 /* If we have a local VPB, we'll have to delete it
140 * but we won't dismount us - something went bad before
141 */
142 if (Vcb->LocalVpb)
143 {
144 DelVpb = Vcb->LocalVpb;
145 }
146 /* Otherwise, dismount our device if possible */
147 else
148 {
149 if (Vcb->Vpb->ReferenceCount)
150 {
151 ObfDereferenceObject(Vcb->TargetDeviceObject);
152 IoDeleteDevice((PDEVICE_OBJECT)CONTAINING_RECORD(Vcb,
153 VOLUME_DEVICE_OBJECT,
154 Vcb));
155 return Delete;
156 }
157
158 DelVpb = Vcb->Vpb;
159 }
160
161 /* Delete any of the available VPB and dismount */
162 ExFreePool(DelVpb);
163 ObfDereferenceObject(Vcb->TargetDeviceObject);
164 IoDeleteDevice((PDEVICE_OBJECT)CONTAINING_RECORD(Vcb,
165 VOLUME_DEVICE_OBJECT,
166 Vcb));
167
168 return Delete;
169 }
170
171 return Delete;
172 }
173
174 NTSTATUS
175 NTAPI
176 RawCompletionRoutine(IN PDEVICE_OBJECT DeviceObject,
177 IN PIRP Irp,
178 IN PVOID Context)
179 {
180 PIO_STACK_LOCATION IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
181
182 DPRINT("RawCompletionRoutine(%p, %p, %p)\n", DeviceObject, Irp, Context);
183
184 /* Check if this was a valid sync R/W request */
185 if (((IoStackLocation->MajorFunction == IRP_MJ_READ) ||
186 (IoStackLocation->MajorFunction == IRP_MJ_WRITE)) &&
187 ((IoStackLocation->FileObject)) &&
188 (FlagOn(IoStackLocation->FileObject->Flags, FO_SYNCHRONOUS_IO)) &&
189 (NT_SUCCESS(Irp->IoStatus.Status)))
190 {
191 /* Update byte offset */
192 IoStackLocation->FileObject->CurrentByteOffset.QuadPart +=
193 Irp->IoStatus.Information;
194 }
195
196 /* Mark the IRP Pending if it was */
197 if (Irp->PendingReturned) IoMarkIrpPending(Irp);
198 return STATUS_SUCCESS;
199 }
200
201 NTSTATUS
202 NTAPI
203 RawClose(IN PVCB Vcb,
204 IN PIRP Irp,
205 IN PIO_STACK_LOCATION IoStackLocation)
206 {
207 NTSTATUS Status;
208 PAGED_CODE();
209
210 DPRINT("RawClose(%p, %p, %p)\n", Vcb, Irp, IoStackLocation);
211
212 /* If its a stream, not much to do */
213 if (IoStackLocation->FileObject->Flags & FO_STREAM_FILE)
214 {
215 Irp->IoStatus.Status = STATUS_SUCCESS;
216 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
217 return STATUS_SUCCESS;
218 }
219
220 /* Make sure we can clean up */
221 Status = KeWaitForSingleObject(&Vcb->Mutex,
222 Executive,
223 KernelMode,
224 FALSE,
225 NULL);
226 ASSERT(NT_SUCCESS(Status));
227
228 /* Decrease the open count and check if this is a dismount */
229 Vcb->OpenCount--;
230 if (!Vcb->OpenCount || !RawCheckForDismount(Vcb, FALSE))
231 {
232 KeReleaseMutex(&Vcb->Mutex, FALSE);
233 }
234
235 /* Complete the request */
236 Irp->IoStatus.Status = STATUS_SUCCESS;
237 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
238 return STATUS_SUCCESS;
239 }
240
241 NTSTATUS
242 NTAPI
243 RawCreate(IN PVCB Vcb,
244 IN PIRP Irp,
245 IN PIO_STACK_LOCATION IoStackLocation)
246 {
247 NTSTATUS Status;
248 USHORT ShareAccess;
249 ACCESS_MASK DesiredAccess;
250 BOOLEAN Deleted = FALSE;
251 PAGED_CODE();
252
253 DPRINT("RawCreate(%p, %p, %p)\n", Vcb, Irp, IoStackLocation);
254
255 /* Make sure we can clean up */
256 Status = KeWaitForSingleObject(&Vcb->Mutex,
257 Executive,
258 KernelMode,
259 FALSE,
260 NULL);
261 ASSERT(NT_SUCCESS(Status));
262
263 /* Check if this is a valid non-directory file open */
264 if ((!(IoStackLocation->FileObject) ||
265 !(IoStackLocation->FileObject->FileName.Length)) &&
266 ((IoStackLocation->Parameters.Create.Options >> 24) == FILE_OPEN) &&
267 (!(IoStackLocation->Parameters.Create.Options & FILE_DIRECTORY_FILE)))
268 {
269 /* Make sure the VCB isn't locked */
270 if (Vcb->VcbState & VCB_STATE_LOCKED)
271 {
272 /* Refuse the operation */
273 Status = STATUS_ACCESS_DENIED;
274 Irp->IoStatus.Information = 0;
275 }
276 else if (Vcb->VcbState & VCB_STATE_DISMOUNTED)
277 {
278 /* Refuse the operation */
279 Status = STATUS_VOLUME_DISMOUNTED;
280 Irp->IoStatus.Information = 0;
281 }
282 else
283 {
284 /* Setup share access */
285 ShareAccess = IoStackLocation->Parameters.Create.ShareAccess;
286 DesiredAccess = IoStackLocation->Parameters.Create.
287 SecurityContext->DesiredAccess;
288
289 /* Check if this VCB was already opened */
290 if (Vcb->OpenCount > 0)
291 {
292 /* Try to see if we have access to it */
293 Status = IoCheckShareAccess(DesiredAccess,
294 ShareAccess,
295 IoStackLocation->FileObject,
296 &Vcb->ShareAccess,
297 TRUE);
298 if (!NT_SUCCESS(Status)) Irp->IoStatus.Information = 0;
299 }
300
301 /* Make sure we have access */
302 if (NT_SUCCESS(Status))
303 {
304 /* Check if this is the first open */
305 if (!Vcb->OpenCount)
306 {
307 /* Set the share access */
308 IoSetShareAccess(DesiredAccess,
309 ShareAccess,
310 IoStackLocation->FileObject,
311 &Vcb->ShareAccess);
312 }
313
314 /* Increase the open count and set the VPB */
315 Vcb->OpenCount++;
316 IoStackLocation->FileObject->Vpb = Vcb->Vpb;
317
318 /* Set IRP status and disable intermediate buffering */
319 Status = STATUS_SUCCESS;
320 Irp->IoStatus.Information = FILE_OPENED;
321 IoStackLocation->FileObject->Flags |=
322 FO_NO_INTERMEDIATE_BUFFERING;
323 }
324 }
325 }
326 else
327 {
328 /* Invalid create request */
329 Status = STATUS_INVALID_PARAMETER;
330 Irp->IoStatus.Information = 0;
331 }
332
333 /* Check if the request failed */
334 if (!NT_SUCCESS(Status) && !Vcb->OpenCount)
335 {
336 /* Check if we can dismount the device */
337 Deleted = RawCheckForDismount(Vcb, TRUE);
338 }
339
340 /* In case of deletion, the mutex is already released */
341 if (!Deleted)
342 {
343 KeReleaseMutex(&Vcb->Mutex, FALSE);
344 }
345
346 /* Complete the request */
347 Irp->IoStatus.Status = Status;
348 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
349 return Status;
350 }
351
352 NTSTATUS
353 NTAPI
354 RawReadWriteDeviceControl(IN PVCB Vcb,
355 IN PIRP Irp,
356 IN PIO_STACK_LOCATION IoStackLocation)
357 {
358 NTSTATUS Status;
359 PAGED_CODE();
360
361 DPRINT("RawReadWriteDeviceControl(%p, %p, %p)\n", Vcb, Irp, IoStackLocation);
362
363 /* Don't do anything if the request was 0 bytes */
364 if (((IoStackLocation->MajorFunction == IRP_MJ_READ) ||
365 (IoStackLocation->MajorFunction == IRP_MJ_WRITE)) &&
366 !(IoStackLocation->Parameters.Read.Length))
367 {
368 /* Complete it */
369 Irp->IoStatus.Status = STATUS_SUCCESS;
370 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
371 return STATUS_SUCCESS;
372 }
373
374 /* Copy the IRP stack location */
375 IoCopyCurrentIrpStackLocationToNext(Irp);
376
377 /* Disable verifies */
378 IoGetNextIrpStackLocation(Irp)->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
379
380 /* Setup a completion routine */
381 IoSetCompletionRoutine(Irp,
382 RawCompletionRoutine,
383 NULL,
384 TRUE,
385 TRUE,
386 TRUE);
387
388 /* Call the next driver and exit */
389 Status = IoCallDriver(Vcb->TargetDeviceObject, Irp);
390 return Status;
391 }
392
393 NTSTATUS
394 NTAPI
395 RawMountVolume(IN PIO_STACK_LOCATION IoStackLocation)
396 {
397 NTSTATUS Status;
398 PDEVICE_OBJECT DeviceObject;
399 PVOLUME_DEVICE_OBJECT Volume;
400 PFILE_OBJECT FileObject = NULL;
401 PAGED_CODE();
402
403 DPRINT("RawMountVolume(%p)\n", IoStackLocation);
404
405 /* Remember our owner */
406 DeviceObject = IoStackLocation->Parameters.MountVolume.DeviceObject;
407
408 /* Create the volume */
409 Status = IoCreateDevice(RawDiskDeviceObject->DriverObject,
410 sizeof(VOLUME_DEVICE_OBJECT) -
411 sizeof(DEVICE_OBJECT),
412 NULL,
413 FILE_DEVICE_DISK_FILE_SYSTEM,
414 0,
415 FALSE,
416 (PDEVICE_OBJECT*)&Volume);
417 if (!NT_SUCCESS(Status)) return Status;
418
419 /* Use highest alignment requirement */
420 Volume->DeviceObject.AlignmentRequirement = max(DeviceObject->
421 AlignmentRequirement,
422 Volume->DeviceObject.
423 AlignmentRequirement);
424
425 /* Setup the VCB */
426 Status = RawInitializeVcb(&Volume->Vcb,
427 IoStackLocation->Parameters.MountVolume.DeviceObject,
428 IoStackLocation->Parameters.MountVolume.Vpb);
429 if (!NT_SUCCESS(Status))
430 {
431 IoDeleteDevice((PDEVICE_OBJECT)Volume);
432 return Status;
433 }
434
435 /* Set dummy label and serial number */
436 Volume->Vcb.Vpb->SerialNumber = 0xFFFFFFFF;
437 Volume->Vcb.Vpb->VolumeLabelLength = 0;
438
439 /* Setup the DO */
440 Volume->Vcb.Vpb->DeviceObject = &Volume->DeviceObject;
441 Volume->DeviceObject.StackSize = DeviceObject->StackSize + 1;
442 Volume->DeviceObject.SectorSize = DeviceObject->SectorSize;
443 Volume->DeviceObject.Flags |= DO_DIRECT_IO;
444 Volume->DeviceObject.Flags &= ~DO_DEVICE_INITIALIZING;
445
446 /* Try to get associated FO (for notification) */
447 _SEH2_TRY
448 {
449 FileObject = IoCreateStreamFileObjectLite(NULL,
450 &(Volume->DeviceObject));
451 }
452 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
453 {
454 /* Get the exception code */
455 Status = _SEH2_GetExceptionCode();
456 }
457 _SEH2_END;
458
459 /* If failed, delete devive */
460 if (!NT_SUCCESS(Status))
461 {
462 IoDeleteDevice((PDEVICE_OBJECT)Volume);
463 return Status;
464 }
465
466 /* Increment OpenCount by two to avoid dismount when RawClose() will be called on ObDereferenceObject() */
467 Volume->Vcb.OpenCount += 2;
468 /* Notify for successful mount */
469 FsRtlNotifyVolumeEvent(FileObject, FSRTL_VOLUME_MOUNT);
470 /* It's not opened anymore, decrease the reference count to 0 to make FileObject being released */
471 ObDereferenceObject(FileObject);
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 */