enumerator: Enumerate glob(3) matches using gl_pathc
[strongswan.git] / src / libstrongswan / collections / enumerator.c
1 /*
2 * Copyright (C) 2008-2013 Tobias Brunner
3 * Copyright (C) 2007 Martin Willi
4 * Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #include "enumerator.h"
18
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <unistd.h>
22 #include <limits.h>
23 #include <stdio.h>
24 #include <dirent.h>
25 #include <errno.h>
26 #include <string.h>
27
28 #ifdef HAVE_GLOB_H
29 #include <glob.h>
30 #endif /* HAVE_GLOB_H */
31
32 #include <utils/debug.h>
33
34 /**
35 * Implementation of enumerator_create_empty().enumerate
36 */
37 static bool enumerate_empty(enumerator_t *enumerator, ...)
38 {
39 return FALSE;
40 }
41
42 /**
43 * See header
44 */
45 enumerator_t* enumerator_create_empty()
46 {
47 enumerator_t *this = malloc_thing(enumerator_t);
48 this->enumerate = enumerate_empty;
49 this->destroy = (void*)free;
50 return this;
51 }
52
53 /**
54 * Enumerator implementation for directory enumerator
55 */
56 typedef struct {
57 /** implements enumerator_t */
58 enumerator_t public;
59 /** directory handle */
60 DIR *dir;
61 /** absolute path of current file */
62 char full[PATH_MAX];
63 /** where directory part of full ends and relative file gets written */
64 char *full_end;
65 } dir_enum_t;
66
67 /**
68 * Implementation of enumerator_create_directory().destroy
69 */
70 static void destroy_dir_enum(dir_enum_t *this)
71 {
72 closedir(this->dir);
73 free(this);
74 }
75
76 /**
77 * Implementation of enumerator_create_directory().enumerate
78 */
79 static bool enumerate_dir_enum(dir_enum_t *this, char **relative,
80 char **absolute, struct stat *st)
81 {
82 struct dirent *entry = readdir(this->dir);
83 size_t remaining;
84 int len;
85
86 if (!entry)
87 {
88 return FALSE;
89 }
90 if (streq(entry->d_name, ".") || streq(entry->d_name, ".."))
91 {
92 return enumerate_dir_enum(this, relative, absolute, st);
93 }
94 if (relative)
95 {
96 *relative = entry->d_name;
97 }
98 if (absolute || st)
99 {
100 remaining = sizeof(this->full) - (this->full_end - this->full);
101 len = snprintf(this->full_end, remaining, "%s", entry->d_name);
102 if (len < 0 || len >= remaining)
103 {
104 DBG1(DBG_LIB, "buffer too small to enumerate file '%s'",
105 entry->d_name);
106 return FALSE;
107 }
108 if (absolute)
109 {
110 *absolute = this->full;
111 }
112 if (st)
113 {
114 if (stat(this->full, st))
115 {
116 DBG1(DBG_LIB, "stat() on '%s' failed: %s", this->full,
117 strerror(errno));
118 return FALSE;
119 }
120 }
121 }
122 return TRUE;
123 }
124
125 /**
126 * See header
127 */
128 enumerator_t* enumerator_create_directory(const char *path)
129 {
130 int len;
131 dir_enum_t *this = malloc_thing(dir_enum_t);
132 this->public.enumerate = (void*)enumerate_dir_enum;
133 this->public.destroy = (void*)destroy_dir_enum;
134
135 if (*path == '\0')
136 {
137 path = "./";
138 }
139 len = snprintf(this->full, sizeof(this->full)-1, "%s", path);
140 if (len < 0 || len >= sizeof(this->full)-1)
141 {
142 DBG1(DBG_LIB, "path string '%s' too long", path);
143 free(this);
144 return NULL;
145 }
146 /* append a '/' if not already done */
147 if (this->full[len-1] != '/')
148 {
149 this->full[len++] = '/';
150 this->full[len] = '\0';
151 }
152 this->full_end = &this->full[len];
153
154 this->dir = opendir(path);
155 if (this->dir == NULL)
156 {
157 DBG1(DBG_LIB, "opening directory '%s' failed: %s", path, strerror(errno));
158 free(this);
159 return NULL;
160 }
161 return &this->public;
162 }
163
164 #ifdef HAVE_GLOB_H
165
166 /**
167 * Enumerator implementation for glob enumerator
168 */
169 typedef struct {
170 /** implements enumerator_t */
171 enumerator_t public;
172 /** glob data */
173 glob_t glob;
174 /** iteration count */
175 u_int pos;
176 /** absolute path of current file */
177 char full[PATH_MAX];
178 } glob_enum_t;
179
180 /**
181 * Implementation of enumerator_create_glob().destroy
182 */
183 static void destroy_glob_enum(glob_enum_t *this)
184 {
185 globfree(&this->glob);
186 free(this);
187 }
188
189 /**
190 * Implementation of enumerator_create_glob().enumerate
191 */
192 static bool enumerate_glob_enum(glob_enum_t *this, char **file, struct stat *st)
193 {
194 char *match;
195
196 if (this->pos >= this->glob.gl_pathc)
197 {
198 return FALSE;
199 }
200 match = this->glob.gl_pathv[this->pos++];
201 if (file)
202 {
203 *file = match;
204 }
205 if (st)
206 {
207 if (stat(match, st))
208 {
209 DBG1(DBG_LIB, "stat() on '%s' failed: %s", match,
210 strerror(errno));
211 return FALSE;
212 }
213 }
214 return TRUE;
215 }
216
217 /**
218 * See header
219 */
220 enumerator_t* enumerator_create_glob(const char *pattern)
221 {
222 glob_enum_t *this;
223 int status;
224
225 if (!pattern)
226 {
227 return enumerator_create_empty();
228 }
229
230 INIT(this,
231 .public = {
232 .enumerate = (void*)enumerate_glob_enum,
233 .destroy = (void*)destroy_glob_enum,
234 },
235 );
236
237 status = glob(pattern, GLOB_ERR, NULL, &this->glob);
238 if (status == GLOB_NOMATCH)
239 {
240 DBG1(DBG_LIB, "no files found matching '%s'", pattern);
241 }
242 else if (status != 0)
243 {
244 DBG1(DBG_LIB, "expanding file pattern '%s' failed: %s", pattern,
245 strerror(errno));
246 }
247 return &this->public;
248 }
249
250 #else /* HAVE_GLOB_H */
251
252 enumerator_t* enumerator_create_glob(const char *pattern)
253 {
254 return NULL;
255 }
256
257 #endif /* HAVE_GLOB_H */
258
259 /**
260 * Enumerator implementation for token enumerator
261 */
262 typedef struct {
263 /** implements enumerator_t */
264 enumerator_t public;
265 /** string to parse */
266 char *string;
267 /** current position */
268 char *pos;
269 /** separater chars */
270 const char *sep;
271 /** trim chars */
272 const char *trim;
273 } token_enum_t;
274
275 /**
276 * Implementation of enumerator_create_token().destroy
277 */
278 static void destroy_token_enum(token_enum_t *this)
279 {
280 free(this->string);
281 free(this);
282 }
283
284 /**
285 * Implementation of enumerator_create_token().enumerate
286 */
287 static bool enumerate_token_enum(token_enum_t *this, char **token)
288 {
289 const char *sep, *trim;
290 char *pos = NULL, *tmp;
291 bool last = FALSE;
292
293 /* trim leading characters/separators */
294 while (*this->pos)
295 {
296 trim = this->trim;
297 while (*trim)
298 {
299 if (*trim == *this->pos)
300 {
301 this->pos++;
302 break;
303 }
304 trim++;
305 }
306 sep = this->sep;
307 while (*sep)
308 {
309 if (*sep == *this->pos)
310 {
311 this->pos++;
312 break;
313 }
314 sep++;
315 }
316 if (!*trim && !*sep)
317 {
318 break;
319 }
320 }
321
322 switch (*this->pos)
323 {
324 case '"':
325 case '\'':
326 {
327 /* read quoted token */
328 tmp = strchr(this->pos + 1, *this->pos);
329 if (tmp)
330 {
331 *token = this->pos + 1;
332 *tmp = '\0';
333 this->pos = tmp + 1;
334 return TRUE;
335 }
336 /* unterminated string, FALL-THROUGH */
337 }
338 default:
339 {
340 /* find nearest separator */
341 sep = this->sep;
342 while (*sep)
343 {
344 tmp = strchr(this->pos, *sep);
345 if (tmp && (pos == NULL || tmp < pos))
346 {
347 pos = tmp;
348 }
349 sep++;
350 }
351 *token = this->pos;
352 if (pos)
353 {
354 *pos = '\0';
355 this->pos = pos + 1;
356 }
357 else
358 {
359 last = TRUE;
360 pos = this->pos = strchr(this->pos, '\0');
361 }
362 break;
363 }
364 }
365
366 /* trim trailing characters */
367 pos--;
368 while (pos >= *token)
369 {
370 trim = this->trim;
371 while (*trim)
372 {
373 if (*trim == *pos)
374 {
375 *(pos--) = '\0';
376 break;
377 }
378 trim++;
379 }
380 if (!*trim)
381 {
382 break;
383 }
384 }
385
386 if (!last || pos >= *token)
387 {
388 return TRUE;
389 }
390 return FALSE;
391 }
392
393 /**
394 * See header
395 */
396 enumerator_t* enumerator_create_token(const char *string, const char *sep,
397 const char *trim)
398 {
399 token_enum_t *enumerator = malloc_thing(token_enum_t);
400
401 enumerator->public.enumerate = (void*)enumerate_token_enum;
402 enumerator->public.destroy = (void*)destroy_token_enum;
403 enumerator->string = strdup(string);
404 enumerator->pos = enumerator->string;
405 enumerator->sep = sep;
406 enumerator->trim = trim;
407
408 return &enumerator->public;
409 }
410
411 /**
412 * enumerator for nested enumerations
413 */
414 typedef struct {
415 /* implements enumerator_t */
416 enumerator_t public;
417 /* outer enumerator */
418 enumerator_t *outer;
419 /* inner enumerator */
420 enumerator_t *inner;
421 /* constructor for inner enumerator */
422 enumerator_t *(*create_inner)(void *outer, void *data);
423 /* data to pass to constructor above */
424 void *data;
425 /* destructor for data */
426 void (*destroy_data)(void *data);
427 } nested_enumerator_t;
428
429
430 /**
431 * Implementation of enumerator_create_nested().enumerate()
432 */
433 static bool enumerate_nested(nested_enumerator_t *this, void *v1, void *v2,
434 void *v3, void *v4, void *v5)
435 {
436 while (TRUE)
437 {
438 while (this->inner == NULL)
439 {
440 void *outer;
441
442 if (!this->outer->enumerate(this->outer, &outer))
443 {
444 return FALSE;
445 }
446 this->inner = this->create_inner(outer, this->data);
447 }
448 if (this->inner->enumerate(this->inner, v1, v2, v3, v4, v5))
449 {
450 return TRUE;
451 }
452 this->inner->destroy(this->inner);
453 this->inner = NULL;
454 }
455 }
456
457 /**
458 * Implementation of enumerator_create_nested().destroy()
459 **/
460 static void destroy_nested(nested_enumerator_t *this)
461 {
462 if (this->destroy_data)
463 {
464 this->destroy_data(this->data);
465 }
466 DESTROY_IF(this->inner);
467 this->outer->destroy(this->outer);
468 free(this);
469 }
470
471 /**
472 * See header
473 */
474 enumerator_t *enumerator_create_nested(enumerator_t *outer,
475 enumerator_t *(inner_constructor)(void *outer, void *data),
476 void *data, void (*destroy_data)(void *data))
477 {
478 nested_enumerator_t *enumerator = malloc_thing(nested_enumerator_t);
479
480 enumerator->public.enumerate = (void*)enumerate_nested;
481 enumerator->public.destroy = (void*)destroy_nested;
482 enumerator->outer = outer;
483 enumerator->inner = NULL;
484 enumerator->create_inner = (void*)inner_constructor;
485 enumerator->data = data;
486 enumerator->destroy_data = destroy_data;
487
488 return &enumerator->public;
489 }
490
491 /**
492 * enumerator for filtered enumerator
493 */
494 typedef struct {
495 enumerator_t public;
496 enumerator_t *unfiltered;
497 void *data;
498 bool (*filter)(void *data, ...);
499 void (*destructor)(void *data);
500 } filter_enumerator_t;
501
502 /**
503 * Implementation of enumerator_create_filter().destroy
504 */
505 static void destroy_filter(filter_enumerator_t *this)
506 {
507 if (this->destructor)
508 {
509 this->destructor(this->data);
510 }
511 this->unfiltered->destroy(this->unfiltered);
512 free(this);
513 }
514
515 /**
516 * Implementation of enumerator_create_filter().enumerate
517 */
518 static bool enumerate_filter(filter_enumerator_t *this, void *o1, void *o2,
519 void *o3, void *o4, void *o5)
520 {
521 void *i1, *i2, *i3, *i4, *i5;
522
523 while (this->unfiltered->enumerate(this->unfiltered, &i1, &i2, &i3, &i4, &i5))
524 {
525 if (this->filter(this->data, &i1, o1, &i2, o2, &i3, o3, &i4, o4, &i5, o5))
526 {
527 return TRUE;
528 }
529 }
530 return FALSE;
531 }
532
533 /**
534 * see header
535 */
536 enumerator_t *enumerator_create_filter(enumerator_t *unfiltered,
537 bool (*filter)(void *data, ...),
538 void *data, void (*destructor)(void *data))
539 {
540 filter_enumerator_t *this = malloc_thing(filter_enumerator_t);
541
542 this->public.enumerate = (void*)enumerate_filter;
543 this->public.destroy = (void*)destroy_filter;
544 this->unfiltered = unfiltered;
545 this->filter = filter;
546 this->data = data;
547 this->destructor = destructor;
548
549 return &this->public;
550 }
551
552 /**
553 * enumerator for cleaner enumerator
554 */
555 typedef struct {
556 enumerator_t public;
557 enumerator_t *wrapped;
558 void (*cleanup)(void *data);
559 void *data;
560 } cleaner_enumerator_t;
561
562 /**
563 * Implementation of enumerator_create_cleanup().destroy
564 */
565 static void destroy_cleaner(cleaner_enumerator_t *this)
566 {
567 this->cleanup(this->data);
568 this->wrapped->destroy(this->wrapped);
569 free(this);
570 }
571
572 /**
573 * Implementation of enumerator_create_cleaner().enumerate
574 */
575 static bool enumerate_cleaner(cleaner_enumerator_t *this, void *v1, void *v2,
576 void *v3, void *v4, void *v5)
577 {
578 return this->wrapped->enumerate(this->wrapped, v1, v2, v3, v4, v5);
579 }
580
581 /**
582 * see header
583 */
584 enumerator_t *enumerator_create_cleaner(enumerator_t *wrapped,
585 void (*cleanup)(void *data), void *data)
586 {
587 cleaner_enumerator_t *this = malloc_thing(cleaner_enumerator_t);
588
589 this->public.enumerate = (void*)enumerate_cleaner;
590 this->public.destroy = (void*)destroy_cleaner;
591 this->wrapped = wrapped;
592 this->cleanup = cleanup;
593 this->data = data;
594
595 return &this->public;
596 }
597
598 /**
599 * enumerator for single enumerator
600 */
601 typedef struct {
602 enumerator_t public;
603 void *item;
604 void (*cleanup)(void *item);
605 bool done;
606 } single_enumerator_t;
607
608 /**
609 * Implementation of enumerator_create_single().destroy
610 */
611 static void destroy_single(single_enumerator_t *this)
612 {
613 if (this->cleanup)
614 {
615 this->cleanup(this->item);
616 }
617 free(this);
618 }
619
620 /**
621 * Implementation of enumerator_create_single().enumerate
622 */
623 static bool enumerate_single(single_enumerator_t *this, void **item)
624 {
625 if (this->done)
626 {
627 return FALSE;
628 }
629 *item = this->item;
630 this->done = TRUE;
631 return TRUE;
632 }
633
634 /**
635 * see header
636 */
637 enumerator_t *enumerator_create_single(void *item, void (*cleanup)(void *item))
638 {
639 single_enumerator_t *this = malloc_thing(single_enumerator_t);
640
641 this->public.enumerate = (void*)enumerate_single;
642 this->public.destroy = (void*)destroy_single;
643 this->item = item;
644 this->cleanup = cleanup;
645 this->done = FALSE;
646
647 return &this->public;
648 }
649