From 777e15bd7840f517c9fb826dadca513b5afbfd7e Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Wed, 8 Feb 2017 09:47:43 +0100
Subject: [PATCH] db/DatabaseSong: make the Storage optional

Some database plugins don't use a Storage (e.g. UPnP), and with this
plugin, DatabaseDetachSong() can crash.
---
 src/SongLoader.cxx               | 2 +-
 src/command/DatabaseCommands.cxx | 2 +-
 src/command/PlaylistCommands.cxx | 2 +-
 src/db/DatabasePlaylist.cxx      | 6 +++---
 src/db/DatabasePlaylist.hxx      | 2 +-
 src/db/DatabaseQueue.cxx         | 2 +-
 src/db/DatabaseSong.cxx          | 8 ++++----
 src/db/DatabaseSong.hxx          | 4 ++--
 test/test_translate_song.cxx     | 2 +-
 9 files changed, 15 insertions(+), 15 deletions(-)

diff --git a/src/SongLoader.cxx b/src/SongLoader.cxx
index 7d03ff075..72c035038 100644
--- a/src/SongLoader.cxx
+++ b/src/SongLoader.cxx
@@ -41,7 +41,7 @@ SongLoader::LoadFromDatabase(const char *uri) const
 {
 #ifdef ENABLE_DATABASE
 	if (db != nullptr)
-		return DatabaseDetachSong(*db, *storage, uri);
+		return DatabaseDetachSong(*db, storage, uri);
 #else
 	(void)uri;
 #endif
diff --git a/src/command/DatabaseCommands.cxx b/src/command/DatabaseCommands.cxx
index d8a9393b7..b67e3c1ae 100644
--- a/src/command/DatabaseCommands.cxx
+++ b/src/command/DatabaseCommands.cxx
@@ -134,7 +134,7 @@ handle_searchaddpl(Client &client, Request args, Response &r)
 
 	const Database &db = client.GetDatabaseOrThrow();
 
-	search_add_to_playlist(db, *client.GetStorage(),
+	search_add_to_playlist(db, client.GetStorage(),
 			       "", playlist, &filter);
 	return CommandResult::OK;
 }
diff --git a/src/command/PlaylistCommands.cxx b/src/command/PlaylistCommands.cxx
index da380bcc5..bedbe5740 100644
--- a/src/command/PlaylistCommands.cxx
+++ b/src/command/PlaylistCommands.cxx
@@ -166,7 +166,7 @@ handle_playlistadd(Client &client, Request args, gcc_unused Response &r)
 #ifdef ENABLE_DATABASE
 		const Database &db = client.GetDatabaseOrThrow();
 
-		search_add_to_playlist(db, *client.GetStorage(),
+		search_add_to_playlist(db, client.GetStorage(),
 				       uri, playlist, nullptr);
 #else
 		r.Error(ACK_ERROR_NO_EXIST, "directory or file not found");
diff --git a/src/db/DatabasePlaylist.cxx b/src/db/DatabasePlaylist.cxx
index 78bbdd5cd..f1deb3a36 100644
--- a/src/db/DatabasePlaylist.cxx
+++ b/src/db/DatabasePlaylist.cxx
@@ -28,7 +28,7 @@
 #include <functional>
 
 static void
-AddSong(const Storage &storage, const char *playlist_path_utf8,
+AddSong(const Storage *storage, const char *playlist_path_utf8,
 	const LightSong &song)
 {
 	spl_append_song(playlist_path_utf8,
@@ -36,14 +36,14 @@ AddSong(const Storage &storage, const char *playlist_path_utf8,
 }
 
 void
-search_add_to_playlist(const Database &db, const Storage &storage,
+search_add_to_playlist(const Database &db, const Storage *storage,
 		       const char *uri, const char *playlist_path_utf8,
 		       const SongFilter *filter)
 {
 	const DatabaseSelection selection(uri, true, filter);
 
 	using namespace std::placeholders;
-	const auto f = std::bind(AddSong, std::ref(storage),
+	const auto f = std::bind(AddSong, storage,
 				 playlist_path_utf8, _1);
 	db.Visit(selection, f);
 }
diff --git a/src/db/DatabasePlaylist.hxx b/src/db/DatabasePlaylist.hxx
index c1b2654e0..cdfb490a2 100644
--- a/src/db/DatabasePlaylist.hxx
+++ b/src/db/DatabasePlaylist.hxx
@@ -28,7 +28,7 @@ class SongFilter;
 
 gcc_nonnull(3,4)
 void
-search_add_to_playlist(const Database &db, const Storage &storage,
+search_add_to_playlist(const Database &db, const Storage *storage,
 		       const char *uri, const char *path_utf8,
 		       const SongFilter *filter);
 
diff --git a/src/db/DatabaseQueue.cxx b/src/db/DatabaseQueue.cxx
index 1b9adcfdc..1fe8c2cd6 100644
--- a/src/db/DatabaseQueue.cxx
+++ b/src/db/DatabaseQueue.cxx
@@ -30,7 +30,7 @@
 static void
 AddToQueue(Partition &partition, const LightSong &song)
 {
-	const Storage &storage = *partition.instance.storage;
+	const auto *storage = partition.instance.storage;
 	partition.playlist.AppendSong(partition.pc,
 				      DatabaseDetachSong(storage,
 							 song));
diff --git a/src/db/DatabaseSong.cxx b/src/db/DatabaseSong.cxx
index ca39ffa49..5b4ca1caa 100644
--- a/src/db/DatabaseSong.cxx
+++ b/src/db/DatabaseSong.cxx
@@ -28,21 +28,21 @@
 #include <assert.h>
 
 DetachedSong
-DatabaseDetachSong(const Storage &storage, const LightSong &song)
+DatabaseDetachSong(const Storage *storage, const LightSong &song)
 {
 	DetachedSong detached(song);
 	assert(detached.IsInDatabase());
 
-	if (!detached.HasRealURI()) {
+	if (!detached.HasRealURI() && storage != nullptr) {
 		const auto uri = song.GetURI();
-		detached.SetRealURI(storage.MapUTF8(uri.c_str()));
+		detached.SetRealURI(storage->MapUTF8(uri.c_str()));
 	}
 
 	return detached;
 }
 
 DetachedSong
-DatabaseDetachSong(const Database &db, const Storage &storage, const char *uri)
+DatabaseDetachSong(const Database &db, const Storage *storage, const char *uri)
 {
 	const LightSong *tmp = db.GetSong(uri);
 	assert(tmp != nullptr);
diff --git a/src/db/DatabaseSong.hxx b/src/db/DatabaseSong.hxx
index b47c4e2a2..316d628b1 100644
--- a/src/db/DatabaseSong.hxx
+++ b/src/db/DatabaseSong.hxx
@@ -33,7 +33,7 @@ class DetachedSong;
  */
 gcc_pure
 DetachedSong
-DatabaseDetachSong(const Storage &storage, const LightSong &song);
+DatabaseDetachSong(const Storage *storage, const LightSong &song);
 
 /**
  * Look up a song in the database and convert it to a #DetachedSong
@@ -43,7 +43,7 @@ DatabaseDetachSong(const Storage &storage, const LightSong &song);
  */
 gcc_pure
 DetachedSong
-DatabaseDetachSong(const Database &db, const Storage &storage,
+DatabaseDetachSong(const Database &db, const Storage *storage,
 		   const char *uri);
 
 #endif
diff --git a/test/test_translate_song.cxx b/test/test_translate_song.cxx
index 0c4be2f37..3e8ae2111 100644
--- a/test/test_translate_song.cxx
+++ b/test/test_translate_song.cxx
@@ -109,7 +109,7 @@ static const char *uri2 = "foo/bar.ogg";
 
 DetachedSong
 DatabaseDetachSong(gcc_unused const Database &db,
-		   gcc_unused const Storage &_storage,
+		   gcc_unused const Storage *_storage,
 		   const char *uri)
 {
 	if (strcmp(uri, uri2) == 0)