From 197caee151f7b8a53eeaebc5b88f833a708fd8b8 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 14 Oct 2008 11:10:54 +0200 Subject: update: don't follow relative symlinks Don't follow relative symlinks which point into the music directory. This allows you to organize music with symbolic links, without MPD managing separate copies of each song. --- src/update.c | 45 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/src/update.c b/src/update.c index e36a980dd..219806a4c 100644 --- a/src/update.c +++ b/src/update.c @@ -312,6 +312,48 @@ static int skip_path(const char *path) return (path[0] == '.' || strchr(path, '\n')) ? 1 : 0; } +static bool +skip_symlink(const struct directory *directory, const char *utf8_name) +{ + char buffer[MPD_PATH_MAX]; + const char *p; + ssize_t ret; + + p = map_directory_child_fs(directory, utf8_name, buffer); + if (p == NULL) + return true; + + ret = readlink(p, buffer, sizeof(buffer)); + if (ret < 0) + /* don't skip if this is not a symlink */ + return errno != EINVAL; + + if (buffer[0] == '/') + return false; + + p = buffer; + while (*p == '.') { + if (p[1] == '.' && p[2] == '/') { + /* "../" moves to parent directory */ + directory = directory->parent; + if (directory == NULL) + /* we have moved outside the music + directory - don't skip this + symlink */ + return false; + p += 3; + } else if (p[1] == '/') + /* eliminate "./" */ + p += 2; + else + break; + } + + /* we are still in the music directory, so this symlink points + to a song which is already in the database - skip it */ + return true; +} + static bool updateDirectory(struct directory *directory, const struct stat *st) { @@ -338,7 +380,8 @@ updateDirectory(struct directory *directory, const struct stat *st) char *utf8; struct stat st2; - if (skip_path(ent->d_name)) + if (skip_path(ent->d_name) || + skip_symlink(directory, ent->d_name)) continue; utf8 = fs_charset_to_utf8(path_max_tmp, ent->d_name); -- cgit v1.2.3