aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Sucan <jan@jansucan.com>2024-12-28 11:52:13 +0100
committerJán Sučan <jan@jansucan.com>2024-12-31 08:26:48 +0100
commite34296bbaa3b80a9c5c1bf6dba3ada28016f03de (patch)
tree88c4302c93ee9c0ef8946a0fc305774c4d7d22be
parent9280ff2c747a5a59f0a6e0cc6335b24de62cacc9 (diff)
Use options instead of positional arguments for file paths
-rw-r--r--README.md16
-rw-r--r--src/options.cpp184
-rw-r--r--tests/002-missing_arguments.sh4
-rw-r--r--tests/003-too_many_arguments.sh4
-rw-r--r--tests/004-unknown_option.sh4
-rw-r--r--tests/005-missing_argument_for_option.sh8
-rw-r--r--tests/006-incorrect_buffer_size.sh12
-rw-r--r--tests/007-incorrect_sector_size.sh12
-rw-r--r--tests/100-cannot_open_files.sh6
-rw-r--r--tests/200-input_and_reference_size_differs.sh2
-rw-r--r--tests/201-input_or_reference_size_is_not_multiple_of_sector_size.sh2
-rw-r--r--tests/300-incorrect_reference_file.sh8
-rw-r--r--tests/400-successful_backup_restore.sh4
13 files changed, 164 insertions, 102 deletions
diff --git a/README.md b/README.md
index 7572f9a..8139443 100644
--- a/README.md
+++ b/README.md
@@ -18,16 +18,16 @@ is read twice when restoring it. Because of that, it is slower.
> diff-dd help
-> diff-dd backup [-s SECTOR_SIZE] [-b BUFFER_SIZE] INFILE BASEFILE OUTFILE
+> diff-dd backup [-S SECTOR_SIZE] [-B BUFFER_SIZE] -i INFILE -b BASEFILE -o OUTFILE
-> diff-dd restore [-s SECTOR_SIZE] [-b BUFFER_SIZE] DIFFFILE OUTFILE
+> diff-dd restore [-S SECTOR_SIZE] [-B BUFFER_SIZE] -d DIFFFILE -o OUTFILE
## Backup
Using ```diff-dd ``` for backup requires the full backup image to
exist. Differential backup is created with:
-> diff-dd backup INFILE BASEFILE OUTFILE
+> diff-dd backup -i INFILE -b BASEFILE -o OUTFILE
The ```INFILE``` is a path to the file to backup differentially, the
```BASEFILE``` is the full image, and the ```OUTFILE``` is the file to
@@ -39,15 +39,15 @@ which only the changed sectors of the ```INFILE```, compared to the
The restoration means application of the changed sectors saved in the
```DIFFFILE```, which is the differential image, to the ```OUTFILE```:
-> diff-dd restore DIFFFILE OUTFILE
+> diff-dd restore -d DIFFFILE -o OUTFILE
## Options
-```-s``` sets the sector size by which the files will be processed
+```-S``` sets the sector size by which the files will be processed
(default is 512 B). It can be used to control granularity of
differential backup.
-```-b``` sets the size of the buffer for the sectors of the input and
+```-B``` sets the size of the buffer for the sectors of the input and
output file (default is 4 MiB). The input data is always buffered. The
output data are buffered only in backup mode.
@@ -59,13 +59,13 @@ First, the full image of the partition to backup has to be created:
When the user decides to create the differential image, he or she runs:
-> diff-dd backup /dev/sda1 full.img diff.img
+> diff-dd backup -i /dev/sda1 -b full.img -o diff.img
If a data accident happens, the partition can be restored by running:
> dd bs=4M if=full.img of=/dev/sda1
-> diff-dd restore diff.img /dev/sda1
+> diff-dd restore -d diff.img -o /dev/sda1
The first command restores the old full image. The second one applies
the differences.
diff --git a/src/options.cpp b/src/options.cpp
index 280d5c6..66a8c69 100644
--- a/src/options.cpp
+++ b/src/options.cpp
@@ -86,11 +86,12 @@ OptionsRestore::getOutFilePath() const
void
OptionParser::printUsage()
{
- std::cout << "Usage: " << PROGRAM_NAME_STR << " backup [-s SECTOR_SIZE]";
- std::cout << " [-b BUFFER_SIZE] INFILE BASEFILE OUTFILE" << std::endl;
+ std::cout << "Usage: " << PROGRAM_NAME_STR << " backup [-S SECTOR_SIZE]";
+ std::cout << " [-B BUFFER_SIZE] -i INFILE -b BASEFILE -o OUTFILE"
+ << std::endl;
- std::cout << " Or: " << PROGRAM_NAME_STR << " restore [-s SECTOR_SIZE]";
- std::cout << "[-b BUFFER_SIZE] DIFFFILE OUTFILE" << std::endl;
+ std::cout << " Or: " << PROGRAM_NAME_STR << " restore [-S SECTOR_SIZE]";
+ std::cout << "[-B BUFFER_SIZE] -d DIFFFILE -o OUTFILE" << std::endl;
std::cout << " Or: " << PROGRAM_NAME_STR << " help" << std::endl;
}
@@ -118,82 +119,118 @@ OptionParser::parseBackup(int argc, char **argv)
{
OptionsBackup opts;
- parse_common(&argc, &argv, opts);
+ // Skip the executable name. Do not skip the operation name. getopt expects
+ // to start at an argument immediately preceding the possible options.
+ argc -= 1;
+ argv += 1;
- if (argc < 3) {
- throw OptionError("missing arguments");
- } else if (argc > 3) {
- throw OptionError("too many arguments");
- } else {
- opts.in_file_path = next_arg(&argv);
- opts.base_file_path = next_arg(&argv);
- opts.out_file_path = next_arg(&argv);
- }
+ int ch;
+ const char *arg_sector_size = NULL;
+ const char *arg_buffer_size = NULL;
+ const char *arg_input_file = NULL;
+ const char *arg_base_file = NULL;
+ const char *arg_output_file = NULL;
- return opts;
-}
+ while ((ch = getopt(argc, argv, ":B:S:i:b:o:")) != -1) {
+ switch (ch) {
+ case 'B':
+ arg_buffer_size = optarg;
+ break;
-OptionsRestore
-OptionParser::parseRestore(int argc, char **argv)
-{
- OptionsRestore opts;
+ case 'S':
+ arg_sector_size = optarg;
+ break;
- parse_common(&argc, &argv, opts);
+ case 'i':
+ arg_input_file = optarg;
+ break;
- if (argc < 2) {
- throw OptionError("missing arguments");
- } else if (argc > 2) {
- throw OptionError("too many arguments");
- } else {
- opts.diff_file_path = next_arg(&argv);
- opts.out_file_path = next_arg(&argv);
- }
+ case 'b':
+ arg_base_file = optarg;
+ break;
- return opts;
-}
+ case 'o':
+ arg_output_file = optarg;
+ break;
-bool
-OptionParser::isOperation(int argc, char **argv, std::string_view operationName)
-{
- return ((argc >= 2) &&
- (strncmp(argv[1], operationName.data(),
- OptionParser::MAX_OPERATION_NAME_LENGTH) == 0));
-}
+ case ':':
+ throw OptionError("missing argument for option '-" +
+ std::string(1, optopt) + "'");
+ default:
+ throw OptionError("unknown option '-" + std::string(1, optopt) +
+ "'");
+ }
+ }
-int
-OptionParser::parse_unsigned(const char *const arg, uint32_t *const value)
-{
- char *end;
+ argc -= optind;
+ argv += optind;
- errno = 0;
+ /* Convert numbers in the arguments */
+ if ((arg_sector_size != NULL) &&
+ parse_unsigned(arg_sector_size, &(opts.sector_size))) {
+ throw OptionError("incorrect sector size");
+ } else if ((arg_buffer_size != NULL) &&
+ parse_unsigned(arg_buffer_size, &(opts.buffer_size))) {
+ throw OptionError("incorrect buffer size");
+ } else if (opts.sector_size == 0) {
+ throw OptionError("sector size cannot be 0");
+ } else if (opts.buffer_size == 0) {
+ throw OptionError("buffer size cannot be 0");
+ } else if (opts.sector_size > opts.buffer_size) {
+ throw OptionError("sector size cannot larger than buffer size");
+ } else if ((opts.buffer_size % opts.sector_size) != 0) {
+ throw OptionError("buffer size is not multiple of sector size");
+ }
- *value = strtoul(arg, &end, 0);
+ if (arg_input_file == NULL) {
+ throw OptionError("missing input file");
+ } else if (arg_base_file == NULL) {
+ throw OptionError("missing base file");
+ } else if (arg_output_file == NULL) {
+ throw OptionError("missing output file");
+ } else if (argc != 0) {
+ throw OptionError("too many arguments");
+ }
- return ((*end != '\0') || (errno != 0)) ? -1 : 0;
+ opts.in_file_path = arg_input_file;
+ opts.base_file_path = arg_base_file;
+ opts.out_file_path = arg_output_file;
+
+ return opts;
}
-void
-OptionParser::parse_common(int *const argc, char ***const argv, Options &opts)
+OptionsRestore
+OptionParser::parseRestore(int argc, char **argv)
{
- // Skip the executable name. Do not skip the operation name. getopt expects
- // to start at an argument immediately preceding the possible options.
- *argc -= 1;
- *argv += 1;
+ OptionsRestore opts;
+
+ argc -= 1;
+ argv += 1;
int ch;
const char *arg_sector_size = NULL;
const char *arg_buffer_size = NULL;
+ const char *arg_diff_file = NULL;
+ const char *arg_output_file = NULL;
- while ((ch = getopt(*argc, *argv, ":b:s:")) != -1) {
+ while ((ch = getopt(argc, argv, ":B:S:d:o:")) != -1) {
switch (ch) {
- case 'b':
+ case 'B':
arg_buffer_size = optarg;
break;
- case 's':
+ case 'S':
arg_sector_size = optarg;
break;
+ case 'd':
+ arg_diff_file = optarg;
+ break;
+
+ case 'o':
+ arg_output_file = optarg;
+ break;
+
case ':':
throw OptionError("missing argument for option '-" +
std::string(1, optopt) + "'");
@@ -203,8 +240,8 @@ OptionParser::parse_common(int *const argc, char ***const argv, Options &opts)
}
}
- *argc -= optind;
- *argv += optind;
+ argc -= optind;
+ argv += optind;
/* Convert numbers in the arguments */
if ((arg_sector_size != NULL) &&
@@ -222,12 +259,37 @@ OptionParser::parse_common(int *const argc, char ***const argv, Options &opts)
} else if ((opts.buffer_size % opts.sector_size) != 0) {
throw OptionError("buffer size is not multiple of sector size");
}
+
+ if (arg_diff_file == NULL) {
+ throw OptionError("missing diff file");
+ } else if (arg_output_file == NULL) {
+ throw OptionError("missing output file");
+ } else if (argc != 0) {
+ throw OptionError("too many arguments");
+ }
+
+ opts.diff_file_path = arg_diff_file;
+ opts.out_file_path = arg_output_file;
+
+ return opts;
}
-const char *
-OptionParser::next_arg(char ***const argv)
+bool
+OptionParser::isOperation(int argc, char **argv, std::string_view operationName)
{
- const char *arg = **argv;
- ++(*argv);
- return arg;
+ return ((argc >= 2) &&
+ (strncmp(argv[1], operationName.data(),
+ OptionParser::MAX_OPERATION_NAME_LENGTH) == 0));
+}
+
+int
+OptionParser::parse_unsigned(const char *const arg, uint32_t *const value)
+{
+ char *end;
+
+ errno = 0;
+
+ *value = strtoul(arg, &end, 0);
+
+ return ((*end != '\0') || (errno != 0)) ? -1 : 0;
}
diff --git a/tests/002-missing_arguments.sh b/tests/002-missing_arguments.sh
index a8cb13c..c3aaa1b 100644
--- a/tests/002-missing_arguments.sh
+++ b/tests/002-missing_arguments.sh
@@ -4,7 +4,7 @@ source ./assert.sh
PROGRAM_EXEC="$1"
-assert "Usage" "missing arguments" 1 $PROGRAM_EXEC backup
-assert "Usage" "missing arguments" 1 $PROGRAM_EXEC restore
+assert "Usage" "missing input file" 1 $PROGRAM_EXEC backup
+assert "Usage" "missing diff file" 1 $PROGRAM_EXEC restore
exit 0
diff --git a/tests/003-too_many_arguments.sh b/tests/003-too_many_arguments.sh
index 3bdc55f..2891afd 100644
--- a/tests/003-too_many_arguments.sh
+++ b/tests/003-too_many_arguments.sh
@@ -4,7 +4,7 @@ source ./assert.sh
PROGRAM_EXEC="$1"
-assert "Usage" "too many arguments" 1 $PROGRAM_EXEC backup arg1 arg2 arg3 arg4
-assert "Usage" "too many arguments" 1 $PROGRAM_EXEC restore arg1 arg2 arg3
+assert "Usage" "too many arguments" 1 $PROGRAM_EXEC backup -i arg1 -b arg2 -o arg3 arg4
+assert "Usage" "too many arguments" 1 $PROGRAM_EXEC restore -d arg1 -o arg2 arg3
exit 0
diff --git a/tests/004-unknown_option.sh b/tests/004-unknown_option.sh
index 4a03a37..452d904 100644
--- a/tests/004-unknown_option.sh
+++ b/tests/004-unknown_option.sh
@@ -4,7 +4,7 @@ source ./assert.sh
PROGRAM_EXEC="$1"
-assert "Usage" "unknown option '-x'" 1 $PROGRAM_EXEC backup -x in base out
-assert "Usage" "unknown option '-x'" 1 $PROGRAM_EXEC restore -x diff out
+assert "Usage" "unknown option '-x'" 1 $PROGRAM_EXEC backup -x -i in -b base -o out
+assert "Usage" "unknown option '-x'" 1 $PROGRAM_EXEC restore -x -d diff -o out
exit 0
diff --git a/tests/005-missing_argument_for_option.sh b/tests/005-missing_argument_for_option.sh
index aa7a899..b519513 100644
--- a/tests/005-missing_argument_for_option.sh
+++ b/tests/005-missing_argument_for_option.sh
@@ -4,10 +4,10 @@ source ./assert.sh
PROGRAM_EXEC="$1"
-assert "Usage" "missing argument for option '-b'" 1 $PROGRAM_EXEC backup -b
-assert "Usage" "missing argument for option '-s'" 1 $PROGRAM_EXEC backup -s
+assert "Usage" "missing argument for option '-B'" 1 $PROGRAM_EXEC backup -B
+assert "Usage" "missing argument for option '-S'" 1 $PROGRAM_EXEC backup -S
-assert "Usage" "missing argument for option '-b'" 1 $PROGRAM_EXEC restore -b
-assert "Usage" "missing argument for option '-s'" 1 $PROGRAM_EXEC restore -s
+assert "Usage" "missing argument for option '-B'" 1 $PROGRAM_EXEC restore -B
+assert "Usage" "missing argument for option '-S'" 1 $PROGRAM_EXEC restore -S
exit 0
diff --git a/tests/006-incorrect_buffer_size.sh b/tests/006-incorrect_buffer_size.sh
index 5e59952..1dfbc24 100644
--- a/tests/006-incorrect_buffer_size.sh
+++ b/tests/006-incorrect_buffer_size.sh
@@ -4,12 +4,12 @@ source ./assert.sh
PROGRAM_EXEC="$1"
-assert "Usage" "incorrect sector size" 1 $PROGRAM_EXEC backup -s abc123 in base out
-assert "Usage" "sector size cannot be 0" 1 $PROGRAM_EXEC backup -s 0 in base out
-assert "Usage" "sector size cannot larger than buffer size" 1 $PROGRAM_EXEC backup -s 2 -b 1 in base out
+assert "Usage" "incorrect sector size" 1 $PROGRAM_EXEC backup -S abc123 -i in -b base -o out
+assert "Usage" "sector size cannot be 0" 1 $PROGRAM_EXEC backup -S 0 -i in -b base -o out
+assert "Usage" "sector size cannot larger than buffer size" 1 $PROGRAM_EXEC backup -S 2 -B 1 -i in -b base -o out
-assert "Usage" "incorrect sector size" 1 $PROGRAM_EXEC restore -s abc123 diff out
-assert "Usage" "sector size cannot be 0" 1 $PROGRAM_EXEC restore -s 0 diff out
-assert "Usage" "sector size cannot larger than buffer size" 1 $PROGRAM_EXEC restore -s 2 -b 1 diff out
+assert "Usage" "incorrect sector size" 1 $PROGRAM_EXEC restore -S abc123 -d diff -o out
+assert "Usage" "sector size cannot be 0" 1 $PROGRAM_EXEC restore -S 0 -d diff -o out
+assert "Usage" "sector size cannot larger than buffer size" 1 $PROGRAM_EXEC restore -S 2 -B 1 -d diff -o out
exit 0
diff --git a/tests/007-incorrect_sector_size.sh b/tests/007-incorrect_sector_size.sh
index a8dc956..5d8a689 100644
--- a/tests/007-incorrect_sector_size.sh
+++ b/tests/007-incorrect_sector_size.sh
@@ -4,12 +4,12 @@ source ./assert.sh
PROGRAM_EXEC="$1"
-assert "Usage" "incorrect buffer size" 1 $PROGRAM_EXEC backup -b abc123 in base out
-assert "Usage" "buffer size cannot be 0" 1 $PROGRAM_EXEC backup -b 0 in base out
-assert "Usage" "buffer size is not multiple of sector size" 1 $PROGRAM_EXEC backup -b 3 -s 2 in base out
+assert "Usage" "incorrect buffer size" 1 $PROGRAM_EXEC backup -B abc123 -i in -b base -o out
+assert "Usage" "buffer size cannot be 0" 1 $PROGRAM_EXEC backup -B 0 -i in -b base -o out
+assert "Usage" "buffer size is not multiple of sector size" 1 $PROGRAM_EXEC backup -B 3 -S 2 -i in -b base -o out
-assert "Usage" "incorrect buffer size" 1 $PROGRAM_EXEC restore -b abc123 diff out
-assert "Usage" "buffer size cannot be 0" 1 $PROGRAM_EXEC restore -b 0 diff out
-assert "Usage" "buffer size is not multiple of sector size" 1 $PROGRAM_EXEC restore -b 3 -s 2 diff out
+assert "Usage" "incorrect buffer size" 1 $PROGRAM_EXEC restore -B abc123 -d diff -o out
+assert "Usage" "buffer size cannot be 0" 1 $PROGRAM_EXEC restore -B 0 -d diff -o out
+assert "Usage" "buffer size is not multiple of sector size" 1 $PROGRAM_EXEC restore -B 3 -S 2 -d diff -o out
exit 0
diff --git a/tests/100-cannot_open_files.sh b/tests/100-cannot_open_files.sh
index 64d2a87..34cf3e0 100644
--- a/tests/100-cannot_open_files.sh
+++ b/tests/100-cannot_open_files.sh
@@ -6,18 +6,18 @@ PROGRAM_EXEC="$1"
rm -f input base out
touch base out
-assert "" "cannot get size of input file" 1 $PROGRAM_EXEC backup input base out
+assert "" "cannot get size of input file" 1 $PROGRAM_EXEC backup -i input -b base -o out
rm -f input base out
touch input out
-assert "" "cannot get size of base file" 1 $PROGRAM_EXEC backup input base out
+assert "" "cannot get size of base file" 1 $PROGRAM_EXEC backup -i input -b base -o out
rm -f input base out
rmdir outdir 2>/dev/null
touch input base
mkdir outdir
chmod -w outdir
-assert "" "cannot open output file" 1 $PROGRAM_EXEC backup input base outdir/out
+assert "" "cannot open output file" 1 $PROGRAM_EXEC backup -i input -b base -o outdir/out
rm -f input base out
rmdir outdir
diff --git a/tests/200-input_and_reference_size_differs.sh b/tests/200-input_and_reference_size_differs.sh
index ca0f368..dceb63b 100644
--- a/tests/200-input_and_reference_size_differs.sh
+++ b/tests/200-input_and_reference_size_differs.sh
@@ -8,7 +8,7 @@ rm -f input base
dd if=/dev/zero of=input bs=500 count=1 1>/dev/null 2>&1
dd if=/dev/zero of=base bs=501 count=1 1>/dev/null 2>&1
-assert "" "input file and base file differ in size" 1 $PROGRAM_EXEC backup input base out
+assert "" "input file and base file differ in size" 1 $PROGRAM_EXEC backup -i input -b base -o out
rm -f input base out
diff --git a/tests/201-input_or_reference_size_is_not_multiple_of_sector_size.sh b/tests/201-input_or_reference_size_is_not_multiple_of_sector_size.sh
index abfb3c5..d7c6aa6 100644
--- a/tests/201-input_or_reference_size_is_not_multiple_of_sector_size.sh
+++ b/tests/201-input_or_reference_size_is_not_multiple_of_sector_size.sh
@@ -9,7 +9,7 @@ dd if=/dev/zero of=input bs=513 count=1 1>/dev/null 2>&1
dd if=/dev/zero of=base bs=513 count=1 1>/dev/null 2>&1
assert "" "size of input file and base file is not multiple of [0-9]" \
- 1 $PROGRAM_EXEC backup -s 512 input base out
+ 1 $PROGRAM_EXEC backup -S 512 -i input -b base -o out
rm -f input base out
diff --git a/tests/300-incorrect_reference_file.sh b/tests/300-incorrect_reference_file.sh
index b15ee12..c250541 100644
--- a/tests/300-incorrect_reference_file.sh
+++ b/tests/300-incorrect_reference_file.sh
@@ -6,11 +6,11 @@ PROGRAM_EXEC="$1"
rm -f diff out
touch diff out
-assert "" "diff file is empty" 1 $PROGRAM_EXEC restore diff out
+assert "" "diff file is empty" 1 $PROGRAM_EXEC restore -d diff -o out
dd if=/dev/zero of=diff bs=513 count=1 1>/dev/null 2>&1
assert "" "diff file has size that cannot contain valid diff data" \
- 1 $PROGRAM_EXEC restore -s 512 diff out
+ 1 $PROGRAM_EXEC restore -S 512 -d diff -o out
rm -f diff out
dd if=/dev/zero of=out bs=512 count=2 1>/dev/null 2>&1
@@ -21,7 +21,7 @@ printf '\x02' | dd of=diff bs=1 count=1 seek=0 conv=notrunc 1>/dev/null 2>&1
# The second offset will be 1
printf '\x01' | dd of=diff bs=1 count=1 seek=520 conv=notrunc 1>/dev/null 2>&1
assert "" "a sector offset points behind the previous offset" \
- 1 $PROGRAM_EXEC restore -s 512 diff out
+ 1 $PROGRAM_EXEC restore -S 512 -d diff -o out
rm -f diff out
dd if=/dev/zero of=out bs=512 count=1 1>/dev/null 2>&1
@@ -30,7 +30,7 @@ dd if=/dev/zero of=diff bs=$(( 512 + 8 )) count=2 1>/dev/null 2>&1
# The first offset will be 1
printf '\x01' | dd of=diff bs=1 count=1 seek=0 conv=notrunc 1>/dev/null 2>&1
assert "" "a sector offset points past the end of the output file" \
- 1 $PROGRAM_EXEC restore -s 512 diff out
+ 1 $PROGRAM_EXEC restore -S 512 -d diff -o out
rm -f diff out
diff --git a/tests/400-successful_backup_restore.sh b/tests/400-successful_backup_restore.sh
index 8274964..fb44dda 100644
--- a/tests/400-successful_backup_restore.sh
+++ b/tests/400-successful_backup_restore.sh
@@ -29,7 +29,7 @@ printf '\xFF' | dd of=input bs=1 count=1 seek=$(( (512 * 3) - 1 )) conv=notrunc
# The fourth sector will have the middle byte changed
printf '\xFF' | dd of=input bs=1 count=1 seek=$(( (512 * 4) - (512 / 2) )) conv=notrunc 1>/dev/null 2>&1
-assert "" "" 0 $PROGRAM_EXEC backup -s 512 input base out
+assert "" "" 0 $PROGRAM_EXEC backup -S 512 -i input -b base -o out
if ! files_are_the_same out 400-expected_backup_output.bin; then
echo "assert: Backup output file differs from the expected one"
@@ -44,7 +44,7 @@ if ! files_are_the_same base input; then
exit 1
fi
-assert "" "" 0 $PROGRAM_EXEC restore -s 512 out input
+assert "" "" 0 $PROGRAM_EXEC restore -S 512 -d out -o input
if ! files_are_the_same input backedup_input; then
echo "assert: Cannot restore the backup"