settings: Make loading a NULL or empty pattern a (nop-)success
[strongswan.git] / src / libstrongswan / settings / settings.c
1 /*
2 * Copyright (C) 2010-2014 Tobias Brunner
3 * Copyright (C) 2008 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 #define _GNU_SOURCE
18 #include <string.h>
19 #include <stdarg.h>
20 #include <stdio.h>
21 #include <errno.h>
22 #include <limits.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <unistd.h>
26 #include <ctype.h>
27
28 #include "settings.h"
29 #include "settings_types.h"
30
31 #include "collections/array.h"
32 #include "collections/hashtable.h"
33 #include "collections/linked_list.h"
34 #include "threading/rwlock.h"
35 #include "utils/debug.h"
36
37 typedef struct private_settings_t private_settings_t;
38
39 /**
40 * Parse function provided by the generated parser.
41 */
42 bool settings_parser_parse_file(section_t *root, char *name);
43
44 /**
45 * Private data of settings
46 */
47 struct private_settings_t {
48
49 /**
50 * Public interface
51 */
52 settings_t public;
53
54 /**
55 * Top level section
56 */
57 section_t *top;
58
59 /**
60 * Contents of replaced settings (char*)
61 *
62 * FIXME: This is required because the pointer returned by get_str()
63 * is not refcounted. Might cause ever increasing usage stats.
64 */
65 array_t *contents;
66
67 /**
68 * Lock to safely access the settings
69 */
70 rwlock_t *lock;
71 };
72
73 /**
74 * Print a format key, but consume already processed arguments
75 */
76 static bool print_key(char *buf, int len, char *start, char *key, va_list args)
77 {
78 va_list copy;
79 char *pos = start;
80 bool res;
81
82 va_copy(copy, args);
83 while (TRUE)
84 {
85 pos = memchr(pos, '%', key - pos);
86 if (!pos)
87 {
88 break;
89 }
90 pos++;
91 switch (*pos)
92 {
93 case 'd':
94 va_arg(copy, int);
95 break;
96 case 's':
97 va_arg(copy, char*);
98 break;
99 case 'N':
100 va_arg(copy, enum_name_t*);
101 va_arg(copy, int);
102 break;
103 case '%':
104 break;
105 default:
106 DBG1(DBG_CFG, "settings with %%%c not supported!", *pos);
107 break;
108 }
109 pos++;
110 }
111 res = vsnprintf(buf, len, key, copy) < len;
112 va_end(copy);
113 return res;
114 }
115
116 /**
117 * Find a section by a given key, using buffered key, reusable buffer.
118 * If "ensure" is TRUE, the sections are created if they don't exist.
119 */
120 static section_t *find_section_buffered(section_t *section,
121 char *start, char *key, va_list args, char *buf, int len,
122 bool ensure)
123 {
124 char *pos;
125 section_t *found = NULL;
126
127 if (section == NULL)
128 {
129 return NULL;
130 }
131 pos = strchr(key, '.');
132 if (pos)
133 {
134 *pos = '\0';
135 pos++;
136 }
137 if (!print_key(buf, len, start, key, args))
138 {
139 return NULL;
140 }
141 if (!strlen(buf))
142 {
143 found = section;
144 }
145 else if (array_bsearch(section->sections, buf, settings_section_find,
146 &found) == -1)
147 {
148 if (ensure)
149 {
150 found = settings_section_create(strdup(buf));
151 settings_section_add(section, found, NULL);
152 }
153 }
154 if (found && pos)
155 {
156 return find_section_buffered(found, start, pos, args, buf, len, ensure);
157 }
158 return found;
159 }
160
161 /**
162 * Find all sections via a given key considering fallbacks, using buffered key,
163 * reusable buffer.
164 */
165 static void find_sections_buffered(section_t *section, char *start, char *key,
166 va_list args, char *buf, int len, array_t **sections)
167 {
168 section_t *found = NULL, *fallback;
169 char *pos;
170 int i;
171
172 if (!section)
173 {
174 return;
175 }
176 pos = strchr(key, '.');
177 if (pos)
178 {
179 *pos = '\0';
180 }
181 if (!print_key(buf, len, start, key, args))
182 {
183 return;
184 }
185 if (pos)
186 { /* restore so we can follow fallbacks */
187 *pos = '.';
188 }
189 if (!strlen(buf))
190 {
191 found = section;
192 }
193 else
194 {
195 array_bsearch(section->sections, buf, settings_section_find, &found);
196 }
197 if (found)
198 {
199 if (pos)
200 {
201 find_sections_buffered(found, start, pos+1, args, buf, len,
202 sections);
203 }
204 else
205 {
206 array_insert_create(sections, ARRAY_TAIL, found);
207 for (i = 0; i < array_count(found->fallbacks); i++)
208 {
209 array_get(found->fallbacks, i, &fallback);
210 array_insert_create(sections, ARRAY_TAIL, fallback);
211 }
212 }
213 }
214 if (section->fallbacks)
215 {
216 for (i = 0; i < array_count(section->fallbacks); i++)
217 {
218 array_get(section->fallbacks, i, &fallback);
219 find_sections_buffered(fallback, start, key, args, buf, len,
220 sections);
221 }
222 }
223 }
224
225 /**
226 * Ensure that the section with the given key exists (thread-safe).
227 */
228 static section_t *ensure_section(private_settings_t *this, section_t *section,
229 const char *key, va_list args)
230 {
231 char buf[128], keybuf[512];
232 section_t *found;
233
234 if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf))
235 {
236 return NULL;
237 }
238 /* we might have to change the tree */
239 this->lock->write_lock(this->lock);
240 found = find_section_buffered(section, keybuf, keybuf, args, buf,
241 sizeof(buf), TRUE);
242 this->lock->unlock(this->lock);
243 return found;
244 }
245
246 /**
247 * Find a section by a given key with its fallbacks (not thread-safe!).
248 * Sections are returned in depth-first order (array is allocated). NULL is
249 * returned if no sections are found.
250 */
251 static array_t *find_sections(private_settings_t *this, section_t *section,
252 char *key, va_list args)
253 {
254 char buf[128], keybuf[512];
255 array_t *sections = NULL;
256
257 if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf))
258 {
259 return NULL;
260 }
261 find_sections_buffered(section, keybuf, keybuf, args, buf,
262 sizeof(buf), &sections);
263 return sections;
264 }
265
266 /**
267 * Check if the given fallback section already exists
268 */
269 static bool fallback_exists(section_t *section, section_t *fallback)
270 {
271 if (section == fallback)
272 {
273 return TRUE;
274 }
275 else if (section->fallbacks)
276 {
277 section_t *existing;
278 int i;
279
280 for (i = 0; i < array_count(section->fallbacks); i++)
281 {
282 array_get(section->fallbacks, i, &existing);
283 if (existing == fallback)
284 {
285 return TRUE;
286 }
287 }
288 }
289 return FALSE;
290 }
291
292 /**
293 * Ensure that the section with the given key exists and add the given fallback
294 * section (thread-safe).
295 */
296 static void add_fallback_to_section(private_settings_t *this,
297 section_t *section, const char *key, va_list args,
298 section_t *fallback)
299 {
300 char buf[128], keybuf[512];
301 section_t *found;
302
303 if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf))
304 {
305 return;
306 }
307 this->lock->write_lock(this->lock);
308 found = find_section_buffered(section, keybuf, keybuf, args, buf,
309 sizeof(buf), TRUE);
310 if (!fallback_exists(found, fallback))
311 {
312 /* to ensure sections referred to as fallback are not purged, we create
313 * the array there too */
314 if (!fallback->fallbacks)
315 {
316 fallback->fallbacks = array_create(0, 0);
317 }
318 array_insert_create(&found->fallbacks, ARRAY_TAIL, fallback);
319 }
320 this->lock->unlock(this->lock);
321 }
322
323 /**
324 * Find the key/value pair for a key, using buffered key, reusable buffer
325 * If "ensure" is TRUE, the sections (and key/value pair) are created if they
326 * don't exist.
327 * Fallbacks are only considered if "ensure" is FALSE.
328 */
329 static kv_t *find_value_buffered(section_t *section, char *start, char *key,
330 va_list args, char *buf, int len, bool ensure)
331 {
332 int i;
333 char *pos;
334 kv_t *kv = NULL;
335 section_t *found = NULL;
336
337 if (section == NULL)
338 {
339 return NULL;
340 }
341
342 pos = strchr(key, '.');
343 if (pos)
344 {
345 *pos = '\0';
346 if (!print_key(buf, len, start, key, args))
347 {
348 return NULL;
349 }
350 /* restore so we can retry for fallbacks */
351 *pos = '.';
352 if (!strlen(buf))
353 {
354 found = section;
355 }
356 else if (array_bsearch(section->sections, buf, settings_section_find,
357 &found) == -1)
358 {
359 if (ensure)
360 {
361 found = settings_section_create(strdup(buf));
362 settings_section_add(section, found, NULL);
363 }
364 }
365 if (found)
366 {
367 kv = find_value_buffered(found, start, pos+1, args, buf, len,
368 ensure);
369 }
370 if (!kv && !ensure && section->fallbacks)
371 {
372 for (i = 0; !kv && i < array_count(section->fallbacks); i++)
373 {
374 array_get(section->fallbacks, i, &found);
375 kv = find_value_buffered(found, start, key, args, buf, len,
376 ensure);
377 }
378 }
379 }
380 else
381 {
382 if (!print_key(buf, len, start, key, args))
383 {
384 return NULL;
385 }
386 if (array_bsearch(section->kv, buf, settings_kv_find, &kv) == -1)
387 {
388 if (ensure)
389 {
390 kv = settings_kv_create(strdup(buf), NULL);
391 settings_kv_add(section, kv, NULL);
392 }
393 else if (section->fallbacks)
394 {
395 for (i = 0; !kv && i < array_count(section->fallbacks); i++)
396 {
397 array_get(section->fallbacks, i, &found);
398 kv = find_value_buffered(found, start, key, args, buf, len,
399 ensure);
400 }
401 }
402 }
403 }
404 return kv;
405 }
406
407 /**
408 * Find the string value for a key (thread-safe).
409 */
410 static char *find_value(private_settings_t *this, section_t *section,
411 char *key, va_list args)
412 {
413 char buf[128], keybuf[512], *value = NULL;
414 kv_t *kv;
415
416 if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf))
417 {
418 return NULL;
419 }
420 this->lock->read_lock(this->lock);
421 kv = find_value_buffered(section, keybuf, keybuf, args, buf, sizeof(buf),
422 FALSE);
423 if (kv)
424 {
425 value = kv->value;
426 }
427 this->lock->unlock(this->lock);
428 return value;
429 }
430
431 /**
432 * Set a value to a copy of the given string (thread-safe).
433 */
434 static void set_value(private_settings_t *this, section_t *section,
435 char *key, va_list args, char *value)
436 {
437 char buf[128], keybuf[512];
438 kv_t *kv;
439
440 if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf))
441 {
442 return;
443 }
444 this->lock->write_lock(this->lock);
445 kv = find_value_buffered(section, keybuf, keybuf, args, buf, sizeof(buf),
446 TRUE);
447 if (kv)
448 {
449 settings_kv_set(kv, strdupnull(value), this->contents);
450 }
451 this->lock->unlock(this->lock);
452 }
453
454 METHOD(settings_t, get_str, char*,
455 private_settings_t *this, char *key, char *def, ...)
456 {
457 char *value;
458 va_list args;
459
460 va_start(args, def);
461 value = find_value(this, this->top, key, args);
462 va_end(args);
463 if (value)
464 {
465 return value;
466 }
467 return def;
468 }
469
470 /**
471 * Described in header
472 */
473 inline bool settings_value_as_bool(char *value, bool def)
474 {
475 if (value)
476 {
477 if (strcaseeq(value, "1") ||
478 strcaseeq(value, "yes") ||
479 strcaseeq(value, "true") ||
480 strcaseeq(value, "enabled"))
481 {
482 return TRUE;
483 }
484 else if (strcaseeq(value, "0") ||
485 strcaseeq(value, "no") ||
486 strcaseeq(value, "false") ||
487 strcaseeq(value, "disabled"))
488 {
489 return FALSE;
490 }
491 }
492 return def;
493 }
494
495 METHOD(settings_t, get_bool, bool,
496 private_settings_t *this, char *key, bool def, ...)
497 {
498 char *value;
499 va_list args;
500
501 va_start(args, def);
502 value = find_value(this, this->top, key, args);
503 va_end(args);
504 return settings_value_as_bool(value, def);
505 }
506
507 /**
508 * Described in header
509 */
510 inline int settings_value_as_int(char *value, int def)
511 {
512 int intval;
513 char *end;
514
515 if (value)
516 {
517 errno = 0;
518 intval = strtol(value, &end, 10);
519 if (errno == 0 && *end == 0 && end != value)
520 {
521 return intval;
522 }
523 }
524 return def;
525 }
526
527 METHOD(settings_t, get_int, int,
528 private_settings_t *this, char *key, int def, ...)
529 {
530 char *value;
531 va_list args;
532
533 va_start(args, def);
534 value = find_value(this, this->top, key, args);
535 va_end(args);
536 return settings_value_as_int(value, def);
537 }
538
539 /**
540 * Described in header
541 */
542 inline double settings_value_as_double(char *value, double def)
543 {
544 double dval;
545 char *end;
546
547 if (value)
548 {
549 errno = 0;
550 dval = strtod(value, &end);
551 if (errno == 0 && *end == 0 && end != value)
552 {
553 return dval;
554 }
555 }
556 return def;
557 }
558
559 METHOD(settings_t, get_double, double,
560 private_settings_t *this, char *key, double def, ...)
561 {
562 char *value;
563 va_list args;
564
565 va_start(args, def);
566 value = find_value(this, this->top, key, args);
567 va_end(args);
568 return settings_value_as_double(value, def);
569 }
570
571 /**
572 * Described in header
573 */
574 inline u_int32_t settings_value_as_time(char *value, u_int32_t def)
575 {
576 char *endptr;
577 u_int32_t timeval;
578 if (value)
579 {
580 errno = 0;
581 timeval = strtoul(value, &endptr, 10);
582 if (endptr == value)
583 {
584 return def;
585 }
586 if (errno == 0)
587 {
588 while (isspace(*endptr))
589 {
590 endptr++;
591 }
592 switch (*endptr)
593 {
594 case 'd': /* time in days */
595 timeval *= 24 * 3600;
596 break;
597 case 'h': /* time in hours */
598 timeval *= 3600;
599 break;
600 case 'm': /* time in minutes */
601 timeval *= 60;
602 break;
603 case 's': /* time in seconds */
604 case '\0':
605 break;
606 default:
607 return def;
608 }
609 return timeval;
610 }
611 }
612 return def;
613 }
614
615 METHOD(settings_t, get_time, u_int32_t,
616 private_settings_t *this, char *key, u_int32_t def, ...)
617 {
618 char *value;
619 va_list args;
620
621 va_start(args, def);
622 value = find_value(this, this->top, key, args);
623 va_end(args);
624 return settings_value_as_time(value, def);
625 }
626
627 METHOD(settings_t, set_str, void,
628 private_settings_t *this, char *key, char *value, ...)
629 {
630 va_list args;
631 va_start(args, value);
632 set_value(this, this->top, key, args, value);
633 va_end(args);
634 }
635
636 METHOD(settings_t, set_bool, void,
637 private_settings_t *this, char *key, bool value, ...)
638 {
639 va_list args;
640 va_start(args, value);
641 set_value(this, this->top, key, args, value ? "1" : "0");
642 va_end(args);
643 }
644
645 METHOD(settings_t, set_int, void,
646 private_settings_t *this, char *key, int value, ...)
647 {
648 char val[16];
649 va_list args;
650 va_start(args, value);
651 if (snprintf(val, sizeof(val), "%d", value) < sizeof(val))
652 {
653 set_value(this, this->top, key, args, val);
654 }
655 va_end(args);
656 }
657
658 METHOD(settings_t, set_double, void,
659 private_settings_t *this, char *key, double value, ...)
660 {
661 char val[64];
662 va_list args;
663 va_start(args, value);
664 if (snprintf(val, sizeof(val), "%f", value) < sizeof(val))
665 {
666 set_value(this, this->top, key, args, val);
667 }
668 va_end(args);
669 }
670
671 METHOD(settings_t, set_time, void,
672 private_settings_t *this, char *key, u_int32_t value, ...)
673 {
674 char val[16];
675 va_list args;
676 va_start(args, value);
677 if (snprintf(val, sizeof(val), "%u", value) < sizeof(val))
678 {
679 set_value(this, this->top, key, args, val);
680 }
681 va_end(args);
682 }
683
684 METHOD(settings_t, set_default_str, bool,
685 private_settings_t *this, char *key, char *value, ...)
686 {
687 char *old;
688 va_list args;
689
690 va_start(args, value);
691 old = find_value(this, this->top, key, args);
692 va_end(args);
693
694 if (!old)
695 {
696 va_start(args, value);
697 set_value(this, this->top, key, args, value);
698 va_end(args);
699 return TRUE;
700 }
701 return FALSE;
702 }
703
704 /**
705 * Data for enumerators
706 */
707 typedef struct {
708 /** settings_t instance */
709 private_settings_t *settings;
710 /** sections to enumerate */
711 array_t *sections;
712 /** sections/keys that were already enumerated */
713 hashtable_t *seen;
714 } enumerator_data_t;
715
716 /**
717 * Destroy enumerator data
718 */
719 static void enumerator_destroy(enumerator_data_t *this)
720 {
721 this->settings->lock->unlock(this->settings->lock);
722 this->seen->destroy(this->seen);
723 array_destroy(this->sections);
724 free(this);
725 }
726
727 /**
728 * Enumerate section names, not sections
729 */
730 static bool section_filter(hashtable_t *seen, section_t **in, char **out)
731 {
732 *out = (*in)->name;
733 if (seen->get(seen, *out))
734 {
735 return FALSE;
736 }
737 seen->put(seen, *out, *out);
738 return TRUE;
739 }
740
741 /**
742 * Enumerate sections of the given section
743 */
744 static enumerator_t *section_enumerator(section_t *section,
745 enumerator_data_t *data)
746 {
747 return enumerator_create_filter(
748 array_create_enumerator(section->sections_order),
749 (void*)section_filter, data->seen, NULL);
750 }
751
752 METHOD(settings_t, create_section_enumerator, enumerator_t*,
753 private_settings_t *this, char *key, ...)
754 {
755 enumerator_data_t *data;
756 array_t *sections;
757 va_list args;
758
759 this->lock->read_lock(this->lock);
760 va_start(args, key);
761 sections = find_sections(this, this->top, key, args);
762 va_end(args);
763
764 if (!sections)
765 {
766 this->lock->unlock(this->lock);
767 return enumerator_create_empty();
768 }
769 INIT(data,
770 .settings = this,
771 .sections = sections,
772 .seen = hashtable_create(hashtable_hash_str, hashtable_equals_str, 8),
773 );
774 return enumerator_create_nested(array_create_enumerator(sections),
775 (void*)section_enumerator, data, (void*)enumerator_destroy);
776 }
777
778 /**
779 * Enumerate key and values, not kv_t entries
780 */
781 static bool kv_filter(hashtable_t *seen, kv_t **in, char **key,
782 void *none, char **value)
783 {
784 *key = (*in)->key;
785 if (seen->get(seen, *key) || !(*in)->value)
786 {
787 return FALSE;
788 }
789 *value = (*in)->value;
790 seen->put(seen, *key, *key);
791 return TRUE;
792 }
793
794 /**
795 * Enumerate key/value pairs of the given section
796 */
797 static enumerator_t *kv_enumerator(section_t *section, enumerator_data_t *data)
798 {
799 return enumerator_create_filter(array_create_enumerator(section->kv_order),
800 (void*)kv_filter, data->seen, NULL);
801 }
802
803 METHOD(settings_t, create_key_value_enumerator, enumerator_t*,
804 private_settings_t *this, char *key, ...)
805 {
806 enumerator_data_t *data;
807 array_t *sections;
808 va_list args;
809
810 this->lock->read_lock(this->lock);
811 va_start(args, key);
812 sections = find_sections(this, this->top, key, args);
813 va_end(args);
814
815 if (!sections)
816 {
817 this->lock->unlock(this->lock);
818 return enumerator_create_empty();
819 }
820 INIT(data,
821 .settings = this,
822 .sections = sections,
823 .seen = hashtable_create(hashtable_hash_str, hashtable_equals_str, 8),
824 );
825 return enumerator_create_nested(array_create_enumerator(sections),
826 (void*)kv_enumerator, data, (void*)enumerator_destroy);
827 }
828
829 METHOD(settings_t, add_fallback, void,
830 private_settings_t *this, const char *key, const char *fallback, ...)
831 {
832 section_t *section;
833 va_list args;
834
835 /* find/create the fallback */
836 va_start(args, fallback);
837 section = ensure_section(this, this->top, fallback, args);
838 va_end(args);
839
840 va_start(args, fallback);
841 add_fallback_to_section(this, this->top, key, args, section);
842 va_end(args);
843 }
844
845 /**
846 * Load settings from files matching the given file pattern.
847 * All sections and values are added relative to "parent".
848 * All files (even included ones) have to be loaded successfully.
849 * If merge is FALSE the contents of parent are replaced with the parsed
850 * contents, otherwise they are merged together.
851 */
852 static bool load_files_internal(private_settings_t *this, section_t *parent,
853 char *pattern, bool merge)
854 {
855 section_t *section;
856
857 if (pattern == NULL || !pattern[0])
858 { /* TODO: Clear parent if merge is FALSE? */
859 return TRUE;
860 }
861
862 section = settings_section_create(NULL);
863 if (!settings_parser_parse_file(section, pattern))
864 {
865 settings_section_destroy(section, NULL);
866 return FALSE;
867 }
868
869 this->lock->write_lock(this->lock);
870 settings_section_extend(parent, section, this->contents, !merge);
871 this->lock->unlock(this->lock);
872
873 settings_section_destroy(section, NULL);
874 return TRUE;
875 }
876
877 METHOD(settings_t, load_files, bool,
878 private_settings_t *this, char *pattern, bool merge)
879 {
880 return load_files_internal(this, this->top, pattern, merge);
881 }
882
883 METHOD(settings_t, load_files_section, bool,
884 private_settings_t *this, char *pattern, bool merge, char *key, ...)
885 {
886 section_t *section;
887 va_list args;
888
889 va_start(args, key);
890 section = ensure_section(this, this->top, key, args);
891 va_end(args);
892
893 if (!section)
894 {
895 return FALSE;
896 }
897 return load_files_internal(this, section, pattern, merge);
898 }
899
900 METHOD(settings_t, destroy, void,
901 private_settings_t *this)
902 {
903 settings_section_destroy(this->top, NULL);
904 array_destroy_function(this->contents, (void*)free, NULL);
905 this->lock->destroy(this->lock);
906 free(this);
907 }
908
909 /*
910 * see header file
911 */
912 settings_t *settings_create(char *file)
913 {
914 private_settings_t *this;
915
916 INIT(this,
917 .public = {
918 .get_str = _get_str,
919 .get_int = _get_int,
920 .get_double = _get_double,
921 .get_time = _get_time,
922 .get_bool = _get_bool,
923 .set_str = _set_str,
924 .set_int = _set_int,
925 .set_double = _set_double,
926 .set_time = _set_time,
927 .set_bool = _set_bool,
928 .set_default_str = _set_default_str,
929 .create_section_enumerator = _create_section_enumerator,
930 .create_key_value_enumerator = _create_key_value_enumerator,
931 .add_fallback = _add_fallback,
932 .load_files = _load_files,
933 .load_files_section = _load_files_section,
934 .destroy = _destroy,
935 },
936 .top = settings_section_create(NULL),
937 .contents = array_create(0, 0),
938 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
939 );
940
941 load_files(this, file, FALSE);
942
943 return &this->public;
944 }