From b6c74c78f20929fff5c92e5277ea0a6dc0f4bc7f Mon Sep 17 00:00:00 2001 From: Morgan Weetman Date: Fri, 7 Nov 2014 18:59:45 +1100 Subject: [PATCH 1/8] find: added extended attribute predicate * find/defs.h (typedef PREDICATEFUNCTION): added pred_xattr * find/parser.c (parse_xattr): added function, added an entry to parse_table[] * find/pred.c (pred_xattr): added function, added an entry to pred_table[] * find/tree.c (costlookup[]): added pred_xattr entry --- find/defs.h | 1 + find/parser.c | 28 ++++++++++++++++++++++++++++ find/pred.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ find/tree.c | 1 + 4 files changed, 86 insertions(+) diff --git a/find/defs.h b/find/defs.h index caccd2b..4ab1bb1 100644 --- a/find/defs.h +++ b/find/defs.h @@ -457,6 +457,7 @@ PREDICATEFUNCTION pred_uid; PREDICATEFUNCTION pred_used; PREDICATEFUNCTION pred_user; PREDICATEFUNCTION pred_writable; +PREDICATEFUNCTION pred_xattr; PREDICATEFUNCTION pred_xtype; PREDICATEFUNCTION pred_context; diff --git a/find/parser.c b/find/parser.c index dc6c47c..bb43286 100644 --- a/find/parser.c +++ b/find/parser.c @@ -149,6 +149,7 @@ static bool parse_xdev (const struct parser_table*, char *argv[], int * static bool parse_ignore_race (const struct parser_table*, char *argv[], int *arg_ptr); static bool parse_noignore_race (const struct parser_table*, char *argv[], int *arg_ptr); static bool parse_warn (const struct parser_table*, char *argv[], int *arg_ptr); +static bool parse_xattr (const struct parser_table*, char *argv[], int *arg_ptr); static bool parse_xtype (const struct parser_table*, char *argv[], int *arg_ptr); static bool parse_quit (const struct parser_table*, char *argv[], int *arg_ptr); static bool parse_context (const struct parser_table*, char *argv[], int *arg_ptr); @@ -306,6 +307,7 @@ static struct parser_table const parse_table[] = PARSE_TEST_NP ("wholename", wholename), /* GNU, replaced -path, but anyway -path will soon be in POSIX */ {ARG_TEST, "writable", parse_accesscheck, pred_writable}, /* GNU, 4.3.0+ */ PARSE_OPTION ("xdev", xdev), /* POSIX */ + PARSE_TEST ("xattr", xattr), /* GNU */ PARSE_TEST ("xtype", xtype), /* GNU */ #ifdef UNIMPLEMENTED_UNIX /* It's pretty ugly for find to know about archive formats. @@ -2757,6 +2759,32 @@ parse_warn (const struct parser_table* entry, char **argv, int *arg_ptr) } static bool +parse_xattr (const struct parser_table* entry, char **argv, int *arg_ptr) +{ + const char *name; + const int saved_argc = *arg_ptr; + + if (collect_arg (argv, arg_ptr, &name)) + { + fnmatch_sanitycheck (); + if (check_name_arg ("-xattr", name)) + { + struct predicate *our_pred = insert_primary (entry, name); + our_pred->need_stat = our_pred->need_type = false; + our_pred->args.str = name; + our_pred->est_success_rate = estimate_pattern_match_rate (name, 0); + return true; + } + else + { + *arg_ptr = saved_argc; /* don't consume the invalid argument. */ + } + } + return false; +} + + +static bool parse_xtype (const struct parser_table* entry, char **argv, int *arg_ptr) { return insert_type (argv, arg_ptr, entry, pred_xtype); diff --git a/find/pred.c b/find/pred.c index 3a89679..048e263 100644 --- a/find/pred.c +++ b/find/pred.c @@ -141,6 +141,7 @@ struct pred_assoc pred_table[] = {pred_used, "used "}, {pred_user, "user "}, {pred_writable, "writable "}, + {pred_xattr, "xattr "}, {pred_xtype, "xtype "}, {pred_context, "context"}, {0, "none "} @@ -1156,6 +1157,61 @@ pred_user (const char *pathname, struct stat *stat_buf, struct predicate *pred_p } bool +pred_xattr (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr) +{ + (void) pathname; + const char *re_string = pred_ptr->args.str; + char empty[0]; + char *list; + char *substrings; + ssize_t list_size; + int i, j; + bool ret = false; + regex_t re_pattern; + + // get size of xattr list for the given path by passing an empty list + list_size = listxattr(pathname, empty, 0); + + // allocate just enough memory to hold all xattrs + list = malloc(list_size); + + // used to hold individual attributes (substrings) + // allocate same size as list just in case there's only one xattr + substrings = malloc(list_size); + + // retrieve the list of xattrs + listxattr(pathname, list, list_size); + + // compile regex pattern + if (regcomp(&re_pattern, re_string, REG_ICASE|REG_NOSUB|REG_NEWLINE) != 0) { + free(list); + free(substrings); + return(ret); + } + + // break list into asciiz strings + for (i = 0, j = 0; i < list_size; i++) { + substrings[j] = list[i]; + if (list[i] == 0) { + // perform regex match against substring + j = 0; + if (regexec(&re_pattern, substrings, (size_t) 0, NULL, 0) == 0) { + ret = true; + } + continue; + } + j++; + } + + // clean up + free(list); + free(substrings); + regfree(&re_pattern); + return(ret); + +} + +bool pred_xtype (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr) { struct stat sbuf; /* local copy, not stat_buf because we're using a different stat method */ diff --git a/find/tree.c b/find/tree.c index 026dead..2dba99d 100644 --- a/find/tree.c +++ b/find/tree.c @@ -1001,6 +1001,7 @@ static struct pred_cost_lookup costlookup[] = { pred_used , NeedsStatInfo }, { pred_user , NeedsStatInfo }, { pred_writable , NeedsAccessInfo }, + { pred_xattr , NeedsNothing }, { pred_xtype , NeedsType } /* roughly correct unless most files are symlinks */ }; static int pred_table_sorted = 0; -- 1.9.3