Import disk image manipulation tool
This commit is contained in:
2
build.sh
2
build.sh
@@ -408,7 +408,7 @@ xtchain_build()
|
||||
echo ">>> Building XTchain tools ..."
|
||||
mkdir -p ${BINDIR}/bin
|
||||
mkdir -p ${BINDIR}/lib/xtchain
|
||||
for EXEC in bin2c exetool xtcspecc; do
|
||||
for EXEC in bin2c diskimg exetool xtcspecc; do
|
||||
if [ ! -e ${BINDIR}/bin/${EXEC} ]; then
|
||||
${CCOMPILER} ${WRKDIR}/tools/${EXEC}.c -o ${BINDIR}/bin/${EXEC}
|
||||
fi
|
||||
|
186
tools/diskimg.c
Normal file
186
tools/diskimg.c
Normal file
@@ -0,0 +1,186 @@
|
||||
/**
|
||||
* PROJECT: XTchain
|
||||
* LICENSE: See COPYING.md in the top level directory
|
||||
* FILE: tools/diskimg.c
|
||||
* DESCRIPTION: Disk Image manipulation tool
|
||||
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
|
||||
*/
|
||||
|
||||
#include "xtchain.h"
|
||||
|
||||
|
||||
/* Loads a sector from a file */
|
||||
int LoadSector(const char *FileName, uint8_t *Buffer)
|
||||
{
|
||||
FILE *File;
|
||||
long Size;
|
||||
|
||||
/* Open the file in binary mode */
|
||||
File= fopen(FileName, "rb");
|
||||
if(!File)
|
||||
{
|
||||
/* Failed to open file */
|
||||
perror("Failed to open sector file");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check the file size */
|
||||
fseek(File, 0, SEEK_END);
|
||||
Size = ftell(File);
|
||||
fseek(File, 0, SEEK_SET);
|
||||
if(Size != SECTOR_SIZE)
|
||||
{
|
||||
/* File is not exactly 512 bytes */
|
||||
fprintf(stderr, "Error: file '%s' must be exactly 512 bytes.\n", FileName);
|
||||
fclose(File);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Read sector to buffer */
|
||||
if(fread(Buffer, 1, SECTOR_SIZE, File) != SECTOR_SIZE)
|
||||
{
|
||||
/* Failed to read sector */
|
||||
perror("Failed to read sector from file");
|
||||
fclose(File);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Close the file */
|
||||
fclose(File);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Main function */
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
FILE *File;
|
||||
long DiskSizeBytes = 0;
|
||||
long DiskSizeMB = 0;
|
||||
MBR_PARTITION Partition = {0};
|
||||
char Zero[SECTOR_SIZE] = {0};
|
||||
uint8_t Mbr[SECTOR_SIZE] = {0};
|
||||
uint8_t Vbr[SECTOR_SIZE];
|
||||
const char *FileName = NULL;
|
||||
const char *MbrFile = NULL;
|
||||
const char *VbrFile = NULL;
|
||||
|
||||
/* Parse command line arguments */
|
||||
for(int i = 1; i < argc; i++)
|
||||
{
|
||||
if(strcmp(argv[i], "-s") == 0 && i + 1 < argc)
|
||||
{
|
||||
/* Disk size */
|
||||
DiskSizeMB = atol(argv[++i]);
|
||||
}
|
||||
else if(strcmp(argv[i], "-o") == 0 && i + 1 < argc)
|
||||
{
|
||||
/* Output file */
|
||||
FileName = argv[++i];
|
||||
}
|
||||
else if(strcmp(argv[i], "-m") == 0 && i + 1 < argc)
|
||||
{
|
||||
/* MBR file */
|
||||
MbrFile = argv[++i];
|
||||
}
|
||||
else if(strcmp(argv[i], "-v") == 0 && i + 1 < argc)
|
||||
{
|
||||
/* VBR file */
|
||||
VbrFile = argv[++i];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Unknown argument */
|
||||
fprintf(stderr, "Unknown argument: %s\n", argv[i]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for required arguments */
|
||||
if(DiskSizeMB <= 0 || FileName == NULL)
|
||||
{
|
||||
/* Missing required arguments, print usage */
|
||||
fprintf(stderr, "Usage: %s -s <size_MB> -o <output.img> [-m <mbr.img>] [-v <vbr.img>]\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Calculate disk size in bytes */
|
||||
DiskSizeBytes = DiskSizeMB * 1024 * 1024;
|
||||
|
||||
/* Open the output file in binary mode */
|
||||
File = fopen(FileName, "wb");
|
||||
if(!File) {
|
||||
/* Failed to open file */
|
||||
perror("Failed to open disk image file");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Write zeros to the disk image file */
|
||||
for(long i = 0; i < DiskSizeBytes / SECTOR_SIZE; i++)
|
||||
{
|
||||
if(fwrite(Zero, 1, SECTOR_SIZE, File) != SECTOR_SIZE)
|
||||
{
|
||||
/* Failed to write to disk image file */
|
||||
perror("Failed to write to disk image file");
|
||||
fclose(File);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Load MBR if provided */
|
||||
if(MbrFile)
|
||||
{
|
||||
if(LoadSector(MbrFile, Mbr) != 0)
|
||||
{
|
||||
/* Failed to load MBR from file */
|
||||
perror("Failed to load MBR from file");
|
||||
fclose(File);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Setup MBR partition as W95 FAT32 */
|
||||
Partition.BootFlag = 0x80;
|
||||
Partition.Type = 0x0B;
|
||||
Partition.StartLBA = 2048;
|
||||
Partition.Size = (DiskSizeBytes / SECTOR_SIZE) - 2048;
|
||||
|
||||
/* Write MBR */
|
||||
memcpy(&Mbr[446], &Partition, sizeof(MBR_PARTITION));
|
||||
Mbr[510] = 0x55;
|
||||
Mbr[511] = 0xAA;
|
||||
|
||||
/* Write the MBR to the beginning of the disk image */
|
||||
fseek(File, 0, SEEK_SET);
|
||||
if(fwrite(Mbr, 1, SECTOR_SIZE, File) != SECTOR_SIZE)
|
||||
{
|
||||
perror("Failed to write MBR to disk image");
|
||||
fclose(File);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Write VBR to the start of the partition, if provided */
|
||||
if(VbrFile)
|
||||
{
|
||||
if (LoadSector(VbrFile, Vbr) != 0) {
|
||||
fclose(File);
|
||||
return 1;
|
||||
}
|
||||
/* Seek to the start of the partition and write VBR */
|
||||
fseek(File, Partition.StartLBA * SECTOR_SIZE, SEEK_SET);
|
||||
if(fwrite(Vbr, 1, SECTOR_SIZE, File) != SECTOR_SIZE)
|
||||
{
|
||||
/* Failed to write VBR to disk image */
|
||||
perror("Failed to write VBR to disk image");
|
||||
fclose(File);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(File);
|
||||
printf("Successfully created disk image '%s' (%ld MB) with one bootable W95 FAT32 partition%s%s.\n",
|
||||
FileName,
|
||||
DiskSizeMB,
|
||||
MbrFile ? " with MBR from file" : "",
|
||||
VbrFile ? " and VBR from file" : "");
|
||||
return 0;
|
||||
}
|
@@ -9,10 +9,22 @@
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define _T(x) x
|
||||
|
||||
#define SECTOR_SIZE 512
|
||||
#define _T(x) x
|
||||
|
||||
typedef struct MBR_PARTITION {
|
||||
uint8_t BootFlag; // 0x80 = bootable, 0x00 = non-boot
|
||||
uint8_t StartCHS [3]; // CHS address
|
||||
uint8_t Type; // Partition type
|
||||
uint8_t EndCHS[3]; // CHS address
|
||||
uint32_t StartLBA; // Start sector
|
||||
uint32_t Size; // Sectors count
|
||||
} MBR_PARTITION, *PMBR_PARTITION;
|
||||
|
||||
static
|
||||
inline
|
||||
@@ -52,17 +64,17 @@ split_argv(const char *argv0,
|
||||
char **exe_ptr)
|
||||
{
|
||||
const char *sep = _tcsrchrs(argv0, '/', '\\');
|
||||
const char *basename_ptr_const = argv0;
|
||||
char *dir = strdup(_T(""));
|
||||
const char *basename = argv0;
|
||||
|
||||
if(sep)
|
||||
{
|
||||
dir = strdup(argv0);
|
||||
dir[sep + 1 - argv0] = '\0';
|
||||
basename = sep + 1;
|
||||
basename_ptr_const = sep + 1;
|
||||
}
|
||||
|
||||
basename = strdup(basename);
|
||||
char *basename = strdup(basename_ptr_const);
|
||||
char *period = strchr(basename, '.');
|
||||
|
||||
if(period)
|
||||
@@ -72,7 +84,7 @@ split_argv(const char *argv0,
|
||||
|
||||
char *target = strdup(basename);
|
||||
char *dash = strrchr(target, '-');
|
||||
const char *exe = basename;
|
||||
char *exe = basename;
|
||||
|
||||
if(dash)
|
||||
{
|
||||
|
Reference in New Issue
Block a user