]> git.ipfire.org Git - thirdparty/libsolv.git/commitdiff
Support custom filelist filters.
authorMichael Schroeder <mls@suse.de>
Mon, 10 Sep 2018 09:44:52 +0000 (11:44 +0200)
committerMichael Schroeder <mls@suse.de>
Mon, 10 Sep 2018 09:44:52 +0000 (11:44 +0200)
REPOSITORY_FILTEREDFILELIST can now be an idarray where each
element is a glob pattern.

src/filelistfilter.c
src/repodata.c
src/repodata.h

index 4dacdbe377ccf0c62f9d7527d6052c836dd9a778..e698d6fac8b5a067ba445649c6707dc6a41bcdd6 100644 (file)
 #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;
 }
 
index 421f914b9045bbe6e62eeb0f034b9934173a2a5f..aca80a3e7e2f410e2befbb765f5edf0921b893c1 100644 (file)
@@ -94,6 +94,8 @@ repodata_freedata(Repodata *data)
   solv_free(data->attrnum64data);
 
   solv_free(data->dircache);
+
+  repodata_free_filelistfilter(data);
 }
 
 void
index f377a31f3be345febc904f5a16709284cb5b37f3..9dcfc7295b3fdbc122ad034cc0c6010dea9bd6a3 100644 (file)
@@ -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);