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