[asterisk-commits] file: branch file/bucket r396743 - in /team/file/bucket: ./ build_tools/ incl...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Thu Aug 15 10:25:08 CDT 2013


Author: file
Date: Thu Aug 15 10:25:04 2013
New Revision: 396743

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=396743
Log:
Incorporate review feedback.

Still need to document stuff some more and take care of temporary file stuff.

Modified:
    team/file/bucket/build_tools/menuselect-deps.in
    team/file/bucket/configure
    team/file/bucket/configure.ac
    team/file/bucket/include/asterisk/autoconfig.h.in
    team/file/bucket/include/asterisk/bucket.h
    team/file/bucket/include/asterisk/config_options.h
    team/file/bucket/main/Makefile
    team/file/bucket/main/bucket.c
    team/file/bucket/main/config_options.c
    team/file/bucket/makeopts.in
    team/file/bucket/tests/test_bucket.c

Modified: team/file/bucket/build_tools/menuselect-deps.in
URL: http://svnview.digium.com/svn/asterisk/team/file/bucket/build_tools/menuselect-deps.in?view=diff&rev=396743&r1=396742&r2=396743
==============================================================================
--- team/file/bucket/build_tools/menuselect-deps.in (original)
+++ team/file/bucket/build_tools/menuselect-deps.in Thu Aug 15 10:25:04 2013
@@ -26,6 +26,7 @@
 IXJUSER=@PBX_IXJUSER@
 JACK=@PBX_JACK@
 JANSSON=@PBX_JANSSON@
+URIPARSER=@PBX_URIPARSER@
 KQUEUE=@PBX_KQUEUE@
 LDAP=@PBX_LDAP@
 LIBEDIT=@PBX_LIBEDIT@

Modified: team/file/bucket/configure.ac
URL: http://svnview.digium.com/svn/asterisk/team/file/bucket/configure.ac?view=diff&rev=396743&r1=396742&r2=396743
==============================================================================
--- team/file/bucket/configure.ac (original)
+++ team/file/bucket/configure.ac Thu Aug 15 10:25:04 2013
@@ -408,6 +408,7 @@
 AST_EXT_LIB_SETUP([ISDNNET], [ISDN4Linux], [isdnnet])
 AST_EXT_LIB_SETUP([JACK], [Jack Audio Connection Kit], [jack])
 AST_EXT_LIB_SETUP([JANSSON], [Jansson JSON library], [jansson])
+AST_EXT_LIB_SETUP([URIPARSER], [uriparser library], [uriparser])
 AST_EXT_LIB_SETUP([KQUEUE], [kqueue support], [kqueue])
 AST_EXT_LIB_SETUP([LDAP], [OpenLDAP], [ldap])
 AST_LIBCURL_CHECK_CONFIG([], [7.10.1])
@@ -541,6 +542,13 @@
 
 if test "x$JANSSON_LIB" == "x"; then
   AC_MSG_ERROR([*** JSON support not found (this typically means the libjansson development package is missing)])
+fi
+
+# Find required uriparser support.
+AST_EXT_LIB_CHECK([URIPARSER], [uriparser], [uriParseUriA], [uriparser/Uri.h])
+
+if test "x$URIPARSER_LIB" == "x"; then
+   AC_MSG_ERROR([*** uriparser support not found (this typically means the liburiparser development package is missing)])
 fi
 
 # Another mandatory item (unless it's explicitly disabled)

Modified: team/file/bucket/include/asterisk/autoconfig.h.in
URL: http://svnview.digium.com/svn/asterisk/team/file/bucket/include/asterisk/autoconfig.h.in?view=diff&rev=396743&r1=396742&r2=396743
==============================================================================
--- team/file/bucket/include/asterisk/autoconfig.h.in (original)
+++ team/file/bucket/include/asterisk/autoconfig.h.in Thu Aug 15 10:25:04 2013
@@ -1018,6 +1018,9 @@
 
 /* Define to 1 if you have the `unsetenv' function. */
 #undef HAVE_UNSETENV
+
+/* Define to 1 if you have the uriparser library library. */
+#undef HAVE_URIPARSER
 
 /* Define to 1 if you have the `utime' function. */
 #undef HAVE_UTIME

Modified: team/file/bucket/include/asterisk/bucket.h
URL: http://svnview.digium.com/svn/asterisk/team/file/bucket/include/asterisk/bucket.h?view=diff&rev=396743&r1=396742&r2=396743
==============================================================================
--- team/file/bucket/include/asterisk/bucket.h (original)
+++ team/file/bucket/include/asterisk/bucket.h Thu Aug 15 10:25:04 2013
@@ -28,7 +28,8 @@
  * Bucket is an API which provides directory and file access in a generic fashion. It is
  * implemented as a thin wrapper over the sorcery data access layer API and is written in
  * a pluggable fashion to allow different backend storage mechanisms.
-  */
+ *
+ */
 
 #ifndef _ASTERISK_BUCKET_H
 #define _ASTERISK_BUCKET_H

