From bce036cea10a8dd21eb8c9bf1b641d8790429c8e Mon Sep 17 00:00:00 2001 From: Mark Lord Date: Thu, 1 Jul 2010 18:16:14 -0400 Subject: [PATCH] libata: glob_match for ata_device_blacklist (v2) Replace rudimentry pattern matching with more capable shell-style globbing. This will enable shrinking ata_device_blacklist[] table in subsequent patches, and helps with future editions to the table, such as matching only the end of a firmware revision string etc.. Signed-off-by: Mark Lord Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 78 ++++++++++++++++++++++++++++----------- 1 file changed, 57 insertions(+), 21 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index ddf8e4862787..f8c72a1867fd 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4326,29 +4326,65 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { } }; -static int strn_pattern_cmp(const char *patt, const char *name, int wildchar) +/** + * glob_match - match a text string against a glob-style pattern + * @text: the string to be examined + * @pattern: the glob-style pattern to be matched against + * + * Either/both of text and pattern can be empty strings. + * + * Match text against a glob-style pattern, with wildcards and simple sets: + * + * ? matches any single character. + * * matches any run of characters. + * [xyz] matches a single character from the set: x, y, or z. + * + * Note: hyphenated ranges [0-9] are _not_ supported here. + * The special characters ?, [, or *, can be matched using a set, eg. [*] + * + * Example patterns: "SD1?", "SD1[012345]", "*R0", SD*1?[012]*xx" + * + * This function uses one level of recursion per '*' in pattern. + * Since it calls _nothing_ else, and has _no_ explicit local variables, + * this will not cause stack problems for any reasonable use here. + * + * RETURNS: + * 0 on match, 1 otherwise. + */ +static int glob_match (const char *text, const char *pattern) { - const char *p; - int len; - - /* - * check for trailing wildcard: *\0 - */ - p = strchr(patt, wildchar); - if (p && ((*(p + 1)) == 0)) - len = p - patt; - else { - len = strlen(name); - if (!len) { - if (!*patt) - return 0; - return -1; + do { + /* Match single character or a '?' wildcard */ + if (*text == *pattern || *pattern == '?') { + if (!*pattern++) + return 0; /* End of both strings: match */ + } else { + /* Match single char against a '[' bracketed ']' pattern set */ + if (!*text || *pattern != '[') + break; /* Not a pattern set */ + while (*++pattern && *pattern != ']' && *text != *pattern); + if (!*pattern || *pattern == ']') + return 1; /* No match */ + while (*pattern && *pattern++ != ']'); + } + } while (*++text && *pattern); + + /* Match any run of chars against a '*' wildcard */ + if (*pattern == '*') { + if (!*++pattern) + return 0; /* Match: avoid recursion at end of pattern */ + /* Loop to handle additional pattern chars after the wildcard */ + while (*text) { + if (glob_match(text, pattern) == 0) + return 0; /* Remainder matched */ + ++text; /* Absorb (match) this char and try again */ } } - - return strncmp(patt, name, len); + if (!*text && !*pattern) + return 0; /* End of both strings: match */ + return 1; /* No match */ } - + static unsigned long ata_dev_blacklisted(const struct ata_device *dev) { unsigned char model_num[ATA_ID_PROD_LEN + 1]; @@ -4359,10 +4395,10 @@ static unsigned long ata_dev_blacklisted(const struct ata_device *dev) ata_id_c_string(dev->id, model_rev, ATA_ID_FW_REV, sizeof(model_rev)); while (ad->model_num) { - if (!strn_pattern_cmp(ad->model_num, model_num, '*')) { + if (!glob_match(model_num, ad->model_num)) { if (ad->model_rev == NULL) return ad->horkage; - if (!strn_pattern_cmp(ad->model_rev, model_rev, '*')) + if (!glob_match(model_rev, ad->model_rev)) return ad->horkage; } ad++; -- 2.20.1