aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backup.c151
-rw-r--r--src/backup.h9
-rw-r--r--src/main.c287
-rw-r--r--src/resources.h2
-rw-r--r--src/restore.c150
-rw-r--r--src/restore.h9
6 files changed, 325 insertions, 283 deletions
diff --git a/src/backup.c b/src/backup.c
new file mode 100644
index 0000000..b4c0e0a
--- /dev/null
+++ b/src/backup.c
@@ -0,0 +1,151 @@
+#include "backup.h"
+
+#include "file.h"
+#include "print.h"
+
+#include <errno.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+
+int
+backup(const options_t *const opts, resources_t *const res)
+{
+ const long in_size = file_size(res->in_file);
+
+ if (in_size < 0) {
+ print_error("cannot get size of input file: %s", strerror(errno));
+ return 1;
+ }
+
+ const long ref_size = file_size(res->ref_file);
+
+ if (ref_size < 0) {
+ 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;
+ }
+
+ /* Allocate the buffers */
+ /* The output buffer contains also the offsets */
+ const size_t out_buffer_size =
+ ((opts->buffer_size / opts->sector_size) * sizeof(uint64_t)) +
+ opts->buffer_size;
+
+ if ((res->in_buffer = (char *)malloc(opts->buffer_size)) == NULL) {
+ print_error("cannot allocate buffer for input file data");
+ return 1;
+ } else if ((res->ref_buffer = (char *)malloc(opts->buffer_size)) == NULL) {
+ print_error("cannot allocate buffer for reference file data");
+ return 1;
+ } else if ((res->out_buffer = (char *)malloc(out_buffer_size)) == NULL) {
+ print_error("cannot allocate buffer for output file data");
+ return 1;
+ }
+
+ size_t out_buffer_index = 0;
+ uint64_t offset = 0;
+
+ for (;;) {
+ /* Read the sectors from the input file to the buffer */
+ const size_t in_read =
+ fread(res->in_buffer, 1U, opts->buffer_size, res->in_file);
+
+ if ((in_read % opts->sector_size) != 0) {
+ print_error(
+ "data read from input file is not multiple of sector size");
+ return 1;
+ } else if (ferror(res->in_file)) {
+ print_error("cannot read from input file: %s", strerror(errno));
+ return 1;
+ }
+
+ /* Read sectors from the reference file to the buffer */
+ const size_t ref_read =
+ fread(res->ref_buffer, 1U, opts->buffer_size, res->ref_file);
+
+ if ((ref_read % opts->sector_size) != 0) {
+ print_error(
+ "data read from reference file is not multiple of sector size");
+ return 1;
+ } else if (ferror(res->ref_file)) {
+ print_error("%s", strerror(errno));
+ return 1;
+ }
+
+ if (in_read != ref_read) {
+ print_error(
+ "data read from input file and reference file differ in size");
+ return 1;
+ }
+
+ /* Process sectors in the buffer */
+ for (size_t i = 0; i < in_read; i += opts->sector_size) {
+ /* Compare the sectors */
+ int changed = 0;
+ const size_t j_end = i + opts->sector_size;
+ for (size_t j = i; j < j_end; ++j) {
+ if (res->in_buffer[j] != res->ref_buffer[j]) {
+ changed = 1;
+ break;
+ }
+ }
+
+ if (changed) {
+ /* Write changed sector */
+ if (out_buffer_index >= out_buffer_size) {
+ /* The output buffer is full. Write it to the
+ * output file.
+ */
+ const size_t x = fwrite(res->out_buffer, 1U,
+ out_buffer_index, res->out_file);
+
+ if (x != out_buffer_index) {
+ print_error("cannot write to output file: %s",
+ strerror(errno));
+ return 1;
+ }
+
+ out_buffer_index = 0;
+ }
+
+ const uint64_t o = htole64(offset);
+
+ memcpy(res->out_buffer + out_buffer_index, (void *)&o,
+ sizeof(o));
+ memcpy(res->out_buffer + out_buffer_index, &(res->in_buffer[i]),
+ opts->sector_size);
+ out_buffer_index += sizeof(o) + opts->sector_size;
+ }
+
+ offset += opts->sector_size;
+ }
+
+ if (feof(res->in_file)) {
+ break;
+ }
+ }
+
+ /* Write out the output buffer */
+ if (out_buffer_index >= 0) {
+ const size_t x =
+ fwrite(res->out_buffer, 1U, out_buffer_index, res->out_file);
+
+ if (x != out_buffer_index) {
+ print_error("cannot write to output file: %s", strerror(errno));
+ return 1;
+ }
+ }
+
+ return 0;
+}
diff --git a/src/backup.h b/src/backup.h
new file mode 100644
index 0000000..9d80b67
--- /dev/null
+++ b/src/backup.h
@@ -0,0 +1,9 @@
+#ifndef BACKUP_H
+#define BACKUP_H
+
+#include "options.h"
+#include "resources.h"
+
+int backup(const options_t *const opts, resources_t *const res);
+
+#endif /* BACKUP_H */
diff --git a/src/main.c b/src/main.c
index 27799ad..b6fdbbd 100644
--- a/src/main.c
+++ b/src/main.c
@@ -6,10 +6,12 @@
#include <stdlib.h>
#include <string.h>
+#include "backup.h"
#include "file.h"
#include "options.h"
#include "print.h"
#include "resources.h"
+#include "restore.h"
static void
clean_exit(resources_t *const res, int exit_code)
@@ -58,287 +60,6 @@ open_files(const options_t *const opts, resources_t *const res,
return 0;
}
-static bool
-is_reference_file_valid(resources_t *const res, uint32_t sector_size)
-{
- const long ref_size = file_size(res->ref_file);
-
- if (ref_size < 0) {
- print_error("cannot get size of reference file: %s", strerror(errno));
- return false;
- } else if (ref_size == 0) {
- print_error("reference file is empty");
- return false;
- } else if ((ref_size % (sizeof(uint64_t) + sector_size)) != 0) {
- /* The reference file must hold equally sized sectors and the
- * offset of each of them
- */
- print_error(
- "reference file has size that cannot contain valid diff data");
- return false;
- }
-
- const long out_size = file_size(res->out_file);
-
- if (out_size < 0) {
- print_error("cannot get size of output file: %s", strerror(errno));
- return 1;
- }
-
- uint64_t ref_offset = 0;
- uint64_t prev_out_offset;
-
- /* Scan the reference file and check */
- for (;;) {
- uint64_t out_offset;
- /* Read the next offset */
- const size_t ref_read =
- fread(&out_offset, sizeof(out_offset), 1U, res->ref_file);
- out_offset = le64toh(out_offset);
-
- if (feof(res->ref_file)) {
- break;
- } else if ((ref_read != 1U) || ferror(res->ref_file)) {
- print_error("cannot read from reference file: %s", strerror(errno));
- return false;
- } else if (((ref_offset != 0) && (out_offset <= prev_out_offset)) ||
- ((out_offset + sector_size) > out_size)) {
- /* The offset must be higher than the previous one and it
- * must point into the file
- */
- print_error("reference file is not valid");
- return false;
- } else if (fseek(res->ref_file, sector_size, SEEK_CUR) != 0) {
- print_error("cannot seek in reference file: %s", strerror(errno));
- return false;
- }
-
- prev_out_offset = out_offset;
- }
-
- if (ftell(res->ref_file) != ref_size) {
- /* The reference file must be read completely */
- print_error("reference file is not valid");
- return false;
- } else if (fseek(res->ref_file, 0L, SEEK_SET) != 0) {
- /* The file must be prepared for the restoring */
- print_error("cannot seek in reference file: %s", strerror(errno));
- return false;
- }
-
- return true;
-}
-
-static int
-diff_backup(const options_t *const opts, resources_t *const res)
-{
- const long in_size = file_size(res->in_file);
-
- if (in_size < 0) {
- print_error("cannot get size of input file: %s", strerror(errno));
- return 1;
- }
-
- const long ref_size = file_size(res->ref_file);
-
- if (ref_size < 0) {
- 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;
- }
-
- /* Allocate the buffers */
- /* The output buffer contains also the offsets */
- const size_t out_buffer_size =
- ((opts->buffer_size / opts->sector_size) * sizeof(uint64_t)) +
- opts->buffer_size;
-
- if ((res->in_buffer = (char *)malloc(opts->buffer_size)) == NULL) {
- print_error("cannot allocate buffer for input file data");
- return 1;
- } else if ((res->ref_buffer = (char *)malloc(opts->buffer_size)) == NULL) {
- print_error("cannot allocate buffer for reference file data");
- return 1;
- } else if ((res->out_buffer = (char *)malloc(out_buffer_size)) == NULL) {
- print_error("cannot allocate buffer for output file data");
- return 1;
- }
-
- size_t out_buffer_index = 0;
- uint64_t offset = 0;
-
- for (;;) {
- /* Read the sectors from the input file to the buffer */
- const size_t in_read =
- fread(res->in_buffer, 1U, opts->buffer_size, res->in_file);
-
- if ((in_read % opts->sector_size) != 0) {
- print_error(
- "data read from input file is not multiple of sector size");
- return 1;
- } else if (ferror(res->in_file)) {
- print_error("cannot read from input file: %s", strerror(errno));
- return 1;
- }
-
- /* Read sectors from the reference file to the buffer */
- const size_t ref_read =
- fread(res->ref_buffer, 1U, opts->buffer_size, res->ref_file);
-
- if ((ref_read % opts->sector_size) != 0) {
- print_error(
- "data read from reference file is not multiple of sector size");
- return 1;
- } else if (ferror(res->ref_file)) {
- print_error("%s", strerror(errno));
- return 1;
- }
-
- if (in_read != ref_read) {
- print_error(
- "data read from input file and reference file differ in size");
- return 1;
- }
-
- /* Process sectors in the buffer */
- for (size_t i = 0; i < in_read; i += opts->sector_size) {
- /* Compare the sectors */
- int changed = 0;
- const size_t j_end = i + opts->sector_size;
- for (size_t j = i; j < j_end; ++j) {
- if (res->in_buffer[j] != res->ref_buffer[j]) {
- changed = 1;
- break;
- }
- }
-
- if (changed) {
- /* Write changed sector */
- if (out_buffer_index >= out_buffer_size) {
- /* The output buffer is full. Write it to the
- * output file.
- */
- const size_t x = fwrite(res->out_buffer, 1U,
- out_buffer_index, res->out_file);
-
- if (x != out_buffer_index) {
- print_error("cannot write to output file: %s",
- strerror(errno));
- return 1;
- }
-
- out_buffer_index = 0;
- }
-
- const uint64_t o = htole64(offset);
-
- memcpy(res->out_buffer + out_buffer_index, (void *)&o,
- sizeof(o));
- memcpy(res->out_buffer + out_buffer_index, &(res->in_buffer[i]),
- opts->sector_size);
- out_buffer_index += sizeof(o) + opts->sector_size;
- }
-
- offset += opts->sector_size;
- }
-
- if (feof(res->in_file)) {
- break;
- }
- }
-
- /* Write out the output buffer */
- if (out_buffer_index >= 0) {
- const size_t x =
- fwrite(res->out_buffer, 1U, out_buffer_index, res->out_file);
-
- if (x != out_buffer_index) {
- print_error("cannot write to output file: %s", strerror(errno));
- return 1;
- }
- }
-
- return 0;
-}
-
-static int
-diff_restore(const options_t *const opts, resources_t *const res)
-{
- /* Check validity of the reference file */
- if (!is_reference_file_valid(res, opts->sector_size)) {
- return 1;
- }
-
- const long ref_size = file_size(res->ref_file);
-
- if (ref_size < 0) {
- print_error("cannot get size of reference file: %s", strerror(errno));
- return 1;
- }
-
- /* Allocate the buffer for data from the reference file */
- /* The reference buffer contains also the offsets */
- const size_t ref_buffer_size =
- ((opts->buffer_size / opts->sector_size) * sizeof(uint64_t)) +
- opts->buffer_size;
-
- if ((res->ref_buffer = (char *)malloc(ref_buffer_size)) == NULL) {
- print_error("cannot allocate buffer for reference file data");
- return 1;
- }
-
- /* Restore data from the differential image */
- uint64_t out_offset;
-
- for (;;) {
- /* Read data of the offset and the next sector */
- const size_t ref_read =
- fread(res->ref_buffer, ref_buffer_size, 1U, res->ref_file);
-
- if (feof(res->ref_file)) {
- break;
- } else if ((ref_read != 1U) || ferror(res->ref_file)) {
- print_error("cannot read from reference file: %s", strerror(errno));
- return 1;
- }
-
- /* Get offset */
- out_offset = le64toh(*((uint64_t *)res->ref_buffer));
-
- if (fseek(res->out_file, out_offset, SEEK_SET) != 0) {
- print_error("cannot seek in output file: %s", strerror(errno));
- return 1;
- }
-
- /* Write the sector data to the output file */
- const size_t out_written = fwrite(res->ref_buffer + sizeof(out_offset),
- opts->sector_size, 1U, res->out_file);
-
- if (out_written != 1U) {
- print_error("cannot write to output file: %s", strerror(errno));
- return 1;
- }
- }
-
- /* The reference file must be read completely */
- if (ftell(res->ref_file) != ref_size) {
- print_error("reference file is not valid");
- return 1;
- }
-
- return 0;
-}
-
int
main(int argc, char **argv)
{
@@ -356,8 +77,8 @@ main(int argc, char **argv)
if (open_files(&opts, &res, is_action_backup) != 0) {
clean_exit(&res, 1);
} else if (is_action_backup) {
- clean_exit(&res, diff_backup(&opts, &res));
+ clean_exit(&res, backup(&opts, &res));
} else {
- clean_exit(&res, diff_restore(&opts, &res));
+ clean_exit(&res, restore(&opts, &res));
}
}
diff --git a/src/resources.h b/src/resources.h
index 0cf9777..8effb0c 100644
--- a/src/resources.h
+++ b/src/resources.h
@@ -1,6 +1,8 @@
#ifndef RESOURCES_H
#define RESOURCES_H
+#include <stdio.h>
+
typedef struct {
FILE *in_file;
FILE *ref_file;
diff --git a/src/restore.c b/src/restore.c
new file mode 100644
index 0000000..c6121c1
--- /dev/null
+++ b/src/restore.c
@@ -0,0 +1,150 @@
+#include "restore.h"
+
+#include "file.h"
+#include "print.h"
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static bool
+is_reference_file_valid(resources_t *const res, uint32_t sector_size)
+{
+ const long ref_size = file_size(res->ref_file);
+
+ if (ref_size < 0) {
+ print_error("cannot get size of reference file: %s", strerror(errno));
+ return false;
+ } else if (ref_size == 0) {
+ print_error("reference file is empty");
+ return false;
+ } else if ((ref_size % (sizeof(uint64_t) + sector_size)) != 0) {
+ /* The reference file must hold equally sized sectors and the
+ * offset of each of them
+ */
+ print_error(
+ "reference file has size that cannot contain valid diff data");
+ return false;
+ }
+
+ const long out_size = file_size(res->out_file);
+
+ if (out_size < 0) {
+ print_error("cannot get size of output file: %s", strerror(errno));
+ return 1;
+ }
+
+ uint64_t ref_offset = 0;
+ uint64_t prev_out_offset;
+
+ /* Scan the reference file and check */
+ for (;;) {
+ uint64_t out_offset;
+ /* Read the next offset */
+ const size_t ref_read =
+ fread(&out_offset, sizeof(out_offset), 1U, res->ref_file);
+ out_offset = le64toh(out_offset);
+
+ if (feof(res->ref_file)) {
+ break;
+ } else if ((ref_read != 1U) || ferror(res->ref_file)) {
+ print_error("cannot read from reference file: %s", strerror(errno));
+ return false;
+ } else if (((ref_offset != 0) && (out_offset <= prev_out_offset)) ||
+ ((out_offset + sector_size) > out_size)) {
+ /* The offset must be higher than the previous one and it
+ * must point into the file
+ */
+ print_error("reference file is not valid");
+ return false;
+ } else if (fseek(res->ref_file, sector_size, SEEK_CUR) != 0) {
+ print_error("cannot seek in reference file: %s", strerror(errno));
+ return false;
+ }
+
+ prev_out_offset = out_offset;
+ }
+
+ if (ftell(res->ref_file) != ref_size) {
+ /* The reference file must be read completely */
+ print_error("reference file is not valid");
+ return false;
+ } else if (fseek(res->ref_file, 0L, SEEK_SET) != 0) {
+ /* The file must be prepared for the restoring */
+ print_error("cannot seek in reference file: %s", strerror(errno));
+ return false;
+ }
+
+ return true;
+}
+
+int
+restore(const options_t *const opts, resources_t *const res)
+{
+ /* Check validity of the reference file */
+ if (!is_reference_file_valid(res, opts->sector_size)) {
+ return 1;
+ }
+
+ const long ref_size = file_size(res->ref_file);
+
+ if (ref_size < 0) {
+ print_error("cannot get size of reference file: %s", strerror(errno));
+ return 1;
+ }
+
+ /* Allocate the buffer for data from the reference file */
+ /* The reference buffer contains also the offsets */
+ const size_t ref_buffer_size =
+ ((opts->buffer_size / opts->sector_size) * sizeof(uint64_t)) +
+ opts->buffer_size;
+
+ if ((res->ref_buffer = (char *)malloc(ref_buffer_size)) == NULL) {
+ print_error("cannot allocate buffer for reference file data");
+ return 1;
+ }
+
+ /* Restore data from the differential image */
+ uint64_t out_offset;
+
+ for (;;) {
+ /* Read data of the offset and the next sector */
+ const size_t ref_read =
+ fread(res->ref_buffer, ref_buffer_size, 1U, res->ref_file);
+
+ if (feof(res->ref_file)) {
+ break;
+ } else if ((ref_read != 1U) || ferror(res->ref_file)) {
+ print_error("cannot read from reference file: %s", strerror(errno));
+ return 1;
+ }
+
+ /* Get offset */
+ out_offset = le64toh(*((uint64_t *)res->ref_buffer));
+
+ if (fseek(res->out_file, out_offset, SEEK_SET) != 0) {
+ print_error("cannot seek in output file: %s", strerror(errno));
+ return 1;
+ }
+
+ /* Write the sector data to the output file */
+ const size_t out_written = fwrite(res->ref_buffer + sizeof(out_offset),
+ opts->sector_size, 1U, res->out_file);
+
+ if (out_written != 1U) {
+ print_error("cannot write to output file: %s", strerror(errno));
+ return 1;
+ }
+ }
+
+ /* The reference file must be read completely */
+ if (ftell(res->ref_file) != ref_size) {
+ print_error("reference file is not valid");
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/src/restore.h b/src/restore.h
new file mode 100644
index 0000000..cc095b9
--- /dev/null
+++ b/src/restore.h
@@ -0,0 +1,9 @@
+#ifndef RESTORE_H
+#define RESTORE_H
+
+#include "options.h"
+#include "resources.h"
+
+int restore(const options_t *const opts, resources_t *const res);
+
+#endif /* RESTORE_H */