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