diff --git a/HISTORY b/HISTORY index 5c960d4a..cc41de73 100644 --- a/HISTORY +++ b/HISTORY @@ -3,6 +3,8 @@ SnapRAID HISTORY 1.13 2012/? =========== + * Added a new -A option to make the 'check' command to only check file hashes + without checking the parity data. * The file modification time is now saved using nanosecond precision. This allows to restore the exact modification time in 'fix'. The new 'content' files written with this version are not backward compatible, diff --git a/Makefile.am b/Makefile.am index 1dea1069..b98c0c53 100644 --- a/Makefile.am +++ b/Makefile.am @@ -97,13 +97,16 @@ check-local: $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -v -c $(srcdir)/test-raid6.conf dup $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -v -c $(srcdir)/test-raid6.conf sync $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self -c $(srcdir)/test-raid6.conf check + $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self -c $(srcdir)/test-raid6.conf -A check echo --- Create some files, sync raid6 and check $(TESTENV) ./mktest$(EXEEXT) generate 1 3 $(CHECKCOUNT) $(CHECKSIZE) $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self -v -c $(srcdir)/test-raid6.conf diff $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self -v -c $(srcdir)/test-raid6.conf dup $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self -v -c $(srcdir)/test-raid6.conf sync $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self -c $(srcdir)/test-raid5.conf check + $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self -c $(srcdir)/test-raid5.conf -A check $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self -c $(srcdir)/test-raid6.conf check + $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self -c $(srcdir)/test-raid6.conf -A check echo --- Create some more files, sync raid5 and check $(TESTENV) ./mktest$(EXEEXT) generate 2 3 $(CHECKCOUNT) $(CHECKSIZE) $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self -v -c $(srcdir)/test-raid5.conf diff @@ -293,18 +296,21 @@ check-local: echo --- Corrupt the parity, fix and check with raid5 $(TESTENV) ./mktest$(EXEEXT) damage 1 100 10000 test/parity $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self --test-expect-recoverable -c $(srcdir)/test-raid5.conf check 2>> test.log + $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self -c $(srcdir)/test-raid5.conf -A check $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self -c $(srcdir)/test-raid5.conf fix 2>> test.log $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self -c $(srcdir)/test-raid6.conf check echo --- Corrupt the parity and the q-parity, fix and check with raid6 $(TESTENV) ./mktest$(EXEEXT) damage 2 100 10000 test/parity $(TESTENV) ./mktest$(EXEEXT) damage 2 100 10000 test/q-parity $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self --test-expect-recoverable -c $(srcdir)/test-raid6.conf check 2>> test.log + $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self -c $(srcdir)/test-raid6.conf -A check $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self -c $(srcdir)/test-raid6.conf fix 2>> test.log $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self -c $(srcdir)/test-raid6.conf check echo --- Corrupt some files, fix and check with raid5 $(TESTENV) ./mktest$(EXEEXT) damage 3 1 500 test/disk2/b* $(TESTENV) ./mktest$(EXEEXT) append 3 500 test/disk2/c* $(TESTENV) ./mktest$(EXEEXT) truncate 3 500 test/disk2/d* + $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self --test-expect-recoverable -c $(srcdir)/test-raid5.conf -A check 2>> test.log $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self --test-expect-recoverable -c $(srcdir)/test-raid5.conf check 2>> test.log $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self -c $(srcdir)/test-raid5.conf fix 2>> test.log $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self -c $(srcdir)/test-raid6.conf check @@ -317,6 +323,8 @@ check-local: $(TESTENV) ./mktest$(EXEEXT) append 4 500 test/disk3/_b/_a/* $(TESTENV) ./mktest$(EXEEXT) truncate 4 500 test/disk2/_b/_b/* $(TESTENV) ./mktest$(EXEEXT) truncate 4 500 test/disk3/_b/_b/* + $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self --test-expect-recoverable -c $(srcdir)/test-raid5.conf -A check 2>> test.log + $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self --test-expect-recoverable -c $(srcdir)/test-raid6.conf -A check 2>> test.log $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self --test-expect-unrecoverable -c $(srcdir)/test-raid5.conf check 2>> test.log $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self --test-expect-recoverable -c $(srcdir)/test-raid6.conf check 2>> test.log $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self -c $(srcdir)/test-raid6.conf fix 2>> test.log diff --git a/TODO b/TODO index e26d8ef9..db42452f 100644 --- a/TODO +++ b/TODO @@ -5,13 +5,8 @@ This is the list of TODO items for SnapRAID. - v1.13 -* In error growing, print the last file in the bigger data disk. - * Allow to filter the files to check/fix based on the drive where they reside. -* When checking, allow to disable the parity check, thus allowing to read only -the filtered data to check, and not the one needed to compute the parity. - * In fix an existing symlink with the same name of a file to be recovered may stop the process making the create() operation to fail. diff --git a/check.c b/check.c index 0867b679..6a5f209c 100644 --- a/check.c +++ b/check.c @@ -367,7 +367,7 @@ static int repair(struct snapraid_state* state, unsigned pos, unsigned diskmax, return -1; } -static int state_check_process(struct snapraid_state* state, int fix, struct snapraid_parity* parity, struct snapraid_parity* qarity, block_off_t blockstart, block_off_t blockmax) +static int state_check_process(struct snapraid_state* state, int check, int fix, struct snapraid_parity* parity, struct snapraid_parity* qarity, block_off_t blockstart, block_off_t blockmax) { struct snapraid_handle* handle; unsigned diskmax; @@ -439,9 +439,6 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna unsigned failed_count; int one_tocheck; int check_parity; - unsigned char* buffer_parity; - unsigned char* buffer_qarity; - unsigned char* buffer_zero; /* for each disk */ one_tocheck = 0; @@ -462,8 +459,13 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna if (!one_tocheck) continue; - check_parity = 1; /* if we have to check the parity */ - failed_count = 0; /* number of failed blocks */ + /* If we have to check the parity data read from disk. */ + /* Note that if check==0, we'll anyway skip the full parity check, */ + /* because we also don't read it at all */ + check_parity = 1; + + /* keep track of the number of failed blocks */ + failed_count = 0; /* for each disk, process the block */ for(j=0;jblock_size); + continue; + } + /* get the state of the block */ block_state = block_state_get(block); @@ -555,7 +566,7 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna ++recovered_error; } } else { - /* if checking, open the file for reading */ + /* if checking or hashing, open the file for reading */ ret = handle_open(&handle[j], block_file_get(block)); if (ret == -1) { /* save the failed block for the check/fix */ @@ -585,6 +596,7 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna } } + /* read from the file */ read_size = handle_read(&handle[j], block, buffer[j], state->block_size); if (read_size == -1) { /* save the failed block for the check/fix */ @@ -618,7 +630,7 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna /* if the block has the hash */ if (block_state == BLOCK_STATE_BLK || block_state == BLOCK_STATE_INV) { - /* now compute the hash */ + /* compute the hash of the block just read */ memhash(state->hash, hash, buffer[j], read_size); /* compare the hash */ @@ -638,184 +650,192 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna } } - /* buffers for parity read and not computed */ - if (state->level == 1) { - buffer_parity = buffer[diskmax + 1]; - buffer_qarity = 0; - } else { - buffer_parity = buffer[diskmax + 2]; - buffer_qarity = buffer[diskmax + 3]; - } - buffer_zero = buffer[buffermax-1]; + /* now read and check the parity if requested */ + if (check) { + unsigned char* buffer_parity; + unsigned char* buffer_qarity; + unsigned char* buffer_zero; - /* read the parity */ - if (parity) { - ret = parity_read(parity, i, buffer_parity, state->block_size); - if (ret == -1) { - buffer_parity = 0; /* no parity to use */ - - fprintf(stderr, "error:%u:parity: Read error\n", i); - ++error; + /* buffers for parity read and not computed */ + if (state->level == 1) { + buffer_parity = buffer[diskmax + 1]; + buffer_qarity = 0; + } else { + buffer_parity = buffer[diskmax + 2]; + buffer_qarity = buffer[diskmax + 3]; } - } else { - buffer_parity = 0; - } + buffer_zero = buffer[buffermax-1]; - /* read the qarity */ - if (state->level >= 2) { - if (qarity) { - ret = parity_read(qarity, i, buffer_qarity, state->block_size); + /* read the parity */ + if (parity) { + ret = parity_read(parity, i, buffer_parity, state->block_size); if (ret == -1) { - buffer_qarity = 0; /* no qarity to use */ + buffer_parity = 0; /* no parity to use */ - fprintf(stderr, "error:%u:qarity: Read error\n", i); + fprintf(stderr, "error:%u:parity: Read error\n", i); ++error; } } else { - buffer_qarity = 0; - } - } - - ret = repair(state, i, diskmax, failed, failed_count, buffer, buffer_parity, buffer_qarity, buffer_zero); - if (ret != 0) { - /* increment the number of errors */ - if (ret > 0) - error += ret; - ++unrecoverable_error; - - /* print a list of all the errors in files */ - for(j=0;jdisk->name, block_file_get(failed[j].block)->sub, block_file_pos(failed[j].block)); + buffer_parity = 0; } - if (fix) { - /* keep track of damaged files */ - for(j=0;jlevel >= 2) { + if (qarity) { + ret = parity_read(qarity, i, buffer_qarity, state->block_size); + if (ret == -1) { + buffer_qarity = 0; /* no qarity to use */ - /* print a list of all the errors in files */ - for(j=0;jdisk->name, block_file_get(failed[j].block)->sub, block_file_pos(failed[j].block)); - } - } - if (partial_recover_error != 0) { - error += partial_recover_error; - ++unrecoverable_error; - } - - /* check parity and q-parity only if all the blocks have it computed */ - /* if you check/fix after a partial sync, it's OK to have parity errors on the blocks with invalid parity */ - if (check_parity) { - /* check the parity */ - if (buffer_parity != 0 && memcmp(buffer_parity, buffer[diskmax], state->block_size) != 0) { - buffer_parity = 0; - - fprintf(stderr, "error:%u:parity: Data error\n", i); - ++error; - } - - /* check the qarity */ - if (state->level >= 2) { - if (buffer_qarity != 0 && memcmp(buffer_qarity, buffer[diskmax + 1], state->block_size) != 0) { - buffer_qarity = 0; - - fprintf(stderr, "error:%u:qarity: Data error\n", i); + fprintf(stderr, "error:%u:qarity: Read error\n", i); ++error; } + } else { + buffer_qarity = 0; } } - if (fix) { - /* update the fixed files */ + ret = repair(state, i, diskmax, failed, failed_count, buffer, buffer_parity, buffer_qarity, buffer_zero); + if (ret != 0) { + /* increment the number of errors */ + if (ret > 0) + error += ret; + ++unrecoverable_error; + + /* print a list of all the errors in files */ for(j=0;jblock_size); - if (ret == -1) { - /* mark the file as damaged */ - file_flag_set(block_file_get(failed[j].block), FILE_IS_DAMAGED); - - if (errno == EACCES) { - fprintf(stderr, "WARNING! Please give write permission to the file.\n"); - } else { - /* we do not use DANGER because it could be ENOSPC which is not always correctly reported */ - fprintf(stderr, "WARNING! Without a working data disk, it isn't possible to fix errors on it.\n"); - } - printf("Stopping at block %u\n", i); - ++unrecoverable_error; - goto bail; - } - - /* if we are not sure that the recovered content is uptodate */ - if (failed[j].is_outofdate) { - /* mark the file as damaged */ - file_flag_set(block_file_get(failed[j].block), FILE_IS_DAMAGED); - continue; - } - - /* mark the file as fixed */ - file_flag_set(block_file_get(failed[j].block), FILE_IS_FIXED); - - fprintf(stderr, "fixed:%u:%s:%s: Fixed data error at position %u\n", i, failed[j].handle->disk->name, block_file_get(failed[j].block)->sub, block_file_pos(failed[j].block)); - ++recovered_error; + if (failed[j].is_bad) + fprintf(stderr, "unrecoverable:%u:%s:%s: Unrecoverable error at position %u\n", i, failed[j].handle->disk->name, block_file_get(failed[j].block)->sub, block_file_pos(failed[j].block)); } - /* update parity and q-parity only if all the blocks have it computed */ - /* if you check/fix after a partial sync, you do not want to fix parity */ - /* for blocks that are going to have it computed in the sync completion */ + if (fix) { + /* keep track of damaged files */ + for(j=0;jdisk->name, block_file_get(failed[j].block)->sub, block_file_pos(failed[j].block)); + } + } + if (partial_recover_error != 0) { + error += partial_recover_error; + ++unrecoverable_error; + } + + /* check parity and q-parity only if all the blocks have it computed */ + /* if you check/fix after a partial sync, it's OK to have parity errors on the blocks with invalid parity */ if (check_parity) { - /* update the parity */ - if (buffer_parity == 0 && parity) { - ret = parity_write(parity, i, buffer[diskmax], state->block_size); + /* check the parity */ + if (buffer_parity != 0 && memcmp(buffer_parity, buffer[diskmax], state->block_size) != 0) { + buffer_parity = 0; + + fprintf(stderr, "error:%u:parity: Data error\n", i); + ++error; + } + + /* check the qarity */ + if (state->level >= 2) { + if (buffer_qarity != 0 && memcmp(buffer_qarity, buffer[diskmax + 1], state->block_size) != 0) { + buffer_qarity = 0; + + fprintf(stderr, "error:%u:qarity: Data error\n", i); + ++error; + } + } + } + + if (fix) { + /* update the fixed files */ + for(j=0;jblock_size); if (ret == -1) { - /* we do not use DANGER because it could be ENOSPC which is not always correctly reported */ - fprintf(stderr, "WARNING! Without a working Parity disk, it isn't possible to fix errors on it.\n"); + /* mark the file as damaged */ + file_flag_set(block_file_get(failed[j].block), FILE_IS_DAMAGED); + + if (errno == EACCES) { + fprintf(stderr, "WARNING! Please give write permission to the file.\n"); + } else { + /* we do not use DANGER because it could be ENOSPC which is not always correctly reported */ + fprintf(stderr, "WARNING! Without a working data disk, it isn't possible to fix errors on it.\n"); + } printf("Stopping at block %u\n", i); ++unrecoverable_error; goto bail; } - fprintf(stderr, "fixed:%u:parity: Fixed data error\n", i); + /* if we are not sure that the recovered content is uptodate */ + if (failed[j].is_outofdate) { + /* mark the file as damaged */ + file_flag_set(block_file_get(failed[j].block), FILE_IS_DAMAGED); + continue; + } + + /* mark the file as fixed */ + file_flag_set(block_file_get(failed[j].block), FILE_IS_FIXED); + + fprintf(stderr, "fixed:%u:%s:%s: Fixed data error at position %u\n", i, failed[j].handle->disk->name, block_file_get(failed[j].block)->sub, block_file_pos(failed[j].block)); ++recovered_error; } - /* update the qarity */ - if (state->level >= 2) { - if (buffer_qarity == 0 && qarity) { - ret = parity_write(qarity, i, buffer[diskmax + 1], state->block_size); + /* update parity and q-parity only if all the blocks have it computed */ + /* if you check/fix after a partial sync, you do not want to fix parity */ + /* for blocks that are going to have it computed in the sync completion */ + if (check_parity) { + /* update the parity */ + if (buffer_parity == 0 && parity) { + ret = parity_write(parity, i, buffer[diskmax], state->block_size); if (ret == -1) { /* we do not use DANGER because it could be ENOSPC which is not always correctly reported */ - fprintf(stderr, "WARNING! Without a working Q-Parity disk, it isn't possible to fix errors on it.\n"); + fprintf(stderr, "WARNING! Without a working Parity disk, it isn't possible to fix errors on it.\n"); printf("Stopping at block %u\n", i); ++unrecoverable_error; goto bail; } - fprintf(stderr, "fixed:%u:qarity: Fixed data error\n", i); + fprintf(stderr, "fixed:%u:parity: Fixed data error\n", i); ++recovered_error; } + + /* update the qarity */ + if (state->level >= 2) { + if (buffer_qarity == 0 && qarity) { + ret = parity_write(qarity, i, buffer[diskmax + 1], state->block_size); + if (ret == -1) { + /* we do not use DANGER because it could be ENOSPC which is not always correctly reported */ + fprintf(stderr, "WARNING! Without a working Q-Parity disk, it isn't possible to fix errors on it.\n"); + printf("Stopping at block %u\n", i); + ++unrecoverable_error; + goto bail; + } + + fprintf(stderr, "fixed:%u:qarity: Fixed data error\n", i); + ++recovered_error; + } + } } } } } + /* now fix if requested */ if (fix) { /* for all the files of this block check if we need to fix the modification time */ for(j=0;jblock_size; @@ -1206,7 +1234,7 @@ void state_check(struct snapraid_state* state, int fix, block_off_t blockstart, } else { qarity_ptr = 0; } - } else { + } else if (check) { /* if checking, open the file for reading */ /* it may fail if the file doesn't exist, in this case we continue to check the files */ parity_ptr = &parity; @@ -1228,18 +1256,24 @@ void state_check(struct snapraid_state* state, int fix, block_off_t blockstart, } else { qarity_ptr = 0; } + } else { + /* otherwise don't use any parity */ + parity_ptr = 0; + qarity_ptr = 0; } if (fix) printf("Fixing...\n"); - else + else if (check) printf("Checking...\n"); + else + printf("Hashing...\n"); error = 0; /* skip degenerated cases of empty parity, or skipping all */ if (blockstart < blockmax) { - ret = state_check_process(state, fix, parity_ptr, qarity_ptr, blockstart, blockmax); + ret = state_check_process(state, check, fix, parity_ptr, qarity_ptr, blockstart, blockmax); if (ret == -1) { ++error; /* continue, as we are already exiting */ diff --git a/snapraid.1 b/snapraid.1 index 1f9157b5..be0908cd 100644 --- a/snapraid.1 +++ b/snapraid.1 @@ -9,6 +9,10 @@ snapraid [\(hyc, \(hy\(hyconf CONFIG] [\(hyf, \(hy\(hyfilter PATTERN] [\(hyH, \( [\(hyN, \(hy\(hyfind\(hyby\(hyname] .PD 0 .PP +.PD + [\(hyA, \(hy\(hyaudit\(hyonly] +.PD 0 +.PP .PD [\(hyZ, \(hy\(hyforce\(hyzero] [\(hyE, \(hy\(hyforce\(hyempty] .PD 0 @@ -328,6 +332,8 @@ Nothing is modified. Checks all the files and the redundancy data. All the files are hashed and compared with the snapshot saved in the previous \(a"sync\(a" command. +If you use the \(hyA, \(hy\(hyaudit\(hyonly option, only the file +data is checked, and the redundandy data is ignored. .PP Files are identified by path, and checked by content. Nothing is modified. @@ -355,7 +361,8 @@ the current directory in Windows. .TP .B \(hyf, \(hy\(hyfilter PATTERN Filters the files to operate on with the \(a"check\(a" and \(a"fix\(a" -commands. This option is ignored with the \(a"sync\(a" command. +commands. +This option cannot be used with the \(a"sync\(a" command. See the PATTERN section for more details in the pattern specifications. This option can be used many times. @@ -366,6 +373,11 @@ Filters out hidden files and directory. In Unix hidden files are the ones starting with \(cq.\(cq. In Windows they are the ones with the hidden attribute. .TP +.B \(hyA, \(hy\(hyaudit\(hyonly +When checking, only verify the hash of the files, without +doing any kind of check on the redundancy data. +This option can be used only with the \(a"check\(a" command. +.TP .B \(hyN, \(hy\(hyfind\(hyby\(hyname When syncing finds the files by path instead than by inode. This option allows a fast sync command after having replaced diff --git a/snapraid.c b/snapraid.c index 30a60927..5851634a 100644 --- a/snapraid.c +++ b/snapraid.c @@ -83,6 +83,7 @@ struct option long_options[] = { { "force-zero", 0, 0, 'Z' }, { "force-empty", 0, 0, 'E' }, { "find-by-name", 0, 0, 'N' }, + { "audit-only", 0, 0, 'A' }, { "speed-test", 0, 0, 'T' }, { "verbose", 0, 0, 'v' }, { "gui", 0, 0, 'G' }, /* undocumented GUI interface command */ @@ -98,7 +99,7 @@ struct option long_options[] = { }; #endif -#define OPTIONS "c:f:Hs:t:ZENTvhVG" +#define OPTIONS "c:f:Hs:t:ZENATvhVG" volatile int global_interrupt = 0; @@ -127,6 +128,7 @@ int main(int argc, char* argv[]) int force_empty; int filter_hidden; int find_by_name; + int audit_only; int test_expect_unrecoverable; int test_expect_recoverable; int test_kill_after_sync; @@ -151,6 +153,7 @@ int main(int argc, char* argv[]) force_empty = 0; filter_hidden = 0; find_by_name = 0; + audit_only = 0; test_expect_unrecoverable = 0; test_expect_recoverable = 0; test_kill_after_sync = 0; @@ -206,6 +209,9 @@ int main(int argc, char* argv[]) case 'N' : find_by_name = 1; break; + case 'A' : + audit_only = 1; + break; case 'v' : verbose = 1; break; @@ -349,7 +355,10 @@ int main(int argc, char* argv[]) /* intercept Ctrl+C */ signal(SIGINT, &signal_handler); - state_check(&state, operation == OPERATION_FIX, blockstart, blockcount); + if (operation == OPERATION_CHECK) + state_check(&state, !audit_only, 0, blockstart, blockcount); + else /* it's fix */ + state_check(&state, 1, 1, blockstart, blockcount); } state_done(&state); diff --git a/snapraid.d b/snapraid.d index 2e227b86..ec6ee876 100644 --- a/snapraid.d +++ b/snapraid.d @@ -4,6 +4,7 @@ Name{number} Synopsis :snapraid [-c, --conf CONFIG] [-f, --filter PATTERN] [-H, --filter-nohidden] : [-N, --find-by-name] + : [-A, --audit-only] : [-Z, --force-zero] [-E, --force-empty] : [-s, --start BLKSTART] [-t, --count BLKCOUNT] : [-v, --verbose] @@ -206,6 +207,8 @@ Commands Checks all the files and the redundancy data. All the files are hashed and compared with the snapshot saved in the previous "sync" command. + If you use the -A, --audit-only option, only the file + data is checked, and the redundandy data is ignored. Files are identified by path, and checked by content. Nothing is modified. @@ -235,7 +238,8 @@ Options -f, --filter PATTERN Filters the files to operate on with the "check" and "fix" - commands. This option is ignored with the "sync" command. + commands. + This option cannot be used with the "sync" command. See the PATTERN section for more details in the pattern specifications. This option can be used many times. @@ -246,6 +250,11 @@ Options the ones starting with '.'. In Windows they are the ones with the hidden attribute. + -A, --audit-only + When checking, only verify the hash of the files, without + doing any kind of check on the redundancy data. + This option can be used only with the "check" command. + -N, --find-by-name When syncing finds the files by path instead than by inode. This option allows a fast sync command after having replaced diff --git a/snapraid.txt b/snapraid.txt index 73c39159..48b0e47a 100644 --- a/snapraid.txt +++ b/snapraid.txt @@ -8,6 +8,7 @@ snapraid [-c, --conf CONFIG] [-f, --filter PATTERN] [-H, --filter-nohidden] [-N, --find-by-name] + [-A, --audit-only] [-Z, --force-zero] [-E, --force-empty] [-s, --start BLKSTART] [-t, --count BLKCOUNT] [-v, --verbose] @@ -230,6 +231,8 @@ Nothing is modified. Checks all the files and the redundancy data. All the files are hashed and compared with the snapshot saved in the previous "sync" command. +If you use the -A, --audit-only option, only the file +data is checked, and the redundandy data is ignored. Files are identified by path, and checked by content. Nothing is modified. @@ -264,7 +267,8 @@ SnapRAID provides the following options: -f, --filter PATTERN Filters the files to operate on with the "check" and "fix" - commands. This option is ignored with the "sync" command. + commands. + This option cannot be used with the "sync" command. See the PATTERN section for more details in the pattern specifications. This option can be used many times. @@ -275,6 +279,11 @@ SnapRAID provides the following options: the ones starting with '.'. In Windows they are the ones with the hidden attribute. + -A, --audit-only + When checking, only verify the hash of the files, without + doing any kind of check on the redundancy data. + This option can be used only with the "check" command. + -N, --find-by-name When syncing finds the files by path instead than by inode. This option allows a fast sync command after having replaced diff --git a/state.h b/state.h index 946be1fe..42700b06 100644 --- a/state.h +++ b/state.h @@ -93,9 +93,11 @@ void state_scan(struct snapraid_state* state, int output); int state_sync(struct snapraid_state* state, block_off_t blockstart, block_off_t blockcount); /** - * Checks (and fixes) all the files and the parity data. + * Checks (and fixes) all the files and parity data. + * \param check If we have to check also the parity. + * \param check If we have to fix, after checking. It requires also check==1. */ -void state_check(struct snapraid_state* state, int fix, block_off_t blockstart, block_off_t blockcount); +void state_check(struct snapraid_state* state, int check, int fix, block_off_t blockstart, block_off_t blockcount); /** * Dry the files. @@ -109,6 +111,7 @@ void state_dup(struct snapraid_state* state); /** * Filter files. + * Apply and additional filter to list of file currently loaded. */ void state_filter(struct snapraid_state* state, tommy_list* filterlist);