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:
- fix crash when using "rangeid" while playing
* storage
- fix disappearing mounts after mounting twice
- udisks: fix reading ".mpdignore"
* input
- file: detect premature end of file

View File

@ -198,6 +198,11 @@ handle_mount(Client &client, Request args, Response &r)
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 storage = CreateStorageURI(event_loop, remote_uri);
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);
Directory &directory = root.Make(uri);
assert(!directory.storage);
directory.storage = std::move(storage);
}

View File

@ -100,6 +100,15 @@ public:
gcc_pure gcc_nonnull_all
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
* 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());
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 storage = CreateStorageURI(event_loop, url.c_str());
if (storage == nullptr) {
@ -124,8 +130,7 @@ storage_state_restore(const char *line, TextFile &file, Instance &instance)
}
}
((CompositeStorage*)instance.storage)->Mount(uri.c_str(),
std::move(storage));
composite_storage.Mount(uri.c_str(), std::move(storage));
return true;
}