From 1d640c9887f97ff0f94f4fb631aea3728589abeb Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Sun, 5 May 2024 18:11:00 +0200 Subject: player: normalize paths for resuming playback Paths like foo.mkv, ./foo.mkv .//foo.mkv, ../"$(basename "$PWD")"/foo.mkv, and C:\foo.mkv and C:/foo.mkv on Windows, use different config files for resuming playback, so if you quit-watch-later and later play the same file with a different path, mpv does not resume playback. This commit normalizes the paths on Unix to fix this. --- misc/path_utils.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) (limited to 'misc') diff --git a/misc/path_utils.c b/misc/path_utils.c index 14b4a97031..7fbd1084b8 100644 --- a/misc/path_utils.c +++ b/misc/path_utils.c @@ -151,10 +151,61 @@ char *mp_getcwd(void *talloc_ctx) char *mp_normalize_path(void *talloc_ctx, const char *path) { + if (!path) + return NULL; + if (mp_is_url(bstr0(path))) return talloc_strdup(talloc_ctx, path); - return mp_path_join(talloc_ctx, mp_getcwd(talloc_ctx), path); + if (!mp_path_is_absolute(bstr0(path))) { + char *cwd = mp_getcwd(talloc_ctx); + if (!cwd) + return NULL; + path = mp_path_join(talloc_ctx, cwd, path); + } + +#if HAVE_DOS_PATHS + return talloc_strdup(talloc_ctx, path); +#else + char *result = talloc_strdup(talloc_ctx, ""); + const char *next; + const char *end = path + strlen(path); + + for (const char *ptr = path; ptr < end; ptr = next + 1) { + next = memchr(ptr, '/', end - ptr); + if (next == NULL) + next = end; + + switch (next - ptr) { + case 0: + continue; + case 1: + if (ptr[0] == '.') + continue; + break; + case 2: + // Normalizing symlink/.. results in a wrong path: if the + // current working directory is /tmp/foo, and it is a symlink to + // /usr/bin, mpv ../file.mkv opens /usr/file.mkv, so we can't + // normalize the path to /tmp/file.mkv. Resolve symlinks to fix + // this. Otherwise we don't use realpath so users can use + // symlinks e.g. to hide how media files are distributed over + // real storage and move them while still resuming playback as + // long as the symlinked path doesn't change. + if (ptr[0] == '.' && ptr[1] == '.') { + char *tmp_result = realpath(path, NULL); + result = talloc_strdup(talloc_ctx, tmp_result); + free(tmp_result); + return result; + } + } + + result = talloc_strdup_append_buffer(result, "/"); + result = talloc_strndup_append_buffer(result, ptr, next - ptr); + } + + return result; +#endif } bool mp_path_exists(const char *path) -- cgit v1.2.3