From e86c9c6135ba0462c5a352e6d8ea4b730aa9c370 Mon Sep 17 00:00:00 2001 From: Jan Sucan Date: Sun, 24 Mar 2024 16:22:08 +0100 Subject: Rewrite the option code in object-oriented way --- src/backup.cpp | 112 ++++++++++++++++----- src/backup.h | 4 +- src/main.cpp | 44 ++++---- src/options.cpp | 294 ++++++++++++++++++++++++------------------------------ src/options.h | 109 ++++++++++++++------ src/resources.cpp | 213 --------------------------------------- src/resources.h | 74 -------------- src/restore.cpp | 71 ++++++++++--- src/restore.h | 4 +- 9 files changed, 373 insertions(+), 552 deletions(-) delete mode 100644 src/resources.cpp delete mode 100644 src/resources.h diff --git a/src/backup.cpp b/src/backup.cpp index 0b558b6..b0b0054 100644 --- a/src/backup.cpp +++ b/src/backup.cpp @@ -34,14 +34,69 @@ #include #include -static int check_files(const options_backup_t *const opts, +typedef struct { + FILE *in_file; + FILE *ref_file; + FILE *out_file; + + char *in_buffer; + char *ref_buffer; + char *out_buffer; + + size_t out_buffer_size; +} resources_backup_t; + +static int check_files(const OptionsBackup &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) +resources_allocate_for_backup(const OptionsBackup &opts, + resources_backup_t *const res) +{ + if ((res->in_file = fopen(opts.getInFilePath().c_str(), "r")) == NULL) { + print_error("cannot open input file: %s", strerror(errno)); + return 1; + } + + if ((res->ref_file = fopen(opts.getRefFilePath().c_str(), "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.getOutFilePath().c_str(), "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.getBufferSize() / opts.getSectorSize()) * sizeof(uint64_t)) + + opts.getBufferSize(); + + // TODO: separate function + if ((res->in_buffer = (char *)malloc(opts.getBufferSize())) == NULL) { + print_error("cannot allocate buffer for input file data"); + return 1; + } else if ((res->ref_buffer = (char *)malloc(opts.getBufferSize())) == + 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 int +check_files(const OptionsBackup &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); @@ -63,10 +118,10 @@ check_files(const options_backup_t *const opts, 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) { + } else if ((in_size % opts.getSectorSize()) != 0) { print_error( "size of input file and reference file is not multiple of %" PRIu32, - opts->sector_size); + opts.getSectorSize()); return 1; } @@ -87,9 +142,15 @@ write_out_buffer(const char *const buffer, size_t size, FILE *const file) } int -backup(const options_backup_t *const opts, const resources_backup_t *const res) +backup(const OptionsBackup &opts) { - if (check_files(opts, res) != 0) { + resources_backup_t res; + + if (resources_allocate_for_backup(opts, &res) != 0) { + return 1; + } + + if (check_files(opts, &res) != 0) { return 1; } @@ -99,11 +160,12 @@ backup(const options_backup_t *const opts, const resources_backup_t *const res) 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 in_sectors_read = + file_read_sectors(res.in_file, res.in_buffer, opts.getBufferSize(), + opts.getSectorSize()); const size_t ref_sectors_read = - file_read_sectors(res->ref_file, res->ref_buffer, opts->buffer_size, - opts->sector_size); + file_read_sectors(res.ref_file, res.ref_buffer, + opts.getBufferSize(), opts.getSectorSize()); if ((in_sectors_read == 0) || (ref_sectors_read == 0)) { break; @@ -115,39 +177,39 @@ backup(const options_backup_t *const opts, const resources_backup_t *const res) /* 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; + const size_t buffer_offset = sector * opts.getSectorSize(); - if (memcmp(res->in_buffer + buffer_offset, - res->ref_buffer + buffer_offset, - opts->sector_size) != 0) { + if (memcmp(res.in_buffer + buffer_offset, + res.ref_buffer + buffer_offset, + opts.getSectorSize()) != 0) { /* Backup the changed sector */ - if (out_buffer_index >= res->out_buffer_size) { + 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) { + 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, + 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; + memcpy(res.out_buffer + out_buffer_index, + res.in_buffer + buffer_offset, opts.getSectorSize()); + out_buffer_index += opts.getSectorSize(); } - input_file_offset += opts->sector_size; + input_file_offset += opts.getSectorSize(); } } /* Write out the output buffer */ if (out_buffer_index > 0) { - if (write_out_buffer(res->out_buffer, out_buffer_index, - res->out_file) != 0) { + if (write_out_buffer(res.out_buffer, out_buffer_index, res.out_file) != + 0) { return 1; } } diff --git a/src/backup.h b/src/backup.h index 9f14559..9629cb7 100644 --- a/src/backup.h +++ b/src/backup.h @@ -28,9 +28,7 @@ #define BACKUP_H #include "options.h" -#include "resources.h" -int backup(const options_backup_t *const opts, - const resources_backup_t *const res); +int backup(const OptionsBackup &opts); #endif /* BACKUP_H */ diff --git a/src/main.cpp b/src/main.cpp index 35e5c3d..15b9b1c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -26,38 +26,28 @@ #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); -} +#include 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))); + try { + if (OptionParser::isHelp(argc, argv)) { + OptionParser::printUsage(); + exit(0); + } else if (OptionParser::isBackup(argc, argv)) { + return backup(OptionParser::parseBackup(argc, argv)); + } else if (OptionParser::isRestore(argc, argv)) { + return restore(OptionParser::parseRestore(argc, argv)); + } else { + OptionParser::printUsage(); + exit(1); + } + } catch (const OptionError &e) { + OptionParser::printUsage(); + std::cerr << "ERROR: " << e.what() << std::endl; + exit(1); } } diff --git a/src/options.cpp b/src/options.cpp index ecb1026..545d11a 100644 --- a/src/options.cpp +++ b/src/options.cpp @@ -26,136 +26,160 @@ #include "options.h" -#include "print.h" +#include -#include -#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 { - 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); -static const char *next_arg(char ***const argv); +Options::Options() + : sector_size{Options::DEFAULT_SECTOR_SIZE}, + buffer_size{Options::DEFAULT_BUFFER_SIZE} +{ +} -bool -options_parse(int argc, char **argv, options_t *const opts) +uint32_t +Options::getSectorSize() const { - // Skip the executable name - --argc; - ++argv; + return sector_size; +} - options_parse_operation(argv[0], opts); +uint32_t +Options::getBufferSize() const +{ + return buffer_size; +} - if (options_is_operation(opts, OPERATION_ID_UNKNOWN)) { - return false; - } +std::filesystem::path +OptionsBackup::getInFilePath() const +{ + return in_file_path; +} - 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; +std::filesystem::path +OptionsBackup::getRefFilePath() const +{ + return ref_file_path; +} + +std::filesystem::path +OptionsBackup::getOutFilePath() const +{ + return out_file_path; +} + +std::filesystem::path +OptionsRestore::getInFilePath() const +{ + return in_file_path; +} + +std::filesystem::path +OptionsRestore::getOutFilePath() const +{ + return out_file_path; } void -options_usage(int exit_code) +OptionParser::printUsage() { - printf("Usage: %s backup [-s SECTOR_SIZE] [-b BUFFER_SIZE] INFILE REFFILE " - "OUTFILE\n", - PROGRAM_NAME_STR); - printf(" Or: %s restore [-s SECTOR_SIZE] [-b BUFFER_SIZE] REFFILE " - "OUTFILE\n", - PROGRAM_NAME_STR); - printf(" Or: %s help\n", PROGRAM_NAME_STR); - exit(exit_code); + std::cout << "Usage: " << PROGRAM_NAME_STR << " backup [-s SECTOR_SIZE]"; + std::cout << " [-b BUFFER_SIZE] INFILE REFFILE OUTFILE" << std::endl; + + std::cout << " Or: " << PROGRAM_NAME_STR << " restore [-s SECTOR_SIZE]"; + std::cout << "[-b BUFFER_SIZE] REFFILE OUTFILE" << std::endl; + + std::cout << " Or: " << PROGRAM_NAME_STR << " help" << std::endl; } bool -options_is_operation(const options_t *const opts, operation_id_t operation_id) +OptionParser::isHelp(int argc, char **argv) { - return (opts->operation_id == operation_id); + return isOperation(argc, argv, "help"); } -const options_backup_t * -options_get_for_backup(const options_t *const opts) +bool +OptionParser::isBackup(int argc, char **argv) { - return &(opts->op.backup); + return isOperation(argc, argv, "backup"); } -const options_restore_t * -options_get_for_restore(const options_t *const opts) +bool +OptionParser::isRestore(int argc, char **argv) { - return &(opts->op.restore); + return isOperation(argc, argv, "restore"); } -static int -options_parse_unsigned(const char *const arg, uint32_t *const value) +OptionsBackup +OptionParser::parseBackup(int argc, char **argv) { - char *end; + OptionsBackup opts; - errno = 0; + parse_common(&argc, &argv, opts); - *value = strtoul(arg, &end, 0); + if (argc < 3) { + throw OptionError("missing arguments"); + } else if (argc > 3) { + throw OptionError("too many arguments"); + } else { + opts.in_file_path = next_arg(&argv); + opts.ref_file_path = next_arg(&argv); + opts.out_file_path = next_arg(&argv); + } - return ((*end != '\0') || (errno != 0)) ? -1 : 0; + return opts; } -static void -options_parse_operation(const char *const op_name, options_t *const opts) +OptionsRestore +OptionParser::parseRestore(int argc, char **argv) { - 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; + OptionsRestore opts; + + parse_common(&argc, &argv, opts); + + if (argc < 2) { + throw OptionError("missing arguments"); + } else if (argc > 2) { + throw OptionError("too many arguments"); } else { - opts->operation_id = OPERATION_ID_UNKNOWN; + opts.in_file_path = next_arg(&argv); + opts.out_file_path = next_arg(&argv); } + + return opts; +} + +bool +OptionParser::isOperation(int argc, char **argv, std::string_view operationName) +{ + return ((argc >= 2) && + (strncmp(argv[1], operationName.data(), + OptionParser::MAX_OPERATION_NAME_LENGTH) == 0)); } -static void -options_init_common(struct common_options *const opts) +int +OptionParser::parse_unsigned(const char *const arg, uint32_t *const value) { - opts->sector_size = OPTIONS_DEFAULT_SECTOR_SIZE; - opts->buffer_size = OPTIONS_DEFAULT_BUFFER_SIZE; + char *end; + + errno = 0; + + *value = strtoul(arg, &end, 0); + + return ((*end != '\0') || (errno != 0)) ? -1 : 0; } -static bool -options_parse_common(int *const argc, char ***const argv, - struct common_options *const opts) +void +OptionParser::parse_common(int *const argc, char ***const argv, Options &opts) { + // Skip the executable name. Do not skip the operation name. getopt expects + // to start at an argument immediately preceding the possible options. + *argc -= 1; + *argv += 1; + int ch; char *arg_sector_size = NULL; char *arg_buffer_size = NULL; @@ -171,11 +195,11 @@ options_parse_common(int *const argc, char ***const argv, break; case ':': - print_error("missing argument for option '-%c'", optopt); - return false; + throw OptionError("missing argument for option '-" + + std::string(1, optopt) + "'"); default: - print_error("unknown option '-%c'", optopt); - return false; + throw OptionError("unknown option '-" + std::string(1, optopt) + + "'"); } } @@ -184,84 +208,24 @@ options_parse_common(int *const argc, char ***const argv, /* 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; + parse_unsigned(arg_sector_size, &(opts.sector_size))) { + throw OptionError("incorrect sector size"); } 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 (*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 = next_arg(argv); - opts->op.backup.ref_file_path = next_arg(argv); - opts->op.backup.out_file_path = next_arg(argv); - } - - 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; + parse_unsigned(arg_buffer_size, &(opts.buffer_size))) { + throw OptionError("incorrect buffer size"); + } else if (opts.sector_size == 0) { + throw OptionError("sector size cannot be 0"); + } else if (opts.buffer_size == 0) { + throw OptionError("buffer size cannot be 0"); + } else if (opts.sector_size > opts.buffer_size) { + throw OptionError("sector size cannot larger than buffer size"); + } else if ((opts.buffer_size % opts.sector_size) != 0) { + throw OptionError("buffer size is not multiple of sector size"); } - - 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 = next_arg(argv); - opts->op.restore.out_file_path = next_arg(argv); - } - - return true; } -static const char * -next_arg(char ***const argv) +const char * +OptionParser::next_arg(char ***const argv) { const char *arg = **argv; ++(*argv); diff --git a/src/options.h b/src/options.h index e162fbe..e0c16d1 100644 --- a/src/options.h +++ b/src/options.h @@ -27,40 +27,89 @@ #ifndef OPTIONS_H #define OPTIONS_H -#include "operation_id.h" +#include +#include -#include -#include +class OptionError : public std::runtime_error +{ + public: + explicit OptionError(const std::string &message) + : std::runtime_error(message) + { + } +}; -typedef struct { - uint32_t sector_size; - uint32_t buffer_size; - const char *in_file_path; - const char *ref_file_path; - const char *out_file_path; -} options_backup_t; +class Options +{ + friend class OptionParser; + + public: + static const int DEFAULT_SECTOR_SIZE{512}; + static const int DEFAULT_BUFFER_SIZE{4 * 1024 * 1024}; + + Options(); + virtual ~Options() = default; -typedef struct { + uint32_t getSectorSize() const; + uint32_t getBufferSize() const; + + private: uint32_t sector_size; uint32_t buffer_size; - const char *in_file_path; - const char *out_file_path; -} options_restore_t; - -typedef struct { - operation_id_t operation_id; - - union { - options_backup_t backup; - options_restore_t restore; - } op; -} options_t; - -bool options_parse(int argc, char **argv, options_t *const opts); -void options_usage(int exit_code); -bool options_is_operation(const options_t *const opts, - operation_id_t operation_id); -const options_backup_t *options_get_for_backup(const options_t *const opts); -const options_restore_t *options_get_for_restore(const options_t *const opts); +}; + +class OptionsBackup : public Options +{ + friend class OptionParser; + + public: + virtual ~OptionsBackup() = default; + + std::filesystem::path getInFilePath() const; + std::filesystem::path getRefFilePath() const; + std::filesystem::path getOutFilePath() const; + + private: + std::filesystem::path in_file_path; + std::filesystem::path ref_file_path; + std::filesystem::path out_file_path; +}; + +class OptionsRestore : public Options +{ + friend class OptionParser; + + public: + virtual ~OptionsRestore() = default; + + std::filesystem::path getInFilePath() const; + std::filesystem::path getOutFilePath() const; + + private: + std::filesystem::path in_file_path; + std::filesystem::path out_file_path; +}; + +class OptionParser +{ + public: + static void printUsage(); + static bool isHelp(int argc, char **argv); + static bool isBackup(int argc, char **argv); + static bool isRestore(int argc, char **argv); + ; + static OptionsBackup parseBackup(int argc, char **argv); + static OptionsRestore parseRestore(int argc, char **argv); + + private: + static const size_t MAX_OPERATION_NAME_LENGTH{8}; + + static bool isOperation(int argc, char **argv, + std::string_view operationName); + static int parse_unsigned(const char *const arg, uint32_t *const value); + static void parse_common(int *const argc, char ***const argv, + Options &opts); + static const char *next_arg(char ***const argv); +}; #endif /* OPTIONS_H */ diff --git a/src/resources.cpp b/src/resources.cpp deleted file mode 100644 index 0829c7c..0000000 --- a/src/resources.cpp +++ /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.h b/src/resources.h deleted file mode 100644 index 3cc0dff..0000000 --- a/src/resources.h +++ /dev/null @@ -1,74 +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. - */ - -#ifndef RESOURCES_H -#define RESOURCES_H - -#include "operation_id.h" -#include "options.h" - -#include - -typedef struct { - FILE *in_file; - FILE *ref_file; - FILE *out_file; - - char *in_buffer; - char *ref_buffer; - char *out_buffer; - - size_t out_buffer_size; -} resources_backup_t; - -typedef struct { - FILE *in_file; - FILE *out_file; - - char *in_buffer; - char *out_buffer; - - size_t in_sector_size; - size_t in_buffer_size; -} resources_restore_t; - -typedef struct { - operation_id_t operation_id; - - union { - resources_backup_t backup; - resources_restore_t restore; - } res; -} resources_t; - -int resources_allocate(const options_t *const opts, resources_t *const res); -const resources_backup_t * -resources_get_for_backup(const resources_t *const res); -const resources_restore_t * -resources_get_for_restore(const resources_t *const res); -void resources_free(resources_t *const res); - -#endif /* RESOURCES_H */ diff --git a/src/restore.cpp b/src/restore.cpp index e73e42e..02532aa 100644 --- a/src/restore.cpp +++ b/src/restore.cpp @@ -36,6 +36,49 @@ #include #include +typedef struct { + FILE *in_file; + FILE *out_file; + + char *in_buffer; + char *out_buffer; + + size_t in_sector_size; + size_t in_buffer_size; +} resources_restore_t; + +static int +resources_allocate_for_restore(const OptionsRestore &opts, + resources_restore_t *const res) +{ + if ((res->in_file = fopen(opts.getInFilePath().c_str(), "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.getOutFilePath().c_str(), "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.getSectorSize(); + const size_t in_buffer_sector_count = + opts.getBufferSize() / 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 bool is_input_file_valid(const resources_restore_t *const res, uint32_t sector_size) { @@ -116,16 +159,21 @@ is_input_file_valid(const resources_restore_t *const res, uint32_t sector_size) } int -restore(const options_restore_t *const opts, - const resources_restore_t *const res) +restore(const OptionsRestore &opts) { + resources_restore_t res; + + if (resources_allocate_for_restore(opts, &res) != 0) { + return 1; + } + /* Check validity of the input file */ - if (!is_input_file_valid(res, opts->sector_size)) { + if (!is_input_file_valid(&res, opts.getSectorSize())) { return 1; } bool in_size_ok = false; - const size_t in_size = file_size(res->in_file, &in_size_ok); + 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)); @@ -136,28 +184,27 @@ restore(const options_restore_t *const opts, 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); + 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; + 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) { + 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; + fwrite(in_buffer, opts.getSectorSize(), 1U, res.out_file); + in_buffer += opts.getSectorSize(); if (out_written != 1U) { print_error("cannot write to output file: %s", strerror(errno)); @@ -168,7 +215,7 @@ restore(const options_restore_t *const opts, /* The input file must be read completely */ bool pos_ok = false; - const size_t pos = file_tell(res->in_file, &pos_ok); + const size_t pos = file_tell(res.in_file, &pos_ok); if (!pos_ok) { print_error("cannot get position in the input file"); diff --git a/src/restore.h b/src/restore.h index a6c09d1..457ef48 100644 --- a/src/restore.h +++ b/src/restore.h @@ -28,9 +28,7 @@ #define RESTORE_H #include "options.h" -#include "resources.h" -int restore(const options_restore_t *const opts, - const resources_restore_t *const res); +int restore(const OptionsRestore &opts); #endif /* RESTORE_H */ -- cgit v1.2.3