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