From e391f4b17b2fdd092b729f0dfec0b84265894e41 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@duempel.org>
Date: Wed, 15 Aug 2012 20:57:45 +0200
Subject: ProxyDatabase: pass "detached" objects to visitors

Fixes wrong object URIs with duplicate base names.
---
 src/Song.cxx                   | 10 +++++-
 src/db/ProxyDatabasePlugin.cxx | 73 ++++++++++++++++++++----------------------
 src/song.h                     |  6 ++++
 3 files changed, 49 insertions(+), 40 deletions(-)

(limited to 'src')

diff --git a/src/Song.cxx b/src/Song.cxx
index 2ef690fb0..eb4c2e53e 100644
--- a/src/Song.cxx
+++ b/src/Song.cxx
@@ -78,6 +78,14 @@ song_replace_uri(struct song *old_song, const char *uri)
 	return new_song;
 }
 
+struct song *
+song_detached_new(const char *uri)
+{
+	assert(uri != nullptr);
+
+	return song_alloc(uri, &detached_root);
+}
+
 struct song *
 song_dup_detached(const struct song *src)
 {
@@ -86,7 +94,7 @@ song_dup_detached(const struct song *src)
 	struct song *song;
 	if (song_in_database(src)) {
 		char *uri = song_get_uri(src);
-		song = song_alloc(uri, &detached_root);
+		song = song_detached_new(uri);
 		g_free(uri);
 	} else
 		song = song_alloc(src->uri, nullptr);
diff --git a/src/db/ProxyDatabasePlugin.cxx b/src/db/ProxyDatabasePlugin.cxx
index 3525e6f09..26e7b4b84 100644
--- a/src/db/ProxyDatabasePlugin.cxx
+++ b/src/db/ProxyDatabasePlugin.cxx
@@ -192,29 +192,33 @@ ProxyDatabase::GetSong(const char *uri, GError **error_r) const
 }
 
 static bool
