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