Author: pschweitzer Date: Fri Sep 26 13:57:29 2014 New Revision: 64313
URL: http://svn.reactos.org/svn/reactos?rev=64313&view=rev Log: [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
Modified: trunk/reactos/drivers/filesystems/ntfs/attrib.c trunk/reactos/drivers/filesystems/ntfs/fsctl.c trunk/reactos/drivers/filesystems/ntfs/mft.c trunk/reactos/drivers/filesystems/ntfs/ntfs.h
Modified: trunk/reactos/drivers/filesystems/ntfs/attrib.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/filesystems/ntfs/at... ============================================================================== --- trunk/reactos/drivers/filesystems/ntfs/attrib.c [iso-8859-1] (original) +++ trunk/reactos/drivers/filesystems/ntfs/attrib.c [iso-8859-1] Fri Sep 26 13:57:29 2014 @@ -33,127 +33,106 @@
/* FUNCTIONS ****************************************************************/
-static -ULONG -RunLength(PUCHAR run) -{ - return(*run & 0x0f) + ((*run >> 4) & 0x0f) + 1; -} - - -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; -} - +PUCHAR +DecodeRun(PUCHAR DataRun, + LONGLONG *DataRunOffset, + ULONGLONG *DataRunLength) +{ + 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; +}
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; - - 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; -} - - -static -VOID -NtfsDumpFileNameAttribute(PATTRIBUTE Attribute) -{ - PRESIDENT_ATTRIBUTE ResAttr; + DecodeRun((PUCHAR)((ULONG_PTR)NresAttr + NresAttr->NonResident.MappingPairsOffset), (PLONGLONG)lcn, count); + + return TRUE; +} + + +static +VOID +NtfsDumpFileNameAttribute(PNTFS_ATTR_RECORD Attribute) +{ PFILENAME_ATTRIBUTE FileNameAttr;
DbgPrint(" $FILE_NAME ");
- ResAttr = (PRESIDENT_ATTRIBUTE)Attribute; -// DbgPrint(" Length %lu Offset %hu ", ResAttr->ValueLength, ResAttr->ValueOffset); - - FileNameAttr = (PFILENAME_ATTRIBUTE)((ULONG_PTR)ResAttr + ResAttr->ValueOffset); +// DbgPrint(" Length %lu Offset %hu ", Attribute->Resident.ValueLength, Attribute->Resident.ValueOffset); + + FileNameAttr = (PFILENAME_ATTRIBUTE)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset); DbgPrint(" '%.*S' ", FileNameAttr->NameLength, FileNameAttr->Name); }
static VOID -NtfsDumpVolumeNameAttribute(PATTRIBUTE Attribute) -{ - PRESIDENT_ATTRIBUTE ResAttr; +NtfsDumpVolumeNameAttribute(PNTFS_ATTR_RECORD Attribute) +{ PWCHAR VolumeName;
DbgPrint(" $VOLUME_NAME ");
- ResAttr = (PRESIDENT_ATTRIBUTE)Attribute; -// DbgPrint(" Length %lu Offset %hu ", ResAttr->ValueLength, ResAttr->ValueOffset); - - VolumeName = (PWCHAR)((ULONG_PTR)ResAttr + ResAttr->ValueOffset); - DbgPrint(" '%.*S' ", ResAttr->ValueLength / sizeof(WCHAR), VolumeName); -} - - -static -VOID -NtfsDumpVolumeInformationAttribute(PATTRIBUTE Attribute) -{ - PRESIDENT_ATTRIBUTE ResAttr; +// DbgPrint(" Length %lu Offset %hu ", Attribute->Resident.ValueLength, Attribute->Resident.ValueOffset); + + VolumeName = (PWCHAR)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset); + DbgPrint(" '%.*S' ", Attribute->Resident.ValueLength / sizeof(WCHAR), VolumeName); +} + + +static +VOID +NtfsDumpVolumeInformationAttribute(PNTFS_ATTR_RECORD Attribute) +{ PVOLINFO_ATTRIBUTE VolInfoAttr;
DbgPrint(" $VOLUME_INFORMATION ");
- ResAttr = (PRESIDENT_ATTRIBUTE)Attribute; -// DbgPrint(" Length %lu Offset %hu ", ResAttr->ValueLength, ResAttr->ValueOffset); - - VolInfoAttr = (PVOLINFO_ATTRIBUTE)((ULONG_PTR)ResAttr + ResAttr->ValueOffset); +// DbgPrint(" Length %lu Offset %hu ", Attribute->Resident.ValueLength, Attribute->Resident.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 @@
static VOID -NtfsDumpIndexRootAttribute(PATTRIBUTE Attribute) -{ - PRESIDENT_ATTRIBUTE ResAttr; +NtfsDumpIndexRootAttribute(PNTFS_ATTR_RECORD Attribute) +{ 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 @@
static VOID -NtfsDumpAttribute (PATTRIBUTE Attribute) -{ - PNONRESIDENT_ATTRIBUTE NresAttr; +NtfsDumpAttribute(PNTFS_ATTR_RECORD Attribute) +{ UNICODE_STRING Name;
ULONGLONG lcn = 0; ULONGLONG runcount = 0;
- switch (Attribute->AttributeType) + switch (Attribute->Type) { case AttributeFileName: NtfsDumpFileNameAttribute(Attribute); @@ -267,7 +243,7 @@
default: DbgPrint(" Attribute %lx ", - Attribute->AttributeType); + Attribute->Type); break; }
@@ -281,16 +257,14 @@ }
DbgPrint("(%s)\n", - Attribute->Nonresident ? "non-resident" : "resident"); - - if (Attribute->Nonresident) - { - NresAttr = (PNONRESIDENT_ATTRIBUTE)Attribute; - - FindRun(NresAttr,0,&lcn, &runcount); + Attribute->IsNonResident ? "non-resident" : "resident"); + + if (Attribute->IsNonResident) + { + 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 @@ VOID NtfsDumpFileAttributes(PFILE_RECORD_HEADER FileRecord) { - PATTRIBUTE Attribute; - - Attribute = (PATTRIBUTE)((ULONG_PTR)FileRecord + FileRecord->AttributeOffset); - while (Attribute < (PATTRIBUTE)((ULONG_PTR)FileRecord + FileRecord->BytesInUse) && - Attribute->AttributeType != (ATTRIBUTE_TYPE)-1) + PNTFS_ATTR_RECORD Attribute; + + 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); } }
Modified: trunk/reactos/drivers/filesystems/ntfs/fsctl.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/filesystems/ntfs/fs... ============================================================================== --- trunk/reactos/drivers/filesystems/ntfs/fsctl.c [iso-8859-1] (original) +++ trunk/reactos/drivers/filesystems/ntfs/fsctl.c [iso-8859-1] Fri Sep 26 13:57:29 2014 @@ -34,6 +34,8 @@ #define NDEBUG #include <debug.h>
+UNICODE_STRING EmptyName = RTL_CONSTANT_STRING(L""); + /* FUNCTIONS ****************************************************************/
/* @@ -173,14 +175,14 @@ 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 @@
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 @@ 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 @@ 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); - if (!NT_SUCCESS(Status)) - { + 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); - - if (Attribute != NULL && ((PRESIDENT_ATTRIBUTE)Attribute)->ValueLength != 0) - { - DPRINT("Data length %lu\n", AttributeDataLength (Attribute)); + Status = FindAttribute(DeviceExt, VolumeRecord, AttributeVolumeName, &EmptyName, &AttrCtxt); + + if (NT_SUCCESS(Status) && AttrCtxt->Record.Resident.ValueLength != 0) + { + 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 @@ 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 @@ DeviceExt->VolumeFcb = VolumeFcb;
/* Get volume information */ - Attribute = FindAttribute (VolumeRecord, AttributeVolumeInformation, NULL); - DPRINT("Attribute %p\n", Attribute); - - if (Attribute != NULL && ((PRESIDENT_ATTRIBUTE)Attribute)->ValueLength != 0) - { + Status = FindAttribute(DeviceExt, VolumeRecord, AttributeVolumeInformation, &EmptyName, &AttrCtxt); + + 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;
Modified: trunk/reactos/drivers/filesystems/ntfs/mft.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/filesystems/ntfs/mf... ============================================================================== --- trunk/reactos/drivers/filesystems/ntfs/mft.c [iso-8859-1] (original) +++ trunk/reactos/drivers/filesystems/ntfs/mft.c [iso-8859-1] Fri Sep 26 13:57:29 2014 @@ -31,277 +31,413 @@ #define NDEBUG #include <debug.h>
+UNICODE_STRING IndexOfFileNames = RTL_CONSTANT_STRING(L"$I30"); + /* FUNCTIONS ****************************************************************/
+PNTFS_ATTR_CONTEXT +PrepareAttributeContext(PNTFS_ATTR_RECORD AttrRecord) +{ + PNTFS_ATTR_CONTEXT Context; + + Context = ExAllocatePoolWithTag(NonPagedPool, + FIELD_OFFSET(NTFS_ATTR_CONTEXT, Record) + AttrRecord->Length, + TAG_NTFS); + RtlCopyMemory(&Context->Record, AttrRecord, AttrRecord->Length); + if (AttrRecord->IsNonResident) + { + LONGLONG DataRunOffset; + ULONGLONG DataRunLength; + + 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) + { + /* Normal run. */ + Context->CacheRunStartLCN = + Context->CacheRunLastLCN = DataRunOffset; + } + else + { + /* Sparse run. */ + Context->CacheRunStartLCN = -1; + Context->CacheRunLastLCN = 0; + } + Context->CacheRunCurrentOffset = 0; + } + + return Context; +} + + +VOID +ReleaseAttributeContext(PNTFS_ATTR_CONTEXT Context) +{ + ExFreePoolWithTag(Context, TAG_NTFS); +} + + +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) + { + 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); + } + + DPRINT("Ended\n"); + return NULL; +} + + NTSTATUS -NtfsOpenMft(PDEVICE_EXTENSION Vcb) -{ -// PVOID Bitmap; - PFILE_RECORD_HEADER MftRecord; - PFILE_RECORD_HEADER FileRecord; -// PATTRIBUTE Attribute; -// PATTRIBUTE AttrData; -// PRESIDENT_ATTRIBUTE ResAttr; - +FindAttribute(PDEVICE_EXTENSION Vcb, + PFILE_RECORD_HEADER MftRecord, + ULONG Type, + PUNICODE_STRING Name, + PNTFS_ATTR_CONTEXT * AttrCtx) +{ + PNTFS_ATTR_RECORD AttrRecord; + PNTFS_ATTR_RECORD AttrRecordEnd; + + DPRINT("NtfsFindAttribute(%p, %p, %u, %s)\n", Vcb, MftRecord, Type, Name); + + AttrRecord = (PNTFS_ATTR_RECORD)((PCHAR)MftRecord + MftRecord->AttributeOffset); + AttrRecordEnd = (PNTFS_ATTR_RECORD)((PCHAR)MftRecord + Vcb->NtfsInfo.BytesPerFileRecord); + + *AttrCtx = FindAttributeHelper(Vcb, AttrRecord, AttrRecordEnd, Type, Name->Buffer, Name->Length); + if (*AttrCtx == NULL) + { + return STATUS_OBJECT_NAME_NOT_FOUND; + } + + return STATUS_SUCCESS; +} + + +ULONG +AttributeAllocatedLength(PNTFS_ATTR_RECORD AttrRecord) +{ + if (AttrRecord->IsNonResident) + return AttrRecord->NonResident.AllocatedSize; + else + return AttrRecord->Resident.ValueLength; +} + + +ULONGLONG +AttributeDataLength(PNTFS_ATTR_RECORD AttrRecord) +{ + if (AttrRecord->IsNonResident) + return AttrRecord->NonResident.DataSize; + else + return AttrRecord->Resident.ValueLength; +} + + +ULONG +ReadAttribute(PDEVICE_EXTENSION Vcb, + PNTFS_ATTR_CONTEXT Context, + ULONGLONG Offset, + PCHAR Buffer, + ULONG Length) +{ + ULONGLONG LastLCN; + PUCHAR DataRun; + LONGLONG DataRunOffset; + ULONGLONG DataRunLength; + LONGLONG DataRunStartLCN; + ULONGLONG CurrentOffset; + ULONG ReadLength; + ULONG AlreadyRead; 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) - { - return STATUS_INSUFFICIENT_RESOURCES; - } - - 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)) - { - DPRINT("\nFile %lu\n\n", i); - - /* Enumerate attributtes */ - NtfsDumpFileAttributes (FileRecord); - DbgPrint("\n\n"); - } - } - - 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) - { - return Attribute; - } - - Attribute = (PATTRIBUTE)((ULONG_PTR)Attribute + Attribute->Length); - } - - 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; -} - - -VOID -ReadAttribute(PATTRIBUTE attr, - PVOID buffer, - PDEVICE_EXTENSION Vcb, - PDEVICE_OBJECT DeviceObject) -{ - PNONRESIDENT_ATTRIBUTE NresAttr = (PNONRESIDENT_ATTRIBUTE)attr; - - UNREFERENCED_PARAMETER(DeviceObject); - - if (attr->Nonresident == FALSE) - { - memcpy(buffer, - (PVOID)((ULONG_PTR)attr + ((PRESIDENT_ATTRIBUTE)attr)->ValueOffset), - ((PRESIDENT_ATTRIBUTE)attr)->ValueLength); - } - - ReadExternalAttribute(Vcb, - NresAttr, - 0, - (ULONG)(NresAttr->LastVcn) + 1, - buffer); + + if (!Context->Record.IsNonResident) + { + 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, - ULONG index, - PFILE_RECORD_HEADER file, - PFILE_RECORD_HEADER Mft) -{ - 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; - - p = ExAllocatePoolWithTag(NonPagedPool, - clusters * Vcb->NtfsInfo.BytesPerCluster, - TAG_NTFS); - - ReadVCN (Vcb, Mft, AttributeData, vcn, clusters, p); - - memcpy(file, - (PVOID)((ULONG_PTR)p + n * BytesPerFileRecord), - BytesPerFileRecord); - - ExFreePool(p); - - FixupUpdateSequenceArray(file); + 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; -} - - -VOID -ReadExternalAttribute(PDEVICE_EXTENSION Vcb, - PNONRESIDENT_ATTRIBUTE NresAttr, - ULONGLONG vcn, - ULONG count, - PVOID buffer) -{ - 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; - } -} - - -VOID -ReadVCN(PDEVICE_EXTENSION Vcb, - PFILE_RECORD_HEADER file, - ATTRIBUTE_TYPE type, - ULONGLONG vcn, - ULONG count, - PVOID buffer) -{ - 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 0 -BOOL bitset(PUCHAR bitmap, ULONG i) -{ - return (bitmap[i>>3] & (1 << (i & 7))) !=0; -} -#endif - - -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++) - { - sector[255] = usa[i]; - sector += 256; - } }
@@ -323,4 +459,240 @@ 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 */
Modified: trunk/reactos/drivers/filesystems/ntfs/ntfs.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/filesystems/ntfs/nt... ============================================================================== --- trunk/reactos/drivers/filesystems/ntfs/ntfs.h [iso-8859-1] (original) +++ trunk/reactos/drivers/filesystems/ntfs/ntfs.h [iso-8859-1] Fri Sep 26 13:57:29 2014 @@ -86,7 +86,6 @@ ULONG Size; } NTFSIDENTIFIER, *PNTFSIDENTIFIER;
- typedef struct { NTFSIDENTIFIER Identifier; @@ -101,6 +100,8 @@ PDEVICE_OBJECT StorageDevice; PFILE_OBJECT StreamFileObject;
+ struct _NTFS_ATTR_CONTEXT* MFTContext; + struct _FILE_RECORD_HEADER* MasterFileTable; struct _FCB *VolumeFcb;
NTFS_INFO NtfsInfo; @@ -186,8 +187,22 @@ 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 @@ -200,6 +215,14 @@ #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 @@ #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 { - 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 { @@ -337,6 +359,28 @@
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; UCHAR MajorVersion; UCHAR MinorVersion; @@ -357,6 +401,16 @@ 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 @@ //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 @@
/* mft.c */ -NTSTATUS -NtfsOpenMft(PDEVICE_EXTENSION Vcb); - - -VOID -ReadAttribute(PATTRIBUTE attr, - PVOID buffer, - PDEVICE_EXTENSION Vcb, - PDEVICE_OBJECT DeviceObject); - ULONG -AttributeDataLength(PATTRIBUTE attr); +ReadAttribute(PDEVICE_EXTENSION Vcb, + PNTFS_ATTR_CONTEXT Context, + ULONGLONG Offset, + PCHAR Buffer, + ULONG Length); + +ULONGLONG +AttributeDataLength(PNTFS_ATTR_RECORD AttrRecord);
ULONG -AttributeAllocatedLength(PATTRIBUTE Attribute); +AttributeAllocatedLength(PNTFS_ATTR_RECORD AttrRecord);
NTSTATUS ReadFileRecord(PDEVICE_EXTENSION Vcb, - ULONG index, - PFILE_RECORD_HEADER file, - PFILE_RECORD_HEADER Mft); - -PATTRIBUTE -FindAttribute(PFILE_RECORD_HEADER file, - ATTRIBUTE_TYPE type, - PWSTR name); - -ULONG -AttributeLengthAllocated(PATTRIBUTE attr); + ULONGLONG index, + PFILE_RECORD_HEADER file); + +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 @@ 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 @@ PDEVICE_EXTENSION Vcb, PDEVICE_OBJECT DeviceObject);
+NTSTATUS +NtfsLookupFile(PDEVICE_EXTENSION Vcb, + PUNICODE_STRING PathName, + PFILE_RECORD_HEADER *FileRecord, + PNTFS_ATTR_CONTEXT *DataContext);
/* misc.c */