1 /* 2 * ReactOS kernel 3 * Copyright (C) 2002 ReactOS Team 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. 18 * 19 * COPYRIGHT: See COPYING in the top level directory 20 * PROJECT: ReactOS kernel 21 * FILE: drivers/filesystems/ntfs/fsctl.c 22 * PURPOSE: NTFS filesystem driver 23 * PROGRAMMER: Eric Kohl 24 * Valentin Verkhovsky 25 * Pierre Schweitzer 26 */ 27 28 /* INCLUDES *****************************************************************/ 29 30 #include "ntfs.h" 31 32 #include <ntdddisk.h> 33 34 #define NDEBUG 35 #include <debug.h> 36 37 /* FUNCTIONS ****************************************************************/ 38 39 /* 40 * FUNCTION: Tests if the device contains a filesystem that can be mounted 41 * by this fsd. 42 */ 43 static 44 NTSTATUS 45 NtfsHasFileSystem(PDEVICE_OBJECT DeviceToMount) 46 { 47 PARTITION_INFORMATION PartitionInfo; 48 DISK_GEOMETRY DiskGeometry; 49 ULONG ClusterSize, Size, k; 50 PBOOT_SECTOR BootSector; 51 NTSTATUS Status; 52 53 DPRINT1("NtfsHasFileSystem() called\n"); 54 55 Size = sizeof(DISK_GEOMETRY); 56 Status = NtfsDeviceIoControl(DeviceToMount, 57 IOCTL_DISK_GET_DRIVE_GEOMETRY, 58 NULL, 59 0, 60 &DiskGeometry, 61 &Size, 62 TRUE); 63 if (!NT_SUCCESS(Status)) 64 { 65 DPRINT1("NtfsDeviceIoControl() failed (Status %lx)\n", Status); 66 return Status; 67 } 68 69 if (DiskGeometry.MediaType == FixedMedia) 70 { 71 /* We have found a hard disk */ 72 Size = sizeof(PARTITION_INFORMATION); 73 Status = NtfsDeviceIoControl(DeviceToMount, 74 IOCTL_DISK_GET_PARTITION_INFO, 75 NULL, 76 0, 77 &PartitionInfo, 78 &Size, 79 TRUE); 80 if (!NT_SUCCESS(Status)) 81 { 82 DPRINT1("NtfsDeviceIoControl() failed (Status %lx)\n", Status); 83 return Status; 84 } 85 86 if (PartitionInfo.PartitionType != PARTITION_IFS) 87 { 88 DPRINT1("Invalid partition type\n"); 89 return STATUS_UNRECOGNIZED_VOLUME; 90 } 91 } 92 93 DPRINT1("BytesPerSector: %lu\n", DiskGeometry.BytesPerSector); 94 BootSector = ExAllocatePoolWithTag(NonPagedPool, 95 DiskGeometry.BytesPerSector, 96 TAG_NTFS); 97 if (BootSector == NULL) 98 { 99 return STATUS_INSUFFICIENT_RESOURCES; 100 } 101 102 Status = NtfsReadSectors(DeviceToMount, 103 0, 104 1, 105 DiskGeometry.BytesPerSector, 106 (PVOID)BootSector, 107 TRUE); 108 if (!NT_SUCCESS(Status)) 109 { 110 goto ByeBye; 111 } 112 113 /* 114 * Check values of different fields. If those fields have not expected 115 * values, we fail, to avoid mounting partitions that Windows won't mount. 116 */ 117 118 /* OEMID: this field must be NTFS */ 119 if (RtlCompareMemory(BootSector->OEMID, "NTFS ", 8) != 8) 120 { 121 DPRINT1("Failed with NTFS-identifier: [%.8s]\n", BootSector->OEMID); 122 Status = STATUS_UNRECOGNIZED_VOLUME; 123 goto ByeBye; 124 } 125 126 /* Unused0: this field must be COMPLETELY null */ 127 for (k = 0; k < 7; k++) 128 { 129 if (BootSector->BPB.Unused0[k] != 0) 130 { 131 DPRINT1("Failed in field Unused0: [%.7s]\n", BootSector->BPB.Unused0); 132 Status = STATUS_UNRECOGNIZED_VOLUME; 133 goto ByeBye; 134 } 135 } 136 137 /* Unused3: this field must be COMPLETELY null */ 138 for (k = 0; k < 4; k++) 139 { 140 if (BootSector->BPB.Unused3[k] != 0) 141 { 142 DPRINT1("Failed in field Unused3: [%.4s]\n", BootSector->BPB.Unused3); 143 Status = STATUS_UNRECOGNIZED_VOLUME; 144 goto ByeBye; 145 } 146 } 147 148 /* Check cluster size */ 149 ClusterSize = BootSector->BPB.BytesPerSector * BootSector->BPB.SectorsPerCluster; 150 if (ClusterSize != 512 && ClusterSize != 1024 && 151 ClusterSize != 2048 && ClusterSize != 4096 && 152 ClusterSize != 8192 && ClusterSize != 16384 && 153 ClusterSize != 32768 && ClusterSize != 65536) 154 { 155 DPRINT1("Cluster size failed: %hu, %hu, %hu\n", 156 BootSector->BPB.BytesPerSector, 157 BootSector->BPB.SectorsPerCluster, 158 ClusterSize); 159 Status = STATUS_UNRECOGNIZED_VOLUME; 160 goto ByeBye; 161 } 162 163 ByeBye: 164 ExFreePool(BootSector); 165 166 return Status; 167 } 168 169 170 static 171 ULONG 172 NtfsQueryMftZoneReservation(VOID) 173 { 174 ULONG ZoneReservation = 1; 175 RTL_QUERY_REGISTRY_TABLE QueryTable[2]; 176 177 RtlZeroMemory(QueryTable, sizeof(QueryTable)); 178 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT; 179 QueryTable[0].Name = L"NtfsMftZoneReservation"; 180 QueryTable[0].EntryContext = &ZoneReservation; 181 182 RtlQueryRegistryValues(RTL_REGISTRY_CONTROL, 183 L"FileSystem", 184 QueryTable, 185 NULL, 186 NULL); 187 188 return ZoneReservation; 189 } 190 191 192 static 193 NTSTATUS 194 NtfsGetVolumeData(PDEVICE_OBJECT DeviceObject, 195 PDEVICE_EXTENSION DeviceExt) 196 { 197 DISK_GEOMETRY DiskGeometry; 198 PFILE_RECORD_HEADER VolumeRecord; 199 PVOLINFO_ATTRIBUTE VolumeInfo; 200 PBOOT_SECTOR BootSector; 201 ULONG Size; 202 PNTFS_INFO NtfsInfo = &DeviceExt->NtfsInfo; 203 NTSTATUS Status; 204 PNTFS_ATTR_CONTEXT AttrCtxt; 205 PNTFS_ATTR_RECORD Attribute; 206 PNTFS_FCB VolumeFcb; 207 PWSTR VolumeNameU; 208 209 DPRINT("NtfsGetVolumeData() called\n"); 210 211 Size = sizeof(DISK_GEOMETRY); 212 Status = NtfsDeviceIoControl(DeviceObject, 213 IOCTL_DISK_GET_DRIVE_GEOMETRY, 214 NULL, 215 0, 216 &DiskGeometry, 217 &Size, 218 TRUE); 219 if (!NT_SUCCESS(Status)) 220 { 221 DPRINT("NtfsDeviceIoControl() failed (Status %lx)\n", Status); 222 return Status; 223 } 224 225 DPRINT("BytesPerSector: %lu\n", DiskGeometry.BytesPerSector); 226 BootSector = ExAllocatePoolWithTag(NonPagedPool, 227 DiskGeometry.BytesPerSector, 228 TAG_NTFS); 229 if (BootSector == NULL) 230 { 231 return STATUS_INSUFFICIENT_RESOURCES; 232 } 233 234 Status = NtfsReadSectors(DeviceObject, 235 0, /* Partition boot sector */ 236 1, 237 DiskGeometry.BytesPerSector, 238 (PVOID)BootSector, 239 TRUE); 240 if (!NT_SUCCESS(Status)) 241 { 242 ExFreePool(BootSector); 243 return Status; 244 } 245 246 /* Read data from the bootsector */ 247 NtfsInfo->BytesPerSector = BootSector->BPB.BytesPerSector; 248 NtfsInfo->SectorsPerCluster = BootSector->BPB.SectorsPerCluster; 249 NtfsInfo->BytesPerCluster = BootSector->BPB.BytesPerSector * BootSector->BPB.SectorsPerCluster; 250 NtfsInfo->SectorCount = BootSector->EBPB.SectorCount; 251 NtfsInfo->ClusterCount = DeviceExt->NtfsInfo.SectorCount / (ULONGLONG)DeviceExt->NtfsInfo.SectorsPerCluster; 252 253 NtfsInfo->MftStart.QuadPart = BootSector->EBPB.MftLocation; 254 NtfsInfo->MftMirrStart.QuadPart = BootSector->EBPB.MftMirrLocation; 255 NtfsInfo->SerialNumber = BootSector->EBPB.SerialNumber; 256 if (BootSector->EBPB.ClustersPerMftRecord > 0) 257 NtfsInfo->BytesPerFileRecord = BootSector->EBPB.ClustersPerMftRecord * NtfsInfo->BytesPerCluster; 258 else 259 NtfsInfo->BytesPerFileRecord = 1 << (-BootSector->EBPB.ClustersPerMftRecord); 260 if (BootSector->EBPB.ClustersPerIndexRecord > 0) 261 NtfsInfo->BytesPerIndexRecord = BootSector->EBPB.ClustersPerIndexRecord * NtfsInfo->BytesPerCluster; 262 else 263 NtfsInfo->BytesPerIndexRecord = 1 << (-BootSector->EBPB.ClustersPerIndexRecord); 264 265 DPRINT("Boot sector information:\n"); 266 DPRINT(" BytesPerSector: %hu\n", BootSector->BPB.BytesPerSector); 267 DPRINT(" SectorsPerCluster: %hu\n", BootSector->BPB.SectorsPerCluster); 268 DPRINT(" SectorCount: %I64u\n", BootSector->EBPB.SectorCount); 269 DPRINT(" MftStart: %I64u\n", BootSector->EBPB.MftLocation); 270 DPRINT(" MftMirrStart: %I64u\n", BootSector->EBPB.MftMirrLocation); 271 DPRINT(" ClustersPerMftRecord: %lx\n", BootSector->EBPB.ClustersPerMftRecord); 272 DPRINT(" ClustersPerIndexRecord: %lx\n", BootSector->EBPB.ClustersPerIndexRecord); 273 DPRINT(" SerialNumber: %I64x\n", BootSector->EBPB.SerialNumber); 274 275 ExFreePool(BootSector); 276 277 ExInitializeNPagedLookasideList(&DeviceExt->FileRecLookasideList, 278 NULL, NULL, 0, NtfsInfo->BytesPerFileRecord, TAG_FILE_REC, 0); 279 280 DeviceExt->MasterFileTable = ExAllocateFromNPagedLookasideList(&DeviceExt->FileRecLookasideList); 281 if (DeviceExt->MasterFileTable == NULL) 282 { 283 ExDeleteNPagedLookasideList(&DeviceExt->FileRecLookasideList); 284 return STATUS_INSUFFICIENT_RESOURCES; 285 } 286 287 Status = NtfsReadSectors(DeviceObject, 288 NtfsInfo->MftStart.u.LowPart * NtfsInfo->SectorsPerCluster, 289 NtfsInfo->BytesPerFileRecord / NtfsInfo->BytesPerSector, 290 NtfsInfo->BytesPerSector, 291 (PVOID)DeviceExt->MasterFileTable, 292 TRUE); 293 if (!NT_SUCCESS(Status)) 294 { 295 DPRINT1("Failed reading MFT.\n"); 296 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, DeviceExt->MasterFileTable); 297 ExDeleteNPagedLookasideList(&DeviceExt->FileRecLookasideList); 298 return Status; 299 } 300 301 Status = FindAttribute(DeviceExt, 302 DeviceExt->MasterFileTable, 303 AttributeData, 304 L"", 305 0, 306 &DeviceExt->MFTContext, 307 &DeviceExt->MftDataOffset); 308 if (!NT_SUCCESS(Status)) 309 { 310 DPRINT1("Can't find data attribute for Master File Table.\n"); 311 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, DeviceExt->MasterFileTable); 312 ExDeleteNPagedLookasideList(&DeviceExt->FileRecLookasideList); 313 return Status; 314 } 315 316 VolumeRecord = ExAllocateFromNPagedLookasideList(&DeviceExt->FileRecLookasideList); 317 if (VolumeRecord == NULL) 318 { 319 DPRINT1("Allocation failed for volume record\n"); 320 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, DeviceExt->MasterFileTable); 321 ExDeleteNPagedLookasideList(&DeviceExt->FileRecLookasideList); 322 return STATUS_INSUFFICIENT_RESOURCES; 323 } 324 325 /* Read Volume File (MFT index 3) */ 326 DeviceExt->StorageDevice = DeviceObject; 327 Status = ReadFileRecord(DeviceExt, 328 NTFS_FILE_VOLUME, 329 VolumeRecord); 330 if (!NT_SUCCESS(Status)) 331 { 332 DPRINT1("Failed reading volume file\n"); 333 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, VolumeRecord); 334 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, DeviceExt->MasterFileTable); 335 ExDeleteNPagedLookasideList(&DeviceExt->FileRecLookasideList); 336 return Status; 337 } 338 339 /* Enumerate attributes */ 340 NtfsDumpFileAttributes(DeviceExt, DeviceExt->MasterFileTable); 341 342 /* Enumerate attributes */ 343 NtfsDumpFileAttributes(DeviceExt, VolumeRecord); 344 345 /* Get volume name */ 346 Status = FindAttribute(DeviceExt, VolumeRecord, AttributeVolumeName, L"", 0, &AttrCtxt, NULL); 347 348 if (NT_SUCCESS(Status) && AttrCtxt->pRecord->Resident.ValueLength != 0) 349 { 350 Attribute = AttrCtxt->pRecord; 351 DPRINT("Data length %lu\n", AttributeDataLength(Attribute)); 352 NtfsInfo->VolumeLabelLength = 353 min (Attribute->Resident.ValueLength, MAXIMUM_VOLUME_LABEL_LENGTH); 354 RtlCopyMemory(NtfsInfo->VolumeLabel, 355 (PVOID)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset), 356 NtfsInfo->VolumeLabelLength); 357 VolumeNameU = NtfsInfo->VolumeLabel; 358 } 359 else 360 { 361 NtfsInfo->VolumeLabelLength = 0; 362 VolumeNameU = L"\0"; 363 } 364 365 if (NT_SUCCESS(Status)) 366 { 367 ReleaseAttributeContext(AttrCtxt); 368 } 369 370 VolumeFcb = NtfsCreateFCB(VolumeNameU, NULL, DeviceExt); 371 if (VolumeFcb == NULL) 372 { 373 DPRINT1("Failed allocating volume FCB\n"); 374 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, VolumeRecord); 375 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, DeviceExt->MasterFileTable); 376 ExDeleteNPagedLookasideList(&DeviceExt->FileRecLookasideList); 377 return STATUS_INSUFFICIENT_RESOURCES; 378 } 379 380 VolumeFcb->Flags = FCB_IS_VOLUME; 381 VolumeFcb->RFCB.FileSize.QuadPart = DeviceExt->NtfsInfo.SectorCount * DeviceExt->NtfsInfo.BytesPerSector; 382 VolumeFcb->RFCB.ValidDataLength = VolumeFcb->RFCB.FileSize; 383 VolumeFcb->RFCB.AllocationSize = VolumeFcb->RFCB.FileSize; 384 VolumeFcb->MFTIndex = 0; 385 DeviceExt->VolumeFcb = VolumeFcb; 386 387 /* Get volume information */ 388 Status = FindAttribute(DeviceExt, VolumeRecord, AttributeVolumeInformation, L"", 0, &AttrCtxt, NULL); 389 390 if (NT_SUCCESS(Status) && AttrCtxt->pRecord->Resident.ValueLength != 0) 391 { 392 Attribute = AttrCtxt->pRecord; 393 DPRINT("Data length %lu\n", AttributeDataLength (Attribute)); 394 VolumeInfo = (PVOID)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset); 395 396 NtfsInfo->MajorVersion = VolumeInfo->MajorVersion; 397 NtfsInfo->MinorVersion = VolumeInfo->MinorVersion; 398 NtfsInfo->Flags = VolumeInfo->Flags; 399 } 400 401 if (NT_SUCCESS(Status)) 402 { 403 ReleaseAttributeContext(AttrCtxt); 404 } 405 406 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, VolumeRecord); 407 408 NtfsInfo->MftZoneReservation = NtfsQueryMftZoneReservation(); 409 410 return Status; 411 } 412 413 414 static 415 NTSTATUS 416 NtfsMountVolume(PDEVICE_OBJECT DeviceObject, 417 PIRP Irp) 418 { 419 PDEVICE_OBJECT NewDeviceObject = NULL; 420 PDEVICE_OBJECT DeviceToMount; 421 PIO_STACK_LOCATION Stack; 422 PNTFS_FCB Fcb = NULL; 423 PNTFS_CCB Ccb = NULL; 424 PNTFS_VCB Vcb = NULL; 425 NTSTATUS Status; 426 BOOLEAN Lookaside = FALSE; 427 428 DPRINT1("NtfsMountVolume() called\n"); 429 430 if (DeviceObject != NtfsGlobalData->DeviceObject) 431 { 432 Status = STATUS_INVALID_DEVICE_REQUEST; 433 goto ByeBye; 434 } 435 436 Stack = IoGetCurrentIrpStackLocation(Irp); 437 DeviceToMount = Stack->Parameters.MountVolume.DeviceObject; 438 439 Status = NtfsHasFileSystem(DeviceToMount); 440 if (!NT_SUCCESS(Status)) 441 { 442 goto ByeBye; 443 } 444 445 Status = IoCreateDevice(NtfsGlobalData->DriverObject, 446 sizeof(DEVICE_EXTENSION), 447 NULL, 448 FILE_DEVICE_DISK_FILE_SYSTEM, 449 0, 450 FALSE, 451 &NewDeviceObject); 452 if (!NT_SUCCESS(Status)) 453 goto ByeBye; 454 455 Lookaside = TRUE; 456 457 NewDeviceObject->Flags |= DO_DIRECT_IO; 458 Vcb = (PVOID)NewDeviceObject->DeviceExtension; 459 RtlZeroMemory(Vcb, sizeof(NTFS_VCB)); 460 461 Vcb->Identifier.Type = NTFS_TYPE_VCB; 462 Vcb->Identifier.Size = sizeof(NTFS_TYPE_VCB); 463 464 Status = NtfsGetVolumeData(DeviceToMount, 465 Vcb); 466 if (!NT_SUCCESS(Status)) 467 goto ByeBye; 468 469 NewDeviceObject->Vpb = DeviceToMount->Vpb; 470 471 Vcb->StorageDevice = DeviceToMount; 472 Vcb->StorageDevice->Vpb->DeviceObject = NewDeviceObject; 473 Vcb->StorageDevice->Vpb->RealDevice = Vcb->StorageDevice; 474 Vcb->StorageDevice->Vpb->Flags |= VPB_MOUNTED; 475 NewDeviceObject->StackSize = Vcb->StorageDevice->StackSize + 1; 476 NewDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; 477 478 Vcb->StreamFileObject = IoCreateStreamFileObject(NULL, 479 Vcb->StorageDevice); 480 481 InitializeListHead(&Vcb->FcbListHead); 482 483 Fcb = NtfsCreateFCB(NULL, NULL, Vcb); 484 if (Fcb == NULL) 485 { 486 Status = STATUS_INSUFFICIENT_RESOURCES; 487 goto ByeBye; 488 } 489 490 Ccb = ExAllocatePoolWithTag(NonPagedPool, 491 sizeof(NTFS_CCB), 492 TAG_CCB); 493 if (Ccb == NULL) 494 { 495 Status = STATUS_INSUFFICIENT_RESOURCES; 496 goto ByeBye; 497 } 498 499 RtlZeroMemory(Ccb, sizeof(NTFS_CCB)); 500 501 Ccb->Identifier.Type = NTFS_TYPE_CCB; 502 Ccb->Identifier.Size = sizeof(NTFS_TYPE_CCB); 503 504 Vcb->StreamFileObject->FsContext = Fcb; 505 Vcb->StreamFileObject->FsContext2 = Ccb; 506 Vcb->StreamFileObject->SectionObjectPointer = &Fcb->SectionObjectPointers; 507 Vcb->StreamFileObject->PrivateCacheMap = NULL; 508 Vcb->StreamFileObject->Vpb = Vcb->Vpb; 509 Ccb->PtrFileObject = Vcb->StreamFileObject; 510 Fcb->FileObject = Vcb->StreamFileObject; 511 Fcb->Vcb = (PDEVICE_EXTENSION)Vcb->StorageDevice; 512 513 Fcb->Flags = FCB_IS_VOLUME_STREAM; 514 515 Fcb->RFCB.FileSize.QuadPart = Vcb->NtfsInfo.SectorCount * Vcb->NtfsInfo.BytesPerSector; 516 Fcb->RFCB.ValidDataLength.QuadPart = Vcb->NtfsInfo.SectorCount * Vcb->NtfsInfo.BytesPerSector; 517 Fcb->RFCB.AllocationSize.QuadPart = Vcb->NtfsInfo.SectorCount * Vcb->NtfsInfo.BytesPerSector; /* Correct? */ 518 519 // Fcb->Entry.ExtentLocationL = 0; 520 // Fcb->Entry.DataLengthL = DeviceExt->CdInfo.VolumeSpaceSize * BLOCKSIZE; 521 522 _SEH2_TRY 523 { 524 CcInitializeCacheMap(Vcb->StreamFileObject, 525 (PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize), 526 TRUE, 527 &(NtfsGlobalData->CacheMgrCallbacks), 528 Fcb); 529 } 530 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 531 { 532 Status = _SEH2_GetExceptionCode(); 533 goto ByeBye; 534 } 535 _SEH2_END; 536 537 ExInitializeResourceLite(&Vcb->DirResource); 538 539 KeInitializeSpinLock(&Vcb->FcbListLock); 540 541 /* Get serial number */ 542 NewDeviceObject->Vpb->SerialNumber = Vcb->NtfsInfo.SerialNumber; 543 544 /* Get volume label */ 545 NewDeviceObject->Vpb->VolumeLabelLength = Vcb->NtfsInfo.VolumeLabelLength; 546 RtlCopyMemory(NewDeviceObject->Vpb->VolumeLabel, 547 Vcb->NtfsInfo.VolumeLabel, 548 Vcb->NtfsInfo.VolumeLabelLength); 549 550 FsRtlNotifyVolumeEvent(Vcb->StreamFileObject, FSRTL_VOLUME_MOUNT); 551 552 Status = STATUS_SUCCESS; 553 554 ByeBye: 555 if (!NT_SUCCESS(Status)) 556 { 557 /* Cleanup */ 558 if (Vcb && Vcb->StreamFileObject) 559 ObDereferenceObject(Vcb->StreamFileObject); 560 561 if (Fcb) 562 NtfsDestroyFCB(Fcb); 563 564 if (Ccb) 565 ExFreePool(Ccb); 566 567 if (NewDeviceObject) 568 IoDeleteDevice(NewDeviceObject); 569 570 if (Lookaside) 571 ExDeleteNPagedLookasideList(&Vcb->FileRecLookasideList); 572 } 573 574 DPRINT("NtfsMountVolume() done (Status: %lx)\n", Status); 575 576 return Status; 577 } 578 579 580 static 581 NTSTATUS 582 NtfsVerifyVolume(PDEVICE_OBJECT DeviceObject, 583 PIRP Irp) 584 { 585 UNREFERENCED_PARAMETER(DeviceObject); 586 UNREFERENCED_PARAMETER(Irp); 587 DPRINT1("NtfsVerifyVolume() called\n"); 588 return STATUS_WRONG_VOLUME; 589 } 590 591 592 static 593 NTSTATUS 594 GetNfsVolumeData(PDEVICE_EXTENSION DeviceExt, 595 PIRP Irp) 596 { 597 PIO_STACK_LOCATION Stack; 598 PNTFS_VOLUME_DATA_BUFFER DataBuffer; 599 PNTFS_ATTR_RECORD Attribute; 600 FIND_ATTR_CONTXT Context; 601 NTSTATUS Status; 602 603 DataBuffer = (PNTFS_VOLUME_DATA_BUFFER)Irp->AssociatedIrp.SystemBuffer; 604 Stack = IoGetCurrentIrpStackLocation(Irp); 605 606 if (Stack->Parameters.FileSystemControl.OutputBufferLength < sizeof(NTFS_VOLUME_DATA_BUFFER) || 607 Irp->UserBuffer == NULL) 608 { 609 DPRINT1("Invalid output! %d %p\n", Stack->Parameters.FileSystemControl.OutputBufferLength, Irp->UserBuffer); 610 return STATUS_INVALID_PARAMETER; 611 } 612 613 DataBuffer->VolumeSerialNumber.QuadPart = DeviceExt->NtfsInfo.SerialNumber; 614 DataBuffer->NumberSectors.QuadPart = DeviceExt->NtfsInfo.SectorCount; 615 DataBuffer->TotalClusters.QuadPart = DeviceExt->NtfsInfo.ClusterCount; 616 DataBuffer->FreeClusters.QuadPart = NtfsGetFreeClusters(DeviceExt); 617 DataBuffer->TotalReserved.QuadPart = 0LL; // FIXME 618 DataBuffer->BytesPerSector = DeviceExt->NtfsInfo.BytesPerSector; 619 DataBuffer->BytesPerCluster = DeviceExt->NtfsInfo.BytesPerCluster; 620 DataBuffer->BytesPerFileRecordSegment = DeviceExt->NtfsInfo.BytesPerFileRecord; 621 DataBuffer->ClustersPerFileRecordSegment = DeviceExt->NtfsInfo.BytesPerFileRecord / DeviceExt->NtfsInfo.BytesPerCluster; 622 DataBuffer->MftStartLcn.QuadPart = DeviceExt->NtfsInfo.MftStart.QuadPart; 623 DataBuffer->Mft2StartLcn.QuadPart = DeviceExt->NtfsInfo.MftMirrStart.QuadPart; 624 DataBuffer->MftZoneStart.QuadPart = 0; // FIXME 625 DataBuffer->MftZoneEnd.QuadPart = 0; // FIXME 626 627 Status = FindFirstAttribute(&Context, DeviceExt, DeviceExt->MasterFileTable, FALSE, &Attribute); 628 while (NT_SUCCESS(Status)) 629 { 630 if (Attribute->Type == AttributeData) 631 { 632 ASSERT(Attribute->IsNonResident); 633 DataBuffer->MftValidDataLength.QuadPart = Attribute->NonResident.DataSize; 634 635 break; 636 } 637 638 Status = FindNextAttribute(&Context, &Attribute); 639 } 640 FindCloseAttribute(&Context); 641 642 Irp->IoStatus.Information = sizeof(NTFS_VOLUME_DATA_BUFFER); 643 644 if (Stack->Parameters.FileSystemControl.OutputBufferLength >= sizeof(NTFS_EXTENDED_VOLUME_DATA) + sizeof(NTFS_VOLUME_DATA_BUFFER)) 645 { 646 PNTFS_EXTENDED_VOLUME_DATA ExtendedData = (PNTFS_EXTENDED_VOLUME_DATA)((ULONG_PTR)Irp->UserBuffer + sizeof(NTFS_VOLUME_DATA_BUFFER)); 647 648 ExtendedData->ByteCount = sizeof(NTFS_EXTENDED_VOLUME_DATA); 649 ExtendedData->MajorVersion = DeviceExt->NtfsInfo.MajorVersion; 650 ExtendedData->MinorVersion = DeviceExt->NtfsInfo.MinorVersion; 651 Irp->IoStatus.Information += sizeof(NTFS_EXTENDED_VOLUME_DATA); 652 } 653 654 return STATUS_SUCCESS; 655 } 656 657 658 static 659 NTSTATUS 660 GetNtfsFileRecord(PDEVICE_EXTENSION DeviceExt, 661 PIRP Irp) 662 { 663 NTSTATUS Status; 664 PIO_STACK_LOCATION Stack; 665 PNTFS_FILE_RECORD_INPUT_BUFFER InputBuffer; 666 PFILE_RECORD_HEADER FileRecord; 667 PNTFS_FILE_RECORD_OUTPUT_BUFFER OutputBuffer; 668 ULONGLONG MFTRecord; 669 670 Stack = IoGetCurrentIrpStackLocation(Irp); 671 672 if (Stack->Parameters.FileSystemControl.InputBufferLength < sizeof(NTFS_FILE_RECORD_INPUT_BUFFER) || 673 Irp->AssociatedIrp.SystemBuffer == NULL) 674 { 675 DPRINT1("Invalid input! %d %p\n", Stack->Parameters.FileSystemControl.InputBufferLength, Irp->AssociatedIrp.SystemBuffer); 676 return STATUS_INVALID_PARAMETER; 677 } 678 679 if (Stack->Parameters.FileSystemControl.OutputBufferLength < (FIELD_OFFSET(NTFS_FILE_RECORD_OUTPUT_BUFFER, FileRecordBuffer) + DeviceExt->NtfsInfo.BytesPerFileRecord) || 680 Irp->AssociatedIrp.SystemBuffer == NULL) 681 { 682 DPRINT1("Invalid output! %d %p\n", Stack->Parameters.FileSystemControl.OutputBufferLength, Irp->AssociatedIrp.SystemBuffer); 683 return STATUS_BUFFER_TOO_SMALL; 684 } 685 686 FileRecord = ExAllocateFromNPagedLookasideList(&DeviceExt->FileRecLookasideList); 687 if (FileRecord == NULL) 688 { 689 return STATUS_INSUFFICIENT_RESOURCES; 690 } 691 692 InputBuffer = (PNTFS_FILE_RECORD_INPUT_BUFFER)Irp->AssociatedIrp.SystemBuffer; 693 694 MFTRecord = InputBuffer->FileReferenceNumber.QuadPart; 695 DPRINT1("Requesting: %I64x\n", MFTRecord); 696 697 do 698 { 699 Status = ReadFileRecord(DeviceExt, MFTRecord, FileRecord); 700 if (NT_SUCCESS(Status)) 701 { 702 if (FileRecord->Flags & FRH_IN_USE) 703 { 704 break; 705 } 706 } 707 708 --MFTRecord; 709 } while (TRUE); 710 711 DPRINT1("Returning: %I64x\n", MFTRecord); 712 OutputBuffer = (PNTFS_FILE_RECORD_OUTPUT_BUFFER)Irp->AssociatedIrp.SystemBuffer; 713 OutputBuffer->FileReferenceNumber.QuadPart = MFTRecord; 714 OutputBuffer->FileRecordLength = DeviceExt->NtfsInfo.BytesPerFileRecord; 715 RtlCopyMemory(OutputBuffer->FileRecordBuffer, FileRecord, DeviceExt->NtfsInfo.BytesPerFileRecord); 716 717 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord); 718 719 Irp->IoStatus.Information = FIELD_OFFSET(NTFS_FILE_RECORD_OUTPUT_BUFFER, FileRecordBuffer) + DeviceExt->NtfsInfo.BytesPerFileRecord; 720 721 return STATUS_SUCCESS; 722 } 723 724 725 static 726 NTSTATUS 727 GetVolumeBitmap(PDEVICE_EXTENSION DeviceExt, 728 PIRP Irp) 729 { 730 NTSTATUS Status = STATUS_SUCCESS; 731 PIO_STACK_LOCATION Stack; 732 PVOLUME_BITMAP_BUFFER BitmapBuffer; 733 LONGLONG StartingLcn; 734 PFILE_RECORD_HEADER BitmapRecord; 735 PNTFS_ATTR_CONTEXT DataContext; 736 ULONGLONG TotalClusters; 737 ULONGLONG ToCopy; 738 BOOLEAN Overflow = FALSE; 739 740 DPRINT1("GetVolumeBitmap(%p, %p)\n", DeviceExt, Irp); 741 742 Stack = IoGetCurrentIrpStackLocation(Irp); 743 744 if (Stack->Parameters.FileSystemControl.InputBufferLength < sizeof(STARTING_LCN_INPUT_BUFFER)) 745 { 746 DPRINT1("Invalid input! %d\n", Stack->Parameters.FileSystemControl.InputBufferLength); 747 return STATUS_INVALID_PARAMETER; 748 } 749 750 if (Stack->Parameters.FileSystemControl.OutputBufferLength < sizeof(VOLUME_BITMAP_BUFFER)) 751 { 752 DPRINT1("Invalid output! %d\n", Stack->Parameters.FileSystemControl.OutputBufferLength); 753 return STATUS_BUFFER_TOO_SMALL; 754 } 755 756 BitmapBuffer = NtfsGetUserBuffer(Irp, FALSE); 757 if (Irp->RequestorMode == UserMode) 758 { 759 _SEH2_TRY 760 { 761 ProbeForRead(Stack->Parameters.FileSystemControl.Type3InputBuffer, 762 Stack->Parameters.FileSystemControl.InputBufferLength, 763 sizeof(CHAR)); 764 ProbeForWrite(BitmapBuffer, Stack->Parameters.FileSystemControl.OutputBufferLength, 765 sizeof(CHAR)); 766 } 767 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 768 { 769 Status = _SEH2_GetExceptionCode(); 770 } 771 _SEH2_END; 772 } 773 else 774 { 775 if (Stack->Parameters.FileSystemControl.Type3InputBuffer == NULL || 776 BitmapBuffer == NULL) 777 { 778 Status = STATUS_INVALID_PARAMETER; 779 } 780 } 781 782 if (!NT_SUCCESS(Status)) 783 { 784 DPRINT1("Invalid buffer! %p %p\n", Stack->Parameters.FileSystemControl.Type3InputBuffer, BitmapBuffer); 785 return Status; 786 } 787 788 StartingLcn = ((PSTARTING_LCN_INPUT_BUFFER)Stack->Parameters.FileSystemControl.Type3InputBuffer)->StartingLcn.QuadPart; 789 if (StartingLcn > DeviceExt->NtfsInfo.ClusterCount) 790 { 791 DPRINT1("Requested bitmap start beyond partition end: %I64x %I64x\n", DeviceExt->NtfsInfo.ClusterCount, StartingLcn); 792 return STATUS_INVALID_PARAMETER; 793 } 794 795 /* Round down to a multiple of 8 */ 796 StartingLcn = StartingLcn & ~7; 797 TotalClusters = DeviceExt->NtfsInfo.ClusterCount - StartingLcn; 798 ToCopy = TotalClusters / 8; 799 if ((ToCopy + FIELD_OFFSET(VOLUME_BITMAP_BUFFER, Buffer)) > Stack->Parameters.FileSystemControl.OutputBufferLength) 800 { 801 DPRINT1("Buffer too small: %x, needed: %x\n", Stack->Parameters.FileSystemControl.OutputBufferLength, (ToCopy + FIELD_OFFSET(VOLUME_BITMAP_BUFFER, Buffer))); 802 Overflow = TRUE; 803 ToCopy = Stack->Parameters.FileSystemControl.OutputBufferLength - FIELD_OFFSET(VOLUME_BITMAP_BUFFER, Buffer); 804 } 805 806 BitmapRecord = ExAllocateFromNPagedLookasideList(&DeviceExt->FileRecLookasideList); 807 if (BitmapRecord == NULL) 808 { 809 return STATUS_INSUFFICIENT_RESOURCES; 810 } 811 812 Status = ReadFileRecord(DeviceExt, NTFS_FILE_BITMAP, BitmapRecord); 813 if (!NT_SUCCESS(Status)) 814 { 815 DPRINT1("Failed reading volume bitmap: %lx\n", Status); 816 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, BitmapRecord); 817 return Status; 818 } 819 820 Status = FindAttribute(DeviceExt, BitmapRecord, AttributeData, L"", 0, &DataContext, NULL); 821 if (!NT_SUCCESS(Status)) 822 { 823 DPRINT1("Failed find $DATA for bitmap: %lx\n", Status); 824 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, BitmapRecord); 825 return Status; 826 } 827 828 BitmapBuffer->StartingLcn.QuadPart = StartingLcn; 829 BitmapBuffer->BitmapSize.QuadPart = ToCopy * 8; 830 831 Irp->IoStatus.Information = FIELD_OFFSET(VOLUME_BITMAP_BUFFER, Buffer); 832 _SEH2_TRY 833 { 834 Irp->IoStatus.Information += ReadAttribute(DeviceExt, DataContext, StartingLcn / 8, (PCHAR)BitmapBuffer->Buffer, ToCopy); 835 Status = (Overflow ? STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS); 836 } 837 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 838 { 839 Status = _SEH2_GetExceptionCode(); 840 } 841 _SEH2_END; 842 ReleaseAttributeContext(DataContext); 843 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, BitmapRecord); 844 845 return Status; 846 } 847 848 849 static 850 NTSTATUS 851 LockOrUnlockVolume(PDEVICE_EXTENSION DeviceExt, 852 PIRP Irp, 853 BOOLEAN Lock) 854 { 855 PFILE_OBJECT FileObject; 856 PNTFS_FCB Fcb; 857 PIO_STACK_LOCATION Stack; 858 859 DPRINT("LockOrUnlockVolume(%p, %p, %d)\n", DeviceExt, Irp, Lock); 860 861 Stack = IoGetCurrentIrpStackLocation(Irp); 862 FileObject = Stack->FileObject; 863 Fcb = FileObject->FsContext; 864 865 /* Only allow locking with the volume open */ 866 if (!(Fcb->Flags & FCB_IS_VOLUME)) 867 { 868 return STATUS_ACCESS_DENIED; 869 } 870 871 /* Bail out if it's already in the demanded state */ 872 if (((DeviceExt->Flags & VCB_VOLUME_LOCKED) && Lock) || 873 (!(DeviceExt->Flags & VCB_VOLUME_LOCKED) && !Lock)) 874 { 875 return STATUS_ACCESS_DENIED; 876 } 877 878 /* Deny locking if we're not alone */ 879 if (Lock && DeviceExt->OpenHandleCount != 1) 880 { 881 return STATUS_ACCESS_DENIED; 882 } 883 884 /* Finally, proceed */ 885 if (Lock) 886 { 887 DeviceExt->Flags |= VCB_VOLUME_LOCKED; 888 } 889 else 890 { 891 DeviceExt->Flags &= ~VCB_VOLUME_LOCKED; 892 } 893 894 return STATUS_SUCCESS; 895 } 896 897 898 static 899 NTSTATUS 900 NtfsUserFsRequest(PDEVICE_OBJECT DeviceObject, 901 PIRP Irp) 902 { 903 NTSTATUS Status; 904 PIO_STACK_LOCATION Stack; 905 PDEVICE_EXTENSION DeviceExt; 906 907 DPRINT("NtfsUserFsRequest(%p, %p)\n", DeviceObject, Irp); 908 909 Stack = IoGetCurrentIrpStackLocation(Irp); 910 DeviceExt = DeviceObject->DeviceExtension; 911 switch (Stack->Parameters.FileSystemControl.FsControlCode) 912 { 913 case FSCTL_CREATE_USN_JOURNAL: 914 case FSCTL_DELETE_USN_JOURNAL: 915 case FSCTL_ENUM_USN_DATA: 916 case FSCTL_EXTEND_VOLUME: 917 //case FSCTL_GET_RETRIEVAL_POINTER_BASE: 918 case FSCTL_GET_RETRIEVAL_POINTERS: 919 //case FSCTL_LOOKUP_STREAM_FROM_CLUSTER: 920 case FSCTL_MARK_HANDLE: 921 case FSCTL_MOVE_FILE: 922 case FSCTL_QUERY_USN_JOURNAL: 923 case FSCTL_READ_FILE_USN_DATA: 924 case FSCTL_READ_USN_JOURNAL: 925 //case FSCTL_SHRINK_VOLUME: 926 case FSCTL_WRITE_USN_CLOSE_RECORD: 927 UNIMPLEMENTED; 928 DPRINT1("Unimplemented user request: %x\n", Stack->Parameters.FileSystemControl.FsControlCode); 929 Status = STATUS_NOT_IMPLEMENTED; 930 break; 931 932 case FSCTL_LOCK_VOLUME: 933 Status = LockOrUnlockVolume(DeviceExt, Irp, TRUE); 934 break; 935 936 case FSCTL_UNLOCK_VOLUME: 937 Status = LockOrUnlockVolume(DeviceExt, Irp, FALSE); 938 break; 939 940 case FSCTL_GET_NTFS_VOLUME_DATA: 941 Status = GetNfsVolumeData(DeviceExt, Irp); 942 break; 943 944 case FSCTL_GET_NTFS_FILE_RECORD: 945 Status = GetNtfsFileRecord(DeviceExt, Irp); 946 break; 947 948 case FSCTL_GET_VOLUME_BITMAP: 949 Status = GetVolumeBitmap(DeviceExt, Irp); 950 break; 951 952 default: 953 DPRINT("Invalid user request: %x\n", Stack->Parameters.FileSystemControl.FsControlCode); 954 Status = STATUS_INVALID_DEVICE_REQUEST; 955 break; 956 } 957 958 return Status; 959 } 960 961 962 NTSTATUS 963 NtfsFileSystemControl(PNTFS_IRP_CONTEXT IrpContext) 964 { 965 NTSTATUS Status; 966 PIRP Irp; 967 PDEVICE_OBJECT DeviceObject; 968 969 DPRINT("NtfsFileSystemControl() called\n"); 970 971 DeviceObject = IrpContext->DeviceObject; 972 Irp = IrpContext->Irp; 973 Irp->IoStatus.Information = 0; 974 975 switch (IrpContext->MinorFunction) 976 { 977 case IRP_MN_KERNEL_CALL: 978 DPRINT1("NTFS: IRP_MN_USER_FS_REQUEST\n"); 979 Status = STATUS_INVALID_DEVICE_REQUEST; 980 break; 981 982 case IRP_MN_USER_FS_REQUEST: 983 Status = NtfsUserFsRequest(DeviceObject, Irp); 984 break; 985 986 case IRP_MN_MOUNT_VOLUME: 987 DPRINT("NTFS: IRP_MN_MOUNT_VOLUME\n"); 988 Status = NtfsMountVolume(DeviceObject, Irp); 989 break; 990 991 case IRP_MN_VERIFY_VOLUME: 992 DPRINT1("NTFS: IRP_MN_VERIFY_VOLUME\n"); 993 Status = NtfsVerifyVolume(DeviceObject, Irp); 994 break; 995 996 default: 997 DPRINT1("NTFS FSC: MinorFunction %d\n", IrpContext->MinorFunction); 998 Status = STATUS_INVALID_DEVICE_REQUEST; 999 break; 1000 } 1001 1002 return Status; 1003 } 1004 1005 /* EOF */ 1006