Asterisk - The Open Source Telephony Project GIT-master-754dea3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
bucket.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2013, Digium, Inc.
5 *
6 * Joshua Colp <jcolp@digium.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19/*! \file
20 *
21 * \brief Bucket File API
22 *
23 * \author Joshua Colp <jcolp@digium.com>
24 */
25
26/*** MODULEINFO
27 <use type="external">uriparser</use>
28 <support_level>core</support_level>
29 ***/
30
31#include "asterisk.h"
32
33#ifdef HAVE_URIPARSER
34#include <uriparser/Uri.h>
35#endif
36
37#include "asterisk/logger.h"
38#include "asterisk/sorcery.h"
39#include "asterisk/bucket.h"
41#include "asterisk/astobj2.h"
42#include "asterisk/strings.h"
43#include "asterisk/json.h"
44#include "asterisk/file.h"
45#include "asterisk/module.h"
46#include "asterisk/paths.h"
47
48/*! \brief Number of buckets for the container of schemes */
49#define SCHEME_BUCKETS 53
50
51/*! \brief Number of buckets for the container of metadata in a file */
52#define METADATA_BUCKETS 53
53
54/*! \brief Sorcery instance for all bucket operations */
56
57/*! \brief Container of registered schemes */
58static struct ao2_container *schemes;
59
60/*! \brief Structure for available schemes */
62 /*! \brief Wizard for buckets */
64 /*! \brief Wizard for files */
66 /*! \brief Pointer to the file snapshot creation callback */
68 /*! \brief Pointer to the file snapshot destruction callback */
70 /*! \brief Name of the scheme */
71 char name[0];
72};
73
74/*! \brief Callback function for creating a bucket */
75static int bucket_wizard_create(const struct ast_sorcery *sorcery, void *data, void *object)
76{
77 struct ast_bucket *bucket = object;
78
79 return bucket->scheme_impl->bucket->create(sorcery, data, object);
80}
81
82/*! \brief Callback function for retrieving a bucket */
83static void *bucket_wizard_retrieve(const struct ast_sorcery *sorcery, void *data, const char *type,
84 const char *id)
85{
86#ifdef HAVE_URIPARSER
87 UriParserStateA state;
88 UriUriA uri;
89 size_t len;
90#else
91 char *tmp = ast_strdupa(id);
92#endif
94 char *uri_scheme;
96
97#ifdef HAVE_URIPARSER
98 state.uri = &uri;
99 if (uriParseUriA(&state, id) != URI_SUCCESS ||
100 !uri.scheme.first || !uri.scheme.afterLast) {
101 uriFreeUriMembersA(&uri);
102 return NULL;
103 }
104
105 len = (uri.scheme.afterLast - uri.scheme.first) + 1;
106 uri_scheme = ast_alloca(len);
107 ast_copy_string(uri_scheme, uri.scheme.first, len);
108
109 uriFreeUriMembersA(&uri);
110#else
111 uri_scheme = tmp;
112 if (!(tmp = strchr(uri_scheme, ':'))) {
113 return NULL;
114 }
115 *tmp = '\0';
116#endif
117
118 scheme = ao2_find(schemes, uri_scheme, OBJ_KEY | OBJ_NOLOCK);
119
120 if (!scheme) {
121 return NULL;
122 }
123
124 return scheme->bucket->retrieve_id(sorcery, data, type, id);
125}
126
127/*! \brief Callback function for deleting a bucket */
128static int bucket_wizard_delete(const struct ast_sorcery *sorcery, void *data, void *object)
129{
130 struct ast_bucket *bucket = object;
131
132 return bucket->scheme_impl->bucket->delete(sorcery, data, object);
133}
134
135/*! \brief Callback function for determining if a bucket is stale */
136static int bucket_wizard_is_stale(const struct ast_sorcery *sorcery, void *data, void *object)
137{
138 struct ast_bucket *bucket = object;
139
140 if (!bucket->scheme_impl->bucket->is_stale) {
141 return 0;
142 }
143
144 return bucket->scheme_impl->bucket->is_stale(sorcery, data, object);
145}
146
147/*! \brief Intermediary bucket wizard */
149 .name = "bucket",
150 .create = bucket_wizard_create,
151 .retrieve_id = bucket_wizard_retrieve,
152 .delete = bucket_wizard_delete,
153 .is_stale = bucket_wizard_is_stale,
154};
155
156/*! \brief Callback function for creating a bucket file */
157static int bucket_file_wizard_create(const struct ast_sorcery *sorcery, void *data, void *object)
158{
159 struct ast_bucket_file *file = object;
160
161 return file->scheme_impl->file->create(sorcery, data, object);
162}
163
164/*! \brief Callback function for retrieving a bucket file */
165static void *bucket_file_wizard_retrieve(const struct ast_sorcery *sorcery, void *data, const char *type,
166 const char *id)
167{
168#ifdef HAVE_URIPARSER
169 UriParserStateA state;
170 UriUriA uri;
171 size_t len;
172#else
173 char *tmp = ast_strdupa(id);
174#endif
175 char *uri_scheme;
178
179#ifdef HAVE_URIPARSER
180 state.uri = &uri;
181 if (uriParseUriA(&state, id) != URI_SUCCESS ||
182 !uri.scheme.first || !uri.scheme.afterLast) {
183 uriFreeUriMembersA(&uri);
184 return NULL;
185 }
186
187 len = (uri.scheme.afterLast - uri.scheme.first) + 1;
188 uri_scheme = ast_alloca(len);
189 ast_copy_string(uri_scheme, uri.scheme.first, len);
190
191 uriFreeUriMembersA(&uri);
192#else
193 uri_scheme = tmp;
194 if (!(tmp = strchr(uri_scheme, ':'))) {
195 return NULL;
196 }
197 *tmp = '\0';
198#endif
199
200 scheme = ao2_find(schemes, uri_scheme, OBJ_KEY | OBJ_NOLOCK);
201
202 if (!scheme) {
203 return NULL;
204 }
205
206 return scheme->file->retrieve_id(sorcery, data, type, id);
207}
208
209/*! \brief Callback function for updating a bucket file */
210static int bucket_file_wizard_update(const struct ast_sorcery *sorcery, void *data, void *object)
211{
212 struct ast_bucket_file *file = object;
213
214 return file->scheme_impl->file->update(sorcery, data, object);
215}
216
217/*! \brief Callback function for deleting a bucket file */
218static int bucket_file_wizard_delete(const struct ast_sorcery *sorcery, void *data, void *object)
219{
220 struct ast_bucket_file *file = object;
221
222 return file->scheme_impl->file->delete(sorcery, data, object);
223}
224
225/*! \brief Callback function for determining if a bucket is stale */
226static int bucket_file_wizard_is_stale(const struct ast_sorcery *sorcery, void *data, void *object)
227{
228 struct ast_bucket_file *file = object;
229
230 if (!file->scheme_impl->file->is_stale) {
231 return 0;
232 }
233
234 return file->scheme_impl->file->is_stale(sorcery, data, object);
235}
236
237/*! \brief Intermediary file wizard */
239 .name = "bucket_file",
241 .retrieve_id = bucket_file_wizard_retrieve,
244 .is_stale = bucket_file_wizard_is_stale,
245};
246
249 bucket_file_destroy_cb destroy_cb, struct ast_module *module)
250{
252 RAII_VAR(struct ast_bucket_scheme *, scheme, NULL, ao2_cleanup);
253
254 if (ast_strlen_zero(name) || !bucket || !file ||
255 !bucket->create || !bucket->delete || !bucket->retrieve_id ||
256 (!bucket->create && !create_cb)) {
257 return -1;
258 }
259
260 scheme = ao2_find(schemes, name, OBJ_KEY | OBJ_NOLOCK);
261 if (scheme) {
262 return -1;
263 }
264
265 scheme = ao2_alloc(sizeof(*scheme) + strlen(name) + 1, NULL);
266 if (!scheme) {
267 return -1;
268 }
269
270 strcpy(scheme->name, name);
271 scheme->bucket = bucket;
272 scheme->file = file;
273 scheme->create = create_cb;
274 scheme->destroy = destroy_cb;
275
277
278 ast_verb(5, "Registered bucket scheme '%s'\n", name);
279
281
282 return 0;
283}
284
285/*! \brief Allocator for metadata attributes */
286static struct ast_bucket_metadata *bucket_metadata_alloc(const char *name, const char *value)
287{
288 int name_len = strlen(name) + 1, value_len = strlen(value) + 1;
289 struct ast_bucket_metadata *metadata = ao2_alloc(sizeof(*metadata) + name_len + value_len, NULL);
290 char *dst;
291
292 if (!metadata) {
293 return NULL;
294 }
295
296 dst = metadata->data;
297 metadata->name = strcpy(dst, name);
298 dst += name_len;
299 metadata->value = strcpy(dst, value);
300
301 return metadata;
302}
303
304int ast_bucket_file_metadata_set(struct ast_bucket_file *file, const char *name, const char *value)
305{
307
308 if (!metadata) {
309 return -1;
310 }
311
313 ao2_link(file->metadata, metadata);
314
315 return 0;
316}
317
319{
320 RAII_VAR(struct ast_bucket_metadata *, metadata, ao2_find(file->metadata, name, OBJ_UNLINK | OBJ_KEY), ao2_cleanup);
321
322 if (!metadata) {
323 return -1;
324 }
325
326 return 0;
327}
328
330{
331 return ao2_find(file->metadata, name, OBJ_KEY);
332}
333
335{
336 ao2_callback(file->metadata, 0, cb, arg);
337}
338
339
340/*! \brief Destructor for buckets */
341static void bucket_destroy(void *obj)
342{
343 struct ast_bucket *bucket = obj;
344
345 ao2_cleanup(bucket->scheme_impl);
347 ao2_cleanup(bucket->buckets);
348 ao2_cleanup(bucket->files);
349}
350
351/*! \brief Sorting function for red black tree string container */
352static int bucket_rbtree_str_sort_cmp(const void *obj_left, const void *obj_right, int flags)
353{
354 const char *str_left = obj_left;
355 const char *str_right = obj_right;
356 int cmp = 0;
357
358 switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
359 default:
360 case OBJ_POINTER:
361 case OBJ_KEY:
362 cmp = strcmp(str_left, str_right);
363 break;
364 case OBJ_PARTIAL_KEY:
365 cmp = strncmp(str_left, str_right, strlen(str_right));
366 break;
367 }
368 return cmp;
369}
370
371/*! \brief Allocator for buckets */
372static void *bucket_alloc(const char *name)
373{
374 RAII_VAR(struct ast_bucket *, bucket, NULL, ao2_cleanup);
375
376 bucket = ast_sorcery_generic_alloc(sizeof(*bucket), bucket_destroy);
377 if (!bucket) {
378 return NULL;
379 }
380
381 if (ast_string_field_init(bucket, 128)) {
382 return NULL;
383 }
384
387 if (!bucket->buckets) {
388 return NULL;
389 }
390
393 if (!bucket->files) {
394 return NULL;
395 }
396
397 ao2_ref(bucket, +1);
398 return bucket;
399}
400
401struct ast_bucket *ast_bucket_alloc(const char *uri)
402{
403#ifdef HAVE_URIPARSER
404 UriParserStateA state;
405 UriUriA full_uri;
406 size_t len;
407#else
408 char *tmp = ast_strdupa(uri);
409#endif
410 char *uri_scheme;
412 struct ast_bucket *bucket;
413
414 if (ast_strlen_zero(uri)) {
415 return NULL;
416 }
417
418#ifdef HAVE_URIPARSER
419 state.uri = &full_uri;
420 if (uriParseUriA(&state, uri) != URI_SUCCESS ||
421 !full_uri.scheme.first || !full_uri.scheme.afterLast ||
422 !full_uri.pathTail) {
423 uriFreeUriMembersA(&full_uri);
424 return NULL;
425 }
426
427 len = (full_uri.scheme.afterLast - full_uri.scheme.first) + 1;
428 uri_scheme = ast_alloca(len);
429 ast_copy_string(uri_scheme, full_uri.scheme.first, len);
430
431 uriFreeUriMembersA(&full_uri);
432#else
433 uri_scheme = tmp;
434 if (!(tmp = strchr(uri_scheme, ':'))) {
435 return NULL;
436 }
437 *tmp = '\0';
438#endif
439
440 scheme = ao2_find(schemes, uri_scheme, OBJ_KEY);
441 if (!scheme) {
442 return NULL;
443 }
444
445 bucket = ast_sorcery_alloc(bucket_sorcery, "bucket", uri);
446 if (!bucket) {
447 return NULL;
448 }
449
450 ao2_ref(scheme, +1);
451 bucket->scheme_impl = scheme;
452
453 ast_string_field_set(bucket, scheme, uri_scheme);
454
455 return bucket;
456}
457
458int ast_bucket_create(struct ast_bucket *bucket)
459{
460 return ast_sorcery_create(bucket_sorcery, bucket);
461}
462
463/*!
464 * \internal
465 * \brief Sorcery object type copy handler for \c ast_bucket
466 */
467static int bucket_copy_handler(const void *src, void *dst)
468{
469 const struct ast_bucket *src_bucket = src;
470 struct ast_bucket *dst_bucket = dst;
471
472 dst_bucket->scheme_impl = ao2_bump(src_bucket->scheme_impl);
473 ast_string_field_set(dst_bucket, scheme, src_bucket->scheme);
474 dst_bucket->created = src_bucket->created;
475 dst_bucket->modified = src_bucket->modified;
476
477 return 0;
478}
479
481{
482 return ast_sorcery_copy(bucket_sorcery, bucket);
483}
484
485struct ast_bucket *ast_bucket_retrieve(const char *uri)
486{
487 if (ast_strlen_zero(uri)) {
488 return NULL;
489 }
490
491 return ast_sorcery_retrieve_by_id(bucket_sorcery, "bucket", uri);
492}
493
495{
496 return ast_sorcery_is_stale(bucket_sorcery, bucket);
497}
498
500{
502}
503
505{
507}
508
509int ast_bucket_delete(struct ast_bucket *bucket)
510{
511 return ast_sorcery_delete(bucket_sorcery, bucket);
512}
513
514struct ast_json *ast_bucket_json(const struct ast_bucket *bucket)
515{
516 RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
517 struct ast_json *id, *files, *buckets;
518 struct ao2_iterator i;
519 char *uri;
520 int res = 0;
521
523 if (!json) {
524 return NULL;
525 }
526
528 if (!id) {
529 return NULL;
530 }
531
532 if (ast_json_object_set(json, "id", id)) {
533 return NULL;
534 }
535
536 buckets = ast_json_array_create();
537 if (!buckets) {
538 return NULL;
539 }
540
541 if (ast_json_object_set(json, "buckets", buckets)) {
542 return NULL;
543 }
544
545 i = ao2_iterator_init(bucket->buckets, 0);
546 for (; (uri = ao2_iterator_next(&i)); ao2_ref(uri, -1)) {
547 struct ast_json *bucket_uri = ast_json_string_create(uri);
548
549 if (!bucket_uri || ast_json_array_append(buckets, bucket_uri)) {
550 res = -1;
551 ao2_ref(uri, -1);
552 break;
553 }
554 }
556
557 if (res) {
558 return NULL;
559 }
560
561 files = ast_json_array_create();
562 if (!files) {
563 return NULL;
564 }
565
566 if (ast_json_object_set(json, "files", files)) {
567 return NULL;
568 }
569
570 i = ao2_iterator_init(bucket->files, 0);
571 for (; (uri = ao2_iterator_next(&i)); ao2_ref(uri, -1)) {
572 struct ast_json *file_uri = ast_json_string_create(uri);
573
574 if (!file_uri || ast_json_array_append(files, file_uri)) {
575 res = -1;
576 ao2_ref(uri, -1);
577 break;
578 }
579 }
581
582 if (res) {
583 return NULL;
584 }
585
586 ast_json_ref(json);
587 return json;
588}
589
590/*! \brief Hashing function for file metadata */
592
593/*! \brief Comparison function for file metadata */
595
596/*! \brief Destructor for bucket files */
597static void bucket_file_destroy(void *obj)
598{
599 struct ast_bucket_file *file = obj;
600
601 if (file->scheme_impl->destroy) {
602 file->scheme_impl->destroy(file);
603 }
604
605 ao2_cleanup(file->scheme_impl);
606 ao2_cleanup(file->metadata);
607}
608
609/*! \brief Allocator for bucket files */
610static void *bucket_file_alloc(const char *name)
611{
613
615 if (!file) {
616 return NULL;
617 }
618
619 if (ast_string_field_init(file, 128)) {
620 return NULL;
621 }
622
624 ast_bucket_metadata_hash_fn, NULL, ast_bucket_metadata_cmp_fn);
625 if (!file->metadata) {
626 return NULL;
627 }
628
629 ao2_ref(file, +1);
630 return file;
631}
632
634{
635#ifdef HAVE_URIPARSER
636 UriParserStateA state;
637 UriUriA full_uri;
638 size_t len;
639#else
640 char *tmp = ast_strdupa(uri);
641#endif
642 char *uri_scheme;
644 struct ast_bucket_file *file;
645
646 if (ast_strlen_zero(uri)) {
647 return NULL;
648 }
649
650#ifdef HAVE_URIPARSER
651 state.uri = &full_uri;
652 if (uriParseUriA(&state, uri) != URI_SUCCESS ||
653 !full_uri.scheme.first || !full_uri.scheme.afterLast ||
654 !full_uri.pathTail) {
655 uriFreeUriMembersA(&full_uri);
656 return NULL;
657 }
658
659 len = (full_uri.scheme.afterLast - full_uri.scheme.first) + 1;
660 uri_scheme = ast_alloca(len);
661 ast_copy_string(uri_scheme, full_uri.scheme.first, len);
662
663 uriFreeUriMembersA(&full_uri);
664#else
665 uri_scheme = tmp;
666 if (!(tmp = strchr(uri_scheme, ':'))) {
667 return NULL;
668 }
669 *tmp = '\0';
670#endif
671
672 scheme = ao2_find(schemes, uri_scheme, OBJ_KEY);
673 if (!scheme) {
674 return NULL;
675 }
676
677 file = ast_sorcery_alloc(bucket_sorcery, "file", uri);
678 if (!file) {
679 return NULL;
680 }
681
682 ao2_ref(scheme, +1);
683 file->scheme_impl = scheme;
684
685 ast_string_field_set(file, scheme, uri_scheme);
686
687 if (scheme->create && scheme->create(file)) {
688 ao2_ref(file, -1);
689 return NULL;
690 }
691
692 return file;
693}
694
696{
698}
699
700/*! \brief Copy a file, shamelessly taken from file.c */
701static int bucket_copy(const char *infile, const char *outfile)
702{
703 int ifd, ofd, len;
704 char buf[4096]; /* XXX make it larger. */
705
706 if ((ifd = open(infile, O_RDONLY)) < 0) {
707 ast_log(LOG_WARNING, "Unable to open %s in read-only mode, error: %s\n", infile, strerror(errno));
708 return -1;
709 }
710 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, AST_FILE_MODE)) < 0) {
711 ast_log(LOG_WARNING, "Unable to open %s in write-only mode, error: %s\n", outfile, strerror(errno));
712 close(ifd);
713 return -1;
714 }
715 while ( (len = read(ifd, buf, sizeof(buf)) ) ) {
716 int res;
717 if (len < 0) {
718 ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
719 break;
720 }
721 /* XXX handle partial writes */
722 res = write(ofd, buf, len);
723 if (res != len) {
724 ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
725 len = -1; /* error marker */
726 break;
727 }
728 }
729 close(ifd);
730 close(ofd);
731 if (len < 0) {
732 unlink(outfile);
733 return -1; /* error */
734 }
735 return 0; /* success */
736}
737
738/*!
739 * \internal
740 * \brief Sorcery object type copy handler for \c ast_bucket_file
741 */
742static int bucket_file_copy_handler(const void *src, void *dst)
743{
744 const struct ast_bucket_file *src_file = src;
745 struct ast_bucket_file *dst_file = dst;
746
747 dst_file->scheme_impl = ao2_bump(src_file->scheme_impl);
748 ast_string_field_set(dst_file, scheme, src_file->scheme);
749 dst_file->created = src_file->created;
750 dst_file->modified = src_file->modified;
751 strcpy(dst_file->path, src_file->path); /* safe */
752
753 dst_file->metadata = ao2_container_clone(src_file->metadata, 0);
754 if (!dst_file->metadata) {
755 return -1;
756 }
757
758 return 0;
759}
760
762{
764
765 if (!copy) {
766 return NULL;
767 }
768
769 ao2_cleanup(copy->metadata);
770 copy->metadata = ao2_container_clone(file->metadata, 0);
771 if (!copy->metadata ||
772 bucket_copy(file->path, copy->path)) {
773 return NULL;
774 }
775
776 ao2_ref(copy, +1);
777 return copy;
778}
779
781{
783}
784
786{
787 if (ast_strlen_zero(uri)) {
788 return NULL;
789 }
790
791 return ast_sorcery_retrieve_by_id(bucket_sorcery, "file", uri);
792}
793
795{
797}
798
800{
802}
803
805{
807}
808
810{
812}
813
815{
817}
818
820{
821 RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
822 struct ast_json *id, *metadata;
823 struct ao2_iterator i;
824 struct ast_bucket_metadata *attribute;
825 int res = 0;
826
828 if (!json) {
829 return NULL;
830 }
831
833 if (!id) {
834 return NULL;
835 }
836
837 if (ast_json_object_set(json, "id", id)) {
838 return NULL;
839 }
840
841 metadata = ast_json_object_create();
842 if (!metadata) {
843 return NULL;
844 }
845
846 if (ast_json_object_set(json, "metadata", metadata)) {
847 return NULL;
848 }
849
850 i = ao2_iterator_init(file->metadata, 0);
851 for (; (attribute = ao2_iterator_next(&i)); ao2_ref(attribute, -1)) {
852 struct ast_json *value = ast_json_string_create(attribute->value);
853
854 if (!value || ast_json_object_set(metadata, attribute->name, value)) {
855 res = -1;
856 break;
857 }
858 }
860
861 if (res) {
862 return NULL;
863 }
864
865 ast_json_ref(json);
866 return json;
867}
868
870{
871 int fd;
872
873 snprintf(file->path, sizeof(file->path), "%s/bucket-XXXXXX", ast_config_AST_CACHE_DIR);
874
875 fd = mkstemp(file->path);
876 if (fd < 0) {
877 return -1;
878 }
879
880 close(fd);
881 return 0;
882}
883
885{
886 if (!ast_strlen_zero(file->path)) {
887 unlink(file->path);
888 }
889}
890
891/*! \brief Hashing function for scheme container */
893
894/*! \brief Comparison function for scheme container */
896
897/*! \brief Cleanup function for graceful shutdowns */
898static void bucket_cleanup(void)
899{
902
905
907}
908
909/*! \brief Custom handler for translating from a string timeval to actual structure */
910static int timeval_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj)
911{
912 struct timeval *field = (struct timeval *)(obj + aco_option_get_argument(opt, 0));
913 return ast_get_timeval(var->value, field, ast_tv(0, 0), NULL);
914}
915
916/*! \brief Custom handler for translating from an actual structure timeval to string */
917static int timeval_struct2str(const void *obj, const intptr_t *args, char **buf)
918{
919 struct timeval *field = (struct timeval *)(obj + args[0]);
920 return (ast_asprintf(buf, "%lu.%06lu", (unsigned long)field->tv_sec, (unsigned long)field->tv_usec) < 0) ? -1 : 0;
921}
922
923/*! \brief Initialize bucket support */
925{
927
929 ast_bucket_scheme_hash_fn, NULL, ast_bucket_scheme_cmp_fn);
930 if (!schemes) {
931 ast_log(LOG_ERROR, "Failed to create container for Bucket schemes\n");
932 return -1;
933 }
934
936 ast_log(LOG_ERROR, "Failed to register sorcery wizard for 'bucket' intermediary\n");
937 return -1;
938 }
939
941 ast_log(LOG_ERROR, "Failed to register sorcery wizard for 'file' intermediary\n");
942 return -1;
943 }
944
945 if (!(bucket_sorcery = ast_sorcery_open())) {
946 ast_log(LOG_ERROR, "Failed to create sorcery instance for Bucket support\n");
947 return -1;
948 }
949
951 ast_log(LOG_ERROR, "Failed to apply intermediary for 'bucket' object type in Bucket sorcery\n");
952 return -1;
953 }
954
956 ast_log(LOG_ERROR, "Failed to register 'bucket' object type in Bucket sorcery\n");
957 return -1;
958 }
959
964
966 ast_log(LOG_ERROR, "Failed to apply intermediary for 'file' object type in Bucket sorcery\n");
967 return -1;
968 }
969
971 ast_log(LOG_ERROR, "Failed to register 'file' object type in Bucket sorcery\n");
972 return -1;
973 }
974
979
980 return 0;
981}
enum queue_result id
Definition: app_queue.c:1808
ast_mutex_t lock
Definition: app_sla.c:337
static int copy(char *infile, char *outfile)
Utility function to copy a file.
#define var
Definition: ast_expr2f.c:605
Asterisk main include file. File version handling, generic pbx functions.
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
Definition: clicompat.c:19
#define AST_FILE_MODE
Definition: asterisk.h:32
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:288
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition: astmm.h:267
#define ast_log
Definition: astobj2.c:42
#define ao2_iterator_next(iter)
Definition: astobj2.h:1911
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
#define OBJ_KEY
Definition: astobj2.h:1151
#define OBJ_POINTER
Definition: astobj2.h:1150
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition: astobj2.h:367
@ AO2_ALLOC_OPT_LOCK_RWLOCK
Definition: astobj2.h:365
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition: astobj2.h:1693
#define AO2_STRING_FIELD_CMP_FN(stype, field)
Creates a compare function for a structure string field.
Definition: astobj2.h:2048
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
int() ao2_callback_fn(void *obj, void *arg, int flags)
Type of a generic callback function.
Definition: astobj2.h:1226
#define ao2_link_flags(container, obj, flags)
Add an object to a container.
Definition: astobj2.h:1554
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1736
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a red-black tree container.
Definition: astobj2.h:1349
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define OBJ_PARTIAL_KEY
Definition: astobj2.h:1152
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
#define AO2_STRING_FIELD_HASH_FN(stype, field)
Creates a hash function for a structure string field.
Definition: astobj2.h:2032
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
@ OBJ_NOLOCK
Assume that the ao2_container is already locked.
Definition: astobj2.h:1063
@ OBJ_NODATA
Definition: astobj2.h:1044
@ OBJ_UNLINK
Definition: astobj2.h:1039
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Definition: astobj2.h:1303
#define ao2_container_clone(orig, flags)
Create a clone/copy of the given container.
Definition: astobj2.h:1419
@ AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT
Reject objects with duplicate keys in container.
Definition: astobj2.h:1188
static void * bucket_wizard_retrieve(const struct ast_sorcery *sorcery, void *data, const char *type, const char *id)
Callback function for retrieving a bucket.
Definition: bucket.c:83
struct ast_bucket * ast_bucket_alloc(const char *uri)
Allocate a new bucket.
Definition: bucket.c:401
static int bucket_file_wizard_create(const struct ast_sorcery *sorcery, void *data, void *object)
Callback function for creating a bucket file.
Definition: bucket.c:157
struct ast_bucket_file * ast_bucket_file_clone(struct ast_bucket_file *file)
Clone a bucket file.
Definition: bucket.c:780
#define METADATA_BUCKETS
Number of buckets for the container of metadata in a file.
Definition: bucket.c:52
static void bucket_file_destroy(void *obj)
Hashing function for file metadata.
Definition: bucket.c:597
int ast_bucket_file_metadata_set(struct ast_bucket_file *file, const char *name, const char *value)
Set a metadata attribute on a file to a specific value.
Definition: bucket.c:304
struct ast_bucket_file * ast_bucket_file_alloc(const char *uri)
Allocate a new bucket file.
Definition: bucket.c:633
static void bucket_cleanup(void)
Hashing function for scheme container.
Definition: bucket.c:898
static int bucket_wizard_is_stale(const struct ast_sorcery *sorcery, void *data, void *object)
Callback function for determining if a bucket is stale.
Definition: bucket.c:136
void ast_bucket_file_observer_remove(const struct ast_sorcery_observer *callbacks)
Remove an observer from bucket file creation and deletion.
Definition: bucket.c:804
static int bucket_file_wizard_is_stale(const struct ast_sorcery *sorcery, void *data, void *object)
Callback function for determining if a bucket is stale.
Definition: bucket.c:226
static int bucket_wizard_delete(const struct ast_sorcery *sorcery, void *data, void *object)
Callback function for deleting a bucket.
Definition: bucket.c:128
static void * bucket_file_alloc(const char *name)
Allocator for bucket files.
Definition: bucket.c:610
static struct ast_sorcery_wizard bucket_file_wizard
Intermediary file wizard.
Definition: bucket.c:238
static struct ast_sorcery * bucket_sorcery
Sorcery instance for all bucket operations.
Definition: bucket.c:55
int ast_bucket_file_temporary_create(struct ast_bucket_file *file)
Common file snapshot creation callback for creating a temporary file.
Definition: bucket.c:869
static struct ast_sorcery_wizard bucket_wizard
Intermediary bucket wizard.
Definition: bucket.c:148
void ast_bucket_file_metadata_callback(struct ast_bucket_file *file, ao2_callback_fn cb, void *arg)
Execute a callback function on the metadata associated with a file.
Definition: bucket.c:334
int ast_bucket_create(struct ast_bucket *bucket)
Create a new bucket in backend storage.
Definition: bucket.c:458
static int bucket_file_wizard_update(const struct ast_sorcery *sorcery, void *data, void *object)
Callback function for updating a bucket file.
Definition: bucket.c:210
int ast_bucket_file_create(struct ast_bucket_file *file)
Create a new bucket file in backend storage.
Definition: bucket.c:695
static int timeval_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj)
Custom handler for translating from a string timeval to actual structure.
Definition: bucket.c:910
static void * bucket_file_wizard_retrieve(const struct ast_sorcery *sorcery, void *data, const char *type, const char *id)
Callback function for retrieving a bucket file.
Definition: bucket.c:165
static int timeval_struct2str(const void *obj, const intptr_t *args, char **buf)
Custom handler for translating from an actual structure timeval to string.
Definition: bucket.c:917
static int bucket_copy_handler(const void *src, void *dst)
Definition: bucket.c:467
static struct ao2_container * schemes
Container of registered schemes.
Definition: bucket.c:58
int ast_bucket_file_metadata_unset(struct ast_bucket_file *file, const char *name)
Unset a specific metadata attribute on a file.
Definition: bucket.c:318
int ast_bucket_file_update(struct ast_bucket_file *file)
Update an existing bucket file in backend storage.
Definition: bucket.c:809
struct ast_bucket_metadata * ast_bucket_file_metadata_get(struct ast_bucket_file *file, const char *name)
Retrieve a metadata attribute from a file.
Definition: bucket.c:329
int ast_bucket_file_observer_add(const struct ast_sorcery_observer *callbacks)
Add an observer for bucket file creation and deletion operations.
Definition: bucket.c:799
struct ast_bucket_file * ast_bucket_file_copy(struct ast_bucket_file *file, const char *uri)
Copy a bucket file to a new URI.
Definition: bucket.c:761
int ast_bucket_is_stale(struct ast_bucket *bucket)
Retrieve whether or not the backing datastore views the bucket as stale.
Definition: bucket.c:494
static void * bucket_alloc(const char *name)
Allocator for buckets.
Definition: bucket.c:372
struct ast_bucket_file * ast_bucket_file_retrieve(const char *uri)
Retrieve a bucket file.
Definition: bucket.c:785
void ast_bucket_observer_remove(const struct ast_sorcery_observer *callbacks)
Remove an observer from bucket creation and deletion.
Definition: bucket.c:504
static int bucket_file_copy_handler(const void *src, void *dst)
Definition: bucket.c:742
int __ast_bucket_scheme_register(const char *name, struct ast_sorcery_wizard *bucket, struct ast_sorcery_wizard *file, bucket_file_create_cb create_cb, bucket_file_destroy_cb destroy_cb, struct ast_module *module)
Register support for a specific scheme.
Definition: bucket.c:247
#define SCHEME_BUCKETS
Number of buckets for the container of schemes.
Definition: bucket.c:49
static void bucket_destroy(void *obj)
Destructor for buckets.
Definition: bucket.c:341
struct ast_bucket * ast_bucket_retrieve(const char *uri)
Retrieve information about a bucket.
Definition: bucket.c:485
int ast_bucket_file_delete(struct ast_bucket_file *file)
Delete a bucket file from backend storage.
Definition: bucket.c:814
struct ast_json * ast_bucket_json(const struct ast_bucket *bucket)
Get a JSON representation of a bucket.
Definition: bucket.c:514
static struct ast_bucket_metadata * bucket_metadata_alloc(const char *name, const char *value)
Allocator for metadata attributes.
Definition: bucket.c:286
struct ast_json * ast_bucket_file_json(const struct ast_bucket_file *file)
Get a JSON representation of a bucket file.
Definition: bucket.c:819
struct ast_bucket * ast_bucket_clone(struct ast_bucket *bucket)
Clone a bucket.
Definition: bucket.c:480
void ast_bucket_file_temporary_destroy(struct ast_bucket_file *file)
Common file snapshot destruction callback for deleting a temporary file.
Definition: bucket.c:884
int ast_bucket_observer_add(const struct ast_sorcery_observer *callbacks)
Add an observer for bucket creation and deletion operations.
Definition: bucket.c:499
static int bucket_file_wizard_delete(const struct ast_sorcery *sorcery, void *data, void *object)
Callback function for deleting a bucket file.
Definition: bucket.c:218
static int bucket_copy(const char *infile, const char *outfile)
Copy a file, shamelessly taken from file.c.
Definition: bucket.c:701
static int bucket_wizard_create(const struct ast_sorcery *sorcery, void *data, void *object)
Callback function for creating a bucket.
Definition: bucket.c:75
int ast_bucket_init(void)
Initialize bucket support.
Definition: bucket.c:924
static int bucket_rbtree_str_sort_cmp(const void *obj_left, const void *obj_right, int flags)
Sorting function for red black tree string container.
Definition: bucket.c:352
int ast_bucket_file_is_stale(struct ast_bucket_file *file)
Retrieve whether or not the backing datastore views the bucket file as stale.
Definition: bucket.c:794
int ast_bucket_delete(struct ast_bucket *bucket)
Delete a bucket from backend storage.
Definition: bucket.c:509
Bucket File API.
void(* bucket_file_destroy_cb)(struct ast_bucket_file *file)
A callback function invoked when destroying a file snapshot.
Definition: bucket.h:113
int(* bucket_file_create_cb)(struct ast_bucket_file *file)
A callback function invoked when creating a file snapshot.
Definition: bucket.h:106
enum cc_state state
Definition: ccss.c:399
static const char type[]
Definition: chan_ooh323.c:109
Configuration option-handling.
#define STRFLDSET(type,...)
Convert a struct and a list of stringfield fields to an argument list of field offsets.
#define FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
@ OPT_STRINGFIELD_T
Type for default option handler for stringfields.
intptr_t aco_option_get_argument(const struct aco_option *option, unsigned int position)
Get the offset position for an argument within a config option.
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
Generic File Format Support. Should be included by clients of the file handling routines....
static const char name[]
Definition: format_mp3.c:68
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
Support for logging to various files, console and syslog Configuration in file logger....
#define LOG_ERROR
#define ast_verb(level,...)
#define LOG_WARNING
Asterisk JSON abstraction layer.
struct ast_json * ast_json_string_create(const char *value)
Construct a JSON string from value.
Definition: json.c:278
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
int ast_json_array_append(struct ast_json *array, struct ast_json *value)
Append to an array.
Definition: json.c:378
struct ast_json * ast_json_object_create(void)
Create a new JSON object.
Definition: json.c:399
struct ast_json * ast_json_array_create(void)
Create a empty JSON array.
Definition: json.c:362
struct ast_json * ast_json_ref(struct ast_json *value)
Increase refcount on value.
Definition: json.c:67
int ast_json_object_set(struct ast_json *object, const char *key, struct ast_json *value)
Set a field in a JSON object.
Definition: json.c:414
#define SCOPED_AO2WRLOCK(varname, obj)
scoped lock specialization for ao2 write locks.
Definition: lock.h:618
#define SCOPED_AO2RDLOCK(varname, obj)
scoped lock specialization for ao2 read locks.
Definition: lock.h:613
int errno
Asterisk module definitions.
#define ast_module_shutdown_ref(mod)
Prevent unload of the module before shutdown.
Definition: module.h:478
Asterisk file paths, configured in asterisk.conf.
const char * ast_config_AST_CACHE_DIR
Definition: options.c:150
static struct ast_sorcery * sorcery
struct @471 callbacks
#define NULL
Definition: resample.c:96
Sorcery Data Access Layer API.
#define ast_sorcery_unref(sorcery)
Decrease the reference count of a sorcery structure.
Definition: sorcery.h:1500
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2317
#define ast_sorcery_object_field_register_nodoc(sorcery, type, name, default_val, opt_type, flags,...)
Register a field within an object without documentation.
Definition: sorcery.h:987
int ast_sorcery_wizard_unregister(const struct ast_sorcery_wizard *interface)
Unregister a sorcery wizard.
Definition: sorcery.c:474
void ast_sorcery_observer_remove(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks)
Remove an observer from a specific object type.
Definition: sorcery.c:2423
#define ast_sorcery_object_field_register_custom_nodoc(sorcery, type, name, default_val, config_handler, sorcery_handler, multiple_handler, flags,...)
Register a field within an object with custom handlers without documentation.
Definition: sorcery.h:1041
void ast_sorcery_object_set_copy_handler(struct ast_sorcery *sorcery, const char *type, sorcery_copy_handler copy)
Set the copy handler for an object type.
Definition: sorcery.c:1128
int ast_sorcery_create(const struct ast_sorcery *sorcery, void *object)
Create and potentially persist an object using an available wizard.
Definition: sorcery.c:2062
void * ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
Retrieve an object using its unique identifier.
Definition: sorcery.c:1853
int __ast_sorcery_wizard_register(const struct ast_sorcery_wizard *interface, struct ast_module *module)
Register a sorcery wizard.
Definition: sorcery.c:432
int ast_sorcery_observer_add(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks)
Add an observer to a specific object type.
Definition: sorcery.c:2391
#define ast_sorcery_internal_object_register(sorcery, type, alloc, transform, apply)
Register an internal, hidden object type.
Definition: sorcery.h:867
void * ast_sorcery_generic_alloc(size_t size, ao2_destructor_fn destructor)
Allocate a generic sorcery capable object.
Definition: sorcery.c:1728
void * ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, const char *id)
Allocate an object.
Definition: sorcery.c:1744
int ast_sorcery_update(const struct ast_sorcery *sorcery, void *object)
Update an object.
Definition: sorcery.c:2150
#define ast_sorcery_apply_default(sorcery, type, name, data)
Definition: sorcery.h:476
struct ast_json * ast_sorcery_objectset_json_create(const struct ast_sorcery *sorcery, const void *object)
Create an object set in JSON format for an object.
Definition: sorcery.c:1565
#define ast_sorcery_open()
Open a new sorcery structure.
Definition: sorcery.h:406
int ast_sorcery_is_stale(const struct ast_sorcery *sorcery, void *object)
Determine if a sorcery object is stale with respect to its backing datastore.
Definition: sorcery.c:2288
int ast_sorcery_delete(const struct ast_sorcery *sorcery, void *object)
Delete an object.
Definition: sorcery.c:2238
void * ast_sorcery_copy(const struct ast_sorcery *sorcery, const void *object)
Create a copy of an object.
Definition: sorcery.c:1778
@ AST_SORCERY_APPLY_FAIL
Definition: sorcery.h:425
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
String manipulation functions.
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
int ast_get_timeval(const char *src, struct timeval *tv, struct timeval _default, int *consumed)
Parse a time (float) string.
Definition: utils.c:2419
Generic container type.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
Bucket file structure, contains reference to file and information about it.
Definition: bucket.h:78
struct timeval modified
When this file was last modified.
Definition: bucket.h:91
struct timeval created
When this file was created.
Definition: bucket.h:89
const ast_string_field scheme
Definition: bucket.h:87
struct ao2_container * metadata
Container of metadata attributes about file.
Definition: bucket.h:93
char path[PATH_MAX]
Local path to this file.
Definition: bucket.h:95
struct ast_bucket_scheme * scheme_impl
Scheme implementation in use.
Definition: bucket.h:82
Bucket metadata structure, AO2 key value pair.
Definition: bucket.h:47
const char * value
Value of the attribute.
Definition: bucket.h:51
const char * name
Name of the attribute.
Definition: bucket.h:49
char data[0]
Storage for the above name and value.
Definition: bucket.h:53
Structure for available schemes.
Definition: bucket.c:61
struct ast_sorcery_wizard * file
Wizard for files.
Definition: bucket.c:65
bucket_file_create_cb create
Pointer to the file snapshot creation callback.
Definition: bucket.c:67
bucket_file_destroy_cb destroy
Pointer to the file snapshot destruction callback.
Definition: bucket.c:69
struct ast_sorcery_wizard * bucket
Wizard for buckets.
Definition: bucket.c:63
char name[0]
Name of the scheme.
Definition: bucket.c:71
Bucket structure, contains other buckets and files.
Definition: bucket.h:57
struct ao2_container * buckets
Container of string URIs of buckets within this bucket.
Definition: bucket.h:72
struct timeval modified
When this bucket was last modified.
Definition: bucket.h:70
struct timeval created
When this bucket was created.
Definition: bucket.h:68
struct ao2_container * files
Container of string URIs of files within this bucket.
Definition: bucket.h:74
const ast_string_field scheme
Definition: bucket.h:66
struct ast_bucket_scheme * scheme_impl
Scheme implementation in use.
Definition: bucket.h:61
Abstract JSON element (object, array, string, int, ...).
Interface for a sorcery object type observer.
Definition: sorcery.h:332
Interface for a sorcery wizard.
Definition: sorcery.h:276
struct ast_module * module
Pointer to the Asterisk module this wizard is implemented by.
Definition: sorcery.h:281
const char * name
Name of the wizard.
Definition: sorcery.h:278
void *(* retrieve_id)(const struct ast_sorcery *sorcery, void *data, const char *type, const char *id)
Callback for retrieving an object using an id.
Definition: sorcery.h:296
int(* create)(const struct ast_sorcery *sorcery, void *data, void *object)
Callback for creating an object.
Definition: sorcery.h:293
int(* delete)(const struct ast_sorcery *sorcery, void *data, void *object)
Callback for deleting an object.
Definition: sorcery.h:319
int(* is_stale)(const struct ast_sorcery *sorcery, void *data, void *object)
Callback for whether or not the wizard believes the object is stale.
Definition: sorcery.h:325
Full structure for sorcery.
Definition: sorcery.c:230
Structure for variables, used for configurations and for channel variables.
int value
Definition: syslog.c:37
const char * args
struct timeval ast_tv(ast_time_t sec, ast_suseconds_t usec)
Returns a timeval from sec, usec.
Definition: time.h:235
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941