aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backup.cpp200
-rw-r--r--src/backup.h11
-rw-r--r--src/file.cpp84
-rw-r--r--src/file.h39
-rw-r--r--src/main.cpp12
-rw-r--r--src/print.cpp47
-rw-r--r--src/print.h32
-rw-r--r--src/restore.cpp224
-rw-r--r--src/restore.h11
9 files changed, 239 insertions, 421 deletions
diff --git a/src/backup.cpp b/src/backup.cpp
index b0b0054..4ffbd87 100644
--- a/src/backup.cpp
+++ b/src/backup.cpp
@@ -26,133 +26,142 @@
#include "backup.h"
-#include "file.h"
-#include "print.h"
-
-#include <errno.h>
+#include <fstream>
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
- FILE *in_file;
- FILE *ref_file;
- FILE *out_file;
+ std::ifstream in_file;
+ std::ifstream ref_file;
+ std::ofstream out_file;
- char *in_buffer;
- char *ref_buffer;
- char *out_buffer;
+ std::unique_ptr<char[]> in_buffer;
+ std::unique_ptr<char[]> ref_buffer;
+ std::unique_ptr<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 void check_files(const OptionsBackup &opts);
+static void write_out_buffer(const char *const buffer, size_t size,
+ std::ofstream &file);
-static int
-resources_allocate_for_backup(const OptionsBackup &opts,
- resources_backup_t *const res)
+static resources_backup_t
+resources_allocate_for_backup(const OptionsBackup &opts)
{
- if ((res->in_file = fopen(opts.getInFilePath().c_str(), "r")) == NULL) {
- print_error("cannot open input file: %s", strerror(errno));
- return 1;
+ resources_backup_t res;
+
+ res.in_file.open(opts.getInFilePath(),
+ std::ifstream::in | std::ifstream::binary);
+ if (!res.in_file) {
+ throw BackupError("cannot open input file");
}
- if ((res->ref_file = fopen(opts.getRefFilePath().c_str(), "r")) == NULL) {
- print_error("cannot open reference file: %s", strerror(errno));
- return 1;
+ res.ref_file.open(opts.getRefFilePath(),
+ std::ifstream::in | std::ifstream::binary);
+ if (!res.ref_file) {
+ throw BackupError("cannot open reference file");
}
/* 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;
+ res.out_file.open(opts.getOutFilePath(), std::ifstream::out |
+ std::ifstream::trunc |
+ std::ifstream::binary);
+ if (!res.out_file) {
+ throw BackupError("cannot open output file");
}
/* The output buffer contains also the offsets */
- res->out_buffer_size =
+ 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;
+ try {
+ res.in_buffer = std::make_unique<char[]>(opts.getBufferSize());
+ } catch (const std::bad_alloc &e) {
+ throw BackupError("cannot allocate buffer for input file data");
+ }
+
+ try {
+ res.ref_buffer = std::make_unique<char[]>(opts.getBufferSize());
+ } catch (const std::bad_alloc &e) {
+ throw BackupError("cannot allocate buffer for reference file data");
}
- return 0;
+ try {
+ res.out_buffer = std::make_unique<char[]>(res.out_buffer_size);
+ } catch (const std::bad_alloc &e) {
+ throw BackupError("cannot allocate buffer for output file data");
+ }
+
+ return res;
}
-static int
-check_files(const OptionsBackup &opts, const resources_backup_t *const res)
+static void
+check_files(const OptionsBackup &opts)
{
- 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;
+ size_t in_size{0};
+ try {
+ in_size = std::filesystem::file_size(opts.getInFilePath());
+ } catch (const std::exception &e) {
+ throw BackupError("cannot get size of input file: " +
+ std::string(e.what()));
}
- 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;
+ size_t ref_size{0};
+ try {
+ ref_size = std::filesystem::file_size(opts.getRefFilePath());
+ } catch (const std::exception &e) {
+ throw BackupError("cannot get size of reference file: " +
+ std::string(e.what()));
}
/* 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;
+ throw BackupError("input file and reference file differ in size");
} else if ((in_size % opts.getSectorSize()) != 0) {
- print_error(
- "size of input file and reference file is not multiple of %" PRIu32,
- opts.getSectorSize());
- return 1;
+ throw BackupError(
+ "size of input file and reference file is not multiple of " +
+ std::to_string(opts.getSectorSize()));
}
-
- return 0;
}
-static int
-write_out_buffer(const char *const buffer, size_t size, FILE *const file)
+static void
+write_out_buffer(const char *const buffer, size_t size, std::ofstream &file)
{
- const size_t bytes_written = fwrite(buffer, 1U, size, file);
+ file.write(buffer, size);
- if (bytes_written != size) {
- print_error("cannot write to output file: %s", strerror(errno));
- return 1;
+ if (!file) {
+ throw BackupError("cannot write to output file");
}
-
- return 0;
}
-int
-backup(const OptionsBackup &opts)
+static size_t
+read_sectors(std::ifstream &file, char *const buffer, uint32_t buffer_size,
+ uint32_t sector_size)
{
- resources_backup_t res;
-
- if (resources_allocate_for_backup(opts, &res) != 0) {
- return 1;
+ file.readsome(buffer, buffer_size);
+ const size_t bytes_read = file.gcount();
+
+ if (!file.good() && !file.eof()) {
+ throw BackupError("cannot read from file");
+ } else if ((bytes_read % sector_size) != 0) {
+ throw BackupError(
+ "data read from input file is not multiple of sector size");
+ } else {
+ return (bytes_read / sector_size);
}
+}
- if (check_files(opts, &res) != 0) {
- return 1;
- }
+void
+backup(const OptionsBackup &opts)
+{
+ resources_backup_t res{resources_allocate_for_backup(opts)};
+ check_files(opts);
size_t out_buffer_index = 0;
uint64_t input_file_offset = 0;
@@ -161,44 +170,42 @@ backup(const OptionsBackup &opts)
/* 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.getBufferSize(),
- opts.getSectorSize());
+ read_sectors(res.in_file, res.in_buffer.get(), opts.getBufferSize(),
+ opts.getSectorSize());
const size_t ref_sectors_read =
- file_read_sectors(res.ref_file, res.ref_buffer,
- opts.getBufferSize(), opts.getSectorSize());
+ read_sectors(res.ref_file, res.ref_buffer.get(),
+ opts.getBufferSize(), opts.getSectorSize());
if ((in_sectors_read == 0) || (ref_sectors_read == 0)) {
break;
} else if (in_sectors_read != ref_sectors_read) {
- print_error(
+ throw BackupError(
"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.getSectorSize();
- if (memcmp(res.in_buffer + buffer_offset,
- res.ref_buffer + buffer_offset,
+ if (memcmp(res.in_buffer.get() + buffer_offset,
+ res.ref_buffer.get() + buffer_offset,
opts.getSectorSize()) != 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;
- }
+ write_out_buffer(res.out_buffer.get(), out_buffer_index,
+ res.out_file);
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.get() + 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.getSectorSize());
+ memcpy(res.out_buffer.get() + out_buffer_index,
+ res.in_buffer.get() + buffer_offset,
+ opts.getSectorSize());
out_buffer_index += opts.getSectorSize();
}
@@ -208,11 +215,6 @@ backup(const OptionsBackup &opts)
/* 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;
- }
+ write_out_buffer(res.out_buffer.get(), out_buffer_index, res.out_file);
}
-
- return 0;
}
diff --git a/src/backup.h b/src/backup.h
index 9629cb7..289ee62 100644
--- a/src/backup.h
+++ b/src/backup.h
@@ -29,6 +29,15 @@
#include "options.h"
-int backup(const OptionsBackup &opts);
+class BackupError : public std::runtime_error
+{
+ public:
+ explicit BackupError(const std::string &message)
+ : std::runtime_error(message)
+ {
+ }
+};
+
+void backup(const OptionsBackup &opts);
#endif /* BACKUP_H */
diff --git a/src/file.cpp b/src/file.cpp
deleted file mode 100644
index d605ceb..0000000
--- a/src/file.cpp
+++ /dev/null
@@ -1,84 +0,0 @@
-/* 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.
- */
-
-#include "file.h"
-
-#include "print.h"
-
-#include <errno.h>
-#include <string.h>
-
-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.h b/src/file.h
deleted file mode 100644
index 3e4a6ee..0000000
--- a/src/file.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/* 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 FILE_H
-#define FILE_H
-
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdio.h>
-
-size_t file_size(FILE *const file, bool *const return_is_ok);
-size_t file_tell(FILE *const file, bool *const return_is_ok);
-size_t file_read_sectors(FILE *const file, char *const buffer,
- uint32_t buffer_size, uint32_t sector_size);
-
-#endif /* FILE_H */
diff --git a/src/main.cpp b/src/main.cpp
index 6b00324..01f3a69 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -37,9 +37,9 @@ main(int argc, char **argv)
if (OptionParser::isHelp(argc, argv)) {
OptionParser::printUsage();
} else if (OptionParser::isBackup(argc, argv)) {
- return backup(OptionParser::parseBackup(argc, argv));
+ backup(OptionParser::parseBackup(argc, argv));
} else if (OptionParser::isRestore(argc, argv)) {
- return restore(OptionParser::parseRestore(argc, argv));
+ restore(OptionParser::parseRestore(argc, argv));
} else {
OptionParser::printUsage();
exit(1);
@@ -48,5 +48,13 @@ main(int argc, char **argv)
OptionParser::printUsage();
std::cerr << "ERROR: " << e.what() << std::endl;
exit(1);
+ } catch (const BackupError &e) {
+ std::cerr << "ERROR: " << e.what() << std::endl;
+ exit(1);
+ } catch (const RestoreError &e) {
+ std::cerr << "ERROR: " << e.what() << std::endl;
+ exit(1);
}
+
+ exit(0);
}
diff --git a/src/print.cpp b/src/print.cpp
deleted file mode 100644
index 1dcb75a..0000000
--- a/src/print.cpp
+++ /dev/null
@@ -1,47 +0,0 @@
-/* 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.
- */
-
-#include "print.h"
-
-#include <stdarg.h>
-#include <stdio.h>
-
-#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.h b/src/print.h
deleted file mode 100644
index 8e0cfb5..0000000
--- a/src/print.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/* 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 PRINT_H
-#define PRINT_H
-
-void print_error(const char *const format, ...);
-
-#endif /* PRINT_H */
diff --git a/src/restore.cpp b/src/restore.cpp
index 02532aa..9091db0 100644
--- a/src/restore.cpp
+++ b/src/restore.cpp
@@ -26,9 +26,6 @@
#include "restore.h"
-#include "file.h"
-#include "print.h"
-
#include <errno.h>
#include <stdbool.h>
#include <stdint.h>
@@ -36,75 +33,83 @@
#include <stdlib.h>
#include <string.h>
+#include <filesystem>
+#include <fstream>
+#include <iostream>
+
typedef struct {
- FILE *in_file;
- FILE *out_file;
+ std::ifstream in_file;
+ std::fstream out_file;
- char *in_buffer;
- char *out_buffer;
+ std::unique_ptr<char[]> in_buffer;
+ std::unique_ptr<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)
+static resources_restore_t
+resources_allocate_for_restore(const OptionsRestore &opts)
{
- if ((res->in_file = fopen(opts.getInFilePath().c_str(), "r")) == NULL) {
- print_error("cannot open input file: %s", strerror(errno));
- return 1;
+ resources_restore_t res;
+
+ res.in_file.open(opts.getInFilePath(), std::ios::in | std::ios::binary);
+ if (!res.in_file) {
+ throw RestoreError("cannot open input file");
}
/* 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;
+ res.out_file.open(opts.getOutFilePath(),
+ std::ios::in | std::ios::out | std::ios::binary);
+ if (!res.out_file) {
+ throw RestoreError("cannot open output file");
}
/* 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();
+ 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;
+ 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;
+ try {
+ res.in_buffer = std::make_unique<char[]>(res.in_buffer_size);
+ } catch (const std::bad_alloc &e) {
+ throw RestoreError("cannot allocate buffer for input file data");
}
- return 0;
+ return res;
}
-static bool
-is_input_file_valid(const resources_restore_t *const res, uint32_t sector_size)
+static void
+check_input_file(resources_restore_t &res, const OptionsRestore &opts)
{
- 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) {
+ size_t in_size{0};
+ try {
+ in_size = std::filesystem::file_size(opts.getInFilePath());
+ } catch (const std::exception &e) {
+ throw RestoreError("cannot get size of input file: " +
+ std::string(e.what()));
+ }
+
+ if (in_size == 0) {
+ throw RestoreError("input file is empty");
+ } else if ((in_size % (sizeof(uint64_t) + opts.getSectorSize())) != 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;
+ throw RestoreError(
+ "input file has size that cannot contain valid diff data");
}
- 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;
+ size_t out_size{0};
+ try {
+ out_size = std::filesystem::file_size(opts.getOutFilePath());
+ } catch (const std::exception &e) {
+ throw RestoreError("cannot get size of output file: " +
+ std::string(e.what()));
}
uint64_t prev_out_offset = 0;
@@ -114,116 +119,103 @@ is_input_file_valid(const resources_restore_t *const res, uint32_t sector_size)
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);
+ res.in_file.read(reinterpret_cast<char *>(&out_offset),
+ sizeof(out_offset));
- if (feof(res->in_file)) {
+ if (res.in_file.eof() && res.in_file.fail() && !res.in_file.bad()) {
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(
+ } else if (!res.in_file.good() && !res.in_file.eof()) {
+ throw RestoreError("cannot read from file");
+ }
+ out_offset = le64toh(out_offset);
+
+ if (!is_first_reading && (out_offset <= prev_out_offset)) {
+ throw RestoreError(
+ "a sector offset points behind the previous offset");
+ } else if ((out_offset + opts.getSectorSize()) > out_size) {
+ throw RestoreError(
"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;
+ } else if (!res.in_file.seekg(opts.getSectorSize(),
+ std::ios_base::cur)) {
+ throw RestoreError("cannot seek in input file");
}
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;
+ /* The input file must be read completely */
+ char c;
+ res.in_file.read(&c, 1);
+ if (res.in_file.gcount() != 0) {
+ throw RestoreError("input file is not valid");
}
+ res.in_file.clear();
- return true;
+ /* The file must be prepared for the restoring */
+ if (!res.in_file.seekg(0, std::ios_base::beg)) {
+ throw RestoreError("cannot seek in input file");
+ }
}
-int
-restore(const OptionsRestore &opts)
+static size_t
+read_sectors(std::ifstream &file, char *const buffer, uint32_t buffer_size,
+ uint32_t sector_size)
{
- 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.getSectorSize())) {
- return 1;
+ file.readsome(buffer, buffer_size);
+ const size_t bytes_read = file.gcount();
+
+ if (!file.good() && !file.eof()) {
+ throw RestoreError("cannot read from file");
+ } else if ((bytes_read % sector_size) != 0) {
+ throw RestoreError(
+ "data read from input file is not multiple of sector size");
+ } else {
+ return (bytes_read / sector_size);
}
+}
- bool in_size_ok = false;
- const size_t in_size = file_size(res.in_file, &in_size_ok);
+void
+restore(const OptionsRestore &opts)
+{
+ resources_restore_t res{resources_allocate_for_restore(opts)};
- if (!in_size_ok) {
- print_error("cannot get size of input file: %s", strerror(errno));
- return 1;
- }
+ check_input_file(res, opts);
/* 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);
+ const size_t in_sectors_read =
+ read_sectors(res.in_file, res.in_buffer.get(), 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.get();
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;
+ if (!res.out_file.seekp(out_offset, std::ios_base::beg)) {
+ throw RestoreError("cannot seek in output file");
}
- const size_t out_written =
- 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));
- return 1;
+ if (!res.out_file.write(in_buffer, opts.getSectorSize())) {
+ throw RestoreError("cannot write to output file");
}
+
+ in_buffer += opts.getSectorSize();
}
}
/* 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;
+ char c;
+ res.in_file.read(&c, 1);
+ if (res.in_file.gcount() != 0) {
+ throw RestoreError("input file is not valid");
}
-
- return 0;
+ res.in_file.clear();
}
diff --git a/src/restore.h b/src/restore.h
index 457ef48..0ea9549 100644
--- a/src/restore.h
+++ b/src/restore.h
@@ -29,6 +29,15 @@
#include "options.h"
-int restore(const OptionsRestore &opts);
+class RestoreError : public std::runtime_error
+{
+ public:
+ explicit RestoreError(const std::string &message)
+ : std::runtime_error(message)
+ {
+ }
+};
+
+void restore(const OptionsRestore &opts);
#endif /* RESTORE_H */