summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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;