0c97f796fe75c044aae8ef0c26301c645c3b8df3
[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 /** current match */
175 char **match;
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 = *(++this->match);
195
196 if (!match)
197 {
198 return FALSE;
199 }
200 if (file)
201 {
202 *file = match;
203 }
204 if (st)
205 {
206 if (stat(match, st))
207 {
208 DBG1(DBG_LIB, "stat() on '%s' failed: %s", match,
209 strerror(errno));
210 return FALSE;
211 }
212 }
213 return TRUE;
214 }
215
216 /**
217 * See header
218 */
219 enumerator_t* enumerator_create_glob(const char *pattern)
220 {
221 glob_enum_t *this;
222 int status;
223
224 if (!pattern)
225 {
226 return enumerator_create_empty();
227 }
228
229 INIT(this,
230 .public = {
231 .enumerate = (void*)enumerate_glob_enum,
232 .destroy = (void*)destroy_glob_enum,
233 },
234 .glob = {
235 .gl_offs = 1, /* reserve one slot so we can enumerate easily */
236 }
237 );
238
239 status = glob(pattern, GLOB_DOOFFS | GLOB_ERR, NULL, &this->glob);
240 if (status == GLOB_NOMATCH)
241 {
242 DBG1(DBG_LIB, "no files found matching '%s'", pattern);
243 }
244 else if (status != 0)
245 {
246 DBG1(DBG_LIB, "expanding file pattern '%s' failed: %s", pattern,
247 strerror(errno));
248 }
249 this->match = this->glob.gl_pathv;
250 return &this->public;
251 }
252
253 #else /* HAVE_GLOB_H */
254
255 enumerator_t* enumerator_create_glob(const char *pattern)
256 {
257 return NULL;
258 }
259
260 #endif /* HAVE_GLOB_H */
261
262 /**
263 * Enumerator implementation for token enumerator
264 */
265 typedef struct {
266 /** implements enumerator_t */
267 enumerator_t public;
268 /** string to parse */
269 char *string;
270 /** current position */
271 char *pos;
272 /** separater chars */
273 const char *sep;
274 /** trim chars */
275 const char *trim;
276 } token_enum_t;
277
278 /**
279 * Implementation of enumerator_create_token().destroy
280 */
281 static void destroy_token_enum(token_enum_t *this)
282 {
283 free(this->string);
284 free(this);
285 }
286
287 /**
288 * Implementation of enumerator_create_token().enumerate
289 */
290 static bool enumerate_token_enum(token_enum_t *this, char **token)
291 {
292 const char *sep, *trim;
293 char *pos = NULL, *tmp;
294 bool last = FALSE;
295
296 /* trim leading characters/separators */
297 while (*this->pos)
298 {
299 trim = this->trim;
300 while (*trim)
301 {
302 if (*trim == *this->pos)
303 {
304 this->pos++;
305 break;
306 }
307 trim++;
308 }
309 sep = this->sep;
310 while (*sep)
311 {
312 if (*sep == *this->pos)
313 {
314 this->pos++;
315 break;
316 }
317 sep++;
318 }
319 if (!*trim && !*sep)
320 {
321 break;
322 }
323 }
324
325 switch (*this->pos)
326 {
327 case '"':
328 case '\'':
329 {
330 /* read quoted token */
331 tmp = strchr(this->pos + 1, *this->pos);
332 if (tmp)
333 {
334 *token = this->pos + 1;
335 *tmp = '\0';
336 this->pos = tmp + 1;
337 return TRUE;
338 }
339 /* unterminated string, FALL-THROUGH */
340 }
341 default:
342 {
343 /* find nearest separator */
344 sep = this->sep;
345 while (*sep)
346 {
347 tmp = strchr(this->pos, *sep);
348 if (tmp && (pos == NULL || tmp < pos))
349 {
350 pos = tmp;
351 }
352 sep++;
353 }
354 *token = this->pos;
355 if (pos)
356 {
357 *pos = '\0';
358 this->pos = pos + 1;
359 }
360 else
361 {
362 last = TRUE;
363 pos = this->pos = strchr(this->pos, '\0');
364 }
365 break;
366 }
367 }
368
369 /* trim trailing characters */
370 pos--;
371 while (pos >= *token)
372 {
373 trim = this->trim;
374 while (*trim)
375 {
376 if (*trim == *pos)
377 {
378 *(pos--) = '\0';
379 break;
380 }
381 trim++;
382 }
383 if (!*trim)
384 {
385 break;
386 }
387 }
388
389 if (!last || pos >= *token)
390 {
391 return TRUE;
392 }
393 return FALSE;
394 }
395
396 /**
397 * See header
398 */
399 enumerator_t* enumerator_create_token(const char *string, const char *sep,
400 const char *trim)
401 {
402 token_enum_t *enumerator = malloc_thing(token_enum_t);
403
404 enumerator->public.enumerate = (void*)enumerate_token_enum;
405 enumerator->public.destroy = (void*)destroy_token_enum;
406 enumerator->string = strdup(string);
407 enumerator->pos = enumerator->string;
408 enumerator->sep = sep;
409 enumerator->trim = trim;
410
411 return &enumerator->public;
412 }
413
414 /**
415 * enumerator for nested enumerations
416 */
417 typedef struct {
418 /* implements enumerator_t */
419 enumerator_t public;
420 /* outer enumerator */
421 enumerator_t *outer;
422 /* inner enumerator */
423 enumerator_t *inner;
424 /* constructor for inner enumerator */
425 enumerator_t *(*create_inner)(void *outer, void *data);
426 /* data to pass to constructor above */
427 void *data;
428 /* destructor for data */
429 void (*destroy_data)(void *data);
430 } nested_enumerator_t;
431
432
433 /**
434 * Implementation of enumerator_create_nested().enumerate()
435 */
436 static bool enumerate_nested(nested_enumerator_t *this, void *v1, void *v2,
437 void *v3, void *v4, void *v5)
438 {
439 while (TRUE)
440 {
441 while (this->inner == NULL)
442 {
443 void *outer;
444
445 if (!this->outer->enumerate(this->outer, &outer))
446 {
447 return FALSE;
448 }
449 this->inner = this->create_inner(outer, this->data);
450 }
451 if (this->inner->enumerate(this->inner, v1, v2, v3, v4, v5))
452 {
453 return TRUE;
454 }
455 this->inner->destroy(this->inner);
456 this->inner = NULL;
457 }
458 }
459
460 /**
461 * Implementation of enumerator_create_nested().destroy()
462 **/
463 static void destroy_nested(nested_enumerator_t *this)
464 {
465 if (this->destroy_data)
466 {
467 this->destroy_data(this->data);
468 }
469 DESTROY_IF(this->inner);
470 this->outer->destroy(this->outer);
471 free(this);
472 }
473
474 /**
475 * See header
476 */
477 enumerator_t *enumerator_create_nested(enumerator_t *outer,
478 enumerator_t *(inner_constructor)(void *outer, void *data),
479 void *data, void (*destroy_data)(void *data))
480 {
481 nested_enumerator_t *enumerator = malloc_thing(nested_enumerator_t);
482
483 enumerator->public.enumerate = (void*)enumerate_nested;
484 enumerator->public.destroy = (void*)destroy_nested;
485 enumerator->outer = outer;
486 enumerator->inner = NULL;
487 enumerator->create_inner = (void*)inner_constructor;
488 enumerator->data = data;
489 enumerator->destroy_data = destroy_data;
490
491 return &enumerator->public;
492 }
493
494 /**
495 * enumerator for filtered enumerator
496 */
497 typedef struct {
498 enumerator_t public;
499 enumerator_t *unfiltered;
500 void *data;
501 bool (*filter)(void *data, ...);
502 void (*destructor)(void *data);
503 } filter_enumerator_t;
504
505 /**
506 * Implementation of enumerator_create_filter().destroy
507 */
508 static void destroy_filter(filter_enumerator_t *this)
509 {
510 if (this->destructor)
511 {
512 this->destructor(this->data);
513 }
514 this->unfiltered->destroy(this->unfiltered);
515 free(this);
516 }
517
518 /**
519 * Implementation of enumerator_create_filter().enumerate
520 */
521 static bool enumerate_filter(filter_enumerator_t *this, void *o1, void *o2,
522 void *o3, void *o4, void *o5)
523 {
524 void *i1, *i2, *i3, *i4, *i5;
525
526 while (this->unfiltered->enumerate(this->unfiltered, &i1, &i2, &i3, &i4, &i5))
527 {
528 if (this->filter(this->data, &i1, o1, &i2, o2, &i3, o3, &i4, o4, &i5, o5))
529 {
530 return TRUE;
531 }
532 }
533 return FALSE;
534 }
535
536 /**
537 * see header
538 */
539 enumerator_t *enumerator_create_filter(enumerator_t *unfiltered,
540 bool (*filter)(void *data, ...),
541 void *data, void (*destructor)(void *data))
542 {
543 filter_enumerator_t *this = malloc_thing(filter_enumerator_t);
544
545 this->public.enumerate = (void*)enumerate_filter;
546 this->public.destroy = (void*)destroy_filter;
547 this->unfiltered = unfiltered;
548 this->filter = filter;
549 this->data = data;
550 this->destructor = destructor;
551
552 return &this->public;
553 }
554
555 /**
556 * enumerator for cleaner enumerator
557 */
558 typedef struct {
559 enumerator_t public;
560 enumerator_t *wrapped;
561 void (*cleanup)(void *data);
562 void *data;
563 } cleaner_enumerator_t;
564
565 /**
566 * Implementation of enumerator_create_cleanup().destroy
567 */
568 static void destroy_cleaner(cleaner_enumerator_t *this)
569 {
570 this->cleanup(this->data);
571 this->wrapped->destroy(this->wrapped);
572 free(this);
573 }
574
575 /**
576 * Implementation of enumerator_create_cleaner().enumerate
577 */
578 static bool enumerate_cleaner(cleaner_enumerator_t *this, void *v1, void *v2,
579 void *v3, void *v4, void *v5)
580 {
581 return this->wrapped->enumerate(this->wrapped, v1, v2, v3, v4, v5);
582 }
583
584 /**
585 * see header
586 */
587 enumerator_t *enumerator_create_cleaner(enumerator_t *wrapped,
588 void (*cleanup)(void *data), void *data)
589 {
590 cleaner_enumerator_t *this = malloc_thing(cleaner_enumerator_t);
591
592 this->public.enumerate = (void*)enumerate_cleaner;
593 this->public.destroy = (void*)destroy_cleaner;
594 this->wrapped = wrapped;
595 this->cleanup = cleanup;
596 this->data = data;
597
598 return &this->public;
599 }
600
601 /**
602 * enumerator for single enumerator
603 */
604 typedef struct {
605 enumerator_t public;
606 void *item;
607 void (*cleanup)(void *item);
608 bool done;
609 } single_enumerator_t;
610
611 /**
612 * Implementation of enumerator_create_single().destroy
613 */
614 static void destroy_single(single_enumerator_t *this)
615 {
616 if (this->cleanup)
617 {
618 this->cleanup(this->item);
619 }
620 free(this);
621 }
622
623 /**
624 * Implementation of enumerator_create_single().enumerate
625 */
626 static bool enumerate_single(single_enumerator_t *this, void **item)
627 {
628 if (this->done)
629 {
630 return FALSE;
631 }
632 *item = this->item;
633 this->done = TRUE;
634 return TRUE;
635 }
636
637 /**
638 * see header
639 */
640 enumerator_t *enumerator_create_single(void *item, void (*cleanup)(void *item))
641 {
642 single_enumerator_t *this = malloc_thing(single_enumerator_t);
643
644 this->public.enumerate = (void*)enumerate_single;
645 this->public.destroy = (void*)destroy_single;
646 this->item = item;
647 this->cleanup = cleanup;
648 this->done = FALSE;
649
650 return &this->public;
651 }
652