aboutsummaryrefslogtreecommitdiff
path: root/src/restore.cpp
diff options
context:
space:
mode:
authorJan Sucan <jan@jansucan.com>2025-01-18 07:57:57 +0100
committerJán Sučan <jan@jansucan.com>2025-01-18 12:44:04 +0100
commit8b51499900e125a55dcdc425d29550b98a8064b4 (patch)
tree938545b3b612bcacd3599785be3f4a23ec08bea7 /src/restore.cpp
parenta7e8d00f5140d250e339736eb49e20609bffa47f (diff)
Initial implementation of diff file format v2
Diffstat (limited to 'src/restore.cpp')
-rw-r--r--src/restore.cpp139
1 files changed, 29 insertions, 110 deletions
diff --git a/src/restore.cpp b/src/restore.cpp
index 8a5b29f..a747d16 100644
--- a/src/restore.cpp
+++ b/src/restore.cpp
@@ -26,93 +26,23 @@
#include "restore.h"
#include "buffered_file.h"
+#include "format_v2.h"
#include <filesystem>
#include <fstream>
-
-static void
-check_diff_file(const OptionsRestore &opts)
-{
- size_t diff_size{0};
- try {
- diff_size = std::filesystem::file_size(opts.getDiffFilePath());
- } catch (const std::exception &e) {
- throw RestoreError("cannot get size of diff file: " +
- std::string(e.what()));
- }
-
- if (diff_size == 0) {
- throw RestoreError("diff file is empty");
- } else if ((diff_size % (sizeof(uint64_t) + opts.getSectorSize())) != 0) {
- /* The diff file must hold equally sized sectors and the
- * offset of each of them
- */
- throw RestoreError(
- "diff file has size that cannot contain valid diff data");
- }
-
- 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()));
- }
-
- std::ifstream diff_file;
- diff_file.open(opts.getDiffFilePath(), std::ios::in | std::ios::binary);
- if (!diff_file) {
- throw RestoreError("cannot open diff file");
- }
-
- uint64_t prev_out_offset = 0;
- bool is_first_reading = true;
-
- /* Scan the diff file and check */
- for (;;) {
- uint64_t out_offset;
- /* Read the next offset */
- diff_file.read(reinterpret_cast<char *>(&out_offset),
- sizeof(out_offset));
-
- if (diff_file.eof() && diff_file.fail() && !diff_file.bad()) {
- break;
- } else if (!diff_file.good() && !diff_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");
- } else if (!diff_file.seekg(opts.getSectorSize(), std::ios_base::cur)) {
- throw RestoreError("cannot seek in diff file");
- }
-
- is_first_reading = false;
- prev_out_offset = out_offset;
- }
-
- /* The diff file must be read completely */
- char c;
- diff_file.read(&c, 1);
- if (diff_file.gcount() != 0) {
- throw RestoreError("diff file is not valid");
- }
- diff_file.clear();
-
- diff_file.close();
-}
+#include <vector>
void
restore(const OptionsRestore &opts)
{
- check_diff_file(opts);
+ std::fstream diff_stream;
+ diff_stream.open(opts.getDiffFilePath(),
+ std::ifstream::in | std::ifstream::binary);
+ if (!diff_stream) {
+ throw RestoreError("cannot open diff file");
+ }
- BufferedFileReader diff_file(opts.getDiffFilePath(), opts.getBufferSize());
+ FormatV2::Reader diff_reader(diff_stream, opts.getBufferSize());
std::fstream out_file;
out_file.open(opts.getOutFilePath(),
@@ -121,45 +51,34 @@ restore(const OptionsRestore &opts)
throw RestoreError("cannot open output file");
}
- const size_t diff_buffer_size = sizeof(uint64_t) + opts.getSectorSize();
- std::unique_ptr<char[]> diff_buffer;
- try {
- diff_buffer = std::make_unique<char[]>(diff_buffer_size);
- } catch (const std::bad_alloc &e) {
- throw RestoreError("cannot allocate sector buffer for diff file data");
- }
-
- /* Restore data from the differential image */
- size_t diff_read_size = {0};
for (;;) {
- diff_read_size = diff_file.read(diff_buffer.get(), diff_buffer_size);
-
- if (diff_read_size == 0) {
+ const uint64_t offset{diff_reader.readOffset()};
+ if (diff_reader.eof()) {
break;
- } else if (diff_read_size != diff_buffer_size) {
- throw RestoreError("cannot read from diff file");
}
- const uint64_t out_offset =
- le64toh(*reinterpret_cast<uint64_t *>(diff_buffer.get()));
-
- if (!out_file.seekp(out_offset, std::ios_base::beg)) {
+ if (!out_file.seekp(offset, std::ios_base::beg)) {
throw RestoreError("cannot seek in output file");
}
- if (!out_file.write(reinterpret_cast<char *>(diff_buffer.get()) +
- sizeof(uint64_t),
- opts.getSectorSize())) {
- throw RestoreError("cannot write to output file");
- }
- }
+ uint64_t size{diff_reader.readSize()};
- out_file.close();
+ while (size > 0) {
+ char *data;
+ const size_t r{diff_reader.readData(size, &data)};
+ if (r == 0) {
+ break;
+ }
- /* The diff file must be read completely */
- char c;
- diff_read_size = diff_file.read(&c, 1);
- if (diff_read_size != 0) {
- throw RestoreError("diff file is not valid");
+ if (!out_file.write(data, r)) {
+ throw RestoreError("cannot write to output file");
+ }
+
+ size -= r;
+ }
+
+ if (size > 0) {
+ throw RestoreError("cannot read all the data of the record");
+ }
}
}