Adds and new -A option to only check hashes.

This commit is contained in:
Andrea Mazzoleni 2012-10-07 23:18:10 +02:00
parent 06637e9264
commit 1078bd4500
9 changed files with 242 additions and 161 deletions

View file

@ -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,

View file

@ -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

5
TODO
View file

@ -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.

332
check.c
View file

@ -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;j<diskmax;++j) {
@ -509,6 +511,15 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna
continue;
}
/* if we are only hashing, we can skip excluded files and don't event read them */
if (!check && file_flag_has(block_file_get(block), FILE_IS_EXCLUDED)) {
/* use an empty block */
/* in true, this is unnecessary, becase we are not checking any parity */
/* but we keep it for completeness */
memset(buffer[j], 0, state->block_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;j<failed_count;++j) {
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));
buffer_parity = 0;
}
if (fix) {
/* keep track of damaged files */
for(j=0;j<failed_count;++j) {
if (failed[j].is_bad)
file_flag_set(block_file_get(failed[j].block), FILE_IS_DAMAGED);
}
}
} else {
/* check if the recover was only partial */
/* note that this could happen only when we have an incomplete 'sync' */
/* and that we have recovered is the state before the 'sync' */
int partial_recover_error = 0;
/* read the qarity */
if (state->level >= 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;j<failed_count;++j) {
if (failed[j].is_bad && failed[j].is_outofdate) {
++partial_recover_error;
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));
}
}
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;j<failed_count;++j) {
/* nothing to do if it doesn't need recovering */
if (!failed[j].is_bad)
continue;
/* do not fix if the file filtered out */
if (file_flag_has(block_file_get(failed[j].block), FILE_IS_EXCLUDED))
continue;
ret = handle_write(failed[j].handle, failed[j].block, buffer[failed[j].index], state->block_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;j<failed_count;++j) {
if (failed[j].is_bad)
file_flag_set(block_file_get(failed[j].block), FILE_IS_DAMAGED);
}
}
} else {
/* check if the recover was only partial */
/* note that this could happen only when we have an incomplete 'sync' */
/* and that we have recovered is the state before the 'sync' */
int partial_recover_error = 0;
/* print a list of all the errors in files */
for(j=0;j<failed_count;++j) {
if (failed[j].is_bad && failed[j].is_outofdate) {
++partial_recover_error;
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));
}
}
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;j<failed_count;++j) {
/* nothing to do if it doesn't need recovering */
if (!failed[j].is_bad)
continue;
/* do not fix if the file filtered out */
if (file_flag_has(block_file_get(failed[j].block), FILE_IS_EXCLUDED))
continue;
ret = handle_write(failed[j].handle, failed[j].block, buffer[failed[j].index], 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 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;j<diskmax;++j) {
@ -1124,8 +1144,11 @@ bail:
}
if (unrecoverable_error)
printf("%u UNRECOVERABLE errors\n", unrecoverable_error);
else
printf("No unrecoverable errors\n");
else {
/* without checking, we don't know if they are really recoverable or not */
if (check)
printf("No unrecoverable errors\n");
}
} else {
printf("No error\n");
}
@ -1160,7 +1183,7 @@ bail:
return 0;
}
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)
{
block_off_t blockmax;
data_off_t size;
@ -1173,6 +1196,11 @@ void state_check(struct snapraid_state* state, int fix, block_off_t blockstart,
printf("Initializing...\n");
if (!check && fix) {
fprintf(stderr, "Error in calling, you cannot fix without checking parity.\n");
exit(EXIT_FAILURE);
}
blockmax = parity_resize(state);
size = blockmax * (data_off_t)state->block_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 */

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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);