command/storage: check if mount point is busy

When mounting something over a directory that is already a mount
point, CompositeStorage::Mount() silently overwrites the previously
mounted storage, disposing it.  After that, SimpleDatabase::Mount()
will fail and handle_mount() will roll back the
CompositeStorage::Mount() command, effectively unmounting what was
there before (and also leaking memory).

Closes https://github.com/MusicPlayerDaemon/MPD/issues/918
This commit is contained in:
Max Kellermann 2020-07-06 17:45:59 +02:00
parent 5b291ff768
commit 33ee35ab92
5 changed files with 23 additions and 2 deletions

1
NEWS
View File

@ -2,6 +2,7 @@ ver 0.21.25 (not yet released)
* protocol: * protocol:
- fix crash when using "rangeid" while playing - fix crash when using "rangeid" while playing
* storage * storage
- fix disappearing mounts after mounting twice
- udisks: fix reading ".mpdignore" - udisks: fix reading ".mpdignore"
* input * input
- file: detect premature end of file - file: detect premature end of file

View File

@ -198,6 +198,11 @@ handle_mount(Client &client, Request args, Response &r)
return CommandResult::ERROR; return CommandResult::ERROR;
} }
if (composite.IsMountPoint(local_uri)) {
r.Error(ACK_ERROR_ARG, "Mount point busy");
return CommandResult::ERROR;
}
auto &event_loop = instance.io_thread.GetEventLoop(); auto &event_loop = instance.io_thread.GetEventLoop();
auto storage = CreateStorageURI(event_loop, remote_uri); auto storage = CreateStorageURI(event_loop, remote_uri);
if (storage == nullptr) { if (storage == nullptr) {

View File

@ -206,6 +206,7 @@ CompositeStorage::Mount(const char *uri, std::unique_ptr<Storage> storage)
const std::lock_guard<Mutex> protect(mutex); const std::lock_guard<Mutex> protect(mutex);
Directory &directory = root.Make(uri); Directory &directory = root.Make(uri);
assert(!directory.storage);
directory.storage = std::move(storage); directory.storage = std::move(storage);
} }

View File

@ -100,6 +100,15 @@ public:
gcc_pure gcc_nonnull_all gcc_pure gcc_nonnull_all
Storage *GetMount(const char *uri) noexcept; Storage *GetMount(const char *uri) noexcept;
/**
* Is the given URI a mount point, i.e. is something already
* mounted on this path?
*/
gcc_pure gcc_nonnull_all
bool IsMountPoint(const char *uri) noexcept {
return GetMount(uri) != nullptr;
}
/** /**
* Call the given function for each mounted storage, including * Call the given function for each mounted storage, including
* the root storage. Passes mount point URI and the a const * the root storage. Passes mount point URI and the a const

View File

@ -106,6 +106,12 @@ storage_state_restore(const char *line, TextFile &file, Instance &instance)
FormatDebug(storage_domain, "Restoring mount %s => %s", uri.c_str(), url.c_str()); FormatDebug(storage_domain, "Restoring mount %s => %s", uri.c_str(), url.c_str());
auto &composite_storage = *(CompositeStorage *)instance.storage;
if (composite_storage.IsMountPoint(uri.c_str())) {
LogError(storage_domain, "Mount point busy");
return true;
}
auto &event_loop = instance.io_thread.GetEventLoop(); auto &event_loop = instance.io_thread.GetEventLoop();
auto storage = CreateStorageURI(event_loop, url.c_str()); auto storage = CreateStorageURI(event_loop, url.c_str());
if (storage == nullptr) { if (storage == nullptr) {
@ -124,8 +130,7 @@ storage_state_restore(const char *line, TextFile &file, Instance &instance)
} }
} }
((CompositeStorage*)instance.storage)->Mount(uri.c_str(), composite_storage.Mount(uri.c_str(), std::move(storage));
std::move(storage));
return true; return true;
} }