mirror of
https://github.com/ApfelTeeSaft/reactos.git
synced 2026-08-30 04:13:33 +00:00
[NTFS]
- 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:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user