ntfs.c

来自「一个类似windows」· C语言 代码 · 共 733 行 · 第 1/2 页

C
733
字号
    UCHAR EntryFileNameLength;
    UCHAR i;

    EntryFileName = IndexEntry->FileName.FileName;
    EntryFileNameLength = IndexEntry->FileName.FileNameLength;

#ifdef DEBUG
    NtfsPrintFile(IndexEntry);
#endif

    if (strlen(FileName) != EntryFileNameLength)
        return FALSE;

    /* Do case-sensitive compares for Posix file names. */
    if (IndexEntry->FileName.FileNameType == NTFS_FILE_NAME_POSIX)
    {
        for (i = 0; i < EntryFileNameLength; i++)
            if (EntryFileName[i] != FileName[i])
                return FALSE;
    }
    else
    {
        for (i = 0; i < EntryFileNameLength; i++)
            if (tolower(EntryFileName[i]) != tolower(FileName[i]))
                return FALSE;
    }

    return TRUE;
}

static BOOL NtfsFindMftRecord(ULONG MFTIndex, PCHAR FileName, ULONG *OutMFTIndex)
{
    PNTFS_MFT_RECORD MftRecord;
    ULONG Magic;
    NTFS_ATTR_CONTEXT IndexRootCtx;
    NTFS_ATTR_CONTEXT IndexBitmapCtx;
    NTFS_ATTR_CONTEXT IndexAllocationCtx;
    PNTFS_INDEX_ROOT IndexRoot;
    ULONGLONG BitmapDataSize;
    ULONGLONG IndexAllocationSize;
    PCHAR BitmapData;
    PCHAR IndexRecord;
    PNTFS_INDEX_ENTRY IndexEntry, IndexEntryEnd;
    ULONG RecordOffset;
    ULONG IndexBlockSize;

    MftRecord = MmAllocateMemory(NtfsMftRecordSize);
    if (MftRecord == NULL)
    {
        return FALSE;
    }

    if (NtfsReadMftRecord(MFTIndex, MftRecord))
    {
        Magic = MftRecord->Magic;

        if (!NtfsFindAttribute(&IndexRootCtx, MftRecord, NTFS_ATTR_TYPE_INDEX_ROOT, L"$I30"))
        {
            MmFreeMemory(MftRecord);
            return FALSE;
        }

        IndexRecord = MmAllocateMemory(NtfsIndexRecordSize);
        if (IndexRecord == NULL)
        {
            MmFreeMemory(MftRecord);
            return FALSE;
        }

        NtfsReadAttribute(&IndexRootCtx, 0, IndexRecord, NtfsIndexRecordSize);
        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);

        DbgPrint((DPRINT_FILESYSTEM, "NtfsIndexRecordSize: %x IndexBlockSize: %x\n", NtfsIndexRecordSize, IndexRoot->IndexBlockSize));

        while (IndexEntry < IndexEntryEnd &&
               !(IndexEntry->Flags & NTFS_INDEX_ENTRY_END))
        {
            if (NtfsCompareFileName(FileName, IndexEntry))
            {
                *OutMFTIndex = IndexEntry->Data.Directory.IndexedFile;
                MmFreeMemory(IndexRecord);
                MmFreeMemory(MftRecord);
                return TRUE;
            }
	    IndexEntry = (PNTFS_INDEX_ENTRY)((PCHAR)IndexEntry + IndexEntry->Length);
        }

        if (IndexRoot->IndexHeader.Flags & NTFS_LARGE_INDEX)
        {
            DbgPrint((DPRINT_FILESYSTEM, "Large Index!\n"));

            IndexBlockSize = IndexRoot->IndexBlockSize;

            if (!NtfsFindAttribute(&IndexBitmapCtx, MftRecord, NTFS_ATTR_TYPE_BITMAP, L"$I30"))
            {
                DbgPrint((DPRINT_FILESYSTEM, "Corrupted filesystem!\n"));
                MmFreeMemory(MftRecord);
                return FALSE;
            }
            if (IndexBitmapCtx.Record->IsNonResident)
                BitmapDataSize = IndexBitmapCtx.Record->NonResident.DataSize;
            else
                BitmapDataSize = IndexBitmapCtx.Record->Resident.ValueLength;
            DbgPrint((DPRINT_FILESYSTEM, "BitmapDataSize: %x\n", BitmapDataSize));
            BitmapData = MmAllocateMemory(BitmapDataSize);
            if (BitmapData == NULL)
            {
                MmFreeMemory(IndexRecord);
                MmFreeMemory(MftRecord);
                return FALSE;
            }
            NtfsReadAttribute(&IndexBitmapCtx, 0, BitmapData, BitmapDataSize);

            if (!NtfsFindAttribute(&IndexAllocationCtx, MftRecord, NTFS_ATTR_TYPE_INDEX_ALLOCATION, L"$I30"))
            {
                DbgPrint((DPRINT_FILESYSTEM, "Corrupted filesystem!\n"));
                MmFreeMemory(BitmapData);
                MmFreeMemory(IndexRecord);
                MmFreeMemory(MftRecord);
                return FALSE;
            }
            if (IndexAllocationCtx.Record->IsNonResident)
                IndexAllocationSize = IndexAllocationCtx.Record->NonResident.DataSize;
            else
                IndexAllocationSize = IndexAllocationCtx.Record->Resident.ValueLength;

            RecordOffset = 0;

            for (;;)
            {
                DbgPrint((DPRINT_FILESYSTEM, "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;
                }

                NtfsReadAttribute(&IndexAllocationCtx, RecordOffset, IndexRecord, IndexBlockSize);

                if (!NtfsFixupRecord((PNTFS_RECORD)IndexRecord))
                {
                    break;
                }

                /* FIXME */
                IndexEntry = (PNTFS_INDEX_ENTRY)(IndexRecord + 0x18 + *(USHORT *)(IndexRecord + 0x18));
	        IndexEntryEnd = (PNTFS_INDEX_ENTRY)(IndexRecord + IndexBlockSize);

                while (IndexEntry < IndexEntryEnd &&
                       !(IndexEntry->Flags & NTFS_INDEX_ENTRY_END))
                {
                    if (NtfsCompareFileName(FileName, IndexEntry))
                    {
                        DbgPrint((DPRINT_FILESYSTEM, "File found\n"));
                        *OutMFTIndex = IndexEntry->Data.Directory.IndexedFile;
                        MmFreeMemory(BitmapData);
                        MmFreeMemory(IndexRecord);
                        MmFreeMemory(MftRecord);
                        return TRUE;
                    }
                    IndexEntry = (PNTFS_INDEX_ENTRY)((PCHAR)IndexEntry + IndexEntry->Length);
                }

                RecordOffset += IndexBlockSize;
            }

            MmFreeMemory(BitmapData);
        }

        MmFreeMemory(IndexRecord);
    }
    else
    {
        DbgPrint((DPRINT_FILESYSTEM, "Can't read MFT record\n"));
    }
    MmFreeMemory(MftRecord);

    return FALSE;
}

