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/backup.cpp | 179 +++++++++++++-------------------------------------------- 1 file changed, 39 insertions(+), 140 deletions(-) (limited to 'src/backup.cpp') diff --git a/src/backup.cpp b/src/backup.cpp index 99a9141..111d3f3 100644 --- a/src/backup.cpp +++ b/src/backup.cpp @@ -25,79 +25,12 @@ */ #include "backup.h" +#include "buffered_file.h" #include #include -typedef struct { - std::ifstream in_file; - std::ifstream ref_file; - std::ofstream out_file; - - std::unique_ptr in_buffer; - std::unique_ptr ref_buffer; - std::unique_ptr out_buffer; - - size_t out_buffer_size; -} resources_backup_t; - static void check_files(const OptionsBackup &opts); -static void write_out_buffer(const char *const buffer, size_t size, - std::ofstream &file); - -static resources_backup_t -resources_allocate_for_backup(const OptionsBackup &opts) -{ - 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"); - } - - 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 - */ - 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 = - ((opts.getBufferSize() / opts.getSectorSize()) * sizeof(uint64_t)) + - opts.getBufferSize(); - - // TODO: separate function - try { - res.in_buffer = std::make_unique(opts.getBufferSize()); - } catch (const std::bad_alloc &e) { - throw BackupError("cannot allocate buffer for input file data"); - } - - try { - res.ref_buffer = std::make_unique(opts.getBufferSize()); - } catch (const std::bad_alloc &e) { - throw BackupError("cannot allocate buffer for reference file data"); - } - - try { - res.out_buffer = std::make_unique(res.out_buffer_size); - } catch (const std::bad_alloc &e) { - throw BackupError("cannot allocate buffer for output file data"); - } - - return res; -} static void check_files(const OptionsBackup &opts) @@ -128,91 +61,57 @@ check_files(const OptionsBackup &opts) } } -static void -write_out_buffer(const char *const buffer, size_t size, std::ofstream &file) +void +backup(const OptionsBackup &opts) { - file.write(buffer, size); + check_files(opts); - if (!file) { - throw BackupError("cannot write to output file"); - } -} + BufferedFileReader in_file(opts.getInFilePath(), opts.getBufferSize()); + BufferedFileReader ref_file(opts.getRefFilePath(), opts.getBufferSize()); + BufferedFileWriter out_file(opts.getOutFilePath(), opts.getBufferSize()); -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(); + std::unique_ptr in_buffer; + try { + in_buffer = std::make_unique(opts.getSectorSize()); + } catch (const std::bad_alloc &e) { + throw BackupError("cannot allocate sector buffer for input file data"); + } - if (!file.good() && !file.eof()) { - throw BackupError("cannot read from file"); - } else if ((bytes_read % sector_size) != 0) { + std::unique_ptr ref_buffer; + try { + ref_buffer = std::make_unique(opts.getSectorSize()); + } catch (const std::bad_alloc &e) { throw BackupError( - "data read from input file is not multiple of sector size"); - } else { - return (bytes_read / sector_size); + "cannot allocate sector buffer for reference file data"); } -} - -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; + uint64_t input_file_offset{0}; for (;;) { - /* Read the sectors from the input and reference files into the buffers - */ - const size_t in_sectors_read = - read_sectors(res.in_file, res.in_buffer.get(), opts.getBufferSize(), - opts.getSectorSize()); - const size_t ref_sectors_read = - read_sectors(res.ref_file, res.ref_buffer.get(), - opts.getBufferSize(), opts.getSectorSize()); + // Read sectors + const size_t in_read_size = + in_file.read(in_buffer.get(), opts.getSectorSize()); + const size_t ref_read_size = + ref_file.read(ref_buffer.get(), opts.getSectorSize()); - if ((in_sectors_read == 0) || (ref_sectors_read == 0)) { - break; - } else if (in_sectors_read != ref_sectors_read) { + if (in_read_size != ref_read_size) { throw BackupError( - "cannot read equal amount of sectors from the input files"); + "cannot read equal amount of bytes from the input files"); + } else if (in_read_size == 0) { + break; + } else if (in_read_size != opts.getSectorSize()) { + throw BackupError("cannot read full sectors from the input files"); } - /* 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.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 */ - 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.get() + out_buffer_index, - reinterpret_cast(&o), sizeof(o)); - out_buffer_index += sizeof(o); - - memcpy(res.out_buffer.get() + out_buffer_index, - res.in_buffer.get() + buffer_offset, - opts.getSectorSize()); - out_buffer_index += opts.getSectorSize(); - } - - input_file_offset += opts.getSectorSize(); + // Check for difference + const bool differ = (memcmp(in_buffer.get(), ref_buffer.get(), + opts.getSectorSize()) != 0); + if (differ) { + // Backup sector + uint64_t o = htole64(input_file_offset); + out_file.write(reinterpret_cast(&o), sizeof(o)); + out_file.write(in_buffer.get(), opts.getSectorSize()); } - } - /* Write out the output buffer */ - if (out_buffer_index > 0) { - write_out_buffer(res.out_buffer.get(), out_buffer_index, res.out_file); + input_file_offset += opts.getSectorSize(); } } -- cgit v1.2.3