From 16ff70613a95d7f85f4cab09f2b3316f67e5901b Mon Sep 17 00:00:00 2001 From: Jan Sucan Date: Sun, 14 Apr 2024 11:51:34 +0200 Subject: Move input and output buffering to classes --- src/restore.cpp | 152 +++++++++++++++++++------------------------------------- 1 file changed, 51 insertions(+), 101 deletions(-) (limited to 'src/restore.cpp') 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 #include -#include - -typedef struct { - std::ifstream in_file; - std::fstream out_file; - - std::unique_ptr 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(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(&out_offset), - sizeof(out_offset)); + in_file.read(reinterpret_cast(&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 in_buffer; + try { + in_buffer = std::make_unique(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(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(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(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(); } -- cgit v1.2.3