diff --git a/main/file.c b/main/file.c index 37b9e79117..fb4ede6c88 100644 --- a/main/file.c +++ b/main/file.c @@ -1093,27 +1093,27 @@ int ast_filecopy(const char *filename, const char *filename2, const char *fmt) return filehelper(filename, filename2, fmt, ACTION_COPY); } -static int __ast_file_read_dirs(struct ast_str **path, ast_file_on_file on_file, +static int __ast_file_read_dirs(const char *path, ast_file_on_file on_file, void *obj, int max_depth) { DIR *dir; struct dirent *entry; - size_t size; int res; - if (!(dir = opendir(ast_str_buffer(*path)))) { + if (!(dir = opendir(path))) { ast_log(LOG_ERROR, "Error opening directory - %s: %s\n", - ast_str_buffer(*path), strerror(errno)); + path, strerror(errno)); return -1; } - size = ast_str_strlen(*path); --max_depth; res = 0; while ((entry = readdir(dir)) != NULL && !errno) { - int is_file, is_dir, used_stat = 0; + int is_file = 0; + int is_dir = 0; + RAII_VAR(char *, full_path, NULL, ast_free); if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) { continue; @@ -1128,23 +1128,24 @@ static int __ast_file_read_dirs(struct ast_str **path, ast_file_on_file on_file, if (entry->d_type != DT_UNKNOWN && entry->d_type != DT_LNK) { is_file = entry->d_type == DT_REG; is_dir = entry->d_type == DT_DIR; - ast_log(LOG_VERBOSE, "!###### d_name=%s, path=%s, NO USE STAT used_stat=%d\n", entry->d_name, ast_str_buffer(*path), used_stat); } else #endif { struct stat statbuf; /* - * If using the stat function the file needs to be appended to the - * path so it can be found. However, before appending make sure the - * path contains only the directory for this depth level. + * Don't use alloca or we risk blowing out the stack if recursing + * into subdirectories. */ - ast_str_truncate(*path, size); - ast_str_append(path, 0, "/%s", entry->d_name); + full_path = ast_malloc(strlen(path) + strlen(entry->d_name) + 2); + if (!full_path) { + return -1; + } + sprintf(full_path, "%s/%s", path, entry->d_name); - if (stat(ast_str_buffer(*path), &statbuf)) { + if (stat(full_path, &statbuf)) { ast_log(LOG_ERROR, "Error reading path stats - %s: %s\n", - ast_str_buffer(*path), strerror(errno)); + full_path, strerror(errno)); /* * Output an error, but keep going. It could just be * a broken link and other files could be fine. @@ -1154,13 +1155,11 @@ static int __ast_file_read_dirs(struct ast_str **path, ast_file_on_file on_file, is_file = S_ISREG(statbuf.st_mode); is_dir = S_ISDIR(statbuf.st_mode); - used_stat = 1; - ast_log(LOG_VERBOSE, "!###### d_name=%s, path=%s, WE USED IT YO used_stat=%d\n", entry->d_name, ast_str_buffer(*path), used_stat); } if (is_file) { /* If the handler returns non-zero then stop */ - if ((res = on_file(ast_str_buffer(*path), entry->d_name, obj))) { + if ((res = on_file(path, entry->d_name, obj))) { break; } /* Otherwise move on to next item in directory */ @@ -1168,25 +1167,22 @@ static int __ast_file_read_dirs(struct ast_str **path, ast_file_on_file on_file, } if (!is_dir) { - ast_debug(5, "Skipping %s: not a regular file or directory\n", - ast_str_buffer(*path)); + ast_debug(5, "Skipping %s: not a regular file or directory\n", full_path); continue; } /* Only re-curse into sub-directories if not at the max depth */ if (max_depth != 0) { - /* - * If the stat function was used then the sub-directory has - * already been appended, otherwise append it. - */ - ast_log(LOG_VERBOSE, "!###### do dir d_name=%s, path=%s, used_stat=%d\n", entry->d_name, ast_str_buffer(*path), used_stat); - if (!used_stat) { - ast_str_truncate(*path, size); - ast_str_append(path, 0, "/%s", entry->d_name); - ast_log(LOG_VERBOSE, "!###### d_name=%s, path=%s\n", entry->d_name, ast_str_buffer(*path)); + if (!full_path) { + /* Don't use alloca. See note above. */ + full_path = ast_malloc(strlen(path) + strlen(entry->d_name) + 2); + if (!full_path) { + return -1; + } + sprintf(full_path, "%s/%s", path, entry->d_name); } - if ((res = __ast_file_read_dirs(path, on_file, obj, max_depth))) { + if ((res = __ast_file_read_dirs(full_path, on_file, obj, max_depth))) { break; } } @@ -1196,7 +1192,7 @@ static int __ast_file_read_dirs(struct ast_str **path, ast_file_on_file on_file, if (!res && errno) { ast_log(LOG_ERROR, "Error while reading directories - %s: %s\n", - ast_str_buffer(*path), strerror(errno)); + path, strerror(errno)); res = -1; } @@ -1217,27 +1213,20 @@ AST_MUTEX_DEFINE_STATIC(read_dirs_lock); int ast_file_read_dirs(const char *dir_name, ast_file_on_file on_file, void *obj, int max_depth) { - struct ast_str *path; int res; - if (!(path = ast_str_create(256))) { - return -1; - } - - ast_str_set(&path, 0, "%s", dir_name); errno = 0; #if !defined(__GLIBC__) ast_mutex_lock(&read_dirs_lock); #endif - res = __ast_file_read_dirs(&path, on_file, obj, max_depth); + res = __ast_file_read_dirs(dir_name, on_file, obj, max_depth); #if !defined(__GLIBC__) ast_mutex_unlock(&read_dirs_lock); #endif - ast_free(path); return res; } diff --git a/tests/test_file.c b/tests/test_file.c index 64bad9218d..bb8a99584d 100644 --- a/tests/test_file.c +++ b/tests/test_file.c @@ -21,7 +21,10 @@ core ***/ + #include "asterisk.h" +#include +#include #include "asterisk/file.h" #include "asterisk/paths.h" @@ -115,6 +118,17 @@ static char *test_files_get_one(struct _filenames *filenames, int num) static int handle_find_file(const char *dir_name, const char *filename, void *obj) { + struct stat statbuf; + char *full_path = ast_alloca(strlen(dir_name) + strlen(filename) + 2); + + sprintf(full_path, "%s/%s", dir_name, filename); + + errno = 0; + if (stat(full_path, &statbuf)) { + ast_log(LOG_ERROR, "Error reading path stats - %s: %s\n", + full_path, strerror(errno)); + return 0; + } /* obj contains the name of the file we are looking for */ return strcmp(obj, filename) ? 0 : FOUND; }