diff --git a/src/storage/CompositeStorage.cxx b/src/storage/CompositeStorage.cxx index d7f87c54c..88ccd1bc7 100644 --- a/src/storage/CompositeStorage.cxx +++ b/src/storage/CompositeStorage.cxx @@ -4,6 +4,7 @@ #include "CompositeStorage.hxx" #include "FileInfo.hxx" #include "fs/AllocatedPath.hxx" +#include "input/InputStream.hxx" #include "util/IterableSplitString.hxx" #include "util/StringCompare.hxx" #include "util/StringSplit.hxx" @@ -320,3 +321,15 @@ CompositeStorage::MapToRelativeUTF8(std::string_view uri) const noexcept return relative_buffer; } + +InputStreamPtr +CompositeStorage::OpenFile(std::string_view uri_utf8, Mutex &_mutex) +{ + const std::lock_guard lock(mutex); + + auto f = FindStorage(uri_utf8); + if (f.directory->storage == nullptr) + return nullptr; + + return f.directory->storage->OpenFile(f.uri, _mutex); +} diff --git a/src/storage/CompositeStorage.hxx b/src/storage/CompositeStorage.hxx index add23c155..623e50417 100644 --- a/src/storage/CompositeStorage.hxx +++ b/src/storage/CompositeStorage.hxx @@ -127,6 +127,8 @@ public: std::string_view MapToRelativeUTF8(std::string_view uri) const noexcept override; + InputStreamPtr OpenFile(std::string_view uri_utf8, Mutex &mutex) override; + private: template void VisitMounts(std::string &uri, const Directory &directory, diff --git a/src/storage/StorageInterface.hxx b/src/storage/StorageInterface.hxx index be7a96eaf..772e8c3c7 100644 --- a/src/storage/StorageInterface.hxx +++ b/src/storage/StorageInterface.hxx @@ -3,6 +3,9 @@ #pragma once +#include "input/Ptr.hxx" +#include "thread/Mutex.hxx" + #include #include #include @@ -69,4 +72,12 @@ public: */ [[nodiscard]] [[gnu::pure]] virtual std::string_view MapToRelativeUTF8(std::string_view uri_utf8) const noexcept = 0; + + /** + * Open a file in this storage as an #InputStream. + * + * Throws on error + */ + [[nodiscard]] + virtual InputStreamPtr OpenFile(std::string_view uri_utf8, Mutex &mutex) = 0; }; diff --git a/src/storage/plugins/CurlStorage.cxx b/src/storage/plugins/CurlStorage.cxx index 585396c8c..bac92b513 100644 --- a/src/storage/plugins/CurlStorage.cxx +++ b/src/storage/plugins/CurlStorage.cxx @@ -6,6 +6,9 @@ #include "storage/StorageInterface.hxx" #include "storage/FileInfo.hxx" #include "storage/MemoryDirectoryReader.hxx" +#include "input/InputStream.hxx" +#include "input/RewindInputStream.hxx" +#include "input/plugins/CurlInputPlugin.hxx" #include "lib/curl/HttpStatusError.hxx" #include "lib/curl/Init.hxx" #include "lib/curl/Global.hxx" @@ -52,6 +55,8 @@ public: [[nodiscard]] std::string MapUTF8(std::string_view uri_utf8) const noexcept override; [[nodiscard]] std::string_view MapToRelativeUTF8(std::string_view uri_utf8) const noexcept override; + + InputStreamPtr OpenFile(std::string_view uri_utf8, Mutex &mutex) override; }; std::string @@ -71,6 +76,12 @@ CurlStorage::MapToRelativeUTF8(std::string_view uri_utf8) const noexcept CurlUnescape(uri_utf8)); } +InputStreamPtr +CurlStorage::OpenFile(std::string_view uri_utf8, Mutex &mutex) +{ + return input_rewind_open(OpenCurlInputStream(MapUTF8(uri_utf8), {}, mutex)); +} + class BlockingHttpRequest : protected CurlResponseHandler { InjectEvent defer_start; diff --git a/src/storage/plugins/LocalStorage.cxx b/src/storage/plugins/LocalStorage.cxx index 8163635c3..7d0ae621e 100644 --- a/src/storage/plugins/LocalStorage.cxx +++ b/src/storage/plugins/LocalStorage.cxx @@ -5,6 +5,8 @@ #include "storage/StoragePlugin.hxx" #include "storage/StorageInterface.hxx" #include "storage/FileInfo.hxx" +#include "input/InputStream.hxx" +#include "input/LocalOpen.hxx" #include "fs/FileInfo.hxx" #include "fs/AllocatedPath.hxx" #include "fs/DirectoryReader.hxx" @@ -50,6 +52,8 @@ public: [[nodiscard]] std::string_view MapToRelativeUTF8(std::string_view uri_utf8) const noexcept override; + InputStreamPtr OpenFile(std::string_view uri_utf8, Mutex &mutex) override; + private: [[nodiscard]] AllocatedPath MapFSOrThrow(std::string_view uri_utf8) const; }; @@ -112,6 +116,16 @@ LocalStorage::MapToRelativeUTF8(std::string_view uri_utf8) const noexcept return PathTraitsUTF8::Relative(base_utf8, uri_utf8); } +InputStreamPtr +LocalStorage::OpenFile(std::string_view uri_utf8, Mutex &mutex) +{ + auto path = MapFS(uri_utf8); + if (path == nullptr) + return nullptr; + + return OpenLocalInputStream(path, mutex); +} + StorageFileInfo LocalStorage::GetInfo(std::string_view uri_utf8, bool follow) { diff --git a/src/storage/plugins/NfsStorage.cxx b/src/storage/plugins/NfsStorage.cxx index cf228200b..f9900548e 100644 --- a/src/storage/plugins/NfsStorage.cxx +++ b/src/storage/plugins/NfsStorage.cxx @@ -11,6 +11,7 @@ #include "lib/nfs/Lease.hxx" #include "lib/nfs/Connection.hxx" #include "lib/nfs/Glue.hxx" +#include "input/InputStream.hxx" #include "fs/AllocatedPath.hxx" #include "thread/Mutex.hxx" #include "thread/Cond.hxx" @@ -94,6 +95,8 @@ public: [[nodiscard]] std::string_view MapToRelativeUTF8(std::string_view uri_utf8) const noexcept override; + InputStreamPtr OpenFile(std::string_view uri_utf8, Mutex &mutex) override; + /* virtual methods from NfsLease */ void OnNfsConnectionReady() noexcept final { assert(state == State::CONNECTING); @@ -246,6 +249,14 @@ NfsStorage::MapToRelativeUTF8(std::string_view uri_utf8) const noexcept return PathTraitsUTF8::Relative(base, uri_utf8); } +InputStreamPtr +NfsStorage::OpenFile(std::string_view uri_utf8, Mutex &_mutex) +{ + // TODO create NfsInputStream directly + auto uri = MapUTF8(uri_utf8); + return InputStream::Open(uri.c_str(), _mutex); +} + static void Copy(StorageFileInfo &info, const struct nfs_stat_64 &st) noexcept { diff --git a/src/storage/plugins/SmbclientStorage.cxx b/src/storage/plugins/SmbclientStorage.cxx index 89945601d..31b3b0bb0 100644 --- a/src/storage/plugins/SmbclientStorage.cxx +++ b/src/storage/plugins/SmbclientStorage.cxx @@ -5,6 +5,7 @@ #include "storage/StoragePlugin.hxx" #include "storage/StorageInterface.hxx" #include "storage/FileInfo.hxx" +#include "input/InputStream.hxx" #include "lib/smbclient/Init.hxx" #include "lib/smbclient/Context.hxx" #include "fs/Traits.hxx" @@ -63,6 +64,8 @@ public: [[nodiscard]] std::string MapUTF8(std::string_view uri_utf8) const noexcept override; [[nodiscard]] std::string_view MapToRelativeUTF8(std::string_view uri_utf8) const noexcept override; + + InputStreamPtr OpenFile(std::string_view uri_utf8, Mutex &file_mutex) override; }; std::string @@ -113,6 +116,13 @@ SmbclientStorage::GetInfo(std::string_view uri_utf8, [[maybe_unused]] bool follo return ::GetInfo(ctx, mutex, mapped.c_str()); } +InputStreamPtr +SmbclientStorage::OpenFile(std::string_view uri_utf8, Mutex &file_mutex) +{ + auto uri = MapUTF8(uri_utf8); + return InputStream::Open(uri.c_str(), file_mutex); +} + std::unique_ptr SmbclientStorage::OpenDirectory(std::string_view uri_utf8) { diff --git a/src/storage/plugins/UdisksStorage.cxx b/src/storage/plugins/UdisksStorage.cxx index df2d4dadd..d7c4013f5 100644 --- a/src/storage/plugins/UdisksStorage.cxx +++ b/src/storage/plugins/UdisksStorage.cxx @@ -6,6 +6,8 @@ #include "storage/StoragePlugin.hxx" #include "storage/StorageInterface.hxx" #include "storage/FileInfo.hxx" +#include "input/InputStream.hxx" +#include "input/LocalOpen.hxx" #include "lib/fmt/ExceptionFormatter.hxx" #include "lib/fmt/RuntimeError.hxx" #include "lib/dbus/Glue.hxx" @@ -113,6 +115,12 @@ public: std::string_view MapToRelativeUTF8(std::string_view uri_utf8) const noexcept override; + InputStreamPtr OpenFile(std::string_view uri_utf8, Mutex &file_mutex) override { + MountWait(); + const auto path = mounted_storage->MapFS(uri_utf8); + return OpenLocalInputStream(path, file_mutex); + } + private: void SetMountPoint(Path mount_point); void LockSetMountPoint(Path mount_point); diff --git a/src/storage/plugins/meson.build b/src/storage/plugins/meson.build index f17c414b1..e4caf0705 100644 --- a/src/storage/plugins/meson.build +++ b/src/storage/plugins/meson.build @@ -50,6 +50,8 @@ storage_plugins = static_library( expat_dep, nfs_dep, smbclient_dep, + input_glue_dep, + archive_glue_dep, ], ) diff --git a/test/meson.build b/test/meson.build index b90d4fa7d..bacd44633 100644 --- a/test/meson.build +++ b/test/meson.build @@ -214,6 +214,7 @@ if enable_database executable( 'run_storage', 'run_storage.cxx', + '../src/TagSave.cxx', include_directories: inc, dependencies: [ event_dep, diff --git a/test/run_storage.cxx b/test/run_storage.cxx index 62c35438f..09dbe48aa 100644 --- a/test/run_storage.cxx +++ b/test/run_storage.cxx @@ -4,10 +4,21 @@ #include "cmdline/OptionDef.hxx" #include "cmdline/OptionParser.hxx" #include "event/Thread.hxx" +#include "ConfigGlue.hxx" +#include "tag/Tag.hxx" #include "storage/Registry.hxx" #include "storage/StorageInterface.hxx" #include "storage/FileInfo.hxx" +#include "input/Init.hxx" +#include "input/InputStream.hxx" +#include "input/CondHandler.hxx" +#include "fs/Path.hxx" +#include "fs/NarrowPath.hxx" +#include "event/Thread.hxx" #include "net/Init.hxx" +#include "io/BufferedOutputStream.hxx" +#include "io/FileDescriptor.hxx" +#include "io/StdioOutputStream.hxx" #include "time/ChronoUtil.hxx" #include "time/ISO8601.hxx" #include "util/PrintException.hxx" @@ -15,6 +26,12 @@ #include "util/StringBuffer.hxx" #include "Log.hxx" #include "LogBackend.hxx" +#include "TagSave.hxx" +#include "config.h" + +#ifdef ENABLE_ARCHIVE +#include "archive/ArchiveList.hxx" +#endif #include #include @@ -32,9 +49,12 @@ Options: Available commands: ls URI PATH stat URI PATH + cat URI PATH )"; struct CommandLine { + FromNarrowPath config_path; + bool verbose = false; const char *command; @@ -43,10 +63,12 @@ struct CommandLine { }; enum class Option { + CONFIG, VERBOSE, }; static constexpr OptionDef option_defs[] = { + {"config", 0, true, "Load a MPD configuration file"}, {"verbose", 'v', false, "Verbose logging"}, }; @@ -58,6 +80,10 @@ ParseCommandLine(int argc, char **argv) OptionParser option_parser(option_defs, argc, argv); while (auto o = option_parser.Next()) { switch (static_cast