* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*
* - May crash on corrupted filesystem.
*/
+#ifndef _M_ARM
#include <freeldr.h>
#include <debug.h>
-PNTFS_BOOTSECTOR NtfsBootSector;
-ULONG NtfsClusterSize;
-ULONG NtfsMftRecordSize;
-ULONG NtfsIndexRecordSize;
-ULONG NtfsDriveNumber;
-ULONG NtfsSectorOfClusterZero;
-PNTFS_MFT_RECORD NtfsMasterFileTable;
-/* FIXME: NtfsMFTContext is never freed. */
-PNTFS_ATTR_CONTEXT NtfsMFTContext;
+typedef struct _NTFS_VOLUME_INFO
+{
+ NTFS_BOOTSECTOR BootSector;
+ ULONG ClusterSize;
+ ULONG MftRecordSize;
+ ULONG IndexRecordSize;
+ PNTFS_MFT_RECORD MasterFileTable;
+ /* FIXME: MFTContext is never freed. */
+ PNTFS_ATTR_CONTEXT MFTContext;
+ ULONG DeviceId;
+} NTFS_VOLUME_INFO;
+
+PNTFS_VOLUME_INFO NtfsVolumes[MAX_FDS];
static ULONGLONG NtfsGetAttributeSize(PNTFS_ATTR_RECORD AttrRecord)
{
*DataRunOffset = ((CHAR)(*(DataRun++)) << (i << 3)) + *DataRunOffset;
}
- DbgPrint((DPRINT_FILESYSTEM, "DataRunOffsetSize: %x\n", DataRunOffsetSize));
- DbgPrint((DPRINT_FILESYSTEM, "DataRunLengthSize: %x\n", DataRunLengthSize));
- DbgPrint((DPRINT_FILESYSTEM, "DataRunOffset: %x\n", *DataRunOffset));
- DbgPrint((DPRINT_FILESYSTEM, "DataRunLength: %x\n", *DataRunLength));
+ DPRINTM(DPRINT_FILESYSTEM, "DataRunOffsetSize: %x\n", DataRunOffsetSize);
+ DPRINTM(DPRINT_FILESYSTEM, "DataRunLengthSize: %x\n", DataRunLengthSize);
+ DPRINTM(DPRINT_FILESYSTEM, "DataRunOffset: %x\n", *DataRunOffset);
+ DPRINTM(DPRINT_FILESYSTEM, "DataRunLength: %x\n", *DataRunLength);
return DataRun;
}
MmHeapFree(Context);
}
-/* FIXME: Optimize for multisector reads. */
-static BOOLEAN NtfsDiskRead(ULONGLONG Offset, ULONGLONG Length, PCHAR Buffer)
+static BOOLEAN NtfsDiskRead(PNTFS_VOLUME_INFO Volume, ULONGLONG Offset, ULONGLONG Length, PCHAR Buffer)
{
+ LARGE_INTEGER Position;
+ ULONG Count;
USHORT ReadLength;
+ LONG ret;
- DbgPrint((DPRINT_FILESYSTEM, "NtfsDiskRead - Offset: %I64d Length: %I64d\n", Offset, Length));
- RtlZeroMemory((PCHAR)DISKREADBUFFER, 0x1000);
+ DPRINTM(DPRINT_FILESYSTEM, "NtfsDiskRead - Offset: %I64d Length: %I64d\n", Offset, Length);
- /* 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;
+ ReadLength = min(Length, Volume->BootSector.BytesPerSector - (Offset % Volume->BootSector.BytesPerSector));
+ ret = ArcRead(Volume->DeviceId, Buffer, ReadLength, &Count);
+ if (ret != ESUCCESS || Count != ReadLength)
return FALSE;
- ReadLength = min(Length, NtfsBootSector->BytesPerSector - (Offset % NtfsBootSector->BytesPerSector));
- RtlCopyMemory(Buffer, (PCHAR)DISKREADBUFFER + (Offset % NtfsBootSector->BytesPerSector), ReadLength);
+
+ //
+ // Move to unfilled buffer part
+ //
Buffer += ReadLength;
Length -= 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;
- RtlCopyMemory(Buffer, (PCHAR)DISKREADBUFFER, 64 * NtfsBootSector->BytesPerSector);
- Buffer += 64 * NtfsBootSector->BytesPerSector;
- Length -= 64 * NtfsBootSector->BytesPerSector;
- Offset += 64 * NtfsBootSector->BytesPerSector;
+ ReadLength = Length & ~(Volume->BootSector.BytesPerSector - 1);
+ ret = ArcRead(Volume->DeviceId, Buffer, ReadLength, &Count);
+ if (ret != ESUCCESS || Count != ReadLength)
+ 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)
{
- ReadLength = ((Length + NtfsBootSector->BytesPerSector - 1) / NtfsBootSector->BytesPerSector);
- if (!MachDiskReadLogicalSectors(NtfsDriveNumber, NtfsSectorOfClusterZero + (Offset / NtfsBootSector->BytesPerSector), ReadLength, (PCHAR)DISKREADBUFFER))
+ Position.HighPart = 0;
+ 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;
- RtlCopyMemory(Buffer, (PCHAR)DISKREADBUFFER, Length);
}
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;
PUCHAR DataRun;
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;
LastLCN = Context->CacheRunLastLCN;
}
if (Offset >= CurrentOffset &&
- Offset < CurrentOffset + (DataRunLength * NtfsClusterSize))
+ Offset < CurrentOffset + (DataRunLength * Volume->ClusterSize))
{
break;
}
return AlreadyRead;
}
- CurrentOffset += DataRunLength * NtfsClusterSize;
+ CurrentOffset += DataRunLength * Volume->ClusterSize;
}
}
* 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)
RtlZeroMemory(Buffer, ReadLength);
- if (NtfsDiskRead(DataRunStartLCN * NtfsClusterSize + Offset - CurrentOffset, ReadLength, Buffer))
+ if (NtfsDiskRead(Volume, DataRunStartLCN * Volume->ClusterSize + Offset - CurrentOffset, ReadLength, Buffer))
{
Length -= ReadLength;
Buffer += 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);
- if (DataRunLength != -1)
+ if (DataRunLength != (ULONGLONG)-1)
{
DataRunStartLCN = LastLCN + DataRunOffset;
LastLCN = DataRunStartLCN;
while (Length > 0)
{
- ReadLength = min(DataRunLength * NtfsClusterSize, Length);
+ ReadLength = min(DataRunLength * Volume->ClusterSize, Length);
if (DataRunStartLCN == -1)
RtlZeroMemory(Buffer, ReadLength);
- else if (!NtfsDiskRead(DataRunStartLCN * NtfsClusterSize, ReadLength, Buffer))
+ else if (!NtfsDiskRead(Volume, DataRunStartLCN * Volume->ClusterSize, ReadLength, Buffer))
break;
Length -= ReadLength;
AlreadyRead += ReadLength;
/* 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;
/*
if (*DataRun == 0)
break;
- CurrentOffset += DataRunLength * NtfsClusterSize;
+ CurrentOffset += DataRunLength * Volume->ClusterSize;
DataRun = NtfsDecodeRun(DataRun, &DataRunOffset, &DataRunLength);
if (DataRunOffset != -1)
{
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)
{
ListAttrRecord = (PNTFS_ATTR_RECORD)ListBuffer;
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);
NtfsReleaseAttributeContext(ListContext);
}
}
+ if (AttrRecord->Length == 0)
+ return NULL;
AttrRecord = (PNTFS_ATTR_RECORD)((PCHAR)AttrRecord + AttrRecord->Length);
}
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 AttrRecordEnd;
ULONG NameLength;
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++)
;
- 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 USANumber;
USA = (USHORT*)((PCHAR)Record + Record->USAOffset);
USANumber = *(USA++);
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)
{
if (*Block != USANumber)
return FALSE;
*Block = *(USA++);
- Block = (USHORT*)((PCHAR)Block + NtfsBootSector->BytesPerSector);
+ Block = (USHORT*)((PCHAR)Block + Volume->BootSector.BytesPerSector);
USACount--;
}
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;
- BytesRead = NtfsReadAttribute(NtfsMFTContext, MFTIndex * NtfsMftRecordSize, (PCHAR)Buffer, NtfsMftRecordSize);
- if (BytesRead != NtfsMftRecordSize)
+ BytesRead = NtfsReadAttribute(Volume, Volume->MFTContext, MFTIndex * Volume->MftRecordSize, (PCHAR)Buffer, Volume->MftRecordSize);
+ if (BytesRead != Volume->MftRecordSize)
return FALSE;
/* Apply update sequence array fixups. */
- return NtfsFixupRecord((PNTFS_RECORD)Buffer);
+ return NtfsFixupRecord(Volume, (PNTFS_RECORD)Buffer);
}
-#ifdef DBG
+#if DBG
VOID NtfsPrintFile(PNTFS_INDEX_ENTRY IndexEntry)
{
PWCHAR FileName;
AnsiFileName[i] = FileName[i];
AnsiFileName[i] = 0;
- DbgPrint((DPRINT_FILESYSTEM, "- %s (%x)\n", AnsiFileName, IndexEntry->Data.Directory.IndexedFile));
+ DPRINTM(DPRINT_FILESYSTEM, "- %s (%x)\n", AnsiFileName, IndexEntry->Data.Directory.IndexedFile);
}
#endif
EntryFileName = IndexEntry->FileName.FileName;
EntryFileNameLength = IndexEntry->FileName.FileNameLength;
-#ifdef DBG
+#if DBG
NtfsPrintFile(IndexEntry);
#endif
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;
ULONG Magic;
ULONG RecordOffset;
ULONG IndexBlockSize;
- MftRecord = MmHeapAlloc(NtfsMftRecordSize);
+ MftRecord = MmHeapAlloc(Volume->MftRecordSize);
if (MftRecord == NULL)
{
return FALSE;
}
- if (NtfsReadMftRecord(MFTIndex, MftRecord))
+ if (NtfsReadMftRecord(Volume, MFTIndex, MftRecord))
{
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)
{
MmHeapFree(MftRecord);
return FALSE;
}
- IndexRecord = MmHeapAlloc(NtfsIndexRecordSize);
+ IndexRecord = MmHeapAlloc(Volume->IndexRecordSize);
if (IndexRecord == NULL)
{
MmHeapFree(MftRecord);
return FALSE;
}
- NtfsReadAttribute(IndexRootCtx, 0, IndexRecord, NtfsIndexRecordSize);
+ NtfsReadAttribute(Volume, IndexRootCtx, 0, IndexRecord, Volume->IndexRecordSize);
IndexRoot = (PNTFS_INDEX_ROOT)IndexRecord;
IndexEntry = (PNTFS_INDEX_ENTRY)((PCHAR)&IndexRoot->IndexHeader + IndexRoot->IndexHeader.EntriesOffset);
/* Index root is always resident. */
IndexEntryEnd = (PNTFS_INDEX_ENTRY)(IndexRecord + IndexRootCtx->Record.Resident.ValueLength);
NtfsReleaseAttributeContext(IndexRootCtx);
- DbgPrint((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 &&
!(IndexEntry->Flags & NTFS_INDEX_ENTRY_END))
if (IndexRoot->IndexHeader.Flags & NTFS_LARGE_INDEX)
{
- DbgPrint((DPRINT_FILESYSTEM, "Large Index!\n"));
+ DPRINTM(DPRINT_FILESYSTEM, "Large Index!\n");
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)
{
- DbgPrint((DPRINT_FILESYSTEM, "Corrupted filesystem!\n"));
+ DPRINTM(DPRINT_FILESYSTEM, "Corrupted filesystem!\n");
MmHeapFree(MftRecord);
return FALSE;
}
BitmapDataSize = NtfsGetAttributeSize(&IndexBitmapCtx->Record);
- DbgPrint((DPRINT_FILESYSTEM, "BitmapDataSize: %x\n", BitmapDataSize));
+ DPRINTM(DPRINT_FILESYSTEM, "BitmapDataSize: %x\n", BitmapDataSize);
BitmapData = MmHeapAlloc(BitmapDataSize);
if (BitmapData == NULL)
{
MmHeapFree(MftRecord);
return FALSE;
}
- NtfsReadAttribute(IndexBitmapCtx, 0, BitmapData, BitmapDataSize);
+ NtfsReadAttribute(Volume, IndexBitmapCtx, 0, BitmapData, BitmapDataSize);
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)
{
- DbgPrint((DPRINT_FILESYSTEM, "Corrupted filesystem!\n"));
+ DPRINTM(DPRINT_FILESYSTEM, "Corrupted filesystem!\n");
MmHeapFree(BitmapData);
MmHeapFree(IndexRecord);
MmHeapFree(MftRecord);
for (;;)
{
- DbgPrint((DPRINT_FILESYSTEM, "RecordOffset: %x IndexAllocationSize: %x\n", RecordOffset, IndexAllocationSize));
+ DPRINTM(DPRINT_FILESYSTEM, "RecordOffset: %x IndexAllocationSize: %x\n", RecordOffset, IndexAllocationSize);
for (; RecordOffset < IndexAllocationSize;)
{
UCHAR Bit = 1 << ((RecordOffset / IndexBlockSize) & 7);
break;
}
- NtfsReadAttribute(IndexAllocationCtx, RecordOffset, IndexRecord, IndexBlockSize);
+ NtfsReadAttribute(Volume, IndexAllocationCtx, RecordOffset, IndexRecord, IndexBlockSize);
- if (!NtfsFixupRecord((PNTFS_RECORD)IndexRecord))
+ if (!NtfsFixupRecord(Volume, (PNTFS_RECORD)IndexRecord))
{
break;
}
{
if (NtfsCompareFileName(FileName, IndexEntry))
{
- DbgPrint((DPRINT_FILESYSTEM, "File found\n"));
+ DPRINTM(DPRINT_FILESYSTEM, "File found\n");
*OutMFTIndex = IndexEntry->Data.Directory.IndexedFile;
MmHeapFree(BitmapData);
MmHeapFree(IndexRecord);
}
else
{
- DbgPrint((DPRINT_FILESYSTEM, "Can't read MFT record\n"));
+ DPRINTM(DPRINT_FILESYSTEM, "Can't read MFT record\n");
}
MmHeapFree(MftRecord);
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;
CHAR PathPart[261];
ULONG CurrentMFTIndex;
UCHAR i;
- DbgPrint((DPRINT_FILESYSTEM, "NtfsLookupFile() FileName = %s\n", FileName));
+ DPRINTM(DPRINT_FILESYSTEM, "NtfsLookupFile() FileName = %s\n", FileName);
CurrentMFTIndex = NTFS_FILE_ROOT;
NumberOfPathParts = FsGetNumPathParts(FileName);
;
FileName++;
- DbgPrint((DPRINT_FILESYSTEM, "- Lookup: %s\n", PathPart));
- if (!NtfsFindMftRecord(CurrentMFTIndex, PathPart, &CurrentMFTIndex))
+ DPRINTM(DPRINT_FILESYSTEM, "- Lookup: %s\n", PathPart);
+ if (!NtfsFindMftRecord(Volume, CurrentMFTIndex, PathPart, &CurrentMFTIndex))
{
- DbgPrint((DPRINT_FILESYSTEM, "- Failed\n"));
+ DPRINTM(DPRINT_FILESYSTEM, "- Failed\n");
return FALSE;
}
- DbgPrint((DPRINT_FILESYSTEM, "- Lookup: %x\n", CurrentMFTIndex));
+ DPRINTM(DPRINT_FILESYSTEM, "- Lookup: %x\n", CurrentMFTIndex);
}
- if (!NtfsReadMftRecord(CurrentMFTIndex, MftRecord))
+ if (!NtfsReadMftRecord(Volume, CurrentMFTIndex, MftRecord))
{
- DbgPrint((DPRINT_FILESYSTEM, "NtfsLookupFile: Can't read MFT record\n"));
+ DPRINTM(DPRINT_FILESYSTEM, "NtfsLookupFile: Can't read MFT record\n");
return FALSE;
}
- *DataContext = NtfsFindAttribute(MftRecord, NTFS_ATTR_TYPE_DATA, L"");
+ *DataContext = NtfsFindAttribute(Volume, MftRecord, NTFS_ATTR_TYPE_DATA, L"");
if (*DataContext == NULL)
{
- DbgPrint((DPRINT_FILESYSTEM, "NtfsLookupFile: Can't find data attribute\n"));
+ DPRINTM(DPRINT_FILESYSTEM, "NtfsLookupFile: Can't find data attribute\n");
return FALSE;
}
return TRUE;
}
-BOOLEAN NtfsOpenVolume(UCHAR DriveNumber, ULONGLONG VolumeStartSector, ULONGLONG PartitionSectorCount)
+LONG NtfsClose(ULONG FileId)
{
- NtfsBootSector = (PNTFS_BOOTSECTOR)DISKREADBUFFER;
+ PNTFS_FILE_HANDLE FileHandle = FsGetDeviceSpecific(FileId);
- DbgPrint((DPRINT_FILESYSTEM, "NtfsOpenVolume() DriveNumber = 0x%x VolumeStartSector = 0x%x\n", DriveNumber, VolumeStartSector));
+ NtfsReleaseAttributeContext(FileHandle->DataContext);
+ MmHeapFree(FileHandle);
- if (!MachDiskReadLogicalSectors(DriveNumber, VolumeStartSector, 1, (PCHAR)DISKREADBUFFER))
- {
- FileSystemError("Failed to read the boot sector.");
- return FALSE;
- }
+ return ESUCCESS;
+}
+
+LONG NtfsGetFileInformation(ULONG FileId, FILEINFORMATION* Information)
+{
+ PNTFS_FILE_HANDLE FileHandle = FsGetDeviceSpecific(FileId);
+
+ RtlZeroMemory(Information, sizeof(FILEINFORMATION));
+ Information->EndingAddress.LowPart = (ULONG)NtfsGetAttributeSize(&FileHandle->DataContext->Record);
+ Information->CurrentAddress.LowPart = FileHandle->Offset;
- if (!RtlEqualMemory(NtfsBootSector->SystemId, "NTFS", 4))
+ DPRINTM(DPRINT_FILESYSTEM, "NtfsGetFileInformation() FileSize = %d\n",
+ Information->EndingAddress.LowPart);
+ DPRINTM(DPRINT_FILESYSTEM, "NtfsGetFileInformation() FilePointer = %d\n",
+ Information->CurrentAddress.LowPart);
+
+ return ESUCCESS;
+}
+
+LONG NtfsOpen(CHAR* Path, OPENMODE OpenMode, ULONG* FileId)
+{
+ PNTFS_VOLUME_INFO Volume;
+ PNTFS_FILE_HANDLE FileHandle;
+ PNTFS_MFT_RECORD MftRecord;
+ ULONG DeviceId;
+
+ //
+ // Check parameters
+ //
+ if (OpenMode != OpenReadOnly)
+ return EACCES;
+
+ //
+ // Get underlying device
+ //
+ DeviceId = FsGetDeviceId(*FileId);
+ Volume = NtfsVolumes[DeviceId];
+
+ DPRINTM(DPRINT_FILESYSTEM, "NtfsOpen() FileName = %s\n", Path);
+
+ //
+ // Allocate file structure
+ //
+ FileHandle = MmHeapAlloc(sizeof(NTFS_FILE_HANDLE) + Volume->MftRecordSize);
+ if (!FileHandle)
{
- FileSystemError("Invalid NTFS signature.");
- return FALSE;
+ return ENOMEM;
}
+ RtlZeroMemory(FileHandle, sizeof(NTFS_FILE_HANDLE) + Volume->MftRecordSize);
+ FileHandle->Volume = Volume;
- NtfsBootSector = MmHeapAlloc(NtfsBootSector->BytesPerSector);
- if (NtfsBootSector == NULL)
+ //
+ // Search file entry
+ //
+ MftRecord = (PNTFS_MFT_RECORD)(FileHandle + 1);
+ if (!NtfsLookupFile(Volume, Path, MftRecord, &FileHandle->DataContext))
{
- return FALSE;
+ MmHeapFree(FileHandle);
+ return ENOENT;
}
- RtlCopyMemory(NtfsBootSector, (PCHAR)DISKREADBUFFER, ((PNTFS_BOOTSECTOR)DISKREADBUFFER)->BytesPerSector);
+ return ESUCCESS;
+}
- 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;
+LONG NtfsRead(ULONG FileId, VOID* Buffer, ULONG N, ULONG* Count)
+{
+ PNTFS_FILE_HANDLE FileHandle = FsGetDeviceSpecific(FileId);
+ ULONGLONG BytesRead64;
+
+ //
+ // Read file
+ //
+ BytesRead64 = NtfsReadAttribute(FileHandle->Volume, FileHandle->DataContext, FileHandle->Offset, Buffer, N);
+ *Count = (ULONG)BytesRead64;
+
+ //
+ // Check for success
+ //
+ if (BytesRead64 > 0)
+ return ESUCCESS;
else
- NtfsIndexRecordSize = 1 << (-NtfsBootSector->ClustersPerIndexRecord);
-
- DbgPrint((DPRINT_FILESYSTEM, "NtfsClusterSize: 0x%x\n", NtfsClusterSize));
- DbgPrint((DPRINT_FILESYSTEM, "ClustersPerMftRecord: %d\n", NtfsBootSector->ClustersPerMftRecord));
- DbgPrint((DPRINT_FILESYSTEM, "ClustersPerIndexRecord: %d\n", NtfsBootSector->ClustersPerIndexRecord));
- DbgPrint((DPRINT_FILESYSTEM, "NtfsMftRecordSize: 0x%x\n", NtfsMftRecordSize));
- DbgPrint((DPRINT_FILESYSTEM, "NtfsIndexRecordSize: 0x%x\n", NtfsIndexRecordSize));
-
- NtfsDriveNumber = DriveNumber;
- NtfsSectorOfClusterZero = VolumeStartSector;
-
- DbgPrint((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;
- }
+ return EIO;
+}
- NtfsMasterFileTable = MmHeapAlloc(NtfsMftRecordSize);
- if (NtfsMasterFileTable == NULL)
- {
- MmHeapFree(NtfsBootSector);
- return FALSE;
- }
+LONG NtfsSeek(ULONG FileId, LARGE_INTEGER* Position, SEEKMODE SeekMode)
+{
+ PNTFS_FILE_HANDLE FileHandle = FsGetDeviceSpecific(FileId);
- RtlCopyMemory(NtfsMasterFileTable, (PCHAR)DISKREADBUFFER, NtfsMftRecordSize);
+ DPRINTM(DPRINT_FILESYSTEM, "NtfsSeek() NewFilePointer = %lu\n", Position->LowPart);
- DbgPrint((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;
- }
+ if (SeekMode != SeekAbsolute)
+ return EINVAL;
+ if (Position->HighPart != 0)
+ return EINVAL;
+ if (Position->LowPart >= (ULONG)NtfsGetAttributeSize(&FileHandle->DataContext->Record))
+ return EINVAL;
- return TRUE;
+ FileHandle->Offset = Position->LowPart;
+ return ESUCCESS;
}
-FILE* NtfsOpenFile(PCSTR FileName)
+const DEVVTBL NtfsFuncTable =
{
- PNTFS_FILE_HANDLE FileHandle;
- PNTFS_MFT_RECORD MftRecord;
+ NtfsClose,
+ NtfsGetFileInformation,
+ NtfsOpen,
+ NtfsRead,
+ NtfsSeek,
+ L"ntfs",
+};
- FileHandle = MmHeapAlloc(sizeof(NTFS_FILE_HANDLE) + NtfsMftRecordSize);
- if (FileHandle == NULL)
+const DEVVTBL* NtfsMount(ULONG DeviceId)
+{
+ PNTFS_VOLUME_INFO Volume;
+ LARGE_INTEGER Position;
+ ULONG Count;
+ 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
+ //
+ Position.HighPart = 0;
+ Position.LowPart = 0;
+ ret = ArcSeek(DeviceId, &Position, SeekAbsolute);
+ if (ret != ESUCCESS)
{
+ MmHeapFree(Volume);
return NULL;
}
-
- MftRecord = (PNTFS_MFT_RECORD)(FileHandle + 1);
- if (!NtfsLookupFile(FileName, MftRecord, &FileHandle->DataContext))
+ ret = ArcRead(DeviceId, &Volume->BootSector, sizeof(Volume->BootSector), &Count);
+ if (ret != ESUCCESS || Count != sizeof(Volume->BootSector))
{
- MmHeapFree(FileHandle);
+ MmHeapFree(Volume);
return NULL;
}
- FileHandle->Offset = 0;
-
- return (FILE*)FileHandle;
-}
-
-VOID NtfsCloseFile(FILE *File)
-{
- PNTFS_FILE_HANDLE FileHandle = (PNTFS_FILE_HANDLE)File;
- NtfsReleaseAttributeContext(FileHandle->DataContext);
- MmHeapFree(FileHandle);
-}
+ //
+ // Check if BootSector is valid. If no, return early
+ //
+ if (!RtlEqualMemory(Volume->BootSector.SystemId, "NTFS", 4))
+ {
+ MmHeapFree(Volume);
+ return NULL;
+ }
-BOOLEAN NtfsReadFile(FILE *File, ULONG BytesToRead, ULONG* BytesRead, PVOID Buffer)
-{
- PNTFS_FILE_HANDLE FileHandle = (PNTFS_FILE_HANDLE)File;
- ULONGLONG BytesRead64;
- BytesRead64 = NtfsReadAttribute(FileHandle->DataContext, FileHandle->Offset, Buffer, BytesToRead);
- if (BytesRead64)
+ //
+ // 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)
{
- *BytesRead = (ULONG)BytesRead64;
- FileHandle->Offset += BytesRead64;
- return TRUE;
+ 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;
}
- return FALSE;
-}
-ULONG NtfsGetFileSize(FILE *File)
-{
- PNTFS_FILE_HANDLE FileHandle = (PNTFS_FILE_HANDLE)File;
- return (ULONG)NtfsGetAttributeSize(&FileHandle->DataContext->Record);
-}
+ //
+ // 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;
+ }
-VOID NtfsSetFilePointer(FILE *File, ULONG NewFilePointer)
-{
- PNTFS_FILE_HANDLE FileHandle = (PNTFS_FILE_HANDLE)File;
- FileHandle->Offset = NewFilePointer;
-}
+ //
+ // Remember NTFS volume information
+ //
+ NtfsVolumes[DeviceId] = Volume;
-ULONG NtfsGetFilePointer(FILE *File)
-{
- PNTFS_FILE_HANDLE FileHandle = (PNTFS_FILE_HANDLE)File;
- return FileHandle->Offset;
+ //
+ // Return success
+ //
+ return &NtfsFuncTable;
}
-const FS_VTBL NtfsVtbl = {
- NtfsOpenVolume,
- NtfsOpenFile,
- NtfsCloseFile,
- NtfsReadFile,
- NtfsGetFileSize,
- NtfsSetFilePointer,
- NtfsGetFilePointer,
-};
+#endif