aboutsummaryrefslogtreecommitdiff
path: root/src/restore.cpp
diff options
context:
space:
mode:
authorJan Sucan <jan@jansucan.com>2024-04-14 11:51:34 +0200
committerJán Sučan <jan@jansucan.com>2024-05-04 15:46:47 +0200
commit16ff70613a95d7f85f4cab09f2b3316f67e5901b (patch)
treec7b7768dd048d2ca040ea09c2e9df554d6f1e5ad /src/restore.cpp
parent451be15d119d4d485d06f19f15d9a996cefb5288 (diff)
Move input and output buffering to classes
Diffstat (limited to 'src/restore.cpp')
-rw-r--r--src/restore.cpp152
1 files changed, 51 insertions, 101 deletions
diff --git a/src/restore.cpp b/src/restore.cpp
index c9ace96..813d9ce 100644
--- a/src/restore.cpp
+++ b/src/restore.cpp
@@ -25,58 +25,13 @@
*/
#include "restore.h"
+#include "buffered_file.h"
#include <filesystem>
#include <fstream>
-#include <iostream>
-
-typedef struct {
- std::ifstream in_file;
- std::fstream out_file;
-
- std::unique_ptr<char[]> in_buffer;
-
- size_t in_sector_size;
- size_t in_buffer_size;
-} resources_restore_t;
-
-static resources_restore_t
-resources_allocate_for_restore(const OptionsRestore &opts)
-{
- 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
- */
- 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();
- 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;
-
- 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 res;
-}
static void
-check_input_file(resources_restore_t &res, const OptionsRestore &opts)
+check_input_file(const OptionsRestore &opts)
{
size_t in_size{0};
try {
@@ -104,6 +59,12 @@ check_input_file(resources_restore_t &res, const OptionsRestore &opts)
std::string(e.what()));
}
+ std::ifstream in_file;
+ in_file.open(opts.getInFilePath(), std::ios::in | std::ios::binary);
+ if (!in_file) {
+ throw RestoreError("cannot open input file");
+ }
+
uint64_t prev_out_offset = 0;
bool is_first_reading = true;
@@ -111,12 +72,11 @@ check_input_file(resources_restore_t &res, const OptionsRestore &opts)
for (;;) {
uint64_t out_offset;
/* Read the next offset */
- res.in_file.read(reinterpret_cast<char *>(&out_offset),
- sizeof(out_offset));
+ in_file.read(reinterpret_cast<char *>(&out_offset), sizeof(out_offset));
- if (res.in_file.eof() && res.in_file.fail() && !res.in_file.bad()) {
+ if (in_file.eof() && in_file.fail() && !in_file.bad()) {
break;
- } else if (!res.in_file.good() && !res.in_file.eof()) {
+ } else if (!in_file.good() && !in_file.eof()) {
throw RestoreError("cannot read from file");
}
out_offset = le64toh(out_offset);
@@ -127,8 +87,7 @@ check_input_file(resources_restore_t &res, const OptionsRestore &opts)
} else if ((out_offset + opts.getSectorSize()) > out_size) {
throw RestoreError(
"a sector offset points past the end of the output file");
- } else if (!res.in_file.seekg(opts.getSectorSize(),
- std::ios_base::cur)) {
+ } else if (!in_file.seekg(opts.getSectorSize(), std::ios_base::cur)) {
throw RestoreError("cannot seek in input file");
}
@@ -138,77 +97,68 @@ check_input_file(resources_restore_t &res, const OptionsRestore &opts)
/* The input file must be read completely */
char c;
- res.in_file.read(&c, 1);
- if (res.in_file.gcount() != 0) {
+ in_file.read(&c, 1);
+ if (in_file.gcount() != 0) {
throw RestoreError("input file is not valid");
}
- res.in_file.clear();
+ in_file.clear();
- /* 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");
- }
-}
-
-static size_t
-read_sectors(std::ifstream &file, char *const buffer, uint32_t buffer_size,
- uint32_t sector_size)
-{
- file.read(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);
- }
+ in_file.close();
}
void
restore(const OptionsRestore &opts)
{
- resources_restore_t res{resources_allocate_for_restore(opts)};
+ check_input_file(opts);
+
+ BufferedFileReader in_file(opts.getInFilePath(), opts.getBufferSize());
+
+ std::fstream out_file;
+ out_file.open(opts.getOutFilePath(),
+ std::ios::in | std::ios::out | std::ios::binary);
+ if (!out_file) {
+ throw RestoreError("cannot open output file");
+ }
- check_input_file(res, opts);
+ const size_t in_buffer_size = sizeof(uint64_t) + opts.getSectorSize();
+ std::unique_ptr<char[]> in_buffer;
+ try {
+ in_buffer = std::make_unique<char[]>(in_buffer_size);
+ } catch (const std::bad_alloc &e) {
+ throw RestoreError("cannot allocate sector buffer for input file data");
+ }
/* Restore data from the differential image */
+ size_t in_read_size = {0};
for (;;) {
- /* Read data of the offset and the next sector */
- const size_t in_sectors_read =
- read_sectors(res.in_file, res.in_buffer.get(), res.in_buffer_size,
- res.in_sector_size);
+ in_read_size = in_file.read(in_buffer.get(), in_buffer_size);
- if (in_sectors_read == 0) {
+ if (in_read_size == 0) {
break;
+ } else if (in_read_size != in_buffer_size) {
+ throw RestoreError("cannot read from input file");
}
- char *in_buffer = res.in_buffer.get();
-
- for (size_t s = 0; s < in_sectors_read; ++s) {
- const uint64_t out_offset =
- le64toh(*(reinterpret_cast<uint64_t *>(in_buffer)));
- in_buffer += sizeof(uint64_t);
-
- if (!res.out_file.seekp(out_offset, std::ios_base::beg)) {
- throw RestoreError("cannot seek in output file");
- }
+ const uint64_t out_offset =
+ le64toh(*reinterpret_cast<uint64_t *>(in_buffer.get()));
- if (!res.out_file.write(in_buffer, opts.getSectorSize())) {
- throw RestoreError("cannot write to output file");
- }
+ if (!out_file.seekp(out_offset, std::ios_base::beg)) {
+ throw RestoreError("cannot seek in output file");
+ }
- in_buffer += opts.getSectorSize();
+ if (!out_file.write(reinterpret_cast<char *>(in_buffer.get()) +
+ sizeof(uint64_t),
+ opts.getSectorSize())) {
+ throw RestoreError("cannot write to output file");
}
}
+ out_file.close();
+
/* The input file must be read completely */
char c;
- res.in_file.read(&c, 1);
- if (res.in_file.gcount() != 0) {
+ in_read_size = in_file.read(&c, 1);
+ if (in_read_size != 0) {
throw RestoreError("input file is not valid");
}
- res.in_file.clear();
}