From: Michael Schroeder Date: Mon, 10 Sep 2018 09:44:52 +0000 (+0200) Subject: Support custom filelist filters. X-Git-Tag: 0.7.0~54 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7d71a88d3b55b21b69c24f7834283d116edb3bd9;p=thirdparty%2Flibsolv.git Support custom filelist filters. REPOSITORY_FILTEREDFILELIST can now be an idarray where each element is a glob pattern. --- diff --git a/src/filelistfilter.c b/src/filelistfilter.c index 4dacdbe3..e698d6fa 100644 --- a/src/filelistfilter.c +++ b/src/filelistfilter.c @@ -24,17 +24,173 @@ #include "pool.h" #include "util.h" +static Id default_filelist_filter; + +#define FF_EXACT 0 +#define FF_END 1 +#define FF_START 2 +#define FF_SUB 3 /* FF_END | FF_START */ +#define FF_GLOB 4 +#define FF_START5 5 + +void +repodata_free_filelistfilter(Repodata *data) +{ + if (data->filelistfilter) + { + if (data->filelistfilter != &default_filelist_filter) + solv_free(data->filelistfilter); + data->filelistfilter = 0; + } + data->filelistfilterdata = solv_free(data->filelistfilterdata); +} + +static void +repodata_set_filelistfilter(Repodata *data) +{ + Id type; + Queue q; + int i, j; + char *filterdata; + int nfilterdata; + + if (data->filelistfilter && data->filelistfilter != &default_filelist_filter) + data->filelistfilter = solv_free(data->filelistfilter); + data->filelistfilterdata = solv_free(data->filelistfilterdata); + type = repodata_lookup_type(data, SOLVID_META, REPOSITORY_FILTEREDFILELIST); + if (type != REPOKEY_TYPE_IDARRAY) + { + data->filelistfilter = &default_filelist_filter; + return; + } + queue_init(&q); + repodata_lookup_idarray(data, SOLVID_META, REPOSITORY_FILTEREDFILELIST, &q); + if (q.count == 3) + { + /* check if this is the default filter */ + int t = 0; + for (i = 0; i < 3; i++) + { + Id id = q.elements[i]; + const char *g = data->localpool ? stringpool_id2str(&data->spool, id) : pool_id2str(data->repo->pool, id); + if (!strcmp(g, "*bin/*")) + t |= 1; + else if (!strcmp(g, "/etc/*")) + t |= 2; + else if (!strcmp(g, "/usr/lib/sendmail")) + t |= 4; + } + if (t == 7) + { + queue_free(&q); + data->filelistfilter = &default_filelist_filter; + return; + } + } + data->filelistfilter = solv_calloc(q.count * 2 + 1, sizeof(Id)); + filterdata = solv_calloc_block(1, 1, 255); + nfilterdata = 1; + + for (i = j = 0; i < q.count; i++) + { + Id id = q.elements[i]; + const char *g = data->localpool ? stringpool_id2str(&data->spool, id) : pool_id2str(data->repo->pool, id); + const char *p; + int t = FF_EXACT; + int gl; + if (!id || !g || !*g) + continue; + for (p = g; *p && t != FF_GLOB; p++) + { + if (*p == '*') + { + if (p == g) + t |= FF_END; + else if (!p[1]) + t |= FF_START; + else + t = FF_GLOB; + } + else if (*p == '[' || *p == '?') + t = FF_GLOB; + } + gl = strlen(g); + if (t == FF_END) /* not supported */ + t = FF_GLOB; + if (t == FF_START && gl == 5) + t = FF_START5; + filterdata = solv_extend(filterdata, nfilterdata, gl + 1, 1, 255); + data->filelistfilter[j++] = nfilterdata; + data->filelistfilter[j++] = t; + switch (t) + { + case FF_START: + case FF_START5: + strcpy(filterdata + nfilterdata, g); + filterdata[nfilterdata + gl - 1] = 0; + nfilterdata += gl; + break; + case FF_SUB: + strcpy(filterdata + nfilterdata, g + 1); + filterdata[nfilterdata + gl - 2] = 0; + nfilterdata += gl - 1; + break; + default: + strcpy(filterdata + nfilterdata, g); + nfilterdata += gl + 1; + break; + } + } + filterdata = solv_realloc(filterdata, nfilterdata); + data->filelistfilter[j++] = 0; + data->filelistfilterdata = filterdata; + queue_free(&q); +} + int repodata_filelistfilter_matches(Repodata *data, const char *str) { - /* '.*bin\/.*', '^\/etc\/.*', '^\/usr\/lib\/sendmail$' */ - /* for now hardcoded */ - if (strstr(str, "bin/")) - return 1; - if (!strncmp(str, "/etc/", 5)) - return 1; - if (!strcmp(str, "/usr/lib/sendmail")) - return 1; + Id *ff; + if (data && !data->filelistfilter) + repodata_set_filelistfilter(data); + if (!data || data->filelistfilter == &default_filelist_filter) + { + /* '.*bin\/.*', '^\/etc\/.*', '^\/usr\/lib\/sendmail$' */ + if (strstr(str, "bin/")) + return 1; + if (!strncmp(str, "/etc/", 5)) + return 1; + if (!strcmp(str, "/usr/lib/sendmail")) + return 1; + return 0; + } + for (ff = data->filelistfilter; *ff; ff += 2) + { + const char *g = data->filelistfilterdata + *ff; + switch (ff[1]) + { + case FF_EXACT: + if (!strcmp(str, g)) + return 1; + break; + case FF_START: + if (!strncmp(str, g, strlen(g))) + return 1; + break; + case FF_SUB: + if (!strstr(str, g)) + return 1; + break; + case FF_START5: + if (!strncmp(str, g, 5)) + return 1; + break; + default: + if (!fnmatch(g, str, 0)) + return 1; + break; + } + } return 0; } diff --git a/src/repodata.c b/src/repodata.c index 421f914b..aca80a3e 100644 --- a/src/repodata.c +++ b/src/repodata.c @@ -94,6 +94,8 @@ repodata_freedata(Repodata *data) solv_free(data->attrnum64data); solv_free(data->dircache); + + repodata_free_filelistfilter(data); } void diff --git a/src/repodata.h b/src/repodata.h index f377a31f..9dcfc729 100644 --- a/src/repodata.h +++ b/src/repodata.h @@ -95,6 +95,8 @@ typedef struct _Repodata { int error; /* corrupt solv file */ int filelisttype; /* type of filelist */ + Id *filelistfilter; /* filelist filter used */ + char *filelistfilterdata; /* filelist filter string space */ unsigned int schemadatalen; /* schema storage size */ Id *schematahash; /* unification helper */ @@ -215,6 +217,7 @@ const char *repodata_stringify(Pool *pool, Repodata *data, Repokey *key, struct /* filelist filter support */ void repodata_set_filelisttype(Repodata *data, int filelisttype); int repodata_filelistfilter_matches(Repodata *data, const char *str); +void repodata_free_filelistfilter(Repodata *data); /* lookup functions */ Id repodata_lookup_type(Repodata *data, Id solvid, Id keyname);