mirror of
https://github.com/reactos/reactos.git
synced 2025-08-03 19:55:41 +00:00
[freeldr] Rework NTFS filesystem to not be tied to boot filesystem
svn path=/trunk/; revision=43115
This commit is contained in:
parent
9b86293dce
commit
4648a3e59d
2 changed files with 212 additions and 166 deletions
|
@ -26,15 +26,19 @@
|
||||||
#include <freeldr.h>
|
#include <freeldr.h>
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
|
|
||||||
PNTFS_BOOTSECTOR NtfsBootSector;
|
typedef struct _NTFS_VOLUME_INFO
|
||||||
ULONG NtfsClusterSize;
|
{
|
||||||
ULONG NtfsMftRecordSize;
|
NTFS_BOOTSECTOR BootSector;
|
||||||
ULONG NtfsIndexRecordSize;
|
ULONG ClusterSize;
|
||||||
ULONG NtfsDriveNumber;
|
ULONG MftRecordSize;
|
||||||
ULONG NtfsSectorOfClusterZero;
|
ULONG IndexRecordSize;
|
||||||
PNTFS_MFT_RECORD NtfsMasterFileTable;
|
PNTFS_MFT_RECORD MasterFileTable;
|
||||||
/* FIXME: NtfsMFTContext is never freed. */
|
/* FIXME: MFTContext is never freed. */
|
||||||
PNTFS_ATTR_CONTEXT NtfsMFTContext;
|
PNTFS_ATTR_CONTEXT MFTContext;
|
||||||
|
ULONG DeviceId;
|
||||||
|
} NTFS_VOLUME_INFO;
|
||||||
|
|
||||||
|
PNTFS_VOLUME_INFO NtfsVolumes[MAX_FDS];
|
||||||
|
|
||||||
static ULONGLONG NtfsGetAttributeSize(PNTFS_ATTR_RECORD AttrRecord)
|
static ULONGLONG NtfsGetAttributeSize(PNTFS_ATTR_RECORD AttrRecord)
|
||||||
{
|
{
|
||||||
|
@ -123,50 +127,80 @@ static VOID NtfsReleaseAttributeContext(PNTFS_ATTR_CONTEXT Context)
|
||||||
MmHeapFree(Context);
|
MmHeapFree(Context);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: Optimize for multisector reads. */
|
static BOOLEAN NtfsDiskRead(PNTFS_VOLUME_INFO Volume, ULONGLONG Offset, ULONGLONG Length, PCHAR Buffer)
|
||||||
static BOOLEAN NtfsDiskRead(ULONGLONG Offset, ULONGLONG Length, PCHAR Buffer)
|
|
||||||
{
|
{
|
||||||
|
LARGE_INTEGER Position;
|
||||||
|
ULONG Count;
|
||||||
USHORT ReadLength;
|
USHORT ReadLength;
|
||||||
|
LONG ret;
|
||||||
|
|
||||||
DPRINTM(DPRINT_FILESYSTEM, "NtfsDiskRead - Offset: %I64d Length: %I64d\n", Offset, Length);
|
DPRINTM(DPRINT_FILESYSTEM, "NtfsDiskRead - Offset: %I64d Length: %I64d\n", Offset, Length);
|
||||||
RtlZeroMemory((PCHAR)DISKREADBUFFER, 0x1000);
|
|
||||||
|
|
||||||
/* I. Read partial first sector if needed */
|
//
|
||||||
if (Offset % NtfsBootSector->BytesPerSector)
|
// I. Read partial first sector if needed
|
||||||
|
//
|
||||||
|
if (Offset % Volume->BootSector.BytesPerSector)
|
||||||
{
|
{
|
||||||
if (!MachDiskReadLogicalSectors(NtfsDriveNumber, NtfsSectorOfClusterZero + (Offset / NtfsBootSector->BytesPerSector), 1, (PCHAR)DISKREADBUFFER))
|
Position.HighPart = 0;
|
||||||
|
Position.LowPart = Offset & ~(Volume->BootSector.BytesPerSector - 1);
|
||||||
|
ret = ArcSeek(Volume->DeviceId, &Position, SeekAbsolute);
|
||||||
|
if (ret != ESUCCESS)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
ReadLength = min(Length, NtfsBootSector->BytesPerSector - (Offset % NtfsBootSector->BytesPerSector));
|
ReadLength = min(Length, Volume->BootSector.BytesPerSector - (Offset % Volume->BootSector.BytesPerSector));
|
||||||
RtlCopyMemory(Buffer, (PCHAR)DISKREADBUFFER + (Offset % NtfsBootSector->BytesPerSector), ReadLength);
|
ret = ArcRead(Volume->DeviceId, Buffer, ReadLength, &Count);
|
||||||
|
if (ret != ESUCCESS || Count != ReadLength)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Move to unfilled buffer part
|
||||||
|
//
|
||||||
Buffer += ReadLength;
|
Buffer += ReadLength;
|
||||||
Length -= ReadLength;
|
Length -= ReadLength;
|
||||||
Offset += ReadLength;
|
Offset += ReadLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* II. Read all complete 64-sector blocks. */
|
//
|
||||||
while (Length >= (ULONGLONG)64 * (ULONGLONG)NtfsBootSector->BytesPerSector)
|
// II. Read all complete blocks
|
||||||
|
//
|
||||||
|
if (Length >= Volume->BootSector.BytesPerSector)
|
||||||
{
|
{
|
||||||
if (!MachDiskReadLogicalSectors(NtfsDriveNumber, NtfsSectorOfClusterZero + (Offset / NtfsBootSector->BytesPerSector), 64, (PCHAR)DISKREADBUFFER))
|
Position.HighPart = 0;
|
||||||
|
Position.LowPart = Offset;
|
||||||
|
ret = ArcSeek(Volume->DeviceId, &Position, SeekAbsolute);
|
||||||
|
if (ret != ESUCCESS)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
RtlCopyMemory(Buffer, (PCHAR)DISKREADBUFFER, 64 * NtfsBootSector->BytesPerSector);
|
ReadLength = Length & ~(Volume->BootSector.BytesPerSector - 1);
|
||||||
Buffer += 64 * NtfsBootSector->BytesPerSector;
|
ret = ArcRead(Volume->DeviceId, Buffer, ReadLength, &Count);
|
||||||
Length -= 64 * NtfsBootSector->BytesPerSector;
|
if (ret != ESUCCESS || Count != ReadLength)
|
||||||
Offset += 64 * NtfsBootSector->BytesPerSector;
|
return FALSE;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Move to unfilled buffer part
|
||||||
|
//
|
||||||
|
Buffer += ReadLength;
|
||||||
|
Length -= ReadLength;
|
||||||
|
Offset += ReadLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* III. Read the rest of data */
|
//
|
||||||
|
// III. Read the rest of data
|
||||||
|
//
|
||||||
if (Length)
|
if (Length)
|
||||||
{
|
{
|
||||||
ReadLength = ((Length + NtfsBootSector->BytesPerSector - 1) / NtfsBootSector->BytesPerSector);
|
Position.HighPart = 0;
|
||||||
if (!MachDiskReadLogicalSectors(NtfsDriveNumber, NtfsSectorOfClusterZero + (Offset / NtfsBootSector->BytesPerSector), ReadLength, (PCHAR)DISKREADBUFFER))
|
Position.LowPart = Offset;
|
||||||
|
ret = ArcSeek(Volume->DeviceId, &Position, SeekAbsolute);
|
||||||
|
if (ret != ESUCCESS)
|
||||||
|
return FALSE;
|
||||||
|
ret = ArcRead(Volume->DeviceId, Buffer, Length, &Count);
|
||||||
|
if (ret != ESUCCESS || Count != Length)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
RtlCopyMemory(Buffer, (PCHAR)DISKREADBUFFER, Length);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ULONGLONG NtfsReadAttribute(PNTFS_ATTR_CONTEXT Context, ULONGLONG Offset, PCHAR Buffer, ULONGLONG Length)
|
static ULONGLONG NtfsReadAttribute(PNTFS_VOLUME_INFO Volume, PNTFS_ATTR_CONTEXT Context, ULONGLONG Offset, PCHAR Buffer, ULONGLONG Length)
|
||||||
{
|
{
|
||||||
ULONGLONG LastLCN;
|
ULONGLONG LastLCN;
|
||||||
PUCHAR DataRun;
|
PUCHAR DataRun;
|
||||||
|
@ -197,7 +231,7 @@ static ULONGLONG NtfsReadAttribute(PNTFS_ATTR_CONTEXT Context, ULONGLONG Offset,
|
||||||
|
|
||||||
AlreadyRead = 0;
|
AlreadyRead = 0;
|
||||||
|
|
||||||
if(Context->CacheRunOffset <= Offset && Offset < Context->CacheRunOffset + Context->CacheRunLength * NtfsClusterSize)
|
if(Context->CacheRunOffset <= Offset && Offset < Context->CacheRunOffset + Context->CacheRunLength * Volume->ClusterSize)
|
||||||
{
|
{
|
||||||
DataRun = Context->CacheRun;
|
DataRun = Context->CacheRun;
|
||||||
LastLCN = Context->CacheRunLastLCN;
|
LastLCN = Context->CacheRunLastLCN;
|
||||||
|
@ -227,7 +261,7 @@ static ULONGLONG NtfsReadAttribute(PNTFS_ATTR_CONTEXT Context, ULONGLONG Offset,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Offset >= CurrentOffset &&
|
if (Offset >= CurrentOffset &&
|
||||||
Offset < CurrentOffset + (DataRunLength * NtfsClusterSize))
|
Offset < CurrentOffset + (DataRunLength * Volume->ClusterSize))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -237,7 +271,7 @@ static ULONGLONG NtfsReadAttribute(PNTFS_ATTR_CONTEXT Context, ULONGLONG Offset,
|
||||||
return AlreadyRead;
|
return AlreadyRead;
|
||||||
}
|
}
|
||||||
|
|
||||||
CurrentOffset += DataRunLength * NtfsClusterSize;
|
CurrentOffset += DataRunLength * Volume->ClusterSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,18 +279,18 @@ static ULONGLONG NtfsReadAttribute(PNTFS_ATTR_CONTEXT Context, ULONGLONG Offset,
|
||||||
* II. Go through the run list and read the data
|
* II. Go through the run list and read the data
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ReadLength = min(DataRunLength * NtfsClusterSize - (Offset - CurrentOffset), Length);
|
ReadLength = min(DataRunLength * Volume->ClusterSize - (Offset - CurrentOffset), Length);
|
||||||
if (DataRunStartLCN == -1)
|
if (DataRunStartLCN == -1)
|
||||||
RtlZeroMemory(Buffer, ReadLength);
|
RtlZeroMemory(Buffer, ReadLength);
|
||||||
if (NtfsDiskRead(DataRunStartLCN * NtfsClusterSize + Offset - CurrentOffset, ReadLength, Buffer))
|
if (NtfsDiskRead(Volume, DataRunStartLCN * Volume->ClusterSize + Offset - CurrentOffset, ReadLength, Buffer))
|
||||||
{
|
{
|
||||||
Length -= ReadLength;
|
Length -= ReadLength;
|
||||||
Buffer += ReadLength;
|
Buffer += ReadLength;
|
||||||
AlreadyRead += ReadLength;
|
AlreadyRead += ReadLength;
|
||||||
|
|
||||||
if (ReadLength == DataRunLength * NtfsClusterSize - (Offset - CurrentOffset))
|
if (ReadLength == DataRunLength * Volume->ClusterSize - (Offset - CurrentOffset))
|
||||||
{
|
{
|
||||||
CurrentOffset += DataRunLength * NtfsClusterSize;
|
CurrentOffset += DataRunLength * Volume->ClusterSize;
|
||||||
DataRun = NtfsDecodeRun(DataRun, &DataRunOffset, &DataRunLength);
|
DataRun = NtfsDecodeRun(DataRun, &DataRunOffset, &DataRunLength);
|
||||||
if (DataRunLength != (ULONGLONG)-1)
|
if (DataRunLength != (ULONGLONG)-1)
|
||||||
{
|
{
|
||||||
|
@ -272,10 +306,10 @@ static ULONGLONG NtfsReadAttribute(PNTFS_ATTR_CONTEXT Context, ULONGLONG Offset,
|
||||||
|
|
||||||
while (Length > 0)
|
while (Length > 0)
|
||||||
{
|
{
|
||||||
ReadLength = min(DataRunLength * NtfsClusterSize, Length);
|
ReadLength = min(DataRunLength * Volume->ClusterSize, Length);
|
||||||
if (DataRunStartLCN == -1)
|
if (DataRunStartLCN == -1)
|
||||||
RtlZeroMemory(Buffer, ReadLength);
|
RtlZeroMemory(Buffer, ReadLength);
|
||||||
else if (!NtfsDiskRead(DataRunStartLCN * NtfsClusterSize, ReadLength, Buffer))
|
else if (!NtfsDiskRead(Volume, DataRunStartLCN * Volume->ClusterSize, ReadLength, Buffer))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
Length -= ReadLength;
|
Length -= ReadLength;
|
||||||
|
@ -283,7 +317,7 @@ static ULONGLONG NtfsReadAttribute(PNTFS_ATTR_CONTEXT Context, ULONGLONG Offset,
|
||||||
AlreadyRead += ReadLength;
|
AlreadyRead += ReadLength;
|
||||||
|
|
||||||
/* We finished this request, but there still data in this data run. */
|
/* We finished this request, but there still data in this data run. */
|
||||||
if (Length == 0 && ReadLength != DataRunLength * NtfsClusterSize)
|
if (Length == 0 && ReadLength != DataRunLength * Volume->ClusterSize)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -292,7 +326,7 @@ static ULONGLONG NtfsReadAttribute(PNTFS_ATTR_CONTEXT Context, ULONGLONG Offset,
|
||||||
|
|
||||||
if (*DataRun == 0)
|
if (*DataRun == 0)
|
||||||
break;
|
break;
|
||||||
CurrentOffset += DataRunLength * NtfsClusterSize;
|
CurrentOffset += DataRunLength * Volume->ClusterSize;
|
||||||
DataRun = NtfsDecodeRun(DataRun, &DataRunOffset, &DataRunLength);
|
DataRun = NtfsDecodeRun(DataRun, &DataRunOffset, &DataRunLength);
|
||||||
if (DataRunOffset != -1)
|
if (DataRunOffset != -1)
|
||||||
{
|
{
|
||||||
|
@ -319,7 +353,7 @@ static ULONGLONG NtfsReadAttribute(PNTFS_ATTR_CONTEXT Context, ULONGLONG Offset,
|
||||||
return AlreadyRead;
|
return AlreadyRead;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PNTFS_ATTR_CONTEXT NtfsFindAttributeHelper(PNTFS_ATTR_RECORD AttrRecord, PNTFS_ATTR_RECORD AttrRecordEnd, ULONG Type, const WCHAR *Name, ULONG NameLength)
|
static PNTFS_ATTR_CONTEXT NtfsFindAttributeHelper(PNTFS_VOLUME_INFO Volume, PNTFS_ATTR_RECORD AttrRecord, PNTFS_ATTR_RECORD AttrRecordEnd, ULONG Type, const WCHAR *Name, ULONG NameLength)
|
||||||
{
|
{
|
||||||
while (AttrRecord < AttrRecordEnd)
|
while (AttrRecord < AttrRecordEnd)
|
||||||
{
|
{
|
||||||
|
@ -343,9 +377,9 @@ static PNTFS_ATTR_CONTEXT NtfsFindAttributeHelper(PNTFS_ATTR_RECORD AttrRecord,
|
||||||
ListAttrRecord = (PNTFS_ATTR_RECORD)ListBuffer;
|
ListAttrRecord = (PNTFS_ATTR_RECORD)ListBuffer;
|
||||||
ListAttrRecordEnd = (PNTFS_ATTR_RECORD)((PCHAR)ListBuffer + ListSize);
|
ListAttrRecordEnd = (PNTFS_ATTR_RECORD)((PCHAR)ListBuffer + ListSize);
|
||||||
|
|
||||||
if (NtfsReadAttribute(ListContext, 0, ListBuffer, ListSize) == ListSize)
|
if (NtfsReadAttribute(Volume, ListContext, 0, ListBuffer, ListSize) == ListSize)
|
||||||
{
|
{
|
||||||
Context = NtfsFindAttributeHelper(ListAttrRecord, ListAttrRecordEnd,
|
Context = NtfsFindAttributeHelper(Volume, ListAttrRecord, ListAttrRecordEnd,
|
||||||
Type, Name, NameLength);
|
Type, Name, NameLength);
|
||||||
|
|
||||||
NtfsReleaseAttributeContext(ListContext);
|
NtfsReleaseAttributeContext(ListContext);
|
||||||
|
@ -371,27 +405,29 @@ static PNTFS_ATTR_CONTEXT NtfsFindAttributeHelper(PNTFS_ATTR_RECORD AttrRecord,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (AttrRecord->Length == 0)
|
||||||
|
return NULL;
|
||||||
AttrRecord = (PNTFS_ATTR_RECORD)((PCHAR)AttrRecord + AttrRecord->Length);
|
AttrRecord = (PNTFS_ATTR_RECORD)((PCHAR)AttrRecord + AttrRecord->Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PNTFS_ATTR_CONTEXT NtfsFindAttribute(PNTFS_MFT_RECORD MftRecord, ULONG Type, const WCHAR *Name)
|
static PNTFS_ATTR_CONTEXT NtfsFindAttribute(PNTFS_VOLUME_INFO Volume, PNTFS_MFT_RECORD MftRecord, ULONG Type, const WCHAR *Name)
|
||||||
{
|
{
|
||||||
PNTFS_ATTR_RECORD AttrRecord;
|
PNTFS_ATTR_RECORD AttrRecord;
|
||||||
PNTFS_ATTR_RECORD AttrRecordEnd;
|
PNTFS_ATTR_RECORD AttrRecordEnd;
|
||||||
ULONG NameLength;
|
ULONG NameLength;
|
||||||
|
|
||||||
AttrRecord = (PNTFS_ATTR_RECORD)((PCHAR)MftRecord + MftRecord->AttributesOffset);
|
AttrRecord = (PNTFS_ATTR_RECORD)((PCHAR)MftRecord + MftRecord->AttributesOffset);
|
||||||
AttrRecordEnd = (PNTFS_ATTR_RECORD)((PCHAR)MftRecord + NtfsMftRecordSize);
|
AttrRecordEnd = (PNTFS_ATTR_RECORD)((PCHAR)MftRecord + Volume->MftRecordSize);
|
||||||
for (NameLength = 0; Name[NameLength] != 0; NameLength++)
|
for (NameLength = 0; Name[NameLength] != 0; NameLength++)
|
||||||
;
|
;
|
||||||
|
|
||||||
return NtfsFindAttributeHelper(AttrRecord, AttrRecordEnd, Type, Name, NameLength);
|
return NtfsFindAttributeHelper(Volume, AttrRecord, AttrRecordEnd, Type, Name, NameLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
static BOOLEAN NtfsFixupRecord(PNTFS_RECORD Record)
|
static BOOLEAN NtfsFixupRecord(PNTFS_VOLUME_INFO Volume, PNTFS_RECORD Record)
|
||||||
{
|
{
|
||||||
USHORT *USA;
|
USHORT *USA;
|
||||||
USHORT USANumber;
|
USHORT USANumber;
|
||||||
|
@ -401,30 +437,30 @@ static BOOLEAN NtfsFixupRecord(PNTFS_RECORD Record)
|
||||||
USA = (USHORT*)((PCHAR)Record + Record->USAOffset);
|
USA = (USHORT*)((PCHAR)Record + Record->USAOffset);
|
||||||
USANumber = *(USA++);
|
USANumber = *(USA++);
|
||||||
USACount = Record->USACount - 1; /* Exclude the USA Number. */
|
USACount = Record->USACount - 1; /* Exclude the USA Number. */
|
||||||
Block = (USHORT*)((PCHAR)Record + NtfsBootSector->BytesPerSector - 2);
|
Block = (USHORT*)((PCHAR)Record + Volume->BootSector.BytesPerSector - 2);
|
||||||
|
|
||||||
while (USACount)
|
while (USACount)
|
||||||
{
|
{
|
||||||
if (*Block != USANumber)
|
if (*Block != USANumber)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
*Block = *(USA++);
|
*Block = *(USA++);
|
||||||
Block = (USHORT*)((PCHAR)Block + NtfsBootSector->BytesPerSector);
|
Block = (USHORT*)((PCHAR)Block + Volume->BootSector.BytesPerSector);
|
||||||
USACount--;
|
USACount--;
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static BOOLEAN NtfsReadMftRecord(ULONG MFTIndex, PNTFS_MFT_RECORD Buffer)
|
static BOOLEAN NtfsReadMftRecord(PNTFS_VOLUME_INFO Volume, ULONG MFTIndex, PNTFS_MFT_RECORD Buffer)
|
||||||
{
|
{
|
||||||
ULONGLONG BytesRead;
|
ULONGLONG BytesRead;
|
||||||
|
|
||||||
BytesRead = NtfsReadAttribute(NtfsMFTContext, MFTIndex * NtfsMftRecordSize, (PCHAR)Buffer, NtfsMftRecordSize);
|
BytesRead = NtfsReadAttribute(Volume, Volume->MFTContext, MFTIndex * Volume->MftRecordSize, (PCHAR)Buffer, Volume->MftRecordSize);
|
||||||
if (BytesRead != NtfsMftRecordSize)
|
if (BytesRead != Volume->MftRecordSize)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
/* Apply update sequence array fixups. */
|
/* Apply update sequence array fixups. */
|
||||||
return NtfsFixupRecord((PNTFS_RECORD)Buffer);
|
return NtfsFixupRecord(Volume, (PNTFS_RECORD)Buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DBG
|
#if DBG
|
||||||
|
@ -479,7 +515,7 @@ static BOOLEAN NtfsCompareFileName(PCHAR FileName, PNTFS_INDEX_ENTRY IndexEntry)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static BOOLEAN NtfsFindMftRecord(ULONG MFTIndex, PCHAR FileName, ULONG *OutMFTIndex)
|
static BOOLEAN NtfsFindMftRecord(PNTFS_VOLUME_INFO Volume, ULONG MFTIndex, PCHAR FileName, ULONG *OutMFTIndex)
|
||||||
{
|
{
|
||||||
PNTFS_MFT_RECORD MftRecord;
|
PNTFS_MFT_RECORD MftRecord;
|
||||||
ULONG Magic;
|
ULONG Magic;
|
||||||
|
@ -495,38 +531,38 @@ static BOOLEAN NtfsFindMftRecord(ULONG MFTIndex, PCHAR FileName, ULONG *OutMFTIn
|
||||||
ULONG RecordOffset;
|
ULONG RecordOffset;
|
||||||
ULONG IndexBlockSize;
|
ULONG IndexBlockSize;
|
||||||
|
|
||||||
MftRecord = MmHeapAlloc(NtfsMftRecordSize);
|
MftRecord = MmHeapAlloc(Volume->MftRecordSize);
|
||||||
if (MftRecord == NULL)
|
if (MftRecord == NULL)
|
||||||
{
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NtfsReadMftRecord(MFTIndex, MftRecord))
|
if (NtfsReadMftRecord(Volume, MFTIndex, MftRecord))
|
||||||
{
|
{
|
||||||
Magic = MftRecord->Magic;
|
Magic = MftRecord->Magic;
|
||||||
|
|
||||||
IndexRootCtx = NtfsFindAttribute(MftRecord, NTFS_ATTR_TYPE_INDEX_ROOT, L"$I30");
|
IndexRootCtx = NtfsFindAttribute(Volume, MftRecord, NTFS_ATTR_TYPE_INDEX_ROOT, L"$I30");
|
||||||
if (IndexRootCtx == NULL)
|
if (IndexRootCtx == NULL)
|
||||||
{
|
{
|
||||||
MmHeapFree(MftRecord);
|
MmHeapFree(MftRecord);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
IndexRecord = MmHeapAlloc(NtfsIndexRecordSize);
|
IndexRecord = MmHeapAlloc(Volume->IndexRecordSize);
|
||||||
if (IndexRecord == NULL)
|
if (IndexRecord == NULL)
|
||||||
{
|
{
|
||||||
MmHeapFree(MftRecord);
|
MmHeapFree(MftRecord);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
NtfsReadAttribute(IndexRootCtx, 0, IndexRecord, NtfsIndexRecordSize);
|
NtfsReadAttribute(Volume, IndexRootCtx, 0, IndexRecord, Volume->IndexRecordSize);
|
||||||
IndexRoot = (PNTFS_INDEX_ROOT)IndexRecord;
|
IndexRoot = (PNTFS_INDEX_ROOT)IndexRecord;
|
||||||
IndexEntry = (PNTFS_INDEX_ENTRY)((PCHAR)&IndexRoot->IndexHeader + IndexRoot->IndexHeader.EntriesOffset);
|
IndexEntry = (PNTFS_INDEX_ENTRY)((PCHAR)&IndexRoot->IndexHeader + IndexRoot->IndexHeader.EntriesOffset);
|
||||||
/* Index root is always resident. */
|
/* Index root is always resident. */
|
||||||
IndexEntryEnd = (PNTFS_INDEX_ENTRY)(IndexRecord + IndexRootCtx->Record.Resident.ValueLength);
|
IndexEntryEnd = (PNTFS_INDEX_ENTRY)(IndexRecord + IndexRootCtx->Record.Resident.ValueLength);
|
||||||
NtfsReleaseAttributeContext(IndexRootCtx);
|
NtfsReleaseAttributeContext(IndexRootCtx);
|
||||||
|
|
||||||
DPRINTM(DPRINT_FILESYSTEM, "NtfsIndexRecordSize: %x IndexBlockSize: %x\n", NtfsIndexRecordSize, IndexRoot->IndexBlockSize);
|
DPRINTM(DPRINT_FILESYSTEM, "IndexRecordSize: %x IndexBlockSize: %x\n", Volume->IndexRecordSize, IndexRoot->IndexBlockSize);
|
||||||
|
|
||||||
while (IndexEntry < IndexEntryEnd &&
|
while (IndexEntry < IndexEntryEnd &&
|
||||||
!(IndexEntry->Flags & NTFS_INDEX_ENTRY_END))
|
!(IndexEntry->Flags & NTFS_INDEX_ENTRY_END))
|
||||||
|
@ -547,7 +583,7 @@ static BOOLEAN NtfsFindMftRecord(ULONG MFTIndex, PCHAR FileName, ULONG *OutMFTIn
|
||||||
|
|
||||||
IndexBlockSize = IndexRoot->IndexBlockSize;
|
IndexBlockSize = IndexRoot->IndexBlockSize;
|
||||||
|
|
||||||
IndexBitmapCtx = NtfsFindAttribute(MftRecord, NTFS_ATTR_TYPE_BITMAP, L"$I30");
|
IndexBitmapCtx = NtfsFindAttribute(Volume, MftRecord, NTFS_ATTR_TYPE_BITMAP, L"$I30");
|
||||||
if (IndexBitmapCtx == NULL)
|
if (IndexBitmapCtx == NULL)
|
||||||
{
|
{
|
||||||
DPRINTM(DPRINT_FILESYSTEM, "Corrupted filesystem!\n");
|
DPRINTM(DPRINT_FILESYSTEM, "Corrupted filesystem!\n");
|
||||||
|
@ -563,10 +599,10 @@ static BOOLEAN NtfsFindMftRecord(ULONG MFTIndex, PCHAR FileName, ULONG *OutMFTIn
|
||||||
MmHeapFree(MftRecord);
|
MmHeapFree(MftRecord);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
NtfsReadAttribute(IndexBitmapCtx, 0, BitmapData, BitmapDataSize);
|
NtfsReadAttribute(Volume, IndexBitmapCtx, 0, BitmapData, BitmapDataSize);
|
||||||
NtfsReleaseAttributeContext(IndexBitmapCtx);
|
NtfsReleaseAttributeContext(IndexBitmapCtx);
|
||||||
|
|
||||||
IndexAllocationCtx = NtfsFindAttribute(MftRecord, NTFS_ATTR_TYPE_INDEX_ALLOCATION, L"$I30");
|
IndexAllocationCtx = NtfsFindAttribute(Volume, MftRecord, NTFS_ATTR_TYPE_INDEX_ALLOCATION, L"$I30");
|
||||||
if (IndexAllocationCtx == NULL)
|
if (IndexAllocationCtx == NULL)
|
||||||
{
|
{
|
||||||
DPRINTM(DPRINT_FILESYSTEM, "Corrupted filesystem!\n");
|
DPRINTM(DPRINT_FILESYSTEM, "Corrupted filesystem!\n");
|
||||||
|
@ -596,9 +632,9 @@ static BOOLEAN NtfsFindMftRecord(ULONG MFTIndex, PCHAR FileName, ULONG *OutMFTIn
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
NtfsReadAttribute(IndexAllocationCtx, RecordOffset, IndexRecord, IndexBlockSize);
|
NtfsReadAttribute(Volume, IndexAllocationCtx, RecordOffset, IndexRecord, IndexBlockSize);
|
||||||
|
|
||||||
if (!NtfsFixupRecord((PNTFS_RECORD)IndexRecord))
|
if (!NtfsFixupRecord(Volume, (PNTFS_RECORD)IndexRecord))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -641,7 +677,7 @@ static BOOLEAN NtfsFindMftRecord(ULONG MFTIndex, PCHAR FileName, ULONG *OutMFTIn
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static BOOLEAN NtfsLookupFile(PCSTR FileName, PNTFS_MFT_RECORD MftRecord, PNTFS_ATTR_CONTEXT *DataContext)
|
static BOOLEAN NtfsLookupFile(PNTFS_VOLUME_INFO Volume, PCSTR FileName, PNTFS_MFT_RECORD MftRecord, PNTFS_ATTR_CONTEXT *DataContext)
|
||||||
{
|
{
|
||||||
ULONG NumberOfPathParts;
|
ULONG NumberOfPathParts;
|
||||||
CHAR PathPart[261];
|
CHAR PathPart[261];
|
||||||
|
@ -661,7 +697,7 @@ static BOOLEAN NtfsLookupFile(PCSTR FileName, PNTFS_MFT_RECORD MftRecord, PNTFS_
|
||||||
FileName++;
|
FileName++;
|
||||||
|
|
||||||
DPRINTM(DPRINT_FILESYSTEM, "- Lookup: %s\n", PathPart);
|
DPRINTM(DPRINT_FILESYSTEM, "- Lookup: %s\n", PathPart);
|
||||||
if (!NtfsFindMftRecord(CurrentMFTIndex, PathPart, &CurrentMFTIndex))
|
if (!NtfsFindMftRecord(Volume, CurrentMFTIndex, PathPart, &CurrentMFTIndex))
|
||||||
{
|
{
|
||||||
DPRINTM(DPRINT_FILESYSTEM, "- Failed\n");
|
DPRINTM(DPRINT_FILESYSTEM, "- Failed\n");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
@ -669,13 +705,13 @@ static BOOLEAN NtfsLookupFile(PCSTR FileName, PNTFS_MFT_RECORD MftRecord, PNTFS_
|
||||||
DPRINTM(DPRINT_FILESYSTEM, "- Lookup: %x\n", CurrentMFTIndex);
|
DPRINTM(DPRINT_FILESYSTEM, "- Lookup: %x\n", CurrentMFTIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!NtfsReadMftRecord(CurrentMFTIndex, MftRecord))
|
if (!NtfsReadMftRecord(Volume, CurrentMFTIndex, MftRecord))
|
||||||
{
|
{
|
||||||
DPRINTM(DPRINT_FILESYSTEM, "NtfsLookupFile: Can't read MFT record\n");
|
DPRINTM(DPRINT_FILESYSTEM, "NtfsLookupFile: Can't read MFT record\n");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
*DataContext = NtfsFindAttribute(MftRecord, NTFS_ATTR_TYPE_DATA, L"");
|
*DataContext = NtfsFindAttribute(Volume, MftRecord, NTFS_ATTR_TYPE_DATA, L"");
|
||||||
if (*DataContext == NULL)
|
if (*DataContext == NULL)
|
||||||
{
|
{
|
||||||
DPRINTM(DPRINT_FILESYSTEM, "NtfsLookupFile: Can't find data attribute\n");
|
DPRINTM(DPRINT_FILESYSTEM, "NtfsLookupFile: Can't find data attribute\n");
|
||||||
|
@ -685,81 +721,6 @@ static BOOLEAN NtfsLookupFile(PCSTR FileName, PNTFS_MFT_RECORD MftRecord, PNTFS_
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOLEAN NtfsOpenVolume(UCHAR DriveNumber, ULONGLONG VolumeStartSector, ULONGLONG PartitionSectorCount)
|
|
||||||
{
|
|
||||||
NtfsBootSector = (PNTFS_BOOTSECTOR)DISKREADBUFFER;
|
|
||||||
|
|
||||||
DPRINTM(DPRINT_FILESYSTEM, "NtfsOpenVolume() DriveNumber = 0x%x VolumeStartSector = 0x%x\n", DriveNumber, VolumeStartSector);
|
|
||||||
|
|
||||||
if (!MachDiskReadLogicalSectors(DriveNumber, VolumeStartSector, 1, (PCHAR)DISKREADBUFFER))
|
|
||||||
{
|
|
||||||
FileSystemError("Failed to read the boot sector.");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!RtlEqualMemory(NtfsBootSector->SystemId, "NTFS", 4))
|
|
||||||
{
|
|
||||||
FileSystemError("Invalid NTFS signature.");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
NtfsBootSector = MmHeapAlloc(NtfsBootSector->BytesPerSector);
|
|
||||||
if (NtfsBootSector == NULL)
|
|
||||||
{
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
RtlCopyMemory(NtfsBootSector, (PCHAR)DISKREADBUFFER, ((PNTFS_BOOTSECTOR)DISKREADBUFFER)->BytesPerSector);
|
|
||||||
|
|
||||||
NtfsClusterSize = NtfsBootSector->SectorsPerCluster * NtfsBootSector->BytesPerSector;
|
|
||||||
if (NtfsBootSector->ClustersPerMftRecord > 0)
|
|
||||||
NtfsMftRecordSize = NtfsBootSector->ClustersPerMftRecord * NtfsClusterSize;
|
|
||||||
else
|
|
||||||
NtfsMftRecordSize = 1 << (-NtfsBootSector->ClustersPerMftRecord);
|
|
||||||
if (NtfsBootSector->ClustersPerIndexRecord > 0)
|
|
||||||
NtfsIndexRecordSize = NtfsBootSector->ClustersPerIndexRecord * NtfsClusterSize;
|
|
||||||
else
|
|
||||||
NtfsIndexRecordSize = 1 << (-NtfsBootSector->ClustersPerIndexRecord);
|
|
||||||
|
|
||||||
DPRINTM(DPRINT_FILESYSTEM, "NtfsClusterSize: 0x%x\n", NtfsClusterSize);
|
|
||||||
DPRINTM(DPRINT_FILESYSTEM, "ClustersPerMftRecord: %d\n", NtfsBootSector->ClustersPerMftRecord);
|
|
||||||
DPRINTM(DPRINT_FILESYSTEM, "ClustersPerIndexRecord: %d\n", NtfsBootSector->ClustersPerIndexRecord);
|
|
||||||
DPRINTM(DPRINT_FILESYSTEM, "NtfsMftRecordSize: 0x%x\n", NtfsMftRecordSize);
|
|
||||||
DPRINTM(DPRINT_FILESYSTEM, "NtfsIndexRecordSize: 0x%x\n", NtfsIndexRecordSize);
|
|
||||||
|
|
||||||
NtfsDriveNumber = DriveNumber;
|
|
||||||
NtfsSectorOfClusterZero = VolumeStartSector;
|
|
||||||
|
|
||||||
DPRINTM(DPRINT_FILESYSTEM, "Reading MFT index...\n");
|
|
||||||
if (!MachDiskReadLogicalSectors(DriveNumber,
|
|
||||||
NtfsSectorOfClusterZero +
|
|
||||||
(NtfsBootSector->MftLocation * NtfsBootSector->SectorsPerCluster),
|
|
||||||
NtfsMftRecordSize / NtfsBootSector->BytesPerSector, (PCHAR)DISKREADBUFFER))
|
|
||||||
{
|
|
||||||
FileSystemError("Failed to read the Master File Table record.");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
NtfsMasterFileTable = MmHeapAlloc(NtfsMftRecordSize);
|
|
||||||
if (NtfsMasterFileTable == NULL)
|
|
||||||
{
|
|
||||||
MmHeapFree(NtfsBootSector);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
RtlCopyMemory(NtfsMasterFileTable, (PCHAR)DISKREADBUFFER, NtfsMftRecordSize);
|
|
||||||
|
|
||||||
DPRINTM(DPRINT_FILESYSTEM, "Searching for DATA attribute...\n");
|
|
||||||
NtfsMFTContext = NtfsFindAttribute(NtfsMasterFileTable, NTFS_ATTR_TYPE_DATA, L"");
|
|
||||||
if (NtfsMFTContext == NULL)
|
|
||||||
{
|
|
||||||
FileSystemError("Can't find data attribute for Master File Table.");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
LONG NtfsClose(ULONG FileId)
|
LONG NtfsClose(ULONG FileId)
|
||||||
{
|
{
|
||||||
PNTFS_FILE_HANDLE FileHandle = FsGetDeviceSpecific(FileId);
|
PNTFS_FILE_HANDLE FileHandle = FsGetDeviceSpecific(FileId);
|
||||||
|
@ -788,6 +749,7 @@ LONG NtfsGetFileInformation(ULONG FileId, FILEINFORMATION* Information)
|
||||||
|
|
||||||
LONG NtfsOpen(CHAR* Path, OPENMODE OpenMode, ULONG* FileId)
|
LONG NtfsOpen(CHAR* Path, OPENMODE OpenMode, ULONG* FileId)
|
||||||
{
|
{
|
||||||
|
PNTFS_VOLUME_INFO Volume;
|
||||||
PNTFS_FILE_HANDLE FileHandle;
|
PNTFS_FILE_HANDLE FileHandle;
|
||||||
PNTFS_MFT_RECORD MftRecord;
|
PNTFS_MFT_RECORD MftRecord;
|
||||||
ULONG DeviceId;
|
ULONG DeviceId;
|
||||||
|
@ -802,24 +764,26 @@ LONG NtfsOpen(CHAR* Path, OPENMODE OpenMode, ULONG* FileId)
|
||||||
// Get underlying device
|
// Get underlying device
|
||||||
//
|
//
|
||||||
DeviceId = FsGetDeviceId(*FileId);
|
DeviceId = FsGetDeviceId(*FileId);
|
||||||
|
Volume = NtfsVolumes[DeviceId];
|
||||||
|
|
||||||
DPRINTM(DPRINT_FILESYSTEM, "NtfsOpen() FileName = %s\n", Path);
|
DPRINTM(DPRINT_FILESYSTEM, "NtfsOpen() FileName = %s\n", Path);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Allocate file structure
|
// Allocate file structure
|
||||||
//
|
//
|
||||||
FileHandle = MmHeapAlloc(sizeof(NTFS_FILE_HANDLE) + NtfsMftRecordSize);
|
FileHandle = MmHeapAlloc(sizeof(NTFS_FILE_HANDLE) + Volume->MftRecordSize);
|
||||||
if (!FileHandle)
|
if (!FileHandle)
|
||||||
{
|
{
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
}
|
}
|
||||||
RtlZeroMemory(FileHandle, sizeof(NTFS_FILE_HANDLE) + NtfsMftRecordSize);
|
RtlZeroMemory(FileHandle, sizeof(NTFS_FILE_HANDLE) + Volume->MftRecordSize);
|
||||||
|
FileHandle->Volume = Volume;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Search file entry
|
// Search file entry
|
||||||
//
|
//
|
||||||
MftRecord = (PNTFS_MFT_RECORD)(FileHandle + 1);
|
MftRecord = (PNTFS_MFT_RECORD)(FileHandle + 1);
|
||||||
if (!NtfsLookupFile(Path, MftRecord, &FileHandle->DataContext))
|
if (!NtfsLookupFile(Volume, Path, MftRecord, &FileHandle->DataContext))
|
||||||
{
|
{
|
||||||
MmHeapFree(FileHandle);
|
MmHeapFree(FileHandle);
|
||||||
return ENOENT;
|
return ENOENT;
|
||||||
|
@ -836,7 +800,7 @@ LONG NtfsRead(ULONG FileId, VOID* Buffer, ULONG N, ULONG* Count)
|
||||||
//
|
//
|
||||||
// Read file
|
// Read file
|
||||||
//
|
//
|
||||||
BytesRead64 = NtfsReadAttribute(FileHandle->DataContext, FileHandle->Offset, Buffer, N);
|
BytesRead64 = NtfsReadAttribute(FileHandle->Volume, FileHandle->DataContext, FileHandle->Offset, Buffer, N);
|
||||||
*Count = (ULONG)BytesRead64;
|
*Count = (ULONG)BytesRead64;
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -876,11 +840,19 @@ const DEVVTBL NtfsFuncTable =
|
||||||
|
|
||||||
const DEVVTBL* NtfsMount(ULONG DeviceId)
|
const DEVVTBL* NtfsMount(ULONG DeviceId)
|
||||||
{
|
{
|
||||||
NTFS_BOOTSECTOR BootSector;
|
PNTFS_VOLUME_INFO Volume;
|
||||||
LARGE_INTEGER Position;
|
LARGE_INTEGER Position;
|
||||||
ULONG Count;
|
ULONG Count;
|
||||||
LONG ret;
|
LONG ret;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Allocate data for volume information
|
||||||
|
//
|
||||||
|
Volume = MmHeapAlloc(sizeof(NTFS_VOLUME_INFO));
|
||||||
|
if (!Volume)
|
||||||
|
return NULL;
|
||||||
|
RtlZeroMemory(Volume, sizeof(NTFS_VOLUME_INFO));
|
||||||
|
|
||||||
//
|
//
|
||||||
// Read the BootSector
|
// Read the BootSector
|
||||||
//
|
//
|
||||||
|
@ -888,28 +860,99 @@ const DEVVTBL* NtfsMount(ULONG DeviceId)
|
||||||
Position.LowPart = 0;
|
Position.LowPart = 0;
|
||||||
ret = ArcSeek(DeviceId, &Position, SeekAbsolute);
|
ret = ArcSeek(DeviceId, &Position, SeekAbsolute);
|
||||||
if (ret != ESUCCESS)
|
if (ret != ESUCCESS)
|
||||||
|
{
|
||||||
|
MmHeapFree(Volume);
|
||||||
return NULL;
|
return NULL;
|
||||||
ret = ArcRead(DeviceId, &BootSector, sizeof(BootSector), &Count);
|
}
|
||||||
if (ret != ESUCCESS || Count != sizeof(BootSector))
|
ret = ArcRead(DeviceId, &Volume->BootSector, sizeof(Volume->BootSector), &Count);
|
||||||
|
if (ret != ESUCCESS || Count != sizeof(Volume->BootSector))
|
||||||
|
{
|
||||||
|
MmHeapFree(Volume);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Check if BootSector is valid. If yes, return NTFS function table
|
// Check if BootSector is valid. If no, return early
|
||||||
//
|
//
|
||||||
if (RtlEqualMemory(BootSector.SystemId, "NTFS", 4))
|
if (!RtlEqualMemory(Volume->BootSector.SystemId, "NTFS", 4))
|
||||||
{
|
{
|
||||||
//
|
MmHeapFree(Volume);
|
||||||
// Compatibility hack as long as FS is not using underlying device DeviceId
|
|
||||||
//
|
|
||||||
ULONG DriveNumber;
|
|
||||||
ULONGLONG StartSector;
|
|
||||||
ULONGLONG SectorCount;
|
|
||||||
int Type;
|
|
||||||
if (!DiskGetBootVolume(&DriveNumber, &StartSector, &SectorCount, &Type))
|
|
||||||
return NULL;
|
|
||||||
NtfsOpenVolume(DriveNumber, StartSector, SectorCount);
|
|
||||||
return &NtfsFuncTable;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Calculate cluster size and MFT record size
|
||||||
|
//
|
||||||
|
Volume->ClusterSize = Volume->BootSector.SectorsPerCluster * Volume->BootSector.BytesPerSector;
|
||||||
|
if (Volume->BootSector.ClustersPerMftRecord > 0)
|
||||||
|
Volume->MftRecordSize = Volume->BootSector.ClustersPerMftRecord * Volume->ClusterSize;
|
||||||
|
else
|
||||||
|
Volume->MftRecordSize = 1 << (-Volume->BootSector.ClustersPerMftRecord);
|
||||||
|
if (Volume->BootSector.ClustersPerIndexRecord > 0)
|
||||||
|
Volume->IndexRecordSize = Volume->BootSector.ClustersPerIndexRecord * Volume->ClusterSize;
|
||||||
|
else
|
||||||
|
Volume->IndexRecordSize = 1 << (-Volume->BootSector.ClustersPerIndexRecord);
|
||||||
|
|
||||||
|
DPRINTM(DPRINT_FILESYSTEM, "ClusterSize: 0x%x\n", Volume->ClusterSize);
|
||||||
|
DPRINTM(DPRINT_FILESYSTEM, "ClustersPerMftRecord: %d\n", Volume->BootSector.ClustersPerMftRecord);
|
||||||
|
DPRINTM(DPRINT_FILESYSTEM, "ClustersPerIndexRecord: %d\n", Volume->BootSector.ClustersPerIndexRecord);
|
||||||
|
DPRINTM(DPRINT_FILESYSTEM, "MftRecordSize: 0x%x\n", Volume->MftRecordSize);
|
||||||
|
DPRINTM(DPRINT_FILESYSTEM, "IndexRecordSize: 0x%x\n", Volume->IndexRecordSize);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Read MFT index
|
||||||
|
//
|
||||||
|
DPRINTM(DPRINT_FILESYSTEM, "Reading MFT index...\n");
|
||||||
|
Volume->MasterFileTable = MmHeapAlloc(Volume->MftRecordSize);
|
||||||
|
if (!Volume->MasterFileTable)
|
||||||
|
{
|
||||||
|
MmHeapFree(Volume);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
Position.HighPart = 0;
|
||||||
|
Position.LowPart = Volume->BootSector.MftLocation * Volume->ClusterSize;
|
||||||
|
ret = ArcSeek(DeviceId, &Position, SeekAbsolute);
|
||||||
|
if (ret != ESUCCESS)
|
||||||
|
{
|
||||||
|
FileSystemError("Failed to seek to Master File Table record.");
|
||||||
|
MmHeapFree(Volume->MasterFileTable);
|
||||||
|
MmHeapFree(Volume);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
ret = ArcRead(DeviceId, Volume->MasterFileTable, Volume->MftRecordSize, &Count);
|
||||||
|
if (ret != ESUCCESS || Count != Volume->MftRecordSize)
|
||||||
|
{
|
||||||
|
FileSystemError("Failed to read the Master File Table record.");
|
||||||
|
MmHeapFree(Volume->MasterFileTable);
|
||||||
|
MmHeapFree(Volume);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Keep device id
|
||||||
|
//
|
||||||
|
Volume->DeviceId = DeviceId;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Search DATA attribute
|
||||||
|
//
|
||||||
|
DPRINTM(DPRINT_FILESYSTEM, "Searching for DATA attribute...\n");
|
||||||
|
Volume->MFTContext = NtfsFindAttribute(Volume, Volume->MasterFileTable, NTFS_ATTR_TYPE_DATA, L"");
|
||||||
|
if (!Volume->MFTContext)
|
||||||
|
{
|
||||||
|
FileSystemError("Can't find data attribute for Master File Table.");
|
||||||
|
MmHeapFree(Volume->MasterFileTable);
|
||||||
|
MmHeapFree(Volume);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Remember NTFS volume information
|
||||||
|
//
|
||||||
|
NtfsVolumes[DeviceId] = Volume;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Return success
|
||||||
|
//
|
||||||
|
return &NtfsFuncTable;
|
||||||
}
|
}
|
||||||
|
|
|
@ -214,11 +214,14 @@ typedef struct
|
||||||
NTFS_ATTR_RECORD Record;
|
NTFS_ATTR_RECORD Record;
|
||||||
} NTFS_ATTR_CONTEXT, *PNTFS_ATTR_CONTEXT;
|
} NTFS_ATTR_CONTEXT, *PNTFS_ATTR_CONTEXT;
|
||||||
|
|
||||||
|
typedef struct _NTFS_VOLUME_INFO *PNTFS_VOLUME_INFO;
|
||||||
|
|
||||||
#include <pshpack1.h>
|
#include <pshpack1.h>
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
PNTFS_ATTR_CONTEXT DataContext;
|
PNTFS_ATTR_CONTEXT DataContext;
|
||||||
ULONGLONG Offset;
|
ULONGLONG Offset;
|
||||||
|
PNTFS_VOLUME_INFO Volume;
|
||||||
} NTFS_FILE_HANDLE, *PNTFS_FILE_HANDLE;
|
} NTFS_FILE_HANDLE, *PNTFS_FILE_HANDLE;
|
||||||
#include <poppack.h>
|
#include <poppack.h>
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue