enumerator: Add enumerator to enumerate files matching a pattern
authorTobias Brunner <tobias@strongswan.org>
Wed, 4 Sep 2013 16:14:29 +0000 (18:14 +0200)
committerTobias Brunner <tobias@strongswan.org>
Thu, 15 May 2014 09:28:05 +0000 (11:28 +0200)
This enumerator is a wrapper around glob(3).  If that function is not
supported NULL is returned.  If no files match or an error occurs during
the pattern expansion an error is logged and the enumerator simply returns
no items.

RFC: if GLOB_ERR is not supplied glob returns GLOB_NOMATCH if e.g. the
base directory of the pattern does not exist, which would otherwise
result in an error. This way there is at least a clear error message in
case of a typo.

src/libstrongswan/collections/enumerator.c
src/libstrongswan/collections/enumerator.h

index 8049ac0..0c97f79 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 Tobias Brunner
+ * Copyright (C) 2008-2013 Tobias Brunner
  * Copyright (C) 2007 Martin Willi
  * Hochschule fuer Technik Rapperswil
  *
 #include <errno.h>
 #include <string.h>
 
+#ifdef HAVE_GLOB_H
+#include <glob.h>
+#endif /* HAVE_GLOB_H */
+
 #include <utils/debug.h>
 
 /**
@@ -157,8 +161,106 @@ enumerator_t* enumerator_create_directory(const char *path)
        return &this->public;
 }
 
+#ifdef HAVE_GLOB_H
+
 /**
- * Enumerator implementation for directory enumerator
+ * Enumerator implementation for glob enumerator
+ */
+typedef struct {
+       /** implements enumerator_t */
+       enumerator_t public;
+       /** glob data */
+       glob_t glob;
+       /** current match */
+       char **match;
+       /** absolute path of current file */
+       char full[PATH_MAX];
+} glob_enum_t;
+
+/**
+ * Implementation of enumerator_create_glob().destroy
+ */
+static void destroy_glob_enum(glob_enum_t *this)
+{
+       globfree(&this->glob);
+       free(this);
+}
+
+/**
+ * Implementation of enumerator_create_glob().enumerate
+ */
+static bool enumerate_glob_enum(glob_enum_t *this, char **file, struct stat *st)
+{
+       char *match = *(++this->match);
+
+       if (!match)
+       {
+               return FALSE;
+       }
+       if (file)
+       {
+               *file = match;
+       }
+       if (st)
+       {
+               if (stat(match, st))
+               {
+                       DBG1(DBG_LIB, "stat() on '%s' failed: %s", match,
+                                strerror(errno));
+                       return FALSE;
+               }
+       }
+       return TRUE;
+}
+
+/**
+ * See header
+ */
+enumerator_t* enumerator_create_glob(const char *pattern)
+{
+       glob_enum_t *this;
+       int status;
+
+       if (!pattern)
+       {
+               return enumerator_create_empty();
+       }
+
+       INIT(this,
+               .public = {
+                       .enumerate = (void*)enumerate_glob_enum,
+                       .destroy = (void*)destroy_glob_enum,
+               },
+               .glob = {
+                       .gl_offs = 1, /* reserve one slot so we can enumerate easily */
+               }
+       );
+
+       status = glob(pattern, GLOB_DOOFFS | GLOB_ERR, NULL, &this->glob);
+       if (status == GLOB_NOMATCH)
+       {
+               DBG1(DBG_LIB, "no files found matching '%s'", pattern);
+       }
+       else if (status != 0)
+       {
+               DBG1(DBG_LIB, "expanding file pattern '%s' failed: %s", pattern,
+                        strerror(errno));
+       }
+       this->match = this->glob.gl_pathv;
+       return &this->public;
+}
+
+#else /* HAVE_GLOB_H */
+
+enumerator_t* enumerator_create_glob(const char *pattern)
+{
+       return NULL;
+}
+
+#endif /* HAVE_GLOB_H */
+
+/**
+ * Enumerator implementation for token enumerator
  */
 typedef struct {
        /** implements enumerator_t */
index 299373a..55f8d83 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2013 Tobias Brunner
  * Copyright (C) 2007 Martin Willi
  * Hochschule fuer Technik Rapperswil
  *
@@ -69,7 +70,9 @@ enumerator_t *enumerator_create_single(void *item, void (*cleanup)(void *item));
  * This enumerator_t.enumerate() function returns a (to the directory) relative
  * filename (as a char*), an absolute filename (as a char*) and a file status
  * (to a struct stat), which all may be NULL. "." and ".." entries are
- * skipped. Example:
+ * skipped.
+ *
+ * Example:
  *
  * @code
        char *rel, *abs;
@@ -96,6 +99,38 @@ enumerator_t *enumerator_create_single(void *item, void (*cleanup)(void *item));
 enumerator_t* enumerator_create_directory(const char *path);
 
 /**
+ * Create an enumerator over files/directories matching a file pattern.
+ *
+ * This enumerator_t.enumerate() function returns the filename (as a char*),
+ * and a file status (to a struct stat), which both may be NULL.
+ *
+ * Example:
+ *
+ * @code
+       char *file;
+       struct stat st;
+       enumerator_t *e;
+
+       e = enumerator_create_glob("/etc/ipsec.*.conf");
+       if (e)
+       {
+               while (e->enumerate(e, &file, &st))
+               {
+                       if (S_ISREG(st.st_mode))
+                       {
+                               printf("%s\n", file);
+                       }
+               }
+               e->destroy(e);
+       }
+   @endcode
+ *
+ * @param pattern      file pattern to match
+ * @return                     the enumerator, NULL if not supported
+ */
+enumerator_t* enumerator_create_glob(const char *pattern);
+
+/**
  * Create an enumerator over tokens of a string.
  *
  * Tokens are separated by one of the characters in sep and trimmed by the