mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 10:04:49 +00:00
- Fixed lots of bugs in NTFS code and added correct update sequence
fixups handling and untested NTFS 3+ sparse file support. svn path=/trunk/; revision=10467
This commit is contained in:
parent
99e5dd3e01
commit
5775259453
4 changed files with 140 additions and 80 deletions
|
@ -1,3 +1,8 @@
|
|||
Changes in v1.8.22 (21/05/2004) (navaraf)
|
||||
|
||||
- Fixed lots of bugs in NTFS code and added correct update sequence
|
||||
fixups handling and untested NTFS 3+ sparse file support.
|
||||
|
||||
Changes in v1.8.21 (21/05/2004) (navaraf)
|
||||
|
||||
- Experimental NTFS reading support with no boot code yet.
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
/*
|
||||
* FreeLoader
|
||||
* Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
|
||||
*
|
||||
* FreeLoader NTFS support
|
||||
* Copyright (C) 2004 Filip Navara <xnavara@volny.cz>
|
||||
*
|
||||
|
@ -25,10 +22,6 @@
|
|||
* - No support for compressed files.
|
||||
* - No attribute list support.
|
||||
* - May crash on currupted filesystem.
|
||||
*
|
||||
* Bugs:
|
||||
* - I encountered file names like 'KERNEL~1.EE' stored on
|
||||
* the disk. These aren't handled correctly yet.
|
||||
*/
|
||||
|
||||
#include <freeldr.h>
|
||||
|
@ -40,7 +33,6 @@
|
|||
#include <debug.h>
|
||||
#include <cache.h>
|
||||
|
||||
#define NTFS_DEFS
|
||||
#include "ntfs.h"
|
||||
|
||||
PNTFS_BOOTSECTOR NtfsBootSector;
|
||||
|
@ -56,7 +48,7 @@ PUCHAR NtfsDecodeRun(PUCHAR DataRun, S64 *DataRunOffset, U64 *DataRunLength)
|
|||
{
|
||||
U8 DataRunOffsetSize;
|
||||
U8 DataRunLengthSize;
|
||||
U8 i;
|
||||
S8 i;
|
||||
|
||||
DataRunOffsetSize = (*DataRun >> 4) & 0xF;
|
||||
DataRunLengthSize = *DataRun & 0xF;
|
||||
|
@ -68,16 +60,27 @@ PUCHAR NtfsDecodeRun(PUCHAR DataRun, S64 *DataRunOffset, U64 *DataRunLength)
|
|||
*DataRunLength += *DataRun << (i << 3);
|
||||
DataRun++;
|
||||
}
|
||||
for (i = 0; i < DataRunOffsetSize; i++)
|
||||
|
||||
/* NTFS 3+ sparse files */
|
||||
if (DataRunOffsetSize == 0)
|
||||
{
|
||||
*DataRunOffset = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < DataRunOffsetSize - 1; i++)
|
||||
{
|
||||
*DataRunOffset += *DataRun << (i << 3);
|
||||
DataRun++;
|
||||
}
|
||||
/* The last byte contains sign so we must process it different way. */
|
||||
*DataRunOffset = ((S8)(*(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));
|
||||
DbgPrint((DPRINT_FILESYSTEM, "DataRunOffset: %x\n", *DataRunOffset));
|
||||
DbgPrint((DPRINT_FILESYSTEM, "DataRunLength: %x\n", *DataRunLength));
|
||||
|
||||
return DataRun;
|
||||
}
|
||||
|
@ -97,7 +100,7 @@ BOOL NtfsFindAttribute(PNTFS_ATTR_CONTEXT Context, PNTFS_MFT_RECORD MftRecord, U
|
|||
|
||||
while (AttrRecord < AttrRecordEnd)
|
||||
{
|
||||
if (AttrRecord->Type == ATTR_TYPE_END)
|
||||
if (AttrRecord->Type == NTFS_ATTR_TYPE_END)
|
||||
break;
|
||||
|
||||
if (AttrRecord->Type == Type)
|
||||
|
@ -117,6 +120,7 @@ BOOL NtfsFindAttribute(PNTFS_ATTR_CONTEXT Context, PNTFS_MFT_RECORD MftRecord, U
|
|||
Context->CacheRun = (PUCHAR)Context->Record + Context->Record->NonResident.MappingPairsOffset;
|
||||
Context->CacheRunOffset = 0;
|
||||
Context->CacheRun = NtfsDecodeRun(Context->CacheRun, &DataRunOffset, &DataRunLength);
|
||||
Context->CacheRunLength = DataRunLength;
|
||||
if (DataRunOffset != -1)
|
||||
{
|
||||
/* Normal run. */
|
||||
|
@ -147,6 +151,9 @@ BOOL NtfsDiskRead(U64 Offset, U64 Length, PCHAR Buffer)
|
|||
{
|
||||
U16 ReadLength;
|
||||
|
||||
DbgPrint((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)
|
||||
{
|
||||
|
@ -216,6 +223,7 @@ U64 NtfsReadAttribute(PNTFS_ATTR_CONTEXT Context, U64 Offset, PCHAR Buffer, U64
|
|||
DataRun = Context->CacheRun;
|
||||
LastLCN = Context->CacheRunLastLCN;
|
||||
DataRunStartLCN = Context->CacheRunStartLCN;
|
||||
DataRunLength = Context->CacheRunLength;
|
||||
CurrentOffset = Context->CacheRunCurrentOffset;
|
||||
}
|
||||
else
|
||||
|
@ -239,6 +247,8 @@ U64 NtfsReadAttribute(PNTFS_ATTR_CONTEXT Context, U64 Offset, PCHAR Buffer, U64
|
|||
DataRunStartLCN = -1;
|
||||
}
|
||||
|
||||
DbgPrint((DPRINT_FILESYSTEM, "YYY - %I64x\n", DataRunStartLCN));
|
||||
|
||||
if (Offset >= CurrentOffset &&
|
||||
Offset < CurrentOffset + (DataRunLength * NtfsClusterSize))
|
||||
{
|
||||
|
@ -270,6 +280,10 @@ U64 NtfsReadAttribute(PNTFS_ATTR_CONTEXT Context, U64 Offset, PCHAR Buffer, U64
|
|||
Buffer += ReadLength;
|
||||
AlreadyRead += ReadLength;
|
||||
|
||||
/* We finished this request, but there still data in this data run. */
|
||||
if (Length == 0 && ReadLength != DataRunLength * NtfsClusterSize)
|
||||
break;
|
||||
|
||||
/*
|
||||
* Go to next run in the list.
|
||||
*/
|
||||
|
@ -294,15 +308,47 @@ U64 NtfsReadAttribute(PNTFS_ATTR_CONTEXT Context, U64 Offset, PCHAR Buffer, U64
|
|||
Context->CacheRun = DataRun;
|
||||
Context->CacheRunOffset = Offset + AlreadyRead;
|
||||
Context->CacheRunStartLCN = DataRunStartLCN;
|
||||
Context->CacheRunLength = DataRunLength;
|
||||
Context->CacheRunLastLCN = LastLCN;
|
||||
Context->CacheRunCurrentOffset = CurrentOffset;
|
||||
|
||||
return AlreadyRead;
|
||||
}
|
||||
|
||||
BOOL NtfsFixupRecord(PNTFS_RECORD Record)
|
||||
{
|
||||
U16 *USA;
|
||||
U16 USANumber;
|
||||
U16 USACount;
|
||||
U16 *Block;
|
||||
|
||||
USA = (U16*)((PCHAR)Record + Record->USAOffset);
|
||||
USANumber = *(USA++);
|
||||
USACount = Record->USACount - 1; /* Exclude the USA Number. */
|
||||
Block = (U16*)((PCHAR)Record + NtfsBootSector->BytesPerSector - 2);
|
||||
|
||||
while (USACount)
|
||||
{
|
||||
if (*Block != USANumber)
|
||||
return FALSE;
|
||||
*Block = *(USA++);
|
||||
Block = (U16*)((PCHAR)Block + NtfsBootSector->BytesPerSector);
|
||||
USACount--;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL NtfsReadMftRecord(U32 MFTIndex, PNTFS_MFT_RECORD Buffer)
|
||||
{
|
||||
return NtfsReadAttribute(&NtfsMFTContext, MFTIndex * NtfsMftRecordSize, (PCHAR)Buffer, NtfsMftRecordSize) == NtfsMftRecordSize;
|
||||
U64 BytesRead;
|
||||
|
||||
BytesRead = NtfsReadAttribute(&NtfsMFTContext, MFTIndex * NtfsMftRecordSize, (PCHAR)Buffer, NtfsMftRecordSize);
|
||||
if (BytesRead != NtfsMftRecordSize)
|
||||
return FALSE;
|
||||
|
||||
/* Apply update sequence array fixups. */
|
||||
return NtfsFixupRecord((PNTFS_RECORD)Buffer);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
@ -341,7 +387,7 @@ BOOL NtfsCompareFileName(PCHAR FileName, PNTFS_INDEX_ENTRY IndexEntry)
|
|||
return FALSE;
|
||||
|
||||
/* Do case-sensitive compares for Posix file names. */
|
||||
if (IndexEntry->FileName.FileNameType == FILE_NAME_POSIX)
|
||||
if (IndexEntry->FileName.FileNameType == NTFS_FILE_NAME_POSIX)
|
||||
{
|
||||
for (i = 0; i < EntryFileNameLength; i++)
|
||||
if (EntryFileName[i] != FileName[i])
|
||||
|
@ -383,7 +429,7 @@ BOOL NtfsFindMftRecord(U32 MFTIndex, PCHAR FileName, U32 *OutMFTIndex)
|
|||
{
|
||||
Magic = MftRecord->Magic;
|
||||
|
||||
if (!NtfsFindAttribute(&IndexRootCtx, MftRecord, ATTR_TYPE_INDEX_ROOT, L"$I30"))
|
||||
if (!NtfsFindAttribute(&IndexRootCtx, MftRecord, NTFS_ATTR_TYPE_INDEX_ROOT, L"$I30"))
|
||||
{
|
||||
MmFreeMemory(MftRecord);
|
||||
return FALSE;
|
||||
|
@ -405,7 +451,7 @@ BOOL NtfsFindMftRecord(U32 MFTIndex, PCHAR FileName, U32 *OutMFTIndex)
|
|||
DbgPrint((DPRINT_FILESYSTEM, "NtfsIndexRecordSize: %x IndexBlockSize: %x\n", NtfsIndexRecordSize, IndexRoot->IndexBlockSize));
|
||||
|
||||
while (IndexEntry < IndexEntryEnd &&
|
||||
!(IndexEntry->Flags & INDEX_ENTRY_END))
|
||||
!(IndexEntry->Flags & NTFS_INDEX_ENTRY_END))
|
||||
{
|
||||
if (NtfsCompareFileName(FileName, IndexEntry))
|
||||
{
|
||||
|
@ -417,13 +463,13 @@ BOOL NtfsFindMftRecord(U32 MFTIndex, PCHAR FileName, U32 *OutMFTIndex)
|
|||
IndexEntry = (PNTFS_INDEX_ENTRY)((PCHAR)IndexEntry + IndexEntry->Length);
|
||||
}
|
||||
|
||||
if (IndexRoot->IndexHeader.Flags & LARGE_INDEX)
|
||||
if (IndexRoot->IndexHeader.Flags & NTFS_LARGE_INDEX)
|
||||
{
|
||||
DbgPrint((DPRINT_FILESYSTEM, "Large Index!\n"));
|
||||
|
||||
IndexBlockSize = IndexRoot->IndexBlockSize;
|
||||
|
||||
if (!NtfsFindAttribute(&IndexBitmapCtx, MftRecord, ATTR_TYPE_BITMAP, L"$I30"))
|
||||
if (!NtfsFindAttribute(&IndexBitmapCtx, MftRecord, NTFS_ATTR_TYPE_BITMAP, L"$I30"))
|
||||
{
|
||||
DbgPrint((DPRINT_FILESYSTEM, "Corrupted filesystem!\n"));
|
||||
MmFreeMemory(MftRecord);
|
||||
|
@ -443,7 +489,7 @@ BOOL NtfsFindMftRecord(U32 MFTIndex, PCHAR FileName, U32 *OutMFTIndex)
|
|||
}
|
||||
NtfsReadAttribute(&IndexBitmapCtx, 0, BitmapData, BitmapDataSize);
|
||||
|
||||
if (!NtfsFindAttribute(&IndexAllocationCtx, MftRecord, ATTR_TYPE_INDEX_ALLOCATION, L"$I30"))
|
||||
if (!NtfsFindAttribute(&IndexAllocationCtx, MftRecord, NTFS_ATTR_TYPE_INDEX_ALLOCATION, L"$I30"))
|
||||
{
|
||||
DbgPrint((DPRINT_FILESYSTEM, "Corrupted filesystem!\n"));
|
||||
MmFreeMemory(BitmapData);
|
||||
|
@ -463,7 +509,7 @@ BOOL NtfsFindMftRecord(U32 MFTIndex, PCHAR FileName, U32 *OutMFTIndex)
|
|||
DbgPrint((DPRINT_FILESYSTEM, "RecordOffset: %x IndexAllocationSize: %x\n", RecordOffset, IndexAllocationSize));
|
||||
for (; RecordOffset < IndexAllocationSize;)
|
||||
{
|
||||
U8 Bit = 1 << ((RecordOffset / IndexBlockSize) & 3);
|
||||
U8 Bit = 1 << ((RecordOffset / IndexBlockSize) & 7);
|
||||
U32 Byte = (RecordOffset / IndexBlockSize) >> 3;
|
||||
if ((BitmapData[Byte] & Bit))
|
||||
break;
|
||||
|
@ -471,16 +517,23 @@ BOOL NtfsFindMftRecord(U32 MFTIndex, PCHAR FileName, U32 *OutMFTIndex)
|
|||
}
|
||||
|
||||
if (RecordOffset >= IndexAllocationSize)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
NtfsReadAttribute(&IndexAllocationCtx, RecordOffset, IndexRecord, IndexBlockSize);
|
||||
|
||||
if (!NtfsFixupRecord((PNTFS_RECORD)IndexRecord))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
/* FIXME */
|
||||
IndexEntry = (PNTFS_INDEX_ENTRY)(IndexRecord + 0x18 + *(U16 *)(IndexRecord + 0x18));
|
||||
IndexEntryEnd = (PNTFS_INDEX_ENTRY)(IndexRecord + IndexBlockSize);
|
||||
|
||||
while (IndexEntry < IndexEntryEnd &&
|
||||
!(IndexEntry->Flags & INDEX_ENTRY_END))
|
||||
!(IndexEntry->Flags & NTFS_INDEX_ENTRY_END))
|
||||
{
|
||||
if (NtfsCompareFileName(FileName, IndexEntry))
|
||||
{
|
||||
|
@ -520,7 +573,7 @@ BOOL NtfsLookupFile(PUCHAR FileName, PNTFS_MFT_RECORD MftRecord, PNTFS_ATTR_CONT
|
|||
|
||||
DbgPrint((DPRINT_FILESYSTEM, "NtfsLookupFile() FileName = %s\n", FileName));
|
||||
|
||||
CurrentMFTIndex = FILE_ROOT;
|
||||
CurrentMFTIndex = NTFS_FILE_ROOT;
|
||||
NumberOfPathParts = FsGetNumPathParts(FileName);
|
||||
for (i = 0; i < NumberOfPathParts; i++)
|
||||
{
|
||||
|
@ -545,7 +598,7 @@ BOOL NtfsLookupFile(PUCHAR FileName, PNTFS_MFT_RECORD MftRecord, PNTFS_ATTR_CONT
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
if (!NtfsFindAttribute(DataContext, MftRecord, ATTR_TYPE_DATA, L""))
|
||||
if (!NtfsFindAttribute(DataContext, MftRecord, NTFS_ATTR_TYPE_DATA, L""))
|
||||
{
|
||||
DbgPrint((DPRINT_FILESYSTEM, "NtfsLookupFile: Can't find data attribute\n"));
|
||||
return FALSE;
|
||||
|
@ -619,7 +672,7 @@ BOOL NtfsOpenVolume(U32 DriveNumber, U32 VolumeStartSector)
|
|||
RtlCopyMemory(NtfsMasterFileTable, (PCHAR)DISKREADBUFFER, NtfsMftRecordSize);
|
||||
|
||||
DbgPrint((DPRINT_FILESYSTEM, "Searching for DATA attribute...\n"));
|
||||
if (!NtfsFindAttribute(&NtfsMFTContext, NtfsMasterFileTable, ATTR_TYPE_DATA, L""))
|
||||
if (!NtfsFindAttribute(&NtfsMFTContext, NtfsMasterFileTable, NTFS_ATTR_TYPE_DATA, L""))
|
||||
{
|
||||
FileSystemError("Can't find data attribute for Master File Table.");
|
||||
return FALSE;
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
/*
|
||||
* FreeLoader
|
||||
* Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
|
||||
*
|
||||
* FreeLoader NTFS support
|
||||
* Copyright (C) 2004 Filip Navara <xnavara@volny.cz>
|
||||
*
|
||||
|
@ -23,47 +20,44 @@
|
|||
#ifndef __NTFS_H
|
||||
#define __NTFS_H
|
||||
|
||||
#ifdef NTFS_DEFS
|
||||
#define NTFS_FILE_MFT 0
|
||||
#define NTFS_FILE_MFTMIRR 1
|
||||
#define NTFS_FILE_LOGFILE 2
|
||||
#define NTFS_FILE_VOLUME 3
|
||||
#define NTFS_FILE_ATTRDEF 4
|
||||
#define NTFS_FILE_ROOT 5
|
||||
#define NTFS_FILE_BITMAP 6
|
||||
#define NTFS_FILE_BOOT 7
|
||||
#define NTFS_FILE_BADCLUS 8
|
||||
#define NTFS_FILE_QUOTA 9
|
||||
#define NTFS_FILE_UPCASE 10
|
||||
|
||||
#define FILE_MFT 0
|
||||
#define FILE_MFTMIRR 1
|
||||
#define FILE_LOGFILE 2
|
||||
#define FILE_VOLUME 3
|
||||
#define FILE_ATTRDEF 4
|
||||
#define FILE_ROOT 5
|
||||
#define FILE_BITMAP 6
|
||||
#define FILE_BOOT 7
|
||||
#define FILE_BADCLUS 8
|
||||
#define FILE_QUOTA 9
|
||||
#define FILE_UPCASE 10
|
||||
#define NTFS_ATTR_TYPE_STANDARD_INFORMATION 0x10
|
||||
#define NTFS_ATTR_TYPE_ATTRIBUTE_LIST 0x20
|
||||
#define NTFS_ATTR_TYPE_FILENAME 0x30
|
||||
#define NTFS_ATTR_TYPE_SECURITY_DESCRIPTOR 0x50
|
||||
#define NTFS_ATTR_TYPE_DATA 0x80
|
||||
#define NTFS_ATTR_TYPE_INDEX_ROOT 0x90
|
||||
#define NTFS_ATTR_TYPE_INDEX_ALLOCATION 0xa0
|
||||
#define NTFS_ATTR_TYPE_BITMAP 0xb0
|
||||
#define NTFS_ATTR_TYPE_SYMLINK 0xc0
|
||||
#define NTFS_ATTR_TYPE_END 0xffffffff
|
||||
|
||||
#define ATTR_TYPE_STANDARD_INFORMATION 0x10
|
||||
#define ATTR_TYPE_ATTRIBUTE_LIST 0x20
|
||||
#define ATTR_TYPE_FILENAME 0x30
|
||||
#define ATTR_TYPE_SECURITY_DESCRIPTOR 0x50
|
||||
#define ATTR_TYPE_DATA 0x80
|
||||
#define ATTR_TYPE_INDEX_ROOT 0x90
|
||||
#define ATTR_TYPE_INDEX_ALLOCATION 0xa0
|
||||
#define ATTR_TYPE_BITMAP 0xb0
|
||||
#define ATTR_TYPE_SYMLINK 0xc0
|
||||
#define ATTR_TYPE_END 0xffffffff
|
||||
#define NTFS_ATTR_NORMAL 0
|
||||
#define NTFS_ATTR_COMPRESSED 1
|
||||
#define NTFS_ATTR_RESIDENT 2
|
||||
#define NTFS_ATTR_ENCRYPTED 0x4000
|
||||
|
||||
#define ATTR_NORMAL 0
|
||||
#define ATTR_COMPRESSED 1
|
||||
#define ATTR_RESIDENT 2
|
||||
#define ATTR_ENCRYPTED 0x4000
|
||||
#define NTFS_SMALL_INDEX 0
|
||||
#define NTFS_LARGE_INDEX 1
|
||||
|
||||
#define SMALL_INDEX 0
|
||||
#define LARGE_INDEX 1
|
||||
#define NTFS_INDEX_ENTRY_NODE 1
|
||||
#define NTFS_INDEX_ENTRY_END 2
|
||||
|
||||
#define INDEX_ENTRY_NODE 1
|
||||
#define INDEX_ENTRY_END 2
|
||||
|
||||
#define FILE_NAME_POSIX 0
|
||||
#define FILE_NAME_WIN32 1
|
||||
#define FILE_NAME_DOS 2
|
||||
#define FILE_NAME_WIN32_AND_DOS 3
|
||||
#endif
|
||||
#define NTFS_FILE_NAME_POSIX 0
|
||||
#define NTFS_FILE_NAME_WIN32 1
|
||||
#define NTFS_FILE_NAME_DOS 2
|
||||
#define NTFS_FILE_NAME_WIN32_AND_DOS 3
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
@ -93,6 +87,13 @@ typedef struct
|
|||
U16 BootSectorMagic; // 0xAA55
|
||||
} PACKED NTFS_BOOTSECTOR, *PNTFS_BOOTSECTOR;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
U32 Magic;
|
||||
U16 USAOffset; // Offset to the Update Sequence Array from the start of the ntfs record
|
||||
U16 USACount;
|
||||
} PACKED NTFS_RECORD, *PNTFS_RECORD;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
U32 Magic;
|
||||
|
@ -206,6 +207,7 @@ typedef struct
|
|||
PUCHAR CacheRun;
|
||||
U64 CacheRunOffset;
|
||||
S64 CacheRunStartLCN;
|
||||
U64 CacheRunLength;
|
||||
S64 CacheRunLastLCN;
|
||||
U64 CacheRunCurrentOffset;
|
||||
} NTFS_ATTR_CONTEXT, *PNTFS_ATTR_CONTEXT;
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
|
||||
/* just some stuff */
|
||||
#define VERSION "FreeLoader v1.8.21"
|
||||
#define VERSION "FreeLoader v1.8.22"
|
||||
#define COPYRIGHT "Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>"
|
||||
#define AUTHOR_EMAIL "<brianp@sginet.com>"
|
||||
#define BY_AUTHOR "by Brian Palmer"
|
||||
|
@ -36,7 +36,7 @@
|
|||
//
|
||||
#define FREELOADER_MAJOR_VERSION 1
|
||||
#define FREELOADER_MINOR_VERSION 8
|
||||
#define FREELOADER_PATCH_VERSION 21
|
||||
#define FREELOADER_PATCH_VERSION 22
|
||||
|
||||
|
||||
#ifndef ASM
|
||||
|
|
Loading…
Reference in a new issue