diff options
author | Max Kellermann <max@musicpd.org> | 2020-07-06 20:45:29 +0200 |
---|---|---|
committer | Max Kellermann <max@musicpd.org> | 2020-07-06 20:56:52 +0200 |
commit | c3cfb5fe166b8ce860d581a0ddd59a4915cb36db (patch) | |
tree | d50c374a57cf8682d27ded88fe9c62856aed2173 /src | |
parent | 86823af6857e06914dcfeab0c76c68ba76126bce (diff) | |
parent | 749ad7cd83f4061fc8714202bcc51b3ec065139d (diff) |
Merge branch 'v0.21.x'
Diffstat (limited to 'src')
25 files changed, 186 insertions, 83 deletions
diff --git a/src/PluginUnavailable.hxx b/src/PluginUnavailable.hxx index f47826689..a29361ad4 100644 --- a/src/PluginUnavailable.hxx +++ b/src/PluginUnavailable.hxx @@ -29,9 +29,7 @@ */ class PluginUnavailable : public std::runtime_error { public: - template<typename M> - explicit PluginUnavailable(M &&msg) noexcept - :std::runtime_error(std::forward<M>(msg)) {} + using std::runtime_error::runtime_error; }; /** @@ -42,9 +40,7 @@ public: */ class PluginUnconfigured : public PluginUnavailable { public: - template<typename M> - explicit PluginUnconfigured(M &&msg) noexcept - :PluginUnavailable(std::forward<M>(msg)) {} + using PluginUnavailable::PluginUnavailable; }; #endif diff --git a/src/SongUpdate.cxx b/src/SongUpdate.cxx index 30cd699e0..c5701d9aa 100644 --- a/src/SongUpdate.cxx +++ b/src/SongUpdate.cxx @@ -69,17 +69,22 @@ Song::UpdateFile(Storage &storage) TagBuilder tag_builder; auto new_audio_format = AudioFormat::Undefined(); - const auto path_fs = storage.MapFS(relative_uri.c_str()); - if (path_fs.IsNull()) { - const auto absolute_uri = - storage.MapUTF8(relative_uri.c_str()); - if (!tag_stream_scan(absolute_uri.c_str(), tag_builder, - &new_audio_format)) - return false; - } else { - if (!ScanFileTagsWithGeneric(path_fs, tag_builder, + try { + const auto path_fs = storage.MapFS(relative_uri.c_str()); + if (path_fs.IsNull()) { + const auto absolute_uri = + storage.MapUTF8(relative_uri.c_str()); + if (!tag_stream_scan(absolute_uri.c_str(), tag_builder, &new_audio_format)) - return false; + return false; + } else { + if (!ScanFileTagsWithGeneric(path_fs, tag_builder, + &new_audio_format)) + return false; + } + } catch (...) { + // TODO: log or propagate I/O errors? + return false; } mtime = info.mtime; @@ -139,8 +144,14 @@ DetachedSong::LoadFile(Path path) return false; TagBuilder tag_builder; - if (!ScanFileTagsWithGeneric(path, tag_builder)) + + try { + if (!ScanFileTagsWithGeneric(path, tag_builder)) + return false; + } catch (...) { + // TODO: log or propagate I/O errors? return false; + } mtime = fi.GetModificationTime(); tag_builder.Commit(tag); @@ -157,8 +168,14 @@ DetachedSong::Update() return LoadFile(path_fs); } else if (IsRemote()) { TagBuilder tag_builder; - if (!tag_stream_scan(uri.c_str(), tag_builder)) + + try { + if (!tag_stream_scan(uri.c_str(), tag_builder)) + return false; + } catch (...) { + // TODO: log or propagate I/O errors? return false; + } mtime = std::chrono::system_clock::time_point::min(); tag_builder.Commit(tag); diff --git a/src/TagStream.cxx b/src/TagStream.cxx index 4010318e1..0a1f0b744 100644 --- a/src/TagStream.cxx +++ b/src/TagStream.cxx @@ -43,7 +43,7 @@ CheckDecoderPlugin(const DecoderPlugin &plugin, } bool -tag_stream_scan(InputStream &is, TagHandler &handler) noexcept +tag_stream_scan(InputStream &is, TagHandler &handler) { assert(is.IsReady()); @@ -81,7 +81,7 @@ tag_stream_scan(const char *uri, TagHandler &handler) bool tag_stream_scan(InputStream &is, TagBuilder &builder, - AudioFormat *audio_format) noexcept + AudioFormat *audio_format) { assert(is.IsReady()); diff --git a/src/TagStream.hxx b/src/TagStream.hxx index f7c54e082..9a61719b4 100644 --- a/src/TagStream.hxx +++ b/src/TagStream.hxx @@ -29,14 +29,16 @@ class TagBuilder; * Scan the tags of an #InputStream. Invokes matching decoder * plugins, but does not invoke the special "APE" and "ID3" scanners. * + * Throws on I/O error. + * * @return true if the file was recognized (even if no metadata was * found) */ bool -tag_stream_scan(InputStream &is, TagHandler &handler) noexcept; +tag_stream_scan(InputStream &is, TagHandler &handler); /** - * Throws on error. + * Throws on I/O error. */ bool tag_stream_scan(const char *uri, TagHandler &handler); @@ -46,15 +48,17 @@ tag_stream_scan(const char *uri, TagHandler &handler); * plugins, and falls back to generic scanners (APE and ID3) if no * tags were found (but the file was recognized). * + * Throws on I/O error. + * * @return true if the file was recognized (even if no metadata was * found) */ bool tag_stream_scan(InputStream &is, TagBuilder &builder, - AudioFormat *audio_format=nullptr) noexcept; + AudioFormat *audio_format=nullptr); /** - * Throws on error. + * Throws on I/O error. */ bool tag_stream_scan(const char *uri, TagBuilder &builder, diff --git a/src/command/StorageCommands.cxx b/src/command/StorageCommands.cxx index 5dbff101f..8b5693103 100644 --- a/src/command/StorageCommands.cxx +++ b/src/command/StorageCommands.cxx @@ -195,6 +195,16 @@ 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; + } + + if (composite.IsMounted(remote_uri)) { + r.Error(ACK_ERROR_ARG, "This storage is already mounted"); + return CommandResult::ERROR; + } + auto &event_loop = instance.io_thread.GetEventLoop(); auto storage = CreateStorageURI(event_loop, remote_uri); if (storage == nullptr) { @@ -207,8 +217,10 @@ handle_mount(Client &client, Request args, Response &r) #ifdef ENABLE_DATABASE if (auto *db = dynamic_cast<SimpleDatabase *>(instance.GetDatabase())) { + bool need_update; + try { - db->Mount(local_uri, remote_uri); + need_update = !db->Mount(local_uri, remote_uri); } catch (...) { composite.Unmount(local_uri); throw; @@ -217,6 +229,12 @@ handle_mount(Client &client, Request args, Response &r) // TODO: call Instance::OnDatabaseModified()? // TODO: trigger database update? instance.EmitIdle(IDLE_DATABASE); + + if (need_update) { + UpdateService *update = client.GetInstance().update; + if (update != nullptr) + update->Enqueue(local_uri, false); + } } #endif diff --git a/src/db/plugins/simple/SimpleDatabasePlugin.cxx b/src/db/plugins/simple/SimpleDatabasePlugin.cxx index c0dff9cc2..3cea58a57 100644 --- a/src/db/plugins/simple/SimpleDatabasePlugin.cxx +++ b/src/db/plugins/simple/SimpleDatabasePlugin.cxx @@ -427,7 +427,7 @@ IsUnsafeChar(char ch) return !IsSafeChar(ch); } -void +bool SimpleDatabase::Mount(const char *local_uri, const char *storage_uri) { if (cache_path.IsNull()) @@ -446,9 +446,11 @@ SimpleDatabase::Mount(const char *local_uri, const char *storage_uri) compress); db->Open(); - // TODO: update the new database instance? + bool exists = db->FileExists(); Mount(local_uri, std::move(db)); + + return exists; } inline DatabasePtr diff --git a/src/db/plugins/simple/SimpleDatabasePlugin.hxx b/src/db/plugins/simple/SimpleDatabasePlugin.hxx index ac4f067d1..efcf87927 100644 --- a/src/db/plugins/simple/SimpleDatabasePlugin.hxx +++ b/src/db/plugins/simple/SimpleDatabasePlugin.hxx @@ -103,9 +103,11 @@ public: /** * Throws #std::runtime_error on error. + * + * @return false if the mounted database needs to be updated */ gcc_nonnull_all - void Mount(const char *local_uri, const char *storage_uri); + bool Mount(const char *local_uri, const char *storage_uri); gcc_nonnull_all bool Unmount(const char *uri) noexcept; diff --git a/src/db/update/Walk.cxx b/src/db/update/Walk.cxx index 1cb1538dc..7526c6b6f 100644 --- a/src/db/update/Walk.cxx +++ b/src/db/update/Walk.cxx @@ -322,8 +322,8 @@ UpdateWalk::UpdateDirectory(Directory &directory, try { Mutex mutex; - auto is = InputStream::OpenReady(PathTraitsUTF8::Build(storage.MapUTF8(directory.GetPath()), - ".mpdignore").c_str(), + auto is = InputStream::OpenReady(storage.MapUTF8(PathTraitsUTF8::Build(directory.GetPath(), + ".mpdignore")).c_str(), mutex); child_exclude_list.Load(std::move(is)); } catch (...) { diff --git a/src/decoder/DecoderPlugin.hxx b/src/decoder/DecoderPlugin.hxx index 61f959c79..da4409e47 100644 --- a/src/decoder/DecoderPlugin.hxx +++ b/src/decoder/DecoderPlugin.hxx @@ -67,18 +67,22 @@ struct DecoderPlugin { void (*file_decode)(DecoderClient &client, Path path_fs) = nullptr; /** - * Scan metadata of a file. + * Scan metadata of a file. + * + * Throws on I/O error. * - * @return false if the operation has failed + * @return false if the file was not recognized */ - bool (*scan_file)(Path path_fs, TagHandler &handler) noexcept = nullptr; + bool (*scan_file)(Path path_fs, TagHandler &handler) = nullptr; /** - * Scan metadata of a file. + * Scan metadata of a stream. + * + * Throws on I/O error. * - * @return false if the operation has failed + * @return false if the stream was not recognized */ - bool (*scan_stream)(InputStream &is, TagHandler &handler) noexcept = nullptr; + bool (*scan_stream)(InputStream &is, TagHandler &handler) = nullptr; /** * @brief Return a "virtual" filename for subtracks in @@ -99,14 +103,14 @@ struct DecoderPlugin { void (*_file_decode)(DecoderClient &client, Path path_fs), bool (*_scan_file)(Path path_fs, - TagHandler &handler) noexcept) noexcept + TagHandler &handler)) noexcept :name(_name), file_decode(_file_decode), scan_file(_scan_file) {} constexpr DecoderPlugin(const char *_name, void (*_stream_decode)(DecoderClient &client, InputStream &is), - bool (*_scan_stream)(InputStream &is, TagHandler &handler) noexcept) noexcept + bool (*_scan_stream)(InputStream &is, TagHandler &handler)) noexcept :name(_name), stream_decode(_stream_decode), scan_stream(_scan_stream) {} @@ -114,11 +118,11 @@ struct DecoderPlugin { constexpr DecoderPlugin(const char *_name, void (*_stream_decode)(DecoderClient &client, InputStream &is), - bool (*_scan_stream)(InputStream &is, TagHandler &handler) noexcept, + bool (*_scan_stream)(InputStream &is, TagHandler &handler), void (*_file_decode)(DecoderClient &client, Path path_fs), bool (*_scan_file)(Path path_fs, - TagHandler &handler) noexcept) noexcept + TagHandler &handler)) noexcept :name(_name), stream_decode(_stream_decode), file_decode(_file_decode), @@ -191,7 +195,7 @@ struct DecoderPlugin { * Read the tag of a file. */ template<typename P> - bool ScanFile(P path_fs, TagHandler &handler) const noexcept { + bool ScanFile(P path_fs, TagHandler &handler) const { return scan_file != nullptr ? scan_file(path_fs, handler) : false; @@ -200,7 +204,7 @@ struct DecoderPlugin { /** * Read the tag of a stream. */ - bool ScanStream(InputStream &is, TagHandler &handler) const noexcept { + bool ScanStream(InputStream &is, TagHandler &handler) const { return scan_stream != nullptr ? scan_stream(is, handler) : false; diff --git a/src/decoder/plugins/AudiofileDecoderPlugin.cxx b/src/decoder/plugins/AudiofileDecoderPlugin.cxx index eff898c3b..ce78c693c 100644 --- a/src/decoder/plugins/AudiofileDecoderPlugin.cxx +++ b/src/decoder/plugins/AudiofileDecoderPlugin.cxx @@ -241,7 +241,7 @@ audiofile_stream_decode(DecoderClient &client, InputStream &is) } static bool -audiofile_scan_stream(InputStream &is, TagHandler &handler) noexcept +audiofile_scan_stream(InputStream &is, TagHandler &handler) { if (!is.IsSeekable() || !is.KnownSize()) return false; diff --git a/src/decoder/plugins/DsdiffDecoderPlugin.cxx b/src/decoder/plugins/DsdiffDecoderPlugin.cxx index 5758e05ad..1fb88da16 100644 --- a/src/decoder/plugins/DsdiffDecoderPlugin.cxx +++ b/src/decoder/plugins/DsdiffDecoderPlugin.cxx @@ -448,7 +448,7 @@ dsdiff_stream_decode(DecoderClient &client, InputStream &is) } static bool -dsdiff_scan_stream(InputStream &is, TagHandler &handler) noexcept +dsdiff_scan_stream(InputStream &is, TagHandler &handler) { DsdiffMetaData metadata; DsdiffChunkHeader chunk_header; diff --git a/src/decoder/plugins/DsfDecoderPlugin.cxx b/src/decoder/plugins/DsfDecoderPlugin.cxx index 1d8e943c3..de627a137 100644 --- a/src/decoder/plugins/DsfDecoderPlugin.cxx +++ b/src/decoder/plugins/DsfDecoderPlugin.cxx @@ -325,7 +325,7 @@ dsf_stream_decode(DecoderClient &client, InputStream &is) } static bool -dsf_scan_stream(InputStream &is, TagHandler &handler) noexcept +dsf_scan_stream(InputStream &is, TagHandler &handler) { /* check DSF metadata */ DsfMetaData metadata; diff --git a/src/decoder/plugins/FaadDecoderPlugin.cxx b/src/decoder/plugins/FaadDecoderPlugin.cxx index a3884adec..e9b0feac9 100644 --- a/src/decoder/plugins/FaadDecoderPlugin.cxx +++ b/src/decoder/plugins/FaadDecoderPlugin.cxx @@ -411,7 +411,7 @@ faad_stream_decode(DecoderClient &client, InputStream &is) } static bool -faad_scan_stream(InputStream &is, TagHandler &handler) noexcept +faad_scan_stream(InputStream &is, TagHandler &handler) { auto result = faad_get_file_time(is); if (!result.first) diff --git a/src/decoder/plugins/FfmpegDecoderPlugin.cxx b/src/decoder/plugins/FfmpegDecoderPlugin.cxx index 971241826..ceb0653c2 100644 --- a/src/decoder/plugins/FfmpegDecoderPlugin.cxx +++ b/src/decoder/plugins/FfmpegDecoderPlugin.cxx @@ -591,8 +591,7 @@ ffmpeg_decode(DecoderClient &client, InputStream &input) } static bool -FfmpegScanStream(AVFormatContext &format_context, - TagHandler &handler) noexcept +FfmpegScanStream(AVFormatContext &format_context, TagHandler &handler) { const int find_result = avformat_find_stream_info(&format_context, nullptr); @@ -625,16 +624,14 @@ FfmpegScanStream(AVFormatContext &format_context, } static bool -ffmpeg_scan_stream(InputStream &is, TagHandler &handler) noexcept -try { +ffmpeg_scan_stream(InputStream &is, TagHandler &handler) +{ AvioStream stream(nullptr, is); if (!stream.Open()) return false; auto f = FfmpegOpenInput(stream.io, is.GetURI(), nullptr); return FfmpegScanStream(*f, handler); -} catch (...) { - return false; } /** diff --git a/src/decoder/plugins/FlacDecoderPlugin.cxx b/src/decoder/plugins/FlacDecoderPlugin.cxx index e1c06c5a6..856169450 100644 --- a/src/decoder/plugins/FlacDecoderPlugin.cxx +++ b/src/decoder/plugins/FlacDecoderPlugin.cxx @@ -69,7 +69,7 @@ flac_write_cb(const FLAC__StreamDecoder *dec, const FLAC__Frame *frame, } static bool -flac_scan_file(Path path_fs, TagHandler &handler) noexcept +flac_scan_file(Path path_fs, TagHandler &handler) { FlacMetadataChain chain; if (!chain.Read(NarrowPath(path_fs))) { @@ -84,7 +84,7 @@ flac_scan_file(Path path_fs, TagHandler &handler) noexcept } static bool -flac_scan_stream(InputStream &is, TagHandler &handler) noexcept +flac_scan_stream(InputStream &is, TagHandler &handler) { FlacMetadataChain chain; if (!chain.Read(is)) { @@ -313,7 +313,7 @@ oggflac_init([[maybe_unused]] const ConfigBlock &block) } static bool -oggflac_scan_file(Path path_fs, TagHandler &handler) noexcept +oggflac_scan_file(Path path_fs, TagHandler &handler) { FlacMetadataChain chain; if (!chain.ReadOgg(NarrowPath(path_fs))) { @@ -328,7 +328,7 @@ oggflac_scan_file(Path path_fs, TagHandler &handler) noexcept } static bool -oggflac_scan_stream(InputStream &is, TagHandler &handler) noexcept +oggflac_scan_stream(InputStream &is, TagHandler &handler) { FlacMetadataChain chain; if (!chain.ReadOgg(is)) { diff --git a/src/decoder/plugins/MadDecoderPlugin.cxx b/src/decoder/plugins/MadDecoderPlugin.cxx index 95dc6f7ce..608b03250 100644 --- a/src/decoder/plugins/MadDecoderPlugin.cxx +++ b/src/decoder/plugins/MadDecoderPlugin.cxx @@ -1013,7 +1013,7 @@ MadDecoder::RunScan(TagHandler &handler) noexcept } static bool -mad_decoder_scan_stream(InputStream &is, TagHandler &handler) noexcept +mad_decoder_scan_stream(InputStream &is, TagHandler &handler) { MadDecoder data(nullptr, is); return data.RunScan(handler); diff --git a/src/decoder/plugins/MpcdecDecoderPlugin.cxx b/src/decoder/plugins/MpcdecDecoderPlugin.cxx index e83925574..2ecbe4a48 100644 --- a/src/decoder/plugins/MpcdecDecoderPlugin.cxx +++ b/src/decoder/plugins/MpcdecDecoderPlugin.cxx @@ -273,7 +273,7 @@ mpcdec_get_file_duration(InputStream &is) } static bool -mpcdec_scan_stream(InputStream &is, TagHandler &handler) noexcept +mpcdec_scan_stream(InputStream &is, TagHandler &handler) { const auto duration = mpcdec_get_file_duration(is); if (duration.IsNegative()) diff --git a/src/decoder/plugins/OpusDecoderPlugin.cxx b/src/decoder/plugins/OpusDecoderPlugin.cxx index 126409098..ba5a2bff4 100644 --- a/src/decoder/plugins/OpusDecoderPlugin.cxx +++ b/src/decoder/plugins/OpusDecoderPlugin.cxx @@ -423,8 +423,8 @@ VisitOpusDuration(InputStream &is, OggSyncState &sync, OggStreamState &stream, } } -bool -mpd_opus_scan_stream(InputStream &is, TagHandler &handler) noexcept +static bool +mpd_opus_scan_stream(InputStream &is, TagHandler &handler) { InputStreamReader reader(is); OggSyncState oy(reader); diff --git a/src/decoder/plugins/SndfileDecoderPlugin.cxx b/src/decoder/plugins/SndfileDecoderPlugin.cxx index 803dd259b..bde242c87 100644 --- a/src/decoder/plugins/SndfileDecoderPlugin.cxx +++ b/src/decoder/plugins/SndfileDecoderPlugin.cxx @@ -268,7 +268,7 @@ static constexpr struct { }; static bool -sndfile_scan_stream(InputStream &is, TagHandler &handler) noexcept +sndfile_scan_stream(InputStream &is, TagHandler &handler) { SF_INFO info; diff --git a/src/decoder/plugins/VorbisDecoderPlugin.cxx b/src/decoder/plugins/VorbisDecoderPlugin.cxx index 13361c2ad..cadef0ca2 100644 --- a/src/decoder/plugins/VorbisDecoderPlugin.cxx +++ b/src/decoder/plugins/VorbisDecoderPlugin.cxx @@ -370,7 +370,7 @@ VisitVorbisDuration(InputStream &is, } static bool -vorbis_scan_stream(InputStream &is, TagHandler &handler) noexcept +vorbis_scan_stream(InputStream &is, TagHandler &handler) { /* initialize libogg */ diff --git a/src/decoder/plugins/WavpackDecoderPlugin.cxx b/src/decoder/plugins/WavpackDecoderPlugin.cxx index 983c4e0f7..a3b6f0991 100644 --- a/src/decoder/plugins/WavpackDecoderPlugin.cxx +++ b/src/decoder/plugins/WavpackDecoderPlugin.cxx @@ -612,7 +612,7 @@ wavpack_scan_file(Path path_fs, TagHandler &handler) noexcept } static bool -wavpack_scan_stream(InputStream &is, TagHandler &handler) noexcept +wavpack_scan_stream(InputStream &is, TagHandler &handler) { WavpackInput isp(nullptr, is); diff --git a/src/neighbor/plugins/UdisksNeighborPlugin.cxx b/src/neighbor/plugins/UdisksNeighborPlugin.cxx index 4ff406f2c..687fff0e2 100644 --- a/src/neighbor/plugins/UdisksNeighborPlugin.cxx +++ b/src/neighbor/plugins/UdisksNeighborPlugin.cxx @@ -45,6 +45,11 @@ ToNeighborInfo(const UDisks2::Object &o) noexcept return {o.GetUri(), o.path}; } +static constexpr char udisks_neighbor_match[] = + "type='signal',sender='" UDISKS2_INTERFACE "'," + "interface='" DBUS_OM_INTERFACE "'," + "path='" UDISKS2_PATH "'"; + class UdisksNeighborExplorer final : public NeighborExplorer { @@ -106,26 +111,37 @@ UdisksNeighborExplorer::DoOpen() auto &connection = GetConnection(); + /* this ugly try/catch cascade is only here because this + method has no RAII for this method - TODO: improve this */ try { Error error; - dbus_bus_add_match(connection, - "type='signal',sender='" UDISKS2_INTERFACE "'," - "interface='" DBUS_OM_INTERFACE "'," - "path='" UDISKS2_PATH "'", - error); + dbus_bus_add_match(connection, udisks_neighbor_match, error); error.CheckThrow("DBus AddMatch error"); - dbus_connection_add_filter(connection, - HandleMessage, this, - nullptr); - - auto msg = Message::NewMethodCall(UDISKS2_INTERFACE, - UDISKS2_PATH, - DBUS_OM_INTERFACE, - "GetManagedObjects"); - list_request.Send(connection, *msg.Get(), - std::bind(&UdisksNeighborExplorer::OnListNotify, - this, std::placeholders::_1)); + try { + dbus_connection_add_filter(connection, + HandleMessage, this, + nullptr); + + try { + auto msg = Message::NewMethodCall(UDISKS2_INTERFACE, + UDISKS2_PATH, + DBUS_OM_INTERFACE, + "GetManagedObjects"); + list_request.Send(connection, *msg.Get(), + std::bind(&UdisksNeighborExplorer::OnListNotify, + this, std::placeholders::_1)); + } catch (...) { + dbus_connection_remove_filter(connection, + HandleMessage, + this); + throw; + } + } catch (...) { + dbus_bus_remove_match(connection, + udisks_neighbor_match, nullptr); + throw; + } } catch (...) { dbus_glue.Destruct(); throw; @@ -145,8 +161,10 @@ UdisksNeighborExplorer::DoClose() noexcept list_request.Cancel(); } - // TODO: remove_match - // TODO: remove_filter + auto &connection = GetConnection(); + + dbus_connection_remove_filter(connection, HandleMessage, this); + dbus_bus_remove_match(connection, udisks_neighbor_match, nullptr); dbus_glue.Destruct(); } diff --git a/src/storage/CompositeStorage.cxx b/src/storage/CompositeStorage.cxx index 479927f65..f93452b70 100644 --- a/src/storage/CompositeStorage.cxx +++ b/src/storage/CompositeStorage.cxx @@ -211,6 +211,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); } diff --git a/src/storage/CompositeStorage.hxx b/src/storage/CompositeStorage.hxx index 3ed9ab730..432aecbd1 100644 --- a/src/storage/CompositeStorage.hxx +++ b/src/storage/CompositeStorage.hxx @@ -101,6 +101,15 @@ public: Storage *GetMount(std::string_view 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 * Storage reference to the function. @@ -112,6 +121,15 @@ public: VisitMounts(uri, root, t); } + /** + * Is a storage with the given URI already mounted? + */ + gcc_pure gcc_nonnull_all + bool IsMounted(const char *storage_uri) const noexcept { + const std::lock_guard<Mutex> protect(mutex); + return IsMounted(root, storage_uri); + } + void Mount(const char *uri, std::unique_ptr<Storage> storage); bool Unmount(const char *uri); @@ -146,6 +164,22 @@ private: } } + gcc_pure gcc_nonnull_all + static bool IsMounted(const Directory &directory, + const char *storage_uri) noexcept { + if (directory.storage) { + const auto uri = directory.storage->MapUTF8(""); + if (uri == storage_uri) + return true; + } + + for (const auto &i : directory.children) + if (IsMounted(i.second, storage_uri)) + return true; + + return false; + } + /** * Follow the given URI path, and find the outermost directory * which is a #Storage mount point. If there are no mounts, diff --git a/src/storage/StorageState.cxx b/src/storage/StorageState.cxx index 8d4445dc8..9d2f0d10b 100644 --- a/src/storage/StorageState.cxx +++ b/src/storage/StorageState.cxx @@ -106,6 +106,17 @@ 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; + } + + if (composite_storage.IsMounted(url.c_str())) { + LogError(storage_domain, "This storage is already mounted"); + return true; + } + auto &event_loop = instance.io_thread.GetEventLoop(); auto storage = CreateStorageURI(event_loop, url.c_str()); if (storage == nullptr) { @@ -124,8 +135,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; } |