Annotation of embedaddon/strongswan/src/libstrongswan/collections/enumerator.c, revision 1.1.1.2
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>
1.1.1.2 ! misho 30: #elif defined(WIN32)
! 31: #include <fileapi.h>
1.1 misho 32: #endif /* HAVE_GLOB_H */
33:
34: #include <utils/debug.h>
35:
36: /*
37: * Described in header.
38: */
39: bool enumerator_enumerate_default(enumerator_t *enumerator, ...)
40: {
41: va_list args;
42: bool result;
43:
44: if (!enumerator->venumerate)
45: {
46: DBG1(DBG_LIB, "!!! ENUMERATE DEFAULT: venumerate() missing !!!");
47: return FALSE;
48: }
49: va_start(args, enumerator);
50: result = enumerator->venumerate(enumerator, args);
51: va_end(args);
52: return result;
53: }
54:
55: METHOD(enumerator_t, enumerate_empty, bool,
56: enumerator_t *enumerator, va_list args)
57: {
58: return FALSE;
59: }
60:
61: /*
62: * Described in header
63: */
64: enumerator_t* enumerator_create_empty()
65: {
66: enumerator_t *this;
67:
68: INIT(this,
69: .enumerate = enumerator_enumerate_default,
70: .venumerate = _enumerate_empty,
71: .destroy = (void*)free,
72: );
73: return this;
74: }
75:
76: /**
77: * Enumerator implementation for directory enumerator
78: */
79: typedef struct {
80: /** implements enumerator_t */
81: enumerator_t public;
82: /** directory handle */
83: DIR *dir;
84: /** absolute path of current file */
85: char full[PATH_MAX];
86: /** where directory part of full ends and relative file gets written */
87: char *full_end;
88: } dir_enum_t;
89:
90: METHOD(enumerator_t, destroy_dir_enum, void,
91: dir_enum_t *this)
92: {
93: closedir(this->dir);
94: free(this);
95: }
96:
97: METHOD(enumerator_t, enumerate_dir_enum, bool,
98: dir_enum_t *this, va_list args)
99: {
100: struct dirent *entry = readdir(this->dir);
101: struct stat *st;
102: size_t remaining;
103: char **relative, **absolute;
104: int len;
105:
106: VA_ARGS_VGET(args, relative, absolute, st);
107:
108: if (!entry)
109: {
110: return FALSE;
111: }
112: if (streq(entry->d_name, ".") || streq(entry->d_name, ".."))
113: {
114: return this->public.enumerate(&this->public, relative, absolute, st);
115: }
116: if (relative)
117: {
118: *relative = entry->d_name;
119: }
120: if (absolute || st)
121: {
122: remaining = sizeof(this->full) - (this->full_end - this->full);
123: len = snprintf(this->full_end, remaining, "%s", entry->d_name);
124: if (len < 0 || len >= remaining)
125: {
126: DBG1(DBG_LIB, "buffer too small to enumerate file '%s'",
127: entry->d_name);
128: return FALSE;
129: }
130: if (absolute)
131: {
132: *absolute = this->full;
133: }
134: if (st && stat(this->full, st))
135: {
136: /* try lstat() e.g. if a symlink is not valid anymore */
137: if ((errno != ENOENT && errno != ENOTDIR) || lstat(this->full, st))
138: {
139: DBG1(DBG_LIB, "stat() on '%s' failed: %s", this->full,
140: strerror(errno));
141: return FALSE;
142: }
143: }
144: }
145: return TRUE;
146: }
147:
148: /*
149: * Described in header
150: */
151: enumerator_t* enumerator_create_directory(const char *path)
152: {
153: dir_enum_t *this;
154: int len;
155:
156: INIT(this,
157: .public = {
158: .enumerate = enumerator_enumerate_default,
159: .venumerate = _enumerate_dir_enum,
160: .destroy = _destroy_dir_enum,
161: },
162: );
163:
164: if (*path == '\0')
165: {
166: path = "./";
167: }
168: len = snprintf(this->full, sizeof(this->full)-1, "%s", path);
169: if (len < 0 || len >= sizeof(this->full)-1)
170: {
171: DBG1(DBG_LIB, "path string '%s' too long", path);
172: free(this);
173: return NULL;
174: }
175: /* append a '/' if not already done */
1.1.1.2 ! misho 176: if (!path_is_separator(this->full[len-1]))
1.1 misho 177: {
1.1.1.2 ! misho 178: this->full[len++] = DIRECTORY_SEPARATOR[0];
1.1 misho 179: this->full[len] = '\0';
180: }
181: this->full_end = &this->full[len];
182:
183: this->dir = opendir(path);
184: if (!this->dir)
185: {
186: DBG1(DBG_LIB, "opening directory '%s' failed: %s", path,
187: strerror(errno));
188: free(this);
189: return NULL;
190: }
191: return &this->public;
192: }
193:
194: #ifdef HAVE_GLOB_H
195:
196: /**
197: * Enumerator implementation for glob enumerator
198: */
199: typedef struct {
200: /** implements enumerator_t */
201: enumerator_t public;
202: /** glob data */
203: glob_t glob;
204: /** iteration count */
205: u_int pos;
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:
1.1.1.2 ! misho 276: #elif defined(WIN32) /* HAVE_GLOB_H */
! 277:
! 278: /**
! 279: * Enumerator implementation for glob enumerator on Windows
! 280: */
! 281: typedef struct {
! 282: /** implements enumerator_t */
! 283: enumerator_t public;
! 284: /** search handle */
! 285: HANDLE handle;
! 286: /** current file path */
! 287: char path[PATH_MAX];
! 288: /** base path */
! 289: char *base;
! 290: } glob_enum_t;
! 291:
! 292: METHOD(enumerator_t, destroy_glob_enum, void,
! 293: glob_enum_t *this)
! 294: {
! 295: if (this->handle != INVALID_HANDLE_VALUE)
! 296: {
! 297: FindClose(this->handle);
! 298: }
! 299: free(this->base);
! 300: free(this);
! 301: }
! 302:
! 303: /**
! 304: * Create the combined path from the given file data
! 305: */
! 306: static bool combine_glob_path(glob_enum_t *this, WIN32_FIND_DATA *data)
! 307: {
! 308: if (snprintf(this->path, sizeof(this->path), "%s%s%s", this->base,
! 309: DIRECTORY_SEPARATOR, data->cFileName) >= sizeof(this->path))
! 310: {
! 311: DBG1(DBG_LIB, "path for '%s' too long, ignored", data->cFileName);
! 312: return FALSE;
! 313: }
! 314: return TRUE;
! 315: }
! 316:
! 317: /**
! 318: * Return the path and stat data for the current file
! 319: */
! 320: static bool enumerate_glob_enum_data(glob_enum_t *this, va_list args)
! 321: {
! 322: struct stat *st;
! 323: char **file;
! 324:
! 325: VA_ARGS_VGET(args, file, st);
! 326:
! 327: if (file)
! 328: {
! 329: *file = this->path;
! 330: }
! 331: if (st && stat(this->path, st))
! 332: {
! 333: DBG1(DBG_LIB, "stat() on '%s' failed: %s", this->path,
! 334: strerror(errno));
! 335: return FALSE;
! 336: }
! 337: return TRUE;
! 338: }
! 339:
! 340: METHOD(enumerator_t, enumerate_glob_enum, bool,
! 341: glob_enum_t *this, va_list args)
! 342: {
! 343: WIN32_FIND_DATA data;
! 344:
! 345: do
! 346: {
! 347: if (!FindNextFile(this->handle, &data))
! 348: {
! 349: return FALSE;
! 350: }
! 351: }
! 352: while (!combine_glob_path(this, &data));
! 353:
! 354: return enumerate_glob_enum_data(this, args);
! 355: }
! 356:
! 357: METHOD(enumerator_t, enumerate_glob_enum_first, bool,
! 358: glob_enum_t *this, va_list args)
! 359: {
! 360: if (enumerate_glob_enum_data(this, args))
! 361: {
! 362: this->public.venumerate = _enumerate_glob_enum;
! 363: return TRUE;
! 364: }
! 365: return FALSE;
! 366: }
! 367:
! 368: /*
! 369: * Described in header
! 370: */
! 371: enumerator_t *enumerator_create_glob(const char *pattern)
! 372: {
! 373: glob_enum_t *this;
! 374: WIN32_FIND_DATA data;
! 375:
! 376: if (!pattern)
! 377: {
! 378: return enumerator_create_empty();
! 379: }
! 380:
! 381: INIT(this,
! 382: .public = {
! 383: .enumerate = enumerator_enumerate_default,
! 384: .venumerate = _enumerate_glob_enum_first,
! 385: .destroy = _destroy_glob_enum,
! 386: },
! 387: .base = path_dirname(pattern),
! 388: );
! 389:
! 390: this->handle = FindFirstFile(pattern, &data);
! 391: if (this->handle == INVALID_HANDLE_VALUE)
! 392: {
! 393: if (GetLastError() == ERROR_FILE_NOT_FOUND ||
! 394: GetLastError() == ERROR_PATH_NOT_FOUND)
! 395: {
! 396: DBG1(DBG_LIB, "no files found matching '%s'", pattern);
! 397: }
! 398: else
! 399: {
! 400: DBG1(DBG_LIB, "FindFirstFile failed for pattern '%s' (%d)", pattern,
! 401: GetLastError());
! 402: }
! 403: destroy_glob_enum(this);
! 404: return enumerator_create_empty();
! 405: }
! 406: else if (!combine_glob_path(this, &data))
! 407: { /* check the next file if we can't combine the path for the first one */
! 408: this->public.venumerate = _enumerate_glob_enum;
! 409: }
! 410: return &this->public;
! 411: }
! 412:
1.1 misho 413: #else /* HAVE_GLOB_H */
414:
415: enumerator_t* enumerator_create_glob(const char *pattern)
416: {
417: return NULL;
418: }
419:
420: #endif /* HAVE_GLOB_H */
421:
422: /**
423: * Enumerator implementation for token enumerator
424: */
425: typedef struct {
426: /** implements enumerator_t */
427: enumerator_t public;
428: /** string to parse */
429: char *string;
430: /** current position */
431: char *pos;
432: /** separator chars */
433: const char *sep;
434: /** trim chars */
435: const char *trim;
436: } token_enum_t;
437:
438: METHOD(enumerator_t, destroy_token_enum, void,
439: token_enum_t *this)
440: {
441: free(this->string);
442: free(this);
443: }
444:
445: METHOD(enumerator_t, enumerate_token_enum, bool,
446: token_enum_t *this, va_list args)
447: {
448: const char *sep, *trim;
449: char *pos = NULL, *tmp, **token;
450: bool last = FALSE;
451:
452: VA_ARGS_VGET(args, token);
453:
454: /* trim leading characters/separators */
455: while (*this->pos)
456: {
457: trim = this->trim;
458: while (*trim)
459: {
460: if (*trim == *this->pos)
461: {
462: this->pos++;
463: break;
464: }
465: trim++;
466: }
467: sep = this->sep;
468: while (*sep)
469: {
470: if (*sep == *this->pos)
471: {
472: this->pos++;
473: break;
474: }
475: sep++;
476: }
477: if (!*trim && !*sep)
478: {
479: break;
480: }
481: }
482:
483: switch (*this->pos)
484: {
485: case '"':
486: case '\'':
487: {
488: /* read quoted token */
489: tmp = strchr(this->pos + 1, *this->pos);
490: if (tmp)
491: {
492: *token = this->pos + 1;
493: *tmp = '\0';
494: this->pos = tmp + 1;
495: return TRUE;
496: }
497: /* unterminated string, FALL-THROUGH */
498: }
499: default:
500: {
501: /* find nearest separator */
502: sep = this->sep;
503: while (*sep)
504: {
505: tmp = strchr(this->pos, *sep);
506: if (tmp && (pos == NULL || tmp < pos))
507: {
508: pos = tmp;
509: }
510: sep++;
511: }
512: *token = this->pos;
513: if (pos)
514: {
515: *pos = '\0';
516: this->pos = pos + 1;
517: }
518: else
519: {
520: last = TRUE;
521: pos = this->pos = strchr(this->pos, '\0');
522: }
523: break;
524: }
525: }
526:
527: /* trim trailing characters */
528: pos--;
529: while (pos >= *token)
530: {
531: trim = this->trim;
532: while (*trim)
533: {
534: if (*trim == *pos)
535: {
536: *(pos--) = '\0';
537: break;
538: }
539: trim++;
540: }
541: if (!*trim)
542: {
543: break;
544: }
545: }
546:
547: if (!last || pos >= *token)
548: {
549: return TRUE;
550: }
551: return FALSE;
552: }
553:
554: /*
555: * Described in header
556: */
557: enumerator_t* enumerator_create_token(const char *string, const char *sep,
558: const char *trim)
559: {
560: token_enum_t *this;
561:
562: INIT(this,
563: .public = {
564: .enumerate = enumerator_enumerate_default,
565: .venumerate = _enumerate_token_enum,
566: .destroy = _destroy_token_enum,
567: },
568: .string = strdup(string),
569: .sep = sep,
570: .trim = trim,
571: );
572: this->pos = this->string;
573:
574: return &this->public;
575: }
576:
577: /**
578: * Enumerator for nested enumerations
579: */
580: typedef struct {
581: enumerator_t public;
582: enumerator_t *outer;
583: enumerator_t *inner;
584: enumerator_t *(*create_inner)(void *outer, void *data);
585: void *data;
586: void (*destructor)(void *data);
587: } nested_enumerator_t;
588:
589:
590: METHOD(enumerator_t, enumerate_nested, bool,
591: nested_enumerator_t *this, va_list args)
592: {
593: while (TRUE)
594: {
595: while (!this->inner)
596: {
597: void *outer;
598:
599: if (!this->outer->enumerate(this->outer, &outer))
600: {
601: return FALSE;
602: }
603: this->inner = this->create_inner(outer, this->data);
604: if (this->inner && !this->inner->venumerate)
605: {
606: DBG1(DBG_LIB, "!!! ENUMERATE NESTED: venumerate() missing !!!");
607: return FALSE;
608: }
609: }
610: if (this->inner->venumerate(this->inner, args))
611: {
612: return TRUE;
613: }
614: this->inner->destroy(this->inner);
615: this->inner = NULL;
616: }
617: }
618:
619: METHOD(enumerator_t, destroy_nested, void,
620: nested_enumerator_t *this)
621: {
622: if (this->destructor)
623: {
624: this->destructor(this->data);
625: }
626: DESTROY_IF(this->inner);
627: this->outer->destroy(this->outer);
628: free(this);
629: }
630:
631: /*
632: * Described in header
633: */
634: enumerator_t *enumerator_create_nested(enumerator_t *outer,
635: enumerator_t *(inner_constructor)(void *outer, void *data),
636: void *data, void (*destructor)(void *data))
637: {
638: nested_enumerator_t *this;
639:
640: INIT(this,
641: .public = {
642: .enumerate = enumerator_enumerate_default,
643: .venumerate = _enumerate_nested,
644: .destroy = _destroy_nested,
645: },
646: .outer = outer,
647: .create_inner = inner_constructor,
648: .data = data,
649: .destructor = destructor,
650: );
651: return &this->public;
652: }
653:
654: /**
655: * Enumerator for filtered enumerator
656: */
657: typedef struct {
658: enumerator_t public;
659: enumerator_t *orig;
660: void *data;
661: bool (*filter)(void*,enumerator_t*,va_list);
662: void (*destructor)(void *data);
663: } filter_enumerator_t;
664:
665: METHOD(enumerator_t, destroy_filter, void,
666: filter_enumerator_t *this)
667: {
668: if (this->destructor)
669: {
670: this->destructor(this->data);
671: }
672: this->orig->destroy(this->orig);
673: free(this);
674: }
675:
676: METHOD(enumerator_t, enumerate_filter, bool,
677: filter_enumerator_t *this, va_list args)
678: {
679: bool result = FALSE;
680:
681: if (this->filter(this->data, this->orig, args))
682: {
683: result = TRUE;
684: }
685: return result;
686: }
687:
688: /*
689: * Described in header
690: */
691: enumerator_t *enumerator_create_filter(enumerator_t *orig,
692: bool (*filter)(void *data, enumerator_t *orig, va_list args),
693: void *data, void (*destructor)(void *data))
694: {
695: filter_enumerator_t *this;
696:
697: INIT(this,
698: .public = {
699: .enumerate = enumerator_enumerate_default,
700: .venumerate = _enumerate_filter,
701: .destroy = _destroy_filter,
702: },
703: .orig = orig,
704: .filter = filter,
705: .data = data,
706: .destructor = destructor,
707: );
708: return &this->public;
709: }
710:
711: /**
712: * Enumerator for cleaner enumerator
713: */
714: typedef struct {
715: enumerator_t public;
716: enumerator_t *wrapped;
717: void (*cleanup)(void *data);
718: void *data;
719: } cleaner_enumerator_t;
720:
721: METHOD(enumerator_t, destroy_cleaner, void,
722: cleaner_enumerator_t *this)
723: {
724: this->cleanup(this->data);
725: this->wrapped->destroy(this->wrapped);
726: free(this);
727: }
728:
729: METHOD(enumerator_t, enumerate_cleaner, bool,
730: cleaner_enumerator_t *this, va_list args)
731: {
732: if (!this->wrapped->venumerate)
733: {
734: DBG1(DBG_LIB, "!!! CLEANER ENUMERATOR: venumerate() missing !!!");
735: return FALSE;
736: }
737: return this->wrapped->venumerate(this->wrapped, args);
738: }
739:
740: /*
741: * Described in header
742: */
743: enumerator_t *enumerator_create_cleaner(enumerator_t *wrapped,
744: void (*cleanup)(void *data), void *data)
745: {
746: cleaner_enumerator_t *this;
747:
748: INIT(this,
749: .public = {
750: .enumerate = enumerator_enumerate_default,
751: .venumerate = _enumerate_cleaner,
752: .destroy = _destroy_cleaner,
753: },
754: .wrapped = wrapped,
755: .cleanup = cleanup,
756: .data = data,
757: );
758: return &this->public;
759: }
760:
761: /**
762: * Enumerator for single enumerator
763: */
764: typedef struct {
765: enumerator_t public;
766: void *item;
767: void (*cleanup)(void *item);
768: bool done;
769: } single_enumerator_t;
770:
771: METHOD(enumerator_t, destroy_single, void,
772: single_enumerator_t *this)
773: {
774: if (this->cleanup)
775: {
776: this->cleanup(this->item);
777: }
778: free(this);
779: }
780:
781: METHOD(enumerator_t, enumerate_single, bool,
782: single_enumerator_t *this, va_list args)
783: {
784: void **item;
785:
786: VA_ARGS_VGET(args, item);
787: if (this->done)
788: {
789: return FALSE;
790: }
791: *item = this->item;
792: this->done = TRUE;
793: return TRUE;
794: }
795:
796: /*
797: * Described in header
798: */
799: enumerator_t *enumerator_create_single(void *item, void (*cleanup)(void *item))
800: {
801: single_enumerator_t *this;
802:
803: INIT(this,
804: .public = {
805: .enumerate = enumerator_enumerate_default,
806: .venumerate = _enumerate_single,
807: .destroy = _destroy_single,
808: },
809: .item = item,
810: .cleanup = cleanup,
811: );
812: return &this->public;
813: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>