Modified: team/file/bucket/include/asterisk/config_options.h
URL: http://svnview.digium.com/svn/asterisk/team/file/bucket/include/asterisk/config_options.h?view=diff&rev=396743&r1=396742&r2=396743
==============================================================================
--- team/file/bucket/include/asterisk/config_options.h (original)
+++ team/file/bucket/include/asterisk/config_options.h Thu Aug 15 10:25:04 2013
@@ -53,17 +53,6 @@
 	ACO_EXACT = 1,
 	ACO_REGEX,
 };
-
-
-/*! \brief A callback function for handling a particular option
- * \param opt The option being configured
- * \param var The config variable to use to configure \a obj
- * \param obj The object to be configured
- *
- * \retval 0 Parsing and recording the config value succeeded
- * \retval non-zero Failure. Parsing should stop and no reload applied
- */
-typedef int (*aco_option_handler)(const struct aco_option *opt, struct ast_variable *var, void *obj);
 
 /*! Callback functions for option parsing via aco_process_config() */
 
@@ -448,21 +437,15 @@
 	OPT_UINT_T,
 };
 
-/*! \brief Configuration option structure */
-struct aco_option {
-	const char *name;
-	const char *aliased_to;
-	const char *default_val;
-	enum aco_matchtype match_type;
-	regex_t *name_regex;
-	struct aco_type **obj;
-	enum aco_option_type type;
-	aco_option_handler handler;
-	unsigned int flags;
-	unsigned char deprecated:1;
-	size_t argc;
-	intptr_t args[0];
-};
+/*! \brief A callback function for handling a particular option
+ * \param opt The option being configured
+ * \param var The config variable to use to configure \a obj
+ * \param obj The object to be configured
+ *
+ * \retval 0 Parsing and recording the config value succeeded
+ * \retval non-zero Failure. Parsing should stop and no reload applied
+ */
+typedef int (*aco_option_handler)(const struct aco_option *opt, struct ast_variable *var, void *obj);
 
 /*! \brief Allocate a container to hold config options */
 struct ao2_container *aco_option_container_alloc(void);
@@ -605,6 +588,16 @@
  * \retval value of the flags on the config option
  */
 unsigned int aco_option_get_flags(const struct aco_option *option);
+
+/*!
+ * \brief Get the offset position for an argument within a config option
+ *
+ * \param option Pointer to the aco_option struct
+ * \param arg Argument number
+ *
+ * \retval position of the argument
+ */
+intptr_t aco_option_get_argument(const struct aco_option *option, unsigned int position);
 
 /*! \note  Everything below this point is to handle converting varargs
  * containing field names, to varargs containing a count of args, followed

Modified: team/file/bucket/main/Makefile
URL: http://svnview.digium.com/svn/asterisk/team/file/bucket/main/Makefile?view=diff&rev=396743&r1=396742&r2=396743
==============================================================================
--- team/file/bucket/main/Makefile (original)
+++ team/file/bucket/main/Makefile Thu Aug 15 10:25:04 2013
@@ -36,6 +36,7 @@
 AST_LIBS+=$(SQLITE3_LIB)
 AST_LIBS+=$(ASTSSL_LIBS)
 AST_LIBS+=$(JANSSON_LIB)
+AST_LIBS+=$(URIPARSER_LIB)
 AST_LIBS+=$(UUID_LIB)
 AST_LIBS+=$(CRYPT_LIB)
 
@@ -154,6 +155,7 @@
 asterisk.o: _ASTCFLAGS+=$(LIBEDIT_INCLUDE)
 cli.o: _ASTCFLAGS+=$(LIBEDIT_INCLUDE)
 json.o: _ASTCFLAGS+=$(JANSSON_INCLUDE)
+bucket.o: _ASTCFLAGS+=$(URIPARSER_INCLUDE)
 crypt.o: _ASTCFLAGS+=$(CRYPT_INCLUDE)
 uuid.o: _ASTCFLAGS+=$(UUID_INCLUDE)
 

Modified: team/file/bucket/main/bucket.c
URL: http://svnview.digium.com/svn/asterisk/team/file/bucket/main/bucket.c?view=diff&rev=396743&r1=396742&r2=396743
==============================================================================
--- team/file/bucket/main/bucket.c (original)
+++ team/file/bucket/main/bucket.c Thu Aug 15 10:25:04 2013
@@ -24,12 +24,15 @@
  */
 
 /*** MODULEINFO
+	<depend>uriparser</depend>
 	<support_level>core</support_level>
  ***/
 
 #include "asterisk.h"
 
 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include <uriparser/Uri.h>
 
 #include "asterisk/logger.h"
 #include "asterisk/sorcery.h"
@@ -72,48 +75,6 @@
 	char name[0];
 };
 
