From 8376578921c344a584b604657cc7275be804551d Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Fri, 19 Jan 2018 23:35:05 +0100
Subject: [PATCH] db/simple/Mount: drop mount point prefix from
 LOCATE_TAG_BASE_TYPE

Fixes search within mount points, resulting in error "No such
directory".

Closes #190
---
 NEWS                            |  2 ++
 src/SongFilter.cxx              | 32 ++++++++++++++++++++++++++++++++
 src/SongFilter.hxx              |  7 +++++++
 src/db/plugins/simple/Mount.cxx | 12 ++++++++++++
 4 files changed, 53 insertions(+)

diff --git a/NEWS b/NEWS
index f5182a945..2836e984e 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,6 @@
 ver 0.20.16 (not yet released)
+* database
+  - simple: fix search within mount points
 * fix crash in debug build on Haiku and other operating systems
 
 ver 0.20.15 (2018/01/05)
diff --git a/src/SongFilter.cxx b/src/SongFilter.cxx
index a42f15ff4..c0e0a2edd 100644
--- a/src/SongFilter.cxx
+++ b/src/SongFilter.cxx
@@ -24,6 +24,8 @@
 #include "tag/Tag.hxx"
 #include "util/ConstBuffer.hxx"
 #include "util/StringAPI.hxx"
+#include "util/StringCompare.hxx"
+#include "util/StringView.hxx"
 #include "util/ASCII.hxx"
 #include "util/TimeParser.hxx"
 #include "util/UriUtil.hxx"
@@ -274,3 +276,33 @@ SongFilter::GetBase() const noexcept
 
 	return nullptr;
 }
+
+SongFilter
+SongFilter::WithoutBasePrefix(const char *_prefix) const noexcept
+{
+	const StringView prefix(_prefix);
+	SongFilter result;
+
+	for (const auto &i : items) {
+		if (i.GetTag() == LOCATE_TAG_BASE_TYPE) {
+			const char *s = StringAfterPrefix(i.GetValue(), prefix);
+			if (s != nullptr) {
+				if (*s == 0)
+					continue;
+
+				if (*s == '/') {
+					++s;
+
+					if (*s != 0)
+						result.items.emplace_back(LOCATE_TAG_BASE_TYPE, s);
+
+					continue;
+				}
+			}
+		}
+
+		result.items.emplace_back(i);
+	}
+
+	return result;
+}
diff --git a/src/SongFilter.hxx b/src/SongFilter.hxx
index d102db94f..f0fa73635 100644
--- a/src/SongFilter.hxx
+++ b/src/SongFilter.hxx
@@ -152,6 +152,13 @@ public:
 	 */
 	gcc_pure
 	const char *GetBase() const noexcept;
+
+	/**
+	 * Create a copy of the filter with the given prefix stripped
+	 * from all #LOCATE_TAG_BASE_TYPE items.  This is used to
+	 * filter songs in mounted databases.
+	 */
+	SongFilter WithoutBasePrefix(const char *prefix) const noexcept;
 };
 
 /**
diff --git a/src/db/plugins/simple/Mount.cxx b/src/db/plugins/simple/Mount.cxx
index 1945b74c6..22db95f46 100644
--- a/src/db/plugins/simple/Mount.cxx
+++ b/src/db/plugins/simple/Mount.cxx
@@ -20,6 +20,7 @@
 #include "config.h"
 #include "Mount.hxx"
 #include "PrefixedLightSong.hxx"
+#include "SongFilter.hxx"
 #include "db/Selection.hxx"
 #include "db/LightDirectory.hxx"
 #include "db/Interface.hxx"
@@ -86,5 +87,16 @@ WalkMount(const char *base, const Database &db,
 		vp = std::bind(PrefixVisitPlaylist,
 			       base, std::ref(visit_playlist), _1, _2);
 
+	SongFilter prefix_filter;
+
+	if (base != nullptr && filter != nullptr) {
+		/* if the SongFilter contains a LOCATE_TAG_BASE_TYPE
+		   item, copy the SongFilter and drop the mount point
+		   from the filter, because the mounted database
+		   doesn't know its own location within MPD's VFS */
+		prefix_filter = filter->WithoutBasePrefix(base);
+		filter = &prefix_filter;
+	}
+
 	db.Visit(DatabaseSelection(uri, recursive, filter), vd, vs, vp);
 }