From 452903126d15ab2228910eb36b78b152c07fb247 Mon Sep 17 00:00:00 2001 From: Jan Sucan Date: Sun, 12 Nov 2023 15:23:37 +0100 Subject: Rename C source file to C++ source files --- src/Makefile | 2 +- src/backup.c | 156 -------------------------------- src/backup.cpp | 156 ++++++++++++++++++++++++++++++++ src/file.c | 84 ----------------- src/file.cpp | 84 +++++++++++++++++ src/main.c | 63 ------------- src/main.cpp | 63 +++++++++++++ src/options.c | 266 ------------------------------------------------------ src/options.cpp | 266 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/print.c | 47 ---------- src/print.cpp | 47 ++++++++++ src/resources.c | 213 ------------------------------------------- src/resources.cpp | 213 +++++++++++++++++++++++++++++++++++++++++++ src/restore.c | 182 ------------------------------------- src/restore.cpp | 182 +++++++++++++++++++++++++++++++++++++ 15 files changed, 1012 insertions(+), 1012 deletions(-) delete mode 100644 src/backup.c create mode 100644 src/backup.cpp delete mode 100644 src/file.c create mode 100644 src/file.cpp delete mode 100644 src/main.c create mode 100644 src/main.cpp delete mode 100644 src/options.c create mode 100644 src/options.cpp delete mode 100644 src/print.c create mode 100644 src/print.cpp delete mode 100644 src/resources.c create mode 100644 src/resources.cpp delete mode 100644 src/restore.c create mode 100644 src/restore.cpp (limited to 'src') diff --git a/src/Makefile b/src/Makefile index 7c5cb1f..7aa7e25 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,7 +1,7 @@ CC=g++ CFLAGS=-Wall -fmax-errors=2 -SOURCES=*.c +SOURCES=*.cpp HEADERS=*.h all: $(PROGRAM_NAME) diff --git a/src/backup.c b/src/backup.c deleted file mode 100644 index 0b558b6..0000000 --- a/src/backup.c +++ /dev/null @@ -1,156 +0,0 @@ -/* Copyright 2021 Ján Sučan - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "backup.h" - -#include "file.h" -#include "print.h" - -#include -#include -#include -#include - -static int check_files(const options_backup_t *const opts, - const resources_backup_t *const res); -static int write_out_buffer(const char *const buffer, size_t size, - FILE *const file); - -static int -check_files(const options_backup_t *const opts, - const resources_backup_t *const res) -{ - bool in_size_ok = false; - const size_t in_size = file_size(res->in_file, &in_size_ok); - - if (!in_size_ok) { - print_error("cannot get size of input file: %s", strerror(errno)); - return 1; - } - - bool ref_size_ok = false; - const size_t ref_size = file_size(res->ref_file, &ref_size_ok); - - if (!ref_size_ok) { - print_error("cannot get size of reference file: %s", strerror(errno)); - return 1; - } - - /* Check sizes of the input file and the reference file */ - if (in_size != ref_size) { - print_error("input file and reference file differ in size"); - return 1; - } else if ((in_size % opts->sector_size) != 0) { - print_error( - "size of input file and reference file is not multiple of %" PRIu32, - opts->sector_size); - return 1; - } - - return 0; -} - -static int -write_out_buffer(const char *const buffer, size_t size, FILE *const file) -{ - const size_t bytes_written = fwrite(buffer, 1U, size, file); - - if (bytes_written != size) { - print_error("cannot write to output file: %s", strerror(errno)); - return 1; - } - - return 0; -} - -int -backup(const options_backup_t *const opts, const resources_backup_t *const res) -{ - if (check_files(opts, res) != 0) { - return 1; - } - - size_t out_buffer_index = 0; - uint64_t input_file_offset = 0; - - for (;;) { - /* Read the sectors from the input and reference files into the buffers - */ - const size_t in_sectors_read = file_read_sectors( - res->in_file, res->in_buffer, opts->buffer_size, opts->sector_size); - const size_t ref_sectors_read = - file_read_sectors(res->ref_file, res->ref_buffer, opts->buffer_size, - opts->sector_size); - - if ((in_sectors_read == 0) || (ref_sectors_read == 0)) { - break; - } else if (in_sectors_read != ref_sectors_read) { - print_error( - "cannot read equal amount of sectors from the input files"); - return 1; - } - - /* Process the sectors in the buffers */ - for (size_t sector = 0; sector < in_sectors_read; ++sector) { - const size_t buffer_offset = sector * opts->sector_size; - - if (memcmp(res->in_buffer + buffer_offset, - res->ref_buffer + buffer_offset, - opts->sector_size) != 0) { - /* Backup the changed sector */ - if (out_buffer_index >= res->out_buffer_size) { - /* The output buffer is full. Write it to the output file */ - if (write_out_buffer(res->out_buffer, out_buffer_index, - res->out_file) != 0) { - return 1; - } - out_buffer_index = 0; - } - /* Write the next backup record */ - const uint64_t o = htole64(input_file_offset); - memcpy(res->out_buffer + out_buffer_index, (void *)&o, - sizeof(o)); - out_buffer_index += sizeof(o); - - memcpy(res->out_buffer + out_buffer_index, - res->in_buffer + buffer_offset, opts->sector_size); - out_buffer_index += opts->sector_size; - } - - input_file_offset += opts->sector_size; - } - } - - /* Write out the output buffer */ - if (out_buffer_index > 0) { - if (write_out_buffer(res->out_buffer, out_buffer_index, - res->out_file) != 0) { - return 1; - } - } - - return 0; -} diff --git a/src/backup.cpp b/src/backup.cpp new file mode 100644 index 0000000..0b558b6 --- /dev/null +++ b/src/backup.cpp @@ -0,0 +1,156 @@ +/* Copyright 2021 Ján Sučan + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "backup.h" + +#include "file.h" +#include "print.h" + +#include +#include +#include +#include + +static int check_files(const options_backup_t *const opts, + const resources_backup_t *const res); +static int write_out_buffer(const char *const buffer, size_t size, + FILE *const file); + +static int +check_files(const options_backup_t *const opts, + const resources_backup_t *const res) +{ + bool in_size_ok = false; + const size_t in_size = file_size(res->in_file, &in_size_ok); + + if (!in_size_ok) { + print_error("cannot get size of input file: %s", strerror(errno)); + return 1; + } + + bool ref_size_ok = false; + const size_t ref_size = file_size(res->ref_file, &ref_size_ok); + + if (!ref_size_ok) { + print_error("cannot get size of reference file: %s", strerror(errno)); + return 1; + } + + /* Check sizes of the input file and the reference file */ + if (in_size != ref_size) { + print_error("input file and reference file differ in size"); + return 1; + } else if ((in_size % opts->sector_size) != 0) { + print_error( + "size of input file and reference file is not multiple of %" PRIu32, + opts->sector_size); + return 1; + } + + return 0; +} + +static int +write_out_buffer(const char *const buffer, size_t size, FILE *const file) +{ + const size_t bytes_written = fwrite(buffer, 1U, size, file); + + if (bytes_written != size) { + print_error("cannot write to output file: %s", strerror(errno)); + return 1; + } + + return 0; +} + +int +backup(const options_backup_t *const opts, const resources_backup_t *const res) +{ + if (check_files(opts, res) != 0) { + return 1; + } + + size_t out_buffer_index = 0; + uint64_t input_file_offset = 0; + + for (;;) { + /* Read the sectors from the input and reference files into the buffers + */ + const size_t in_sectors_read = file_read_sectors( + res->in_file, res->in_buffer, opts->buffer_size, opts->sector_size); + const size_t ref_sectors_read = + file_read_sectors(res->ref_file, res->ref_buffer, opts->buffer_size, + opts->sector_size); + + if ((in_sectors_read == 0) || (ref_sectors_read == 0)) { + break; + } else if (in_sectors_read != ref_sectors_read) { + print_error( + "cannot read equal amount of sectors from the input files"); + return 1; + } + + /* Process the sectors in the buffers */ + for (size_t sector = 0; sector < in_sectors_read; ++sector) { + const size_t buffer_offset = sector * opts->sector_size; + + if (memcmp(res->in_buffer + buffer_offset, + res->ref_buffer + buffer_offset, + opts->sector_size) != 0) { + /* Backup the changed sector */ + if (out_buffer_index >= res->out_buffer_size) { + /* The output buffer is full. Write it to the output file */ + if (write_out_buffer(res->out_buffer, out_buffer_index, + res->out_file) != 0) { + return 1; + } + out_buffer_index = 0; + } + /* Write the next backup record */ + const uint64_t o = htole64(input_file_offset); + memcpy(res->out_buffer + out_buffer_index, (void *)&o, + sizeof(o)); + out_buffer_index += sizeof(o); + + memcpy(res->out_buffer + out_buffer_index, + res->in_buffer + buffer_offset, opts->sector_size); + out_buffer_index += opts->sector_size; + } + + input_file_offset += opts->sector_size; + } + } + + /* Write out the output buffer */ + if (out_buffer_index > 0) { + if (write_out_buffer(res->out_buffer, out_buffer_index, + res->out_file) != 0) { + return 1; + } + } + + return 0; +} diff --git a/src/file.c b/src/file.c deleted file mode 100644 index d605ceb..0000000 --- a/src/file.c +++ /dev/null @@ -1,84 +0,0 @@ -/* Copyright 2019 Ján Sučan - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "file.h" - -#include "print.h" - -#include -#include - -size_t -file_size(FILE *const file, bool *const return_is_ok) -{ - fpos_t p; - - if ((fgetpos(file, &p) != 0) || (fseek(file, 0L, SEEK_END) != 0)) { - *return_is_ok = false; - return 0; - } - - const long size = ftell(file); - - if (fsetpos(file, &p) != 0) { - *return_is_ok = false; - return 0; - } - - *return_is_ok = true; - return (size_t)size; -} - -size_t -file_tell(FILE *const file, bool *const return_is_ok) -{ - const long pos = ftell(file); - - if (pos < 0) { - *return_is_ok = false; - return 0; - } else { - *return_is_ok = true; - return (size_t)pos; - } -} - -size_t -file_read_sectors(FILE *const file, char *const buffer, uint32_t buffer_size, - uint32_t sector_size) -{ - const size_t bytes_read = fread(buffer, 1U, buffer_size, file); - - if (ferror(file)) { - print_error("cannot read from file: %s", strerror(errno)); - return 0; - } else if ((bytes_read % sector_size) != 0) { - print_error("data read from input file is not multiple of sector size"); - return 0; - } else { - return (bytes_read / sector_size); - } -} diff --git a/src/file.cpp b/src/file.cpp new file mode 100644 index 0000000..d605ceb --- /dev/null +++ b/src/file.cpp @@ -0,0 +1,84 @@ +/* Copyright 2019 Ján Sučan + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "file.h" + +#include "print.h" + +#include +#include + +size_t +file_size(FILE *const file, bool *const return_is_ok) +{ + fpos_t p; + + if ((fgetpos(file, &p) != 0) || (fseek(file, 0L, SEEK_END) != 0)) { + *return_is_ok = false; + return 0; + } + + const long size = ftell(file); + + if (fsetpos(file, &p) != 0) { + *return_is_ok = false; + return 0; + } + + *return_is_ok = true; + return (size_t)size; +} + +size_t +file_tell(FILE *const file, bool *const return_is_ok) +{ + const long pos = ftell(file); + + if (pos < 0) { + *return_is_ok = false; + return 0; + } else { + *return_is_ok = true; + return (size_t)pos; + } +} + +size_t +file_read_sectors(FILE *const file, char *const buffer, uint32_t buffer_size, + uint32_t sector_size) +{ + const size_t bytes_read = fread(buffer, 1U, buffer_size, file); + + if (ferror(file)) { + print_error("cannot read from file: %s", strerror(errno)); + return 0; + } else if ((bytes_read % sector_size) != 0) { + print_error("data read from input file is not multiple of sector size"); + return 0; + } else { + return (bytes_read / sector_size); + } +} diff --git a/src/main.c b/src/main.c deleted file mode 100644 index 35e5c3d..0000000 --- a/src/main.c +++ /dev/null @@ -1,63 +0,0 @@ -/* Copyright 2019 Ján Sučan - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "backup.h" -#include "options.h" -#include "resources.h" -#include "restore.h" - -#include - -static void -clean_exit(resources_t *const res, int exit_code) -{ - resources_free(res); - exit(exit_code); -} - -int -main(int argc, char **argv) -{ - options_t opts; - - if (!options_parse(argc, argv, &opts)) { - options_usage(1); - } else if (options_is_operation(&opts, OPERATION_ID_HELP)) { - options_usage(0); - } - - resources_t res; - - if (resources_allocate(&opts, &res)) { - clean_exit(&res, 1); - } else if (options_is_operation(&opts, OPERATION_ID_BACKUP)) { - clean_exit(&res, backup(options_get_for_backup(&opts), - resources_get_for_backup(&res))); - } else { - clean_exit(&res, restore(options_get_for_restore(&opts), - resources_get_for_restore(&res))); - } -} diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..35e5c3d --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,63 @@ +/* Copyright 2019 Ján Sučan + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "backup.h" +#include "options.h" +#include "resources.h" +#include "restore.h" + +#include + +static void +clean_exit(resources_t *const res, int exit_code) +{ + resources_free(res); + exit(exit_code); +} + +int +main(int argc, char **argv) +{ + options_t opts; + + if (!options_parse(argc, argv, &opts)) { + options_usage(1); + } else if (options_is_operation(&opts, OPERATION_ID_HELP)) { + options_usage(0); + } + + resources_t res; + + if (resources_allocate(&opts, &res)) { + clean_exit(&res, 1); + } else if (options_is_operation(&opts, OPERATION_ID_BACKUP)) { + clean_exit(&res, backup(options_get_for_backup(&opts), + resources_get_for_backup(&res))); + } else { + clean_exit(&res, restore(options_get_for_restore(&opts), + resources_get_for_restore(&res))); + } +} diff --git a/src/options.c b/src/options.c deleted file mode 100644 index e2fcfdb..0000000 --- a/src/options.c +++ /dev/null @@ -1,266 +0,0 @@ -/* Copyright 2019 Ján Sučan - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "options.h" - -#include "print.h" - -#include -#include -#include -#include -#include - -/* This header file is automatically generated at build time from the Makefile - */ -#include "program_info.h" - -#define OPTIONS_MAX_OPERATION_NAME_LENGTH 8 -#define OPTIONS_DEFAULT_SECTOR_SIZE 512 -#define OPTIONS_DEFAULT_BUFFER_SIZE (4 * 1024 * 1024) - -struct common_options { - bool help; - uint32_t sector_size; - uint32_t buffer_size; -}; - -static int options_parse_unsigned(const char *const arg, uint32_t *const value); -static void options_parse_operation(const char *const argv, - options_t *const opts); -static bool options_parse_common(int *const argc, char ***const argv, - struct common_options *const opts); -static bool options_parse_backup(int *const argc, char ***const argv, - options_t *const opts); -static bool options_parse_restore(int *const argc, char ***const argv, - options_t *const opts); - -bool -options_parse(int argc, char **argv, options_t *const opts) -{ - // Skip the executable name - --argc; - ++argv; - - options_parse_operation(argv[0], opts); - - if (options_is_operation(opts, OPERATION_ID_UNKNOWN)) { - return false; - } - - if (options_is_operation(opts, OPERATION_ID_BACKUP)) { - if (!options_parse_backup(&argc, &argv, opts)) { - return false; - } - } else if (options_is_operation(opts, OPERATION_ID_RESTORE)) { - if (!options_parse_restore(&argc, &argv, opts)) { - return false; - } - } - return true; -} - -void -options_usage(int exit_code) -{ - printf("Usage: %s [-s SECTOR_SIZE] [-b BUFFER_SIZE] [INFILE] REFFILE " - "OUTFILE\n", - PROGRAM_NAME_STR); - exit(exit_code); -} - -bool -options_is_operation(const options_t *const opts, operation_id_t operation_id) -{ - return (opts->operation_id == operation_id); -} - -const options_backup_t * -options_get_for_backup(const options_t *const opts) -{ - return &(opts->op.backup); -} - -const options_restore_t * -options_get_for_restore(const options_t *const opts) -{ - return &(opts->op.restore); -} - -static int -options_parse_unsigned(const char *const arg, uint32_t *const value) -{ - char *end; - - errno = 0; - - *value = strtoul(arg, &end, 0); - - return ((*end != '\0') || (errno != 0)) ? -1 : 0; -} - -static void -options_parse_operation(const char *const op_name, options_t *const opts) -{ - if (op_name == NULL) { - opts->operation_id = OPERATION_ID_UNKNOWN; - } else if (strncmp(op_name, "help", OPTIONS_MAX_OPERATION_NAME_LENGTH) == - 0) { - opts->operation_id = OPERATION_ID_HELP; - } else if (strncmp(op_name, "backup", OPTIONS_MAX_OPERATION_NAME_LENGTH) == - 0) { - opts->operation_id = OPERATION_ID_BACKUP; - } else if (strncmp(op_name, "restore", OPTIONS_MAX_OPERATION_NAME_LENGTH) == - 0) { - opts->operation_id = OPERATION_ID_RESTORE; - } else { - opts->operation_id = OPERATION_ID_UNKNOWN; - } -} - -static void -options_init_common(struct common_options *const opts) -{ - opts->help = false; - opts->sector_size = OPTIONS_DEFAULT_SECTOR_SIZE; - opts->buffer_size = OPTIONS_DEFAULT_BUFFER_SIZE; -} - -static bool -options_parse_common(int *const argc, char ***const argv, - struct common_options *const opts) -{ - int ch; - char *arg_sector_size = NULL; - char *arg_buffer_size = NULL; - - while ((ch = getopt(*argc, *argv, ":b:hs:")) != -1) { - switch (ch) { - case 'b': - arg_buffer_size = optarg; - break; - - case 'h': - opts->help = true; - break; - - case 's': - arg_sector_size = optarg; - break; - - case ':': - print_error("missing argument for option '-%c'", optopt); - return false; - default: - print_error("unknown option '-%c'", optopt); - return false; - } - } - - *argc -= optind; - *argv += optind; - - /* Convert numbers in the arguments */ - if ((arg_sector_size != NULL) && - options_parse_unsigned(arg_sector_size, &(opts->sector_size))) { - print_error("incorrect sector size"); - return false; - } else if ((arg_buffer_size != NULL) && - options_parse_unsigned(arg_buffer_size, &(opts->buffer_size))) { - print_error("incorrect buffer size"); - return false; - } else if (opts->sector_size == 0) { - print_error("sector size cannot be 0"); - return false; - } else if (opts->buffer_size == 0) { - print_error("buffer size cannot be 0"); - return false; - } else if (opts->sector_size > opts->buffer_size) { - print_error("sector size cannot larger than buffer size"); - return false; - } else if ((opts->buffer_size % opts->sector_size) != 0) { - print_error("buffer size is not multiple of sector size"); - return false; - } - - return true; -} - -static bool -options_parse_backup(int *const argc, char ***const argv, options_t *const opts) -{ - struct common_options common_opts; - options_init_common(&common_opts); - if (!options_parse_common(argc, argv, &common_opts)) { - return false; - } - - if (common_opts.help) { - opts->operation_id = OPERATION_ID_HELP; - } else if (*argc < 3) { - print_error("missing arguments"); - return false; - } else if (*argc > 3) { - print_error("too many arguments"); - return false; - } else { - opts->op.backup.sector_size = common_opts.sector_size; - opts->op.backup.buffer_size = common_opts.buffer_size; - opts->op.backup.in_file_path = (*argv)[0]; - opts->op.backup.ref_file_path = (*argv)[1]; - opts->op.backup.out_file_path = (*argv)[2]; - } - - return true; -} - -static bool -options_parse_restore(int *const argc, char ***const argv, - options_t *const opts) -{ - struct common_options common_opts; - options_init_common(&common_opts); - if (!options_parse_common(argc, argv, &common_opts)) { - return false; - } - - if (common_opts.help) { - opts->operation_id = OPERATION_ID_HELP; - } else if (*argc < 2) { - print_error("missing arguments"); - return false; - } else if (*argc > 2) { - print_error("too many arguments"); - return false; - } else { - opts->op.restore.sector_size = common_opts.sector_size; - opts->op.restore.buffer_size = common_opts.buffer_size; - opts->op.restore.in_file_path = (*argv)[0]; - opts->op.restore.out_file_path = (*argv)[1]; - } - - return true; -} diff --git a/src/options.cpp b/src/options.cpp new file mode 100644 index 0000000..e2fcfdb --- /dev/null +++ b/src/options.cpp @@ -0,0 +1,266 @@ +/* Copyright 2019 Ján Sučan + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "options.h" + +#include "print.h" + +#include +#include +#include +#include +#include + +/* This header file is automatically generated at build time from the Makefile + */ +#include "program_info.h" + +#define OPTIONS_MAX_OPERATION_NAME_LENGTH 8 +#define OPTIONS_DEFAULT_SECTOR_SIZE 512 +#define OPTIONS_DEFAULT_BUFFER_SIZE (4 * 1024 * 1024) + +struct common_options { + bool help; + uint32_t sector_size; + uint32_t buffer_size; +}; + +static int options_parse_unsigned(const char *const arg, uint32_t *const value); +static void options_parse_operation(const char *const argv, + options_t *const opts); +static bool options_parse_common(int *const argc, char ***const argv, + struct common_options *const opts); +static bool options_parse_backup(int *const argc, char ***const argv, + options_t *const opts); +static bool options_parse_restore(int *const argc, char ***const argv, + options_t *const opts); + +bool +options_parse(int argc, char **argv, options_t *const opts) +{ + // Skip the executable name + --argc; + ++argv; + + options_parse_operation(argv[0], opts); + + if (options_is_operation(opts, OPERATION_ID_UNKNOWN)) { + return false; + } + + if (options_is_operation(opts, OPERATION_ID_BACKUP)) { + if (!options_parse_backup(&argc, &argv, opts)) { + return false; + } + } else if (options_is_operation(opts, OPERATION_ID_RESTORE)) { + if (!options_parse_restore(&argc, &argv, opts)) { + return false; + } + } + return true; +} + +void +options_usage(int exit_code) +{ + printf("Usage: %s [-s SECTOR_SIZE] [-b BUFFER_SIZE] [INFILE] REFFILE " + "OUTFILE\n", + PROGRAM_NAME_STR); + exit(exit_code); +} + +bool +options_is_operation(const options_t *const opts, operation_id_t operation_id) +{ + return (opts->operation_id == operation_id); +} + +const options_backup_t * +options_get_for_backup(const options_t *const opts) +{ + return &(opts->op.backup); +} + +const options_restore_t * +options_get_for_restore(const options_t *const opts) +{ + return &(opts->op.restore); +} + +static int +options_parse_unsigned(const char *const arg, uint32_t *const value) +{ + char *end; + + errno = 0; + + *value = strtoul(arg, &end, 0); + + return ((*end != '\0') || (errno != 0)) ? -1 : 0; +} + +static void +options_parse_operation(const char *const op_name, options_t *const opts) +{ + if (op_name == NULL) { + opts->operation_id = OPERATION_ID_UNKNOWN; + } else if (strncmp(op_name, "help", OPTIONS_MAX_OPERATION_NAME_LENGTH) == + 0) { + opts->operation_id = OPERATION_ID_HELP; + } else if (strncmp(op_name, "backup", OPTIONS_MAX_OPERATION_NAME_LENGTH) == + 0) { + opts->operation_id = OPERATION_ID_BACKUP; + } else if (strncmp(op_name, "restore", OPTIONS_MAX_OPERATION_NAME_LENGTH) == + 0) { + opts->operation_id = OPERATION_ID_RESTORE; + } else { + opts->operation_id = OPERATION_ID_UNKNOWN; + } +} + +static void +options_init_common(struct common_options *const opts) +{ + opts->help = false; + opts->sector_size = OPTIONS_DEFAULT_SECTOR_SIZE; + opts->buffer_size = OPTIONS_DEFAULT_BUFFER_SIZE; +} + +static bool +options_parse_common(int *const argc, char ***const argv, + struct common_options *const opts) +{ + int ch; + char *arg_sector_size = NULL; + char *arg_buffer_size = NULL; + + while ((ch = getopt(*argc, *argv, ":b:hs:")) != -1) { + switch (ch) { + case 'b': + arg_buffer_size = optarg; + break; + + case 'h': + opts->help = true; + break; + + case 's': + arg_sector_size = optarg; + break; + + case ':': + print_error("missing argument for option '-%c'", optopt); + return false; + default: + print_error("unknown option '-%c'", optopt); + return false; + } + } + + *argc -= optind; + *argv += optind; + + /* Convert numbers in the arguments */ + if ((arg_sector_size != NULL) && + options_parse_unsigned(arg_sector_size, &(opts->sector_size))) { + print_error("incorrect sector size"); + return false; + } else if ((arg_buffer_size != NULL) && + options_parse_unsigned(arg_buffer_size, &(opts->buffer_size))) { + print_error("incorrect buffer size"); + return false; + } else if (opts->sector_size == 0) { + print_error("sector size cannot be 0"); + return false; + } else if (opts->buffer_size == 0) { + print_error("buffer size cannot be 0"); + return false; + } else if (opts->sector_size > opts->buffer_size) { + print_error("sector size cannot larger than buffer size"); + return false; + } else if ((opts->buffer_size % opts->sector_size) != 0) { + print_error("buffer size is not multiple of sector size"); + return false; + } + + return true; +} + +static bool +options_parse_backup(int *const argc, char ***const argv, options_t *const opts) +{ + struct common_options common_opts; + options_init_common(&common_opts); + if (!options_parse_common(argc, argv, &common_opts)) { + return false; + } + + if (common_opts.help) { + opts->operation_id = OPERATION_ID_HELP; + } else if (*argc < 3) { + print_error("missing arguments"); + return false; + } else if (*argc > 3) { + print_error("too many arguments"); + return false; + } else { + opts->op.backup.sector_size = common_opts.sector_size; + opts->op.backup.buffer_size = common_opts.buffer_size; + opts->op.backup.in_file_path = (*argv)[0]; + opts->op.backup.ref_file_path = (*argv)[1]; + opts->op.backup.out_file_path = (*argv)[2]; + } + + return true; +} + +static bool +options_parse_restore(int *const argc, char ***const argv, + options_t *const opts) +{ + struct common_options common_opts; + options_init_common(&common_opts); + if (!options_parse_common(argc, argv, &common_opts)) { + return false; + } + + if (common_opts.help) { + opts->operation_id = OPERATION_ID_HELP; + } else if (*argc < 2) { + print_error("missing arguments"); + return false; + } else if (*argc > 2) { + print_error("too many arguments"); + return false; + } else { + opts->op.restore.sector_size = common_opts.sector_size; + opts->op.restore.buffer_size = common_opts.buffer_size; + opts->op.restore.in_file_path = (*argv)[0]; + opts->op.restore.out_file_path = (*argv)[1]; + } + + return true; +} diff --git a/src/print.c b/src/print.c deleted file mode 100644 index 1dcb75a..0000000 --- a/src/print.c +++ /dev/null @@ -1,47 +0,0 @@ -/* Copyright 2019 Ján Sučan - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "print.h" - -#include -#include - -#define PRINT_ERROR_PREFIX "ERROR: " -#define PRINT_ERROR_SUFFIX "\n" - -void -print_error(const char *const format, ...) -{ - fprintf(stderr, PRINT_ERROR_PREFIX); - - va_list args; - - va_start(args, format); - vfprintf(stderr, format, args); - va_end(args); - - fprintf(stderr, PRINT_ERROR_SUFFIX); -} diff --git a/src/print.cpp b/src/print.cpp new file mode 100644 index 0000000..1dcb75a --- /dev/null +++ b/src/print.cpp @@ -0,0 +1,47 @@ +/* Copyright 2019 Ján Sučan + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "print.h" + +#include +#include + +#define PRINT_ERROR_PREFIX "ERROR: " +#define PRINT_ERROR_SUFFIX "\n" + +void +print_error(const char *const format, ...) +{ + fprintf(stderr, PRINT_ERROR_PREFIX); + + va_list args; + + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + + fprintf(stderr, PRINT_ERROR_SUFFIX); +} diff --git a/src/resources.c b/src/resources.c deleted file mode 100644 index 0829c7c..0000000 --- a/src/resources.c +++ /dev/null @@ -1,213 +0,0 @@ -/* Copyright 2019 Ján Sučan - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "resources.h" - -#include "print.h" - -#include -#include -#include -#include - -static void -resources_init_for_backup(resources_backup_t *const res) -{ - res->in_file = NULL; - res->ref_file = NULL; - res->out_file = NULL; - - res->in_buffer = NULL; - res->ref_buffer = NULL; - res->out_buffer = NULL; -} - -static int -resources_allocate_for_backup(const options_backup_t *const opts, - resources_backup_t *const res) -{ - if ((res->in_file = fopen(opts->in_file_path, "r")) == NULL) { - print_error("cannot open input file: %s", strerror(errno)); - return 1; - } - - if ((res->ref_file = fopen(opts->ref_file_path, "r")) == NULL) { - print_error("cannot open reference file: %s", strerror(errno)); - return 1; - } - - /* When backing up, the output file is truncated to hold the - * new data - */ - if ((res->out_file = fopen(opts->out_file_path, "w+")) == NULL) { - print_error("cannot open output file: %s", strerror(errno)); - return 1; - } - - /* The output buffer contains also the offsets */ - res->out_buffer_size = - ((opts->buffer_size / opts->sector_size) * sizeof(uint64_t)) + - opts->buffer_size; - - // TODO: separate function - if ((res->in_buffer = (char *)malloc(opts->buffer_size)) == NULL) { - print_error("cannot allocate buffer for input file data"); - return 1; - } else if ((res->ref_buffer = (char *)malloc(opts->buffer_size)) == NULL) { - print_error("cannot allocate buffer for reference file data"); - return 1; - } else if ((res->out_buffer = (char *)malloc(res->out_buffer_size)) == - NULL) { - print_error("cannot allocate buffer for output file data"); - return 1; - } - - return 0; -} - -static void -resources_init_for_restore(resources_restore_t *const res) -{ - res->in_file = NULL; - res->out_file = NULL; - - res->in_buffer = NULL; - res->out_buffer = NULL; -} - -static int -resources_allocate_for_restore(const options_restore_t *const opts, - resources_restore_t *const res) -{ - if ((res->in_file = fopen(opts->in_file_path, "r")) == NULL) { - print_error("cannot open input file: %s", strerror(errno)); - return 1; - } - - /* When restoring, the file must be opened for writing and not - * truncated - */ - if ((res->out_file = fopen(opts->out_file_path, "r+")) == NULL) { - print_error("cannot open output file: %s", strerror(errno)); - return 1; - } - - /* Allocate the buffer for data from the input file */ - /* The input buffer contains also the offsets */ - res->in_sector_size = sizeof(uint64_t) + opts->sector_size; - const size_t in_buffer_sector_count = - opts->buffer_size / res->in_sector_size; - res->in_buffer_size = in_buffer_sector_count * res->in_sector_size; - - if ((res->in_buffer = (char *)malloc(res->in_buffer_size)) == NULL) { - print_error("cannot allocate buffer for input file data"); - return 1; - } - - return 0; -} - -static void -resources_close_file(FILE **const file) -{ - if (*file != NULL) { - fclose(*file); - *file = NULL; - } -} - -static void -resources_close_buffer(char **const buffer) -{ - if (*buffer != NULL) { - free(*buffer); - *buffer = NULL; - } -} - -static void -resources_free_backup(resources_backup_t *const res) -{ - resources_close_file(&(res->in_file)); - resources_close_file(&(res->ref_file)); - resources_close_file(&(res->out_file)); - - resources_close_buffer(&(res->in_buffer)); - resources_close_buffer(&(res->ref_buffer)); - resources_close_buffer(&(res->out_buffer)); -} - -static void -resources_free_restore(resources_restore_t *const res) -{ - resources_close_file(&(res->in_file)); - resources_close_file(&(res->out_file)); - - resources_close_buffer(&(res->in_buffer)); - resources_close_buffer(&(res->out_buffer)); -} - -int -resources_allocate(const options_t *const opts, resources_t *const res) -{ - res->operation_id = opts->operation_id; - - if (res->operation_id == OPERATION_ID_BACKUP) { - resources_init_for_backup(&(res->res.backup)); - return resources_allocate_for_backup(&(opts->op.backup), - &(res->res.backup)); - } else if (res->operation_id == OPERATION_ID_RESTORE) { - resources_init_for_restore(&(res->res.restore)); - return resources_allocate_for_restore(&(opts->op.restore), - &(res->res.restore)); - } - - return 0; -} - -const resources_backup_t * -resources_get_for_backup(const resources_t *const res) -{ - return &(res->res.backup); -} - -const resources_restore_t * -resources_get_for_restore(const resources_t *const res) -{ - return &(res->res.restore); -} - -void -resources_free(resources_t *const res) -{ - if (res->operation_id == OPERATION_ID_BACKUP) { - resources_free_backup(&(res->res.backup)); - } else if (res->operation_id == OPERATION_ID_RESTORE) { - resources_free_restore(&(res->res.restore)); - } - - res->operation_id = OPERATION_ID_UNKNOWN; -} diff --git a/src/resources.cpp b/src/resources.cpp new file mode 100644 index 0000000..0829c7c --- /dev/null +++ b/src/resources.cpp @@ -0,0 +1,213 @@ +/* Copyright 2019 Ján Sučan + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "resources.h" + +#include "print.h" + +#include +#include +#include +#include + +static void +resources_init_for_backup(resources_backup_t *const res) +{ + res->in_file = NULL; + res->ref_file = NULL; + res->out_file = NULL; + + res->in_buffer = NULL; + res->ref_buffer = NULL; + res->out_buffer = NULL; +} + +static int +resources_allocate_for_backup(const options_backup_t *const opts, + resources_backup_t *const res) +{ + if ((res->in_file = fopen(opts->in_file_path, "r")) == NULL) { + print_error("cannot open input file: %s", strerror(errno)); + return 1; + } + + if ((res->ref_file = fopen(opts->ref_file_path, "r")) == NULL) { + print_error("cannot open reference file: %s", strerror(errno)); + return 1; + } + + /* When backing up, the output file is truncated to hold the + * new data + */ + if ((res->out_file = fopen(opts->out_file_path, "w+")) == NULL) { + print_error("cannot open output file: %s", strerror(errno)); + return 1; + } + + /* The output buffer contains also the offsets */ + res->out_buffer_size = + ((opts->buffer_size / opts->sector_size) * sizeof(uint64_t)) + + opts->buffer_size; + + // TODO: separate function + if ((res->in_buffer = (char *)malloc(opts->buffer_size)) == NULL) { + print_error("cannot allocate buffer for input file data"); + return 1; + } else if ((res->ref_buffer = (char *)malloc(opts->buffer_size)) == NULL) { + print_error("cannot allocate buffer for reference file data"); + return 1; + } else if ((res->out_buffer = (char *)malloc(res->out_buffer_size)) == + NULL) { + print_error("cannot allocate buffer for output file data"); + return 1; + } + + return 0; +} + +static void +resources_init_for_restore(resources_restore_t *const res) +{ + res->in_file = NULL; + res->out_file = NULL; + + res->in_buffer = NULL; + res->out_buffer = NULL; +} + +static int +resources_allocate_for_restore(const options_restore_t *const opts, + resources_restore_t *const res) +{ + if ((res->in_file = fopen(opts->in_file_path, "r")) == NULL) { + print_error("cannot open input file: %s", strerror(errno)); + return 1; + } + + /* When restoring, the file must be opened for writing and not + * truncated + */ + if ((res->out_file = fopen(opts->out_file_path, "r+")) == NULL) { + print_error("cannot open output file: %s", strerror(errno)); + return 1; + } + + /* Allocate the buffer for data from the input file */ + /* The input buffer contains also the offsets */ + res->in_sector_size = sizeof(uint64_t) + opts->sector_size; + const size_t in_buffer_sector_count = + opts->buffer_size / res->in_sector_size; + res->in_buffer_size = in_buffer_sector_count * res->in_sector_size; + + if ((res->in_buffer = (char *)malloc(res->in_buffer_size)) == NULL) { + print_error("cannot allocate buffer for input file data"); + return 1; + } + + return 0; +} + +static void +resources_close_file(FILE **const file) +{ + if (*file != NULL) { + fclose(*file); + *file = NULL; + } +} + +static void +resources_close_buffer(char **const buffer) +{ + if (*buffer != NULL) { + free(*buffer); + *buffer = NULL; + } +} + +static void +resources_free_backup(resources_backup_t *const res) +{ + resources_close_file(&(res->in_file)); + resources_close_file(&(res->ref_file)); + resources_close_file(&(res->out_file)); + + resources_close_buffer(&(res->in_buffer)); + resources_close_buffer(&(res->ref_buffer)); + resources_close_buffer(&(res->out_buffer)); +} + +static void +resources_free_restore(resources_restore_t *const res) +{ + resources_close_file(&(res->in_file)); + resources_close_file(&(res->out_file)); + + resources_close_buffer(&(res->in_buffer)); + resources_close_buffer(&(res->out_buffer)); +} + +int +resources_allocate(const options_t *const opts, resources_t *const res) +{ + res->operation_id = opts->operation_id; + + if (res->operation_id == OPERATION_ID_BACKUP) { + resources_init_for_backup(&(res->res.backup)); + return resources_allocate_for_backup(&(opts->op.backup), + &(res->res.backup)); + } else if (res->operation_id == OPERATION_ID_RESTORE) { + resources_init_for_restore(&(res->res.restore)); + return resources_allocate_for_restore(&(opts->op.restore), + &(res->res.restore)); + } + + return 0; +} + +const resources_backup_t * +resources_get_for_backup(const resources_t *const res) +{ + return &(res->res.backup); +} + +const resources_restore_t * +resources_get_for_restore(const resources_t *const res) +{ + return &(res->res.restore); +} + +void +resources_free(resources_t *const res) +{ + if (res->operation_id == OPERATION_ID_BACKUP) { + resources_free_backup(&(res->res.backup)); + } else if (res->operation_id == OPERATION_ID_RESTORE) { + resources_free_restore(&(res->res.restore)); + } + + res->operation_id = OPERATION_ID_UNKNOWN; +} diff --git a/src/restore.c b/src/restore.c deleted file mode 100644 index e73e42e..0000000 --- a/src/restore.c +++ /dev/null @@ -1,182 +0,0 @@ -/* Copyright 2021 Ján Sučan - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "restore.h" - -#include "file.h" -#include "print.h" - -#include -#include -#include -#include -#include -#include - -static bool -is_input_file_valid(const resources_restore_t *const res, uint32_t sector_size) -{ - bool in_size_ok = false; - const size_t in_size = file_size(res->in_file, &in_size_ok); - - if (!in_size_ok) { - print_error("cannot get size of input file: %s", strerror(errno)); - return false; - } else if (in_size == 0) { - print_error("input file is empty"); - return false; - } else if ((in_size % (sizeof(uint64_t) + sector_size)) != 0) { - /* The input file must hold equally sized sectors and the - * offset of each of them - */ - print_error("input file has size that cannot contain valid diff data"); - return false; - } - - bool out_size_ok = false; - const size_t out_size = file_size(res->out_file, &out_size_ok); - - if (!out_size_ok) { - print_error("cannot get size of output file: %s", strerror(errno)); - return 1; - } - - uint64_t prev_out_offset = 0; - bool is_first_reading = true; - - /* Scan the input file and check */ - for (;;) { - uint64_t out_offset; - /* Read the next offset */ - const size_t in_read = - fread(&out_offset, sizeof(out_offset), 1U, res->in_file); - out_offset = le64toh(out_offset); - - if (feof(res->in_file)) { - break; - } else if ((in_read != 1U) || ferror(res->in_file)) { - print_error("cannot read from input file: %s", strerror(errno)); - return false; - } else if (!is_first_reading && (out_offset <= prev_out_offset)) { - print_error("a sector offset points behind the previous offset"); - return false; - } else if ((out_offset + sector_size) > out_size) { - print_error( - "a sector offset points past the end of the output file"); - return false; - } else if (fseek(res->in_file, sector_size, SEEK_CUR) != 0) { - print_error("cannot seek in input file: %s", strerror(errno)); - return false; - } - - is_first_reading = false; - prev_out_offset = out_offset; - } - - bool pos_ok = false; - const size_t pos = file_tell(res->in_file, &pos_ok); - - if (!pos_ok) { - print_error("cannot get position in the input file"); - return false; - } else if (pos != in_size) { - /* The input file must be read completely */ - print_error("input file is not valid"); - return false; - } else if (fseek(res->in_file, 0L, SEEK_SET) != 0) { - /* The file must be prepared for the restoring */ - print_error("cannot seek in input file: %s", strerror(errno)); - return false; - } - - return true; -} - -int -restore(const options_restore_t *const opts, - const resources_restore_t *const res) -{ - /* Check validity of the input file */ - if (!is_input_file_valid(res, opts->sector_size)) { - return 1; - } - - bool in_size_ok = false; - const size_t in_size = file_size(res->in_file, &in_size_ok); - - if (!in_size_ok) { - print_error("cannot get size of input file: %s", strerror(errno)); - return 1; - } - - /* Restore data from the differential image */ - for (;;) { - - /* Read data of the offset and the next sector */ - const size_t in_sectors_read = - file_read_sectors(res->in_file, res->in_buffer, res->in_buffer_size, - res->in_sector_size); - - if (in_sectors_read == 0) { - break; - } - - char *in_buffer = res->in_buffer; - - for (size_t s = 0; s < in_sectors_read; ++s) { - const uint64_t out_offset = le64toh(*((uint64_t *)in_buffer)); - in_buffer += sizeof(uint64_t); - - if (fseek(res->out_file, out_offset, SEEK_SET) != 0) { - print_error("cannot seek in output file: %s", strerror(errno)); - return 1; - } - - const size_t out_written = - fwrite(in_buffer, opts->sector_size, 1U, res->out_file); - in_buffer += opts->sector_size; - - if (out_written != 1U) { - print_error("cannot write to output file: %s", strerror(errno)); - return 1; - } - } - } - - /* The input file must be read completely */ - bool pos_ok = false; - const size_t pos = file_tell(res->in_file, &pos_ok); - - if (!pos_ok) { - print_error("cannot get position in the input file"); - return 1; - } else if (pos != in_size) { - print_error("input file is not valid"); - return 1; - } - - return 0; -} diff --git a/src/restore.cpp b/src/restore.cpp new file mode 100644 index 0000000..e73e42e --- /dev/null +++ b/src/restore.cpp @@ -0,0 +1,182 @@ +/* Copyright 2021 Ján Sučan + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "restore.h" + +#include "file.h" +#include "print.h" + +#include +#include +#include +#include +#include +#include + +static bool +is_input_file_valid(const resources_restore_t *const res, uint32_t sector_size) +{ + bool in_size_ok = false; + const size_t in_size = file_size(res->in_file, &in_size_ok); + + if (!in_size_ok) { + print_error("cannot get size of input file: %s", strerror(errno)); + return false; + } else if (in_size == 0) { + print_error("input file is empty"); + return false; + } else if ((in_size % (sizeof(uint64_t) + sector_size)) != 0) { + /* The input file must hold equally sized sectors and the + * offset of each of them + */ + print_error("input file has size that cannot contain valid diff data"); + return false; + } + + bool out_size_ok = false; + const size_t out_size = file_size(res->out_file, &out_size_ok); + + if (!out_size_ok) { + print_error("cannot get size of output file: %s", strerror(errno)); + return 1; + } + + uint64_t prev_out_offset = 0; + bool is_first_reading = true; + + /* Scan the input file and check */ + for (;;) { + uint64_t out_offset; + /* Read the next offset */ + const size_t in_read = + fread(&out_offset, sizeof(out_offset), 1U, res->in_file); + out_offset = le64toh(out_offset); + + if (feof(res->in_file)) { + break; + } else if ((in_read != 1U) || ferror(res->in_file)) { + print_error("cannot read from input file: %s", strerror(errno)); + return false; + } else if (!is_first_reading && (out_offset <= prev_out_offset)) { + print_error("a sector offset points behind the previous offset"); + return false; + } else if ((out_offset + sector_size) > out_size) { + print_error( + "a sector offset points past the end of the output file"); + return false; + } else if (fseek(res->in_file, sector_size, SEEK_CUR) != 0) { + print_error("cannot seek in input file: %s", strerror(errno)); + return false; + } + + is_first_reading = false; + prev_out_offset = out_offset; + } + + bool pos_ok = false; + const size_t pos = file_tell(res->in_file, &pos_ok); + + if (!pos_ok) { + print_error("cannot get position in the input file"); + return false; + } else if (pos != in_size) { + /* The input file must be read completely */ + print_error("input file is not valid"); + return false; + } else if (fseek(res->in_file, 0L, SEEK_SET) != 0) { + /* The file must be prepared for the restoring */ + print_error("cannot seek in input file: %s", strerror(errno)); + return false; + } + + return true; +} + +int +restore(const options_restore_t *const opts, + const resources_restore_t *const res) +{ + /* Check validity of the input file */ + if (!is_input_file_valid(res, opts->sector_size)) { + return 1; + } + + bool in_size_ok = false; + const size_t in_size = file_size(res->in_file, &in_size_ok); + + if (!in_size_ok) { + print_error("cannot get size of input file: %s", strerror(errno)); + return 1; + } + + /* Restore data from the differential image */ + for (;;) { + + /* Read data of the offset and the next sector */ + const size_t in_sectors_read = + file_read_sectors(res->in_file, res->in_buffer, res->in_buffer_size, + res->in_sector_size); + + if (in_sectors_read == 0) { + break; + } + + char *in_buffer = res->in_buffer; + + for (size_t s = 0; s < in_sectors_read; ++s) { + const uint64_t out_offset = le64toh(*((uint64_t *)in_buffer)); + in_buffer += sizeof(uint64_t); + + if (fseek(res->out_file, out_offset, SEEK_SET) != 0) { + print_error("cannot seek in output file: %s", strerror(errno)); + return 1; + } + + const size_t out_written = + fwrite(in_buffer, opts->sector_size, 1U, res->out_file); + in_buffer += opts->sector_size; + + if (out_written != 1U) { + print_error("cannot write to output file: %s", strerror(errno)); + return 1; + } + } + } + + /* The input file must be read completely */ + bool pos_ok = false; + const size_t pos = file_tell(res->in_file, &pos_ok); + + if (!pos_ok) { + print_error("cannot get position in the input file"); + return 1; + } else if (pos != in_size) { + print_error("input file is not valid"); + return 1; + } + + return 0; +} -- cgit v1.2.3