summaryrefslogtreecommitdiffstats
path: root/demux
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2016-04-18 22:08:18 +0200
committerwm4 <wm4@nowhere>2016-04-18 22:08:44 +0200
commit503dada42f1ea1007768da0dc6a41b67cdf89400 (patch)
tree9c04d3fefa8261c6dba44a3809187dbadf25c4aa /demux
parent382bafcb1349855c2871bbe0a813f8493e1bd9f7 (diff)
downloadmpv-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.)
Diffstat (limited to 'demux')
-rw-r--r--demux/demux_playlist.c74
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;