storage: migrate from class Error to C++ exceptions

This commit is contained in:
Max Kellermann 2016-10-27 08:40:40 +02:00
parent cab87e9398
commit c598686bd9
19 changed files with 208 additions and 281 deletions

View File

@ -161,19 +161,16 @@ glue_mapper_init(Error &error)
#ifdef ENABLE_DATABASE #ifdef ENABLE_DATABASE
static bool static void
InitStorage(Error &error) InitStorage()
{ {
Storage *storage = CreateConfiguredStorage(io_thread_get(), error); Storage *storage = CreateConfiguredStorage(io_thread_get());
if (storage == nullptr) if (storage == nullptr)
return !error.IsDefined(); return;
assert(!error.IsDefined());
CompositeStorage *composite = new CompositeStorage(); CompositeStorage *composite = new CompositeStorage();
instance->storage = composite; instance->storage = composite;
composite->Mount("", storage); composite->Mount("", storage);
return true;
} }
/** /**
@ -196,8 +193,7 @@ glue_db_init_and_load(void)
} }
if (instance->database->GetPlugin().flags & DatabasePlugin::FLAG_REQUIRE_STORAGE) { if (instance->database->GetPlugin().flags & DatabasePlugin::FLAG_REQUIRE_STORAGE) {
if (!InitStorage(error)) InitStorage();
FatalError(error);
if (instance->storage == nullptr) { if (instance->storage == nullptr) {
delete instance->database; delete instance->database;

View File

@ -68,9 +68,7 @@ Song::UpdateFile(Storage &storage)
StorageFileInfo info; StorageFileInfo info;
try { try {
if (!storage.GetInfo(relative_uri.c_str(), true, info, info = storage.GetInfo(relative_uri.c_str(), true);
IgnoreError()))
return false;
} catch (const std::runtime_error &) { } catch (const std::runtime_error &) {
return false; return false;
} }

View File

@ -58,9 +58,8 @@ skip_path(const char *name_utf8)
#pragma GCC diagnostic ignored "-Wformat-extra-args" #pragma GCC diagnostic ignored "-Wformat-extra-args"
#endif #endif
static bool static void
handle_listfiles_storage(Response &r, StorageDirectoryReader &reader, handle_listfiles_storage(Response &r, StorageDirectoryReader &reader)
Error &error)
{ {
const char *name_utf8; const char *name_utf8;
while ((name_utf8 = reader.Read()) != nullptr) { while ((name_utf8 = reader.Read()) != nullptr) {
@ -68,8 +67,11 @@ handle_listfiles_storage(Response &r, StorageDirectoryReader &reader,
continue; continue;
StorageFileInfo info; StorageFileInfo info;
if (!reader.GetInfo(false, info, error)) try {
info = reader.GetInfo(false);
} catch (const std::runtime_error &) {
continue; continue;
}
switch (info.type) { switch (info.type) {
case StorageFileInfo::Type::OTHER: case StorageFileInfo::Type::OTHER:
@ -91,53 +93,30 @@ handle_listfiles_storage(Response &r, StorageDirectoryReader &reader,
if (info.mtime != 0) if (info.mtime != 0)
time_print(r, "Last-Modified", info.mtime); time_print(r, "Last-Modified", info.mtime);
} }
return true;
} }
#if defined(WIN32) && GCC_CHECK_VERSION(4,6) #if defined(WIN32) && GCC_CHECK_VERSION(4,6)
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#endif #endif
static bool
handle_listfiles_storage(Response &r, Storage &storage, const char *uri,
Error &error)
{
std::unique_ptr<StorageDirectoryReader> reader(storage.OpenDirectory(uri, error));
if (reader == nullptr)
return false;
return handle_listfiles_storage(r, *reader, error);
}
CommandResult CommandResult
handle_listfiles_storage(Response &r, Storage &storage, const char *uri) handle_listfiles_storage(Response &r, Storage &storage, const char *uri)
{ {
Error error; std::unique_ptr<StorageDirectoryReader> reader(storage.OpenDirectory(uri));
if (!handle_listfiles_storage(r, storage, uri, error)) handle_listfiles_storage(r, *reader);
return print_error(r, error);
return CommandResult::OK; return CommandResult::OK;
} }
CommandResult CommandResult
handle_listfiles_storage(Response &r, const char *uri) handle_listfiles_storage(Response &r, const char *uri)
{ {
Error error; std::unique_ptr<Storage> storage(CreateStorageURI(io_thread_get(), uri));
std::unique_ptr<Storage> storage(CreateStorageURI(io_thread_get(), uri,
error));
if (storage == nullptr) { if (storage == nullptr) {
if (error.IsDefined())
return print_error(r, error);
r.Error(ACK_ERROR_ARG, "Unrecognized storage URI"); r.Error(ACK_ERROR_ARG, "Unrecognized storage URI");
return CommandResult::ERROR; return CommandResult::ERROR;
} }
if (!handle_listfiles_storage(r, *storage, "", error)) return handle_listfiles_storage(r, *storage, "");
return print_error(r, error);
return CommandResult::OK;
} }
static void static void
@ -217,13 +196,8 @@ handle_mount(Client &client, Request args, Response &r)
return CommandResult::ERROR; return CommandResult::ERROR;
} }
Error error; Storage *storage = CreateStorageURI(io_thread_get(), remote_uri);
Storage *storage = CreateStorageURI(io_thread_get(), remote_uri,
error);
if (storage == nullptr) { if (storage == nullptr) {
if (error.IsDefined())
return print_error(r, error);
r.Error(ACK_ERROR_ARG, "Unrecognized storage URI"); r.Error(ACK_ERROR_ARG, "Unrecognized storage URI");
return CommandResult::ERROR; return CommandResult::ERROR;
} }
@ -237,6 +211,7 @@ handle_mount(Client &client, Request args, Response &r)
SimpleDatabase &db = *(SimpleDatabase *)_db; SimpleDatabase &db = *(SimpleDatabase *)_db;
try { try {
Error error;
if (!db.Mount(local_uri, remote_uri, error)) { if (!db.Mount(local_uri, remote_uri, error)) {
composite.Unmount(local_uri); composite.Unmount(local_uri);
return print_error(r, error); return print_error(r, error);

View File

@ -35,11 +35,8 @@
bool bool
GetInfo(Storage &storage, const char *uri_utf8, StorageFileInfo &info) GetInfo(Storage &storage, const char *uri_utf8, StorageFileInfo &info)
try { try {
Error error; info = storage.GetInfo(uri_utf8, true);
bool success = storage.GetInfo(uri_utf8, true, info, error); return true;
if (!success)
LogError(error);
return success;
} catch (const std::runtime_error &e) { } catch (const std::runtime_error &e) {
LogError(e); LogError(e);
return false; return false;
@ -48,11 +45,8 @@ try {
bool bool
GetInfo(StorageDirectoryReader &reader, StorageFileInfo &info) GetInfo(StorageDirectoryReader &reader, StorageFileInfo &info)
try { try {
Error error; info = reader.GetInfo(true);
bool success = reader.GetInfo(true, info, error); return true;
if (!success)
LogError(error);
return success;
} catch (const std::runtime_error &e) { } catch (const std::runtime_error &e) {
LogError(e); LogError(e);
return false; return false;
@ -64,8 +58,7 @@ DirectoryExists(Storage &storage, const Directory &directory)
StorageFileInfo info; StorageFileInfo info;
try { try {
if (!storage.GetInfo(directory.GetPath(), true, info, IgnoreError())) info = storage.GetInfo(directory.GetPath(), true);
return false;
} catch (const std::runtime_error &) { } catch (const std::runtime_error &) {
return false; return false;
} }
@ -76,24 +69,22 @@ DirectoryExists(Storage &storage, const Directory &directory)
: info.IsDirectory(); : info.IsDirectory();
} }
static bool static StorageFileInfo
GetDirectoryChildInfo(Storage &storage, const Directory &directory, GetDirectoryChildInfo(Storage &storage, const Directory &directory,
const char *name_utf8, StorageFileInfo &info, Error &error) const char *name_utf8)
{ {
const auto uri_utf8 = PathTraitsUTF8::Build(directory.GetPath(), const auto uri_utf8 = PathTraitsUTF8::Build(directory.GetPath(),
name_utf8); name_utf8);
return storage.GetInfo(uri_utf8.c_str(), true, info, error); return storage.GetInfo(uri_utf8.c_str(), true);
} }
bool bool
directory_child_is_regular(Storage &storage, const Directory &directory, directory_child_is_regular(Storage &storage, const Directory &directory,
const char *name_utf8) const char *name_utf8)
try { try {
StorageFileInfo info; return GetDirectoryChildInfo(storage, directory, name_utf8)
return GetDirectoryChildInfo(storage, directory, name_utf8, info, .IsRegular();
IgnoreError()) && } catch (const std::runtime_error &) {
info.IsRegular();
} catch (const std::runtime_error &) {
return false; return false;
} }

View File

@ -338,12 +338,7 @@ UpdateWalk::UpdateDirectory(Directory &directory,
std::unique_ptr<StorageDirectoryReader> reader; std::unique_ptr<StorageDirectoryReader> reader;
try { try {
Error error; reader.reset(storage.OpenDirectory(directory.GetPath()));
reader.reset(storage.OpenDirectory(directory.GetPath(), error));
if (!reader) {
LogError(error);
return false;
}
} catch (const std::runtime_error &e) { } catch (const std::runtime_error &e) {
LogError(e); LogError(e);
return false; return false;

View File

@ -21,16 +21,13 @@
#include "CompositeStorage.hxx" #include "CompositeStorage.hxx"
#include "FileInfo.hxx" #include "FileInfo.hxx"
#include "fs/AllocatedPath.hxx" #include "fs/AllocatedPath.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
#include "util/StringCompare.hxx" #include "util/StringCompare.hxx"
#include <set> #include <set>
#include <stdexcept>
#include <string.h> #include <string.h>
static constexpr Domain composite_domain("composite");
/** /**
* Combines the directory entries of another #StorageDirectoryReader * Combines the directory entries of another #StorageDirectoryReader
* instance and the virtual directory entries. * instance and the virtual directory entries.
@ -57,7 +54,7 @@ public:
/* virtual methods from class StorageDirectoryReader */ /* virtual methods from class StorageDirectoryReader */
const char *Read() override; const char *Read() override;
bool GetInfo(bool follow, StorageFileInfo &info, Error &error) override; StorageFileInfo GetInfo(bool follow) override;
}; };
const char * const char *
@ -81,20 +78,20 @@ CompositeDirectoryReader::Read()
return current->c_str(); return current->c_str();
} }
bool StorageFileInfo
CompositeDirectoryReader::GetInfo(bool follow, StorageFileInfo &info, CompositeDirectoryReader::GetInfo(bool follow)
Error &error)
{ {
if (other != nullptr) if (other != nullptr)
return other->GetInfo(follow, info, error); return other->GetInfo(follow);
assert(current != names.end()); assert(current != names.end());
StorageFileInfo info;
info.type = StorageFileInfo::Type::DIRECTORY; info.type = StorageFileInfo::Type::DIRECTORY;
info.mtime = 0; info.mtime = 0;
info.device = 0; info.device = 0;
info.inode = 0; info.inode = 0;
return true; return info;
} }
static std::string static std::string
@ -266,35 +263,40 @@ CompositeStorage::FindStorage(const char *uri) const
return result; return result;
} }
bool StorageFileInfo
CompositeStorage::GetInfo(const char *uri, bool follow, StorageFileInfo &info, CompositeStorage::GetInfo(const char *uri, bool follow)
Error &error)
{ {
const ScopeLock protect(mutex); const ScopeLock protect(mutex);
std::exception_ptr error;
auto f = FindStorage(uri); auto f = FindStorage(uri);
if (f.directory->storage != nullptr && if (f.directory->storage != nullptr) {
f.directory->storage->GetInfo(f.uri, follow, info, error)) try {
return true; return f.directory->storage->GetInfo(f.uri, follow);
} catch (...) {
error = std::current_exception();
}
}
const Directory *directory = f.directory->Find(f.uri); const Directory *directory = f.directory->Find(f.uri);
if (directory != nullptr) { if (directory != nullptr) {
error.Clear(); StorageFileInfo info;
info.type = StorageFileInfo::Type::DIRECTORY; info.type = StorageFileInfo::Type::DIRECTORY;
info.mtime = 0; info.mtime = 0;
info.device = 0; info.device = 0;
info.inode = 0; info.inode = 0;
return true; return info;
} }
if (!error.IsDefined()) if (error)
error.Set(composite_domain, "No such directory"); std::rethrow_exception(error);
return false; else
throw std::runtime_error("No such file or directory");
} }
StorageDirectoryReader * StorageDirectoryReader *
CompositeStorage::OpenDirectory(const char *uri, CompositeStorage::OpenDirectory(const char *uri)
Error &error)
{ {
const ScopeLock protect(mutex); const ScopeLock protect(mutex);
@ -303,16 +305,19 @@ CompositeStorage::OpenDirectory(const char *uri,
if (directory == nullptr || directory->children.empty()) { if (directory == nullptr || directory->children.empty()) {
/* no virtual directories here */ /* no virtual directories here */
if (f.directory->storage == nullptr) { if (f.directory->storage == nullptr)
error.Set(composite_domain, "No such directory"); throw std::runtime_error("No such directory");
return nullptr;
}
return f.directory->storage->OpenDirectory(f.uri, error); return f.directory->storage->OpenDirectory(f.uri);
}
StorageDirectoryReader *other = nullptr;
try {
other = f.directory->storage->OpenDirectory(f.uri);
} catch (const std::runtime_error &) {
} }
StorageDirectoryReader *other =
f.directory->storage->OpenDirectory(f.uri, IgnoreError());
return new CompositeDirectoryReader(other, directory->children); return new CompositeDirectoryReader(other, directory->children);
} }

View File

@ -28,8 +28,6 @@
#include <string> #include <string>
#include <map> #include <map>
class Error;
/** /**
* A #Storage implementation that combines multiple other #Storage * A #Storage implementation that combines multiple other #Storage
* instances in one virtual tree. It is used to "mount" new #Storage * instances in one virtual tree. It is used to "mount" new #Storage
@ -121,11 +119,9 @@ public:
bool Unmount(const char *uri); bool Unmount(const char *uri);
/* virtual methods from class Storage */ /* virtual methods from class Storage */
bool GetInfo(const char *uri, bool follow, StorageFileInfo &info, StorageFileInfo GetInfo(const char *uri, bool follow) override;
Error &error) override;
StorageDirectoryReader *OpenDirectory(const char *uri, StorageDirectoryReader *OpenDirectory(const char *uri) override;
Error &error) override;
std::string MapUTF8(const char *uri) const override; std::string MapUTF8(const char *uri) const override;

View File

@ -27,34 +27,39 @@
#include "fs/CheckFile.hxx" #include "fs/CheckFile.hxx"
#include "util/UriUtil.hxx" #include "util/UriUtil.hxx"
#include "util/Error.hxx" #include "util/Error.hxx"
#include "util/RuntimeError.hxx"
#include <assert.h> #include <assert.h>
static Storage * static Storage *
CreateConfiguredStorageUri(EventLoop &event_loop, const char *uri, CreateConfiguredStorageUri(EventLoop &event_loop, const char *uri)
Error &error)
{ {
Storage *storage = CreateStorageURI(event_loop, uri, error); Storage *storage = CreateStorageURI(event_loop, uri);
if (storage == nullptr && !error.IsDefined()) if (storage == nullptr)
error.Format(config_domain, throw FormatRuntimeError("Unrecognized storage URI: %s", uri);
"Unrecognized storage URI: %s", uri);
return storage; return storage;
} }
static AllocatedPath static AllocatedPath
GetConfiguredMusicDirectory(Error &error) GetConfiguredMusicDirectory()
{ {
Error error;
AllocatedPath path = config_get_path(ConfigOption::MUSIC_DIR, error); AllocatedPath path = config_get_path(ConfigOption::MUSIC_DIR, error);
if (path.IsNull() && !error.IsDefined()) if (path.IsNull()) {
if (error.IsDefined())
throw std::runtime_error(error.GetMessage());
path = GetUserMusicDir(); path = GetUserMusicDir();
}
return path; return path;
} }
static Storage * static Storage *
CreateConfiguredStorageLocal(Error &error) CreateConfiguredStorageLocal()
{ {
AllocatedPath path = GetConfiguredMusicDirectory(error); AllocatedPath path = GetConfiguredMusicDirectory();
if (path.IsNull()) if (path.IsNull())
return nullptr; return nullptr;
@ -64,15 +69,13 @@ CreateConfiguredStorageLocal(Error &error)
} }
Storage * Storage *
CreateConfiguredStorage(EventLoop &event_loop, Error &error) CreateConfiguredStorage(EventLoop &event_loop)
{ {
assert(!error.IsDefined());
auto uri = config_get_string(ConfigOption::MUSIC_DIR); auto uri = config_get_string(ConfigOption::MUSIC_DIR);
if (uri != nullptr && uri_has_scheme(uri)) if (uri != nullptr && uri_has_scheme(uri))
return CreateConfiguredStorageUri(event_loop, uri, error); return CreateConfiguredStorageUri(event_loop, uri);
return CreateConfiguredStorageLocal(error); return CreateConfiguredStorageLocal();
} }
bool bool

View File

@ -23,17 +23,17 @@
#include "check.h" #include "check.h"
#include "Compiler.h" #include "Compiler.h"
class Error;
class Storage; class Storage;
class EventLoop; class EventLoop;
/** /**
* Read storage configuration settings and create a #Storage instance * Read storage configuration settings and create a #Storage instance
* from it. Returns nullptr on error or if no storage is configured * from it. Returns nullptr if no storage is configured.
* (no #Error set in that case). *
* Throws #std::runtime_error on error.
*/ */
Storage * Storage *
CreateConfiguredStorage(EventLoop &event_loop, Error &error); CreateConfiguredStorage(EventLoop &event_loop);
/** /**
* Returns true if there is configuration for a #Storage instance. * Returns true if there is configuration for a #Storage instance.

View File

@ -36,14 +36,11 @@ MemoryStorageDirectoryReader::Read()
return entries.front().name.c_str(); return entries.front().name.c_str();
} }
bool StorageFileInfo
MemoryStorageDirectoryReader::GetInfo(gcc_unused bool follow, MemoryStorageDirectoryReader::GetInfo(gcc_unused bool follow)
StorageFileInfo &info,
gcc_unused Error &error)
{ {
assert(!first); assert(!first);
assert(!entries.empty()); assert(!entries.empty());
info = entries.front().info; return entries.front().info;
return true;
} }

View File

@ -61,8 +61,7 @@ public:
/* virtual methods from class StorageDirectoryReader */ /* virtual methods from class StorageDirectoryReader */
const char *Read() override; const char *Read() override;
bool GetInfo(bool follow, StorageFileInfo &info, StorageFileInfo GetInfo(bool follow) override;
Error &error) override;
}; };
#endif #endif

