[asterisk-commits] dlee: branch dlee/record r394811 - /team/dlee/record/res/stasis_recording/
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Fri Jul 19 14:45:23 CDT 2013
Author: dlee
Date: Fri Jul 19 14:45:21 2013
New Revision: 394811
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=394811
Log:
Stored recording backend
Added:
team/dlee/record/res/stasis_recording/ (with props)
team/dlee/record/res/stasis_recording/stored.c (with props)
Propchange: team/dlee/record/res/stasis_recording/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Fri Jul 19 14:45:21 2013
@@ -1,0 +1,14 @@
+*.o
+*.a
+*.d
+*.eo
+*.eoo
+*.i
+*.makeopts
+*.moduleinfo
+*.s
+*.so
+*.exports
+modules.link
+*.gcno
+*.gcda
Added: team/dlee/record/res/stasis_recording/stored.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/record/res/stasis_recording/stored.c?view=auto&rev=394811
==============================================================================
--- team/dlee/record/res/stasis_recording/stored.c (added)
+++ team/dlee/record/res/stasis_recording/stored.c Fri Jul 19 14:45:21 2013
@@ -1,0 +1,239 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * David M. Lee, II <dlee at digium.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 Stored file operations for Stasis
+ *
+ * \author David M. Lee, II <dlee at digium.com>
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/astobj2.h"
+#include "asterisk/paths.h"
+#include "asterisk/stasis_app_recording.h"
+
+#include <dirent.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+struct stasis_app_stored_recording {
+ AST_DECLARE_STRING_FIELDS(
+ AST_STRING_FIELD(name); /*!< Recording's name */
+ AST_STRING_FIELD(file); /*!< Absolute filename, without extension; for use with streamfile */
+ AST_STRING_FIELD(file_with_ext); /*!< Absolute filename, with extension; for use with everything */
+ );
+};
+
+static void stored_recording_dtor(void *obj)
+{
+ struct stasis_app_stored_recording *recording = obj;
+
+ ast_string_field_free_memory(recording);
+}
+
+/*!
+ * \brief Split a path into directory and file, resolving canonical directory.
+ *
+ * The path is resolved relative to the recording directory. Both dir and file
+ * are allocated strings, which you must ast_free().
+ *
+ * \param path Path to split.
+ * \param[out] dir Output parameter for directory portion.
+ * \param[out] fail Output parameter for the file portion.
+ * \return 0 on success.
+ * \return Non-zero on error.
+ */
+static int split_path(const char *path, char **dir, char **file)
+{
+ RAII_VAR(char *, relative_dir, NULL, ast_free);
+ RAII_VAR(char *, absolute_dir, NULL, ast_free);
+ RAII_VAR(char *, real_dir, NULL, free);
+ char *file_portion;
+
+ relative_dir = ast_strdup(path);
+ if (!relative_dir) {
+ return -1;
+ }
+
+ file_portion = strrchr(relative_dir, '/');
+ if (file_portion) {
+ *file_portion++ = '\0';
+ ast_asprintf(&absolute_dir, "%s/%s",
+ ast_config_AST_RECORDING_DIR, relative_dir);
+ } else {
+ file_portion = relative_dir;
+ relative_dir = "";
+ absolute_dir = ast_strdup(ast_config_AST_RECORDING_DIR);
+ }
+ if (!absolute_dir) {
+ return -1;
+ }
+
+ real_dir = realpath(absolute_dir, NULL);
+ if (!real_dir) {
+ return -1;
+ }
+
+ *dir = ast_strdup(real_dir); /* Dupe so we can ast_free() */
+ *file = ast_strdup(file_portion);
+ return 0;
+}
+
+static char *find_recording(const char *dir_name, const char *file)
+{
+ RAII_VAR(DIR *, dir, NULL, closedir);
+ struct dirent entry = {};
+ struct dirent *result = NULL;
+ char *ext = NULL;
+ char *file_with_ext = NULL;
+
+ dir = opendir(dir_name);
+ if (dir == NULL) {
+ return NULL;
+ }
+
+ while (readdir_r(dir, &entry, &result) == 0 && result != NULL) {
+ ext = strrchr(result->d_name, '.');
+
+ if (!ext) {
+ /* No file extension; not us */
+ continue;
+ }
+ *ext++ = '\0';
+
+ if (strcmp(file, result->d_name) == 0) {
+ if (!ast_get_format_for_file_ext(ext)) {
+ ast_log(LOG_WARNING,
+ "Recording %s: unrecognized format %s\n",
+ result->d_name,
+ ext);
+ /* Keep looking */
+ continue;
+ }
+ /* We have a winner! */
+ break;
+ }
+ }
+
+ if (!result) {
+ return NULL;
+ }
+
+ ast_asprintf(&file_with_ext, "%s/%s.%s", dir_name, file, ext);
+ return file_with_ext;
+}
+
+static int recording_set_name(struct stasis_app_stored_recording *recording,
+ const char *name)
+{
+ RAII_VAR(char *, dir, NULL, ast_free);
+ RAII_VAR(char *, file, NULL, ast_free);
+ RAII_VAR(char *, file_with_ext, NULL, ast_free);
+ int res;
+ struct stat file_stat;
+
+ ast_string_field_set(recording, name, name);
+
+ res = split_path(name, &dir, &file);
+ if (res != 0) {
+ return -1;
+ }
+ ast_string_field_build(recording, file, "%s/%s", dir, file);
+
+ if (!ast_begins_with(dir, ast_config_AST_RECORDING_DIR)) {
+ /* Attempt to escape the recording directory */
+ ast_log(LOG_WARNING, "Attempt to access invalid recording %s\n",
+ name);
+ errno = EACCES;
+ return -1;
+ }
+
+ file_with_ext = find_recording(dir, file);
+ if (!file_with_ext) {
+ return -1;
+ }
+ ast_string_field_set(recording, file_with_ext, file_with_ext);
+
+ res = stat(file_with_ext, &file_stat);
+ if (res != 0) {
+ return -1;
+ }
+
+ if (!S_ISREG(file_stat.st_mode)) {
+ /* Let's not play if it's not a regular file */
+ errno = EACCES;
+ return -1;
+ }
+
+ return 0;
+}
+
+struct ast_json *stasis_app_stored_recording_to_json(
+ struct stasis_app_stored_recording *recording)
+{
+ if (!recording) {
+ return NULL;
+ }
+
+ return ast_json_pack("{ s: s }", "name", recording->name);
+}
+
+struct ao2_container *stasis_app_stored_recording_find_all(void)
+{
+ return NULL;
+}
+
+struct stasis_app_stored_recording *stasis_app_stored_recording_find_by_name(
+ const char *name)
+{
+ RAII_VAR(struct stasis_app_stored_recording *, recording, NULL,
+ ao2_cleanup);
+ int res;
+
+ errno = 0;
+
+ if (!name) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ recording = ao2_alloc(sizeof(*recording), stored_recording_dtor);
+ if (!recording) {
+ return NULL;
+ }
+
+ res = recording_set_name(recording, name);
+ if (res != 0) {
+ return NULL;
+ }
+
+ ao2_ref(recording, +1);
+ return recording;
+}
+
+int stasis_app_stored_recording_delete(
+ struct stasis_app_stored_recording *recording)
+{
+ /* Path was validated when the recording object was created */
+ return unlink(recording->file_with_ext);
+}
Propchange: team/dlee/record/res/stasis_recording/stored.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: team/dlee/record/res/stasis_recording/stored.c
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Propchange: team/dlee/record/res/stasis_recording/stored.c
------------------------------------------------------------------------------
svn:mime-type = text/plain
More information about the asterisk-commits
mailing list