diff options
author | wm4 <wm4@nowhere> | 2016-04-18 22:08:18 +0200 |
---|---|---|
committer | wm4 <wm4@nowhere> | 2016-04-18 22:08:44 +0200 |
commit | 503dada42f1ea1007768da0dc6a41b67cdf89400 (patch) | |
tree | 9c04d3fefa8261c6dba44a3809187dbadf25c4aa | |
parent | 382bafcb1349855c2871bbe0a813f8493e1bd9f7 (diff) | |
download | mpv-503dada42f1ea1007768da0dc6a41b67cdf89400.tar.bz2 mpv-503dada42f1ea1007768da0dc6a41b67cdf89400.tar.xz |
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.)
-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; |