aboutsummaryrefslogtreecommitdiff
path: root/src/backup.cpp
diff options
context:
space:
mode:
authorJan Sucan <jan@jansucan.com>2023-11-12 15:23:37 +0100
committerJan Sucan <jan@jansucan.com>2023-11-12 15:24:32 +0100
commit452903126d15ab2228910eb36b78b152c07fb247 (patch)
tree8d55ade32531515188e38432c51b76ed8420a91b /src/backup.cpp
parent69b93c3b43210c7745f6ff07ad64a6a8f861e0b9 (diff)
Rename C source file to C++ source files
Diffstat (limited to 'src/backup.cpp')
-rw-r--r--src/backup.cpp156
1 files changed, 156 insertions, 0 deletions
diff --git a/src/backup.cpp b/src/backup.cpp
new file mode 100644
index 0000000..0b558b6
--- /dev/null
+++ b/src/backup.cpp
@@ -0,0 +1,156 @@
+/* Copyright 2021 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 "backup.h"
+
+#include "file.h"
+#include "print.h"
+
+#include <errno.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+
+static int check_files(const options_backup_t *const opts,
+ const resources_backup_t *const res);
+static int write_out_buffer(const char *const buffer, size_t size,
+ FILE *const file);
+
+static int
+check_files(const options_backup_t *const opts,
+ const resources_backup_t *const res)
+{
+ 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;
+ }
+
+ 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;
+ }
+
+ /* 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;
+ } else if ((in_size % opts->sector_size) != 0) {
+ print_error(
+ "size of input file and reference file is not multiple of %" PRIu32,
+ opts->sector_size);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
+write_out_buffer(const char *const buffer, size_t size, FILE *const file)
+{
+ const size_t bytes_written = fwrite(buffer, 1U, size, file);
+
+ if (bytes_written != size) {
+ print_error("cannot write to output file: %s", strerror(errno));
+ return 1;
+ }
+
+ return 0;
+}
+
+int
+backup(const options_backup_t *const opts, const resources_backup_t *const res)
+{
+ if (check_files(opts, res) != 0) {
+ return 1;
+ }
+
+ size_t out_buffer_index = 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 = file_read_sectors(
+ res->in_file, res->in_buffer, opts->buffer_size, opts->sector_size);
+ const size_t ref_sectors_read =
+ file_read_sectors(res->ref_file, res->ref_buffer, opts->buffer_size,
+ opts->sector_size);
+
+ if ((in_sectors_read == 0) || (ref_sectors_read == 0)) {
+ break;
+ } else if (in_sectors_read != ref_sectors_read) {
+ print_error(
+ "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->sector_size;
+
+ if (memcmp(res->in_buffer + buffer_offset,
+ res->ref_buffer + buffer_offset,
+ opts->sector_size) != 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;
+ }
+ 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,
+ sizeof(o));
+ out_buffer_index += sizeof(o);
+
+ memcpy(res->out_buffer + out_buffer_index,
+ res->in_buffer + buffer_offset, opts->sector_size);
+ out_buffer_index += opts->sector_size;
+ }
+
+ input_file_offset += opts->sector_size;
+ }
+ }
+
+ /* 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;
+ }
+ }
+
+ return 0;
+}