-/*!
- * \brief Simple URI parser
- *
- * \param uri Full URI
- * \param scheme The scheme in the URI
- * \param name The name of the object in the URI
- *
- * \retval 0 success
- * \retval -1 failure
- *
- * \note The URI passed in will be modified
- */
-static int bucket_uri_parse(char *uri, char **scheme, char **name)
-{
-	char *tmp;
-
-	/* If no URI has been specified this is invalid */
-	if (ast_strlen_zero(uri)) {
-		return -1;
-	}
-
-	*scheme = DEFAULT_UNSPECIFIED_SCHEME;
-	*name = NULL;
-
-	/* Assume the naming starts at the front until proven otherwise */
-	*name = uri;
-
-	/* Determine the scheme from the provided URI */
-	if ((tmp = strstr(uri, "://"))) {
-		*scheme = uri;
-		*tmp++ = '\0';
-		*name = tmp;
-	}
-
-	/* Determine the name */
-	if ((tmp = strrchr(*name, '/'))) {
-		*name = tmp + 1;
-	}
-
-	return 0;
-}
-
 /*! \brief Callback function for creating a bucket */
 static int bucket_wizard_create(const struct ast_sorcery *sorcery, void *data, void *object)
 {
@@ -132,20 +93,28 @@
 static void *bucket_wizard_retrieve(const struct ast_sorcery *sorcery, void *data, const char *type,
 	const char *id)
 {
-	char *uri, *uri_scheme, *uri_name;
+	UriParserStateA state;
+	UriUriA uri;
 	SCOPED_AO2RDLOCK(lock, schemes);
+	size_t len;
+	char *uri_scheme;
 	RAII_VAR(struct bucket_scheme *, scheme, NULL, ao2_cleanup);
 
-	if (!(uri = ast_strdupa(id))) {
-		return NULL;
-	}
-
-	if (bucket_uri_parse(uri, &uri_scheme, &uri_name) ||
-		ast_strlen_zero(uri_scheme) || ast_strlen_zero(uri_name)) {
-		return NULL;
-	}
+	state.uri = &uri;
+	if (uriParseUriA(&state, id) != URI_SUCCESS ||
+		!uri.scheme.first || !uri.scheme.afterLast) {
+		uriFreeUriMembersA(&uri);
+		return NULL;
+	}
+
+	len = (uri.scheme.afterLast - uri.scheme.first) + 1;
+	uri_scheme = ast_alloca(len);
+	ast_copy_string(uri_scheme, uri.scheme.first, len);
 
 	scheme = ao2_find(schemes, uri_scheme, OBJ_KEY | OBJ_NOLOCK);
+
+	uriFreeUriMembersA(&uri);
+
 	if (!scheme) {
 		return NULL;
 	}
@@ -193,20 +162,28 @@
 static void *bucket_file_wizard_retrieve(const struct ast_sorcery *sorcery, void *data, const char *type,
 	const char *id)
 {
-	char *uri, *uri_scheme, *uri_name;
+	UriParserStateA state;
+	UriUriA uri;
+	size_t len;
+	char *uri_scheme;
 	SCOPED_AO2RDLOCK(lock, schemes);
 	RAII_VAR(struct bucket_scheme *, scheme, NULL, ao2_cleanup);
 
-	if (!(uri = ast_strdupa(id))) {
-		return NULL;
-	}
-
-	if (bucket_uri_parse(uri, &uri_scheme, &uri_name) ||
-		ast_strlen_zero(uri_scheme) || ast_strlen_zero(uri_name)) {
-		return NULL;
-	}
+	state.uri = &uri;
+	if (uriParseUriA(&state, id) != URI_SUCCESS ||
+		!uri.scheme.first || !uri.scheme.afterLast) {
+		uriFreeUriMembersA(&uri);
+		return NULL;
+	}
+
+	len = (uri.scheme.afterLast - uri.scheme.first) + 1;
+	uri_scheme = ast_alloca(len);
+	ast_copy_string(uri_scheme, uri.scheme.first, len);
 
 	scheme = ao2_find(schemes, uri_scheme, OBJ_KEY | OBJ_NOLOCK);
+
+	uriFreeUriMembersA(&uri);
+
 	if (!scheme) {
 		return NULL;
 	}
@@ -344,6 +321,26 @@
 	ao2_cleanup(bucket->files);
 }
 
+/*! \brief Sorting function for red black tree string container */
+static int bucket_rbtree_str_sort_cmp(const void *obj_left, const void *obj_right, int flags)
+{
+	const char *str_left = obj_left;
+	const char *str_right = obj_right;
+	int cmp = 0;
+
+	switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
+	default:
+	case OBJ_POINTER:
+	case OBJ_KEY:
+		cmp = strcmp(str_left, str_right);
+		break;
+	case OBJ_PARTIAL_KEY:
+		cmp = strncmp(str_left, str_right, strlen(str_right));
+		break;
+	}
+	return cmp;
+}
+
 /*! \brief Allocator for buckets */
 static void *bucket_alloc(const char *name)
 {
@@ -358,12 +355,14 @@
 		return NULL;
 	}
 
-	bucket->buckets = ast_str_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, BUCKET_BUCKETS);
+	bucket->buckets = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_NOLOCK,
+		AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT, bucket_rbtree_str_sort_cmp, NULL);
 	if (!bucket->buckets) {
 		return NULL;
 	}
 
-	bucket->files = ast_str_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, FILE_BUCKETS);
+	bucket->files = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_NOLOCK,
+		AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT, bucket_rbtree_str_sort_cmp, NULL);
 	if (!bucket->files) {
 		return NULL;
 	}
@@ -374,17 +373,29 @@
 
 struct ast_bucket *ast_bucket_alloc(const char *uri)
 {
-	char *full_uri, *uri_scheme, *uri_name;
+	UriParserStateA state;
+	UriUriA full_uri;
+	size_t len;
+	char *uri_scheme, *uri_name;
 	struct ast_bucket *bucket;
 
-	if (!(full_uri = ast_strdupa(uri))) {
-		return NULL;
-	}
-
-	if (bucket_uri_parse(full_uri, &uri_scheme, &uri_name) ||
-		ast_strlen_zero(uri_scheme) || ast_strlen_zero(uri_name)) {
-		return NULL;
-	}
+	state.uri = &full_uri;
+	if (uriParseUriA(&state, uri) != URI_SUCCESS ||
+		!full_uri.scheme.first || !full_uri.scheme.afterLast ||
+		!full_uri.pathTail) {
+		uriFreeUriMembersA(&full_uri);
+		return NULL;
+	}
+
+	len = (full_uri.scheme.afterLast - full_uri.scheme.first) + 1;
+	uri_scheme = ast_alloca(len);
+	ast_copy_string(uri_scheme, full_uri.scheme.first, len);
+
+	len = (full_uri.pathTail->text.afterLast - full_uri.pathTail->text.first) + 1;
+	uri_name = ast_alloca(len);
+	ast_copy_string(uri_name, full_uri.pathTail->text.first, len);
+
+	uriFreeUriMembersA(&full_uri);
 
 	if (!(bucket = ast_sorcery_alloc(bucket_sorcery, "bucket", uri))) {
 		return NULL;
@@ -444,12 +455,15 @@
 	}
 
 	if (ast_json_object_set(json, "id", id)) {
-		ast_json_unref(id);
 		return NULL;
 	}
 
 	buckets = ast_json_array_create();
 	if (!buckets) {
+		return NULL;
+	}
+
+	if (ast_json_object_set(json, "buckets", buckets)) {
 		return NULL;
 	}
 
@@ -457,24 +471,23 @@
 	for (; (uri = ao2_iterator_next(&i)); ao2_ref(uri, -1)) {
 		struct ast_json *bucket_uri = ast_json_string_create(uri);
 
-		if (!bucket_uri) {
+		if (!bucket_uri || ast_json_array_append(buckets, bucket_uri)) {
 			res = -1;
 			break;
 		}
-
-		ast_json_array_append(buckets, bucket_uri);
 	}
 	ao2_iterator_destroy(&i);
 
 	if (res) {
-		ast_json_unref(buckets);
-		return NULL;
-	}
-
-	ast_json_object_set(json, "buckets", buckets);
+		return NULL;
+	}
 
 	files = ast_json_array_create();
 	if (!files) {
+		return NULL;
+	}
+
+	if (ast_json_object_set(json, "files", files)) {
 		return NULL;
 	}
 
@@ -482,21 +495,16 @@
 	for (; (uri = ao2_iterator_next(&i)); ao2_ref(uri, -1)) {
 		struct ast_json *file_uri = ast_json_string_create(uri);
 
-		if (!file_uri) {
+		if (!file_uri || ast_json_array_append(files, file_uri)) {
 			res = -1;
 			break;
 		}
-
-		ast_json_array_append(files, file_uri);
 	}
 	ao2_iterator_destroy(&i);
 
 	if (res) {
-		ast_json_unref(files);
-		return NULL;
-	}
-
-	ast_json_object_set(json, "files", files);
+		return NULL;
+	}
 
 	ast_json_ref(json);
 	return json;
@@ -505,10 +513,21 @@
 /*! \brief Hashing function for file metadata */
 static int bucket_file_metadata_hash(const void *obj, const int flags)
 {
-	const struct ast_bucket_metadata *metadata = obj;
-	const char *name = obj;
-
-	return ast_str_hash(flags & OBJ_KEY ? name : metadata->name);
+	const struct ast_bucket_metadata *object;
+	const char *key;
+
+	switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
+	case OBJ_KEY:
+		key = obj;
+		return ast_str_hash(key);
+	case OBJ_POINTER:
+		object = obj;
+		return ast_str_hash(object->name);
+	default:
+		/* Hash can only work on something with a full key */
+		ast_assert(0);
+		return 0;
+	}
 }
 
 /*! \brief Comparison function for file metadata */
