NTSTATUS ReadLCN(PDEVICE_EXTENSION Vcb, ULONGLONG lcn, ULONG count, PVOID buffer) { LARGE_INTEGER DiskSector; DiskSector.QuadPart = lcn; return NtfsReadSectors(Vcb->StorageDevice, DiskSector.u.LowPart * Vcb->NtfsInfo.SectorsPerCluster, count * Vcb->NtfsInfo.SectorsPerCluster, Vcb->NtfsInfo.BytesPerSector, buffer, FALSE); }
/* * FUNCTION: Tests if the device contains a filesystem that can be mounted * by this fsd. */ static NTSTATUS NtfsHasFileSystem(PDEVICE_OBJECT DeviceToMount) { PARTITION_INFORMATION PartitionInfo; DISK_GEOMETRY DiskGeometry; ULONG ClusterSize, Size, k; PBOOT_SECTOR BootSector; NTSTATUS Status; DPRINT1("NtfsHasFileSystem() called\n"); Size = sizeof(DISK_GEOMETRY); Status = NtfsDeviceIoControl(DeviceToMount, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &DiskGeometry, &Size, TRUE); if (!NT_SUCCESS(Status)) { DPRINT1("NtfsDeviceIoControl() failed (Status %lx)\n", Status); return Status; } if (DiskGeometry.MediaType == FixedMedia) { /* We have found a hard disk */ Size = sizeof(PARTITION_INFORMATION); Status = NtfsDeviceIoControl(DeviceToMount, IOCTL_DISK_GET_PARTITION_INFO, NULL, 0, &PartitionInfo, &Size, TRUE); if (!NT_SUCCESS(Status)) { DPRINT1("NtfsDeviceIoControl() failed (Status %lx)\n", Status); return Status; } if (PartitionInfo.PartitionType != PARTITION_IFS) { DPRINT1("Invalid partition type\n"); return STATUS_UNRECOGNIZED_VOLUME; } } DPRINT1("BytesPerSector: %lu\n", DiskGeometry.BytesPerSector); BootSector = ExAllocatePoolWithTag(NonPagedPool, DiskGeometry.BytesPerSector, TAG_NTFS); if (BootSector == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } Status = NtfsReadSectors(DeviceToMount, 0, 1, DiskGeometry.BytesPerSector, (PVOID)BootSector, TRUE); if (!NT_SUCCESS(Status)) { goto ByeBye; } /* * Check values of different fields. If those fields have not expected * values, we fail, to avoid mounting partitions that Windows won't mount. */ /* OEMID: this field must be NTFS */ if (RtlCompareMemory(BootSector->OEMID, "NTFS ", 8) != 8) { DPRINT1("Failed with NTFS-identifier: [%.8s]\n", BootSector->OEMID); Status = STATUS_UNRECOGNIZED_VOLUME; goto ByeBye; } /* Unused0: this field must be COMPLETELY null */ for (k = 0; k < 7; k++) { if (BootSector->BPB.Unused0[k] != 0) { DPRINT1("Failed in field Unused0: [%.7s]\n", BootSector->BPB.Unused0); Status = STATUS_UNRECOGNIZED_VOLUME; goto ByeBye; } } /* Unused3: this field must be COMPLETELY null */ for (k = 0; k < 4; k++) { if (BootSector->BPB.Unused3[k] != 0) { DPRINT1("Failed in field Unused3: [%.4s]\n", BootSector->BPB.Unused3); Status = STATUS_UNRECOGNIZED_VOLUME; goto ByeBye; } } /* Check cluster size */ ClusterSize = BootSector->BPB.BytesPerSector * BootSector->BPB.SectorsPerCluster; if (ClusterSize != 512 && ClusterSize != 1024 && ClusterSize != 2048 && ClusterSize != 4096 && ClusterSize != 8192 && ClusterSize != 16384 && ClusterSize != 32768 && ClusterSize != 65536) { DPRINT1("Cluster size failed: %hu, %hu, %hu\n", BootSector->BPB.BytesPerSector, BootSector->BPB.SectorsPerCluster, ClusterSize); Status = STATUS_UNRECOGNIZED_VOLUME; goto ByeBye; } ByeBye: ExFreePool(BootSector); return Status; }
static NTSTATUS NtfsGetVolumeData(PDEVICE_OBJECT DeviceObject, PDEVICE_EXTENSION DeviceExt) { DISK_GEOMETRY DiskGeometry; PFILE_RECORD_HEADER MftRecord; PFILE_RECORD_HEADER VolumeRecord; PVOLINFO_ATTRIBUTE VolumeInfo; PBOOT_SECTOR BootSector; PATTRIBUTE Attribute; ULONG Size; PNTFS_INFO NtfsInfo = &DeviceExt->NtfsInfo; NTSTATUS Status; DPRINT("NtfsGetVolumeData() called\n"); Size = sizeof(DISK_GEOMETRY); Status = NtfsDeviceIoControl(DeviceObject, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &DiskGeometry, &Size, TRUE); if (!NT_SUCCESS(Status)) { DPRINT("NtfsDeviceIoControl() failed (Status %lx)\n", Status); return Status; } DPRINT("BytesPerSector: %lu\n", DiskGeometry.BytesPerSector); BootSector = ExAllocatePoolWithTag(NonPagedPool, DiskGeometry.BytesPerSector, TAG_NTFS); if (BootSector == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } Status = NtfsReadSectors(DeviceObject, 0, /* Partition boot sector */ 1, DiskGeometry.BytesPerSector, (PVOID)BootSector, TRUE); if (!NT_SUCCESS(Status)) { ExFreePool(BootSector); return Status; } /* Read data from the bootsector */ NtfsInfo->BytesPerSector = BootSector->BPB.BytesPerSector; NtfsInfo->SectorsPerCluster = BootSector->BPB.SectorsPerCluster; NtfsInfo->BytesPerCluster = BootSector->BPB.BytesPerSector * BootSector->BPB.SectorsPerCluster; NtfsInfo->SectorCount = BootSector->EBPB.SectorCount; NtfsInfo->MftStart.QuadPart = BootSector->EBPB.MftLocation; NtfsInfo->MftMirrStart.QuadPart = BootSector->EBPB.MftMirrLocation; NtfsInfo->SerialNumber = BootSector->EBPB.SerialNumber; if (BootSector->EBPB.ClustersPerMftRecord > 0) NtfsInfo->BytesPerFileRecord = BootSector->EBPB.ClustersPerMftRecord * NtfsInfo->BytesPerCluster; else NtfsInfo->BytesPerFileRecord = 1 << (-BootSector->EBPB.ClustersPerMftRecord); DPRINT("Boot sector information:\n"); DPRINT(" BytesPerSector: %hu\n", BootSector->BPB.BytesPerSector); DPRINT(" SectorsPerCluster: %hu\n", BootSector->BPB.SectorsPerCluster); DPRINT(" SectorCount: %I64u\n", BootSector->EBPB.SectorCount); DPRINT(" MftStart: %I64u\n", BootSector->EBPB.MftLocation); DPRINT(" MftMirrStart: %I64u\n", BootSector->EBPB.MftMirrLocation); DPRINT(" ClustersPerMftRecord: %lx\n", BootSector->EBPB.ClustersPerMftRecord); DPRINT(" ClustersPerIndexRecord: %lx\n", BootSector->EBPB.ClustersPerIndexRecord); DPRINT(" SerialNumber: %I64x\n", BootSector->EBPB.SerialNumber); ExFreePool(BootSector); MftRecord = ExAllocatePoolWithTag(NonPagedPool, NtfsInfo->BytesPerFileRecord, TAG_NTFS); if (MftRecord == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } Status = NtfsReadSectors(DeviceObject, NtfsInfo->MftStart.u.LowPart * NtfsInfo->SectorsPerCluster, NtfsInfo->BytesPerFileRecord / NtfsInfo->BytesPerSector, NtfsInfo->BytesPerSector, (PVOID)MftRecord, TRUE); if (!NT_SUCCESS(Status)) { ExFreePool(MftRecord); return Status; } VolumeRecord = ExAllocatePoolWithTag(NonPagedPool, NtfsInfo->BytesPerFileRecord, TAG_NTFS); if (VolumeRecord == NULL) { ExFreePool(MftRecord); return STATUS_INSUFFICIENT_RESOURCES; } /* Read Volume File (MFT index 3) */ DeviceExt->StorageDevice = DeviceObject; Status = ReadFileRecord(DeviceExt, 3, VolumeRecord, MftRecord); if (!NT_SUCCESS(Status)) { ExFreePool(MftRecord); return Status; } /* Enumerate attributes */ NtfsDumpFileAttributes (MftRecord); /* Enumerate attributes */ NtfsDumpFileAttributes (VolumeRecord); /* Get volume name */ Attribute = FindAttribute (VolumeRecord, AttributeVolumeName, NULL); DPRINT("Attribute %p\n", Attribute); if (Attribute != NULL && ((PRESIDENT_ATTRIBUTE)Attribute)->ValueLength != 0) { DPRINT("Data length %lu\n", AttributeDataLength (Attribute)); NtfsInfo->VolumeLabelLength = min (((PRESIDENT_ATTRIBUTE)Attribute)->ValueLength, MAXIMUM_VOLUME_LABEL_LENGTH); RtlCopyMemory(NtfsInfo->VolumeLabel, (PVOID)((ULONG_PTR)Attribute + ((PRESIDENT_ATTRIBUTE)Attribute)->ValueOffset), NtfsInfo->VolumeLabelLength); } else { NtfsInfo->VolumeLabelLength = 0; } /* Get volume information */ Attribute = FindAttribute (VolumeRecord, AttributeVolumeInformation, NULL); DPRINT("Attribute %p\n", Attribute); if (Attribute != NULL && ((PRESIDENT_ATTRIBUTE)Attribute)->ValueLength != 0) { DPRINT("Data length %lu\n", AttributeDataLength (Attribute)); VolumeInfo = (PVOID)((ULONG_PTR)Attribute + ((PRESIDENT_ATTRIBUTE)Attribute)->ValueOffset); NtfsInfo->MajorVersion = VolumeInfo->MajorVersion; NtfsInfo->MinorVersion = VolumeInfo->MinorVersion; NtfsInfo->Flags = VolumeInfo->Flags; } ExFreePool(MftRecord); ExFreePool(VolumeRecord); return Status; }