mirror of
https://github.com/amadvance/snapraid.git
synced 2026-10-26 19:01:57 -04:00
Adds filter capability in check and fix.
Fixes the context saving when only changed files are detected.
This commit is contained in:
parent
ba73d0c574
commit
a70eb4ed2b
13 changed files with 272 additions and 69 deletions
6
HISTORY
6
HISTORY
|
|
@ -3,10 +3,10 @@ SnapRAID HISTORY
|
|||
|
||||
0.3 2011/4
|
||||
==========
|
||||
* Better ETA estimation.
|
||||
* Added --filter option to select a subset of file in check and fix.
|
||||
* Better ETA estimation in all the commands.
|
||||
* Added support for OpenSSL crypto library to use its optimized MD5 implementation.
|
||||
* Added test vector for MD5.
|
||||
* Added a speed test option for MD5.
|
||||
* Added test vectors and a speed test for MD5.
|
||||
|
||||
0.2 2011/3
|
||||
==========
|
||||
|
|
|
|||
28
Makefile.am
28
Makefile.am
|
|
@ -64,33 +64,39 @@ check-local:
|
|||
mkdir test/disk2
|
||||
mkdir test/disk3
|
||||
echo --- As empty, sync and check
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test.conf sync
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -v -c $(srcdir)/test.conf sync
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test.conf check
|
||||
echo --- Create some files, sync and check
|
||||
$(TESTENV) ./mktest$(EXEEXT) generate 1 3 1000 4000
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test.conf sync
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -v -c $(srcdir)/test.conf sync
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test.conf check
|
||||
echo --- Create some more files, sync and check
|
||||
$(TESTENV) ./mktest$(EXEEXT) generate 2 3 1000 4000
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test.conf sync
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -v -c $(srcdir)/test.conf sync
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test.conf check
|
||||
echo --- Delete some files and create some new, sync and check
|
||||
rm test/disk1/1*
|
||||
rm test/disk2/2*
|
||||
rm test/disk2/3*
|
||||
rm test/disk3/3*
|
||||
$(TESTENV) ./mktest$(EXEEXT) generate 3 3 100 4000
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test.conf sync
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -v -c $(srcdir)/test.conf sync
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test.conf check
|
||||
echo --- Move some files, sync and check
|
||||
mv test/disk1/7* test/disk1/_a/
|
||||
mv test/disk2/7* test/disk2/_a/
|
||||
mv test/disk3/7* test/disk3/_a/
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -v -c $(srcdir)/test.conf sync
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test.conf check
|
||||
echo --- Delete some files and create some new, sync and check in multiple steps
|
||||
rm test/disk1/4*
|
||||
rm test/disk2/5*
|
||||
rm test/disk2/6*
|
||||
rm test/disk3/6*
|
||||
$(TESTENV) ./mktest$(EXEEXT) generate 4 3 100 4000
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test.conf -t 7 sync
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -v -c $(srcdir)/test.conf -t 7 sync
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test.conf check
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test.conf -t 11 sync
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -v -c $(srcdir)/test.conf -t 11 sync
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test.conf check
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test.conf sync
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -v -c $(srcdir)/test.conf sync
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test.conf check
|
||||
echo --- Delete some files, fix and check
|
||||
rm test/disk1/1*
|
||||
|
|
@ -109,6 +115,8 @@ check-local:
|
|||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test.conf check 2>/dev/null
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test.conf fix 2>/dev/null
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test.conf check
|
||||
echo --- Sync after all the fixes with an empty drive
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -v -E -c $(srcdir)/test.conf sync
|
||||
echo --- Delete the parity, fix and check
|
||||
rm test/parity
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test.conf check 2>/dev/null
|
||||
|
|
@ -124,6 +132,8 @@ check-local:
|
|||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test.conf check 2>/dev/null
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test.conf fix 2>/dev/null
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test.conf check
|
||||
echo --- Sync after all the fixes
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -v -c $(srcdir)/test.conf sync
|
||||
echo Success!
|
||||
|
||||
# Manual testing
|
||||
|
|
|
|||
2
TODO
2
TODO
|
|
@ -3,6 +3,8 @@ SnapRAID TODO
|
|||
|
||||
This is a list of possible TODO for SnapRAID. The order is not relevant.
|
||||
|
||||
* Easy way to find duplicates using the computed hash.
|
||||
|
||||
* Add RAID6 redundancy support.
|
||||
There is the very good raid6 library from H. Peter Anvin (hpa) in the Linux Kernel ready to use:
|
||||
See:
|
||||
|
|
|
|||
65
check.c
65
check.c
|
|
@ -57,7 +57,31 @@ static int state_check_process(struct snapraid_state* state, int fix, int parity
|
|||
unrecoverable_error = 0;
|
||||
recovered_error = 0;
|
||||
|
||||
countmax = blockmax - blockstart;
|
||||
/* first count the number of blocks to process */
|
||||
countmax = 0;
|
||||
for(i=blockstart;i<blockmax;++i) {
|
||||
int one_tocheck;
|
||||
|
||||
/* for each disk */
|
||||
one_tocheck = 0;
|
||||
for(j=0;j<diskmax;++j) {
|
||||
struct snapraid_block* block = disk_block_get(handle[j].disk, i);
|
||||
if (block
|
||||
&& bit_has(block->flag, BLOCK_HAS_HASH) /* only if the block is hashed */
|
||||
&& !block->file->is_filtered /* only if the file is not filtered out */
|
||||
) {
|
||||
one_tocheck = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* if no block to check skip */
|
||||
if (!one_tocheck)
|
||||
continue;
|
||||
|
||||
++countmax;
|
||||
}
|
||||
|
||||
countsize = 0;
|
||||
countpos = 0;
|
||||
start = time(0);
|
||||
|
|
@ -66,21 +90,24 @@ static int state_check_process(struct snapraid_state* state, int fix, int parity
|
|||
int failed;
|
||||
struct snapraid_block* failed_block;
|
||||
struct snapraid_handle* failed_handle;
|
||||
int one_hash;
|
||||
int one_tocheck;
|
||||
int all_parity;
|
||||
|
||||
/* for each disk */
|
||||
one_hash = 0;
|
||||
one_tocheck = 0;
|
||||
for(j=0;j<diskmax;++j) {
|
||||
struct snapraid_block* block = disk_block_get(handle[j].disk, i);
|
||||
if (block && bit_has(block->flag, BLOCK_HAS_HASH)) {
|
||||
one_hash = 1;
|
||||
if (block
|
||||
&& bit_has(block->flag, BLOCK_HAS_HASH) /* only if the block is hashed */
|
||||
&& !block->file->is_filtered /* only if the file is not filtered out */
|
||||
) {
|
||||
one_tocheck = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* if no hashed block skip */
|
||||
if (!one_hash)
|
||||
/* if no block to check skip */
|
||||
if (!one_tocheck)
|
||||
continue;
|
||||
|
||||
/* start with 0 */
|
||||
|
|
@ -88,7 +115,7 @@ static int state_check_process(struct snapraid_state* state, int fix, int parity
|
|||
|
||||
all_parity = 1; /* if all hashed block have parity computed */
|
||||
failed = 0; /* number of failed block */
|
||||
failed_block = 0; /* last failed block */
|
||||
failed_block = 0; /* last failed block, but not filtered out */
|
||||
failed_handle = 0;
|
||||
|
||||
/* for each disk, process the block */
|
||||
|
|
@ -134,8 +161,10 @@ static int state_check_process(struct snapraid_state* state, int fix, int parity
|
|||
if (ret == -1) {
|
||||
/* save the failed block for the parity check */
|
||||
++failed;
|
||||
failed_block = block;
|
||||
failed_handle = &handle[j];
|
||||
if (!block->file->is_filtered) {
|
||||
failed_block = block;
|
||||
failed_handle = &handle[j];
|
||||
}
|
||||
|
||||
fprintf(stderr, "%u: Open error for file %s at position %u\n", i, block->file->sub, block_file_pos(block));
|
||||
++error;
|
||||
|
|
@ -147,8 +176,10 @@ static int state_check_process(struct snapraid_state* state, int fix, int parity
|
|||
if (read_size == -1) {
|
||||
/* save the failed block for the parity check */
|
||||
++failed;
|
||||
failed_block = block;
|
||||
failed_handle = &handle[j];
|
||||
if (!block->file->is_filtered) {
|
||||
failed_block = block;
|
||||
failed_handle = &handle[j];
|
||||
}
|
||||
|
||||
fprintf(stderr, "%u: Read error for file %s at position %u\n", i, block->file->sub, block_file_pos(block));
|
||||
++error;
|
||||
|
|
@ -162,8 +193,10 @@ static int state_check_process(struct snapraid_state* state, int fix, int parity
|
|||
if (memcmp(hash, block->hash, MD5_SIZE) != 0) {
|
||||
/* save the failed block for the parity check */
|
||||
++failed;
|
||||
failed_block = block;
|
||||
failed_handle = &handle[j];
|
||||
if (!block->file->is_filtered) {
|
||||
failed_block = block;
|
||||
failed_handle = &handle[j];
|
||||
}
|
||||
|
||||
fprintf(stderr, "%u: Data error for file %s at position %u\n", i, block->file->sub, block_file_pos(block));
|
||||
++error;
|
||||
|
|
@ -176,7 +209,9 @@ static int state_check_process(struct snapraid_state* state, int fix, int parity
|
|||
countsize += read_size;
|
||||
}
|
||||
|
||||
if (parity_f == -1 || !all_parity) {
|
||||
if (failed != 0 && !failed_block) {
|
||||
/* if the failed blocks are filtered out, do nothing */
|
||||
} else if (parity_f == -1 || !all_parity) {
|
||||
/* all the cases with no parity file */
|
||||
if (failed != 0) {
|
||||
fprintf(stderr, "%u: UNRECOVERABLE errors for this block\n", i);
|
||||
|
|
|
|||
19
elem.c
19
elem.c
|
|
@ -78,7 +78,7 @@ void filter_free(struct snapraid_filter* filter)
|
|||
free(filter);
|
||||
}
|
||||
|
||||
int filter_filter(struct snapraid_filter* filter, const char* path, const char* name, int is_dir)
|
||||
int filter_path(struct snapraid_filter* filter, const char* path, const char* name, int is_dir)
|
||||
{
|
||||
/* matches dirs with dirs and files with files */
|
||||
if (filter->is_dir && !is_dir)
|
||||
|
|
@ -98,6 +98,12 @@ int filter_filter(struct snapraid_filter* filter, const char* path, const char*
|
|||
return -1;
|
||||
}
|
||||
|
||||
int filter_file(struct snapraid_filter* filter, struct snapraid_file* file)
|
||||
{
|
||||
/* only partially correct as we are not filtering dirs */
|
||||
return filter_path(filter, file->sub, file_name(file), 0);
|
||||
}
|
||||
|
||||
block_off_t block_file_pos(struct snapraid_block* block)
|
||||
{
|
||||
struct snapraid_file* file = block->file;
|
||||
|
|
@ -140,6 +146,7 @@ struct snapraid_file* file_alloc(unsigned block_size, const char* sub, uint64_t
|
|||
file->mtime = mtime;
|
||||
file->inode = inode;
|
||||
file->is_present = 0;
|
||||
file->is_filtered = 0;
|
||||
file->blockvec = malloc_nofail(file->blockmax * sizeof(struct snapraid_block));
|
||||
|
||||
/* set the back pointer */
|
||||
|
|
@ -158,6 +165,16 @@ void file_free(struct snapraid_file* file)
|
|||
free(file);
|
||||
}
|
||||
|
||||
const char* file_name(struct snapraid_file* file)
|
||||
{
|
||||
const char* r = strrchr(file->sub, '/');
|
||||
if (!r)
|
||||
r = file->sub;
|
||||
else
|
||||
++r;
|
||||
return r;
|
||||
}
|
||||
|
||||
int file_inode_compare(const void* void_arg, const void* void_data)
|
||||
{
|
||||
const uint64_t* arg = void_arg;
|
||||
|
|
|
|||
16
elem.h
16
elem.h
|
|
@ -79,6 +79,7 @@ struct snapraid_file {
|
|||
uint64_t mtime; /**< Modification time. */
|
||||
uint64_t inode; /**< Inode. */
|
||||
int is_present; /**< If it's seen as present. */
|
||||
int is_filtered; /**< If it's filtered out. */
|
||||
|
||||
/* nodes for data structures */
|
||||
tommy_node nodelist;
|
||||
|
|
@ -108,10 +109,16 @@ struct snapraid_filter* filter_alloc(const char* pattern);
|
|||
void filter_free(struct snapraid_filter* filter);
|
||||
|
||||
/**
|
||||
* Checks if a path/name matches the pattern.
|
||||
* Filters a path/name.
|
||||
* Returns 0 if it matches.
|
||||
*/
|
||||
int filter_filter(struct snapraid_filter* filter, const char* path, const char* name, int is_dir);
|
||||
int filter_path(struct snapraid_filter* filter, const char* path, const char* name, int is_dir);
|
||||
|
||||
/**
|
||||
* Filters a file.
|
||||
* Returns 0 if it matches.
|
||||
*/
|
||||
int filter_file(struct snapraid_filter* filter, struct snapraid_file* file);
|
||||
|
||||
/**
|
||||
* Gets the relative position of a block inside the file.
|
||||
|
|
@ -134,6 +141,11 @@ struct snapraid_file* file_alloc(unsigned block_size, const char* sub, uint64_t
|
|||
*/
|
||||
void file_free(struct snapraid_file* file);
|
||||
|
||||
/**
|
||||
* Returns the name of the file, without the dir.
|
||||
*/
|
||||
const char* file_name(struct snapraid_file* file);
|
||||
|
||||
/**
|
||||
* Compares two files by inode.
|
||||
*/
|
||||
|
|
|
|||
49
snapraid.1
49
snapraid.1
|
|
@ -2,7 +2,7 @@
|
|||
.SH NAME
|
||||
snapraid \(hy SnapRAID Backup For Disk Arrays
|
||||
.SH SYNOPSIS
|
||||
snapraid [\(hyc, \(hy\(hyconf CONFIG]
|
||||
snapraid [\(hyc, \(hy\(hyconf CONFIG] [\(hyf, \(hy\(hyfilter PATTERN]
|
||||
.PD 0
|
||||
.PP
|
||||
.PD
|
||||
|
|
@ -254,6 +254,14 @@ Selects the configuration file. If not specified is assumed
|
|||
the file \(cq/etc/snapraid.conf\(cq in Unix, and \(cqsnapraid.conf\(cq
|
||||
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.
|
||||
See the PATTERN section for more details in the
|
||||
pattern specifications.
|
||||
This option can be used many times.
|
||||
In Unix, ensure to quote globbing chars if used.
|
||||
.TP
|
||||
.B \(hyZ, \(hy\(hyforce\(hyzero
|
||||
Forces the insecure operation of syncing a file with zero
|
||||
size that before was not empty.
|
||||
|
|
@ -326,7 +334,8 @@ You should use one option for each disk of the array.
|
|||
.TP
|
||||
.B exclude PATTERN
|
||||
Defines the file or directory patterns to exclude from the sync
|
||||
process. See the PATTERN section for more details in the
|
||||
process.
|
||||
See the PATTERN section for more details in the
|
||||
pattern specifications.
|
||||
This option can be used many times.
|
||||
.TP
|
||||
|
|
@ -400,37 +409,36 @@ block_size 256
|
|||
.PD
|
||||
.RE
|
||||
.SH PATTERN
|
||||
Patterns are used to define the files and directories to exclude
|
||||
from the redundancy process.
|
||||
.PP
|
||||
It makes sense to exclude any file not worth to be saved or that
|
||||
changes often.
|
||||
Patterns are used select a subset of files to exclude or operate on.
|
||||
.PP
|
||||
There are four different types of patterns:
|
||||
.TP
|
||||
.B FILE
|
||||
Excludes any file named as FILE. You can use any globbing
|
||||
Selects any file named as FILE. You can use any globbing
|
||||
character like * and ?.
|
||||
This pattern is applied only to files and not to directories.
|
||||
.TP
|
||||
.B DIR/
|
||||
Excludes any directory named DIR. You can use any globbing
|
||||
Selects any directory named DIR. You can use any globbing
|
||||
character like * and ?.
|
||||
This pattern is applied only to directories and not to files.
|
||||
.TP
|
||||
.B /PATH/FILE
|
||||
Excludes the exact specified file path. You can use any
|
||||
Selects the exact specified file path. You can use any
|
||||
globbing character like * and ? but they never matches a
|
||||
directory slash.
|
||||
This pattern is applied only to files and not to directories.
|
||||
.TP
|
||||
.B /PATH/DIR/
|
||||
Excludes the exact specified directory path. You can use any
|
||||
Selects the exact specified directory path. You can use any
|
||||
globbing character like * and ? but they never matches a
|
||||
directory slash.
|
||||
This pattern is applied only to directories and not to files.
|
||||
.PP
|
||||
For example:
|
||||
Note that when globbing char are used in the command line, you have to
|
||||
quote them in Unix. Otherwise the shell will try to expand them.
|
||||
.PP
|
||||
For example, in the configuration file:
|
||||
.PP
|
||||
.RS 4
|
||||
# Excludes any file named \(a"*.bak\(a"
|
||||
|
|
@ -458,6 +466,23 @@ exclude tmp/
|
|||
.PP
|
||||
.PD
|
||||
.RE
|
||||
.PP
|
||||
For example, in the command line:
|
||||
.PP
|
||||
.RS 4
|
||||
# Checks only the .mp3 files.
|
||||
.PD 0
|
||||
.PP
|
||||
.PD
|
||||
# Note the \(a"\(a" use to avoid globbing expansion by the shell.
|
||||
.PD 0
|
||||
.PP
|
||||
.PD
|
||||
snapraid \(hyf \(a"*.mp3\(a" check
|
||||
.PD 0
|
||||
.PP
|
||||
.PD
|
||||
.RE
|
||||
.SH CONTENT
|
||||
SnapRAID creates a content file describing the content of your disk
|
||||
array.
|
||||
|
|
|
|||
25
snapraid.c
25
snapraid.c
|
|
@ -55,7 +55,7 @@ struct test_vector {
|
|||
{ "abcdefghijklmnopqrstuvwxyz", { 0xc3, 0xfc, 0xd3, 0xd7, 0x61, 0x92, 0xe4, 0x00, 0x7d, 0xfb, 0x49, 0x6c, 0xca, 0x67, 0xe1, 0x3b } },
|
||||
{ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", { 0xd1, 0x74, 0xab, 0x98, 0xd2, 0x77, 0xd9, 0xf5, 0xa5, 0x61, 0x1c, 0x2c, 0x9f, 0x41, 0x9d, 0x9f } },
|
||||
{ "12345678901234567890123456789012345678901234567890123456789012345678901234567890", { 0x57, 0xed, 0xf4, 0xa2, 0x2b, 0xe3, 0xc9, 0x55, 0xac, 0x49, 0xda, 0x2e, 0x21, 0x07, 0xb6, 0x7a, } },
|
||||
{ 0 }
|
||||
{ 0, { 0 } }
|
||||
};
|
||||
|
||||
void selftest(void)
|
||||
|
|
@ -123,6 +123,7 @@ void usage(void)
|
|||
printf("\n");
|
||||
printf("Options:\n");
|
||||
printf(" " SWITCH_GETOPT_LONG("-c, --conf FILE ", "-c") " Configuration file (default " CONF ")\n");
|
||||
printf(" " SWITCH_GETOPT_LONG("-f, --filter PATTERN", "-f") " Filter the files to processs\n");
|
||||
printf(" " SWITCH_GETOPT_LONG("-Z, --force-zero ", "-Z") " Force synching of files that get zero size\n");
|
||||
printf(" " SWITCH_GETOPT_LONG("-E, --force-empty ", "-E") " Force synching of disks that get empty\n");
|
||||
printf(" " SWITCH_GETOPT_LONG("-s, --start BLKSTART", "-s") " Start from the specified block number\n");
|
||||
|
|
@ -136,6 +137,7 @@ void usage(void)
|
|||
#if HAVE_GETOPT_LONG
|
||||
struct option long_options[] = {
|
||||
{ "conf", 1, 0, 'c' },
|
||||
{ "filter", 1, 0, 'f' },
|
||||
{ "force-zero", 0, 0, 'Z' },
|
||||
{ "force-empty", 0, 0, 'E' },
|
||||
{ "start", 1, 0, 's' },
|
||||
|
|
@ -148,7 +150,7 @@ struct option long_options[] = {
|
|||
};
|
||||
#endif
|
||||
|
||||
#define OPTIONS "c:s:t:ZETvhV"
|
||||
#define OPTIONS "c:f:s:t:ZETvhV"
|
||||
|
||||
volatile int global_interrupt = 0;
|
||||
|
||||
|
|
@ -177,6 +179,7 @@ int main(int argc, char* argv[])
|
|||
block_off_t blockstart;
|
||||
block_off_t blockcount;
|
||||
int ret;
|
||||
tommy_list filterlist;
|
||||
|
||||
/* defaults */
|
||||
conf = CONF;
|
||||
|
|
@ -185,6 +188,7 @@ int main(int argc, char* argv[])
|
|||
force_empty = 0;
|
||||
blockstart = 0;
|
||||
blockcount = 0;
|
||||
tommy_list_init(&filterlist);
|
||||
|
||||
opterr = 0;
|
||||
while ((c =
|
||||
|
|
@ -198,6 +202,14 @@ int main(int argc, char* argv[])
|
|||
case 'c' :
|
||||
conf = optarg;
|
||||
break;
|
||||
case 'f' : {
|
||||
struct snapraid_filter* filter = filter_alloc(optarg);
|
||||
if (!filter) {
|
||||
fprintf(stderr, "Invalid filter specification '%s'\n", optarg);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
tommy_list_insert_tail(&filterlist, &filter->node, filter);
|
||||
} break;
|
||||
case 's' :
|
||||
if (stru32(optarg, &blockstart) != 0) {
|
||||
fprintf(stderr, "Invalid start position '%s'\n", optarg);
|
||||
|
|
@ -257,6 +269,12 @@ int main(int argc, char* argv[])
|
|||
state_config(&state, conf, verbose, force_zero, force_empty);
|
||||
|
||||
if (operation == OPERATION_SYNC) {
|
||||
|
||||
if (!tommy_list_empty(&filterlist)) {
|
||||
fprintf(stderr, "You cannot filter with the sync command\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
state_read(&state);
|
||||
|
||||
state_scan(&state);
|
||||
|
|
@ -276,6 +294,8 @@ int main(int argc, char* argv[])
|
|||
} else {
|
||||
state_read(&state);
|
||||
|
||||
state_filter(&state, &filterlist);
|
||||
|
||||
/* intercept Ctrl+C */
|
||||
signal(SIGINT, &signal_handler);
|
||||
|
||||
|
|
@ -283,6 +303,7 @@ int main(int argc, char* argv[])
|
|||
}
|
||||
|
||||
state_done(&state);
|
||||
tommy_list_foreach(&filterlist, (tommy_foreach_func*)filter_free);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
37
snapraid.d
37
snapraid.d
|
|
@ -2,7 +2,7 @@ Name{number}
|
|||
snapraid - SnapRAID Backup For Disk Arrays
|
||||
|
||||
Synopsis
|
||||
:snapraid [-c, --conf CONFIG]
|
||||
:snapraid [-c, --conf CONFIG] [-f, --filter PATTERN]
|
||||
: [-Z, --force-zero] [-E, --force-empty]
|
||||
: [-s, --start BLKSTART] [-t, --count BLKCOUNT]
|
||||
: [-v, --verbose]
|
||||
|
|
@ -169,6 +169,14 @@ Options
|
|||
the file '/etc/snapraid.conf' in Unix, and 'snapraid.conf'
|
||||
in Windows.
|
||||
|
||||
-f, --filter PATTERN
|
||||
Filters the files to operate on with the "check" and "fix"
|
||||
commands. This option is ignored with the "sync" command.
|
||||
See the PATTERN section for more details in the
|
||||
pattern specifications.
|
||||
This option can be used many times.
|
||||
In Unix, ensure to quote globbing chars if used.
|
||||
|
||||
-Z, --force-zero
|
||||
Forces the insecure operation of syncing a file with zero
|
||||
size that before was not empty.
|
||||
|
|
@ -242,7 +250,8 @@ Configuration
|
|||
|
||||
=exclude PATTERN
|
||||
Defines the file or directory patterns to exclude from the sync
|
||||
process. See the PATTERN section for more details in the
|
||||
process.
|
||||
See the PATTERN section for more details in the
|
||||
pattern specifications.
|
||||
This option can be used many times.
|
||||
|
||||
|
|
@ -279,37 +288,36 @@ Configuration
|
|||
:block_size 256
|
||||
|
||||
Pattern
|
||||
Patterns are used to define the files and directories to exclude
|
||||
from the redundancy process.
|
||||
|
||||
It makes sense to exclude any file not worth to be saved or that
|
||||
changes often.
|
||||
Patterns are used select a subset of files to exclude or operate on.
|
||||
|
||||
There are four different types of patterns:
|
||||
|
||||
=FILE
|
||||
Excludes any file named as FILE. You can use any globbing
|
||||
Selects any file named as FILE. You can use any globbing
|
||||
character like * and ?.
|
||||
This pattern is applied only to files and not to directories.
|
||||
|
||||
=DIR/
|
||||
Excludes any directory named DIR. You can use any globbing
|
||||
Selects any directory named DIR. You can use any globbing
|
||||
character like * and ?.
|
||||
This pattern is applied only to directories and not to files.
|
||||
|
||||
=/PATH/FILE
|
||||
Excludes the exact specified file path. You can use any
|
||||
Selects the exact specified file path. You can use any
|
||||
globbing character like * and ? but they never matches a
|
||||
directory slash.
|
||||
This pattern is applied only to files and not to directories.
|
||||
|
||||
=/PATH/DIR/
|
||||
Excludes the exact specified directory path. You can use any
|
||||
Selects the exact specified directory path. You can use any
|
||||
globbing character like * and ? but they never matches a
|
||||
directory slash.
|
||||
This pattern is applied only to directories and not to files.
|
||||
|
||||
For example:
|
||||
Note that when globbing char are used in the command line, you have to
|
||||
quote them in Unix. Otherwise the shell will try to expand them.
|
||||
|
||||
For example, in the configuration file:
|
||||
:# Excludes any file named "*.bak"
|
||||
:exclude *.bak
|
||||
:# Excludes the root directory "/lost+found"
|
||||
|
|
@ -317,6 +325,11 @@ Pattern
|
|||
:# Excludes any directory named "tmp"
|
||||
:exclude tmp/
|
||||
|
||||
For example, in the command line:
|
||||
:# Checks only the .mp3 files.
|
||||
:# Note the "" use to avoid globbing expansion by the shell.
|
||||
:snapraid -f "*.mp3" check
|
||||
|
||||
Content
|
||||
SnapRAID creates a content file describing the content of your disk
|
||||
array.
|
||||
|
|
|
|||
37
snapraid.txt
37
snapraid.txt
|
|
@ -6,7 +6,7 @@
|
|||
1 SYNOPSIS
|
||||
==========
|
||||
|
||||
snapraid [-c, --conf CONFIG]
|
||||
snapraid [-c, --conf CONFIG] [-f, --filter PATTERN]
|
||||
[-Z, --force-zero] [-E, --force-empty]
|
||||
[-s, --start BLKSTART] [-t, --count BLKCOUNT]
|
||||
[-v, --verbose]
|
||||
|
|
@ -188,6 +188,14 @@ SnapRAID provides three simple commands that allow to:
|
|||
the file '/etc/snapraid.conf' in Unix, and 'snapraid.conf'
|
||||
in Windows.
|
||||
|
||||
-f, --filter PATTERN
|
||||
Filters the files to operate on with the "check" and "fix"
|
||||
commands. This option is ignored with the "sync" command.
|
||||
See the PATTERN section for more details in the
|
||||
pattern specifications.
|
||||
This option can be used many times.
|
||||
In Unix, ensure to quote globbing chars if used.
|
||||
|
||||
-Z, --force-zero
|
||||
Forces the insecure operation of syncing a file with zero
|
||||
size that before was not empty.
|
||||
|
|
@ -264,7 +272,8 @@ it should contains the following options:
|
|||
|
||||
exclude PATTERN
|
||||
Defines the file or directory patterns to exclude from the sync
|
||||
process. See the PATTERN section for more details in the
|
||||
process.
|
||||
See the PATTERN section for more details in the
|
||||
pattern specifications.
|
||||
This option can be used many times.
|
||||
|
||||
|
|
@ -304,37 +313,36 @@ An example of a typical configuration is:
|
|||
8 PATTERN
|
||||
=========
|
||||
|
||||
Patterns are used to define the files and directories to exclude
|
||||
from the redundancy process.
|
||||
|
||||
It makes sense to exclude any file not worth to be saved or that
|
||||
changes often.
|
||||
Patterns are used select a subset of files to exclude or operate on.
|
||||
|
||||
There are four different types of patterns:
|
||||
|
||||
FILE
|
||||
Excludes any file named as FILE. You can use any globbing
|
||||
Selects any file named as FILE. You can use any globbing
|
||||
character like * and ?.
|
||||
This pattern is applied only to files and not to directories.
|
||||
|
||||
DIR/
|
||||
Excludes any directory named DIR. You can use any globbing
|
||||
Selects any directory named DIR. You can use any globbing
|
||||
character like * and ?.
|
||||
This pattern is applied only to directories and not to files.
|
||||
|
||||
/PATH/FILE
|
||||
Excludes the exact specified file path. You can use any
|
||||
Selects the exact specified file path. You can use any
|
||||
globbing character like * and ? but they never matches a
|
||||
directory slash.
|
||||
This pattern is applied only to files and not to directories.
|
||||
|
||||
/PATH/DIR/
|
||||
Excludes the exact specified directory path. You can use any
|
||||
Selects the exact specified directory path. You can use any
|
||||
globbing character like * and ? but they never matches a
|
||||
directory slash.
|
||||
This pattern is applied only to directories and not to files.
|
||||
|
||||
For example:
|
||||
Note that when globbing char are used in the command line, you have to
|
||||
quote them in Unix. Otherwise the shell will try to expand them.
|
||||
|
||||
For example, in the configuration file:
|
||||
# Excludes any file named "*.bak"
|
||||
exclude *.bak
|
||||
# Excludes the root directory "/lost+found"
|
||||
|
|
@ -342,6 +350,11 @@ For example:
|
|||
# Excludes any directory named "tmp"
|
||||
exclude tmp/
|
||||
|
||||
For example, in the command line:
|
||||
# Checks only the .mp3 files.
|
||||
# Note the "" use to avoid globbing expansion by the shell.
|
||||
snapraid -f "*.mp3" check
|
||||
|
||||
|
||||
9 CONTENT
|
||||
=========
|
||||
|
|
|
|||
50
state.c
50
state.c
|
|
@ -510,6 +510,56 @@ void state_write(struct snapraid_state* state)
|
|||
}
|
||||
}
|
||||
|
||||
void state_filter(struct snapraid_state* state, tommy_list* filterlist)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if (tommy_list_empty(filterlist))
|
||||
return;
|
||||
|
||||
printf("Filtering...\n");
|
||||
|
||||
if (state->verbose) {
|
||||
tommy_node* k;
|
||||
for(k=tommy_list_head(filterlist);k!=0;k=k->next) {
|
||||
struct snapraid_filter* filter = k->data;
|
||||
printf("\t");
|
||||
if (filter->is_path)
|
||||
printf("/");
|
||||
printf("%s", filter->pattern);
|
||||
if (filter->is_dir)
|
||||
printf("/");
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* for each disk */
|
||||
for(i=0;i<tommy_array_size(&state->diskarr);++i) {
|
||||
tommy_node* j;
|
||||
struct snapraid_disk* disk = tommy_array_get(&state->diskarr, i);
|
||||
|
||||
/* for each file */
|
||||
for(j=tommy_list_head(&disk->filelist);j!=0;j=j->next) {
|
||||
tommy_node* k;
|
||||
struct snapraid_file* file = j->data;
|
||||
|
||||
/* filter it out as default */
|
||||
file->is_filtered = 1;
|
||||
|
||||
/* for each filter */
|
||||
for(k=tommy_list_head(filterlist);k!=0;k=k->next) {
|
||||
struct snapraid_filter* filter = k->data;
|
||||
|
||||
if (filter_file(filter, file) == 0) {
|
||||
/* mark it as filtered */
|
||||
file->is_filtered = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define PROGRESS_CLEAR " "
|
||||
|
||||
int state_progress(time_t* start, time_t* last, block_off_t countpos, block_off_t countmax, data_off_t countsize)
|
||||
|
|
|
|||
5
state.h
5
state.h
|
|
@ -78,6 +78,11 @@ int state_sync(struct snapraid_state* state, block_off_t blockstart, block_off_t
|
|||
*/
|
||||
void state_check(struct snapraid_state* state, int fix, block_off_t blockstart, block_off_t blockcount);
|
||||
|
||||
/**
|
||||
* Filter files.
|
||||
*/
|
||||
void state_filter(struct snapraid_state* state, tommy_list* filterlist);
|
||||
|
||||
/**
|
||||
* Writes the progress.
|
||||
*/
|
||||
|
|
|
|||
2
util.c
2
util.c
|
|
@ -180,7 +180,7 @@ void pathcpy(char* str, size_t size, const char* src)
|
|||
|
||||
void pathprint(char* str, size_t size, const char* format, ...)
|
||||
{
|
||||
int len;
|
||||
size_t len;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue