[svn-commits] tilghman: branch tilghman/ast_storage r332755 - in /team/tilghman/ast_storage...
SVN commits to the Digium repositories
svn-commits at lists.digium.com
Sun Aug 21 22:41:44 CDT 2011
Author: tilghman
Date: Sun Aug 21 22:41:38 2011
New Revision: 332755
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=332755
Log:
Adding the core files into the new branch. Compiles okay, but still need to work on imap support.
Added:
team/tilghman/ast_storage/include/asterisk/storage.h (with props)
team/tilghman/ast_storage/main/storage.c (with props)
team/tilghman/ast_storage/res/res_storage_odbc.c (with props)
Modified:
team/tilghman/ast_storage/main/asterisk.c
Added: team/tilghman/ast_storage/include/asterisk/storage.h
URL: http://svnview.digium.com/svn/asterisk/team/tilghman/ast_storage/include/asterisk/storage.h?view=auto&rev=332755
==============================================================================
--- team/tilghman/ast_storage/include/asterisk/storage.h (added)
+++ team/tilghman/ast_storage/include/asterisk/storage.h Sun Aug 21 22:41:38 2011
@@ -1,0 +1,278 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2010, Digium, Inc.
+ *
+ * John Khvatov <ivaxer at gmail.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ * \brief Generic File Storage Engine Support.
+ *
+ * \author John Khvatov <ivaxer at gmail.com>
+ */
+
+#ifndef _ASTERISK_STORAGE_H
+#define _ASTERISK_STORAGE_H
+
+#include "asterisk/linkedlists.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+/*
+ * File instance.
+ */
+struct ast_storage_fileinst {
+ int fd;
+ AST_RWLIST_ENTRY(ast_storage_fileinst) list;
+ char ext[16];
+ unsigned int temporary:1;
+ char localfile[64];
+};
+
+/*
+ * Virtual file in storage medium.
+ * Note: file instance and file object are not equivalent in any sense.
+ */
+struct ast_storage_fileobject {
+ char objectname[256];
+ char pathname[256];
+ struct ast_storage_fileinst *metadata;
+ AST_RWLIST_HEAD(, ast_storage_fileinst) files;
+ AST_RWLIST_ENTRY(ast_storage_fileobject) list;
+};
+
+AST_RWLIST_HEAD(ast_storage_fileobjects, ast_storage_fileobject);
+
+struct ast_storage_be {
+ const char *name;
+ struct ast_storage *(*create)(const char *uri);
+ int (*release)(struct ast_storage *st);
+ struct ast_storage_fileobject *(*get)(struct ast_storage *st, const char *objectname, const char *exts);
+ int (*put)(struct ast_storage *st, struct ast_storage_fileobject *fo, const char *exts);
+ int (*del)(struct ast_storage *st, const char *fileobject);
+ ssize_t (*read)(struct ast_storage *st, struct ast_storage_fileinst *fi, void *buf, size_t count);
+ ssize_t (*write)(struct ast_storage *st, struct ast_storage_fileinst *fi, void *buf, size_t count);
+ struct ast_storage_fileobjects *(*listdir)(struct ast_storage *st, const char *objectpath);
+ off_t (*tell)(struct ast_storage *st, struct ast_storage_fileinst *fi);
+ off_t (*seek)(struct ast_storage *st, struct ast_storage_fileinst *fi, off_t offset, int whence);
+ int (*copy)(struct ast_storage *st, const char *from, const char *to);
+ AST_RWLIST_ENTRY(ast_storage_be) list;
+ struct ast_module *module;
+};
+
+/* Most specific backends will have longer structures */
+struct ast_storage {
+ const struct ast_storage_be *be;
+ void *storage_pvt; /* Backend specific structure */
+};
+
+/*! \brief Register a storage backenda
+ * \retval Returns 1 on success or 0 on failure
+ * \retval 0 Success
+ * \retval -1 Failure
+ */
+int __ast_register_storage(const struct ast_storage_be *e, struct ast_module *mod);
+#define ast_register_storage(e) __ast_register_storage(e, ast_module_info->self)
+
+/*! \brief Unregister a storage backend
+ * \param name Storage backend name
+ * \retval 0 Success
+ * \retval -1 Failure
+ */
+int ast_unregister_storage(const char *name);
+
+/*! \brief Retrieves an instance of a storage engine
+ * \param uri Backend specific URI to the resource
+ * \retval non-NULL Success
+ * \retval NULL Failure
+ */
+struct ast_storage *ast_storage_request(const char *uri);
+
+/*! \brief Releases a storage instance created with ast_storage_request
+ * \param st Storage instance
+ * \retval 0 Success
+ * \retval -1 Failure
+ */
+int ast_storage_release(struct ast_storage *st);
+
+/*! \brief Retrieves a file from the storage medium
+ * \param st Storage instance
+ * \param objectname Logical name of the file
+ * \param exts File extensions to retrieve (separated by | character)
+ * \retval non-NULL Success
+ * \retval NULL Failure
+ */
+struct ast_storage_fileobject *ast_storage_get(struct ast_storage *st, const char *objectname, const char *exts);
+
+/*! \brief Stores a file into the storage medium
+ * \param st Storage instance
+ * \param fo File object to store
+ * \param exts File extensions to store (separated by '|' character)
+ * \retval 0 Success
+ * \retval -1 Failure
+ */
+int ast_storage_put(struct ast_storage *st, struct ast_storage_fileobject *fo, const char *exts);
+
+/*! \brief Reads from a file instance
+ * \param st Storage instance
+ * \param fi File instance to read
+ * \param buf Buffer to read into
+ * \param count Number of bytes to read
+ * \retval 0 Seccess
+ * \retval <0 Failure
+ * \return Returns standard POSIX codes as documented in 'man 3p read'
+ *
+ * \note For more info see 'man 3p read'
+ */
+int ast_storage_read(struct ast_storage *st, struct ast_storage_fileinst *fi, void *buf, size_t count);
+
+/*! \brief Writes on a file instance
+ * \param st Storage instance
+ * \param fi File instance to write
+ * \param buf Buffer to write from
+ * \param count Number of bytes to write
+ * \retval 0 Seccess
+ * \retval <0 Failure
+ * \return Returns standard POSIX codes as documented in 'man 3p write'
+ *
+ * \note For more info see 'man 3p write'
+ */
+int ast_storage_write(struct ast_storage *st, struct ast_storage_fileinst *fi, void *buf, size_t count);
+
+/*! \brief Removes a file from the storage medium
+ * \param st Storage instance
+ * \param fileobject Logical name of the file to delete
+ * \retval 0 Success
+ * \retval -1 Failure
+ */
+int ast_storage_del(struct ast_storage *st, const char *fileobject);
+
+/*! \brief Copies a file in the storage medium
+ * \param st Storage instance
+ * \param from Logical name of the source file
+ * \param to Logical name of the destination
+ * \retval 0 Success
+ * \retval -1 Failure
+ */
+int ast_storage_copy(struct ast_storage *st, const char *from, const char *to);
+
+/*! \brief Retrieves a list of files in the pathname in the storage medium
+ * \param st Storage instance
+ * \param pathname Logical name of the path
+ * \retval non-NULL Success
+ * \retval NULL Failure
+ */
+struct ast_storage_fileobjects *ast_storage_listdir(struct ast_storage *st, const char *pathname);
+
+/*! \brief Returns the current read/write file offset
+ * \param st Storage instance
+ * \param fi File instance
+ * \return Upon successful completion, returns the current offset, as measured
+ * in bytes from the beginning of the file. Returns (off_t)-1 on failure.
+ *
+ * /note For more info see 'man 3p lseek'.
+ */
+off_t ast_storage_tell(struct ast_storage *st, struct ast_storage_fileinst *fi);
+
+/*! \brief Moves the read/write file offset
+ * \param st Storage instance
+ * \param fi File instance
+ * \param offset Offset to set
+ * \param whence Whence
+ * \return Upon successful completion, returns the resulting offset, as measured
+ * in bytes from the beginning of the file. Returns (off_t)-1 on failure.
+ *
+ * /note For more info see 'man 3p lseek'.
+ */
+off_t ast_storage_seek(struct ast_storage *st, struct ast_storage_fileinst *fi, off_t offset, int whence);
+
+/*! \brief Creates new fileobject
+ * \retval non-NULL Success
+ * \retval NULL Failure
+ * \return Successfully allocated and initialized fileobject.
+ */
+struct ast_storage_fileobject *ast_storage_fileobject_create(void);
+
+/*! \brief Releases fileobject
+ * \param fo File object to release
+ * \retval 0 Success
+ * \retval -1 Failure
+ */
+int ast_storage_fileobject_release(struct ast_storage_fileobject *fo);
+
+/*! \brief Creates new file instance
+ * \retval non-NULL Success
+ * \retval NULL Failure
+ * \return Successfully allocated and initialized file instance.
+ */
+struct ast_storage_fileinst *ast_storage_fileinst_create(void);
+
+/*! \brief Releasesfile instance
+ * \param fi File instance to release
+ * \retval 0 Success
+ * \retval -1 Failure
+ */
+int ast_storage_fileinst_release(struct ast_storage_fileinst *fi);
+
+/*! \brief Creates a new list of fileobjects
+ * \retval non-NULL Success
+ * \retval NULL Failure
+ * \return Head of list of fileobjects.
+ */
+struct ast_storage_fileobjects *ast_storage_fileobjects_create(void);
+
+/*! \brief Releases list of fileobjects
+ * \param fobjs Head of list of fileobjects
+ * \retval 0 Success
+ * \retval -1 Failure
+ */
+int ast_storage_fileobjects_release(struct ast_storage_fileobjects *fobjs);
+
+/*! \brief Opens file instance
+ * \param fi File instance to open
+ * \param flags status flags and access modes
+ * \retval -1 Failure
+ * \retval >=0 Success
+ * \return Returns standard POSIX codes as documented in 'man 3p open' and sets
+ * errno.
+ *
+ * \note For more info see 'man 3p open'.
+ */
+int ast_storage_open(struct ast_storage_fileinst *fi, int flags);
+
+/*! \brief Closes file instance
+ * \param fi File instance to close
+ * \retval -1 Failure
+ * \retval 0 Success
+ * \return Returns standard POSIX codes as documented in 'man 3p open' and sets
+ * errno.
+ *
+ * \note For more info see 'man 3p close'.
+ */
+int ast_storage_close(struct ast_storage_fileinst *fi);
+
+/*! \brief Get a storage engine by name
+ * \param name Name of storage engine
+ * \retval non-NULL Success
+ * \retval NULL Failure
+ */
+struct ast_storage_be *ast_storage_getbyname(const char *name);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif /* _ASTERISK_STORAGE_H */
Propchange: team/tilghman/ast_storage/include/asterisk/storage.h
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: team/tilghman/ast_storage/include/asterisk/storage.h
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision Yoyo
Propchange: team/tilghman/ast_storage/include/asterisk/storage.h
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: team/tilghman/ast_storage/main/asterisk.c
URL: http://svnview.digium.com/svn/asterisk/team/tilghman/ast_storage/main/asterisk.c?view=diff&rev=332755&r1=332754&r2=332755
==============================================================================
--- team/tilghman/ast_storage/main/asterisk.c (original)
+++ team/tilghman/ast_storage/main/asterisk.c Sun Aug 21 22:41:38 2011
@@ -130,6 +130,7 @@
#include "asterisk/lock.h"
#include "asterisk/utils.h"
#include "asterisk/file.h"
+#include "asterisk/storage.h"
#include "asterisk/io.h"
#include "editline/histedit.h"
#include "asterisk/config.h"
@@ -3831,6 +3832,11 @@
exit(1);
}
+ if (ast_storage_engine_init()) {
+ printf("%s", term_quit());
+ exit(1);
+ }
+
if (load_pbx()) {
printf("%s", term_quit());
exit(1);
Added: team/tilghman/ast_storage/main/storage.c
URL: http://svnview.digium.com/svn/asterisk/team/tilghman/ast_storage/main/storage.c?view=auto&rev=332755
==============================================================================
--- team/tilghman/ast_storage/main/storage.c (added)
+++ team/tilghman/ast_storage/main/storage.c Sun Aug 21 22:41:38 2011
@@ -1,0 +1,546 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2010, Digium, Inc.
+ *
+ * John Khvatov <ivaxer at gmail.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Generic File Storage Engine Support.
+ *
+ * \author John Khvatov <ivaxer at gmail.com>
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/_private.h"
+#include "asterisk/storage.h"
+#include "asterisk/cli.h"
+#include "asterisk/file.h"
+#include "asterisk/frame.h"
+#include "asterisk/options.h"
+#include "asterisk/linkedlists.h"
+#include "asterisk/module.h"
+#include "asterisk/test.h"
+
+static AST_RWLIST_HEAD_STATIC(storage_engines, ast_storage_be);
+
+int __ast_register_storage(const struct ast_storage_be *be, struct ast_module *mod)
+{
+ struct ast_storage_be *tmp;
+
+ if (AST_RWLIST_WRLOCK(&storage_engines)) {
+ ast_log(LOG_WARNING, "Unable to lock storage engine list\n");
+ return -1;
+ }
+ AST_RWLIST_TRAVERSE(&storage_engines, tmp, list) {
+ if (!strcasecmp(be->name, tmp->name)) {
+ AST_RWLIST_UNLOCK(&storage_engines);
+ ast_log(LOG_WARNING, "Tried to register storage engine '%s', not found in list (was it already unregistered?)\n", be->name);
+ return -1;
+ }
+ }
+ if (!(tmp = ast_calloc(1, sizeof(*tmp)))) {
+ AST_RWLIST_UNLOCK(&storage_engines);
+ return -1;
+ }
+ *tmp = *be;
+ tmp->module = mod;
+
+ AST_RWLIST_INSERT_TAIL(&storage_engines, tmp, list);
+ AST_RWLIST_UNLOCK(&storage_engines);
+ if (option_verbose > 1) {
+ ast_verbose(VERBOSE_PREFIX_2 "Registered storage engine '%s'\n", be->name);
+ }
+
+ return 0;
+}
+
+int ast_unregister_storage(const char *name)
+{
+ struct ast_storage_be *tmp;
+ int res = -1;
+
+ if (AST_RWLIST_WRLOCK(&storage_engines)) {
+ ast_log(LOG_WARNING, "Unable to lock storage engine list\n");
+ return -1;
+ }
+ AST_RWLIST_TRAVERSE_SAFE_BEGIN(&storage_engines, tmp, list) {
+ if (!strcasecmp(name, tmp->name)) {
+ AST_RWLIST_REMOVE_CURRENT(list);
+ ast_free(tmp);
+ res = 0;
+ }
+ }
+ AST_RWLIST_TRAVERSE_SAFE_END
+ AST_RWLIST_UNLOCK(&storage_engines);
+
+ if (!res) {
+ ast_verb(2, "Unregistered storage engine '%s'\n", name);
+ } else {
+ ast_log(LOG_WARNING, "Tried to unregister storage engine '%s', already unregistered\n", name);
+ }
+
+ return res;
+}
+
+struct ast_storage_be *ast_storage_getbyname(const char *name)
+{
+ struct ast_storage_be *be;
+ if (AST_RWLIST_RDLOCK(&storage_engines)) {
+ ast_log(LOG_WARNING, "Unable to lock storage engine list\n");
+ return NULL;
+ }
+
+ AST_RWLIST_TRAVERSE(&storage_engines, be, list) {
+ if (!strcasecmp(name, be->name)) {
+ break;
+ }
+ }
+ AST_RWLIST_UNLOCK(&storage_engines);
+ return be;
+}
+
+struct ast_storage *ast_storage_request(const char *uri)
+{
+ struct ast_storage_be *be;
+ struct ast_storage *st = NULL;
+ char *tmp;
+ char *sename;
+ char *dir;
+
+ tmp = ast_strdupa(uri);
+ if ((dir = strstr(tmp, "://"))) {
+ *dir = '\0';
+ dir += 3;
+ }
+ sename = tmp;
+
+ if (!(be = ast_storage_getbyname(sename))) {
+ return NULL;
+ }
+
+ st = be->create(S_OR(dir, ""));
+ return st;
+}
+
+int ast_storage_release(struct ast_storage *st)
+{
+ return st && st->be->release ? st->be->release(st) : -1;
+}
+
+struct ast_storage_fileobject *ast_storage_get(struct ast_storage *st, const char *objectname, const char *exts)
+{
+ return st && st->be->get ? st->be->get(st, objectname, exts) : NULL;
+}
+
+int ast_storage_put(struct ast_storage *st, struct ast_storage_fileobject *fo, const char *exts)
+{
+ return st && st->be->put ? st->be->put(st, fo, exts) : -1;
+}
+
+int ast_storage_open(struct ast_storage_fileinst *fi, int flags)
+{
+ if (!fi) {
+ return -1;
+ }
+
+ fi->fd = open(fi->localfile, flags);
+ return fi->fd;
+}
+
+int ast_storage_close(struct ast_storage_fileinst *fi)
+{
+ int ret = -1;
+
+ if (!fi) {
+ return -1;
+ }
+
+ ret = close(fi->fd);
+ if (!ret) {
+ fi->fd = -1;
+ }
+ return ret;
+}
+
+int ast_storage_read(struct ast_storage *st, struct ast_storage_fileinst *fi, void *buf, size_t count)
+{
+ return st && st->be->read ? st->be->read(st, fi, buf, count) : -1;
+}
+
+int ast_storage_write(struct ast_storage *st, struct ast_storage_fileinst *fi, void *buf, size_t count)
+{
+ return st && st->be->write ? st->be->write(st, fi, buf, count) : -1;
+}
+
+int ast_storage_del(struct ast_storage *st, const char *fileobject)
+{
+ return st && st->be->del ? st->be->del(st, fileobject) : -1;
+}
+
+int ast_storage_copy(struct ast_storage *st, const char *from, const char *to)
+{
+ struct ast_storage_fileobject *fo;
+
+ if (st && st->be->copy) {
+ return st->be->copy(st, from, to);
+ }
+
+ fo = ast_storage_get(st, from, NULL);
+ if (!fo) {
+ ast_log(LOG_WARNING, "Unable to copy '%s' to '%s': get() failed\n", from, to);
+ return -1;
+ }
+
+ ast_copy_string(fo->objectname, to, sizeof(fo->objectname));
+
+ if (ast_storage_put(st, fo, NULL)) {
+ ast_log(LOG_WARNING, "Unable to copy '%s' to '%s': put() failed\n", from, to);
+ ast_storage_fileobject_release(fo);
+ return -1;
+ }
+
+ ast_storage_fileobject_release(fo);
+ return 0;
+}
+
+struct ast_storage_fileobjects *ast_storage_listdir(struct ast_storage *st, const char *pathname)
+{
+ return st && st->be->listdir ? st->be->listdir(st, pathname) : NULL;
+}
+
+struct ast_storage_fileobject *ast_storage_fileobject_create(void)
+{
+ struct ast_storage_fileobject *fo = ast_calloc(1, sizeof(*fo));
+ if (!fo) {
+ return NULL;
+ }
+
+ AST_RWLIST_HEAD_INIT(&fo->files);
+ return fo;
+}
+
+int ast_storage_fileobject_release(struct ast_storage_fileobject *fo)
+{
+ struct ast_storage_fileinst *inst;
+
+ if (!fo) {
+ return -1;
+ }
+
+ if (fo->metadata) {
+ return ast_storage_fileinst_release(fo->metadata);
+ }
+
+ if (!AST_RWLIST_WRLOCK(&fo->files)) {
+ ast_log(LOG_WARNING, "Unable to lock file instances list\n");
+ return -1;
+ }
+
+ while ((inst = AST_RWLIST_REMOVE_HEAD(&fo->files, list))) {
+ if (!ast_storage_fileinst_release(inst)) {
+ AST_RWLIST_UNLOCK(&fo->files);
+ return -1;
+ }
+ }
+
+ AST_RWLIST_UNLOCK(&fo->files);
+
+ ast_free(fo);
+ return 0;
+}
+
+struct ast_storage_fileinst *ast_storage_fileinst_create(void)
+{
+ struct ast_storage_fileinst *fi = ast_calloc(1, sizeof(*fi));
+ if (!fi) {
+ return NULL;
+ }
+
+ fi->fd = -1;
+ return fi;
+}
+
+int ast_storage_fileinst_release(struct ast_storage_fileinst *fi)
+{
+ if (!fi) {
+ return -1;
+ }
+
+ if (fi->fd != -1) {
+ ast_storage_close(fi);
+ }
+
+ if (fi->temporary && fi->localfile[0]) {
+ unlink(fi->localfile);
+ }
+
+ ast_free(fi);
+ return 0;
+}
+
+struct ast_storage_fileobjects *ast_storage_fileobjects_create(void)
+{
+ struct ast_storage_fileobjects *fobjs = ast_calloc(1, sizeof(*fobjs));
+ if (!fobjs) {
+ return NULL;
+ }
+
+ AST_RWLIST_HEAD_INIT(fobjs);
+ return fobjs;
+}
+
+int ast_storage_fileobjects_release(struct ast_storage_fileobjects *fobjs)
+{
+ struct ast_storage_fileobject *fo;
+
+ if (!fobjs) {
+ return -1;
+ }
+
+ if (!AST_RWLIST_WRLOCK(fobjs)) {
+ ast_log(LOG_WARNING, "Unable to lock fileobjects list\n");
+ return -1;
+ }
+
+ while ((fo = AST_RWLIST_REMOVE_HEAD(fobjs, list))) {
+ if (!ast_storage_fileobject_release(fo)) {
+ AST_RWLIST_UNLOCK(fobjs);
+ return -1;
+ }
+ }
+
+ AST_RWLIST_UNLOCK(fobjs);
+
+ ast_free(fobjs);
+ return 0;
+}
+
+#if 0
+static char *handle_storage_show_file(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ struct ast_storage *st;
+ struct ast_storage_fileinst *fi;
+ int count_files = 0;
+ /* XXX We want to remove the need to pass in a char array like this now.. */
+ char blah[PATH_MAX];
+ char *fn;
+ char *uri;
+
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "storage show file";
+ e->usage =
+ "Usage: storage show file <engine://filename>\n"
+ " Displays information about a file via the storage engine\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ }
+
+ if (a->argc != 4) {
+ return CLI_SHOWUSAGE;
+ }
+
+ uri = ast_strdupa(a->argv[3]);
+ if ((fn = strrchr(uri, '/'))) {
+ *fn++ = '\0';
+ }
+ else {
+ return CLI_SUCCESS;
+ }
+
+ if ((st = ast_storage_request(uri))) {
+ ast_cli(a->fd, "File information\n");
+ /* We don't care about format/extension here, so just send NULL */
+ if (!(ast_storage_get(st, fn, NULL, blah, sizeof(blah)))) {
+ AST_RWLIST_TRAVERSE(&st->fl->files, fi, list) {
+ char *ext;
+
+ /* Parse out the file extension */
+ if ((ext = strrchr(fi->ent->name, '.'))) {
+ ext++;
+ }
+
+ count_files++;
+ ast_cli(a->fd, "Name : %s\n", fi->ent->name);
+ ast_cli(a->fd, "Format: %s\n", ast_getformatname(ast_getformatbyextension(ext)));
+ }
+ }
+ ast_cli(a->fd, "\n");
+ ast_cli(a->fd, "Found %d matching file(s).\n", count_files);
+ }
+ ast_storage_release(st);
+ return CLI_SUCCESS;
+}
+
+static char *handle_storage_show_engines(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ struct ast_storage_be *be;
+ int count_se = 0;
+
+ switch(cmd) {
+ case CLI_INIT:
+ e->command = "storage show engines";
+ e->usage =
+ "Usage: storage show engines\n"
+ " Displays currently registered storage engines (if any)\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ }
+
+ if(a->argc != 3) {
+ return CLI_SHOWUSAGE;
+ }
+
+ ast_cli(a->fd, "Storage Engine\n");
+
+ if (AST_RWLIST_RDLOCK(&storage_engines)) {
+ ast_log(LOG_WARNING, "Unable to lock storage engine list\n");
+ return CLI_FAILURE;
+ }
+
+ AST_RWLIST_TRAVERSE(&storage_engines, be, list) {
+ ast_cli(a->fd, "%s\n", be->name);
+ count_se++;
+ }
+ AST_RWLIST_UNLOCK(&storage_engines);
+ ast_cli(a->fd, "%d storage engine(s) registered.\n", count_se);
+ return CLI_SUCCESS;
+}
+
+static char *complete_storage_show_engines(struct ast_cli_args *a)
+{
+ struct ast_storage_be *be;
+ char *ret = NULL;
+ int which = 0;
+ int wordlen = strlen(a->word);
+
+ AST_RWLIST_RDLOCK(&storage_engines);
+ AST_RWLIST_TRAVERSE(&storage_engines, be, list) {
+ if (!strncasecmp(a->word, be->name, wordlen) && ++which > a->n) {
+ ret = strdup(be->name);
+ break;
+ }
+ }
+ AST_RWLIST_UNLOCK(&storage_engines);
+
+ return ret;
+}
+static char *handle_storage_show_engine(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ struct ast_storage_be *be;
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "storage show engine";
+ e->usage =
+ "Usage: storage show engine <engine>\n"
+ " Displays capabilities of requested storage engine\n";
+ return NULL;
+ case CLI_GENERATE:
+ return complete_storage_show_engines(a);
+ }
+
+ if (a->argc != 4) {
+ return CLI_SHOWUSAGE;
+ }
+
+ if ((be = ast_storage_getbyname(a->argv[3]))) {
+ ast_cli(a->fd, "Storage Engine: %s\n", be->name);
+ ast_cli(a->fd, "Can get : %s\n", be->get ? "yes" : "no");
+#if 0
+ ast_cli(a->fd, "Can put : %s\n", be->put ? "yes" : "no");
+#endif
+ ast_cli(a->fd, "Can del : %s\n", be->del ? "yes" : "no");
+ ast_cli(a->fd, "Can opendir : %s\n", be->opendir ? "yes" : "no");
+ ast_cli(a->fd, "Can readdir : %s\n", be->readdir ? "yes" : "no");
+ ast_cli(a->fd, "Can closedir : %s\n", be->closedir ? "yes" : "no");
+ if (be->status) {
+ ast_cli(a->fd, "\n");
+ ast_cli(a->fd, "Additional status\n");
+ /* XXX Need to rethink this.
+ * This requires a struct ast_storage *, and we can't cast to it from ast_storage_be
+ be->status((struct ast_storage *)be, fd);
+ */
+ }
+ } else {
+ ast_cli(a->fd, "No storage engine named '%s' found.\n", a->argv[3]);
+ }
+ return CLI_SUCCESS;
+}
+#endif
+
+
+struct ast_cli_entry cli_storage[] = {
+/* AST_CLI_DEFINE(handle_storage_show_engines,"Show a storage engine"),
+ AST_CLI_DEFINE(handle_storage_show_engine,"List of storage engines"),
+ AST_CLI_DEFINE(handle_storage_show_file,"Show a file within a storage engine"), */
+};
+
+#ifdef TEST_FRAMEWORK
+
+AST_TEST_DEFINE(copy_test)
+{
+ struct ast_storage *st;
+ int ret;
+ const char uri[] = "odbc://asterisk-storage-test/storage/testpath";
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "copy_test";
+ info->category = "main/storage/generic";
+ info->summary = "copy test";
+ info->description =
+ "Tests the ast_storage_copy function";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ st = ast_storage_request(uri);
+ if (!st) {
+ return AST_TEST_FAIL;
+ }
+
+ ret = ast_storage_copy(st, "test", "huest");
+ if (ret) {
+ return AST_TEST_FAIL;
+ }
+
+ /* TODO: add checks here */
+
+ ret = ast_storage_release(st);
+ if (ret) {
+ return AST_TEST_FAIL;
+ }
+
+ return AST_TEST_PASS;
+}
+#endif
+
+int ast_storage_engine_init(void)
+{
+#ifdef TEST_FRAMEWORK
+ AST_TEST_REGISTER(copy_test);
+#endif
+ ast_cli_register_multiple(cli_storage, ARRAY_LEN(cli_storage));
+ return 0;
+}
Propchange: team/tilghman/ast_storage/main/storage.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: team/tilghman/ast_storage/main/storage.c
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision Yoyo
Propchange: team/tilghman/ast_storage/main/storage.c
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: team/tilghman/ast_storage/res/res_storage_odbc.c
URL: http://svnview.digium.com/svn/asterisk/team/tilghman/ast_storage/res/res_storage_odbc.c?view=auto&rev=332755
==============================================================================
--- team/tilghman/ast_storage/res/res_storage_odbc.c (added)
+++ team/tilghman/ast_storage/res/res_storage_odbc.c Sun Aug 21 22:41:38 2011
@@ -1,0 +1,1216 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2010, John Khvatov
+ *
+ * John Khvatov <ivaxer at gmail.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief ODBC storage engine backend
+ * \author John Khvatov <ivaxer at gmail.com>
+ * \ingroup res
+ */
+
+/*** MODULEINFO
+ <depend>unixodbc</depend>
+ <depend>res_odbc</depend>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/storage.h"
+#include "asterisk/module.h"
+#include "asterisk/res_odbc.h"
+#include "asterisk/app.h"
+#include "asterisk/config.h"
+#include "asterisk/test.h"
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <errno.h>
+
+struct odbc_storage_pvt {
+ char odbc_class[128];
+ char tablename[128];
+ struct odbc_obj *conn;
+ char pathname[1];
+};
+
+struct get_query_data {
+ const char *sql;
+ const char *pathname;
+ const char *objectname;
+ const char *ext;
+};
+
+struct put_query_data {
+ char *sql;
+ char *pathname;
+ char *objectname;
+ char *ext;
+ void *data;
+ void *metadata;
+ SQLLEN data_len;
+ SQLLEN data_ind;
+ SQLLEN metadata_len;
+ SQLLEN metadata_ind;
+};
+
+struct del_query_data {
+ const char *sql;
+ const char *pathname;
+ const char *objectname;
+};
+
+struct copy_query_data {
+ const char *sql;
+ const char *from_pathname;
+ const char *to_pathname;
+ const char *from_objectname;
+ const char *to_objectname;
+};
+
+struct listdir_query_data {
+ const char *sql;
+ const char *pathname;
+};
+
+static const struct ast_storage_be odbc_se;
+
+static int se_release(struct ast_storage *st)
+{
+ struct odbc_storage_pvt *pvt;
+
+ if (!st) {
+ return 0;
+ }
+
+ if (st->storage_pvt) {
+ pvt = (struct odbc_storage_pvt *) st->storage_pvt;
+ if (pvt->conn) {
+ ast_odbc_release_obj(pvt->conn);
+ }
+ free(pvt);
+ }
+ free(st);
+ return 0;
+}
+
+static struct ast_storage *se_create(const char *uri)
+{
+ char tmp[256];
+ SQLRETURN ret;
+ struct ast_storage *st;
+ struct odbc_storage_pvt *pvt;
+ int pathname_len;
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(class);
+ AST_APP_ARG(tablename);
+ AST_APP_ARG(pathname);
+ );
+ SQLHSTMT stmt = NULL;
+
+ st = ast_calloc(1, sizeof(*st));
+ if (!st) {
+ return NULL;
+ }
+
+ if (ast_strlen_zero(uri)) {
+ ast_log(LOG_ERROR, "Invalid request uri.\n");
+ se_release(st);
+ return NULL;
+ }
+
+ ast_copy_string(tmp, uri, sizeof(tmp));
+
+ AST_NONSTANDARD_APP_ARGS(args, tmp, '/');
+
+ pathname_len = sizeof(char) * strlen(args.pathname);
+
+ pvt = ast_calloc(1, sizeof(*pvt) + pathname_len);
+ if (!pvt) {
+ se_release(st);
+ return NULL;
+ }
+
+ st->storage_pvt = (void *)pvt;
+ st->be = &odbc_se;
+
+ ast_copy_string(pvt->odbc_class, args.class, sizeof(pvt->odbc_class));
+ ast_copy_string(pvt->tablename, args.tablename, sizeof(pvt->tablename));
+ strcpy(pvt->pathname, args.pathname);
+
+ pvt->conn = ast_odbc_request_obj(pvt->odbc_class, 0);
+ if (!pvt->conn) {
+ ast_log(LOG_ERROR, "Retrieving a connected ODBC object (ast_odbc_request_obj) failed.\n");
+ se_release(st);
+ return NULL;
+ }
+
+ ret = SQLAllocHandle(SQL_HANDLE_STMT, pvt->conn->con, &stmt);
+ if (!SQL_SUCCEEDED(ret)) {
+ ast_log(LOG_ERROR, "Allocation of database handle failed.\n");
+ se_release(st);
+ return NULL;
+ }
+
+ return st;
+}
+
+static struct ast_storage_fileinst *fetch_fileinst(SQLHSTMT stmt)
+{
+ SQLRETURN ret;
+ SQLSMALLINT colcount, colid, collen;
+ SQLULEN colsize;
+ SQLSMALLINT decimaldigits, nullable, datatype;
+ struct ast_storage_fileinst *fi;
+ char coltitle[128];
+ char rowdata[32];
+ char tmpfile_fmt[] = "/tmp/storage-odbc-XXXXXX";
+ int fd;
+
+ ret = SQLFetch(stmt);
+ if (ret == SQL_NO_DATA) {
+ return NULL;
+ }
+ if (!SQL_SUCCEEDED(ret)) {
+ ast_log(LOG_WARNING, "SQL Fetch error!");
+ return NULL;
+ }
+
+ ret = SQLNumResultCols(stmt, &colcount);
+ if (!SQL_SUCCEEDED(ret)) {
+ ast_log(LOG_WARNING, "SQL Column Count error!");
+ return NULL;
+ }
+
+ fi = ast_storage_fileinst_create();
+ if (!fi) {
+ return NULL;
+ }
+
+ fi->temporary = 1;
+
+ for (colid = 1; colid <= colcount; colid++) {
+ ret = SQLDescribeCol(stmt, colid, (SQLCHAR *)coltitle, sizeof(coltitle), &collen,
+ &datatype, &colsize, &decimaldigits, &nullable);
+ if (!SQL_SUCCEEDED(ret)) {
+ ast_log(LOG_WARNING, "SQL Describe Column error!");
+ goto error;
+ }
+ if (!strcasecmp(coltitle, "recording")) {
+ size_t ndata;
+ off_t offset;
+ void *fdm;
+ int chunksize = 0x4000000; /* Try 64MB chunks initially */
+
+ fd = mkstemp(tmpfile_fmt);
+ if (fd == -1) {
+ ast_log(LOG_WARNING, "Could not create temp file");
+ goto error;
+ }
+
+ ast_copy_string(fi->localfile, tmpfile_fmt, sizeof(fi->localfile));
+
+ ret = SQLGetData(stmt, colid, SQL_BINARY, NULL, 0, (SQLLEN *)&ndata);
+
+ lseek(fd, ndata - 1, SEEK_SET);
+ if (write(fd, "", 1) != 1) {
+ close(fd);
+ fd = -1;
+ ast_log(LOG_WARNING, "Unable to write '%s': [%d]: %s\n", fi->localfile, errno, strerror(errno));
+ goto error;
+ }
+
+ for (offset = 0; offset < ndata; offset += chunksize) {
+ if ((fdm = mmap(NULL, chunksize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) {
+ chunksize >>= 1;
+ offset -= chunksize;
+
+ if (chunksize < 4096) {
+ ast_log(LOG_WARNING, "Could not mmap the output file: [%d] %s\n", errno, strerror(errno));
+ goto error;
+ }
+
+ continue;
+ } else {
+ ret = SQLGetData(stmt, colid, SQL_BINARY, fdm, chunksize, NULL);
+ munmap(fdm, chunksize);
+ if (!SQL_SUCCEEDED(ret)) {
+ ast_log(LOG_WARNING, "SQL Get Data error!\n");
+ goto error;
+ }
+ }
+ }
+
+ fsync(fd);
+
+ if (ftruncate(fd, ndata) < 0) {
+ ast_log(LOG_WARNING, "Unable to truncate '%s': [%d]: %s\n", fi->localfile, errno, strerror(errno));
+ }
+
+ ast_copy_string(fi->localfile, tmpfile_fmt, sizeof(fi->localfile));
+ }
+ else if (!strcasecmp(coltitle, "extension")) {
+ ret = SQLGetData(stmt, colid, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
+ if (!SQL_SUCCEEDED(ret)) {
+ ast_log(LOG_WARNING, "SQL Get Data error!");
+ goto error;
+ }
+
+ ast_copy_string(fi->ext, rowdata, sizeof(fi->ext));
+ }
+ }
+
+ return fi;
+error:
+ ast_storage_fileinst_release(fi);
+ return NULL;
+}
+
+static SQLHSTMT prepare_get_query(struct odbc_obj *obj, void *arg)
+{
+ SQLHSTMT stmt;
+ SQLRETURN ret;
+ struct get_query_data *qdata = (struct get_query_data *) arg;
+
+ ret = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
+ if (!SQL_SUCCEEDED(ret)) {
+ ast_log(LOG_WARNING, "SQL Alloc Handle failed!");
+ return NULL;
+ }
+
+ ret = SQLPrepare(stmt, (SQLCHAR *)qdata->sql, SQL_NTS);
+ if (!SQL_SUCCEEDED(ret)) {
+ ast_log(LOG_WARNING, "SQL Prepare failed!\n[%s]", qdata->sql);
+ SQLFreeHandle(SQL_HANDLE_STMT, stmt);
+ return NULL;
+ }
+
+ SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(qdata->pathname), 0, (void *)qdata->pathname, 0, NULL);
+ SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(qdata->objectname), 0, (void *)qdata->objectname, 0, NULL);
+ if (qdata->ext) {
+ SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(qdata->ext), 0, (void *)qdata->ext, 0, NULL);
+ SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, 3, 0, (void *)"txt", 0, NULL);
+ }
+
+ return stmt;
+}
+
+static struct ast_storage_fileobject *se_get(struct ast_storage *st, const char *objectname, const char *exts)
+{
+ struct odbc_storage_pvt *ost = (struct odbc_storage_pvt *)st->storage_pvt;
+ struct get_query_data qdata;
+ struct ast_storage_fileobject *fo = NULL;
+ struct ast_storage_fileinst *fi = NULL;
+ char ext[16];
+ char sql[128];
+ char *pathname;
+ SQLHSTMT stmt;
+
+ if (ast_strlen_zero(objectname)) {
+ ast_log(LOG_WARNING, "objectname is null.\n");
+ return NULL;
+ }
+
+ if (exts) {
+ char *ptr;
+ ast_copy_string(ext, exts, sizeof(ext));
+ ptr = strchr(ext, '|');
+ if (ptr) {
+ *ptr = '\0';
+ }
+ }
+
+ /*
+ * TODO: objectname may contain relative or absolute path.
+ */
+ pathname = ost->pathname;
+
+ if (exts) {
+ snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE pathname=? AND filename=? AND (extension=? OR extension=?)", ost->tablename);
+ } else {
+ snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE pathname=? AND filename=?", ost->tablename);
+ }
+
+ qdata.sql = sql;
+ qdata.objectname = objectname;
+ qdata.pathname = pathname;
+ if (exts) {
+ qdata.ext = ext;
+ } else {
+ qdata.ext = NULL;
+ }
+
+ stmt = ast_odbc_prepare_and_execute(ost->conn, prepare_get_query, &qdata);
+ if (!stmt) {
+ ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n", sql);
+ return NULL;
+ }
+
+ while ((fi = fetch_fileinst(stmt)) != NULL) {
+ if (!fo) {
+ fo = ast_storage_fileobject_create();
+ if (!fo) {
+ goto error;
+ }
+
+ ast_copy_string(fo->objectname, objectname, sizeof(fo->objectname));
+ ast_copy_string(fo->pathname, pathname, sizeof(fo->pathname));
+ }
+
+ if (!strcasecmp(fi->ext, "txt")) {
+ fo->metadata = fi;
+ continue;
+ }
+
+ AST_RWLIST_WRLOCK(&fo->files);
+ AST_RWLIST_INSERT_TAIL(&fo->files, fi, list);
+ AST_RWLIST_UNLOCK(&fo->files);
+ }
+
+ SQLFreeHandle(SQL_HANDLE_STMT, stmt);
+ return fo;
+
+error:
+ SQLFreeHandle(SQL_HANDLE_STMT, stmt);
+ if (fo) {
+ ast_storage_fileobject_release(fo);
+ }
+ return NULL;
+}
+
+static SQLHSTMT execute_put_query(struct odbc_obj *obj, void *arg)
+{
+ SQLRETURN ret;
+ SQLHSTMT stmt;
+ struct put_query_data *qdata = (struct put_query_data *) arg;
+
+ ret = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
+ if (!SQL_SUCCEEDED(ret)) {
+ ast_log(LOG_WARNING, "SQL Alloc Handle failed!");
+ return NULL;
+ }
+
+ SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(qdata->pathname), 0, (void *)qdata->pathname, 0, NULL);
+ SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(qdata->objectname), 0, (void *)qdata->objectname, 0, NULL);
+ SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(qdata->ext), 0, (void *)qdata->ext, 0, NULL);
+ SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, qdata->data_len, 0, (void *)qdata->data, 0, &qdata->data_ind);
+
+ if (qdata->metadata) {
+ SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(qdata->pathname), 0, (void *)qdata->pathname, 0, NULL);
+ SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(qdata->objectname), 0, (void *)qdata->objectname, 0, NULL);
+ SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, 3, 0, (void *)"txt", 0, NULL);
+ SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, qdata->metadata_len, 0, (void *)qdata->metadata, 0, &qdata->metadata_ind);
+ }
+
+ ret = SQLExecDirect(stmt, (unsigned char *)qdata->sql, SQL_NTS);
+ if (!SQL_SUCCEEDED(ret)) {
+ ast_log(LOG_WARNING, "SQL Exec Direct failed!");
+ SQLFreeHandle(SQL_HANDLE_STMT, stmt);
+ return NULL;
+ }
+
+ return stmt;
+}
+
+static int open_fileinst(struct ast_storage_fileinst *fi, int *fd, int *fdlen, void **fdm)
+{
+ int local_fd, local_fdlen;
+ void *local_fdm;
+
+ local_fd = open(fi->localfile, O_RDONLY);
+ if (local_fd == -1) {
+ ast_log(LOG_WARNING, "Unable to open file '%s': [%d]: %s\n", fi->localfile, errno, strerror(errno));
+ return -1;
+ }
+
+ local_fdlen = lseek(local_fd, 0, SEEK_END);
+
+ local_fdm = mmap(NULL, local_fdlen, PROT_READ, MAP_SHARED, local_fd, 0);
+ if (local_fdm == MAP_FAILED) {
+ ast_log(LOG_WARNING, "Unable to map file '%s': [%d]: %s\n", fi->localfile, errno, strerror(errno));
+ close(local_fd);
+ return -1;
+ }
+
+ *fdm = local_fdm;
+ *fdlen = local_fdlen;
+ *fd = local_fd;
+
+ return 0;
+}
+
+static int se_put(struct ast_storage *st, struct ast_storage_fileobject *fo, const char *exts)
+{
+ SQLHSTMT stmt = NULL;
+ struct odbc_storage_pvt *ost = (struct odbc_storage_pvt *) st->storage_pvt;
+ struct ast_storage_fileinst *fi, *mfi;
+ char sql[128], ext[16];
+ struct put_query_data qdata;
+ int fd, fdlen, mfd, mfdlen;
+ void *fdm, *mfdm;
+ int putret = -1;
+
+ if (!fo) {
+ ast_log(LOG_WARNING, "fileobject is null!\n");
+ return -1;
+ }
+
+ if (exts) {
+ char *ptr;
+ ast_copy_string(ext, exts, sizeof(ext));
+ ptr = strchr(ext, '|');
+ if (ptr) {
+ *ptr = '\0';
+ }
+ }
+
+ AST_RWLIST_RDLOCK(&fo->files);
+ AST_RWLIST_TRAVERSE(&fo->files, fi, list) {
+ if (!exts || !strcasecmp(fi->ext, ext)) {
+ break;
+ }
+ }
+ AST_RWLIST_UNLOCK(&fo->files);
+
+ mfi = fo->metadata;
+
+ if (!fi) {
+ ast_log(LOG_WARNING, "Unable to find file instance for put()\n");
+ return -1;
+ }
+
+ fdm = mfdm = NULL;
+
+ if (open_fileinst(fi, &fd, &fdlen, &fdm) == -1) {
+ return -1;
+ }
+ if (mfi) {
+ if (open_fileinst(mfi, &mfd, &mfdlen, &mfdm) == -1) {
+ goto error;
+ }
+ }
+
+ if (mfi) {
+ snprintf(sql, sizeof(sql), "INSERT INTO %s (pathname,filename,extension,recording) VALUES (?,?,?,?), (?,?,?,?)", ost->tablename);
+ }
+ else {
+ snprintf(sql, sizeof(sql), "INSERT INTO %s (pathname,filename,extension,recording) VALUES (?,?,?,?)", ost->tablename);
+ }
+
+ memset(&qdata, 0, sizeof(qdata));
+ qdata.sql = sql;
+ qdata.pathname = fo->pathname;
+ qdata.objectname = fo->objectname;
+ qdata.ext = fi->ext;
+ qdata.data = fdm;
+ qdata.data_len = qdata.data_ind = fdlen;
+ if (mfi) {
+ qdata.metadata = mfdm;
+ qdata.metadata_len = qdata.metadata_ind = mfdlen;
+ }
+
+ stmt = ast_odbc_direct_execute(ost->conn, execute_put_query, &qdata);
+ if (!stmt) {
+ ast_log(LOG_WARNING, "SQL Execute failed!\n");
+ goto error;
+ }
+
+ putret = 0;
+error:
+ if (stmt) {
+ SQLFreeHandle(SQL_HANDLE_STMT, stmt);
+ }
+ if (fdm) {
[... 686 lines stripped ...]
More information about the svn-commits
mailing list