#include "ntfs.h"
+#include <ntdddisk.h>
+
#define NDEBUG
#include <debug.h>
-/* GLOBALS *****************************************************************/
-
/* FUNCTIONS ****************************************************************/
-static NTSTATUS
-NtfsHasFileSystem(PDEVICE_OBJECT DeviceToMount)
/*
* FUNCTION: Tests if the device contains a filesystem that can be mounted
- * by this fsd
+ * 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);
+ 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_PARTITION_INFO,
+ IOCTL_DISK_GET_DRIVE_GEOMETRY,
NULL,
0,
- &PartitionInfo,
+ &DiskGeometry,
&Size,
TRUE);
if (!NT_SUCCESS(Status))
{
- DPRINT1("NtfsDeviceIoControl() failed (Status %lx)\n", Status);
- return(Status);
+ DPRINT1("NtfsDeviceIoControl() failed (Status %lx)\n", Status);
+ return Status;
}
- if (PartitionInfo.PartitionType != PARTITION_IFS)
+ if (DiskGeometry.MediaType == FixedMedia)
{
- DPRINT1("Invalid partition type\n");
- return(STATUS_UNRECOGNIZED_VOLUME);
+ /* 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);
- }
+ 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;
- }
+ 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;
+ ExFreePool(BootSector);
+
+ return Status;
}
-static NTSTATUS
+static
+ULONG
+NtfsQueryMftZoneReservation(VOID)
+{
+ ULONG ZoneReservation = 1;
+ RTL_QUERY_REGISTRY_TABLE QueryTable[2];
+
+ RtlZeroMemory(QueryTable, sizeof(QueryTable));
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ QueryTable[0].Name = L"NtfsMftZoneReservation";
+ QueryTable[0].EntryContext = &ZoneReservation;
+
+ RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
+ L"FileSystem",
+ QueryTable,
+ NULL,
+ NULL);
+
+ return ZoneReservation;
+}
+
+
+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;
- NTSTATUS Status;
- PNTFS_INFO NtfsInfo = &DeviceExt->NtfsInfo;
-
- 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))
- {
+ DISK_GEOMETRY DiskGeometry;
+ PFILE_RECORD_HEADER VolumeRecord;
+ PVOLINFO_ATTRIBUTE VolumeInfo;
+ PBOOT_SECTOR BootSector;
+ ULONG Size;
+ PNTFS_INFO NtfsInfo = &DeviceExt->NtfsInfo;
+ NTSTATUS Status;
+ PNTFS_ATTR_CONTEXT AttrCtxt;
+ PNTFS_ATTR_RECORD Attribute;
+ PNTFS_FCB VolumeFcb;
+ PWSTR VolumeNameU;
+
+ 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->ClusterCount = DeviceExt->NtfsInfo.SectorCount / (ULONGLONG)DeviceExt->NtfsInfo.SectorsPerCluster;
+
+ 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);
+ if (BootSector->EBPB.ClustersPerIndexRecord > 0)
+ NtfsInfo->BytesPerIndexRecord = BootSector->EBPB.ClustersPerIndexRecord * NtfsInfo->BytesPerCluster;
+ else
+ NtfsInfo->BytesPerIndexRecord = 1 << (-BootSector->EBPB.ClustersPerIndexRecord);
+
+ 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);
+
+ DeviceExt->MasterFileTable = ExAllocatePoolWithTag(NonPagedPool,
+ NtfsInfo->BytesPerFileRecord,
+ TAG_NTFS);
+ if (DeviceExt->MasterFileTable == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ Status = NtfsReadSectors(DeviceObject,
+ NtfsInfo->MftStart.u.LowPart * NtfsInfo->SectorsPerCluster,
+ NtfsInfo->BytesPerFileRecord / NtfsInfo->BytesPerSector,
+ NtfsInfo->BytesPerSector,
+ (PVOID)DeviceExt->MasterFileTable,
+ TRUE);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed reading MFT.\n");
+ ExFreePool(DeviceExt->MasterFileTable);
+ return Status;
+ }
+
+ Status = FindAttribute(DeviceExt,
+ DeviceExt->MasterFileTable,
+ AttributeData,
+ L"",
+ 0,
+ &DeviceExt->MFTContext,
+ &DeviceExt->MftDataOffset);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Can't find data attribute for Master File Table.\n");
+ ExFreePool(DeviceExt->MasterFileTable);
+ return Status;
+ }
+
+ VolumeRecord = ExAllocatePoolWithTag(NonPagedPool,
+ NtfsInfo->BytesPerFileRecord,
+ TAG_NTFS);
+ if (VolumeRecord == NULL)
+ {
+ DPRINT1("Allocation failed for volume record\n");
+ ExFreePool(DeviceExt->MasterFileTable);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ /* Read Volume File (MFT index 3) */
+ DeviceExt->StorageDevice = DeviceObject;
+ Status = ReadFileRecord(DeviceExt,
+ NTFS_FILE_VOLUME,
+ VolumeRecord);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed reading volume file\n");
+ ExFreePool(VolumeRecord);
+ ExFreePool(DeviceExt->MasterFileTable);
+ return Status;
+ }
+
+ /* Enumerate attributes */
+ NtfsDumpFileAttributes(DeviceExt, DeviceExt->MasterFileTable);
+
+ /* Enumerate attributes */
+ NtfsDumpFileAttributes(DeviceExt, VolumeRecord);
+
+ /* Get volume name */
+ Status = FindAttribute(DeviceExt, VolumeRecord, AttributeVolumeName, L"", 0, &AttrCtxt, NULL);
+
+ if (NT_SUCCESS(Status) && AttrCtxt->Record.Resident.ValueLength != 0)
+ {
+ Attribute = &AttrCtxt->Record;
+ DPRINT("Data length %lu\n", AttributeDataLength(Attribute));
+ NtfsInfo->VolumeLabelLength =
+ min (Attribute->Resident.ValueLength, MAXIMUM_VOLUME_LABEL_LENGTH);
+ RtlCopyMemory(NtfsInfo->VolumeLabel,
+ (PVOID)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset),
+ NtfsInfo->VolumeLabelLength);
+ VolumeNameU = NtfsInfo->VolumeLabel;
+ }
+ else
+ {
+ NtfsInfo->VolumeLabelLength = 0;
+ VolumeNameU = L"\0";
+ }
+
+ if (NT_SUCCESS(Status))
+ {
+ ReleaseAttributeContext(AttrCtxt);
+ }
+
+ VolumeFcb = NtfsCreateFCB(VolumeNameU, NULL, DeviceExt);
+ if (VolumeFcb == NULL)
+ {
+ DPRINT1("Failed allocating volume FCB\n");
+ ExFreePool(VolumeRecord);
+ ExFreePool(DeviceExt->MasterFileTable);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ VolumeFcb->Flags = FCB_IS_VOLUME;
+ VolumeFcb->RFCB.FileSize.QuadPart = DeviceExt->NtfsInfo.SectorCount * DeviceExt->NtfsInfo.BytesPerSector;
+ VolumeFcb->RFCB.ValidDataLength = VolumeFcb->RFCB.FileSize;
+ VolumeFcb->RFCB.AllocationSize = VolumeFcb->RFCB.FileSize;
+ VolumeFcb->MFTIndex = 0;
+ DeviceExt->VolumeFcb = VolumeFcb;
+
+ /* Get volume information */
+ Status = FindAttribute(DeviceExt, VolumeRecord, AttributeVolumeInformation, L"", 0, &AttrCtxt, NULL);
+
+ if (NT_SUCCESS(Status) && AttrCtxt->Record.Resident.ValueLength != 0)
+ {
+ Attribute = &AttrCtxt->Record;
+ DPRINT("Data length %lu\n", AttributeDataLength (Attribute));
+ VolumeInfo = (PVOID)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset);
+
+ NtfsInfo->MajorVersion = VolumeInfo->MajorVersion;
+ NtfsInfo->MinorVersion = VolumeInfo->MinorVersion;
+ NtfsInfo->Flags = VolumeInfo->Flags;
+ }
+
+ if (NT_SUCCESS(Status))
+ {
+ ReleaseAttributeContext(AttrCtxt);
+ }
+
+ ExFreePool(VolumeRecord);
+
+ NtfsInfo->MftZoneReservation = NtfsQueryMftZoneReservation();
+
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;
}
-static NTSTATUS
+static
+NTSTATUS
NtfsMountVolume(PDEVICE_OBJECT DeviceObject,
PIRP Irp)
{
- PDEVICE_OBJECT NewDeviceObject = NULL;
- PDEVICE_OBJECT DeviceToMount;
- PIO_STACK_LOCATION Stack;
- PNTFS_FCB Fcb = NULL;
- PNTFS_CCB Ccb = NULL;
- PNTFS_VCB Vcb = NULL;
- NTSTATUS Status;
-
- DPRINT1("NtfsMountVolume() called\n");
-
- if (DeviceObject != NtfsGlobalData->DeviceObject)
- {
- Status = STATUS_INVALID_DEVICE_REQUEST;
- goto ByeBye;
- }
-
- Stack = IoGetCurrentIrpStackLocation(Irp);
- DeviceToMount = Stack->Parameters.MountVolume.DeviceObject;
-
- Status = NtfsHasFileSystem(DeviceToMount);
- if (!NT_SUCCESS(Status))
- {
- goto ByeBye;
- }
-
- Status = IoCreateDevice(NtfsGlobalData->DriverObject,
- sizeof(DEVICE_EXTENSION),
- NULL,
- FILE_DEVICE_DISK_FILE_SYSTEM,
- 0,
- FALSE,
- &NewDeviceObject);
- if (!NT_SUCCESS(Status))
- goto ByeBye;
-
- NewDeviceObject->Flags |= DO_DIRECT_IO;
- Vcb = (PVOID)NewDeviceObject->DeviceExtension;
- RtlZeroMemory(Vcb, sizeof(NTFS_VCB));
-
- Vcb->Identifier.Type = NTFS_TYPE_VCB;
- Vcb->Identifier.Size = sizeof(NTFS_TYPE_VCB);
-
- Status = NtfsGetVolumeData(DeviceToMount,
- Vcb);
- if (!NT_SUCCESS(Status))
- goto ByeBye;
-
- NewDeviceObject->Vpb = DeviceToMount->Vpb;
-
- Vcb->StorageDevice = DeviceToMount;
- Vcb->StorageDevice->Vpb->DeviceObject = NewDeviceObject;
- Vcb->StorageDevice->Vpb->RealDevice = Vcb->StorageDevice;
- Vcb->StorageDevice->Vpb->Flags |= VPB_MOUNTED;
- NewDeviceObject->StackSize = Vcb->StorageDevice->StackSize + 1;
- NewDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
-
- Vcb->StreamFileObject = IoCreateStreamFileObject(NULL,
- Vcb->StorageDevice);
-
- InitializeListHead(&Vcb->FcbListHead);
-
- Fcb = NtfsCreateFCB(NULL, Vcb);
- if (Fcb == NULL)
- {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto ByeBye;
- }
-
- Ccb = ExAllocatePoolWithTag(NonPagedPool,
- sizeof(NTFS_CCB),
- TAG_CCB);
- if (Ccb == NULL)
- {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto ByeBye;
- }
- RtlZeroMemory(Ccb, sizeof(NTFS_CCB));
-
- Ccb->Identifier.Type = NTFS_TYPE_CCB;
- Ccb->Identifier.Size = sizeof(NTFS_TYPE_CCB);
-
- Vcb->StreamFileObject->FsContext = Fcb;
- Vcb->StreamFileObject->FsContext2 = Ccb;
- Vcb->StreamFileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
- Vcb->StreamFileObject->PrivateCacheMap = NULL;
- Vcb->StreamFileObject->Vpb = Vcb->Vpb;
- Ccb->PtrFileObject = Vcb->StreamFileObject;
- Fcb->FileObject = Vcb->StreamFileObject;
- Fcb->Vcb = (PDEVICE_EXTENSION)Vcb->StorageDevice;
-
- Fcb->Flags = FCB_IS_VOLUME_STREAM;
-
- Fcb->RFCB.FileSize.QuadPart = Vcb->NtfsInfo.SectorCount * Vcb->NtfsInfo.BytesPerSector;
- Fcb->RFCB.ValidDataLength.QuadPart = Vcb->NtfsInfo.SectorCount * Vcb->NtfsInfo.BytesPerSector;
- Fcb->RFCB.AllocationSize.QuadPart = Vcb->NtfsInfo.SectorCount * Vcb->NtfsInfo.BytesPerSector; /* Correct? */
-
-// Fcb->Entry.ExtentLocationL = 0;
-// Fcb->Entry.DataLengthL = DeviceExt->CdInfo.VolumeSpaceSize * BLOCKSIZE;
-
- CcInitializeCacheMap(Vcb->StreamFileObject,
- (PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize),
- FALSE,
- &(NtfsGlobalData->CacheMgrCallbacks),
- Fcb);
-
- ExInitializeResourceLite(&Vcb->DirResource);
-
- KeInitializeSpinLock(&Vcb->FcbListLock);
-
- /* Get serial number */
- NewDeviceObject->Vpb->SerialNumber = Vcb->NtfsInfo.SerialNumber;
-
- /* Get volume label */
- NewDeviceObject->Vpb->VolumeLabelLength = Vcb->NtfsInfo.VolumeLabelLength;
- RtlCopyMemory(NewDeviceObject->Vpb->VolumeLabel,
- Vcb->NtfsInfo.VolumeLabel,
- Vcb->NtfsInfo.VolumeLabelLength);
-
- Status = STATUS_SUCCESS;
+ PDEVICE_OBJECT NewDeviceObject = NULL;
+ PDEVICE_OBJECT DeviceToMount;
+ PIO_STACK_LOCATION Stack;
+ PNTFS_FCB Fcb = NULL;
+ PNTFS_CCB Ccb = NULL;
+ PNTFS_VCB Vcb = NULL;
+ NTSTATUS Status;
+
+ DPRINT1("NtfsMountVolume() called\n");
+
+ if (DeviceObject != NtfsGlobalData->DeviceObject)
+ {
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ goto ByeBye;
+ }
+
+ Stack = IoGetCurrentIrpStackLocation(Irp);
+ DeviceToMount = Stack->Parameters.MountVolume.DeviceObject;
+
+ Status = NtfsHasFileSystem(DeviceToMount);
+ if (!NT_SUCCESS(Status))
+ {
+ goto ByeBye;
+ }
+
+ Status = IoCreateDevice(NtfsGlobalData->DriverObject,
+ sizeof(DEVICE_EXTENSION),
+ NULL,
+ FILE_DEVICE_DISK_FILE_SYSTEM,
+ 0,
+ FALSE,
+ &NewDeviceObject);
+ if (!NT_SUCCESS(Status))
+ goto ByeBye;
+
+ NewDeviceObject->Flags |= DO_DIRECT_IO;
+ Vcb = (PVOID)NewDeviceObject->DeviceExtension;
+ RtlZeroMemory(Vcb, sizeof(NTFS_VCB));
+
+ Vcb->Identifier.Type = NTFS_TYPE_VCB;
+ Vcb->Identifier.Size = sizeof(NTFS_TYPE_VCB);
+
+ Status = NtfsGetVolumeData(DeviceToMount,
+ Vcb);
+ if (!NT_SUCCESS(Status))
+ goto ByeBye;
+
+ NewDeviceObject->Vpb = DeviceToMount->Vpb;
+
+ Vcb->StorageDevice = DeviceToMount;
+ Vcb->StorageDevice->Vpb->DeviceObject = NewDeviceObject;
+ Vcb->StorageDevice->Vpb->RealDevice = Vcb->StorageDevice;
+ Vcb->StorageDevice->Vpb->Flags |= VPB_MOUNTED;
+ NewDeviceObject->StackSize = Vcb->StorageDevice->StackSize + 1;
+ NewDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
+
+ Vcb->StreamFileObject = IoCreateStreamFileObject(NULL,
+ Vcb->StorageDevice);
+
+ InitializeListHead(&Vcb->FcbListHead);
+
+ Fcb = NtfsCreateFCB(NULL, NULL, Vcb);
+ if (Fcb == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto ByeBye;
+ }
+
+ Ccb = ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(NTFS_CCB),
+ TAG_CCB);
+ if (Ccb == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto ByeBye;
+ }
+
+ RtlZeroMemory(Ccb, sizeof(NTFS_CCB));
+
+ Ccb->Identifier.Type = NTFS_TYPE_CCB;
+ Ccb->Identifier.Size = sizeof(NTFS_TYPE_CCB);
+
+ Vcb->StreamFileObject->FsContext = Fcb;
+ Vcb->StreamFileObject->FsContext2 = Ccb;
+ Vcb->StreamFileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
+ Vcb->StreamFileObject->PrivateCacheMap = NULL;
+ Vcb->StreamFileObject->Vpb = Vcb->Vpb;
+ Ccb->PtrFileObject = Vcb->StreamFileObject;
+ Fcb->FileObject = Vcb->StreamFileObject;
+ Fcb->Vcb = (PDEVICE_EXTENSION)Vcb->StorageDevice;
+
+ Fcb->Flags = FCB_IS_VOLUME_STREAM;
+
+ Fcb->RFCB.FileSize.QuadPart = Vcb->NtfsInfo.SectorCount * Vcb->NtfsInfo.BytesPerSector;
+ Fcb->RFCB.ValidDataLength.QuadPart = Vcb->NtfsInfo.SectorCount * Vcb->NtfsInfo.BytesPerSector;
+ Fcb->RFCB.AllocationSize.QuadPart = Vcb->NtfsInfo.SectorCount * Vcb->NtfsInfo.BytesPerSector; /* Correct? */
+
+// Fcb->Entry.ExtentLocationL = 0;
+// Fcb->Entry.DataLengthL = DeviceExt->CdInfo.VolumeSpaceSize * BLOCKSIZE;
+
+ _SEH2_TRY
+ {
+ CcInitializeCacheMap(Vcb->StreamFileObject,
+ (PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize),
+ TRUE,
+ &(NtfsGlobalData->CacheMgrCallbacks),
+ Fcb);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ goto ByeBye;
+ }
+ _SEH2_END;
+
+ ExInitializeResourceLite(&Vcb->DirResource);
+
+ KeInitializeSpinLock(&Vcb->FcbListLock);
+
+ /* Get serial number */
+ NewDeviceObject->Vpb->SerialNumber = Vcb->NtfsInfo.SerialNumber;
+
+ /* Get volume label */
+ NewDeviceObject->Vpb->VolumeLabelLength = Vcb->NtfsInfo.VolumeLabelLength;
+ RtlCopyMemory(NewDeviceObject->Vpb->VolumeLabel,
+ Vcb->NtfsInfo.VolumeLabel,
+ Vcb->NtfsInfo.VolumeLabelLength);
+
+ FsRtlNotifyVolumeEvent(Vcb->StreamFileObject, FSRTL_VOLUME_MOUNT);
+
+ Status = STATUS_SUCCESS;
ByeBye:
- if (!NT_SUCCESS(Status))
- {
- /* Cleanup */
- if (Vcb && Vcb->StreamFileObject)
- ObDereferenceObject(Vcb->StreamFileObject);
- if (Fcb)
- ExFreePool(Fcb);
- if (Ccb)
- ExFreePool(Ccb);
- if (NewDeviceObject)
- IoDeleteDevice(NewDeviceObject);
- }
-
- DPRINT("NtfsMountVolume() done (Status: %lx)\n", Status);
-
- return Status;
+ if (!NT_SUCCESS(Status))
+ {
+ /* Cleanup */
+ if (Vcb && Vcb->StreamFileObject)
+ ObDereferenceObject(Vcb->StreamFileObject);
+
+ if (Fcb)
+ NtfsDestroyFCB(Fcb);
+
+ if (Ccb)
+ ExFreePool(Ccb);
+
+ if (NewDeviceObject)
+ IoDeleteDevice(NewDeviceObject);
+ }
+
+ DPRINT("NtfsMountVolume() done (Status: %lx)\n", Status);
+
+ return Status;
}
-static NTSTATUS
+static
+NTSTATUS
NtfsVerifyVolume(PDEVICE_OBJECT DeviceObject,
PIRP Irp)
{
- DPRINT1("NtfsVerifyVolume() called\n");
+ UNREFERENCED_PARAMETER(DeviceObject);
+ UNREFERENCED_PARAMETER(Irp);
+ DPRINT1("NtfsVerifyVolume() called\n");
+ return STATUS_WRONG_VOLUME;
+}
+
+
+static
+NTSTATUS
+GetNfsVolumeData(PDEVICE_EXTENSION DeviceExt,
+ PIRP Irp)
+{
+ PIO_STACK_LOCATION Stack;
+ PNTFS_VOLUME_DATA_BUFFER DataBuffer;
+ PNTFS_ATTR_RECORD Attribute;
+ FIND_ATTR_CONTXT Context;
+ NTSTATUS Status;
+
+ DataBuffer = (PNTFS_VOLUME_DATA_BUFFER)Irp->AssociatedIrp.SystemBuffer;
+ Stack = IoGetCurrentIrpStackLocation(Irp);
+
+ if (Stack->Parameters.FileSystemControl.OutputBufferLength < sizeof(NTFS_VOLUME_DATA_BUFFER) ||
+ Irp->UserBuffer == NULL)
+ {
+ DPRINT1("Invalid output! %d %p\n", Stack->Parameters.FileSystemControl.OutputBufferLength, Irp->UserBuffer);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ DataBuffer->VolumeSerialNumber.QuadPart = DeviceExt->NtfsInfo.SerialNumber;
+ DataBuffer->NumberSectors.QuadPart = DeviceExt->NtfsInfo.SectorCount;
+ DataBuffer->TotalClusters.QuadPart = DeviceExt->NtfsInfo.ClusterCount;
+ DataBuffer->FreeClusters.QuadPart = NtfsGetFreeClusters(DeviceExt);
+ DataBuffer->TotalReserved.QuadPart = 0LL; // FIXME
+ DataBuffer->BytesPerSector = DeviceExt->NtfsInfo.BytesPerSector;
+ DataBuffer->BytesPerCluster = DeviceExt->NtfsInfo.BytesPerCluster;
+ DataBuffer->BytesPerFileRecordSegment = DeviceExt->NtfsInfo.BytesPerFileRecord;
+ DataBuffer->ClustersPerFileRecordSegment = DeviceExt->NtfsInfo.BytesPerFileRecord / DeviceExt->NtfsInfo.BytesPerCluster;
+ DataBuffer->MftStartLcn.QuadPart = DeviceExt->NtfsInfo.MftStart.QuadPart;
+ DataBuffer->Mft2StartLcn.QuadPart = DeviceExt->NtfsInfo.MftMirrStart.QuadPart;
+ DataBuffer->MftZoneStart.QuadPart = 0; // FIXME
+ DataBuffer->MftZoneEnd.QuadPart = 0; // FIXME
+
+ Status = FindFirstAttribute(&Context, DeviceExt, DeviceExt->MasterFileTable, FALSE, &Attribute);
+ while (NT_SUCCESS(Status))
+ {
+ if (Attribute->Type == AttributeData)
+ {
+ ASSERT(Attribute->IsNonResident);
+ DataBuffer->MftValidDataLength.QuadPart = Attribute->NonResident.DataSize;
+
+ break;
+ }
+
+ Status = FindNextAttribute(&Context, &Attribute);
+ }
+ FindCloseAttribute(&Context);
+
+ Irp->IoStatus.Information = sizeof(NTFS_VOLUME_DATA_BUFFER);
+
+ if (Stack->Parameters.FileSystemControl.OutputBufferLength >= sizeof(NTFS_EXTENDED_VOLUME_DATA) + sizeof(NTFS_VOLUME_DATA_BUFFER))
+ {
+ PNTFS_EXTENDED_VOLUME_DATA ExtendedData = (PNTFS_EXTENDED_VOLUME_DATA)((ULONG_PTR)Irp->UserBuffer + sizeof(NTFS_VOLUME_DATA_BUFFER));
+
+ ExtendedData->ByteCount = sizeof(NTFS_EXTENDED_VOLUME_DATA);
+ ExtendedData->MajorVersion = DeviceExt->NtfsInfo.MajorVersion;
+ ExtendedData->MinorVersion = DeviceExt->NtfsInfo.MinorVersion;
+ Irp->IoStatus.Information += sizeof(NTFS_EXTENDED_VOLUME_DATA);
+ }
- return STATUS_WRONG_VOLUME;
+ return STATUS_SUCCESS;
}
-NTSTATUS NTAPI
-NtfsFsdFileSystemControl(PDEVICE_OBJECT DeviceObject,
- PIRP Irp)
+static
+NTSTATUS
+GetNtfsFileRecord(PDEVICE_EXTENSION DeviceExt,
+ PIRP Irp)
{
- PIO_STACK_LOCATION Stack;
- NTSTATUS Status;
+ NTSTATUS Status;
+ PIO_STACK_LOCATION Stack;
+ PNTFS_FILE_RECORD_INPUT_BUFFER InputBuffer;
+ PFILE_RECORD_HEADER FileRecord;
+ PNTFS_FILE_RECORD_OUTPUT_BUFFER OutputBuffer;
+ ULONGLONG MFTRecord;
- DPRINT1("NtfsFileSystemControl() called\n");
+ Stack = IoGetCurrentIrpStackLocation(Irp);
- Stack = IoGetCurrentIrpStackLocation(Irp);
+ if (Stack->Parameters.FileSystemControl.InputBufferLength < sizeof(NTFS_FILE_RECORD_INPUT_BUFFER) ||
+ Irp->AssociatedIrp.SystemBuffer == NULL)
+ {
+ DPRINT1("Invalid input! %d %p\n", Stack->Parameters.FileSystemControl.InputBufferLength, Irp->AssociatedIrp.SystemBuffer);
+ return STATUS_INVALID_PARAMETER;
+ }
- switch (Stack->MinorFunction)
- {
- case IRP_MN_KERNEL_CALL:
- case IRP_MN_USER_FS_REQUEST:
- DPRINT("NTFS: IRP_MN_USER_FS_REQUEST/IRP_MN_KERNEL_CALL\n");
- Status = STATUS_INVALID_DEVICE_REQUEST;
- break;
+ if (Stack->Parameters.FileSystemControl.OutputBufferLength < (FIELD_OFFSET(NTFS_FILE_RECORD_OUTPUT_BUFFER, FileRecordBuffer) + DeviceExt->NtfsInfo.BytesPerFileRecord) ||
+ Irp->AssociatedIrp.SystemBuffer == NULL)
+ {
+ DPRINT1("Invalid output! %d %p\n", Stack->Parameters.FileSystemControl.OutputBufferLength, Irp->AssociatedIrp.SystemBuffer);
+ return STATUS_BUFFER_TOO_SMALL;
+ }
- case IRP_MN_MOUNT_VOLUME:
- DPRINT("NTFS: IRP_MN_MOUNT_VOLUME\n");
- Status = NtfsMountVolume(DeviceObject, Irp);
- break;
+ FileRecord = ExAllocatePoolWithTag(NonPagedPool,
+ DeviceExt->NtfsInfo.BytesPerFileRecord,
+ TAG_NTFS);
+ if (FileRecord == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ InputBuffer = (PNTFS_FILE_RECORD_INPUT_BUFFER)Irp->AssociatedIrp.SystemBuffer;
- case IRP_MN_VERIFY_VOLUME:
- DPRINT1("NTFS: IRP_MN_VERIFY_VOLUME\n");
- Status = NtfsVerifyVolume(DeviceObject, Irp);
- break;
+ MFTRecord = InputBuffer->FileReferenceNumber.QuadPart;
+ DPRINT1("Requesting: %I64x\n", MFTRecord);
+
+ do
+ {
+ Status = ReadFileRecord(DeviceExt, MFTRecord, FileRecord);
+ if (NT_SUCCESS(Status))
+ {
+ if (FileRecord->Flags & FRH_IN_USE)
+ {
+ break;
+ }
+ }
- default:
- DPRINT("NTFS FSC: MinorFunction %d\n", Stack->MinorFunction);
- Status = STATUS_INVALID_DEVICE_REQUEST;
- break;
- }
+ --MFTRecord;
+ } while (TRUE);
- Irp->IoStatus.Status = Status;
- Irp->IoStatus.Information = 0;
+ DPRINT1("Returning: %I64x\n", MFTRecord);
+ OutputBuffer = (PNTFS_FILE_RECORD_OUTPUT_BUFFER)Irp->AssociatedIrp.SystemBuffer;
+ OutputBuffer->FileReferenceNumber.QuadPart = MFTRecord;
+ OutputBuffer->FileRecordLength = DeviceExt->NtfsInfo.BytesPerFileRecord;
+ RtlCopyMemory(OutputBuffer->FileRecordBuffer, FileRecord, DeviceExt->NtfsInfo.BytesPerFileRecord);
+
+ ExFreePoolWithTag(FileRecord, TAG_NTFS);
+
+ Irp->IoStatus.Information = FIELD_OFFSET(NTFS_FILE_RECORD_OUTPUT_BUFFER, FileRecordBuffer) + DeviceExt->NtfsInfo.BytesPerFileRecord;
+
+ return STATUS_SUCCESS;
+}
+
+
+static
+NTSTATUS
+GetVolumeBitmap(PDEVICE_EXTENSION DeviceExt,
+ PIRP Irp)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PIO_STACK_LOCATION Stack;
+ PVOLUME_BITMAP_BUFFER BitmapBuffer;
+ LONGLONG StartingLcn;
+ PFILE_RECORD_HEADER BitmapRecord;
+ PNTFS_ATTR_CONTEXT DataContext;
+ ULONGLONG TotalClusters;
+ ULONGLONG ToCopy;
+ BOOLEAN Overflow = FALSE;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ DPRINT1("GetVolumeBitmap(%p, %p)\n", DeviceExt, Irp);
+
+ Stack = IoGetCurrentIrpStackLocation(Irp);
+
+ if (Stack->Parameters.FileSystemControl.InputBufferLength < sizeof(STARTING_LCN_INPUT_BUFFER))
+ {
+ DPRINT1("Invalid input! %d\n", Stack->Parameters.FileSystemControl.InputBufferLength);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (Stack->Parameters.FileSystemControl.OutputBufferLength < sizeof(VOLUME_BITMAP_BUFFER))
+ {
+ DPRINT1("Invalid output! %d\n", Stack->Parameters.FileSystemControl.OutputBufferLength);
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ BitmapBuffer = NtfsGetUserBuffer(Irp, FALSE);
+ if (Irp->RequestorMode == UserMode)
+ {
+ _SEH2_TRY
+ {
+ ProbeForRead(Stack->Parameters.FileSystemControl.Type3InputBuffer,
+ Stack->Parameters.FileSystemControl.InputBufferLength,
+ sizeof(CHAR));
+ ProbeForWrite(BitmapBuffer, Stack->Parameters.FileSystemControl.OutputBufferLength,
+ sizeof(CHAR));
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+ }
+ else
+ {
+ if (Stack->Parameters.FileSystemControl.Type3InputBuffer == NULL ||
+ BitmapBuffer == NULL)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ }
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Invalid buffer! %p %p\n", Stack->Parameters.FileSystemControl.Type3InputBuffer, BitmapBuffer);
+ return Status;
+ }
- return(Status);
+ StartingLcn = ((PSTARTING_LCN_INPUT_BUFFER)Stack->Parameters.FileSystemControl.Type3InputBuffer)->StartingLcn.QuadPart;
+ if (StartingLcn > DeviceExt->NtfsInfo.ClusterCount)
+ {
+ DPRINT1("Requested bitmap start beyond partition end: %I64x %I64x\n", DeviceExt->NtfsInfo.ClusterCount, StartingLcn);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* Round down to a multiple of 8 */
+ StartingLcn = StartingLcn & ~7;
+ TotalClusters = DeviceExt->NtfsInfo.ClusterCount - StartingLcn;
+ ToCopy = TotalClusters / 8;
+ if ((ToCopy + FIELD_OFFSET(VOLUME_BITMAP_BUFFER, Buffer)) > Stack->Parameters.FileSystemControl.OutputBufferLength)
+ {
+ DPRINT1("Buffer too small: %x, needed: %x\n", Stack->Parameters.FileSystemControl.OutputBufferLength, (ToCopy + FIELD_OFFSET(VOLUME_BITMAP_BUFFER, Buffer)));
+ Overflow = TRUE;
+ ToCopy = Stack->Parameters.FileSystemControl.OutputBufferLength - FIELD_OFFSET(VOLUME_BITMAP_BUFFER, Buffer);
+ }
+
+ BitmapRecord = ExAllocatePoolWithTag(NonPagedPool,
+ DeviceExt->NtfsInfo.BytesPerFileRecord,
+ TAG_NTFS);
+ if (BitmapRecord == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ Status = ReadFileRecord(DeviceExt, NTFS_FILE_BITMAP, BitmapRecord);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed reading volume bitmap: %lx\n", Status);
+ ExFreePoolWithTag(BitmapRecord, TAG_NTFS);
+ return Status;
+ }
+
+ Status = FindAttribute(DeviceExt, BitmapRecord, AttributeData, L"", 0, &DataContext, NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed find $DATA for bitmap: %lx\n", Status);
+ ExFreePoolWithTag(BitmapRecord, TAG_NTFS);
+ return Status;
+ }
+
+ BitmapBuffer->StartingLcn.QuadPart = StartingLcn;
+ BitmapBuffer->BitmapSize.QuadPart = ToCopy * 8;
+
+ Irp->IoStatus.Information = FIELD_OFFSET(VOLUME_BITMAP_BUFFER, Buffer);
+ _SEH2_TRY
+ {
+ Irp->IoStatus.Information += ReadAttribute(DeviceExt, DataContext, StartingLcn / 8, (PCHAR)BitmapBuffer->Buffer, ToCopy);
+ Status = (Overflow ? STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+ ReleaseAttributeContext(DataContext);
+ ExFreePoolWithTag(BitmapRecord, TAG_NTFS);
+
+ return Status;
+}
+
+
+static
+NTSTATUS
+LockOrUnlockVolume(PDEVICE_EXTENSION DeviceExt,
+ PIRP Irp,
+ BOOLEAN Lock)
+{
+ PFILE_OBJECT FileObject;
+ PNTFS_FCB Fcb;
+ PIO_STACK_LOCATION Stack;
+
+ DPRINT("LockOrUnlockVolume(%p, %p, %d)\n", DeviceExt, Irp, Lock);
+
+ Stack = IoGetCurrentIrpStackLocation(Irp);
+ FileObject = Stack->FileObject;
+ Fcb = FileObject->FsContext;
+
+ /* Only allow locking with the volume open */
+ if (!(Fcb->Flags & FCB_IS_VOLUME))
+ {
+ return STATUS_ACCESS_DENIED;
+ }
+
+ /* Bail out if it's already in the demanded state */
+ if (((DeviceExt->Flags & VCB_VOLUME_LOCKED) && Lock) ||
+ (!(DeviceExt->Flags & VCB_VOLUME_LOCKED) && !Lock))
+ {
+ return STATUS_ACCESS_DENIED;
+ }
+
+ /* Deny locking if we're not alone */
+ if (Lock && DeviceExt->OpenHandleCount != 1)
+ {
+ return STATUS_ACCESS_DENIED;
+ }
+
+ /* Finally, proceed */
+ if (Lock)
+ {
+ DeviceExt->Flags |= VCB_VOLUME_LOCKED;
+ }
+ else
+ {
+ DeviceExt->Flags &= ~VCB_VOLUME_LOCKED;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+
+static
+NTSTATUS
+NtfsUserFsRequest(PDEVICE_OBJECT DeviceObject,
+ PIRP Irp)
+{
+ NTSTATUS Status;
+ PIO_STACK_LOCATION Stack;
+ PDEVICE_EXTENSION DeviceExt;
+
+ DPRINT1("NtfsUserFsRequest(%p, %p)\n", DeviceObject, Irp);
+
+ Stack = IoGetCurrentIrpStackLocation(Irp);
+ DeviceExt = DeviceObject->DeviceExtension;
+ switch (Stack->Parameters.FileSystemControl.FsControlCode)
+ {
+ case FSCTL_CREATE_USN_JOURNAL:
+ case FSCTL_DELETE_USN_JOURNAL:
+ case FSCTL_ENUM_USN_DATA:
+ case FSCTL_EXTEND_VOLUME:
+ //case FSCTL_GET_RETRIEVAL_POINTER_BASE:
+ case FSCTL_GET_RETRIEVAL_POINTERS:
+ //case FSCTL_LOOKUP_STREAM_FROM_CLUSTER:
+ case FSCTL_MARK_HANDLE:
+ case FSCTL_MOVE_FILE:
+ case FSCTL_QUERY_USN_JOURNAL:
+ case FSCTL_READ_FILE_USN_DATA:
+ case FSCTL_READ_USN_JOURNAL:
+ //case FSCTL_SHRINK_VOLUME:
+ case FSCTL_WRITE_USN_CLOSE_RECORD:
+ UNIMPLEMENTED;
+ DPRINT1("Unimplemented user request: %x\n", Stack->Parameters.FileSystemControl.FsControlCode);
+ Status = STATUS_NOT_IMPLEMENTED;
+ break;
+
+ case FSCTL_LOCK_VOLUME:
+ Status = LockOrUnlockVolume(DeviceExt, Irp, TRUE);
+ break;
+
+ case FSCTL_UNLOCK_VOLUME:
+ Status = LockOrUnlockVolume(DeviceExt, Irp, FALSE);
+ break;
+
+ case FSCTL_GET_NTFS_VOLUME_DATA:
+ Status = GetNfsVolumeData(DeviceExt, Irp);
+ break;
+
+ case FSCTL_GET_NTFS_FILE_RECORD:
+ Status = GetNtfsFileRecord(DeviceExt, Irp);
+ break;
+
+ case FSCTL_GET_VOLUME_BITMAP:
+ Status = GetVolumeBitmap(DeviceExt, Irp);
+ break;
+
+ default:
+ DPRINT("Invalid user request: %x\n", Stack->Parameters.FileSystemControl.FsControlCode);
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ break;
+ }
+
+ return Status;
+}
+
+
+NTSTATUS
+NtfsFileSystemControl(PNTFS_IRP_CONTEXT IrpContext)
+{
+ NTSTATUS Status;
+ PIRP Irp;
+ PDEVICE_OBJECT DeviceObject;
+
+ DPRINT1("NtfsFileSystemControl() called\n");
+
+ DeviceObject = IrpContext->DeviceObject;
+ Irp = IrpContext->Irp;
+ Irp->IoStatus.Information = 0;
+
+ switch (IrpContext->MinorFunction)
+ {
+ case IRP_MN_KERNEL_CALL:
+ DPRINT1("NTFS: IRP_MN_USER_FS_REQUEST\n");
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ break;
+
+ case IRP_MN_USER_FS_REQUEST:
+ Status = NtfsUserFsRequest(DeviceObject, Irp);
+ break;
+
+ case IRP_MN_MOUNT_VOLUME:
+ DPRINT("NTFS: IRP_MN_MOUNT_VOLUME\n");
+ Status = NtfsMountVolume(DeviceObject, Irp);
+ break;
+
+ case IRP_MN_VERIFY_VOLUME:
+ DPRINT1("NTFS: IRP_MN_VERIFY_VOLUME\n");
+ Status = NtfsVerifyVolume(DeviceObject, Irp);
+ break;
+
+ default:
+ DPRINT1("NTFS FSC: MinorFunction %d\n", IrpContext->MinorFunction);
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ break;
+ }
+
+ return Status;
}
/* EOF */