- Import structures and defines from FreeLdr NTFS driver header
- Import lot of code from FreeLdr NTFS driver to handle MFT & attributes
- Remove code that has been overtaken by FreeLdr code
- Adapt & port code from FreeLdr (allocation, status, data structures)
- Adapt old code to the new functions defined from FreeLdr code

- Open the MFT during volume mount and keep in VCB for further use
- Implement a function to lookup a file in the MFT given its full path

svn path=/trunk/; revision=64313
This commit is contained in:
Pierre Schweitzer
2014-09-26 13:57:29 +00:00
parent d8175d3e64
commit 32afa0efb3
4 changed files with 823 additions and 422 deletions
+69 -95
View File
@@ -33,127 +33,106 @@
/* FUNCTIONS ****************************************************************/
static
ULONG
RunLength(PUCHAR run)
PUCHAR
DecodeRun(PUCHAR DataRun,
LONGLONG *DataRunOffset,
ULONGLONG *DataRunLength)
{
return(*run & 0x0f) + ((*run >> 4) & 0x0f) + 1;
UCHAR DataRunOffsetSize;
UCHAR DataRunLengthSize;
CHAR i;
DataRunOffsetSize = (*DataRun >> 4) & 0xF;
DataRunLengthSize = *DataRun & 0xF;
*DataRunOffset = 0;
*DataRunLength = 0;
DataRun++;
for (i = 0; i < DataRunLengthSize; i++)
{
*DataRunLength += ((ULONG64)*DataRun) << (i * 8);
DataRun++;
}
/* NTFS 3+ sparse files */
if (DataRunOffsetSize == 0)
{
*DataRunOffset = -1;
}
else
{
for (i = 0; i < DataRunOffsetSize - 1; i++)
{
*DataRunOffset += ((ULONG64)*DataRun) << (i * 8);
DataRun++;
}
/* The last byte contains sign so we must process it different way. */
*DataRunOffset = ((LONG64)(CHAR)(*(DataRun++)) << (i * 8)) + *DataRunOffset;
}
DPRINT("DataRunOffsetSize: %x\n", DataRunOffsetSize);
DPRINT("DataRunLengthSize: %x\n", DataRunLengthSize);
DPRINT("DataRunOffset: %x\n", *DataRunOffset);
DPRINT("DataRunLength: %x\n", *DataRunLength);
return DataRun;
}
static
LONGLONG
RunLCN(PUCHAR run)
{
UCHAR n1 = *run & 0x0f;
UCHAR n2 = (*run >> 4) & 0x0f;
LONGLONG lcn = (n2 == 0) ? 0 : (CHAR)(run[n1 + n2]);
LONG i = 0;
for (i = n1 +n2 - 1; i > n1; i--)
lcn = (lcn << 8) + run[i];
return lcn;
}
static
ULONGLONG
RunCount(PUCHAR run)
{
UCHAR n = *run & 0xf;
ULONGLONG count = 0;
ULONG i = 0;
for (i = n; i > 0; i--)
count = (count << 8) + run[i];
return count;
}
BOOLEAN
FindRun(PNONRESIDENT_ATTRIBUTE NresAttr,
FindRun(PNTFS_ATTR_RECORD NresAttr,
ULONGLONG vcn,
PULONGLONG lcn,
PULONGLONG count)
{
PUCHAR run;
ULONGLONG base = NresAttr->StartVcn;
if (vcn < NresAttr->StartVcn || vcn > NresAttr->LastVcn)
if (vcn < NresAttr->NonResident.LowestVCN || vcn > NresAttr->NonResident.HighestVCN)
return FALSE;
*lcn = 0;
DecodeRun((PUCHAR)((ULONG_PTR)NresAttr + NresAttr->NonResident.MappingPairsOffset), (PLONGLONG)lcn, count);
for (run = (PUCHAR)((ULONG_PTR)NresAttr + NresAttr->RunArrayOffset);
*run != 0; run += RunLength(run))
{
*lcn += RunLCN(run);
*count = RunCount(run);
if (base <= vcn && vcn < base + *count)
{
*lcn = (RunLCN(run) == 0) ? 0 : *lcn + vcn - base;
*count -= (ULONG)(vcn - base);
return TRUE;
}
else
{
base += *count;
}
}
return FALSE;
return TRUE;
}
static
VOID
NtfsDumpFileNameAttribute(PATTRIBUTE Attribute)
NtfsDumpFileNameAttribute(PNTFS_ATTR_RECORD Attribute)
{
PRESIDENT_ATTRIBUTE ResAttr;
PFILENAME_ATTRIBUTE FileNameAttr;
DbgPrint(" $FILE_NAME ");
ResAttr = (PRESIDENT_ATTRIBUTE)Attribute;
// DbgPrint(" Length %lu Offset %hu ", ResAttr->ValueLength, ResAttr->ValueOffset);
// DbgPrint(" Length %lu Offset %hu ", Attribute->Resident.ValueLength, Attribute->Resident.ValueOffset);
FileNameAttr = (PFILENAME_ATTRIBUTE)((ULONG_PTR)ResAttr + ResAttr->ValueOffset);
FileNameAttr = (PFILENAME_ATTRIBUTE)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset);
DbgPrint(" '%.*S' ", FileNameAttr->NameLength, FileNameAttr->Name);
}
static
VOID
NtfsDumpVolumeNameAttribute(PATTRIBUTE Attribute)
NtfsDumpVolumeNameAttribute(PNTFS_ATTR_RECORD Attribute)
{
PRESIDENT_ATTRIBUTE ResAttr;
PWCHAR VolumeName;
DbgPrint(" $VOLUME_NAME ");
ResAttr = (PRESIDENT_ATTRIBUTE)Attribute;
// DbgPrint(" Length %lu Offset %hu ", ResAttr->ValueLength, ResAttr->ValueOffset);
// DbgPrint(" Length %lu Offset %hu ", Attribute->Resident.ValueLength, Attribute->Resident.ValueOffset);
VolumeName = (PWCHAR)((ULONG_PTR)ResAttr + ResAttr->ValueOffset);
DbgPrint(" '%.*S' ", ResAttr->ValueLength / sizeof(WCHAR), VolumeName);
VolumeName = (PWCHAR)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset);
DbgPrint(" '%.*S' ", Attribute->Resident.ValueLength / sizeof(WCHAR), VolumeName);
}
static
VOID
NtfsDumpVolumeInformationAttribute(PATTRIBUTE Attribute)
NtfsDumpVolumeInformationAttribute(PNTFS_ATTR_RECORD Attribute)
{
PRESIDENT_ATTRIBUTE ResAttr;
PVOLINFO_ATTRIBUTE VolInfoAttr;
DbgPrint(" $VOLUME_INFORMATION ");
ResAttr = (PRESIDENT_ATTRIBUTE)Attribute;
// DbgPrint(" Length %lu Offset %hu ", ResAttr->ValueLength, ResAttr->ValueOffset);
// DbgPrint(" Length %lu Offset %hu ", Attribute->Resident.ValueLength, Attribute->Resident.ValueOffset);
VolInfoAttr = (PVOLINFO_ATTRIBUTE)((ULONG_PTR)ResAttr + ResAttr->ValueOffset);
VolInfoAttr = (PVOLINFO_ATTRIBUTE)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset);
DbgPrint(" NTFS Version %u.%u Flags 0x%04hx ",
VolInfoAttr->MajorVersion,
VolInfoAttr->MinorVersion,
@@ -163,13 +142,11 @@ NtfsDumpVolumeInformationAttribute(PATTRIBUTE Attribute)
static
VOID
NtfsDumpIndexRootAttribute(PATTRIBUTE Attribute)
NtfsDumpIndexRootAttribute(PNTFS_ATTR_RECORD Attribute)
{
PRESIDENT_ATTRIBUTE ResAttr;
PINDEX_ROOT_ATTRIBUTE IndexRootAttr;
ResAttr = (PRESIDENT_ATTRIBUTE)Attribute;
IndexRootAttr = (PINDEX_ROOT_ATTRIBUTE)((ULONG_PTR)ResAttr + ResAttr->ValueOffset);
IndexRootAttr = (PINDEX_ROOT_ATTRIBUTE)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset);
if (IndexRootAttr->AttributeType == AttributeFileName)
ASSERT(IndexRootAttr->CollationRule == COLLATION_FILE_NAME);
@@ -190,15 +167,14 @@ NtfsDumpIndexRootAttribute(PATTRIBUTE Attribute)
static
VOID
NtfsDumpAttribute (PATTRIBUTE Attribute)
NtfsDumpAttribute(PNTFS_ATTR_RECORD Attribute)
{
PNONRESIDENT_ATTRIBUTE NresAttr;
UNICODE_STRING Name;
ULONGLONG lcn = 0;
ULONGLONG runcount = 0;
switch (Attribute->AttributeType)
switch (Attribute->Type)
{
case AttributeFileName:
NtfsDumpFileNameAttribute(Attribute);
@@ -267,7 +243,7 @@ NtfsDumpAttribute (PATTRIBUTE Attribute)
default:
DbgPrint(" Attribute %lx ",
Attribute->AttributeType);
Attribute->Type);
break;
}
@@ -281,16 +257,14 @@ NtfsDumpAttribute (PATTRIBUTE Attribute)
}
DbgPrint("(%s)\n",
Attribute->Nonresident ? "non-resident" : "resident");
Attribute->IsNonResident ? "non-resident" : "resident");
if (Attribute->Nonresident)
if (Attribute->IsNonResident)
{
NresAttr = (PNONRESIDENT_ATTRIBUTE)Attribute;
FindRun(NresAttr,0,&lcn, &runcount);
FindRun(Attribute,0,&lcn, &runcount);
DbgPrint(" AllocatedSize %I64u DataSize %I64u\n",
NresAttr->AllocatedSize, NresAttr->DataSize);
Attribute->NonResident.AllocatedSize, Attribute->NonResident.DataSize);
DbgPrint(" logical clusters: %I64u - %I64u\n",
lcn, lcn + runcount - 1);
}
@@ -300,15 +274,15 @@ NtfsDumpAttribute (PATTRIBUTE Attribute)
VOID
NtfsDumpFileAttributes(PFILE_RECORD_HEADER FileRecord)
{
PATTRIBUTE Attribute;
PNTFS_ATTR_RECORD Attribute;
Attribute = (PATTRIBUTE)((ULONG_PTR)FileRecord + FileRecord->AttributeOffset);
while (Attribute < (PATTRIBUTE)((ULONG_PTR)FileRecord + FileRecord->BytesInUse) &&
Attribute->AttributeType != (ATTRIBUTE_TYPE)-1)
Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->AttributeOffset);
while (Attribute < (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->BytesInUse) &&
Attribute->Type != (ATTRIBUTE_TYPE)-1)
{
NtfsDumpAttribute(Attribute);
Attribute = (PATTRIBUTE)((ULONG_PTR)Attribute + Attribute->Length);
Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)Attribute + Attribute->Length);
}
}
+39 -27
View File
@@ -34,6 +34,8 @@
#define NDEBUG
#include <debug.h>
UNICODE_STRING EmptyName = RTL_CONSTANT_STRING(L"");
/* FUNCTIONS ****************************************************************/
/*
@@ -173,14 +175,14 @@ 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;
PNTFS_ATTR_CONTEXT AttrCtxt;
PNTFS_ATTR_RECORD Attribute;
PNTFS_FCB VolumeFcb;
PWSTR VolumeNameU;
@@ -251,10 +253,10 @@ NtfsGetVolumeData(PDEVICE_OBJECT DeviceObject,
ExFreePool(BootSector);
MftRecord = ExAllocatePoolWithTag(NonPagedPool,
NtfsInfo->BytesPerFileRecord,
TAG_NTFS);
if (MftRecord == NULL)
DeviceExt->MasterFileTable = ExAllocatePoolWithTag(NonPagedPool,
NtfsInfo->BytesPerFileRecord,
TAG_NTFS);
if (DeviceExt->MasterFileTable == NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
@@ -263,11 +265,20 @@ NtfsGetVolumeData(PDEVICE_OBJECT DeviceObject,
NtfsInfo->MftStart.u.LowPart * NtfsInfo->SectorsPerCluster,
NtfsInfo->BytesPerFileRecord / NtfsInfo->BytesPerSector,
NtfsInfo->BytesPerSector,
(PVOID)MftRecord,
(PVOID)DeviceExt->MasterFileTable,
TRUE);
if (!NT_SUCCESS(Status))
{
ExFreePool(MftRecord);
DPRINT1("Failed reading MFT.\n");
ExFreePool(DeviceExt->MasterFileTable);
return Status;
}
Status = FindAttribute(DeviceExt, DeviceExt->MasterFileTable, AttributeData, &EmptyName, &DeviceExt->MFTContext);
if (!NT_SUCCESS(Status))
{
DPRINT1("Can't find data attribute for Master File Table.\n");
ExFreePool(DeviceExt->MasterFileTable);
return Status;
}
@@ -276,40 +287,41 @@ NtfsGetVolumeData(PDEVICE_OBJECT DeviceObject,
TAG_NTFS);
if (VolumeRecord == NULL)
{
ExFreePool(MftRecord);
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,
3,
VolumeRecord,
MftRecord);
NTFS_FILE_VOLUME,
VolumeRecord);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed reading volume file\n");
ExFreePool(VolumeRecord);
ExFreePool(MftRecord);
ExFreePool(DeviceExt->MasterFileTable);
return Status;
}
/* Enumerate attributes */
NtfsDumpFileAttributes (MftRecord);
NtfsDumpFileAttributes(DeviceExt->MasterFileTable);
/* Enumerate attributes */
NtfsDumpFileAttributes (VolumeRecord);
NtfsDumpFileAttributes(VolumeRecord);
/* Get volume name */
Attribute = FindAttribute (VolumeRecord, AttributeVolumeName, NULL);
DPRINT("Attribute %p\n", Attribute);
Status = FindAttribute(DeviceExt, VolumeRecord, AttributeVolumeName, &EmptyName, &AttrCtxt);
if (Attribute != NULL && ((PRESIDENT_ATTRIBUTE)Attribute)->ValueLength != 0)
if (NT_SUCCESS(Status) && AttrCtxt->Record.Resident.ValueLength != 0)
{
DPRINT("Data length %lu\n", AttributeDataLength (Attribute));
Attribute = &AttrCtxt->Record;
DPRINT("Data length %lu\n", AttributeDataLength(Attribute));
NtfsInfo->VolumeLabelLength =
min (((PRESIDENT_ATTRIBUTE)Attribute)->ValueLength, MAXIMUM_VOLUME_LABEL_LENGTH);
min (Attribute->Resident.ValueLength, MAXIMUM_VOLUME_LABEL_LENGTH);
RtlCopyMemory(NtfsInfo->VolumeLabel,
(PVOID)((ULONG_PTR)Attribute + ((PRESIDENT_ATTRIBUTE)Attribute)->ValueOffset),
(PVOID)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset),
NtfsInfo->VolumeLabelLength);
VolumeNameU = NtfsInfo->VolumeLabel;
}
@@ -322,8 +334,9 @@ NtfsGetVolumeData(PDEVICE_OBJECT DeviceObject,
VolumeFcb = NtfsCreateFCB(VolumeNameU, DeviceExt);
if (VolumeFcb == NULL)
{
DPRINT1("Failed allocating volume FCB\n");
ExFreePool(VolumeRecord);
ExFreePool(MftRecord);
ExFreePool(DeviceExt->MasterFileTable);
return STATUS_INSUFFICIENT_RESOURCES;
}
@@ -334,20 +347,19 @@ NtfsGetVolumeData(PDEVICE_OBJECT DeviceObject,
DeviceExt->VolumeFcb = VolumeFcb;
/* Get volume information */
Attribute = FindAttribute (VolumeRecord, AttributeVolumeInformation, NULL);
DPRINT("Attribute %p\n", Attribute);
Status = FindAttribute(DeviceExt, VolumeRecord, AttributeVolumeInformation, &EmptyName, &AttrCtxt);
if (Attribute != NULL && ((PRESIDENT_ATTRIBUTE)Attribute)->ValueLength != 0)
if (NT_SUCCESS(Status) && AttrCtxt->Record.Resident.ValueLength != 0)
{
Attribute = &AttrCtxt->Record;
DPRINT("Data length %lu\n", AttributeDataLength (Attribute));
VolumeInfo = (PVOID)((ULONG_PTR)Attribute + ((PRESIDENT_ATTRIBUTE)Attribute)->ValueOffset);
VolumeInfo = (PVOID)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset);
NtfsInfo->MajorVersion = VolumeInfo->MajorVersion;
NtfsInfo->MinorVersion = VolumeInfo->MinorVersion;
NtfsInfo->Flags = VolumeInfo->Flags;
}
ExFreePool(MftRecord);
ExFreePool(VolumeRecord);
return Status;
+596 -224
View File
@@ -31,277 +31,413 @@
#define NDEBUG
#include <debug.h>
UNICODE_STRING IndexOfFileNames = RTL_CONSTANT_STRING(L"$I30");
/* FUNCTIONS ****************************************************************/
NTSTATUS
NtfsOpenMft(PDEVICE_EXTENSION Vcb)
PNTFS_ATTR_CONTEXT
PrepareAttributeContext(PNTFS_ATTR_RECORD AttrRecord)
{
// PVOID Bitmap;
PFILE_RECORD_HEADER MftRecord;
PFILE_RECORD_HEADER FileRecord;
// PATTRIBUTE Attribute;
// PATTRIBUTE AttrData;
// PRESIDENT_ATTRIBUTE ResAttr;
PNTFS_ATTR_CONTEXT Context;
NTSTATUS Status;
ULONG BytesPerFileRecord;
ULONG n;
ULONG i;
DPRINT1("NtfsOpenMft() called\n");
BytesPerFileRecord = Vcb->NtfsInfo.BytesPerFileRecord;
MftRecord = ExAllocatePoolWithTag(NonPagedPool,
BytesPerFileRecord,
TAG_NTFS);
if (MftRecord == NULL)
Context = ExAllocatePoolWithTag(NonPagedPool,
FIELD_OFFSET(NTFS_ATTR_CONTEXT, Record) + AttrRecord->Length,
TAG_NTFS);
RtlCopyMemory(&Context->Record, AttrRecord, AttrRecord->Length);
if (AttrRecord->IsNonResident)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
LONGLONG DataRunOffset;
ULONGLONG DataRunLength;
Status = NtfsReadSectors(Vcb->StorageDevice,
Vcb->NtfsInfo.MftStart.u.LowPart * Vcb->NtfsInfo.SectorsPerCluster,
BytesPerFileRecord / Vcb->NtfsInfo.BytesPerSector,
Vcb->NtfsInfo.BytesPerSector,
(PVOID)MftRecord,
FALSE);
if (!NT_SUCCESS(Status))
{
ExFreePool(MftRecord);
return Status;
}
FixupUpdateSequenceArray(MftRecord);
// Attribute = FindAttribute(MftRecord, AttributeBitmap, 0);
/* Get number of file records*/
n = AttributeDataLength(FindAttribute(MftRecord, AttributeData, 0)) / BytesPerFileRecord;
FileRecord = ExAllocatePoolWithTag(NonPagedPool,
BytesPerFileRecord,
TAG_NTFS);
if (FileRecord == NULL)
{
ExFreePool(MftRecord);
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Enumerate MFT Records */
DPRINT("Enumerate MFT records\n");
for (i = 0; i < n; i++)
{
ReadFileRecord(Vcb,
i,
FileRecord,
MftRecord);
if (FileRecord->Ntfs.Type == NRH_FILE_TYPE &&
(FileRecord->Flags & FRH_IN_USE))
Context->CacheRun = (PUCHAR)&Context->Record + Context->Record.NonResident.MappingPairsOffset;
Context->CacheRunOffset = 0;
Context->CacheRun = DecodeRun(Context->CacheRun, &DataRunOffset, &DataRunLength);
Context->CacheRunLength = DataRunLength;
if (DataRunOffset != -1)
{
DPRINT("\nFile %lu\n\n", i);
/* Enumerate attributtes */
NtfsDumpFileAttributes (FileRecord);
DbgPrint("\n\n");
/* Normal run. */
Context->CacheRunStartLCN =
Context->CacheRunLastLCN = DataRunOffset;
}
}
ExFreePool(FileRecord);
ExFreePool(MftRecord);
return Status;
}
PATTRIBUTE
FindAttribute(PFILE_RECORD_HEADER FileRecord,
ATTRIBUTE_TYPE Type,
PWSTR name)
{
PATTRIBUTE Attribute;
UNREFERENCED_PARAMETER(name);
Attribute = (PATTRIBUTE)((ULONG_PTR)FileRecord + FileRecord->AttributeOffset);
while (Attribute < (PATTRIBUTE)((ULONG_PTR)FileRecord + FileRecord->BytesInUse) &&
Attribute->AttributeType != (ATTRIBUTE_TYPE)-1)
{
if (Attribute->AttributeType == Type)
else
{
return Attribute;
/* Sparse run. */
Context->CacheRunStartLCN = -1;
Context->CacheRunLastLCN = 0;
}
Attribute = (PATTRIBUTE)((ULONG_PTR)Attribute + Attribute->Length);
Context->CacheRunCurrentOffset = 0;
}
return NULL;
}
ULONG
AttributeAllocatedLength(PATTRIBUTE Attribute)
{
if (Attribute->Nonresident)
{
return ((PNONRESIDENT_ATTRIBUTE)Attribute)->AllocatedSize;
}
return ((PRESIDENT_ATTRIBUTE)Attribute)->ValueLength;
}
ULONG
AttributeDataLength(PATTRIBUTE Attribute)
{
if (Attribute->Nonresident)
{
return ((PNONRESIDENT_ATTRIBUTE)Attribute)->DataSize;
}
return ((PRESIDENT_ATTRIBUTE)Attribute)->ValueLength;
return Context;
}
VOID
ReadAttribute(PATTRIBUTE attr,
PVOID buffer,
PDEVICE_EXTENSION Vcb,
PDEVICE_OBJECT DeviceObject)
ReleaseAttributeContext(PNTFS_ATTR_CONTEXT Context)
{
PNONRESIDENT_ATTRIBUTE NresAttr = (PNONRESIDENT_ATTRIBUTE)attr;
ExFreePoolWithTag(Context, TAG_NTFS);
}
UNREFERENCED_PARAMETER(DeviceObject);
if (attr->Nonresident == FALSE)
PNTFS_ATTR_CONTEXT
FindAttributeHelper(PDEVICE_EXTENSION Vcb,
PNTFS_ATTR_RECORD AttrRecord,
PNTFS_ATTR_RECORD AttrRecordEnd,
ULONG Type,
const WCHAR *Name,
ULONG NameLength)
{
DPRINT("FindAttributeHelper(%p, %p, %p, 0x%x, %s, %u)\n", Vcb, AttrRecord, AttrRecordEnd, Type, Name, NameLength);
while (AttrRecord < AttrRecordEnd)
{
memcpy(buffer,
(PVOID)((ULONG_PTR)attr + ((PRESIDENT_ATTRIBUTE)attr)->ValueOffset),
((PRESIDENT_ATTRIBUTE)attr)->ValueLength);
DPRINT("AttrRecord->Type = 0x%x\n", AttrRecord->Type);
if (AttrRecord->Type == AttributeEnd)
break;
if (AttrRecord->Type == AttributeAttributeList)
{
PNTFS_ATTR_CONTEXT Context;
PNTFS_ATTR_CONTEXT ListContext;
PVOID ListBuffer;
ULONGLONG ListSize;
PNTFS_ATTR_RECORD ListAttrRecord;
PNTFS_ATTR_RECORD ListAttrRecordEnd;
// Do not handle non-resident yet
ASSERT(!(AttrRecord->IsNonResident & 1));
ListContext = PrepareAttributeContext(AttrRecord);
ListSize = AttributeDataLength(&ListContext->Record);
if(ListSize <= 0xFFFFFFFF)
ListBuffer = ExAllocatePoolWithTag(NonPagedPool, (ULONG)ListSize, TAG_NTFS);
else
ListBuffer = NULL;
if(!ListBuffer)
{
DPRINT("Failed to allocate memory: %x\n", (ULONG)ListSize);
continue;
}
ListAttrRecord = (PNTFS_ATTR_RECORD)ListBuffer;
ListAttrRecordEnd = (PNTFS_ATTR_RECORD)((PCHAR)ListBuffer + ListSize);
if (ReadAttribute(Vcb, ListContext, 0, ListBuffer, (ULONG)ListSize) == ListSize)
{
Context = FindAttributeHelper(Vcb, ListAttrRecord, ListAttrRecordEnd,
Type, Name, NameLength);
ReleaseAttributeContext(ListContext);
ExFreePoolWithTag(ListBuffer, TAG_NTFS);
if (Context != NULL)
{
DPRINT("Found context = %p\n", Context);
return Context;
}
}
}
if (AttrRecord->Type == Type)
{
DPRINT("%d, %d\n", AttrRecord->NameLength, NameLength);
if (AttrRecord->NameLength == NameLength)
{
PWCHAR AttrName;
AttrName = (PWCHAR)((PCHAR)AttrRecord + AttrRecord->NameOffset);
DPRINT("%s, %s\n", AttrName, Name);
if (RtlCompareMemory(AttrName, Name, NameLength << 1) == (NameLength << 1))
{
/* Found it, fill up the context and return. */
DPRINT("Found context\n");
return PrepareAttributeContext(AttrRecord);
}
}
}
if (AttrRecord->Length == 0)
{
DPRINT("Null length attribute record\n");
return NULL;
}
AttrRecord = (PNTFS_ATTR_RECORD)((PCHAR)AttrRecord + AttrRecord->Length);
}
ReadExternalAttribute(Vcb,
NresAttr,
0,
(ULONG)(NresAttr->LastVcn) + 1,
buffer);
DPRINT("Ended\n");
return NULL;
}
NTSTATUS
ReadFileRecord(PDEVICE_EXTENSION Vcb,
ULONG index,
PFILE_RECORD_HEADER file,
PFILE_RECORD_HEADER Mft)
FindAttribute(PDEVICE_EXTENSION Vcb,
PFILE_RECORD_HEADER MftRecord,
ULONG Type,
PUNICODE_STRING Name,
PNTFS_ATTR_CONTEXT * AttrCtx)
{
PVOID p;
ULONG BytesPerFileRecord = Vcb->NtfsInfo.BytesPerFileRecord;
ULONG clusters = max(BytesPerFileRecord / Vcb->NtfsInfo.BytesPerCluster, 1);
ULONGLONG vcn = index * BytesPerFileRecord / Vcb->NtfsInfo.BytesPerCluster;
LONG m = (Vcb->NtfsInfo.BytesPerCluster / BytesPerFileRecord) - 1;
ULONG n = m > 0 ? (index & m) : 0;
PNTFS_ATTR_RECORD AttrRecord;
PNTFS_ATTR_RECORD AttrRecordEnd;
p = ExAllocatePoolWithTag(NonPagedPool,
clusters * Vcb->NtfsInfo.BytesPerCluster,
TAG_NTFS);
DPRINT("NtfsFindAttribute(%p, %p, %u, %s)\n", Vcb, MftRecord, Type, Name);
ReadVCN (Vcb, Mft, AttributeData, vcn, clusters, p);
AttrRecord = (PNTFS_ATTR_RECORD)((PCHAR)MftRecord + MftRecord->AttributeOffset);
AttrRecordEnd = (PNTFS_ATTR_RECORD)((PCHAR)MftRecord + Vcb->NtfsInfo.BytesPerFileRecord);
memcpy(file,
(PVOID)((ULONG_PTR)p + n * BytesPerFileRecord),
BytesPerFileRecord);
ExFreePool(p);
FixupUpdateSequenceArray(file);
*AttrCtx = FindAttributeHelper(Vcb, AttrRecord, AttrRecordEnd, Type, Name->Buffer, Name->Length);
if (*AttrCtx == NULL)
{
return STATUS_OBJECT_NAME_NOT_FOUND;
}
return STATUS_SUCCESS;
}
VOID
ReadExternalAttribute(PDEVICE_EXTENSION Vcb,
PNONRESIDENT_ATTRIBUTE NresAttr,
ULONGLONG vcn,
ULONG count,
PVOID buffer)
ULONG
AttributeAllocatedLength(PNTFS_ATTR_RECORD AttrRecord)
{
ULONGLONG lcn;
ULONGLONG runcount;
ULONG readcount;
ULONG left;
ULONG n;
PUCHAR bytes = (PUCHAR)buffer;
for (left = count; left > 0; left -= readcount)
{
FindRun(NresAttr, vcn, &lcn, &runcount);
// readcount = (ULONG)(__min(runcount, left));
readcount = (ULONG)min(runcount, left);
n = readcount * Vcb->NtfsInfo.BytesPerCluster;
if (lcn == 0)
memset(bytes, 0, n);
else
ReadLCN(Vcb, lcn, readcount, bytes);
vcn += readcount;
bytes += n;
}
if (AttrRecord->IsNonResident)
return AttrRecord->NonResident.AllocatedSize;
else
return AttrRecord->Resident.ValueLength;
}
VOID
ReadVCN(PDEVICE_EXTENSION Vcb,
PFILE_RECORD_HEADER file,
ATTRIBUTE_TYPE type,
ULONGLONG vcn,
ULONG count,
PVOID buffer)
ULONGLONG
AttributeDataLength(PNTFS_ATTR_RECORD AttrRecord)
{
PNONRESIDENT_ATTRIBUTE NresAttr;
PATTRIBUTE attr;
attr = FindAttribute(file, type, 0);
NresAttr = (PNONRESIDENT_ATTRIBUTE) attr;
if (NresAttr == 0 || (vcn < NresAttr->StartVcn ||vcn > NresAttr->LastVcn))
{
// PATTRIBUTE attrList = FindAttribute(file,AttributeAttributeList,0);
DbgPrint("Exeption \n");
// KeDebugCheck(0);
}
ReadExternalAttribute(Vcb, NresAttr, vcn, count, buffer);
if (AttrRecord->IsNonResident)
return AttrRecord->NonResident.DataSize;
else
return AttrRecord->Resident.ValueLength;
}
#if 0
BOOL bitset(PUCHAR bitmap, ULONG i)
ULONG
ReadAttribute(PDEVICE_EXTENSION Vcb,
PNTFS_ATTR_CONTEXT Context,
ULONGLONG Offset,
PCHAR Buffer,
ULONG Length)
{
return (bitmap[i>>3] & (1 << (i & 7))) !=0;
}
#endif
ULONGLONG LastLCN;
PUCHAR DataRun;
LONGLONG DataRunOffset;
ULONGLONG DataRunLength;
LONGLONG DataRunStartLCN;
ULONGLONG CurrentOffset;
ULONG ReadLength;
ULONG AlreadyRead;
NTSTATUS Status;
VOID
FixupUpdateSequenceArray(PFILE_RECORD_HEADER file)
{
PUSHORT usa = (PUSHORT)((ULONG_PTR)file + file->Ntfs.UsaOffset);
PUSHORT sector = (PUSHORT)file;
ULONG i;
for (i = 1; i < file->Ntfs.UsaCount; i++)
if (!Context->Record.IsNonResident)
{
sector[255] = usa[i];
sector += 256;
if (Offset > Context->Record.Resident.ValueLength)
return 0;
if (Offset + Length > Context->Record.Resident.ValueLength)
Length = (ULONG)(Context->Record.Resident.ValueLength - Offset);
RtlCopyMemory(Buffer, (PCHAR)&Context->Record + Context->Record.Resident.ValueOffset + Offset, Length);
return Length;
}
/*
* Non-resident attribute
*/
/*
* I. Find the corresponding start data run.
*/
AlreadyRead = 0;
// FIXME: Cache seems to be non-working. Disable it for now
//if(Context->CacheRunOffset <= Offset && Offset < Context->CacheRunOffset + Context->CacheRunLength * Volume->ClusterSize)
if (0)
{
DataRun = Context->CacheRun;
LastLCN = Context->CacheRunLastLCN;
DataRunStartLCN = Context->CacheRunStartLCN;
DataRunLength = Context->CacheRunLength;
CurrentOffset = Context->CacheRunCurrentOffset;
}
else
{
LastLCN = 0;
DataRun = (PUCHAR)&Context->Record + Context->Record.NonResident.MappingPairsOffset;
CurrentOffset = 0;
while (1)
{
DataRun = DecodeRun(DataRun, &DataRunOffset, &DataRunLength);
if (DataRunOffset != -1)
{
/* Normal data run. */
DataRunStartLCN = LastLCN + DataRunOffset;
LastLCN = DataRunStartLCN;
}
else
{
/* Sparse data run. */
DataRunStartLCN = -1;
}
if (Offset >= CurrentOffset &&
Offset < CurrentOffset + (DataRunLength * Vcb->NtfsInfo.BytesPerCluster))
{
break;
}
if (*DataRun == 0)
{
return AlreadyRead;
}
CurrentOffset += DataRunLength * Vcb->NtfsInfo.BytesPerCluster;
}
}
/*
* II. Go through the run list and read the data
*/
ReadLength = (ULONG)min(DataRunLength * Vcb->NtfsInfo.BytesPerCluster - (Offset - CurrentOffset), Length);
if (DataRunStartLCN == -1)
RtlZeroMemory(Buffer, ReadLength);
Status = NtfsReadDisk(Vcb->StorageDevice,
DataRunStartLCN * Vcb->NtfsInfo.BytesPerCluster + Offset - CurrentOffset,
ReadLength,
(PVOID)Buffer,
FALSE);
if (NT_SUCCESS(Status))
{
Length -= ReadLength;
Buffer += ReadLength;
AlreadyRead += ReadLength;
if (ReadLength == DataRunLength * Vcb->NtfsInfo.BytesPerCluster - (Offset - CurrentOffset))
{
CurrentOffset += DataRunLength * Vcb->NtfsInfo.BytesPerCluster;
DataRun = DecodeRun(DataRun, &DataRunOffset, &DataRunLength);
if (DataRunLength != (ULONGLONG)-1)
{
DataRunStartLCN = LastLCN + DataRunOffset;
LastLCN = DataRunStartLCN;
}
else
DataRunStartLCN = -1;
if (*DataRun == 0)
return AlreadyRead;
}
while (Length > 0)
{
ReadLength = (ULONG)min(DataRunLength * Vcb->NtfsInfo.BytesPerCluster, Length);
if (DataRunStartLCN == -1)
RtlZeroMemory(Buffer, ReadLength);
else
{
Status = NtfsReadDisk(Vcb->StorageDevice,
DataRunStartLCN * Vcb->NtfsInfo.BytesPerCluster,
ReadLength,
(PVOID)Buffer,
FALSE);
if (!NT_SUCCESS(Status))
break;
}
Length -= ReadLength;
Buffer += ReadLength;
AlreadyRead += ReadLength;
/* We finished this request, but there still data in this data run. */
if (Length == 0 && ReadLength != DataRunLength * Vcb->NtfsInfo.BytesPerCluster)
break;
/*
* Go to next run in the list.
*/
if (*DataRun == 0)
break;
CurrentOffset += DataRunLength * Vcb->NtfsInfo.BytesPerCluster;
DataRun = DecodeRun(DataRun, &DataRunOffset, &DataRunLength);
if (DataRunOffset != -1)
{
/* Normal data run. */
DataRunStartLCN = LastLCN + DataRunOffset;
LastLCN = DataRunStartLCN;
}
else
{
/* Sparse data run. */
DataRunStartLCN = -1;
}
} /* while */
} /* if Disk */
Context->CacheRun = DataRun;
Context->CacheRunOffset = Offset + AlreadyRead;
Context->CacheRunStartLCN = DataRunStartLCN;
Context->CacheRunLength = DataRunLength;
Context->CacheRunLastLCN = LastLCN;
Context->CacheRunCurrentOffset = CurrentOffset;
return AlreadyRead;
}
NTSTATUS
ReadFileRecord(PDEVICE_EXTENSION Vcb,
ULONGLONG index,
PFILE_RECORD_HEADER file)
{
ULONGLONG BytesRead;
BytesRead = ReadAttribute(Vcb, Vcb->MFTContext, index * Vcb->NtfsInfo.BytesPerFileRecord, (PCHAR)file, Vcb->NtfsInfo.BytesPerFileRecord);
if (BytesRead != Vcb->NtfsInfo.BytesPerFileRecord)
{
DPRINT1("ReadFileRecord failed: %u read, %u expected\n", BytesRead, Vcb->NtfsInfo.BytesPerFileRecord);
return STATUS_PARTIAL_COPY;
}
/* Apply update sequence array fixups. */
return FixupUpdateSequenceArray(Vcb, &file->Ntfs);
}
NTSTATUS
FixupUpdateSequenceArray(PDEVICE_EXTENSION Vcb,
PNTFS_RECORD_HEADER Record)
{
USHORT *USA;
USHORT USANumber;
USHORT USACount;
USHORT *Block;
USA = (USHORT*)((PCHAR)Record + Record->UsaOffset);
USANumber = *(USA++);
USACount = Record->UsaCount - 1; /* Exclude the USA Number. */
Block = (USHORT*)((PCHAR)Record + Vcb->NtfsInfo.BytesPerSector - 2);
while (USACount)
{
if (*Block != USANumber)
{
DPRINT1("Mismatch with USA: %u read, %u expected\n" , *Block, USANumber);
return STATUS_UNSUCCESSFUL;
}
*Block = *(USA++);
Block = (USHORT*)((PCHAR)Block + Vcb->NtfsInfo.BytesPerSector);
USACount--;
}
return STATUS_SUCCESS;
}
@@ -323,4 +459,240 @@ ReadLCN(PDEVICE_EXTENSION Vcb,
FALSE);
}
BOOLEAN
CompareFileName(PUNICODE_STRING FileName,
PINDEX_ENTRY_ATTRIBUTE IndexEntry)
{
UNICODE_STRING EntryName;
EntryName.Buffer = IndexEntry->FileName.Name;
EntryName.Length =
EntryName.MaximumLength = IndexEntry->FileName.NameLength;
return (RtlCompareUnicodeString(FileName, &EntryName, !!(IndexEntry->FileName.NameType != NTFS_FILE_NAME_POSIX)) == TRUE);
}
NTSTATUS
NtfsFindMftRecord(PDEVICE_EXTENSION Vcb, ULONGLONG MFTIndex, PUNICODE_STRING FileName, ULONGLONG *OutMFTIndex)
{
PFILE_RECORD_HEADER MftRecord;
//ULONG Magic;
PNTFS_ATTR_CONTEXT IndexRootCtx;
PNTFS_ATTR_CONTEXT IndexBitmapCtx;
PNTFS_ATTR_CONTEXT IndexAllocationCtx;
PINDEX_ROOT_ATTRIBUTE IndexRoot;
ULONGLONG BitmapDataSize;
ULONGLONG IndexAllocationSize;
PCHAR BitmapData;
PCHAR IndexRecord;
PINDEX_ENTRY_ATTRIBUTE IndexEntry, IndexEntryEnd;
ULONG RecordOffset;
ULONG IndexBlockSize;
NTSTATUS Status;
MftRecord = ExAllocatePoolWithTag(NonPagedPool,
Vcb->NtfsInfo.BytesPerFileRecord,
TAG_NTFS);
if (MftRecord == NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
if (ReadFileRecord(Vcb, MFTIndex, MftRecord))
{
//Magic = MftRecord->Magic;
Status = FindAttribute(Vcb, MftRecord, AttributeIndexRoot, &IndexOfFileNames, &IndexRootCtx);
if (!NT_SUCCESS(Status))
{
ExFreePoolWithTag(MftRecord, TAG_NTFS);
return Status;
}
IndexRecord = ExAllocatePoolWithTag(NonPagedPool, Vcb->NtfsInfo.BytesPerIndexRecord, TAG_NTFS);
if (IndexRecord == NULL)
{
ExFreePoolWithTag(MftRecord, TAG_NTFS);
return STATUS_INSUFFICIENT_RESOURCES;
}
ReadAttribute(Vcb, IndexRootCtx, 0, IndexRecord, Vcb->NtfsInfo.BytesPerIndexRecord);
IndexRoot = (PINDEX_ROOT_ATTRIBUTE)IndexRecord;
IndexEntry = (PINDEX_ENTRY_ATTRIBUTE)((PCHAR)&IndexRoot->Header + IndexRoot->Header.FirstEntryOffset);
/* Index root is always resident. */
IndexEntryEnd = (PINDEX_ENTRY_ATTRIBUTE)(IndexRecord + IndexRootCtx->Record.Resident.ValueLength);
ReleaseAttributeContext(IndexRootCtx);
DPRINT("IndexRecordSize: %x IndexBlockSize: %x\n", Vcb->NtfsInfo.BytesPerIndexRecord, IndexRoot->SizeOfEntry);
while (IndexEntry < IndexEntryEnd &&
!(IndexEntry->Flags & NTFS_INDEX_ENTRY_END))
{
if (CompareFileName(FileName, IndexEntry))
{
*OutMFTIndex = IndexEntry->Data.Directory.IndexedFile;
ExFreePoolWithTag(IndexRecord, TAG_NTFS);
ExFreePoolWithTag(MftRecord, TAG_NTFS);
return STATUS_SUCCESS;
}
IndexEntry = (PINDEX_ENTRY_ATTRIBUTE)((PCHAR)IndexEntry + IndexEntry->Length);
}
if (IndexRoot->Header.Flags & INDEX_ROOT_LARGE)
{
DPRINT("Large Index!\n");
IndexBlockSize = IndexRoot->SizeOfEntry;
Status = FindAttribute(Vcb, MftRecord, AttributeBitmap, &IndexOfFileNames, &IndexBitmapCtx);
if (!NT_SUCCESS(Status))
{
DPRINT("Corrupted filesystem!\n");
ExFreePoolWithTag(MftRecord, TAG_NTFS);
return Status;
}
BitmapDataSize = AttributeDataLength(&IndexBitmapCtx->Record);
DPRINT("BitmapDataSize: %x\n", (ULONG)BitmapDataSize);
if(BitmapDataSize <= 0xFFFFFFFF)
BitmapData = ExAllocatePoolWithTag(NonPagedPool, (ULONG)BitmapDataSize, TAG_NTFS);
else
BitmapData = NULL;
if (BitmapData == NULL)
{
ExFreePoolWithTag(IndexRecord, TAG_NTFS);
ExFreePoolWithTag(MftRecord, TAG_NTFS);
return STATUS_INSUFFICIENT_RESOURCES;
}
ReadAttribute(Vcb, IndexBitmapCtx, 0, BitmapData, (ULONG)BitmapDataSize);
ReleaseAttributeContext(IndexBitmapCtx);
Status = FindAttribute(Vcb, MftRecord, AttributeIndexAllocation, &IndexOfFileNames, &IndexAllocationCtx);
if (!NT_SUCCESS(Status))
{
DPRINT("Corrupted filesystem!\n");
ExFreePoolWithTag(BitmapData, TAG_NTFS);
ExFreePoolWithTag(IndexRecord, TAG_NTFS);
ExFreePoolWithTag(MftRecord, TAG_NTFS);
return Status;
}
IndexAllocationSize = AttributeDataLength(&IndexAllocationCtx->Record);
RecordOffset = 0;
for (;;)
{
DPRINT("RecordOffset: %x IndexAllocationSize: %x\n", RecordOffset, IndexAllocationSize);
for (; RecordOffset < IndexAllocationSize;)
{
UCHAR Bit = 1 << ((RecordOffset / IndexBlockSize) & 7);
ULONG Byte = (RecordOffset / IndexBlockSize) >> 3;
if ((BitmapData[Byte] & Bit))
break;
RecordOffset += IndexBlockSize;
}
if (RecordOffset >= IndexAllocationSize)
{
break;
}
ReadAttribute(Vcb, IndexAllocationCtx, RecordOffset, IndexRecord, IndexBlockSize);
if (!FixupUpdateSequenceArray(Vcb, &((PFILE_RECORD_HEADER)IndexRecord)->Ntfs))
{
break;
}
/* FIXME */
IndexEntry = (PINDEX_ENTRY_ATTRIBUTE)(IndexRecord + 0x18 + *(USHORT *)(IndexRecord + 0x18));
IndexEntryEnd = (PINDEX_ENTRY_ATTRIBUTE)(IndexRecord + IndexBlockSize);
while (IndexEntry < IndexEntryEnd &&
!(IndexEntry->Flags & NTFS_INDEX_ENTRY_END))
{
if (CompareFileName(FileName, IndexEntry))
{
DPRINT("File found\n");
*OutMFTIndex = IndexEntry->Data.Directory.IndexedFile;
ExFreePoolWithTag(BitmapData, TAG_NTFS);
ExFreePoolWithTag(IndexRecord, TAG_NTFS);
ExFreePoolWithTag(MftRecord, TAG_NTFS);
ReleaseAttributeContext(IndexAllocationCtx);
return STATUS_SUCCESS;
}
IndexEntry = (PINDEX_ENTRY_ATTRIBUTE)((PCHAR)IndexEntry + IndexEntry->Length);
}
RecordOffset += IndexBlockSize;
}
ReleaseAttributeContext(IndexAllocationCtx);
ExFreePoolWithTag(BitmapData, TAG_NTFS);
}
ExFreePoolWithTag(IndexRecord, TAG_NTFS);
}
else
{
DPRINT("Can't read MFT record\n");
}
ExFreePoolWithTag(MftRecord, TAG_NTFS);
return STATUS_OBJECT_PATH_NOT_FOUND;
}
NTSTATUS
NtfsLookupFile(PDEVICE_EXTENSION Vcb,
PUNICODE_STRING PathName,
PFILE_RECORD_HEADER *FileRecord,
PNTFS_ATTR_CONTEXT *DataContext)
{
ULONGLONG CurrentMFTIndex;
UNICODE_STRING Current, Remaining;
NTSTATUS Status;
DPRINT1("NtfsLookupFile(%p, %wZ, %p)\n", Vcb, PathName, FileRecord);
CurrentMFTIndex = NTFS_FILE_ROOT;
FsRtlDissectName(*PathName, &Current, &Remaining);
while (Current.Length != 0)
{
DPRINT1("Lookup: %wZ\n", &Current);
Status = NtfsFindMftRecord(Vcb, CurrentMFTIndex, &Current, &CurrentMFTIndex);
if (!NT_SUCCESS(Status))
{
return Status;
}
FsRtlDissectName(*PathName, &Current, &Remaining);
}
*FileRecord = ExAllocatePoolWithTag(NonPagedPool, Vcb->NtfsInfo.BytesPerFileRecord, TAG_NTFS);
if (*FileRecord == NULL)
{
DPRINT("NtfsLookupFile: Can't allocate MFT record\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
Status = ReadFileRecord(Vcb, CurrentMFTIndex, *FileRecord);
if (!NT_SUCCESS(Status))
{
DPRINT("NtfsLookupFile: Can't read MFT record\n");
return Status;
}
Status = FindAttribute(Vcb, *FileRecord, AttributeData, PathName, DataContext);
if (!NT_SUCCESS(Status))
{
DPRINT("NtfsLookupFile: Can't find data attribute\n");
return Status;
}
return STATUS_SUCCESS;
}
/* EOF */
+119 -76
View File
@@ -86,7 +86,6 @@ typedef struct
ULONG Size;
} NTFSIDENTIFIER, *PNTFSIDENTIFIER;
typedef struct
{
NTFSIDENTIFIER Identifier;
@@ -101,6 +100,8 @@ typedef struct
PDEVICE_OBJECT StorageDevice;
PFILE_OBJECT StreamFileObject;
struct _NTFS_ATTR_CONTEXT* MFTContext;
struct _FILE_RECORD_HEADER* MasterFileTable;
struct _FCB *VolumeFcb;
NTFS_INFO NtfsInfo;
@@ -186,9 +187,23 @@ typedef enum
AttributeEAInformation = 0xD0,
AttributeEA = 0xE0,
AttributePropertySet = 0xF0,
AttributeLoggedUtilityStream = 0x100
AttributeLoggedUtilityStream = 0x100,
AttributeEnd = 0xFFFFFFFF
} ATTRIBUTE_TYPE, *PATTRIBUTE_TYPE;
#define NTFS_FILE_MFT 0
#define NTFS_FILE_MFTMIRR 1
#define NTFS_FILE_LOGFILE 2
#define NTFS_FILE_VOLUME 3
#define NTFS_FILE_ATTRDEF 4
#define NTFS_FILE_ROOT 5
#define NTFS_FILE_BITMAP 6
#define NTFS_FILE_BOOT 7
#define NTFS_FILE_BADCLUS 8
#define NTFS_FILE_QUOTA 9
#define NTFS_FILE_UPCASE 10
#define NTFS_FILE_EXTEND 11
#define COLLATION_BINARY 0x00
#define COLLATION_FILE_NAME 0x01
#define COLLATION_UNICODE_STRING 0x02
@@ -200,6 +215,14 @@ typedef enum
#define INDEX_ROOT_SMALL 0x0
#define INDEX_ROOT_LARGE 0x1
#define NTFS_INDEX_ENTRY_NODE 1
#define NTFS_INDEX_ENTRY_END 2
#define NTFS_FILE_NAME_POSIX 0
#define NTFS_FILE_NAME_WIN32 1
#define NTFS_FILE_NAME_DOS 2
#define NTFS_FILE_NAME_WIN32_AND_DOS 3
typedef struct
{
ULONG Type; /* Magic number 'FILE' */
@@ -212,7 +235,7 @@ typedef struct
#define NRH_FILE_TYPE 0x454C4946 /* 'FILE' */
typedef struct
typedef struct _FILE_RECORD_HEADER
{
NTFS_RECORD_HEADER Ntfs;
USHORT SequenceNumber; /* Sequence number */
@@ -236,39 +259,38 @@ typedef struct
typedef struct
{
ATTRIBUTE_TYPE AttributeType;
ULONG Length;
BOOLEAN Nonresident;
UCHAR NameLength;
USHORT NameOffset;
USHORT Flags;
USHORT AttributeNumber;
} ATTRIBUTE, *PATTRIBUTE;
typedef struct
{
ATTRIBUTE Attribute;
ULONG ValueLength;
USHORT ValueOffset;
UCHAR Flags;
// UCHAR Padding0;
} RESIDENT_ATTRIBUTE, *PRESIDENT_ATTRIBUTE;
typedef struct
{
ATTRIBUTE Attribute;
ULONGLONG StartVcn; // LowVcn
ULONGLONG LastVcn; // HighVcn
USHORT RunArrayOffset;
USHORT CompressionUnit;
ULONG Padding0;
UCHAR IndexedFlag;
ULONGLONG AllocatedSize;
ULONGLONG DataSize;
ULONGLONG InitializedSize;
ULONGLONG CompressedSize;
} NONRESIDENT_ATTRIBUTE, *PNONRESIDENT_ATTRIBUTE;
ULONG Type;
ULONG Length;
UCHAR IsNonResident;
UCHAR NameLength;
USHORT NameOffset;
USHORT Flags;
USHORT Instance;
union
{
// Resident attributes
struct
{
ULONG ValueLength;
USHORT ValueOffset;
UCHAR Flags;
UCHAR Reserved;
} Resident;
// Non-resident attributes
struct
{
ULONGLONG LowestVCN;
ULONGLONG HighestVCN;
USHORT MappingPairsOffset;
USHORT CompressionUnit;
UCHAR Reserved[4];
LONGLONG AllocatedSize;
LONGLONG DataSize;
LONGLONG InitializedSize;
LONGLONG CompressedSize;
} NonResident;
};
} NTFS_ATTR_RECORD, *PNTFS_ATTR_RECORD;
typedef struct
{
@@ -335,6 +357,28 @@ typedef struct
INDEX_HEADER_ATTRIBUTE Header;
} INDEX_ROOT_ATTRIBUTE, *PINDEX_ROOT_ATTRIBUTE;
typedef struct
{
union
{
struct
{
ULONGLONG IndexedFile;
} Directory;
struct
{
USHORT DataOffset;
USHORT DataLength;
ULONG Reserved;
} ViewIndex;
} Data;
USHORT Length;
USHORT KeyLength;
USHORT Flags;
USHORT Reserved;
FILENAME_ATTRIBUTE FileName;
} INDEX_ENTRY_ATTRIBUTE, *PINDEX_ENTRY_ATTRIBUTE;
typedef struct
{
ULONGLONG Unknown1;
@@ -357,6 +401,16 @@ typedef struct
NTSTATUS SavedExceptionCode;
} NTFS_IRP_CONTEXT, *PNTFS_IRP_CONTEXT;
typedef struct _NTFS_ATTR_CONTEXT
{
PUCHAR CacheRun;
ULONGLONG CacheRunOffset;
LONGLONG CacheRunStartLCN;
ULONGLONG CacheRunLength;
LONGLONG CacheRunLastLCN;
ULONGLONG CacheRunCurrentOffset;
NTFS_ATTR_RECORD Record;
} NTFS_ATTR_CONTEXT, *PNTFS_ATTR_CONTEXT;
extern PNTFS_GLOBAL_DATA NtfsGlobalData;
@@ -369,15 +423,10 @@ extern PNTFS_GLOBAL_DATA NtfsGlobalData;
//VOID
//NtfsDumpAttribute(PATTRIBUTE Attribute);
//LONGLONG RunLCN(PUCHAR run);
//ULONG RunLength(PUCHAR run);
BOOLEAN
FindRun(PNONRESIDENT_ATTRIBUTE NresAttr,
ULONGLONG vcn,
PULONGLONG lcn,
PULONGLONG count);
PUCHAR
DecodeRun(PUCHAR DataRun,
LONGLONG *DataRunOffset,
ULONGLONG *DataRunLength);
VOID
NtfsDumpFileAttributes(PFILE_RECORD_HEADER FileRecord);
@@ -529,35 +578,30 @@ NtfsFsdFileSystemControl(PDEVICE_OBJECT DeviceObject,
/* mft.c */
NTSTATUS
NtfsOpenMft(PDEVICE_EXTENSION Vcb);
ULONG
ReadAttribute(PDEVICE_EXTENSION Vcb,
PNTFS_ATTR_CONTEXT Context,
ULONGLONG Offset,
PCHAR Buffer,
ULONG Length);
VOID
ReadAttribute(PATTRIBUTE attr,
PVOID buffer,
PDEVICE_EXTENSION Vcb,
PDEVICE_OBJECT DeviceObject);
ULONGLONG
AttributeDataLength(PNTFS_ATTR_RECORD AttrRecord);
ULONG
AttributeDataLength(PATTRIBUTE attr);
ULONG
AttributeAllocatedLength(PATTRIBUTE Attribute);
AttributeAllocatedLength(PNTFS_ATTR_RECORD AttrRecord);
NTSTATUS
ReadFileRecord(PDEVICE_EXTENSION Vcb,
ULONG index,
PFILE_RECORD_HEADER file,
PFILE_RECORD_HEADER Mft);
ULONGLONG index,
PFILE_RECORD_HEADER file);
PATTRIBUTE
FindAttribute(PFILE_RECORD_HEADER file,
ATTRIBUTE_TYPE type,
PWSTR name);
ULONG
AttributeLengthAllocated(PATTRIBUTE attr);
NTSTATUS
FindAttribute(PDEVICE_EXTENSION Vcb,
PFILE_RECORD_HEADER MftRecord,
ULONG Type,
PUNICODE_STRING Name,
PNTFS_ATTR_CONTEXT * AttrCtx);
VOID
ReadVCN(PDEVICE_EXTENSION Vcb,
@@ -567,15 +611,9 @@ ReadVCN(PDEVICE_EXTENSION Vcb,
ULONG count,
PVOID buffer);
VOID
FixupUpdateSequenceArray(PFILE_RECORD_HEADER file);
VOID
ReadExternalAttribute(PDEVICE_EXTENSION Vcb,
PNONRESIDENT_ATTRIBUTE NresAttr,
ULONGLONG vcn,
ULONG count,
PVOID buffer);
NTSTATUS
FixupUpdateSequenceArray(PDEVICE_EXTENSION Vcb,
PNTFS_RECORD_HEADER Record);
NTSTATUS
ReadLCN(PDEVICE_EXTENSION Vcb,
@@ -588,6 +626,11 @@ EnumerAttribute(PFILE_RECORD_HEADER file,
PDEVICE_EXTENSION Vcb,
PDEVICE_OBJECT DeviceObject);
NTSTATUS
NtfsLookupFile(PDEVICE_EXTENSION Vcb,
PUNICODE_STRING PathName,
PFILE_RECORD_HEADER *FileRecord,
PNTFS_ATTR_CONTEXT *DataContext);
/* misc.c */