static BOOL NtfsLookupFile(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));

    CurrentMFTIndex = NTFS_FILE_ROOT;
    NumberOfPathParts = FsGetNumPathParts(FileName);
    for (i = 0; i < NumberOfPathParts; i++)
    {
        FsGetFirstNameFromPath(PathPart, FileName);

        for (; (*FileName != '\\') && (*FileName != '/') && (*FileName != '\0'); FileName++)
            ;
        FileName++;

        DbgPrint((DPRINT_FILESYSTEM, "- Lookup: %s\n", PathPart));
        if (!NtfsFindMftRecord(CurrentMFTIndex, PathPart, &CurrentMFTIndex))
        {
            DbgPrint((DPRINT_FILESYSTEM, "- Failed\n"));
            return FALSE;
        }
        DbgPrint((DPRINT_FILESYSTEM, "- Lookup: %x\n", CurrentMFTIndex));
    }

    if (!NtfsReadMftRecord(CurrentMFTIndex, MftRecord))
    {
        DbgPrint((DPRINT_FILESYSTEM, "NtfsLookupFile: Can't read MFT record\n"));
        return FALSE;
    }

    if (!NtfsFindAttribute(DataContext, MftRecord, NTFS_ATTR_TYPE_DATA, L""))
    {
        DbgPrint((DPRINT_FILESYSTEM, "NtfsLookupFile: Can't find data attribute\n"));
        return FALSE;
    }

    return TRUE;
}

BOOL NtfsOpenVolume(ULONG DriveNumber, ULONG VolumeStartSector)
{
    NtfsBootSector = (PNTFS_BOOTSECTOR)DISKREADBUFFER;

    DbgPrint((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 = MmAllocateMemory(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);

    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;
    }

    NtfsMasterFileTable = MmAllocateMemory(NtfsMftRecordSize);
    if (NtfsMasterFileTable == NULL)
    {
        MmFreeMemory(NtfsBootSector);
        return FALSE;
    }

    RtlCopyMemory(NtfsMasterFileTable, (PCHAR)DISKREADBUFFER, NtfsMftRecordSize);

    DbgPrint((DPRINT_FILESYSTEM, "Searching for DATA attribute...\n"));
    if (!NtfsFindAttribute(&NtfsMFTContext, NtfsMasterFileTable, NTFS_ATTR_TYPE_DATA, L""))
    {
        FileSystemError("Can't find data attribute for Master File Table.");
        return FALSE;
    }

    return TRUE;
}

FILE* NtfsOpenFile(PCSTR FileName)
{
    PNTFS_FILE_HANDLE FileHandle;
    PNTFS_MFT_RECORD MftRecord;

    FileHandle = MmAllocateMemory(sizeof(NTFS_FILE_HANDLE) + NtfsMftRecordSize);
    if (FileHandle == NULL)
    {
        return NULL;
    }

    MftRecord = (PNTFS_MFT_RECORD)(FileHandle + 1);
    if (!NtfsLookupFile(FileName, MftRecord, &FileHandle->DataContext))
    {
        MmFreeMemory(FileHandle);
        return NULL;
    }

    FileHandle->Offset = 0;

    return (FILE*)FileHandle;
}

BOOL 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)
    {
        *BytesRead = (ULONG)BytesRead64;
        FileHandle->Offset += BytesRead64;
        return TRUE;
    }
    return FALSE;
}

ULONG NtfsGetFileSize(FILE *File)
{
    PNTFS_FILE_HANDLE FileHandle = (PNTFS_FILE_HANDLE)File;
    if (FileHandle->DataContext.Record->IsNonResident)
        return (ULONG)FileHandle->DataContext.Record->NonResident.DataSize;
    else
        return (ULONG)FileHandle->DataContext.Record->Resident.ValueLength;
}

VOID NtfsSetFilePointer(FILE *File, ULONG NewFilePointer)
{
    PNTFS_FILE_HANDLE FileHandle = (PNTFS_FILE_HANDLE)File;
    FileHandle->Offset = NewFilePointer;
}

ULONG NtfsGetFilePointer(FILE *File)
{
    PNTFS_FILE_HANDLE FileHandle = (PNTFS_FILE_HANDLE)File;
    return FileHandle->Offset;
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?