From 468aedb2078c4bd1869100e40d578a5e5bccd286 Mon Sep 17 00:00:00 2001 From: Robert Pengelly Date: Mon, 3 Jun 2024 04:33:22 +0100 Subject: [PATCH] New server --- LICENSE | 24 +++ Makefile.pdw | 22 ++ Makefile.std | 22 ++ Makefile.unix | 26 +++ Makefile.w32 | 19 ++ README.md | 23 +++ lib.c | 522 +++++++++++++++++++++++++++++++++++++++++++++++ lib.h | 17 ++ parted.c | 549 ++++++++++++++++++++++++++++++++++++++++++++++++++ parted.h | 29 +++ report.c | 125 ++++++++++++ report.h | 28 +++ write7x.c | 94 +++++++++ write7x.h | 11 + 14 files changed, 1511 insertions(+) create mode 100644 LICENSE create mode 100644 Makefile.pdw create mode 100644 Makefile.std create mode 100644 Makefile.unix create mode 100644 Makefile.w32 create mode 100644 README.md create mode 100644 lib.c create mode 100644 lib.h create mode 100644 parted.c create mode 100644 parted.h create mode 100644 report.c create mode 100644 report.h create mode 100644 write7x.c create mode 100644 write7x.h diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..fdddb29 --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to diff --git a/Makefile.pdw b/Makefile.pdw new file mode 100644 index 0000000..5cd3611 --- /dev/null +++ b/Makefile.pdw @@ -0,0 +1,22 @@ +#****************************************************************************** +# @file Makefile.pdw +#****************************************************************************** +AS=aswin +CC=gccwin +LD=ldwin + +COPTS=-S -O2 -fno-common -ansi -I. -I../pdos/pdpclib -D__WIN32__ -D__NOBIVA__ -D__PDOS__ +COBJ=lib.o parted.o report.o write7x.o + +all: clean parted.exe + +parted.exe: $(COBJ) + $(LD) -s -o parted.exe ../pdos/pdpclib/w32start.o $(COBJ) ../pdos/pdpclib/msvcrt.a + +.c.o: + $(CC) $(COPTS) $< + $(AS) -o $@ $*.s + rm -f $*.s + +clean: + rm -f *.o parted.exe diff --git a/Makefile.std b/Makefile.std new file mode 100644 index 0000000..09b5446 --- /dev/null +++ b/Makefile.std @@ -0,0 +1,22 @@ +#****************************************************************************** +# @file Makefile.std +#****************************************************************************** +AS=pdas --oformat coff +CC=gccwin +LD=pdld --no-insert-timestamp + +COPTS=-S -O2 -fno-common -ansi -I. -I../pdos/pdpclib -D__WIN32__ -D__NOBIVA__ -D__PDOS__ +COBJ=lib.obj parted.obj report.obj write7x.obj + +all: clean parted.exe + +parted.exe: $(COBJ) + $(LD) -s -o parted.exe ../pdos/pdpclib/w32start.obj $(COBJ) ../pdos/pdpclib/msvcrt.lib + +.c.obj: + $(CC) $(COPTS) $< + $(AS) -o $@ $*.s + rm -f $*.s + +clean: + rm -f *.obj parted.exe diff --git a/Makefile.unix b/Makefile.unix new file mode 100644 index 0000000..647a61b --- /dev/null +++ b/Makefile.unix @@ -0,0 +1,26 @@ +#****************************************************************************** +# @file Makefile.unix +#****************************************************************************** +SRCDIR ?= $(CURDIR) +VPATH := $(SRCDIR) + +CC := gcc +CFLAGS := -D_FILE_OFFSET_BITS=64 -Wall -Werror -Wextra -std=c90 + +CSRC := lib.c parted.c report.c write7x.c + +ifeq ($(OS), Windows_NT) +all: parted.exe + +parted.exe: $(CSRC) + $(CC) $(CFLAGS) -o $@ $^ +else +all: parted + +parted: $(CSRC) + $(CC) $(CFLAGS) -o $@ $^ +endif + +clean: + if [ -f parted.exe ]; then rm -rf parted.exe; fi + if [ -f parted ]; then rm -rf parted; fi diff --git a/Makefile.w32 b/Makefile.w32 new file mode 100644 index 0000000..f318641 --- /dev/null +++ b/Makefile.w32 @@ -0,0 +1,19 @@ +#****************************************************************************** +# @file Makefile.w32 +#****************************************************************************** +SRCDIR ?= $(CURDIR) +VPATH := $(SRCDIR) + +CC := gcc +CFLAGS := -D_FILE_OFFSET_BITS=64 -Wall -Werror -Wextra -std=c90 + +CSRC := lib.c parted.c report.c write7x.c + +all: parted.exe + +clean: + if exist parted.exe ( del /q parted.exe ) + if exist parted ( del /q parted ) + +parted.exe: $(CSRC) + $(CC) $(CFLAGS) -o $@ $^ diff --git a/README.md b/README.md new file mode 100644 index 0000000..d4a6607 --- /dev/null +++ b/README.md @@ -0,0 +1,23 @@ +All source code is Public Domain. + +## Obtain the source code + + git clone https://git.candlhat.org/parted.git + +## Building + + BSD: + + Make sure you have gcc and gmake installed then run gmake -f Makefile.unix. + + Linux: + + Make sure you have gcc and make installed then run make -f Makefile.unix. + + macOS: + + Make sure you have xcode command line tools installed then run make -f Makefile.unix. + + Windows: + + Make sure you have mingw installed and the location within your PATH variable then run mingw32-make.exe -f Makefile.w32. diff --git a/lib.c b/lib.c new file mode 100644 index 0000000..815434a --- /dev/null +++ b/lib.c @@ -0,0 +1,522 @@ +/****************************************************************************** + * @file lib.c + *****************************************************************************/ +#include +#include +#include +#include +#include + +#include "lib.h" +#include "parted.h" +#include "report.h" + +struct option { + + const char *name; + int index, flags; + +}; + +#define OPTION_NO_ARG 0x0001 +#define OPTION_HAS_ARG 0x0002 + +enum options { + + OPTION_IGNORED = 0, + OPTION_ARCA, + OPTION_BOOT, + OPTION_HELP, + OPTION_LABEL, + OPTION_PART + +}; + +static struct option opts[] = { + + { "-arca", OPTION_ARCA, OPTION_NO_ARG }, + { "-boot", OPTION_BOOT, OPTION_HAS_ARG }, + { "-help", OPTION_HELP, OPTION_NO_ARG }, + { 0, 0, 0 } + +}; + +static struct option opts1[] = { + + { "mklabel", OPTION_LABEL, OPTION_HAS_ARG }, + { "mkpart", OPTION_PART, OPTION_HAS_ARG }, + { 0, 0, 0 } + +}; + +static int strstart (const char *val, const char **str) { + + const char *p = val; + const char *q = *str; + + while (*p != '\0') { + + if (*p != *q) { + return 0; + } + + ++p; + ++q; + + } + + *str = q; + return 1; + +} + +static char *skip_whitespace (char *p) { + + while (*p && *p == ' ') { + ++p; + } + + return p; + +} + +static char *trim (char *p) { + + unsigned long len = strlen (p); + unsigned long i; + + for (i = len; i > 0; --i) { + + if (p[i] == ' ') { + p[i] = '\0'; + } + + } + + if (p[i] == ' ') { + p[i] = '\0'; + } + + return p; + +} + +char *xstrdup (const char *str) { + + char *ptr = xmalloc (strlen (str) + 1); + strcpy (ptr, str); + + return ptr; + +} + +int xstrcasecmp (const char *s1, const char *s2) { + + const unsigned char *p1; + const unsigned char *p2; + + p1 = (const unsigned char *) s1; + p2 = (const unsigned char *) s2; + + while (*p1 != '\0') { + + if (toupper (*p1) < toupper (*p2)) { + return (-1); + } else if (toupper (*p1) > toupper (*p2)) { + return (1); + } + + p1++; + p2++; + + } + + if (*p2 == '\0') { + return (0); + } else { + return (-1); + } + +} + +void *xmalloc (unsigned long size) { + + void *ptr = malloc (size); + + if (ptr == NULL && size) { + + report_at (program_name, 0, REPORT_ERROR, "memory full (malloc)"); + exit (EXIT_FAILURE); + + } + + memset (ptr, 0, size); + return ptr; + +} + +void *xrealloc (void *ptr, unsigned long size) { + + void *new_ptr = realloc (ptr, size); + + if (new_ptr == NULL && size) { + + report_at (program_name, 0, REPORT_ERROR, "memory full (realloc)"); + exit (EXIT_FAILURE); + + } + + return new_ptr; + +} + +void dynarray_add (void *ptab, long *nb_ptr, void *data) { + + int nb, nb_alloc; + void **pp; + + nb = *nb_ptr; + pp = *(void ***) ptab; + + if ((nb & (nb - 1)) == 0) { + + if (!nb) { + nb_alloc = 1; + } else { + nb_alloc = nb * 2; + } + + pp = xrealloc (pp, nb_alloc * sizeof (void *)); + *(void ***) ptab = pp; + + } + + pp[nb++] = data; + *nb_ptr = nb; + +} + +void parse_args (int *pargc, char ***pargv, int optind) { + + char **argv = *pargv; + int argc = *pargc; + + struct option *popt; + const char *optarg, *r; + + if (argc == optind) { + print_help (EXIT_SUCCESS); + } + + while (optind < argc) { + + r = argv[optind++]; + + if (r[0] != '-' || r[1] == '\0') { + + for (popt = opts1; popt->name; ++popt) { + + const char *p1 = popt->name; + + if (xstrcasecmp (p1, r) != 0) { + continue; + } + + if (popt->flags & OPTION_HAS_ARG) { + + if (optind >= argc) { + + report_at (program_name, 0, REPORT_ERROR, "argument to '%s' is missing", r); + exit (EXIT_FAILURE); + + } + + optarg = argv[optind++]; + goto have_opt; + + } + + } + + if (state->outfile) { + + report_at (program_name, 0, REPORT_ERROR, "multiple output files provided"); + exit (EXIT_FAILURE); + + } + + state->outfile = xstrdup (r); + continue; + + } + + for (popt = opts; popt; ++popt) { + + const char *p1 = popt->name; + const char *r1 = (r + 1); + + if (!p1) { + + report_at (program_name, 0, REPORT_ERROR, "invalid option -- '%s'", r); + exit (EXIT_FAILURE); + + } + + if (!strstart (p1, &r1)) { + continue; + } + + optarg = r1; + + if (popt->flags & OPTION_HAS_ARG) { + + if (*optarg == '\0') { + + if (optind >= argc) { + + report_at (program_name, 0, REPORT_ERROR, "argument to '%s' is missing", r); + exit (EXIT_FAILURE); + + } + + optarg = argv[optind++]; + + } + + } else if (*optarg != '\0') { + continue; + } + + break; + + } + + have_opt: + + switch (popt->index) { + + case OPTION_ARCA: { + + state->chs_align = 1; + break; + + } + + case OPTION_BOOT: { + + state->boot = xstrdup (optarg); + break; + + } + + case OPTION_HELP: { + + print_help (EXIT_SUCCESS); + break; + + } + + case OPTION_LABEL: { + + /*report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "label: %s", optarg);*/ + break; + + } + + case OPTION_PART: { + + long conversion, size; + char *temp; + + struct part_info *part = xmalloc (sizeof (*part)); + + char *p1 = skip_whitespace ((char *) optarg); + char *p2 = p1; + + while (*p2 && *p2 != ',') { + p2++; + } + + if (*p2 == ',') { + *p2++ = '\0'; + } + + p1 = trim (p1); + + errno = 0; + conversion = strtol (p1, &temp, 0); + + if (!*p1 || isspace ((int) *p1) || *temp || errno) { + + report_at (program_name, 0, REPORT_ERROR, "failed to get partition status"); + exit (EXIT_FAILURE); + + } + + if (conversion != 0 && conversion != 128) { + + report_at (program_name, 0, REPORT_ERROR, "partition status must be either 0 or 128"); + exit (EXIT_FAILURE); + + } + + part->status = conversion; + + p2 = skip_whitespace (p2); + p1 = p2; + + while (*p2 && *p2 != ',') { + p2++; + } + + if (*p2 == ',') { + *p2++ = '\0'; + } + + p1 = trim (p1); + + errno = 0; + conversion = strtol (p1, &temp, 0); + + if (!*p1 || isspace ((int) *p1) || *temp || errno) { + + report_at (program_name, 0, REPORT_ERROR, "failed to get partition type"); + exit (EXIT_FAILURE); + + } + + switch (conversion) { + + case 0x01: + case 0x04: + case 0x06: + case 0x0B: + case 0x0C: + case 0x0E: + + break; + + default: + + report_at (program_name, 0, REPORT_ERROR, "unsupported partition type provided"); + exit (EXIT_FAILURE); + + } + + part->type = conversion; + + p2 = skip_whitespace (p2); + p1 = p2; + + while (*p2 && *p2 != ',') { + p2++; + } + + if (*p2 == ',') { + *p2++ = '\0'; + } + + p1 = trim (p1); + + errno = 0; + conversion = strtol (p1, &temp, 0); + + if (!*p1 || isspace ((int) *p1) || *temp || errno) { + + report_at (program_name, 0, REPORT_ERROR, "failed to get partition start"); + exit (EXIT_FAILURE); + + } + + if (conversion < 0) { + + report_at (program_name, 0, REPORT_ERROR, "partition start must be greater than 0"); + exit (EXIT_FAILURE); + + } + + part->start = conversion; + + p2 = skip_whitespace (p2); + p1 = p2; + + while (*p2 && *p2 != ',') { + p2++; + } + + if (*p2 == ',') { + *p2++ = '\0'; + } + + p1 = trim (p1); + + errno = 0; + conversion = strtol (p1, &temp, 0); + + if (!*p1 || isspace ((int) *p1) || *temp || errno) { + + report_at (program_name, 0, REPORT_ERROR, "failed to get partition end"); + exit (EXIT_FAILURE); + + } + + if (conversion < 0) { + + report_at (program_name, 0, REPORT_ERROR, "partition end must be greater than 0"); + exit (EXIT_FAILURE); + + } + + part->end = conversion; + + /*if (part->end < part->start) { + + report_at (program_name, 0, REPORT_ERROR, "partition end must be greater than partition start"); + exit (EXIT_FAILURE); + + }*/ + + size = (part->start + part->end) * 512; + + if (state->image_size < size) { + state->image_size = size; + } + + dynarray_add (&state->parts, &state->nb_parts, part); + break; + + } + + default: { + + report_at (program_name, 0, REPORT_ERROR, "unsupported option '%s'", r); + exit (EXIT_FAILURE); + + } + + } + + } + +} + +void print_help (int exitval) { + + if (!program_name) { + goto _exit; + } + + fprintf (stderr, "Usage: %s [options] [commands] file\n\n", program_name); + fprintf (stderr, "Options:\n\n"); + fprintf (stderr, " --arca Use CHS-alignment\n"); + fprintf (stderr, " --boot FILE Write FILE to start of image\n"); + fprintf (stderr, " --help Print this help information\n"); + fprintf (stderr, "\n"); + fprintf (stderr, "Commands:\n\n"); + fprintf (stderr, " mkpart status,type,start,end Make a partition\n"); + +_exit: + + exit (exitval); + +} diff --git a/lib.h b/lib.h new file mode 100644 index 0000000..6438ca7 --- /dev/null +++ b/lib.h @@ -0,0 +1,17 @@ +/****************************************************************************** + * @file lib.h + *****************************************************************************/ +#ifndef _LIB_H +#define _LIB_H + +char *xstrdup (const char *str); +int xstrcasecmp (const char *s1, const char *s2); + +void *xmalloc (unsigned long size); +void *xrealloc (void *ptr, unsigned long size); + +void dynarray_add (void *ptab, long *nb_ptr, void *data); +void parse_args (int *pargc, char ***pargv, int optind); +void print_help (int exitval); + +#endif /* _LIB_H */ diff --git a/parted.c b/parted.c new file mode 100644 index 0000000..dd809e7 --- /dev/null +++ b/parted.c @@ -0,0 +1,549 @@ +/****************************************************************************** + * @file parted.c + *****************************************************************************/ +#include +#include +#include +#include +#include + +#include "lib.h" +#include "parted.h" +#include "report.h" +#include "write7x.h" + +#ifndef __PDOS__ +# if defined (__GNUC__) +# include +# include +# else +# include +# endif +#endif + +static long cylinders = 0; +static long heads_per_cylinder = 0; +static long sectors_per_track = 0; + +struct parted_state *state = 0; +const char *program_name = 0; + +struct part { + + unsigned char status; + unsigned char start_chs[3]; + unsigned char type; + unsigned char end_chs[3]; + unsigned char start_lba[4]; + unsigned char end_lba[4]; + +}; + +struct mbr { + + unsigned char boot_code[440]; + unsigned char signature[4]; + unsigned char copy_protected[2]; + + struct part parts[4]; + unsigned char boot_sig[2]; + +}; + +struct footer { + + unsigned char cookie[8]; + unsigned char features[4]; + + struct { + + unsigned char major[2]; + unsigned char minor[2]; + + } version; + + unsigned char next_offset[8]; + unsigned char modified_time[4]; + unsigned char creator_name[4]; + + struct { + + unsigned char major[2]; + unsigned char minor[2]; + + } creator_version; + + unsigned char creator_host[4]; + unsigned char disk_size[8]; + unsigned char data_size[8]; + + struct { + + unsigned char cylinders[2]; + unsigned char heads_per_cyl; + unsigned char secs_per_track; + + } disk_geom; + + unsigned char disk_type[4]; + unsigned char checksum[4]; + unsigned char identifier[16]; + unsigned char saved_state; + unsigned char reserved[427]; + +}; + +static void calculate_geometry (void) { + + long sectors = state->image_size / 512; + long cylinder_times_heads; + + if (sectors > (long) 65535 * 16 * 255) { + sectors = (long) 65535 * 16 * 255; + } + + if (sectors > (long) 65535 * 16 * 63) { + + sectors_per_track = 63; + heads_per_cylinder = 255; + + cylinder_times_heads = sectors / sectors_per_track; + + } else { + + sectors_per_track = 17; + cylinder_times_heads = sectors / sectors_per_track; + + heads_per_cylinder = (cylinder_times_heads + 1023) >> 10; + + if (heads_per_cylinder < 4) { + heads_per_cylinder = 4; + } + + if (cylinder_times_heads >= heads_per_cylinder << 10 || heads_per_cylinder > 16) { + + sectors_per_track = 31; + heads_per_cylinder = 16; + + cylinder_times_heads = sectors / sectors_per_track; + + } + + if (cylinder_times_heads >= heads_per_cylinder << 10) { + + sectors_per_track = 63; + heads_per_cylinder = 16; + + cylinder_times_heads = sectors / sectors_per_track; + + } + + } + + cylinders = cylinder_times_heads / heads_per_cylinder; + +} + +/** Generate a unique volume id. */ +static unsigned int generate_signature (void) { + +#if defined (__PDOS__) + + srand (time (NULL)); + + /* rand() returns int from [0,RAND_MAX], therefor only 31-bits. */ + return (((unsigned int) (rand () & 0xFFFF)) << 16) | ((unsigned int) (rand() & 0xFFFF)); + +#elif defined (__GNUC__) + + struct timeval now; + + if (gettimeofday (&now, 0) != 0 || now.tv_sec == (time_t) -1 || now.tv_sec < 0) { + + srand (getpid ()); + + /*- rand() returns int from [0,RAND_MAX], therefor only 31-bits. */ + return (((unsigned int) (rand () & 0xFFFF)) << 16) | ((unsigned int) (rand() & 0xFFFF)); + + } + + /* volume id = current time, fudged for more uniqueness. */ + return ((unsigned int) now.tv_sec << 20) | (unsigned int) now.tv_usec; + +#elif defined (__WATCOMC__) + + srand (getpid ()); + + /* rand() returns int from [0,RAND_MAX], therefor only 31-bits. */ + return (((unsigned int) (rand () & 0xFFFF)) << 16) | ((unsigned int) (rand() & 0xFFFF)); + +#endif + +} + +static void get_random_bytes (void *buf, unsigned long nbytes) { + + unsigned char *cp = (unsigned char *) buf; + unsigned int seed; + + unsigned long i; + +#if defined (__PDOS__) + seed = time (NULL); +#elif defined (__GNUC__) + + struct timeval now; + seed = (getpid () << 16); + + if (gettimeofday (&now, 0) != 0 || now.tv_sec == (time_t) -1 || now.tv_sec < 0) { + seed = seed ^ now.tv_sec ^ now.tv_usec; + } else { + seed ^= time (NULL); + } + +#else + + seed = (getpid () << 16); + seed ^= time (NULL); + +#endif + + srand (seed); + + for (i = 0; i < nbytes; i++) { + *cp++ ^= (rand () >> 7) % (CHAR_MAX + 1); + } + +} + +static unsigned int generate_checksum (unsigned char *data, unsigned long len) { + + unsigned int sum = 0; + int i = 0; + + unsigned long j; + + for (j = 0; j < len; j++) { + sum += data[i++]; + } + + return sum ^ 0xffffffff; + +} + +int main (int argc, char **argv) { + + FILE *ofp; + long flen; + + struct footer footer; + struct mbr mbr; + + long p, sector = 1; + long sectors_per_cylinder, start, end; + + if (argc && *argv) { + + char *p; + program_name = *argv; + + if ((p = strrchr (program_name, '/')) || (p = strrchr (program_name, '\\'))) { + program_name = (p + 1); + } + + } + + state = xmalloc (sizeof (*state)); + parse_args (&argc, &argv, 1); + + if (!state->outfile) { + + report_at (program_name, 0, REPORT_ERROR, "no outfile file provided"); + return EXIT_FAILURE; + + } + + if (!state->outfile || state->nb_parts == 0) { + print_help (EXIT_FAILURE); + } + + memset (&mbr, 0, sizeof (mbr)); + + if (state->boot) { + + FILE *ifp; + + if ((ifp = fopen (state->boot, "rb")) == NULL) { + + report_at (program_name, 0, REPORT_ERROR, "failed to open '%s' for reading", state->boot); + return EXIT_FAILURE; + + } + + fseek (ifp, 0, SEEK_END); + + if (ftell (ifp) != 440) { + + report_at (program_name, 0, REPORT_ERROR, "size of %s is not equal to 440 bytes", state->boot); + fclose (ifp); + + return EXIT_FAILURE; + + } + + fseek (ifp, 0, SEEK_SET); + + if (fread (&mbr, 440, 1, ifp) != 1) { + + report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", state->boot); + fclose (ifp); + + return EXIT_FAILURE; + + } + + fclose (ifp); + + } + + write721_to_byte_array (mbr.boot_sig, 0xAA55, 1); + write741_to_byte_array (mbr.signature, generate_signature (), 1); + + calculate_geometry (); + sectors_per_cylinder = heads_per_cylinder * sectors_per_track; + + for (p = 0; p < state->nb_parts; ++p) { + + struct part_info *info = state->parts[p]; + unsigned cyl, head, sect, temp; + + if (p >= 4) { + + report_at (program_name, 0, REPORT_ERROR, "too many partitions provided"); + return EXIT_FAILURE; + + } + + mbr.parts[p].status = info->status; + mbr.parts[p].type = info->type; + + start = info->start; + + if (state->chs_align && start % sectors_per_track) { + + start = ((start / sectors_per_track) + 1) * sectors_per_track; + report_at (program_name, 0, REPORT_WARNING, "starting sector changed from %lu to %lu for partition %lu", info->start, start, p + 1); + + } + + if (start < sector) { + + report_at (program_name, 0, REPORT_ERROR, "overlapping partitions"); + return EXIT_FAILURE; + + } + + sector = start; + + if (sector * 512 > state->image_size) { + + report_at (program_name, 0, REPORT_ERROR, "partition %lu start exceeds image size", p + 1); + return EXIT_FAILURE; + + } + + cyl = sector / sectors_per_cylinder; + mbr.parts[p].start_chs[2] = cyl; + + temp = sector % sectors_per_cylinder; + + head = temp / sectors_per_track; + sect = temp % sectors_per_track + 1; + + mbr.parts[p].start_chs[0] = head; + + cyl = (cyl >> 8) & 0xff; + mbr.parts[p].start_chs[1] = (cyl << 6) | sect; + + write741_to_byte_array (mbr.parts[p].start_lba, start, 1); + end = info->end; + + if (state->chs_align) { + + long adjustment; + + if (end % sectors_per_cylinder) { + end = ((end / sectors_per_cylinder) + 1) * sectors_per_cylinder; + } + + if (sector + end > info->start + info->end) { + + adjustment = (sector + end) - (info->start + info->end); + end -= adjustment; + + } + + if ((adjustment = (start + end) % sectors_per_cylinder)) { + end -= adjustment; + } + + if (end != info->end) { + report_at (program_name, 0, REPORT_WARNING, "number of sectors changed from %lu to %lu for partition %lu", info->end, end, p + 1); + } + + } + + /*if (end < sector) { + + report_at (program_name, 0, REPORT_ERROR, "overlapping partitions"); + return EXIT_FAILURE; + + }*/ + + sector += end; + sector--; + + if (sector * 512 > state->image_size) { + + report_at (program_name, 0, REPORT_ERROR, "partition %lu end exceeds image size", p + 1); + return EXIT_FAILURE; + + } + + cyl = sector / sectors_per_cylinder; + mbr.parts[p].end_chs[2] = cyl; + + temp = sector % sectors_per_cylinder; + + head = temp / sectors_per_track; + sect = (temp % sectors_per_track) + 1; + + mbr.parts[p].end_chs[0] = head; + + cyl = (cyl >> 8) & 0xff; + mbr.parts[p].end_chs[1] = (cyl << 6) | sect; + + write741_to_byte_array (mbr.parts[p].end_lba, end, 1); + + } + + state->image_size += 512; + state->image_size += sizeof (footer); + + if ((ofp = fopen (state->outfile, "r+b")) == NULL) { + + void *zero; + long len; + + if ((ofp = fopen (state->outfile, "wb")) == NULL) { + + report_at (program_name, 0, REPORT_ERROR, "failed to open '%s' for writing", state->outfile); + return EXIT_FAILURE; + + } + + len = state->image_size; + zero = xmalloc (512); + + while (len > 0) { + + if (fwrite (zero, 512, 1, ofp) != 1) { + + report_at (program_name, 0, REPORT_ERROR, "failed whilst writing '%s'", state->outfile); + fclose (ofp); + + free (zero); + remove (state->outfile); + + return EXIT_FAILURE; + + } + + len -= 512; + + } + + free (zero); + + } + + fseek (ofp, 0, SEEK_END); + flen = ftell (ofp); + + if (flen < state->image_size) { + + report_at (program_name, 0, REPORT_ERROR, "file size mismatch (%lu vs %lu)", flen, state->image_size); + fclose (ofp); + + remove (state->outfile); + return EXIT_FAILURE; + + } + + fseek (ofp, 0, SEEK_SET); + + if (fwrite (&mbr, sizeof (mbr), 1, ofp) != 1) { + + report_at (program_name, 0, REPORT_ERROR, "failed whilst writing the master boot record"); + + fclose (ofp); + remove (state->outfile); + + return EXIT_FAILURE; + + } + + memset (&footer, 0, sizeof (footer)); + + memcpy (footer.cookie, "conectix", 8); + memcpy (footer.creator_host, "Wi2k", 4); + memcpy (footer.creator_name, "win ", 4); + + write721_to_byte_array (footer.version.major, 1, 0); + write721_to_byte_array (footer.version.minor, 0, 0); + write721_to_byte_array (footer.creator_version.major, 6, 0); + write721_to_byte_array (footer.creator_version.minor, 1, 0); + + write741_to_byte_array (footer.features, 2, 0); + write741_to_byte_array (footer.disk_type, 2, 0); + + memset (footer.next_offset, 0xff, 8); + + write781_to_byte_array (footer.disk_size, flen - sizeof (footer), 0); + write781_to_byte_array (footer.data_size, flen - sizeof (footer), 0); + + write721_to_byte_array (footer.disk_geom.cylinders, cylinders, 0); + footer.disk_geom.heads_per_cyl = heads_per_cylinder; + footer.disk_geom.secs_per_track = sectors_per_track; + + get_random_bytes (footer.identifier, sizeof (footer.identifier)); + + write741_to_byte_array (footer.modified_time, time (NULL) - 946684800, 0); + write741_to_byte_array (footer.checksum, generate_checksum ((unsigned char *) &footer, sizeof (footer)), 0); + + if (fseek (ofp, state->image_size - sizeof (footer), SEEK_SET)) { + + report_at (program_name, 0, REPORT_ERROR, "failed whilst seeking '%s'", state->outfile); + + fclose (ofp); + remove (state->outfile); + + return EXIT_FAILURE; + + } + + if (fwrite (&footer, sizeof (footer), 1, ofp) != 1) { + + report_at (program_name, 0, REPORT_ERROR, "failed whilst writing footer"); + + fclose (ofp); + remove (state->outfile); + + return EXIT_FAILURE; + + } + + fclose (ofp); + return EXIT_SUCCESS; + +} diff --git a/parted.h b/parted.h new file mode 100644 index 0000000..bee4997 --- /dev/null +++ b/parted.h @@ -0,0 +1,29 @@ +/****************************************************************************** + * @file parted.h + *****************************************************************************/ +#ifndef _PARTED_H +#define _PARTED_H + +struct part_info { + + int status, type; + long start, end; + +}; + +struct parted_state { + + const char *boot, *outfile; + + struct part_info **parts; + long nb_parts; + + long image_size; + int chs_align; + +}; + +extern struct parted_state *state; +extern const char *program_name; + +#endif /* _PARTED_H */ diff --git a/report.c b/report.c new file mode 100644 index 0000000..cb60fe7 --- /dev/null +++ b/report.c @@ -0,0 +1,125 @@ +/****************************************************************************** + * @file report.c + *****************************************************************************/ +#include +#include + +#include "report.h" + +#ifndef __PDOS__ +#if defined (_WIN32) +# include +static int OriginalConsoleColor = -1; +#endif + +static void reset_console_color (void) { + +#if defined (_WIN32) + + HANDLE hStdError = GetStdHandle (STD_ERROR_HANDLE); + + if (OriginalConsoleColor == -1) { return; } + + SetConsoleTextAttribute (hStdError, OriginalConsoleColor); + OriginalConsoleColor = -1; + +#else + + fprintf (stderr, "\033[0m"); + +#endif + +} + +static void set_console_color (int color) { + +#if defined (_WIN32) + + HANDLE hStdError = GetStdHandle (STD_ERROR_HANDLE); + WORD wColor; + + if (OriginalConsoleColor == -1) { + + CONSOLE_SCREEN_BUFFER_INFO csbi; + + if (!GetConsoleScreenBufferInfo (hStdError, &csbi)) { + return; + } + + OriginalConsoleColor = csbi.wAttributes; + + } + + wColor = (OriginalConsoleColor & 0xF0) + (color & 0xF); + SetConsoleTextAttribute (hStdError, wColor); + +#else + + fprintf (stderr, "\033[%dm", color); + +#endif + +} +#endif + +void report_at (const char *filename, unsigned long line_number, int type, const char *fmt, ...) { + + va_list ap; + + if (filename) { + + if (line_number == 0) { + fprintf (stderr, "%s: ", filename); + } else { + fprintf (stderr, "%s:", filename); + } + + } + + if (line_number > 0) { + fprintf (stderr, "%lu: ", line_number); + } + + if (type == REPORT_ERROR || type == REPORT_FATAL_ERROR) { + +#ifndef __PDOS__ + set_console_color (COLOR_ERROR); +#endif + + if (type == REPORT_ERROR) { + fprintf (stderr, "error:"); + } else { + fprintf (stderr, "fatal error:"); + } + + } else if (type == REPORT_INTERNAL_ERROR) { + +#ifndef __PDOS__ + set_console_color (COLOR_INTERNAL_ERROR); +#endif + + fprintf (stderr, "internal error:"); + + } else if (type == REPORT_WARNING) { + + #ifndef __PDOS__ + set_console_color (COLOR_INTERNAL_ERROR); +#endif + + fprintf (stderr, "warning:"); + + } + +#ifndef __PDOS__ + reset_console_color (); +#endif + + fprintf (stderr, " "); + + va_start (ap, fmt); + vfprintf (stderr, fmt, ap); + va_end (ap); + + fprintf (stderr, "\n"); + +} diff --git a/report.h b/report.h new file mode 100644 index 0000000..bdd121e --- /dev/null +++ b/report.h @@ -0,0 +1,28 @@ +/****************************************************************************** + * @file report.h + *****************************************************************************/ +#ifndef _REPORT_H +#define _REPORT_H + +enum { + + REPORT_ERROR = 0, + REPORT_FATAL_ERROR, + REPORT_INTERNAL_ERROR, + REPORT_WARNING + +}; + +#if defined (_WIN32) +# define COLOR_ERROR 12 +# define COLOR_WARNING 13 +# define COLOR_INTERNAL_ERROR 19 +#else +# define COLOR_ERROR 91 +# define COLOR_INTERNAL_ERROR 94 +# define COLOR_WARNING 95 +#endif + +void report_at (const char *filename, unsigned long line_number, int type, const char *fmt, ...); + +#endif /* _REPORT_H */ diff --git a/write7x.c b/write7x.c new file mode 100644 index 0000000..e1a0257 --- /dev/null +++ b/write7x.c @@ -0,0 +1,94 @@ +/****************************************************************************** + * @file write7x.c + *****************************************************************************/ +#include + +#include "write7x.h" + +void write721_to_byte_array (unsigned char *dest, unsigned short val, int little_endian) { + + if (little_endian) { + + dest[0] = (val & 0xFF); + dest[1] = (val >> 8) & 0xFF; + + } else { + + dest[1] = (val & 0xFF); + dest[0] = (val >> 8) & 0xFF; + + } + +} + +void write741_to_byte_array (unsigned char *dest, unsigned int val, int little_endian) { + + if (little_endian) { + + dest[0] = (val & 0xFF); + dest[1] = (val >> 8) & 0xFF; + dest[2] = (val >> 16) & 0xFF; + dest[3] = (val >> 24) & 0xFF; + + } else { + + dest[3] = (val & 0xFF); + dest[2] = (val >> 8) & 0xFF; + dest[1] = (val >> 16) & 0xFF; + dest[0] = (val >> 24) & 0xFF; + + } + +} + +void write781_to_byte_array (unsigned char *dest, unsigned long val, int little_endian) { + + if (little_endian) { + + dest[0] = (val & 0xFF); + dest[1] = (val >> 8) & 0xFF; + dest[2] = (val >> 16) & 0xFF; + dest[3] = (val >> 24) & 0xFF; + +#if ULONG_MAX > 4294967295UL + + dest[4] = (val >> 32) & 0xFF; + dest[5] = (val >> 40) & 0xFF; + dest[6] = (val >> 48) & 0xFF; + dest[7] = (val >> 56) & 0xFF; + +#else + + dest[4] = 0; + dest[5] = 0; + dest[6] = 0; + dest[7] = 0; + +#endif + + } else { + + dest[7] = (val & 0xFF); + dest[6] = (val >> 8) & 0xFF; + dest[5] = (val >> 16) & 0xFF; + dest[4] = (val >> 24) & 0xFF; + +#if ULONG_MAX > 4294967295UL + + dest[3] = (val >> 32) & 0xFF; + dest[2] = (val >> 40) & 0xFF; + dest[1] = (val >> 48) & 0xFF; + dest[0] = (val >> 56) & 0xFF; + +#else + + dest[3] = 0; + dest[2] = 0; + dest[1] = 0; + dest[0] = 0; + +#endif + + } + +} diff --git a/write7x.h b/write7x.h new file mode 100644 index 0000000..310fd75 --- /dev/null +++ b/write7x.h @@ -0,0 +1,11 @@ +/****************************************************************************** + * @file write7x.h + *****************************************************************************/ +#ifndef _WRITE7X_H +#define _WRITE7X_H + +void write721_to_byte_array (unsigned char *dest, unsigned short val, int little_endian); +void write741_to_byte_array (unsigned char *dest, unsigned int val, int little_endian); +void write781_to_byte_array (unsigned char *dest, unsigned long val, int little_endian); + +#endif /* _WRITE7X_H */ -- 2.34.1