@@ -558,18 +577,30 @@
 
 struct ast_bucket_file *ast_bucket_file_alloc(const char *uri)
 {
-	char *full_uri, *uri_scheme, *uri_name;
+	UriParserStateA state;
+	UriUriA full_uri;
+	size_t len;
+	char *uri_scheme, *uri_name;
 	struct ast_bucket_file *file;
 	int fd;
 
-	if (!(full_uri = ast_strdupa(uri))) {
-		return NULL;
-	}
-
-	if (bucket_uri_parse(full_uri, &uri_scheme, &uri_name) ||
-		ast_strlen_zero(uri_scheme) || ast_strlen_zero(uri_name)) {
-		return NULL;
-	}
+	state.uri = &full_uri;
+	if (uriParseUriA(&state, uri) != URI_SUCCESS ||
+		!full_uri.scheme.first || !full_uri.scheme.afterLast ||
+		!full_uri.pathTail) {
+		uriFreeUriMembersA(&full_uri);
+		return NULL;
+	}
+
+	len = (full_uri.scheme.afterLast - full_uri.scheme.first) + 1;
+	uri_scheme = ast_alloca(len);
+	ast_copy_string(uri_scheme, full_uri.scheme.first, len);
+
+	len = (full_uri.pathTail->text.afterLast - full_uri.pathTail->text.first) + 1;
+	uri_name = ast_alloca(len);
+	ast_copy_string(uri_name, full_uri.pathTail->text.first, len);
+
+	uriFreeUriMembersA(&full_uri);
 
 	if (!(file = ast_sorcery_alloc(bucket_sorcery, "file", uri))) {
 		return NULL;
@@ -601,11 +632,11 @@
 	char buf[4096];	/* XXX make it lerger. */
 
 	if ((ifd = open(infile, O_RDONLY)) < 0) {
-		ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", infile);
+		ast_log(LOG_WARNING, "Unable to open %s in read-only mode, error: %s\n", infile, strerror(errno));
 		return -1;
 	}
 	if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, AST_FILE_MODE)) < 0) {
-		ast_log(LOG_WARNING, "Unable to open %s in write-only mode\n", outfile);
+		ast_log(LOG_WARNING, "Unable to open %s in write-only mode, error: %s\n", outfile, strerror(errno));
 		close(ifd);
 		return -1;
 	}
@@ -634,25 +665,20 @@
 
 struct ast_bucket_file *ast_bucket_file_copy(struct ast_bucket_file *file, const char *uri)
 {
-	struct ast_bucket_file *copy;
-
-	copy = ast_bucket_file_alloc(uri);
+	RAII_VAR(struct ast_bucket_file *, copy, ast_bucket_file_alloc(uri), ao2_cleanup);
+
 	if (!copy) {
 		return NULL;
 	}
 
 	ao2_cleanup(copy->metadata);
 	copy->metadata = ao2_container_clone(file->metadata, 0);
-	if (!copy->metadata) {
-		ao2_ref(copy, -1);
-		return NULL;
-	}
-
-	if (bucket_copy(file->path, copy->path)) {
-		ao2_ref(copy, -1);
-		return NULL;
-	}
-
+	if (!copy->metadata ||
+		bucket_copy(file->path, copy->path)) {
+		return NULL;
+	}
+
+	ao2_ref(copy, +1);
 	return copy;
 }
 
@@ -704,12 +730,15 @@
 	}
 
 	if (ast_json_object_set(json, "id", id)) {
-		ast_json_unref(id);
 		return NULL;
 	}
 
 	metadata = ast_json_object_create();
 	if (!metadata) {
+		return NULL;
+	}
+
+	if (ast_json_object_set(json, "metadata", metadata)) {
 		return NULL;
 	}
 
@@ -717,21 +746,16 @@
 	for (; (attribute = ao2_iterator_next(&i)); ao2_ref(attribute, -1)) {
 		struct ast_json *value = ast_json_string_create(attribute->value);
 
-		if (!value) {
+		if (!value || ast_json_object_set(metadata, attribute->name, value)) {
 			res = -1;
 			break;
 		}
-
-		ast_json_object_set(metadata, attribute->name, value);
 	}
 	ao2_iterator_destroy(&i);
 
 	if (res) {
-		ast_json_unref(metadata);
-		return NULL;
-	}
-
-	ast_json_object_set(json, "metadata", metadata);
+		return NULL;
+	}
 
 	ast_json_ref(json);
 	return json;
@@ -740,10 +764,21 @@
 /*! \brief Hashing function for scheme container */
 static int bucket_scheme_hash(const void *obj, const int flags)
 {
-	const struct bucket_scheme *scheme = obj;
-	const char *name = obj;
-
-	return ast_str_hash(flags & OBJ_KEY ? name : scheme->name);
+	const struct bucket_scheme *object;
+	const char *key;
+
+	switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
+	case OBJ_KEY:
+		key = obj;
+		return ast_str_hash(key);
+	case OBJ_POINTER:
+		object = obj;
+		return ast_str_hash(object->name);
+	default:
+		/* Hash can only work on something with a full key */
+		ast_assert(0);
+		return 0;
+	}
 }
 
 /*! \brief Comparison function for scheme container */
@@ -771,7 +806,7 @@
 /*! \brief Custom handler for translating from a string timeval to actual structure */
 static int timeval_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj)
 {
-	struct timeval *field = (struct timeval *)(obj + opt->args[0]);
+	struct timeval *field = (struct timeval *)(obj + aco_option_get_argument(opt, 0));
 	return ast_get_timeval(var->value, field, ast_tv(0, 0), NULL);
 }
 
@@ -785,36 +820,38 @@
 /*! \brief Initialize bucket support */
 int ast_bucket_init(void)
 {
+	ast_register_cleanup(&bucket_cleanup);
+
 	schemes = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_RWLOCK, SCHEME_BUCKETS, bucket_scheme_hash,
 		bucket_scheme_cmp);
 	if (!schemes) {
 		ast_log(LOG_ERROR, "Failed to create container for Bucket schemes\n");
-		goto failure;
+		return -1;
 	}
 
 	if (__ast_sorcery_wizard_register(&bucket_wizard, NULL)) {
 		ast_log(LOG_ERROR, "Failed to register sorcery wizard for 'bucket' intermediary\n");
-		goto failure;
+		return -1;
 	}
 
 	if (__ast_sorcery_wizard_register(&bucket_file_wizard, NULL)) {
 		ast_log(LOG_ERROR, "Failed to register sorcery wizard for 'file' intermediary\n");
-		goto failure;
+		return -1;
 	}
 
 	if (!(bucket_sorcery = ast_sorcery_open())) {
 		ast_log(LOG_ERROR, "Failed to create sorcery instance for Bucket support\n");
-		goto failure;
+		return -1;
 	}
 
 	if (ast_sorcery_apply_default(bucket_sorcery, "bucket", "bucket", NULL)) {
 		ast_log(LOG_ERROR, "Failed to apply intermediary for 'bucket' object type in Bucket sorcery\n");
-		goto failure;
+		return -1;
 	}
 
 	if (ast_sorcery_object_register(bucket_sorcery, "bucket", bucket_alloc, NULL, NULL)) {
 		ast_log(LOG_ERROR, "Failed to register 'bucket' object type in Bucket sorcery\n");
-		goto failure;
+		return -1;
 	}
 
 	ast_sorcery_object_field_register(bucket_sorcery, "bucket", "name", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_bucket, name));
@@ -824,12 +861,12 @@
 
 	if (ast_sorcery_apply_default(bucket_sorcery, "file", "bucket_file", NULL)) {
 		ast_log(LOG_ERROR, "Failed to apply intermediary for 'file' object type in Bucket sorcery\n");
-		goto failure;
+		return -1;
 	}
 
 	if (ast_sorcery_object_register(bucket_sorcery, "file", bucket_file_alloc, NULL, NULL)) {
 		ast_log(LOG_ERROR, "Failed to register 'file' object type in Bucket sorcery\n");
-		goto failure;
+		return -1;
 	}
 
 	ast_sorcery_object_field_register(bucket_sorcery, "file", "name", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_bucket_file, name));
@@ -837,11 +874,5 @@
 	ast_sorcery_object_field_register_custom(bucket_sorcery, "file", "created", "", timeval_str2struct, timeval_struct2str, 0, FLDSET(struct ast_bucket_file, created));
 	ast_sorcery_object_field_register_custom(bucket_sorcery, "file", "modified", "", timeval_str2struct, timeval_struct2str, 0, FLDSET(struct ast_bucket_file, modified));
 
-	ast_register_cleanup(bucket_cleanup);
-
 	return 0;
-
-failure:
-	bucket_cleanup();
-	return -1;
-}
+}

Modified: team/file/bucket/main/config_options.c
URL: http://svnview.digium.com/svn/asterisk/team/file/bucket/main/config_options.c?view=diff&rev=396743&r1=396742&r2=396743
==============================================================================
--- team/file/bucket/main/config_options.c (original)
+++ team/file/bucket/main/config_options.c Thu Aug 15 10:25:04 2013
@@ -59,6 +59,21 @@
 	struct ao2_container *opts; /*!< The container of options registered to the aco_info */
 };
 
+struct aco_option {
+	const char *name;
+	const char *aliased_to;
+	const char *default_val;
+	enum aco_matchtype match_type;
+	regex_t *name_regex;
+	struct aco_type **obj;
+	enum aco_option_type type;
+	aco_option_handler handler;
+	unsigned int flags;
+	unsigned char deprecated:1;
+	size_t argc;
+	intptr_t args[0];
+};
+
 #ifdef AST_XML_DOCS
 static struct ao2_container *xmldocs;
 #endif /* AST_XML_DOCS */
@@ -211,6 +226,11 @@
 unsigned int aco_option_get_flags(const struct aco_option *option)
 {
 	return option->flags;
+}
+
+intptr_t aco_option_get_argument(const struct aco_option *option, unsigned int position)
+{
+	return option->args[position];
 }
 
 #ifdef AST_XML_DOCS

Modified: team/file/bucket/makeopts.in
URL: http://svnview.digium.com/svn/asterisk/team/file/bucket/makeopts.in?view=diff&rev=396743&r1=396742&r2=396743
==============================================================================
--- team/file/bucket/makeopts.in (original)
+++ team/file/bucket/makeopts.in Thu Aug 15 10:25:04 2013
@@ -173,6 +173,9 @@
 JANSSON_INCLUDE=@JANSSON_INCLUDE@
 JANSSON_LIB=@JANSSON_LIB@
 
+URIPARSER_INCLUDE=@URIPARSER_INCLUDE@
+URIPARSER_LIB=@URIPARSER_LIB@
+
 LDAP_INCLUDE=@LDAP_INCLUDE@
 LDAP_LIB=@LDAP_LIB@
 

