[svn-commits] dlee: branch dlee/record r394811 - /team/dlee/record/res/stasis_recording/

SVN commits to the Digium repositories svn-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 svn-commits mailing list