From a70eb4ed2b82dc1bb5f75c2ad1ff0727e8fea24c Mon Sep 17 00:00:00 2001 From: Andrea Mazzoleni Date: Wed, 30 Mar 2011 00:14:43 +0200 Subject: [PATCH] Adds filter capability in check and fix. Fixes the context saving when only changed files are detected. --- HISTORY | 6 ++--- Makefile.am | 28 ++++++++++++++-------- TODO | 2 ++ check.c | 65 ++++++++++++++++++++++++++++++++++++++++------------ elem.c | 19 ++++++++++++++- elem.h | 16 +++++++++++-- snapraid.1 | 49 +++++++++++++++++++++++++++++---------- snapraid.c | 25 ++++++++++++++++++-- snapraid.d | 37 ++++++++++++++++++++---------- snapraid.txt | 37 ++++++++++++++++++++---------- state.c | 50 ++++++++++++++++++++++++++++++++++++++++ state.h | 5 ++++ util.c | 2 +- 13 files changed, 272 insertions(+), 69 deletions(-) diff --git a/HISTORY b/HISTORY index 1bbc32fe..e6425046 100644 --- a/HISTORY +++ b/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 ========== diff --git a/Makefile.am b/Makefile.am index 99975a66..fd167fa9 100644 --- a/Makefile.am +++ b/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 diff --git a/TODO b/TODO index 0beab84c..4baa1b09 100644 --- a/TODO +++ b/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: diff --git a/check.c b/check.c index fa37a37e..701b9c0d 100644 --- a/check.c +++ b/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;iflag, 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;jflag, 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); diff --git a/elem.c b/elem.c index 976b92fe..2ae198a4 100644 --- a/elem.c +++ b/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; diff --git a/elem.h b/elem.h index 19abf8df..c402b64b 100644 --- a/elem.h +++ b/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. */ diff --git a/snapraid.1 b/snapraid.1 index e739ce45..05f6c007 100644 --- a/snapraid.1 +++ b/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. diff --git a/snapraid.c b/snapraid.c index 58e221d6..b64c8c5d 100644 --- a/snapraid.c +++ b/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; } diff --git a/snapraid.d b/snapraid.d index b304142d..6de52a2d 100644 --- a/snapraid.d +++ b/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. diff --git a/snapraid.txt b/snapraid.txt index 8c2e87ae..be1777cf 100644 --- a/snapraid.txt +++ b/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 ========= diff --git a/state.c b/state.c index 61dbf4da..fbfd0001 100644 --- a/state.c +++ b/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;idiskarr);++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) diff --git a/state.h b/state.h index d8721d6c..380a1173 100644 --- a/state.h +++ b/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. */ diff --git a/util.c b/util.c index ab13b086..4510765f 100644 --- a/util.c +++ b/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);