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