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/a…
==============================================================================
--- 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/f…
==============================================================================
--- 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/m…
==============================================================================
--- 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/n…
==============================================================================
--- 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 */