Modified: team/file/bucket/tests/test_bucket.c
URL: http://svnview.digium.com/svn/asterisk/team/file/bucket/tests/test_bucket.c?view=diff&rev=396743&r1=396742&r2=396743
==============================================================================
--- team/file/bucket/tests/test_bucket.c (original)
+++ team/file/bucket/tests/test_bucket.c Thu Aug 15 10:25:04 2013
@@ -290,8 +290,8 @@
 AST_TEST_DEFINE(bucket_json)
 {
 	RAII_VAR(struct ast_bucket *, bucket, NULL, ao2_cleanup);
+	RAII_VAR(struct ast_json *, expected, NULL, ast_json_unref);
 	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
-	struct ast_json_iter *field;
 
 	switch (cmd) {
 	case TEST_INIT:
@@ -312,6 +312,17 @@
 
 	ast_str_container_add(bucket->buckets, "test:///tmp/bob/joe");
 	ast_str_container_add(bucket->files, "test:///tmp/bob/recording.wav");
+
+	expected = ast_json_pack("{s: s, s: s, s: [s], s: s, s: s, s: [s], s: s}",
+		"modified", "0.000000", "created", "0.000000",
+		"buckets", "test:///tmp/bob/joe",
+		"name", "bob", "scheme", "test",
+		"files", "test:///tmp/bob/recording.wav",
+		"id", "test:///tmp/bob");
+	if (!expected) {
+		ast_test_status_update(test, "Could not produce JSON for expected bucket value\n");
+		return AST_TEST_FAIL;
+	}
 
 	json = ast_bucket_json(bucket);
 	if (!json) {
@@ -319,72 +330,9 @@
 		return AST_TEST_FAIL;
 	}
 
-	for (field = ast_json_object_iter(json); field; field = ast_json_object_iter_next(json, field)) {
-		struct ast_json *value = ast_json_object_iter_value(field);
-
-		if (!strcmp(ast_json_object_iter_key(field), "id")) {
-			if (strcmp(ast_json_string_get(value), "bob")) {
-				ast_test_status_update(test, "Expected id of 'bob' in bucket JSON but got '%s'\n",
-					ast_json_string_get(value));
-				return AST_TEST_FAIL;
-			}
-		} else if (!strcmp(ast_json_object_iter_key(field), "modified")) {
-			if (strcmp(ast_json_string_get(value), "0")) {
-				ast_test_status_update(test, "Expected modified time of '0' in bucket JSON but got '%s'\n",
-					ast_json_string_get(value));
-				return AST_TEST_FAIL;
-			}
-		} else if (!strcmp(ast_json_object_iter_key(field), "created")) {
-			if (strcmp(ast_json_string_get(value), "0")) {
-				ast_test_status_update(test, "Expected created time of '0' in bucket JSON but got '%s'\n",
-					ast_json_string_get(value));
-				return AST_TEST_FAIL;
-			}
-		} else if (!strcmp(ast_json_object_iter_key(field), "scheme")) {
-			if (strcmp(ast_json_string_get(value), "test")) {
-				ast_test_status_update(test, "Expected scheme of 'test' in bucket JSON but got '%s'\n",
-					ast_json_string_get(value));
-				return AST_TEST_FAIL;
-			}
-		} else if (!strcmp(ast_json_object_iter_key(field), "uri")) {
-			if (strcmp(ast_json_string_get(value), "test:///tmp/bob")) {
-				ast_test_status_update(test, "Expected URI of 'test:///tmp/bob' in bucket JSON but got '%s'\n",
-					ast_json_string_get(value));
-				return AST_TEST_FAIL;
-			}
-		} else if (!strcmp(ast_json_object_iter_key(field), "buckets")) {
-			struct ast_json *uri;
-
-			if (ast_json_array_size(value) != 1) {
-				ast_test_status_update(test, "Expected buckets array size of '1' in bucket JSON but got '%zd'\n",
-					ast_json_array_size(value));
-				return AST_TEST_FAIL;
-			}
-
-			uri = ast_json_array_get(value, 0);
-
-			if (strcmp(ast_json_string_get(uri), "test:///tmp/bob/joe")) {
-				ast_test_status_update(test, "Expected URI of 'test:///tmp/bob/joe' in buckets array but got '%s'\n",
-					ast_json_string_get(value));
-				return AST_TEST_FAIL;
-			}
-		} else if (!strcmp(ast_json_object_iter_key(field), "files")) {
-			struct ast_json *uri;
-
-			if (ast_json_array_size(value) != 1) {
-				ast_test_status_update(test, "Expected files array size of '1' in bucket JSON but got '%zd'\n",
-					ast_json_array_size(value));
-				return AST_TEST_FAIL;
-			}
-
-			uri = ast_json_array_get(value, 0);
-
-			if (strcmp(ast_json_string_get(uri), "test:///tmp/bob/recording.wav")) {
-				ast_test_status_update(test, "Expected URI of 'test:///tmp/bob/recording.wav' in buckets array but got '%s'\n",
-					ast_json_string_get(value));
-				return AST_TEST_FAIL;
-			}
-		}
+	if (!ast_json_equal(json, expected)) {
+		ast_test_status_update(test, "Bucket JSON does not match expected output\n");
+		return AST_TEST_FAIL;
 	}
 
 	return AST_TEST_PASS;
@@ -495,12 +443,6 @@
 		return AST_TEST_FAIL;
 	}
 
-	if (!stat(file->path, &st)) {
-		ast_test_status_update(test, "Temporary file '%s' existed before creating it\n",
-			file->path);
-		return AST_TEST_FAIL;
-	}
-
 	if (!(temporary = fopen(file->path, "w"))) {
 		ast_test_status_update(test, "Failed to open temporary file '%s'\n",
 			file->path);
@@ -579,6 +521,7 @@
 	RAII_VAR(struct ast_bucket_file *, copy, NULL, ao2_cleanup);
 	FILE *temporary;
 	struct stat old, new;
+	RAII_VAR(struct ast_bucket_metadata *, metadata, NULL, ao2_cleanup);
 
 	switch (cmd) {
 	case TEST_INIT:
@@ -633,6 +576,17 @@
 		return AST_TEST_FAIL;
 	}
 
+	metadata = ast_bucket_file_metadata_get(copy, "bob");
+	if (!metadata) {
+		ast_test_status_update(test, "Copy of file does not have expected metadata\n");
+		return AST_TEST_FAIL;
+	}
+
+	if (strcmp(metadata->value, "joe")) {
+		ast_test_status_update(test, "Copy of file contains metadata for 'bob' but value is not what it should be\n");
+		return AST_TEST_FAIL;
+	}
+
 	return AST_TEST_PASS;
 }
 
@@ -884,14 +838,20 @@
 		return AST_TEST_FAIL;
 	}
 
+	if (strcmp(metadata->value, "joe")) {
+		ast_test_status_update(test, "Retrieved metadata value is '%s' while it should be 'joe'\n",
+			metadata->value);
+		return AST_TEST_FAIL;
+	}
+
 	return AST_TEST_PASS;
 }
 
 AST_TEST_DEFINE(bucket_file_json)
 {
 	RAII_VAR(struct ast_bucket_file *, file, NULL, ao2_cleanup);
+	RAII_VAR(struct ast_json *, expected, NULL, ast_json_unref);
 	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
-	struct ast_json_iter *field;
 
 	switch (cmd) {
 	case TEST_INIT:
@@ -912,6 +872,14 @@
 
 	if (ast_bucket_file_metadata_set(file, "bob", "joe")) {
 		ast_test_status_update(test, "Failed to set metadata 'bob' to 'joe' on newly allocated file\n");
+		return AST_TEST_FAIL;
+	}
+
+	expected = ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: {s :s}}",
+		"modified", "0.000000", "created", "0.000000", "name", "bob", "scheme", "test",
+		"id", "test:///tmp/bob", "metadata", "bob", "joe");
+	if (!expected) {
+		ast_test_status_update(test, "Could not produce JSON for expected bucket file value\n");
 		return AST_TEST_FAIL;
 	}
 