View File

@ -23,7 +23,6 @@
#include "plugins/LocalStorage.hxx" #include "plugins/LocalStorage.hxx"
#include "plugins/SmbclientStorage.hxx" #include "plugins/SmbclientStorage.hxx"
#include "plugins/NfsStorage.hxx" #include "plugins/NfsStorage.hxx"
#include "util/Error.hxx"
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
@ -52,18 +51,16 @@ GetStoragePluginByName(const char *name)
} }
Storage * Storage *
CreateStorageURI(EventLoop &event_loop, const char *uri, Error &error) CreateStorageURI(EventLoop &event_loop, const char *uri)
{ {
assert(!error.IsDefined());
for (auto i = storage_plugins; *i != nullptr; ++i) { for (auto i = storage_plugins; *i != nullptr; ++i) {
const StoragePlugin &plugin = **i; const StoragePlugin &plugin = **i;
if (plugin.create_uri == nullptr) if (plugin.create_uri == nullptr)
continue; continue;
Storage *storage = plugin.create_uri(event_loop, uri, error); Storage *storage = plugin.create_uri(event_loop, uri);
if (storage != nullptr || error.IsDefined()) if (storage != nullptr)
return storage; return storage;
} }

View File

@ -25,7 +25,6 @@
struct StoragePlugin; struct StoragePlugin;
class Storage; class Storage;
class Error;
class EventLoop; class EventLoop;
/** /**
@ -40,6 +39,6 @@ GetStoragePluginByName(const char *name);
gcc_nonnull_all gcc_malloc gcc_nonnull_all gcc_malloc
Storage * Storage *
CreateStorageURI(EventLoop &event_loop, const char *uri, Error &error); CreateStorageURI(EventLoop &event_loop, const char *uri);
#endif #endif

View File

@ -27,7 +27,6 @@
struct StorageFileInfo; struct StorageFileInfo;
class AllocatedPath; class AllocatedPath;
class Error;
class StorageDirectoryReader { class StorageDirectoryReader {
public: public:
@ -36,8 +35,12 @@ public:
virtual ~StorageDirectoryReader() {} virtual ~StorageDirectoryReader() {}
virtual const char *Read() = 0; virtual const char *Read() = 0;
virtual bool GetInfo(bool follow, StorageFileInfo &info,
Error &error) = 0; /**
* Throws #std::runtime_error on error.
*/
gcc_pure
virtual StorageFileInfo GetInfo(bool follow) = 0;
}; };
class Storage { class Storage {
@ -46,12 +49,16 @@ public:
Storage(const Storage &) = delete; Storage(const Storage &) = delete;
virtual ~Storage() {} virtual ~Storage() {}
virtual bool GetInfo(const char *uri_utf8, bool follow, /**
StorageFileInfo &info, * Throws #std::runtime_error on error.
Error &error) = 0; */
gcc_pure
virtual StorageFileInfo GetInfo(const char *uri_utf8, bool follow) = 0;
virtual StorageDirectoryReader *OpenDirectory(const char *uri_utf8, /**
Error &error) = 0; * Throws #std::runtime_error on error.
*/
virtual StorageDirectoryReader *OpenDirectory(const char *uri_utf8) = 0;
/** /**
* Map the given relative URI to an absolute URI. * Map the given relative URI to an absolute URI.

View File

@ -22,15 +22,16 @@
#include "check.h" #include "check.h"
class Error;
class Storage; class Storage;
class EventLoop; class EventLoop;
struct StoragePlugin { struct StoragePlugin {
const char *name; const char *name;
Storage *(*create_uri)(EventLoop &event_loop, const char *uri, /**
Error &error); * Throws #std::runtime_error on error.
*/
Storage *(*create_uri)(EventLoop &event_loop, const char *uri);
}; };
#endif #endif

View File

@ -25,7 +25,6 @@
#include "fs/FileInfo.hxx" #include "fs/FileInfo.hxx"
#include "fs/AllocatedPath.hxx" #include "fs/AllocatedPath.hxx"
#include "fs/DirectoryReader.hxx" #include "fs/DirectoryReader.hxx"
#include "util/Error.hxx"
#include "util/StringCompare.hxx" #include "util/StringCompare.hxx"
#include <string> #include <string>
@ -43,8 +42,7 @@ public:
/* virtual methods from class StorageDirectoryReader */ /* virtual methods from class StorageDirectoryReader */
const char *Read() override; const char *Read() override;
bool GetInfo(bool follow, StorageFileInfo &info, StorageFileInfo GetInfo(bool follow) override;
Error &error) override;
}; };
class LocalStorage final : public Storage { class LocalStorage final : public Storage {
@ -59,11 +57,9 @@ public:
} }
/* virtual methods from class Storage */ /* virtual methods from class Storage */
bool GetInfo(const char *uri_utf8, bool follow, StorageFileInfo &info, StorageFileInfo GetInfo(const char *uri_utf8, bool follow) override;
Error &error) override;
StorageDirectoryReader *OpenDirectory(const char *uri_utf8, StorageDirectoryReader *OpenDirectory(const char *uri_utf8) override;
Error &error) override;
std::string MapUTF8(const char *uri_utf8) const override; std::string MapUTF8(const char *uri_utf8) const override;
@ -72,15 +68,15 @@ public:
const char *MapToRelativeUTF8(const char *uri_utf8) const override; const char *MapToRelativeUTF8(const char *uri_utf8) const override;
private: private:
AllocatedPath MapFS(const char *uri_utf8, Error &error) const; AllocatedPath MapFSOrThrow(const char *uri_utf8) const;
}; };
static bool gcc_pure
Stat(Path path, bool follow, StorageFileInfo &info, Error &error) static StorageFileInfo
Stat(Path path, bool follow)
{ {
FileInfo src; const FileInfo src(path, follow);
if (!GetFileInfo(path, src, follow, error)) StorageFileInfo info;
return false;
if (src.IsRegular()) if (src.IsRegular())
info.type = StorageFileInfo::Type::REGULAR; info.type = StorageFileInfo::Type::REGULAR;
@ -97,7 +93,7 @@ Stat(Path path, bool follow, StorageFileInfo &info, Error &error)
info.device = src.GetDevice(); info.device = src.GetDevice();
info.inode = src.GetInode(); info.inode = src.GetInode();
#endif #endif
return true; return info;
} }
std::string std::string
@ -112,24 +108,25 @@ LocalStorage::MapUTF8(const char *uri_utf8) const
} }
AllocatedPath AllocatedPath
LocalStorage::MapFS(const char *uri_utf8, Error &error) const LocalStorage::MapFSOrThrow(const char *uri_utf8) const
{ {
assert(uri_utf8 != nullptr); assert(uri_utf8 != nullptr);
if (StringIsEmpty(uri_utf8)) if (StringIsEmpty(uri_utf8))
return base_fs; return base_fs;
AllocatedPath path_fs = AllocatedPath::FromUTF8(uri_utf8, error); return AllocatedPath::Build(base_fs,
if (!path_fs.IsNull()) AllocatedPath::FromUTF8Throw(uri_utf8));
path_fs = AllocatedPath::Build(base_fs, path_fs);
return path_fs;
} }
AllocatedPath AllocatedPath
LocalStorage::MapFS(const char *uri_utf8) const LocalStorage::MapFS(const char *uri_utf8) const
{ {
return MapFS(uri_utf8, IgnoreError()); try {
return MapFSOrThrow(uri_utf8);
} catch (const std::runtime_error &) {
return AllocatedPath::Null();
}
} }
const char * const char *
@ -138,25 +135,16 @@ LocalStorage::MapToRelativeUTF8(const char *uri_utf8) const
return PathTraitsUTF8::Relative(base_utf8.c_str(), uri_utf8); return PathTraitsUTF8::Relative(base_utf8.c_str(), uri_utf8);
} }
bool StorageFileInfo
LocalStorage::GetInfo(const char *uri_utf8, bool follow, StorageFileInfo &info, LocalStorage::GetInfo(const char *uri_utf8, bool follow)
Error &error)
{ {
AllocatedPath path_fs = MapFS(uri_utf8, error); return Stat(MapFSOrThrow(uri_utf8), follow);
if (path_fs.IsNull())
return false;
return Stat(path_fs, follow, info, error);
} }
StorageDirectoryReader * StorageDirectoryReader *
LocalStorage::OpenDirectory(const char *uri_utf8, Error &error) LocalStorage::OpenDirectory(const char *uri_utf8)
{ {
AllocatedPath path_fs = MapFS(uri_utf8, error); return new LocalDirectoryReader(MapFSOrThrow(uri_utf8));
if (path_fs.IsNull())
return nullptr;
return new LocalDirectoryReader(std::move(path_fs));
} }
gcc_pure gcc_pure
@ -186,12 +174,10 @@ LocalDirectoryReader::Read()
return nullptr; return nullptr;
} }
bool StorageFileInfo
LocalDirectoryReader::GetInfo(bool follow, StorageFileInfo &info, Error &error) LocalDirectoryReader::GetInfo(bool follow)
{ {
const AllocatedPath path_fs = return Stat(AllocatedPath::Build(base_fs, reader.GetEntry()), follow);
AllocatedPath::Build(base_fs, reader.GetEntry());
return Stat(path_fs, follow, info, error);
} }
Storage * Storage *

