From 503dada42f1ea1007768da0dc6a41b67cdf89400 Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 18 Apr 2016 22:08:18 +0200 Subject: demux_playlist: read directories recursive demux_playlist.c recognizes if the source stream points to a directory, and adds its directory entries. Until now, only 1 level was added. During playback, further directory entries could be resolved as directory paths were "played". While this worked fine, it lead to frequent user confusion, because playlist resuming and other things didn't work as expected. So just recursively scan everything. I'm unsure whether it's a good fix, but at least it gets rid of the complaints. (And probably will add others.) --- demux/demux_playlist.c | 74 ++++++++++++++++++++++++++++++++++++++------------ 1 file 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 #include +#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; -- cgit v1.2.3