res_musiconhold.c: Use ast_file_read_dir to scan MoH directory

Two changes of note in this patch:

* Use ast_file_read_dir instead of opendir/readdir/closedir

* If the files list should be sorted, do that at the end rather than as
  we go which improves performance for large lists

Change-Id: Ic7e9c913c0f85754c99c74c9cf6dd3514b1b941f
pull/29/head
Sean Bright 5 years ago committed by Friendly Automation
parent 64ca2d48da
commit 057fda460b

@ -1208,84 +1208,95 @@ static void moh_parse_options(struct ast_variable *var, struct mohclass *mohclas
} }
} }
static int moh_scan_files(struct mohclass *class) { static int on_moh_file(const char *directory, const char *filename, void *obj)
{
DIR *files_DIR; struct ast_vector_string *files = obj;
struct dirent *files_dirent; char *full_path;
char dir_path[PATH_MAX - sizeof(class->dir)]; char *extension;
char filepath[PATH_MAX];
char *ext;
struct stat statbuf;
int res;
struct ast_vector_string *files;
if (class->dir[0] != '/') { /* Skip files that starts with a dot */
snprintf(dir_path, sizeof(dir_path), "%s/%s", ast_config_AST_DATA_DIR, class->dir); if (*filename == '.') {
} else { ast_debug(4, "Skipping '%s/%s' because it starts with a dot\n",
ast_copy_string(dir_path, class->dir, sizeof(dir_path)); directory, filename);
} return 0;
ast_debug(4, "Scanning '%s' for files for class '%s'\n", dir_path, class->name);
files_DIR = opendir(dir_path);
if (!files_DIR) {
ast_log(LOG_WARNING, "Cannot open dir %s or dir does not exist\n", dir_path);
return -1;
} }
files = moh_file_vector_alloc(16); /* 16 seems like a reasonable default */ /* We can't do anything with files that don't have an extension,
if (!files) { * so check that first and punt if we can't find something */
closedir(files_DIR); extension = strrchr(filename, '.');
return -1; if (!extension) {
ast_debug(4, "Skipping '%s/%s' because it doesn't have an extension\n",
directory, filename);
return 0;
} }
while ((files_dirent = readdir(files_DIR))) { /* The extension needs at least two characters (after the .) to be useful */
char *filepath_copy; if (strlen(extension) < 3) {
ast_debug(4, "Skipping '%s/%s' because it doesn't have at least a two "
"character extension\n", directory, filename);
return 0;
}
/* The file name must be at least long enough to have the file type extension */ /* Build the full path (excluding the extension) */
if ((strlen(files_dirent->d_name) < 4)) if (ast_asprintf(&full_path, "%s/%.*s",
continue; directory,
(int) (extension - filename), filename) < 0) {
/* If we don't have enough memory to build this path, there is no
* point in continuing */
return 1;
}
/* Skip files that starts with a dot */ /* If the file is present in multiple formats, ensure we only put it
if (files_dirent->d_name[0] == '.') * into the list once. Pretty sure this is O(n^2). */
continue; if (AST_VECTOR_GET_CMP(files, &full_path[0], !strcmp)) {
ast_free(full_path);
return 0;
}
/* Skip files without extensions... they are not audio */ if (AST_VECTOR_APPEND(files, full_path)) {
if (!strchr(files_dirent->d_name, '.')) /* AST_VECTOR_APPEND() can only fail on allocation failure, so
continue; * we stop iterating */
ast_free(full_path);
return 1;
}
snprintf(filepath, sizeof(filepath), "%s/%s", dir_path, files_dirent->d_name); return 0;
}
if (stat(filepath, &statbuf)) static int moh_filename_strcasecmp(const void *a, const void *b)
continue; {
const char **s1 = (const char **) a;
const char **s2 = (const char **) b;
return strcasecmp(*s1, *s2);
}
if (!S_ISREG(statbuf.st_mode)) static int moh_scan_files(struct mohclass *class) {
continue;
if ((ext = strrchr(filepath, '.'))) char dir_path[PATH_MAX - sizeof(class->dir)];
*ext = '\0'; struct ast_vector_string *files;
/* if the file is present in multiple formats, ensure we only put it into the list once */ if (class->dir[0] != '/') {
if (AST_VECTOR_GET_CMP(files, &filepath[0], !strcmp)) { snprintf(dir_path, sizeof(dir_path), "%s/%s", ast_config_AST_DATA_DIR, class->dir);
continue; } else {
} ast_copy_string(dir_path, class->dir, sizeof(dir_path));
}
filepath_copy = ast_strdup(filepath); ast_debug(4, "Scanning '%s' for files for class '%s'\n", dir_path, class->name);
if (!filepath_copy) {
break;
}
if (ast_test_flag(class, MOH_SORTALPHA)) { /* 16 seems like a reasonable default */
res = AST_VECTOR_ADD_SORTED(files, filepath_copy, strcasecmp); files = moh_file_vector_alloc(16);
} else { if (!files) {
res = AST_VECTOR_APPEND(files, filepath_copy); return -1;
} }
if (res) { if (ast_file_read_dir(dir_path, on_moh_file, files)) {
ast_free(filepath_copy); ao2_ref(files, -1);
break; return -1;
}
} }
closedir(files_DIR); if (ast_test_flag(class, MOH_SORTALPHA)) {
AST_VECTOR_SORT(files, moh_filename_strcasecmp);
}
AST_VECTOR_COMPACT(files); AST_VECTOR_COMPACT(files);

Loading…
Cancel
Save