@@ -921,53 +889,9 @@
 		return AST_TEST_FAIL;
 	}
 
-	for (field = ast_json_object_iter(json); field; field = ast_json_object_iter_next(json, field)) {
-		struct ast_json *value = ast_json_object_iter_value(field);
-
-		if (!strcmp(ast_json_object_iter_key(field), "id")) {
-			if (strcmp(ast_json_string_get(value), "bob")) {
-				ast_test_status_update(test, "Expected id of 'bob' in file JSON but got '%s'\n",
-					ast_json_string_get(value));
-				return AST_TEST_FAIL;
-			}
-		} else if (!strcmp(ast_json_object_iter_key(field), "modified")) {
-			if (strcmp(ast_json_string_get(value), "0")) {
-				ast_test_status_update(test, "Expected modified time of '0' in file JSON but got '%s'\n",
-					ast_json_string_get(value));
-				return AST_TEST_FAIL;
-			}
-		} else if (!strcmp(ast_json_object_iter_key(field), "created")) {
-			if (strcmp(ast_json_string_get(value), "0")) {
-				ast_test_status_update(test, "Expected created time of '0' in file JSON but got '%s'\n",
-					ast_json_string_get(value));
-				return AST_TEST_FAIL;
-			}
-		} else if (!strcmp(ast_json_object_iter_key(field), "scheme")) {
-			if (strcmp(ast_json_string_get(value), "test")) {
-				ast_test_status_update(test, "Expected scheme of 'test' in file JSON but got '%s'\n",
-					ast_json_string_get(value));
-				return AST_TEST_FAIL;
-			}
-		} else if (!strcmp(ast_json_object_iter_key(field), "uri")) {
-			if (strcmp(ast_json_string_get(value), "test:///tmp/bob")) {
-				ast_test_status_update(test, "Expected URI of 'test:///tmp/bob' in file JSON but got '%s'\n",
-					ast_json_string_get(value));
-				return AST_TEST_FAIL;
-			}
-		} else if (!strcmp(ast_json_object_iter_key(field), "metadata")) {
-			struct ast_json *bob = ast_json_object_get(value, "bob");
-
-			if (!bob) {
-				ast_test_status_update(test, "Failed to get 'bob' metadata in JSON\n");
-				return AST_TEST_FAIL;
-			}
-
-			if (strcmp(ast_json_string_get(bob), "joe")) {
-				ast_test_status_update(test, "Retrieved 'bob' metadata has value '%s' instead of 'joe'\n",
-					ast_json_string_get(bob));
-				return AST_TEST_FAIL;
-			}
-		}
+	if (!ast_json_equal(json, expected)) {
+		ast_test_status_update(test, "Bucket file JSON does not match expected output\n");
+		return AST_TEST_FAIL;
 	}
 
 	return AST_TEST_PASS;




More information about the asterisk-commits mailing list