diff --git a/HISTORY b/HISTORY index 6cc1aa70..0a6a2c74 100644 --- a/HISTORY +++ b/HISTORY @@ -12,7 +12,7 @@ SnapRAID HISTORY * Added support also for hardlinks and empty directories. * Added support to save symlinks to files in Windows. Note that only the symlink is saved and not the linked file. - Symlinks to dirs and junctions are still not supported. + Symlinks to dirs and junctions are still not supported in Windows. * Files without read permission generates now an error instead of a warning. You now must explicitely exclude them in the configuration file with exclusion rules. diff --git a/check.c b/check.c index 9811773b..3a820085 100644 --- a/check.c +++ b/check.c @@ -1405,7 +1405,7 @@ void state_check(struct snapraid_state* state, int check, int fix, block_off_t b exit(EXIT_FAILURE); } - ret = parity_chsize(parity_ptr, size, &out_size); + ret = parity_chsize(parity_ptr, size, &out_size, state->skip_fallocate); if (ret == -1) { fprintf(stderr, "WARNING! Without an accessible Parity file, it isn't possible to sync.\n"); exit(EXIT_FAILURE); @@ -1419,7 +1419,7 @@ void state_check(struct snapraid_state* state, int check, int fix, block_off_t b exit(EXIT_FAILURE); } - ret = parity_chsize(qarity_ptr, size, &out_size); + ret = parity_chsize(qarity_ptr, size, &out_size, state->skip_fallocate); if (ret == -1) { fprintf(stderr, "WARNING! Without an accessible Q-Parity file, it isn't possible to sync.\n"); exit(EXIT_FAILURE); diff --git a/parity.c b/parity.c index a1f448c2..a5b0ca6a 100644 --- a/parity.c +++ b/parity.c @@ -133,7 +133,7 @@ bail: return -1; } -int parity_chsize(struct snapraid_parity* parity, data_off_t size, data_off_t* out_size) +int parity_chsize(struct snapraid_parity* parity, data_off_t size, data_off_t* out_size, int skip_fallocate) { int ret; @@ -143,18 +143,23 @@ int parity_chsize(struct snapraid_parity* parity, data_off_t size, data_off_t* o const char* call; #if HAVE_FALLOCATE - /* allocate real space using the specific Linux fallocate() operation. */ - /* If the underline filesystem doesn't support it, this operation fails, */ - /* instead posix_fallocate() fallbacks to write the whole file. */ - call = "fallocate"; - ret = fallocate(parity->f, 0, 0, size); + if (!skip_fallocate) { + /* allocate real space using the specific Linux fallocate() operation. */ + /* If the underline filesystem doesn't support it, this operation fails, */ + /* instead posix_fallocate() fallbacks to write the whole file. */ + call = "fallocate"; + ret = fallocate(parity->f, 0, 0, size); - /* fallocate() returns the error number as positive integer, */ - /* and in this case it doesn't set errno, just like posix_fallocate() */ - /* Checking the glibc code (2.11.1 and 2.14.1) it seems that ENOSYS */ - /* may be returned in errno, so we support both the return way */ - if (ret > 0) { /* if a positive error is returned, convert it to errno */ - errno = ret; + /* fallocate() returns the error number as positive integer, */ + /* and in this case it doesn't set errno, just like posix_fallocate() */ + /* Checking the glibc code (2.11.1 and 2.14.1) it seems that ENOSYS */ + /* may be returned in errno, so we support both the return way */ + if (ret > 0) { /* if a positive error is returned, convert it to errno */ + errno = ret; + ret = -1; + } + } else { + errno = EOPNOTSUPP; ret = -1; } diff --git a/parity.h b/parity.h index a1c498bd..789881c3 100644 --- a/parity.h +++ b/parity.h @@ -48,7 +48,7 @@ int parity_create(struct snapraid_parity* parity, const char* path, data_off_t* * Changes the parity size. * \param out_size Return the size of the parity file. The out_size is set also on error to reflect a partial resize. */ -int parity_chsize(struct snapraid_parity* parity, data_off_t size, data_off_t* out_size); +int parity_chsize(struct snapraid_parity* parity, data_off_t size, data_off_t* out_size, int skip_fallocate); /** * Opens an already existing parity file. diff --git a/snapraid.c b/snapraid.c index 221bc841..4dfd2933 100644 --- a/snapraid.c +++ b/snapraid.c @@ -77,7 +77,10 @@ void usage(void) #define OPT_TEST_KILL_AFTER_SYNC 257 #define OPT_TEST_EXPECT_UNRECOVERABLE 258 #define OPT_TEST_EXPECT_RECOVERABLE 259 -#define OPT_TEST_SKIP_DEVICE 260 +#define OPT_TEST_SKIP_SIGN 260 +#define OPT_TEST_SKIP_FALLOCATE 261 +#define OPT_TEST_SKIP_DEVICE 262 + #if HAVE_GETOPT_LONG struct option long_options[] = { @@ -98,11 +101,28 @@ struct option long_options[] = { { "gui", 0, 0, 'G' }, /* undocumented GUI interface command */ { "help", 0, 0, 'h' }, { "version", 0, 0, 'V' }, - /* test specific options, DO NOT USE! */ + + /* The following are test specific options, DO NOT USE! */ + + /* After syncing, do not write the new content file */ { "test-kill-after-sync", 0, 0, OPT_TEST_KILL_AFTER_SYNC }, + + /* Exit with failure if after check/fix there ARE NOT unrecoverable errors. */ { "test-expect-unrecoverable", 0, 0, OPT_TEST_EXPECT_UNRECOVERABLE }, + + /* Exit with failure if after check/fix there ARE NOT recoverable errors. */ { "test-expect-recoverable", 0, 0, OPT_TEST_EXPECT_RECOVERABLE }, + + /* Skip the initial self test */ { "test-skip-self", 0, 0, OPT_TEST_SKIP_SELF }, + + /* Skip the initial sign check when reading the content file */ + { "test-skip-sign", 0, 0, OPT_TEST_SKIP_SIGN }, + + /* Skip the fallocate() when growing the parity files */ + { "test-skip-fallocate", 0, 0, OPT_TEST_SKIP_FALLOCATE }, + + /* Skip the device check */ { "test-skip-device", 0, 0, OPT_TEST_SKIP_DEVICE }, { 0, 0, 0, 0 } }; @@ -138,10 +158,12 @@ int main(int argc, char* argv[]) int force_empty; int find_by_name; int audit_only; + int test_kill_after_sync; int test_expect_unrecoverable; int test_expect_recoverable; - int test_kill_after_sync; int test_skip_self; + int test_skip_sign; + int test_skip_fallocate; int test_skip_device; const char* conf; struct snapraid_state state; @@ -166,10 +188,12 @@ int main(int argc, char* argv[]) force_empty = 0; find_by_name = 0; audit_only = 0; + test_kill_after_sync = 0; test_expect_unrecoverable = 0; test_expect_recoverable = 0; - test_kill_after_sync = 0; test_skip_self = 0; + test_skip_sign = 0; + test_skip_fallocate = 0; test_skip_device = 0; blockstart = 0; blockcount = 0; @@ -269,6 +293,12 @@ int main(int argc, char* argv[]) case OPT_TEST_SKIP_SELF : test_skip_self = 1; break; + case OPT_TEST_SKIP_SIGN : + test_skip_sign = 1; + break; + case OPT_TEST_SKIP_FALLOCATE : + test_skip_fallocate = 1; + break; case OPT_TEST_SKIP_DEVICE : test_skip_device = 1; break; @@ -348,7 +378,7 @@ int main(int argc, char* argv[]) state_init(&state); - state_config(&state, conf, verbose, gui, force_zero, force_empty, find_by_name, test_expect_unrecoverable, test_expect_recoverable, test_skip_device); + state_config(&state, conf, verbose, gui, force_zero, force_empty, find_by_name, test_expect_unrecoverable, test_expect_recoverable, test_skip_sign, test_skip_fallocate, test_skip_device); if (import != 0) { printf("%s\n", import); diff --git a/state.c b/state.c index 2354b581..bd5d8bce 100644 --- a/state.c +++ b/state.c @@ -33,6 +33,8 @@ void state_init(struct snapraid_state* state) state->autosave = 0; state->expect_unrecoverable = 0; state->expect_recoverable = 0; + state->skip_sign = 0; + state->skip_fallocate = 0; state->need_write = 0; state->block_size = 256 * 1024; /* default 256 KiB */ state->parity[0] = 0; @@ -218,7 +220,7 @@ static void state_config_check(struct snapraid_state* state, const char* path, i } -void state_config(struct snapraid_state* state, const char* path, int verbose, int gui, int force_zero, int force_empty, int find_by_name, int expect_unrecoverable, int expect_recoverable, int skip_device) +void state_config(struct snapraid_state* state, const char* path, int verbose, int gui, int force_zero, int force_empty, int find_by_name, int expect_unrecoverable, int expect_recoverable, int skip_sign, int skip_fallocate, int skip_device) { STREAM* f; unsigned line; @@ -231,6 +233,8 @@ void state_config(struct snapraid_state* state, const char* path, int verbose, i state->find_by_name = find_by_name; state->expect_unrecoverable = expect_unrecoverable; state->expect_recoverable = expect_recoverable; + state->skip_sign = skip_sign; + state->skip_fallocate = skip_fallocate; if (state->gui) { fprintf(stderr, "version:%s\n", PACKAGE_VERSION); @@ -1390,8 +1394,10 @@ void state_read(struct snapraid_state* state) if (sign != hash) { fprintf(stderr, "Mismatching 'sign' in '%s' at line %u\n", path, line); - fprintf(stderr, "Likely this content file is damaged. Use an alternate copy\n"); - exit(EXIT_FAILURE); + if (!state->skip_sign) { + fprintf(stderr, "Likely this content file is damaged. Use an alternate copy\n"); + exit(EXIT_FAILURE); + } } } else if (tag[0] == 0) { /* allow empty lines */ diff --git a/state.h b/state.h index 18d5cea8..48b995e9 100644 --- a/state.h +++ b/state.h @@ -36,6 +36,8 @@ struct snapraid_state { uint64_t autosave; /**< Autosave after the specified amount of data. 0 to disable. */ int expect_unrecoverable; /**< Expect presence of unrecoverable error in checking or fixing. */ int expect_recoverable; /**< Expect presence of recoverable error in checking. */ + int skip_sign; /**< Skip the sign check for content files. */ + int skip_fallocate; /**< Skip the use of fallocate(). */ int need_write; /**< If the state is changed. */ uint32_t block_size; /**< Block size in bytes. */ char parity[PATH_MAX]; /**< Path of the parity file. */ @@ -72,7 +74,7 @@ void state_done(struct snapraid_state* state); /** * Reads the configuration file. */ -void state_config(struct snapraid_state* state, const char* path, int verbose, int gui, int force_zero, int force_empty, int find_by_name, int expect_unrecoverable, int expect_recoverable, int skip_device); +void state_config(struct snapraid_state* state, const char* path, int verbose, int gui, int force_zero, int force_empty, int find_by_name, int expect_unrecoverable, int expect_recoverable, int skip_sign, int skip_fallocate, int skip_device); /** * Reads the state. diff --git a/sync.c b/sync.c index 3ad00051..f2f0ba3b 100644 --- a/sync.c +++ b/sync.c @@ -422,7 +422,7 @@ int state_sync(struct snapraid_state* state, block_off_t blockstart, block_off_t exit(EXIT_FAILURE); } - ret = parity_chsize(parity_ptr, size, &out_size); + ret = parity_chsize(parity_ptr, size, &out_size, state->skip_fallocate); if (ret == -1) { parity_overflow(state, out_size); fprintf(stderr, "WARNING! Without an accessible Parity file, it isn't possible to sync.\n"); @@ -443,7 +443,7 @@ int state_sync(struct snapraid_state* state, block_off_t blockstart, block_off_t exit(EXIT_FAILURE); } - ret = parity_chsize(qarity_ptr, size, &out_size); + ret = parity_chsize(qarity_ptr, size, &out_size, state->skip_fallocate); if (ret == -1) { parity_overflow(state, out_size); fprintf(stderr, "WARNING! Without an accessible Q-Parity file, it isn't possible to sync.\n");