-Visit(struct mpd_connection *connection, directory &parent,
+Visit(struct mpd_connection *connection, const char *uri,
       bool recursive, VisitDirectory visit_directory, VisitSong visit_song,
       VisitPlaylist visit_playlist, GError **error_r);
 
 static bool
-Visit(struct mpd_connection *connection, directory &parent,
+Visit(struct mpd_connection *connection,
       bool recursive, const struct mpd_directory *directory,
       VisitDirectory visit_directory, VisitSong visit_song,
       VisitPlaylist visit_playlist, GError **error_r)
 {
-	if (!recursive && !visit_directory)
-		return true;
-
-	struct directory *d =
-		directory_new(mpd_directory_get_path(directory), &parent);
+	const char *path = mpd_directory_get_path(directory);
+
+	if (visit_directory) {
+		struct directory *d =
+			directory_new(path, &detached_root);
+		bool success = visit_directory(*d, error_r);
+		directory_free(d);
+		if (!success)
+			return false;
+	}
 
-	bool success = (!visit_directory || visit_directory(*d, error_r)) &&
-		(!recursive ||
-		 Visit(connection, *d, recursive,
-		       visit_directory, visit_song, visit_playlist, error_r));
-	directory_free(d);
+	if (recursive &&
+	    !Visit(connection, path, recursive,
+		   visit_directory, visit_song, visit_playlist, error_r))
+		return false;
 
-	return success;
+	return true;
 }
 
 static void
@@ -232,11 +236,9 @@ Copy(struct tag *tag, enum tag_type d_tag,
 }
 
 static song *
-Convert(struct directory &parent, const struct mpd_song *song)
+Convert(const struct mpd_song *song)
 {
-	char *name = g_path_get_basename(mpd_song_get_uri(song));
-	struct song *s = song_file_new(name, &parent);
-	g_free(name);
+	struct song *s = song_detached_new(mpd_song_get_uri(song));
 
 	s->mtime = mpd_song_get_last_modified(song);
 	s->start_ms = mpd_song_get_start(song) * 1000;
@@ -256,13 +258,13 @@ Convert(struct directory &parent, const struct mpd_song *song)
 }
 
 static bool
-Visit(struct directory &parent, const struct mpd_song *song,
+Visit(const struct mpd_song *song,
       VisitSong visit_song, GError **error_r)
 {
 	if (!visit_song)
 		return true;
 
-	struct song *s = Convert(parent, song);
+	struct song *s = Convert(song);
 	bool success = visit_song(*s, error_r);
 	song_free(s);
 
@@ -270,19 +272,18 @@ Visit(struct directory &parent, const struct mpd_song *song,
 }
 
 static bool
-Visit(struct directory &parent, const struct mpd_playlist *playlist,
+Visit(const struct mpd_playlist *playlist,
       VisitPlaylist visit_playlist, GError **error_r)
 {
 	if (!visit_playlist)
 		return true;
 
-	char *name = g_path_get_basename(mpd_playlist_get_path(playlist));
 	struct playlist_metadata p;
-	p.name = name;
+	p.name = g_strdup(mpd_playlist_get_path(playlist));
 	p.mtime = mpd_playlist_get_last_modified(playlist);
 
-	bool success = visit_playlist(p, parent, error_r);
-	g_free(name);
+	bool success = visit_playlist(p, detached_root, error_r);
+	g_free(p.name);
 
 	return success;
 }
@@ -326,11 +327,11 @@ ReceiveEntities(struct mpd_connection *connection)
 }
 
 static bool
-Visit(struct mpd_connection *connection, struct directory &parent,
+Visit(struct mpd_connection *connection, const char *uri,
       bool recursive, VisitDirectory visit_directory, VisitSong visit_song,
       VisitPlaylist visit_playlist, GError **error_r)
 {
-	if (!mpd_send_list_meta(connection, directory_get_path(&parent)))
+	if (!mpd_send_list_meta(connection, uri))
 		return CheckError(connection, error_r);
 
 	std::list<ProxyEntity> entities(ReceiveEntities(connection));
@@ -343,7 +344,7 @@ Visit(struct mpd_connection *connection, struct directory &parent,
 			break;
 
 		case MPD_ENTITY_TYPE_DIRECTORY:
-			if (!Visit(connection, parent, recursive,
+			if (!Visit(connection, recursive,
 				   mpd_entity_get_directory(entity),
 				   visit_directory, visit_song, visit_playlist,
 				   error_r))
@@ -351,13 +352,13 @@ Visit(struct mpd_connection *connection, struct directory &parent,
 			break;
 
 		case MPD_ENTITY_TYPE_SONG:
-			if (!Visit(parent, mpd_entity_get_song(entity),
-				   visit_song, error_r))
+			if (!Visit(mpd_entity_get_song(entity), visit_song,
+				   error_r))
 				return false;
 			break;
 
 		case MPD_ENTITY_TYPE_PLAYLIST:
-			if (!Visit(parent, mpd_entity_get_playlist(entity),
+			if (!Visit(mpd_entity_get_playlist(entity),
 				   visit_playlist, error_r))
 				return false;
 			break;
@@ -377,15 +378,9 @@ ProxyDatabase::Visit(const DatabaseSelection &selection,
 	// TODO: match
 	// TODO: auto-reconnect
 
-	struct directory *parent = *selection.uri == 0
-		? root
-		: directory_new(selection.uri, root);
-	bool success = ::Visit(connection, *parent, selection.recursive,
-			       visit_directory, visit_song, visit_playlist,
-			       error_r);
-	if (parent != root)
-		directory_free(parent);
-	return success;
+	return ::Visit(connection, selection.uri, selection.recursive,
+		       visit_directory, visit_song, visit_playlist,
+		       error_r);
 }
 
 bool
diff --git a/src/song.h b/src/song.h
index a09b69df2..39f916a6a 100644
--- a/src/song.h
+++ b/src/song.h
@@ -93,6 +93,12 @@ song_file_load(const char *path, struct directory *parent);
 struct song *
 song_replace_uri(struct song *song, const char *uri);
 
+/**
+ * Creates a "detached" song object.
+ */
+struct song *
+song_detached_new(const char *uri);
+
 /**
  * Creates a duplicate of the song object.  If the object is in the
  * database, it creates a "detached" copy of this song, see
-- 
cgit v1.2.3