View File

@ -35,7 +35,6 @@
#include "event/Call.hxx" #include "event/Call.hxx"
#include "event/DeferredMonitor.hxx" #include "event/DeferredMonitor.hxx"
#include "event/TimeoutMonitor.hxx" #include "event/TimeoutMonitor.hxx"
#include "util/Error.hxx"
#include "util/StringCompare.hxx" #include "util/StringCompare.hxx"
extern "C" { extern "C" {
@ -84,11 +83,9 @@ public:
} }
/* virtual methods from class Storage */ /* virtual methods from class Storage */
bool GetInfo(const char *uri_utf8, bool follow, StorageFileInfo &info, StorageFileInfo GetInfo(const char *uri_utf8, bool follow) override;
Error &error) override;
StorageDirectoryReader *OpenDirectory(const char *uri_utf8, StorageDirectoryReader *OpenDirectory(const char *uri_utf8) override;
Error &error) override;
std::string MapUTF8(const char *uri_utf8) const override; std::string MapUTF8(const char *uri_utf8) const override;
@ -214,7 +211,7 @@ private:
}; };
static std::string static std::string
UriToNfsPath(const char *_uri_utf8, Error &error) UriToNfsPath(const char *_uri_utf8)
{ {
assert(_uri_utf8 != nullptr); assert(_uri_utf8 != nullptr);
@ -222,7 +219,7 @@ UriToNfsPath(const char *_uri_utf8, Error &error)
std::string uri_utf8("/"); std::string uri_utf8("/");
uri_utf8.append(_uri_utf8); uri_utf8.append(_uri_utf8);
return AllocatedPath::FromUTF8(uri_utf8.c_str(), error).Steal(); return AllocatedPath::FromUTF8Throw(uri_utf8.c_str()).Steal();
} }
std::string std::string
@ -260,12 +257,15 @@ Copy(StorageFileInfo &info, const struct stat &st)
class NfsGetInfoOperation final : public BlockingNfsOperation { class NfsGetInfoOperation final : public BlockingNfsOperation {
const char *const path; const char *const path;
StorageFileInfo &info; StorageFileInfo info;
public: public:
NfsGetInfoOperation(NfsConnection &_connection, const char *_path, NfsGetInfoOperation(NfsConnection &_connection, const char *_path)
StorageFileInfo &_info) :BlockingNfsOperation(_connection), path(_path) {}
:BlockingNfsOperation(_connection), path(_path), info(_info) {}
const StorageFileInfo &GetInfo() const {
return info;
}
protected: protected:
void Start() override { void Start() override {
@ -277,19 +277,16 @@ protected:
} }
}; };
bool StorageFileInfo
NfsStorage::GetInfo(const char *uri_utf8, gcc_unused bool follow, NfsStorage::GetInfo(const char *uri_utf8, gcc_unused bool follow)
StorageFileInfo &info, Error &error)
{ {
const std::string path = UriToNfsPath(uri_utf8, error); const std::string path = UriToNfsPath(uri_utf8);
if (path.empty())
return false;
WaitConnected(); WaitConnected();
NfsGetInfoOperation operation(*connection, path.c_str(), info); NfsGetInfoOperation operation(*connection, path.c_str());
operation.Run(); operation.Run();
return true; return operation.GetInfo();
} }
gcc_pure gcc_pure
@ -377,11 +374,9 @@ NfsListDirectoryOperation::CollectEntries(struct nfsdir *dir)
} }
StorageDirectoryReader * StorageDirectoryReader *
NfsStorage::OpenDirectory(const char *uri_utf8, Error &error) NfsStorage::OpenDirectory(const char *uri_utf8)
{ {
const std::string path = UriToNfsPath(uri_utf8, error); const std::string path = UriToNfsPath(uri_utf8);
if (path.empty())
return nullptr;
WaitConnected(); WaitConnected();
@ -392,7 +387,7 @@ NfsStorage::OpenDirectory(const char *uri_utf8, Error &error)
} }
static Storage * static Storage *
CreateNfsStorageURI(EventLoop &event_loop, const char *base, Error &) CreateNfsStorageURI(EventLoop &event_loop, const char *base)
{ {
if (memcmp(base, "nfs://", 6) != 0) if (memcmp(base, "nfs://", 6) != 0)
return nullptr; return nullptr;

View File

@ -26,8 +26,9 @@
#include "lib/smbclient/Mutex.hxx" #include "lib/smbclient/Mutex.hxx"
#include "fs/Traits.hxx" #include "fs/Traits.hxx"
#include "thread/Mutex.hxx" #include "thread/Mutex.hxx"
#include "util/Error.hxx" #include "system/Error.hxx"
#include "util/StringCompare.hxx" #include "util/StringCompare.hxx"
#include "util/ScopeExit.hxx"
#include <libsmbclient.h> #include <libsmbclient.h>
@ -45,8 +46,7 @@ public:
/* virtual methods from class StorageDirectoryReader */ /* virtual methods from class StorageDirectoryReader */
const char *Read() override; const char *Read() override;
bool GetInfo(bool follow, StorageFileInfo &info, StorageFileInfo GetInfo(bool follow) override;
Error &error) override;
}; };
class SmbclientStorage final : public Storage { class SmbclientStorage final : public Storage {
@ -65,11 +65,9 @@ public:
} }
/* virtual methods from class Storage */ /* virtual methods from class Storage */
bool GetInfo(const char *uri_utf8, bool follow, StorageFileInfo &info, StorageFileInfo GetInfo(const char *uri_utf8, bool follow) override;
Error &error) override;
StorageDirectoryReader *OpenDirectory(const char *uri_utf8, StorageDirectoryReader *OpenDirectory(const char *uri_utf8) override;
Error &error) override;
std::string MapUTF8(const char *uri_utf8) const override; std::string MapUTF8(const char *uri_utf8) const override;
@ -93,18 +91,18 @@ SmbclientStorage::MapToRelativeUTF8(const char *uri_utf8) const
return PathTraitsUTF8::Relative(base.c_str(), uri_utf8); return PathTraitsUTF8::Relative(base.c_str(), uri_utf8);
} }
static bool static StorageFileInfo
GetInfo(const char *path, StorageFileInfo &info, Error &error) GetInfo(const char *path)
{ {
struct stat st; struct stat st;
smbclient_mutex.lock();
bool success = smbc_stat(path, &st) == 0; {
smbclient_mutex.unlock(); const ScopeLock protect(smbclient_mutex);
if (!success) { if (smbc_stat(path, &st) != 0)
error.SetErrno(); throw MakeErrno("Failed to access file");
return false;
} }
StorageFileInfo info;
if (S_ISREG(st.st_mode)) if (S_ISREG(st.st_mode))
info.type = StorageFileInfo::Type::REGULAR; info.type = StorageFileInfo::Type::REGULAR;
else if (S_ISDIR(st.st_mode)) else if (S_ISDIR(st.st_mode))
@ -116,27 +114,28 @@ GetInfo(const char *path, StorageFileInfo &info, Error &error)
info.mtime = st.st_mtime; info.mtime = st.st_mtime;
info.device = st.st_dev; info.device = st.st_dev;
info.inode = st.st_ino; info.inode = st.st_ino;
return true; return info;
} }
bool StorageFileInfo
SmbclientStorage::GetInfo(const char *uri_utf8, gcc_unused bool follow, SmbclientStorage::GetInfo(const char *uri_utf8, gcc_unused bool follow)
StorageFileInfo &info, Error &error)
{ {
const std::string mapped = MapUTF8(uri_utf8); const std::string mapped = MapUTF8(uri_utf8);
return ::GetInfo(mapped.c_str(), info, error); return ::GetInfo(mapped.c_str());
} }
StorageDirectoryReader * StorageDirectoryReader *
SmbclientStorage::OpenDirectory(const char *uri_utf8, Error &error) SmbclientStorage::OpenDirectory(const char *uri_utf8)
{ {
std::string mapped = MapUTF8(uri_utf8); std::string mapped = MapUTF8(uri_utf8);
smbclient_mutex.lock();
int handle = smbc_opendir(mapped.c_str()); int handle;
smbclient_mutex.unlock();
if (handle < 0) { {
error.SetErrno(); const ScopeLock protect(smbclient_mutex);
return nullptr; handle = smbc_opendir(mapped.c_str());
if (handle < 0)
throw MakeErrno("Failed to open directory");
} }
return new SmbclientDirectoryReader(std::move(mapped.c_str()), handle); return new SmbclientDirectoryReader(std::move(mapped.c_str()), handle);
@ -173,18 +172,15 @@ SmbclientDirectoryReader::Read()
return nullptr; return nullptr;
} }
bool StorageFileInfo
SmbclientDirectoryReader::GetInfo(gcc_unused bool follow, SmbclientDirectoryReader::GetInfo(gcc_unused bool follow)
StorageFileInfo &info,
Error &error)
{ {
const std::string path = PathTraitsUTF8::Build(base.c_str(), name); const std::string path = PathTraitsUTF8::Build(base.c_str(), name);
return ::GetInfo(path.c_str(), info, error); return ::GetInfo(path.c_str());
} }
static Storage * static Storage *
CreateSmbclientStorageURI(gcc_unused EventLoop &event_loop, const char *base, CreateSmbclientStorageURI(gcc_unused EventLoop &event_loop, const char *base)
Error &error)
{ {
if (memcmp(base, "smb://", 6) != 0) if (memcmp(base, "smb://", 6) != 0)
return nullptr; return nullptr;
@ -193,16 +189,13 @@ CreateSmbclientStorageURI(gcc_unused EventLoop &event_loop, const char *base,
const ScopeLock protect(smbclient_mutex); const ScopeLock protect(smbclient_mutex);
SMBCCTX *ctx = smbc_new_context(); SMBCCTX *ctx = smbc_new_context();
if (ctx == nullptr) { if (ctx == nullptr)
error.SetErrno("smbc_new_context() failed"); throw MakeErrno("smbc_new_context() failed");
return nullptr;
}
SMBCCTX *ctx2 = smbc_init_context(ctx); SMBCCTX *ctx2 = smbc_init_context(ctx);
if (ctx2 == nullptr) { if (ctx2 == nullptr) {
error.SetErrno("smbc_init_context() failed"); AtScopeExit(ctx) { smbc_free_context(ctx, 1); };
smbc_free_context(ctx, 1); throw MakeErrno("smbc_new_context() failed");
return nullptr;
} }
return new SmbclientStorage(base, ctx2); return new SmbclientStorage(base, ctx2);

View File

@ -18,6 +18,7 @@
*/ */
#include "config.h" #include "config.h"
#include "Log.hxx"
#include "ScopeIOThread.hxx" #include "ScopeIOThread.hxx"
#include "storage/Registry.hxx" #include "storage/Registry.hxx"
#include "storage/StorageInterface.hxx" #include "storage/StorageInterface.hxx"
@ -25,6 +26,7 @@
#include "util/Error.hxx" #include "util/Error.hxx"
#include <memory> #include <memory>
#include <stdexcept>
#include <unistd.h> #include <unistd.h>
#include <stdlib.h> #include <stdlib.h>
@ -35,12 +37,9 @@
static Storage * static Storage *
MakeStorage(const char *uri) MakeStorage(const char *uri)
{ {
Error error; Storage *storage = CreateStorageURI(io_thread_get(), uri);
Storage *storage = CreateStorageURI(io_thread_get(), uri, error); if (storage == nullptr)
if (storage == nullptr) { throw std::runtime_error("Unrecognized storage URI");
fprintf(stderr, "%s\n", error.GetMessage());
exit(EXIT_FAILURE);
}
return storage; return storage;
} }
@ -48,21 +47,11 @@ MakeStorage(const char *uri)
static int static int
Ls(Storage &storage, const char *path) Ls(Storage &storage, const char *path)
{ {
Error error; auto dir = storage.OpenDirectory(path);
auto dir = storage.OpenDirectory(path, error);
if (dir == nullptr) {
fprintf(stderr, "%s\n", error.GetMessage());
return EXIT_FAILURE;
}
const char *name; const char *name;
while ((name = dir->Read()) != nullptr) { while ((name = dir->Read()) != nullptr) {
StorageFileInfo info; const auto info = dir->GetInfo(false);
if (!dir->GetInfo(false, info, error)) {
printf("Error on %s: %s\n", name, error.GetMessage());
error.Clear();
continue;
}
const char *type = "unk"; const char *type = "unk";
switch (info.type) { switch (info.type) {
@ -93,7 +82,7 @@ Ls(Storage &storage, const char *path)
int int
main(int argc, char **argv) main(int argc, char **argv)
{ try {
if (argc < 3) { if (argc < 3) {
fprintf(stderr, "Usage: run_storage COMMAND URI ...\n"); fprintf(stderr, "Usage: run_storage COMMAND URI ...\n");
return EXIT_FAILURE; return EXIT_FAILURE;
@ -119,4 +108,9 @@ main(int argc, char **argv)
fprintf(stderr, "Unknown command\n"); fprintf(stderr, "Unknown command\n");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
return EXIT_SUCCESS;
} catch (const std::exception &e) {
LogError(e);
return EXIT_FAILURE;
} }