diff options
-rw-r--r-- | demux/demux_playlist.c | 74 |
1 files changed, 57 insertions, 17 deletions
diff --git a/demux/demux_playlist.c b/demux/demux_playlist.c index a5e9ca4ea1..874992c3fa 100644 --- a/demux/demux_playlist.c +++ b/demux/demux_playlist.c @@ -20,6 +20,7 @@ #include <strings.h> #include <dirent.h> +#include "config.h" #include "common/common.h" #include "options/options.h" #include "common/msg.h" @@ -209,6 +210,59 @@ static int parse_txt(struct pl_parser *p) return 0; } +#define MAX_DIR_STACK 20 + +static bool same_st(struct stat *st1, struct stat *st2) +{ + return HAVE_POSIX && st1->st_dev == st2->st_dev && st1->st_ino == st2->st_ino; +} + +// Return true if this was a readable directory. +static bool scan_dir(struct pl_parser *p, char *path, + struct stat *dir_stack, int num_dir_stack, + char ***files, int *num_files) +{ + if (strlen(path) >= 8192 || num_dir_stack == MAX_DIR_STACK) + return false; // things like mount bind loops + + DIR *dp = opendir(path); + if (!dp) { + MP_ERR(p, "Could not read directory.\n"); + return false; + } + + struct dirent *ep; + while ((ep = readdir(dp))) { + if (ep->d_name[0] == '.') + continue; + + if (mp_cancel_test(p->s->cancel)) + break; + + char *file = mp_path_join(p, path, ep->d_name); + + struct stat st; + if (stat(file, &st) == 0 && S_ISDIR(st.st_mode)) { + for (int n = 0; n < num_dir_stack; n++) { + if (same_st(&dir_stack[n], &st)) { + MP_VERBOSE(p, "Skip recursive entry: %s\n", file); + goto skip; + } + } + + dir_stack[num_dir_stack] = st; + scan_dir(p, file, dir_stack, num_dir_stack + 1, files, num_files); + } else { + MP_TARRAY_APPEND(p, *files, *num_files, file); + } + + skip: ; + } + + closedir(dp); + return true; +} + static int cmp_filename(const void *a, const void *b) { return strcmp(*(char **)a, *(char **)b); @@ -222,32 +276,18 @@ static int parse_dir(struct pl_parser *p) return 0; char *path = mp_file_get_path(p, bstr0(p->real_stream->url)); - if (strlen(path) >= 8192) - return -1; // things like mount bind loops - - DIR *dp = opendir(path); - if (!dp) { - MP_ERR(p, "Could not read directory.\n"); - return -1; - } char **files = NULL; int num_files = 0; + struct stat dir_stack[MAX_DIR_STACK]; - struct dirent *ep; - while ((ep = readdir(dp))) { - if (ep->d_name[0] == '.') - continue; - MP_TARRAY_APPEND(p, files, num_files, talloc_strdup(p, ep->d_name)); - } + scan_dir(p, path, dir_stack, 0, &files, &num_files); if (files) qsort(files, num_files, sizeof(files[0]), cmp_filename); for (int n = 0; n < num_files; n++) - playlist_add_file(p->pl, mp_path_join(p, path, files[n])); - - closedir(dp); + playlist_add_file(p->pl, files[n]); p->add_base = false; |