diff --git a/reactos/boot/freeldr/freeldr/fs/ntfs.c b/reactos/boot/freeldr/freeldr/fs/ntfs.c index 6c6f04ba193..b911d23ac95 100644 --- a/reactos/boot/freeldr/freeldr/fs/ntfs.c +++ b/reactos/boot/freeldr/freeldr/fs/ntfs.c @@ -26,15 +26,19 @@ #include #include -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) { @@ -123,50 +127,80 @@ static VOID NtfsReleaseAttributeContext(PNTFS_ATTR_CONTEXT Context) 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; 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; - ReadLength = min(Length, NtfsBootSector->BytesPerSector - (Offset % NtfsBootSector->BytesPerSector)); - RtlCopyMemory(Buffer, (PCHAR)DISKREADBUFFER + (Offset % NtfsBootSector->BytesPerSector), ReadLength); + ReadLength = min(Length, Volume->BootSector.BytesPerSector - (Offset % Volume->BootSector.BytesPerSector)); + 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; } - /* 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; @@ -197,7 +231,7 @@ static ULONGLONG NtfsReadAttribute(PNTFS_ATTR_CONTEXT Context, ULONGLONG Offset, 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; @@ -227,7 +261,7 @@ static ULONGLONG NtfsReadAttribute(PNTFS_ATTR_CONTEXT Context, ULONGLONG Offset, } if (Offset >= CurrentOffset && - Offset < CurrentOffset + (DataRunLength * NtfsClusterSize)) + Offset < CurrentOffset + (DataRunLength * Volume->ClusterSize)) { break; } @@ -237,7 +271,7 @@ static ULONGLONG NtfsReadAttribute(PNTFS_ATTR_CONTEXT Context, ULONGLONG Offset, 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 */ - 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 != (ULONGLONG)-1) { @@ -272,10 +306,10 @@ static ULONGLONG NtfsReadAttribute(PNTFS_ATTR_CONTEXT Context, ULONGLONG Offset, 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; @@ -283,7 +317,7 @@ static ULONGLONG NtfsReadAttribute(PNTFS_ATTR_CONTEXT Context, ULONGLONG Offset, 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; /* @@ -292,7 +326,7 @@ static ULONGLONG NtfsReadAttribute(PNTFS_ATTR_CONTEXT Context, ULONGLONG Offset, if (*DataRun == 0) break; - CurrentOffset += DataRunLength * NtfsClusterSize; + CurrentOffset += DataRunLength * Volume->ClusterSize; DataRun = NtfsDecodeRun(DataRun, &DataRunOffset, &DataRunLength); if (DataRunOffset != -1) { @@ -319,7 +353,7 @@ static ULONGLONG NtfsReadAttribute(PNTFS_ATTR_CONTEXT Context, ULONGLONG Offset, 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) { @@ -343,9 +377,9 @@ static PNTFS_ATTR_CONTEXT NtfsFindAttributeHelper(PNTFS_ATTR_RECORD AttrRecord, 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); @@ -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); } 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; @@ -401,30 +437,30 @@ static BOOLEAN NtfsFixupRecord(PNTFS_RECORD Record) 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); } #if DBG @@ -479,7 +515,7 @@ static BOOLEAN NtfsCompareFileName(PCHAR FileName, PNTFS_INDEX_ENTRY IndexEntry) 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; @@ -495,38 +531,38 @@ static BOOLEAN NtfsFindMftRecord(ULONG MFTIndex, PCHAR FileName, ULONG *OutMFTIn 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); - 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 && !(IndexEntry->Flags & NTFS_INDEX_ENTRY_END)) @@ -547,7 +583,7 @@ static BOOLEAN NtfsFindMftRecord(ULONG MFTIndex, PCHAR FileName, ULONG *OutMFTIn 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) { DPRINTM(DPRINT_FILESYSTEM, "Corrupted filesystem!\n"); @@ -563,10 +599,10 @@ static BOOLEAN NtfsFindMftRecord(ULONG MFTIndex, PCHAR FileName, ULONG *OutMFTIn 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) { DPRINTM(DPRINT_FILESYSTEM, "Corrupted filesystem!\n"); @@ -596,9 +632,9 @@ static BOOLEAN NtfsFindMftRecord(ULONG MFTIndex, PCHAR FileName, ULONG *OutMFTIn break; } - NtfsReadAttribute(IndexAllocationCtx, RecordOffset, IndexRecord, IndexBlockSize); + NtfsReadAttribute(Volume, IndexAllocationCtx, RecordOffset, IndexRecord, IndexBlockSize); - if (!NtfsFixupRecord((PNTFS_RECORD)IndexRecord)) + if (!NtfsFixupRecord(Volume, (PNTFS_RECORD)IndexRecord)) { break; } @@ -641,7 +677,7 @@ static BOOLEAN NtfsFindMftRecord(ULONG MFTIndex, PCHAR FileName, ULONG *OutMFTIn 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]; @@ -661,7 +697,7 @@ static BOOLEAN NtfsLookupFile(PCSTR FileName, PNTFS_MFT_RECORD MftRecord, PNTFS_ FileName++; DPRINTM(DPRINT_FILESYSTEM, "- Lookup: %s\n", PathPart); - if (!NtfsFindMftRecord(CurrentMFTIndex, PathPart, &CurrentMFTIndex)) + if (!NtfsFindMftRecord(Volume, CurrentMFTIndex, PathPart, &CurrentMFTIndex)) { DPRINTM(DPRINT_FILESYSTEM, "- Failed\n"); return FALSE; @@ -669,13 +705,13 @@ static BOOLEAN NtfsLookupFile(PCSTR FileName, PNTFS_MFT_RECORD MftRecord, PNTFS_ 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"); return FALSE; } - *DataContext = NtfsFindAttribute(MftRecord, NTFS_ATTR_TYPE_DATA, L""); + *DataContext = NtfsFindAttribute(Volume, MftRecord, NTFS_ATTR_TYPE_DATA, L""); if (*DataContext == NULL) { 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; } -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) { PNTFS_FILE_HANDLE FileHandle = FsGetDeviceSpecific(FileId); @@ -788,6 +749,7 @@ LONG NtfsGetFileInformation(ULONG FileId, FILEINFORMATION* Information) LONG NtfsOpen(CHAR* Path, OPENMODE OpenMode, ULONG* FileId) { + PNTFS_VOLUME_INFO Volume; PNTFS_FILE_HANDLE FileHandle; PNTFS_MFT_RECORD MftRecord; ULONG DeviceId; @@ -802,24 +764,26 @@ LONG NtfsOpen(CHAR* Path, OPENMODE OpenMode, ULONG* FileId) // 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) + NtfsMftRecordSize); + FileHandle = MmHeapAlloc(sizeof(NTFS_FILE_HANDLE) + Volume->MftRecordSize); if (!FileHandle) { return ENOMEM; } - RtlZeroMemory(FileHandle, sizeof(NTFS_FILE_HANDLE) + NtfsMftRecordSize); + RtlZeroMemory(FileHandle, sizeof(NTFS_FILE_HANDLE) + Volume->MftRecordSize); + FileHandle->Volume = Volume; // // Search file entry // MftRecord = (PNTFS_MFT_RECORD)(FileHandle + 1); - if (!NtfsLookupFile(Path, MftRecord, &FileHandle->DataContext)) + if (!NtfsLookupFile(Volume, Path, MftRecord, &FileHandle->DataContext)) { MmHeapFree(FileHandle); return ENOENT; @@ -836,7 +800,7 @@ LONG NtfsRead(ULONG FileId, VOID* Buffer, ULONG N, ULONG* Count) // // Read file // - BytesRead64 = NtfsReadAttribute(FileHandle->DataContext, FileHandle->Offset, Buffer, N); + BytesRead64 = NtfsReadAttribute(FileHandle->Volume, FileHandle->DataContext, FileHandle->Offset, Buffer, N); *Count = (ULONG)BytesRead64; // @@ -876,11 +840,19 @@ const DEVVTBL NtfsFuncTable = const DEVVTBL* NtfsMount(ULONG DeviceId) { - NTFS_BOOTSECTOR BootSector; + 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 // @@ -888,28 +860,99 @@ const DEVVTBL* NtfsMount(ULONG DeviceId) Position.LowPart = 0; ret = ArcSeek(DeviceId, &Position, SeekAbsolute); if (ret != ESUCCESS) + { + MmHeapFree(Volume); 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; + } // - // 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)) { - // - // 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 + MmHeapFree(Volume); 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; } diff --git a/reactos/boot/freeldr/freeldr/include/fs/ntfs.h b/reactos/boot/freeldr/freeldr/include/fs/ntfs.h index c755b4c93d5..03a69fe3876 100644 --- a/reactos/boot/freeldr/freeldr/include/fs/ntfs.h +++ b/reactos/boot/freeldr/freeldr/include/fs/ntfs.h @@ -214,11 +214,14 @@ typedef struct NTFS_ATTR_RECORD Record; } NTFS_ATTR_CONTEXT, *PNTFS_ATTR_CONTEXT; +typedef struct _NTFS_VOLUME_INFO *PNTFS_VOLUME_INFO; + #include typedef struct { PNTFS_ATTR_CONTEXT DataContext; ULONGLONG Offset; + PNTFS_VOLUME_INFO Volume; } NTFS_FILE_HANDLE, *PNTFS_FILE_HANDLE; #include