diff options
| author | Jan Sucan <jan@jansucan.com> | 2022-06-18 08:50:45 +0200 |
|---|---|---|
| committer | Jan Sucan <jan@jansucan.com> | 2022-06-18 08:50:54 +0200 |
| commit | 948a65cf39c8ce31c5adc0f24979e0cb55bc33c3 (patch) | |
| tree | ae923f4594fef0abb777f63291d62530c345b229 /src | |
| parent | e1d10bea5d9fc94ba800ade1de430c7f3c0ccacd (diff) | |
Refactor the command line interface
Select operation by its name instead of by number of the arguments.
Diffstat (limited to 'src')
| -rw-r--r-- | src/Makefile | 2 | ||||
| -rw-r--r-- | src/backup.c | 41 | ||||
| -rw-r--r-- | src/backup.h | 3 | ||||
| -rw-r--r-- | src/main.c | 65 | ||||
| -rw-r--r-- | src/operation_id.h | 37 | ||||
| -rw-r--r-- | src/options.c | 222 | ||||
| -rw-r--r-- | src/options.h | 26 | ||||
| -rw-r--r-- | src/resources.c | 187 | ||||
| -rw-r--r-- | src/resources.h | 31 | ||||
| -rw-r--r-- | src/restore.c | 94 | ||||
| -rw-r--r-- | src/restore.h | 3 |
11 files changed, 481 insertions, 230 deletions
diff --git a/src/Makefile b/src/Makefile index 8b24b35..4deaaec 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,5 +1,5 @@ CC=gcc -CFLAGS=-Wall +CFLAGS=-Wall -fmax-errors=2 SOURCES=*.c HEADERS=*.h diff --git a/src/backup.c b/src/backup.c index 4691bac..4c9dfbd 100644 --- a/src/backup.c +++ b/src/backup.c @@ -34,15 +34,14 @@ #include <stdlib.h> #include <string.h> -static int check_files(const options_t *const opts, - const resources_t *const res); -static int allocate_buffers(const options_t *const opts, size_t out_buffer_size, - resources_t *const res); +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_t *const opts, const resources_t *const res) +check_files(const options_backup_t *const opts, + const resources_backup_t *const res) { const long in_size = file_size(res->in_file); @@ -73,25 +72,6 @@ check_files(const options_t *const opts, const resources_t *const res) } static int -allocate_buffers(const options_t *const opts, size_t out_buffer_size, - resources_t *const res) -{ - - 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(out_buffer_size)) == NULL) { - print_error("cannot allocate buffer for output file data"); - 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); @@ -105,21 +85,12 @@ write_out_buffer(const char *const buffer, size_t size, FILE *const file) } int -backup(const options_t *const opts, resources_t *const res) +backup(const options_backup_t *const opts, const resources_backup_t *const res) { if (check_files(opts, res) != 0) { return 1; } - /* The output buffer contains also the offsets */ - const size_t out_buffer_size = - ((opts->buffer_size / opts->sector_size) * sizeof(uint64_t)) + - opts->buffer_size; - - if (allocate_buffers(opts, out_buffer_size, res) != 0) { - return 1; - } - size_t out_buffer_index = 0; uint64_t input_file_offset = 0; @@ -148,7 +119,7 @@ backup(const options_t *const opts, resources_t *const res) res->ref_buffer + buffer_offset, opts->sector_size) != 0) { /* Backup the changed sector */ - if (out_buffer_index >= 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) { diff --git a/src/backup.h b/src/backup.h index 057aa15..9f14559 100644 --- a/src/backup.h +++ b/src/backup.h @@ -30,6 +30,7 @@ #include "options.h" #include "resources.h" -int backup(const options_t *const opts, resources_t *const res); +int backup(const options_backup_t *const opts, + const resources_backup_t *const res); #endif /* BACKUP_H */ @@ -25,19 +25,11 @@ */ #include "backup.h" -#include "file.h" #include "options.h" -#include "print.h" #include "resources.h" #include "restore.h" -#include <endian.h> -#include <errno.h> -#include <inttypes.h> -#include <stdint.h> -#include <stdio.h> #include <stdlib.h> -#include <string.h> static void clean_exit(resources_t *const res, int exit_code) @@ -46,67 +38,26 @@ clean_exit(resources_t *const res, int exit_code) exit(exit_code); } -static int -open_files(const options_t *const opts, resources_t *const res, - bool is_action_backup) -{ - /* Open the input file */ - if ((opts->in_file_path != NULL) && - ((res->in_file = fopen(opts->in_file_path, "r")) == NULL)) { - print_error("cannot open input file: %s", strerror(errno)); - return 1; - } - - /* Open the reference file */ - if ((res->ref_file = fopen(opts->ref_file_path, "r")) == NULL) { - print_error("cannot open reference file: %s", strerror(errno)); - return 1; - } - - /* Open the output file - * - * When restoring, the file must be opened for writing and not - * truncated - */ - char out_mode[] = "r+"; - - if (is_action_backup) { - /* When backing up, the output file is truncated to hold the - * new data - */ - out_mode[0] = 'w'; - out_mode[1] = '\0'; - } - - if ((res->out_file = fopen(opts->out_file_path, out_mode)) == NULL) { - print_error("cannot open output file: %s", strerror(errno)); - return 1; - } - - return 0; -} - int main(int argc, char **argv) { options_t opts; - if (options_parse(argc, argv, &opts)) { + if (!options_parse(argc, argv, &opts)) { options_usage(1); - } else if (opts.help) { + } else if (options_is_operation(&opts, OPERATION_ID_HELP)) { options_usage(0); } - const bool is_action_backup = (opts.in_file_path != NULL); resources_t res; - resources_init(&res); - - if (open_files(&opts, &res, is_action_backup) != 0) { + if (resources_allocate(&opts, &res)) { clean_exit(&res, 1); - } else if (is_action_backup) { - clean_exit(&res, backup(&opts, &res)); + } 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(&opts, &res)); + clean_exit(&res, restore(options_get_for_restore(&opts), + resources_get_for_restore(&res))); } } diff --git a/src/operation_id.h b/src/operation_id.h new file mode 100644 index 0000000..99536af --- /dev/null +++ b/src/operation_id.h @@ -0,0 +1,37 @@ +/* Copyright 2019 Ján Sučan <jan@jansucan.com> + * + * 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 OPERATION_ID_H +#define OPERATION_ID_H + +typedef enum { + OPERATION_ID_UNKNOWN, + OPERATION_ID_HELP, + OPERATION_ID_BACKUP, + OPERATION_ID_RESTORE, +} operation_id_t; + +#endif /* OPERATION_ID_H */ diff --git a/src/options.c b/src/options.c index 002b36c..e2fcfdb 100644 --- a/src/options.c +++ b/src/options.c @@ -38,22 +38,126 @@ */ #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) -static void options_init(options_t *const opts); +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); -int +bool options_parse(int argc, char **argv, options_t *const opts) { - options_init(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) { + while ((ch = getopt(*argc, *argv, ":b:hs:")) != -1) { switch (ch) { case 'b': arg_buffer_size = optarg; @@ -69,90 +173,94 @@ options_parse(int argc, char **argv, options_t *const opts) case ':': print_error("missing argument for option '-%c'", optopt); - return 1; - + return false; default: print_error("unknown option '-%c'", optopt); - return 1; + return false; } } - argc -= optind; - argv += optind; - - if (opts->help) { - return 0; - } else if (argc < 2) { - print_error("missing arguments"); - return 1; - } else if (argc > 3) { - print_error("too many arguments"); - return 1; - } + *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 1; + return false; } else if ((arg_buffer_size != NULL) && options_parse_unsigned(arg_buffer_size, &(opts->buffer_size))) { print_error("incorrect buffer size"); - return 1; + return false; } else if (opts->sector_size == 0) { print_error("sector size cannot be 0"); - return 1; + return false; } else if (opts->buffer_size == 0) { print_error("buffer size cannot be 0"); - return 1; + return false; } else if (opts->sector_size > opts->buffer_size) { print_error("sector size cannot larger than buffer size"); - return 1; + return false; } else if ((opts->buffer_size % opts->sector_size) != 0) { print_error("buffer size is not multiple of sector size"); - return 1; + return false; } - /* Pick the file paths */ - int last_path_index = argc - 1; - opts->out_file_path = argv[last_path_index--]; - opts->ref_file_path = argv[last_path_index--]; - if (last_path_index >= 0) { - opts->in_file_path = argv[last_path_index]; - } - - return 0; + return true; } -void -options_usage(int exit_code) +static bool +options_parse_backup(int *const argc, char ***const argv, options_t *const opts) { - printf("Usage: %s [-s SECTOR_SIZE] [-b BUFFER_SIZE] [INFILE] REFFILE " - "OUTFILE\n", - PROGRAM_NAME_STR); - exit(exit_code); -} + struct common_options common_opts; + options_init_common(&common_opts); + if (!options_parse_common(argc, argv, &common_opts)) { + return false; + } -static void -options_init(options_t *const opts) -{ - opts->help = false; - opts->sector_size = OPTIONS_DEFAULT_SECTOR_SIZE; - opts->buffer_size = OPTIONS_DEFAULT_BUFFER_SIZE; + 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]; + } - opts->in_file_path = NULL; - opts->ref_file_path = NULL; - opts->out_file_path = NULL; + return true; } -static int -options_parse_unsigned(const char *const arg, uint32_t *const value) +static bool +options_parse_restore(int *const argc, char ***const argv, + options_t *const opts) { - char *end; - - errno = 0; + struct common_options common_opts; + options_init_common(&common_opts); + if (!options_parse_common(argc, argv, &common_opts)) { + return false; + } - *value = strtoul(arg, &end, 0); + 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 ((*end != '\0') || (errno != 0)) ? -1 : 0; + return true; } diff --git a/src/options.h b/src/options.h index 9ffa14f..e162fbe 100644 --- a/src/options.h +++ b/src/options.h @@ -27,20 +27,40 @@ #ifndef OPTIONS_H #define OPTIONS_H +#include "operation_id.h" + #include <stdbool.h> #include <stdint.h> typedef struct { - bool help; 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; + +typedef struct { + 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; -int options_parse(int argc, char **argv, options_t *const opts); +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); #endif /* OPTIONS_H */ diff --git a/src/resources.c b/src/resources.c index 65b7f71..0829c7c 100644 --- a/src/resources.c +++ b/src/resources.c @@ -26,45 +26,188 @@ #include "resources.h" +#include "print.h" + +#include <errno.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> -void -resources_init(resources_t *const res) +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; } -void -resources_free(resources_t *const res) +static int +resources_allocate_for_backup(const options_backup_t *const opts, + resources_backup_t *const res) { - if (res->in_file != NULL) { - fclose(res->in_file); - res->in_file = NULL; + 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 != NULL) { - fclose(res->ref_file); - res->ref_file = NULL; + + if ((res->ref_file = fopen(opts->ref_file_path, "r")) == NULL) { + print_error("cannot open reference file: %s", strerror(errno)); + return 1; } - if (res->out_file != NULL) { - fclose(res->out_file); - res->out_file = NULL; + + /* 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; } - if (res->in_buffer != NULL) { - free(res->in_buffer); - res->in_buffer = NULL; + + /* 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; } - if (res->ref_buffer != NULL) { - free(res->ref_buffer); - res->ref_buffer = NULL; + + 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; } - if (res->out_buffer != NULL) { - free(res->out_buffer); - res->out_buffer = NULL; + + /* 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 index 3c6e768..3cc0dff 100644 --- a/src/resources.h +++ b/src/resources.h @@ -27,6 +27,9 @@ #ifndef RESOURCES_H #define RESOURCES_H +#include "operation_id.h" +#include "options.h" + #include <stdio.h> typedef struct { @@ -37,9 +40,35 @@ typedef struct { 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; -void resources_init(resources_t *const res); +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.c b/src/restore.c index 6318766..df58ab8 100644 --- a/src/restore.c +++ b/src/restore.c @@ -37,22 +37,21 @@ #include <string.h> static bool -is_reference_file_valid(resources_t *const res, uint32_t sector_size) +is_input_file_valid(const resources_restore_t *const res, uint32_t sector_size) { - const long ref_size = file_size(res->ref_file); + const long in_size = file_size(res->in_file); - if (ref_size < 0) { - print_error("cannot get size of reference file: %s", strerror(errno)); + if (in_size < 0) { + print_error("cannot get size of input file: %s", strerror(errno)); return false; - } else if (ref_size == 0) { - print_error("reference file is empty"); + } else if (in_size == 0) { + print_error("input file is empty"); return false; - } else if ((ref_size % (sizeof(uint64_t) + sector_size)) != 0) { - /* The reference file must hold equally sized sectors and the + } 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( - "reference file has size that cannot contain valid diff data"); + print_error("input file has size that cannot contain valid diff data"); return false; } @@ -66,18 +65,18 @@ is_reference_file_valid(resources_t *const res, uint32_t sector_size) uint64_t prev_out_offset = 0; bool is_first_reading = true; - /* Scan the reference file and check */ + /* Scan the input file and check */ for (;;) { uint64_t out_offset; /* Read the next offset */ - const size_t ref_read = - fread(&out_offset, sizeof(out_offset), 1U, res->ref_file); + const size_t in_read = + fread(&out_offset, sizeof(out_offset), 1U, res->in_file); out_offset = le64toh(out_offset); - if (feof(res->ref_file)) { + if (feof(res->in_file)) { break; - } else if ((ref_read != 1U) || ferror(res->ref_file)) { - print_error("cannot read from reference file: %s", strerror(errno)); + } 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"); @@ -86,8 +85,8 @@ is_reference_file_valid(resources_t *const res, uint32_t sector_size) print_error( "a sector offset points past the end of the output file"); return false; - } else if (fseek(res->ref_file, sector_size, SEEK_CUR) != 0) { - print_error("cannot seek in reference file: %s", strerror(errno)); + } else if (fseek(res->in_file, sector_size, SEEK_CUR) != 0) { + print_error("cannot seek in input file: %s", strerror(errno)); return false; } @@ -95,13 +94,13 @@ is_reference_file_valid(resources_t *const res, uint32_t sector_size) prev_out_offset = out_offset; } - if (ftell(res->ref_file) != ref_size) { - /* The reference file must be read completely */ - print_error("reference file is not valid"); + if (ftell(res->in_file) != in_size) { + /* The input file must be read completely */ + print_error("input file is not valid"); return false; - } else if (fseek(res->ref_file, 0L, SEEK_SET) != 0) { + } else if (fseek(res->in_file, 0L, SEEK_SET) != 0) { /* The file must be prepared for the restoring */ - print_error("cannot seek in reference file: %s", strerror(errno)); + print_error("cannot seek in input file: %s", strerror(errno)); return false; } @@ -109,28 +108,18 @@ is_reference_file_valid(resources_t *const res, uint32_t sector_size) } int -restore(const options_t *const opts, resources_t *const res) +restore(const options_restore_t *const opts, + const resources_restore_t *const res) { - /* Check validity of the reference file */ - if (!is_reference_file_valid(res, opts->sector_size)) { + /* Check validity of the input file */ + if (!is_input_file_valid(res, opts->sector_size)) { return 1; } - const long ref_size = file_size(res->ref_file); + const long in_size = file_size(res->in_file); - if (ref_size < 0) { - print_error("cannot get size of reference file: %s", strerror(errno)); - return 1; - } - - /* Allocate the buffer for data from the reference file */ - /* The reference buffer contains also the offsets */ - const size_t ref_sector_size = sizeof(uint64_t) + opts->sector_size; - const size_t ref_buffer_sector_count = opts->buffer_size / ref_sector_size; - const size_t ref_buffer_size = ref_buffer_sector_count * ref_sector_size; - - if ((res->ref_buffer = (char *)malloc(ref_buffer_size)) == NULL) { - print_error("cannot allocate buffer for reference file data"); + if (in_size < 0) { + print_error("cannot get size of input file: %s", strerror(errno)); return 1; } @@ -138,18 +127,19 @@ restore(const options_t *const opts, resources_t *const res) for (;;) { /* Read data of the offset and the next sector */ - const size_t ref_sectors_read = file_read_sectors( - res->ref_file, res->ref_buffer, ref_buffer_size, ref_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 (ref_sectors_read == 0) { + if (in_sectors_read == 0) { break; } - char *ref_buffer = res->ref_buffer; + char *in_buffer = res->in_buffer; - for (size_t s = 0; s < ref_sectors_read; ++s) { - const uint64_t out_offset = le64toh(*((uint64_t *)ref_buffer)); - ref_buffer += sizeof(uint64_t); + 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)); @@ -157,8 +147,8 @@ restore(const options_t *const opts, resources_t *const res) } const size_t out_written = - fwrite(ref_buffer, opts->sector_size, 1U, res->out_file); - ref_buffer += opts->sector_size; + 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)); @@ -167,9 +157,9 @@ restore(const options_t *const opts, resources_t *const res) } } - /* The reference file must be read completely */ - if (ftell(res->ref_file) != ref_size) { - print_error("reference file is not valid"); + /* The input file must be read completely */ + if (ftell(res->in_file) != in_size) { + print_error("input file is not valid"); return 1; } diff --git a/src/restore.h b/src/restore.h index 02d70ff..a6c09d1 100644 --- a/src/restore.h +++ b/src/restore.h @@ -30,6 +30,7 @@ #include "options.h" #include "resources.h" -int restore(const options_t *const opts, resources_t *const res); +int restore(const options_restore_t *const opts, + const resources_restore_t *const res); #endif /* RESTORE_H */ |
