Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
fc13836423
|
|||
f69b0a4214
|
|||
0ba79fd489
|
|||
e16284f3aa
|
|||
09e54a670a
|
|||
9827395c8c
|
|||
ef272847e1
|
|||
2271d6bde1
|
2
build.sh
2
build.sh
@@ -31,7 +31,7 @@ CMAKEVCS="https://gitlab.kitware.com/cmake/cmake.git"
|
|||||||
|
|
||||||
# LLVM Settings
|
# LLVM Settings
|
||||||
LLVMDIR="${SRCDIR}/llvm"
|
LLVMDIR="${SRCDIR}/llvm"
|
||||||
LLVMTAG="llvmorg-21.1.2"
|
LLVMTAG="llvmorg-21.1.3"
|
||||||
LLVMVCS="https://github.com/llvm/llvm-project.git"
|
LLVMVCS="https://github.com/llvm/llvm-project.git"
|
||||||
|
|
||||||
# Mtools Settings
|
# Mtools Settings
|
||||||
|
490
tools/diskimg.c
490
tools/diskimg.c
@@ -4,17 +4,28 @@
|
|||||||
* FILE: tools/diskimg.c
|
* FILE: tools/diskimg.c
|
||||||
* DESCRIPTION: Disk Image manipulation tool
|
* DESCRIPTION: Disk Image manipulation tool
|
||||||
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
|
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
|
||||||
|
* Aiken Harris <harraiken91@gmail.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "xtchain.h"
|
#include "xtchain.h"
|
||||||
|
|
||||||
|
|
||||||
|
static RESERVED_SECTOR_INFO Fat32ReservedMap[] =
|
||||||
|
{
|
||||||
|
{0, "Main VBR"},
|
||||||
|
{1, "FSInfo Sector"},
|
||||||
|
{6, "Backup VBR"},
|
||||||
|
{7, "Backup FSInfo Sector"},
|
||||||
|
{-1, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
/* Forward references */
|
/* Forward references */
|
||||||
static void CopyData(const char *Image, long Offset, const char *SourceDir, const char *Relative);
|
static void CopyData(const char *Image, long Offset, const char *SourceDir, const char *Relative);
|
||||||
static void CopyImageFile(const char *Image, long Offset, const char *SourceFile, const char *Relative);
|
static void CopyImageFile(const char *Image, long Offset, const char *SourceFile, const char *Relative);
|
||||||
|
static long DetermineExtraSector(long sectors_to_write);
|
||||||
|
long GetSectorFileSize(const char *FileName);
|
||||||
|
int LoadSectors(const char *FileName, uint8_t *Buffer, int SectorCount);
|
||||||
static void MakeDirectory(const char *Image, long Offset, const char *Relative);
|
static void MakeDirectory(const char *Image, long Offset, const char *Relative);
|
||||||
int LoadSector(const char *FileName, uint8_t *Buffer);
|
|
||||||
|
|
||||||
|
|
||||||
/* Copies a directory recursively to the image */
|
/* Copies a directory recursively to the image */
|
||||||
static void CopyData(const char *Image, long Offset, const char *SourceDir, const char *Relative)
|
static void CopyData(const char *Image, long Offset, const char *SourceDir, const char *Relative)
|
||||||
@@ -101,8 +112,53 @@ static void CopyImageFile(const char *Image, long Offset, const char *SourceFile
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Loads a sector from a file */
|
/* Determines a safe sector to write extra VBR data to */
|
||||||
int LoadSector(const char *FileName, uint8_t *Buffer)
|
static long DetermineExtraSector(long sectors_to_write)
|
||||||
|
{
|
||||||
|
long Candidate;
|
||||||
|
long Conflict;
|
||||||
|
long Index;
|
||||||
|
long LastSector;
|
||||||
|
|
||||||
|
/* Start search from sector 1 (sector 0 is the main VBR) */
|
||||||
|
for(Candidate = 1; Candidate < 32; Candidate++)
|
||||||
|
{
|
||||||
|
/* Calculate the last sector to write */
|
||||||
|
LastSector = Candidate + sectors_to_write - 1;
|
||||||
|
Conflict = 0;
|
||||||
|
|
||||||
|
/* Check if it fits within the reserved region (32 sectors) */
|
||||||
|
if(LastSector >= 32)
|
||||||
|
{
|
||||||
|
/* The remaining space is not large enough */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for conflicts with critical sectors */
|
||||||
|
for(Index = 0; Fat32ReservedMap[Index].SectorNumber != -1; Index++)
|
||||||
|
{
|
||||||
|
if(Candidate <= Fat32ReservedMap[Index].SectorNumber && LastSector >= Fat32ReservedMap[Index].SectorNumber)
|
||||||
|
{
|
||||||
|
/* Found a conflict */
|
||||||
|
Conflict = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure there are no conflicts */
|
||||||
|
if(!Conflict)
|
||||||
|
{
|
||||||
|
/* Found a suitable slot */
|
||||||
|
return Candidate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No suitable slot found */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Gets the size of a file */
|
||||||
|
long GetSectorFileSize(const char *FileName)
|
||||||
{
|
{
|
||||||
FILE *File;
|
FILE *File;
|
||||||
long Size;
|
long Size;
|
||||||
@@ -112,27 +168,53 @@ int LoadSector(const char *FileName, uint8_t *Buffer)
|
|||||||
if(!File)
|
if(!File)
|
||||||
{
|
{
|
||||||
/* Failed to open file */
|
/* Failed to open file */
|
||||||
perror("Failed to open sector file");
|
perror("Failed to open file for size check");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check the file size */
|
/* Get the file size */
|
||||||
fseek(File, 0, SEEK_END);
|
fseek(File, 0, SEEK_END);
|
||||||
Size = ftell(File);
|
Size = ftell(File);
|
||||||
fseek(File, 0, SEEK_SET);
|
|
||||||
if(Size != SECTOR_SIZE)
|
/* Close the file and return the size */
|
||||||
{
|
|
||||||
/* File is not exactly 512 bytes */
|
|
||||||
fprintf(stderr, "Error: file '%s' must be exactly 512 bytes.\n", FileName);
|
|
||||||
fclose(File);
|
fclose(File);
|
||||||
|
return Size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Loads one or more sectors from a file */
|
||||||
|
int LoadSectors(const char *FileName, uint8_t *Buffer, int SectorCount)
|
||||||
|
{
|
||||||
|
FILE *File;
|
||||||
|
long FileSize;
|
||||||
|
long BytesToRead = SectorCount * SECTOR_SIZE;
|
||||||
|
|
||||||
|
/* Get and validate file size */
|
||||||
|
FileSize = GetSectorFileSize(FileName);
|
||||||
|
if(FileSize < 0)
|
||||||
|
{
|
||||||
|
/* Failed to get file size */
|
||||||
|
perror("Failed to get file size");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(FileSize != BytesToRead)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error: file '%s' must be exactly %ld bytes, but is %ld bytes.\n", FileName, BytesToRead, FileSize);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read sector to buffer */
|
/* Open the file in binary mode for reading */
|
||||||
if(fread(Buffer, 1, SECTOR_SIZE, File) != SECTOR_SIZE)
|
File = fopen(FileName, "rb");
|
||||||
|
if(!File) {
|
||||||
|
/* Failed to open file */
|
||||||
|
perror("Failed to open sector file for reading");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read sectors to buffer */
|
||||||
|
if(fread(Buffer, 1, BytesToRead, File) != BytesToRead)
|
||||||
{
|
{
|
||||||
/* Failed to read sector */
|
/* Failed to read sectors */
|
||||||
perror("Failed to read sector from file");
|
perror("Failed to read sectors from file");
|
||||||
fclose(File);
|
fclose(File);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -156,63 +238,86 @@ static void MakeDirectory(const char *Image, long Offset, const char *Relative)
|
|||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
FILE *File;
|
FILE *File;
|
||||||
|
long Index;
|
||||||
long FatFormat = 32;
|
long FatFormat = 32;
|
||||||
char FormatCommand[512];
|
char FormatCommand[512];
|
||||||
long FormatPartition = 0;
|
long FormatPartition = 0;
|
||||||
long DiskSizeBytes = 0;
|
long DiskSizeBytes = 0;
|
||||||
long DiskSizeMB = 0;
|
long DiskSizeMB = 0;
|
||||||
|
long MergedSize = 0;
|
||||||
|
long PreloaderSize = 0;
|
||||||
|
long SectorsToWrite = 0;
|
||||||
|
long VbrExtraSector = -1;
|
||||||
|
long VbrFileSize = -1;
|
||||||
|
long VbrTotalSectors = 0;
|
||||||
|
long VbrLastSector = 99;
|
||||||
|
char VbrInfo[128] = "";
|
||||||
MBR_PARTITION Partition = {0};
|
MBR_PARTITION Partition = {0};
|
||||||
char Zero[SECTOR_SIZE] = {0};
|
char Zero[SECTOR_SIZE] = {0};
|
||||||
uint8_t Mbr[SECTOR_SIZE] = {0};
|
uint8_t Mbr[SECTOR_SIZE] = {0};
|
||||||
uint8_t Vbr[SECTOR_SIZE];
|
uint8_t ImageVbr[SECTOR_SIZE * 2] = {0};
|
||||||
|
uint8_t *MergedData = NULL;
|
||||||
|
uint8_t *PreloaderData = NULL;
|
||||||
|
uint8_t *FullVbrData = NULL;
|
||||||
const char *FileName = NULL;
|
const char *FileName = NULL;
|
||||||
const char *MbrFile = NULL;
|
const char *MbrFile = NULL;
|
||||||
|
const char *PreloadFile = NULL;
|
||||||
const char *VbrFile = NULL;
|
const char *VbrFile = NULL;
|
||||||
const char *CopyDir = NULL;
|
const char *CopyDir = NULL;
|
||||||
|
|
||||||
/* Parse command line arguments */
|
/* Parse command line arguments */
|
||||||
for(int i = 1; i < argc; i++)
|
for(Index = 1; Index < argc; Index++)
|
||||||
{
|
{
|
||||||
if(strcmp(argv[i], "-c") == 0 && i + 1 < argc)
|
if(strcmp(argv[Index], "-c") == 0 && Index + 1 < argc)
|
||||||
{
|
{
|
||||||
/* Copy directory */
|
/* Copy directory */
|
||||||
CopyDir = argv[++i];
|
CopyDir = argv[++Index];
|
||||||
}
|
}
|
||||||
else if(strcmp(argv[i], "-f") == 0 && i + 1 < argc)
|
else if(strcmp(argv[Index], "-e") == 0 && Index + 1 < argc)
|
||||||
|
{
|
||||||
|
/* VBR extra data sector */
|
||||||
|
VbrExtraSector = atol(argv[++Index]);
|
||||||
|
}
|
||||||
|
else if(strcmp(argv[Index], "-f") == 0 && Index + 1 < argc)
|
||||||
{
|
{
|
||||||
/* Format partition */
|
/* Format partition */
|
||||||
FormatPartition = 1;
|
FormatPartition = 1;
|
||||||
FatFormat = atoi(argv[++i]);
|
FatFormat = atoi(argv[++Index]);
|
||||||
if(FatFormat != 16 && FatFormat != 32)
|
if(FatFormat != 16 && FatFormat != 32)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Error: FAT format (-f) must be 16 or 32\n");
|
fprintf(stderr, "Error: FAT format (-f) must be 16 or 32\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(strcmp(argv[i], "-m") == 0 && i + 1 < argc)
|
else if(strcmp(argv[Index], "-m") == 0 && Index + 1 < argc)
|
||||||
{
|
{
|
||||||
/* MBR file */
|
/* MBR file */
|
||||||
MbrFile = argv[++i];
|
MbrFile = argv[++Index];
|
||||||
}
|
}
|
||||||
else if(strcmp(argv[i], "-o") == 0 && i + 1 < argc)
|
else if(strcmp(argv[Index], "-o") == 0 && Index + 1 < argc)
|
||||||
{
|
{
|
||||||
/* Output file */
|
/* Output file */
|
||||||
FileName = argv[++i];
|
FileName = argv[++Index];
|
||||||
}
|
}
|
||||||
else if(strcmp(argv[i], "-s") == 0 && i + 1 < argc)
|
else if(strcmp(argv[Index], "-p") == 0 && Index + 1 < argc)
|
||||||
|
{
|
||||||
|
/* Preloader file */
|
||||||
|
PreloadFile = argv[++Index];
|
||||||
|
}
|
||||||
|
else if(strcmp(argv[Index], "-s") == 0 && Index + 1 < argc)
|
||||||
{
|
{
|
||||||
/* Disk size */
|
/* Disk size */
|
||||||
DiskSizeMB = atol(argv[++i]);
|
DiskSizeMB = atol(argv[++Index]);
|
||||||
}
|
}
|
||||||
else if(strcmp(argv[i], "-v") == 0 && i + 1 < argc)
|
else if(strcmp(argv[Index], "-v") == 0 && Index + 1 < argc)
|
||||||
{
|
{
|
||||||
/* VBR file */
|
/* VBR file */
|
||||||
VbrFile = argv[++i];
|
VbrFile = argv[++Index];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Unknown argument */
|
/* Unknown argument */
|
||||||
fprintf(stderr, "Unknown argument: %s\n", argv[i]);
|
fprintf(stderr, "Unknown argument: %s\n", argv[Index]);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -221,7 +326,15 @@ int main(int argc, char **argv)
|
|||||||
if(DiskSizeMB <= 0 || FileName == NULL)
|
if(DiskSizeMB <= 0 || FileName == NULL)
|
||||||
{
|
{
|
||||||
/* Missing required arguments, print usage */
|
/* Missing required arguments, print usage */
|
||||||
fprintf(stderr, "Usage: %s -o <output.img> -s <size_MB> [-c <dir>] [-f 16|32] [-m <mbr.img>] [-v <vbr.img>]\n", argv[0]);
|
fprintf(stderr, "Usage: %s -o <output.img> -s <size_MB> [-b <sector>] [-c <dir>] [-f 16|32] [-m <mbr.img>] [-p <preload.bin>] [-v <vbr.img>]\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Validate preload usage */
|
||||||
|
if(PreloadFile && !VbrFile)
|
||||||
|
{
|
||||||
|
/* Preloader code specified without VBR */
|
||||||
|
fprintf(stderr, "Error: Option -p (PRELOADER code) requires -v (VBR code) to be specified as well.\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,7 +350,7 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Write zeros to the disk image file */
|
/* Write zeros to the disk image file */
|
||||||
for(long i = 0; i < DiskSizeBytes / SECTOR_SIZE; i++)
|
for(Index = 0; Index < DiskSizeBytes / SECTOR_SIZE; Index++)
|
||||||
{
|
{
|
||||||
if(fwrite(Zero, 1, SECTOR_SIZE, File) != SECTOR_SIZE)
|
if(fwrite(Zero, 1, SECTOR_SIZE, File) != SECTOR_SIZE)
|
||||||
{
|
{
|
||||||
@@ -251,7 +364,7 @@ int main(int argc, char **argv)
|
|||||||
/* Load MBR if provided */
|
/* Load MBR if provided */
|
||||||
if(MbrFile)
|
if(MbrFile)
|
||||||
{
|
{
|
||||||
if(LoadSector(MbrFile, Mbr) != 0)
|
if(LoadSectors(MbrFile, Mbr, 1) != 0)
|
||||||
{
|
{
|
||||||
/* Failed to load MBR from file */
|
/* Failed to load MBR from file */
|
||||||
perror("Failed to load MBR from file");
|
perror("Failed to load MBR from file");
|
||||||
@@ -264,7 +377,7 @@ int main(int argc, char **argv)
|
|||||||
Partition.BootFlag = 0x80;
|
Partition.BootFlag = 0x80;
|
||||||
Partition.Type = (FatFormat == 16) ? 0x06 : 0x0B;
|
Partition.Type = (FatFormat == 16) ? 0x06 : 0x0B;
|
||||||
Partition.StartLBA = 2048;
|
Partition.StartLBA = 2048;
|
||||||
Partition.Size = (DiskSizeBytes / SECTOR_SIZE) - 2048;
|
Partition.Size = (DiskSizeBytes / SECTOR_SIZE) - Partition.StartLBA;
|
||||||
|
|
||||||
/* Write MBR */
|
/* Write MBR */
|
||||||
memcpy(&Mbr[446], &Partition, sizeof(MBR_PARTITION));
|
memcpy(&Mbr[446], &Partition, sizeof(MBR_PARTITION));
|
||||||
@@ -275,6 +388,7 @@ int main(int argc, char **argv)
|
|||||||
fseek(File, 0, SEEK_SET);
|
fseek(File, 0, SEEK_SET);
|
||||||
if(fwrite(Mbr, 1, SECTOR_SIZE, File) != SECTOR_SIZE)
|
if(fwrite(Mbr, 1, SECTOR_SIZE, File) != SECTOR_SIZE)
|
||||||
{
|
{
|
||||||
|
/* Failed to write MBR to disk image */
|
||||||
perror("Failed to write MBR to disk image");
|
perror("Failed to write MBR to disk image");
|
||||||
fclose(File);
|
fclose(File);
|
||||||
return 1;
|
return 1;
|
||||||
@@ -302,6 +416,7 @@ int main(int argc, char **argv)
|
|||||||
FileName, (long)(Partition.StartLBA * SECTOR_SIZE));
|
FileName, (long)(Partition.StartLBA * SECTOR_SIZE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Format the partition */
|
||||||
if(system(FormatCommand) != 0)
|
if(system(FormatCommand) != 0)
|
||||||
{
|
{
|
||||||
/* Failed to format partition */
|
/* Failed to format partition */
|
||||||
@@ -316,26 +431,290 @@ int main(int argc, char **argv)
|
|||||||
perror("Failed to reopen disk image");
|
perror("Failed to reopen disk image");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* Write VBR to the start of the partition, if provided */
|
/* Read the VBR created by mformat */
|
||||||
if(VbrFile)
|
fseek(File, Partition.StartLBA * SECTOR_SIZE, SEEK_SET);
|
||||||
|
if(fread(ImageVbr, 1, SECTOR_SIZE, File) != SECTOR_SIZE)
|
||||||
{
|
{
|
||||||
if (LoadSector(VbrFile, Vbr) != 0) {
|
/* Failed to read VBR */
|
||||||
|
perror("Failed to read VBR from disk image");
|
||||||
fclose(File);
|
fclose(File);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
/* Seek to the start of the partition and write VBR */
|
|
||||||
fseek(File, Partition.StartLBA * SECTOR_SIZE, SEEK_SET);
|
/* Set the number of hidden sectors, as mformat sets it to 0 */
|
||||||
if(fwrite(Vbr, 1, SECTOR_SIZE, File) != SECTOR_SIZE)
|
if(*(uint32_t*)&ImageVbr[0x1C] == 0)
|
||||||
{
|
{
|
||||||
/* Failed to write VBR to disk image */
|
memcpy(&ImageVbr[0x1C], &Partition.StartLBA, sizeof(uint32_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check FAT format */
|
||||||
|
if(FatFormat == 32)
|
||||||
|
{
|
||||||
|
/* For FAT32, TotalSectors32 must be set */
|
||||||
|
*(uint16_t*)&ImageVbr[0x13] = 0;
|
||||||
|
if(*(uint32_t*)&ImageVbr[0x20] == 0)
|
||||||
|
{
|
||||||
|
/* Mformat did not set the field, update it */
|
||||||
|
memcpy(&ImageVbr[0x20], &Partition.Size, sizeof(uint32_t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* For FAT16, check if parition size exceeds 65535 sectors */
|
||||||
|
if(Partition.Size < 65536)
|
||||||
|
{
|
||||||
|
/* Partition smaller than 32MB (65536 sectors), use 16-bit field TotalSectors16 */
|
||||||
|
if(*(uint16_t*)&ImageVbr[0x13] == 0)
|
||||||
|
{
|
||||||
|
/* Mformat did not set the field, update it */
|
||||||
|
memcpy(&ImageVbr[0x13], &((uint16_t){Partition.Size}), sizeof(uint16_t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Partition larger than 32MB (65536 sectors), use 32-bit field TotalSectors32 */
|
||||||
|
*(uint16_t*)&ImageVbr[0x13] = 0;
|
||||||
|
if(*(uint32_t*)&ImageVbr[0x20] == 0)
|
||||||
|
{
|
||||||
|
/* Mformat did not set the field, update it */
|
||||||
|
memcpy(&ImageVbr[0x20], &Partition.Size, sizeof(uint32_t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set DriveNumber to emulate hard disk */
|
||||||
|
ImageVbr[0x40] = 0x80;
|
||||||
|
|
||||||
|
/* Write the corrected VBR back to the disk image */
|
||||||
|
fseek(File, Partition.StartLBA * SECTOR_SIZE, SEEK_SET);
|
||||||
|
if(fwrite(ImageVbr, 1, SECTOR_SIZE, File) != SECTOR_SIZE)
|
||||||
|
{
|
||||||
|
/* Failed to write VBR */
|
||||||
perror("Failed to write VBR to disk image");
|
perror("Failed to write VBR to disk image");
|
||||||
fclose(File);
|
fclose(File);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Write VBR to the start of the partition, if provided */
|
||||||
|
if(VbrFile)
|
||||||
|
{
|
||||||
|
VbrFileSize = GetSectorFileSize(VbrFile);
|
||||||
|
if(VbrFileSize < 0)
|
||||||
|
{
|
||||||
|
/* Unable to determine VBR file size */
|
||||||
|
perror("Could not get size of VBR file\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if VBR file size is a multiple of sector size */
|
||||||
|
if(VbrFileSize % SECTOR_SIZE != 0)
|
||||||
|
{
|
||||||
|
/* Unable to determine VBR file size */
|
||||||
|
perror("VBR file size is not a multiple of sector size\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Calculate number of VBR sectors */
|
||||||
|
VbrTotalSectors = VbrFileSize / SECTOR_SIZE;
|
||||||
|
|
||||||
|
/* Allocate memory for the entire VBR file */
|
||||||
|
FullVbrData = malloc(VbrFileSize);
|
||||||
|
if(!FullVbrData)
|
||||||
|
{
|
||||||
|
/* Memory allocation failed */
|
||||||
|
perror("Failed to allocate memory for VBR file\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read the entire VBR file into the buffer */
|
||||||
|
if(LoadSectors(VbrFile, FullVbrData, VbrTotalSectors) != 0)
|
||||||
|
{
|
||||||
|
/* Failed to load VBR from file */
|
||||||
|
perror("Failed to load VBR from file\n");
|
||||||
|
free(FullVbrData);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read the existing VBR from the formatted partition to get the correct BPB */
|
||||||
|
fseek(File, Partition.StartLBA * SECTOR_SIZE, SEEK_SET);
|
||||||
|
if(fread(ImageVbr, 1, SECTOR_SIZE, File) != SECTOR_SIZE)
|
||||||
|
{
|
||||||
|
/* Failed to read VBR from disk image */
|
||||||
|
perror("Failed to read BPB from disk image\n");
|
||||||
|
free(FullVbrData);
|
||||||
|
fclose(File);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the BPB from the image's VBR to VBR buffer */
|
||||||
|
if(FatFormat == 32)
|
||||||
|
{
|
||||||
|
/* For FAT32, BPB is larger (up to offset 89) */
|
||||||
|
memcpy(&FullVbrData[3], &ImageVbr[3], 87);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* For FAT16, BPB is smaller (up to offset 61) */
|
||||||
|
memcpy(&FullVbrData[3], &ImageVbr[3], 59);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write the first 512 bytes of the final, merged VBR to the start of the partition */
|
||||||
|
fseek(File, Partition.StartLBA * SECTOR_SIZE, SEEK_SET);
|
||||||
|
if(fwrite(FullVbrData, 1, SECTOR_SIZE, File) != SECTOR_SIZE)
|
||||||
|
{
|
||||||
|
/* Failed to write VBR to disk image */
|
||||||
|
perror("Failed to write VBR to disk image\n");
|
||||||
|
free(FullVbrData);
|
||||||
|
fclose(File);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle extra VBR data if it exists */
|
||||||
|
if(FatFormat == 32)
|
||||||
|
{
|
||||||
|
/* Check if a preloader file was provided */
|
||||||
|
if(PreloadFile)
|
||||||
|
{
|
||||||
|
/* Get the size of the preloader file */
|
||||||
|
PreloaderSize = GetSectorFileSize(PreloadFile);
|
||||||
|
if(PreloaderSize < 0)
|
||||||
|
{
|
||||||
|
/* Unable to determine preloader file size */
|
||||||
|
perror("Could not get size of preloader file.\n");
|
||||||
|
free(FullVbrData);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if preloader size is multiple of 512 bytes */
|
||||||
|
if(PreloaderSize % SECTOR_SIZE != 0)
|
||||||
|
{
|
||||||
|
/* Preloader file size is not a multiple of 512 bytes */
|
||||||
|
perror("Preloader file size is not a multiple of sector size\n");
|
||||||
|
free(FullVbrData);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate buffer for preloader */
|
||||||
|
PreloaderData = malloc((size_t)PreloaderSize);
|
||||||
|
if(!PreloaderData)
|
||||||
|
{
|
||||||
|
/* Memory allocation failed */
|
||||||
|
perror("Failed to allocate memory for preloader");
|
||||||
|
free(FullVbrData);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Load preloader data */
|
||||||
|
if(LoadSectors(PreloadFile, PreloaderData, PreloaderSize / SECTOR_SIZE) != 0)
|
||||||
|
{
|
||||||
|
/* Failed to load preloader data */
|
||||||
|
perror("Failed to load Preloader code from file\n");
|
||||||
|
free(FullVbrData);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate new buffer for the first 512 bytes of VBR and preloader */
|
||||||
|
MergedSize = SECTOR_SIZE + PreloaderSize;
|
||||||
|
MergedData = malloc(MergedSize);
|
||||||
|
if(!MergedData)
|
||||||
|
{
|
||||||
|
/* Memory allocation failed */
|
||||||
|
perror("Failed to allocate memory for Preloader file\n");
|
||||||
|
free(PreloaderData);
|
||||||
|
free(FullVbrData);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Merge VBR and preloader data */
|
||||||
|
memcpy(MergedData, FullVbrData, SECTOR_SIZE);
|
||||||
|
memcpy(MergedData + SECTOR_SIZE, PreloaderData, PreloaderSize);
|
||||||
|
|
||||||
|
/* Free old buffers and replace with merged data */
|
||||||
|
free(FullVbrData);
|
||||||
|
free(PreloaderData);
|
||||||
|
FullVbrData = MergedData;
|
||||||
|
|
||||||
|
/* Update VBR sectors count */
|
||||||
|
VbrTotalSectors = (MergedSize + SECTOR_SIZE - 1) / SECTOR_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if there is extra VBR data to write */
|
||||||
|
if(VbrTotalSectors > 1)
|
||||||
|
{
|
||||||
|
/* Check if extra sector has been provided by the user */
|
||||||
|
if(VbrExtraSector == -1)
|
||||||
|
{
|
||||||
|
/* Determine a safe sector to write extra VBR data to */
|
||||||
|
long sectors_to_write = VbrTotalSectors - 1;
|
||||||
|
VbrExtraSector = DetermineExtraSector(sectors_to_write);
|
||||||
|
if(VbrExtraSector == -1)
|
||||||
|
{
|
||||||
|
/* Failed to find a safe sector */
|
||||||
|
fprintf(stderr, "Error: Could not automatically find a safe space in the FAT32 reserved region for %ld extra VBR sectors.\n",
|
||||||
|
sectors_to_write);
|
||||||
|
free(FullVbrData);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Calculate number of sectors and last sector to write */
|
||||||
|
SectorsToWrite = VbrTotalSectors - 1;
|
||||||
|
VbrLastSector = VbrExtraSector + SectorsToWrite - 1;
|
||||||
|
|
||||||
|
/* Ensure VBR will not be writen outside the reserved region (32 sectors for FAT32) */
|
||||||
|
if(VbrLastSector >= 32)
|
||||||
|
{
|
||||||
|
/* The remaining space is not large enough to fit the extra VBR data */
|
||||||
|
fprintf(stderr, "Error: VBR file is too large. Writing to sector %ld would exceed the FAT32 reserved region (32 sectors).\n", VbrLastSector);
|
||||||
|
free(FullVbrData);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Safety check: ensure we do not overwrite critical sectors */
|
||||||
|
for(Index = 0; Fat32ReservedMap[Index].SectorNumber != -1; Index++)
|
||||||
|
{
|
||||||
|
/* Check if we are about to overwrite a critical sector */
|
||||||
|
if(VbrExtraSector <= Fat32ReservedMap[Index].SectorNumber && VbrLastSector >= Fat32ReservedMap[Index].SectorNumber)
|
||||||
|
{
|
||||||
|
/* We are about to overwrite a critical sector */
|
||||||
|
fprintf(stderr, "Error: Writing VBR extra data would overwrite critical sector %d (%s).\n",
|
||||||
|
Fat32ReservedMap[Index].SectorNumber, Fat32ReservedMap[Index].Description);
|
||||||
|
free(FullVbrData);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write the rest of the VBR data */
|
||||||
|
fseek(File, (Partition.StartLBA + VbrExtraSector) * SECTOR_SIZE, SEEK_SET);
|
||||||
|
if(fwrite(FullVbrData + SECTOR_SIZE, 1, SectorsToWrite * SECTOR_SIZE, File) != (size_t)(SectorsToWrite * SECTOR_SIZE))
|
||||||
|
{
|
||||||
|
/* Failed to write extra VBR data to disk image */
|
||||||
|
perror("Failed to write extra VBR data to disk image");
|
||||||
|
free(FullVbrData);
|
||||||
|
fclose(File);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else /* FatFormat == 16 */
|
||||||
|
{
|
||||||
|
/* Check if there is extra VBR data to write */
|
||||||
|
if(VbrTotalSectors > 1 || PreloadFile)
|
||||||
|
{
|
||||||
|
/* FAT16 only supports a 1-sector VBR */
|
||||||
|
fprintf(stderr, "Error: FAT16 does not support multi-sector VBR or preloader data.\n");
|
||||||
|
free(FullVbrData);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free allocated memory */
|
||||||
|
free(FullVbrData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Close file */
|
||||||
fclose(File);
|
fclose(File);
|
||||||
|
|
||||||
/* Copy files if requested */
|
/* Copy files if requested */
|
||||||
@@ -344,12 +723,37 @@ int main(int argc, char **argv)
|
|||||||
CopyData(FileName, (long)(Partition.StartLBA * SECTOR_SIZE), CopyDir, "");
|
CopyData(FileName, (long)(Partition.StartLBA * SECTOR_SIZE), CopyDir, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check if VBR was written */
|
||||||
|
if(VbrFile)
|
||||||
|
{
|
||||||
|
/* Compose VBR info string */
|
||||||
|
if(VbrExtraSector != -1)
|
||||||
|
{
|
||||||
|
if(PreloadFile)
|
||||||
|
{
|
||||||
|
/* Preloader written */
|
||||||
|
snprintf(VbrInfo, sizeof(VbrInfo), ", VBR written (preloader at sector %ld)", VbrExtraSector);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* VBR with extra data */
|
||||||
|
snprintf(VbrInfo, sizeof(VbrInfo), ", VBR written (extra data at sector %ld)", VbrExtraSector);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Standard VBR */
|
||||||
|
snprintf(VbrInfo, sizeof(VbrInfo), ", VBR written");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Print success message */
|
||||||
printf("Successfully created disk image '%s' (%ld MB) with bootable W95 FAT-%ld partition%s%s%s.\n",
|
printf("Successfully created disk image '%s' (%ld MB) with bootable W95 FAT-%ld partition%s%s%s.\n",
|
||||||
FileName,
|
FileName,
|
||||||
DiskSizeMB,
|
DiskSizeMB,
|
||||||
FatFormat,
|
FatFormat,
|
||||||
MbrFile ? ", MBR written" : "",
|
MbrFile ? ", MBR written" : "",
|
||||||
VbrFile ? ", VBR written" : "",
|
VbrInfo,
|
||||||
CopyDir ? ", files copied" : "");
|
CopyDir ? ", files copied" : "");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@@ -36,6 +36,12 @@ typedef struct MBR_PARTITION {
|
|||||||
uint32_t Size; // Sectors count
|
uint32_t Size; // Sectors count
|
||||||
} MBR_PARTITION, *PMBR_PARTITION;
|
} MBR_PARTITION, *PMBR_PARTITION;
|
||||||
|
|
||||||
|
typedef struct _RESERVED_SECTOR_INFO
|
||||||
|
{
|
||||||
|
int SectorNumber;
|
||||||
|
const char* Description;
|
||||||
|
} RESERVED_SECTOR_INFO, *PRESERVED_SECTOR_INFO;
|
||||||
|
|
||||||
static
|
static
|
||||||
inline
|
inline
|
||||||
char *
|
char *
|
||||||
|
Reference in New Issue
Block a user