Commit e6e7d6db authored by Max Kellermann's avatar Max Kellermann

fs/io/Reader: use C++ exceptions instead of class Error

parent fe60c52c
...@@ -277,13 +277,7 @@ static void help(void) ...@@ -277,13 +277,7 @@ static void help(void)
class ConfigLoader class ConfigLoader
{ {
Error &error;
bool result;
public: public:
ConfigLoader(Error &_error) : error(_error), result(false) { }
bool GetResult() const { return result; }
bool TryFile(const Path path); bool TryFile(const Path path);
bool TryFile(const AllocatedPath &base_path, bool TryFile(const AllocatedPath &base_path,
PathTraitsFS::const_pointer path); PathTraitsFS::const_pointer path);
...@@ -292,7 +286,7 @@ public: ...@@ -292,7 +286,7 @@ public:
bool ConfigLoader::TryFile(Path path) bool ConfigLoader::TryFile(Path path)
{ {
if (FileExists(path)) { if (FileExists(path)) {
result = ReadConfigFile(path, error); ReadConfigFile(path);
return true; return true;
} }
return false; return false;
...@@ -386,15 +380,16 @@ parse_cmdline(int argc, char **argv, struct options *options, ...@@ -386,15 +380,16 @@ parse_cmdline(int argc, char **argv, struct options *options,
return false; return false;
} }
return ReadConfigFile(Path::FromFS(buffer), error); ReadConfigFile(Path::FromFS(buffer));
#else #else
return ReadConfigFile(Path::FromFS(config_file), error); ReadConfigFile(Path::FromFS(config_file));
#endif #endif
return true;
} }
/* use default configuration file path */ /* use default configuration file path */
ConfigLoader loader(error); ConfigLoader loader;
bool found = bool found =
#ifdef WIN32 #ifdef WIN32
...@@ -413,5 +408,5 @@ parse_cmdline(int argc, char **argv, struct options *options, ...@@ -413,5 +408,5 @@ parse_cmdline(int argc, char **argv, struct options *options,
return false; return false;
} }
return loader.GetResult(); return true;
} }
...@@ -453,11 +453,8 @@ int mpd_main(int argc, char *argv[]) ...@@ -453,11 +453,8 @@ int mpd_main(int argc, char *argv[])
if (!sdcard.IsNull()) { if (!sdcard.IsNull()) {
const auto config_path = const auto config_path =
AllocatedPath::Build(sdcard, "mpd.conf"); AllocatedPath::Build(sdcard, "mpd.conf");
if (FileExists(config_path) && if (FileExists(config_path))
!ReadConfigFile(config_path, error)) { ReadConfigFile(config_path);
LogError(error);
return EXIT_FAILURE;
}
} }
#else #else
if (!parse_cmdline(argc, argv, &options, error)) { if (!parse_cmdline(argc, argv, &options, error)) {
......
...@@ -254,11 +254,7 @@ LoadPlaylistFile(const char *utf8path, Error &error) ...@@ -254,11 +254,7 @@ LoadPlaylistFile(const char *utf8path, Error &error)
if (path_fs.IsNull()) if (path_fs.IsNull())
return contents; return contents;
TextFile file(path_fs, error); TextFile file(path_fs);
if (file.HasFailed()) {
TranslatePlaylistError(error);
return contents;
}
char *s; char *s;
while ((s = file.ReadLine()) != nullptr) { while ((s = file.ReadLine()) != nullptr) {
......
...@@ -102,17 +102,12 @@ StateFile::Write() ...@@ -102,17 +102,12 @@ StateFile::Write()
void void
StateFile::Read() StateFile::Read()
{ try {
bool success; bool success;
FormatDebug(state_file_domain, "Loading state file %s", path_utf8.c_str()); FormatDebug(state_file_domain, "Loading state file %s", path_utf8.c_str());
Error error; TextFile file(path);
TextFile file(path, error);
if (file.HasFailed()) {
LogError(error);
return;
}
#ifdef ENABLE_DATABASE #ifdef ENABLE_DATABASE
const SongLoader song_loader(partition.instance.database, const SongLoader song_loader(partition.instance.database,
...@@ -135,6 +130,8 @@ StateFile::Read() ...@@ -135,6 +130,8 @@ StateFile::Read()
} }
RememberVersions(); RememberVersions();
} catch (const std::exception &e) {
LogError(e);
} }
void void
......
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
#include "ConfigTemplates.hxx" #include "ConfigTemplates.hxx"
#include "util/Tokenizer.hxx" #include "util/Tokenizer.hxx"
#include "util/StringUtil.hxx" #include "util/StringUtil.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx" #include "util/Domain.hxx"
#include "util/RuntimeError.hxx" #include "util/RuntimeError.hxx"
#include "fs/Path.hxx" #include "fs/Path.hxx"
...@@ -65,17 +64,14 @@ config_read_name_value(ConfigBlock &block, char *input, unsigned line) ...@@ -65,17 +64,14 @@ config_read_name_value(ConfigBlock &block, char *input, unsigned line)
} }
static ConfigBlock * static ConfigBlock *
config_read_block(BufferedReader &reader, Error &error) config_read_block(BufferedReader &reader)
try { try {
std::unique_ptr<ConfigBlock> block(new ConfigBlock(reader.GetLineNumber())); std::unique_ptr<ConfigBlock> block(new ConfigBlock(reader.GetLineNumber()));
while (true) { while (true) {
char *line = reader.ReadLine(); char *line = reader.ReadLine();
if (line == nullptr) { if (line == nullptr)
if (reader.Check(error))
throw std::runtime_error("Expected '}' before end-of-file"); throw std::runtime_error("Expected '}' before end-of-file");
return nullptr;
}
line = StripLeft(line); line = StripLeft(line);
if (*line == 0 || *line == CONF_COMMENT) if (*line == 0 || *line == CONF_COMMENT)
...@@ -114,11 +110,10 @@ Append(ConfigBlock *&head, ConfigBlock *p) ...@@ -114,11 +110,10 @@ Append(ConfigBlock *&head, ConfigBlock *p)
*i = p; *i = p;
} }
static bool static void
ReadConfigBlock(ConfigData &config_data, BufferedReader &reader, ReadConfigBlock(ConfigData &config_data, BufferedReader &reader,
const char *name, ConfigBlockOption o, const char *name, ConfigBlockOption o,
Tokenizer &tokenizer, Tokenizer &tokenizer)
Error &error)
{ {
const unsigned i = unsigned(o); const unsigned i = unsigned(o);
const ConfigTemplate &option = config_block_templates[i]; const ConfigTemplate &option = config_block_templates[i];
...@@ -143,12 +138,9 @@ ReadConfigBlock(ConfigData &config_data, BufferedReader &reader, ...@@ -143,12 +138,9 @@ ReadConfigBlock(ConfigData &config_data, BufferedReader &reader,
throw FormatRuntimeError("line %u: Unknown tokens after '{'", throw FormatRuntimeError("line %u: Unknown tokens after '{'",
reader.GetLineNumber()); reader.GetLineNumber());
auto *param = config_read_block(reader, error); auto *param = config_read_block(reader);
if (param == nullptr) assert(param != nullptr);
return false;
Append(head, param); Append(head, param);
return true;
} }
gcc_nonnull_all gcc_nonnull_all
...@@ -196,13 +188,13 @@ ReadConfigParam(ConfigData &config_data, BufferedReader &reader, ...@@ -196,13 +188,13 @@ ReadConfigParam(ConfigData &config_data, BufferedReader &reader,
Append(head, param); Append(head, param);
} }
static bool static void
ReadConfigFile(ConfigData &config_data, BufferedReader &reader, Error &error) ReadConfigFile(ConfigData &config_data, BufferedReader &reader)
{ {
while (true) { while (true) {
char *line = reader.ReadLine(); char *line = reader.ReadLine();
if (line == nullptr) if (line == nullptr)
return true; return;
line = StripLeft(line); line = StripLeft(line);
if (*line == 0 || *line == CONF_COMMENT) if (*line == 0 || *line == CONF_COMMENT)
...@@ -224,9 +216,8 @@ ReadConfigFile(ConfigData &config_data, BufferedReader &reader, Error &error) ...@@ -224,9 +216,8 @@ ReadConfigFile(ConfigData &config_data, BufferedReader &reader, Error &error)
ReadConfigParam(config_data, reader, name, o, ReadConfigParam(config_data, reader, name, o,
tokenizer); tokenizer);
} else if ((bo = ParseConfigBlockOptionName(name)) != ConfigBlockOption::MAX) { } else if ((bo = ParseConfigBlockOptionName(name)) != ConfigBlockOption::MAX) {
if (!ReadConfigBlock(config_data, reader, name, bo, ReadConfigBlock(config_data, reader, name, bo,
tokenizer, error)) tokenizer);
return false;
} else { } else {
throw FormatRuntimeError("unrecognized parameter in config file at " throw FormatRuntimeError("unrecognized parameter in config file at "
"line %u: %s\n", "line %u: %s\n",
...@@ -235,19 +226,16 @@ ReadConfigFile(ConfigData &config_data, BufferedReader &reader, Error &error) ...@@ -235,19 +226,16 @@ ReadConfigFile(ConfigData &config_data, BufferedReader &reader, Error &error)
} }
} }
bool void
ReadConfigFile(ConfigData &config_data, Path path, Error &error) ReadConfigFile(ConfigData &config_data, Path path)
{ {
assert(!path.IsNull()); assert(!path.IsNull());
const std::string path_utf8 = path.ToUTF8(); const std::string path_utf8 = path.ToUTF8();
FormatDebug(config_file_domain, "loading file %s", path_utf8.c_str()); FormatDebug(config_file_domain, "loading file %s", path_utf8.c_str());
FileReader file(path, error); FileReader file(path);
if (!file.IsDefined())
return false;
BufferedReader reader(file); BufferedReader reader(file);
return ReadConfigFile(config_data, reader, error) && ReadConfigFile(config_data, reader);
reader.Check(error);
} }
...@@ -24,7 +24,7 @@ class Error; ...@@ -24,7 +24,7 @@ class Error;
class Path; class Path;
struct ConfigData; struct ConfigData;
bool void
ReadConfigFile(ConfigData &data, Path path, Error &error); ReadConfigFile(ConfigData &data, Path path);
#endif #endif
...@@ -45,10 +45,10 @@ void config_global_init(void) ...@@ -45,10 +45,10 @@ void config_global_init(void)
{ {
} }
bool void
ReadConfigFile(Path path, Error &error) ReadConfigFile(Path path)
{ {
return ReadConfigFile(config_data, path, error); return ReadConfigFile(config_data, path);
} }
static void static void
......
...@@ -42,8 +42,8 @@ config_global_finish(); ...@@ -42,8 +42,8 @@ config_global_finish();
void void
config_global_check(); config_global_check();
bool void
ReadConfigFile(Path path, Error &error); ReadConfigFile(Path path);
gcc_pure gcc_pure
const config_param * const config_param *
......
...@@ -184,11 +184,9 @@ SimpleDatabase::Load(Error &error) ...@@ -184,11 +184,9 @@ SimpleDatabase::Load(Error &error)
assert(!path.IsNull()); assert(!path.IsNull());
assert(root != nullptr); assert(root != nullptr);
TextFile file(path, error); TextFile file(path);
if (file.HasFailed())
return false;
if (!db_load_internal(file, *root, error) || !file.Check(error)) if (!db_load_internal(file, *root, error))
return false; return false;
FileInfo fi; FileInfo fi;
...@@ -200,7 +198,7 @@ SimpleDatabase::Load(Error &error) ...@@ -200,7 +198,7 @@ SimpleDatabase::Load(Error &error)
bool bool
SimpleDatabase::Open(Error &error) SimpleDatabase::Open(Error &error)
{ try {
assert(prefixed_light_song == nullptr); assert(prefixed_light_song == nullptr);
root = Directory::NewRoot(); root = Directory::NewRoot();
...@@ -223,6 +221,9 @@ SimpleDatabase::Open(Error &error) ...@@ -223,6 +221,9 @@ SimpleDatabase::Open(Error &error)
} }
return true; return true;
} catch (const std::exception &e) {
error.Set(e);
return false;
} }
void void
......
...@@ -27,41 +27,18 @@ ...@@ -27,41 +27,18 @@
#include "fs/Path.hxx" #include "fs/Path.hxx"
#include "fs/NarrowPath.hxx" #include "fs/NarrowPath.hxx"
#include "fs/io/TextFile.hxx" #include "fs/io/TextFile.hxx"
#include "util/StringUtil.hxx" #include "system/Error.hxx"
#include "util/Error.hxx"
#include "Log.hxx" #include "Log.hxx"
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#ifdef HAVE_CLASS_GLOB
gcc_pure
static bool
IsFileNotFound(const Error &error)
{
#ifdef WIN32
return error.IsDomain(win32_domain) &&
error.GetCode() == ERROR_FILE_NOT_FOUND;
#else
return error.IsDomain(errno_domain) && error.GetCode() == ENOENT;
#endif
}
#endif
bool bool
ExcludeList::LoadFile(Path path_fs) ExcludeList::LoadFile(Path path_fs)
{ try {
#ifdef HAVE_CLASS_GLOB #ifdef HAVE_CLASS_GLOB
Error error; TextFile file(path_fs);
TextFile file(path_fs, error);
if (file.HasFailed()) {
if (!IsFileNotFound(error))
LogError(error);
return false;
}
char *line; char *line;
while ((line = file.ReadLine()) != nullptr) { while ((line = file.ReadLine()) != nullptr) {
...@@ -79,6 +56,13 @@ ExcludeList::LoadFile(Path path_fs) ...@@ -79,6 +56,13 @@ ExcludeList::LoadFile(Path path_fs)
#endif #endif
return true; return true;
} catch (const std::system_error &e) {
if (!IsFileNotFound(e))
LogError(e);
return false;
} catch (const std::exception &e) {
LogError(e);
return false;
} }
bool bool
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "check.h" #include "check.h"
#include "Path.hxx" #include "Path.hxx"
#include "util/Error.hxx" #include "util/Error.hxx"
#include "system/Error.hxx"
#include <stdint.h> #include <stdint.h>
...@@ -63,6 +64,20 @@ class FileInfo { ...@@ -63,6 +64,20 @@ class FileInfo {
#endif #endif
public: public:
FileInfo() = default;
FileInfo(Path path, bool follow_symlinks=true) {
if (!GetFileInfo(path, *this, follow_symlinks)) {
#ifdef WIN32
throw FormatLastError("Failed to access %s",
path.ToUTF8().c_str());
#else
throw FormatErrno("Failed to access %s",
path.ToUTF8().c_str());
#endif
}
}
bool IsRegular() const { bool IsRegular() const {
#ifdef WIN32 #ifdef WIN32
return (data.dwFileAttributes & return (data.dwFileAttributes &
......
...@@ -200,20 +200,21 @@ ParseConfigLine(char *line, const char *dir_name, AllocatedPath &result_dir) ...@@ -200,20 +200,21 @@ ParseConfigLine(char *line, const char *dir_name, AllocatedPath &result_dir)
} }
static AllocatedPath GetUserDir(const char *name) static AllocatedPath GetUserDir(const char *name)
{ try {
auto result = AllocatedPath::Null(); auto result = AllocatedPath::Null();
auto config_dir = GetUserConfigDir(); auto config_dir = GetUserConfigDir();
if (config_dir.IsNull()) if (config_dir.IsNull())
return result; return result;
auto dirs_file = AllocatedPath::Build(config_dir, "user-dirs.dirs"); auto dirs_file = AllocatedPath::Build(config_dir, "user-dirs.dirs");
TextFile input(dirs_file, IgnoreError());
if (input.HasFailed()) TextFile input(dirs_file);
return result;
char *line; char *line;
while ((line = input.ReadLine()) != nullptr) while ((line = input.ReadLine()) != nullptr)
if (ParseConfigLine(line, name, result)) if (ParseConfigLine(line, name, result))
return result; return result;
return result; return result;
} catch (const std::exception &e) {
return AllocatedPath::Null();
} }
#endif #endif
......
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
#include "config.h" #include "config.h"
#include "AutoGunzipReader.hxx" #include "AutoGunzipReader.hxx"
#include "GunzipReader.hxx" #include "GunzipReader.hxx"
#include "util/Error.hxx"
AutoGunzipReader::~AutoGunzipReader() AutoGunzipReader::~AutoGunzipReader()
{ {
...@@ -35,36 +34,27 @@ IsGzip(const uint8_t data[4]) ...@@ -35,36 +34,27 @@ IsGzip(const uint8_t data[4])
(data[3] & 0xe0) == 0; (data[3] & 0xe0) == 0;
} }
inline bool inline void
AutoGunzipReader::Detect(Error &error) AutoGunzipReader::Detect()
{ {
const uint8_t *data = (const uint8_t *)peek.Peek(4, error); const uint8_t *data = (const uint8_t *)peek.Peek(4);
if (data == nullptr) { if (data == nullptr) {
if (error.IsDefined())
return false;
next = &peek; next = &peek;
return true; return;
} }
if (IsGzip(data)) { if (IsGzip(data))
gunzip = new GunzipReader(peek, error); next = gunzip = new GunzipReader(peek);
if (!gunzip->IsDefined()) else
return false;
next = gunzip;
} else
next = &peek; next = &peek;
return true;
} }
size_t size_t
AutoGunzipReader::Read(void *data, size_t size, Error &error) AutoGunzipReader::Read(void *data, size_t size)
{ {
if (next == nullptr && !Detect(error)) if (next == nullptr)
return false; Detect();
return next->Read(data, size, error); assert(next != nullptr);
return next->Read(data, size);
} }
...@@ -43,10 +43,10 @@ public: ...@@ -43,10 +43,10 @@ public:
~AutoGunzipReader(); ~AutoGunzipReader();
/* virtual methods from class Reader */ /* virtual methods from class Reader */
virtual size_t Read(void *data, size_t size, Error &error) override; virtual size_t Read(void *data, size_t size) override;
private: private:
bool Detect(Error &error); void Detect();
}; };
#endif #endif
...@@ -25,9 +25,6 @@ ...@@ -25,9 +25,6 @@
bool bool
BufferedReader::Fill(bool need_more) BufferedReader::Fill(bool need_more)
{ {
if (gcc_unlikely(last_error.IsDefined()))
return false;
if (eof) if (eof)
return !need_more; return !need_more;
...@@ -41,11 +38,8 @@ BufferedReader::Fill(bool need_more) ...@@ -41,11 +38,8 @@ BufferedReader::Fill(bool need_more)
assert(!w.IsEmpty()); assert(!w.IsEmpty());
} }
size_t nbytes = reader.Read(w.data, w.size, last_error); size_t nbytes = reader.Read(w.data, w.size);
if (nbytes == 0) { if (nbytes == 0) {
if (gcc_unlikely(last_error.IsDefined()))
return false;
eof = true; eof = true;
return !need_more; return !need_more;
} }
...@@ -65,7 +59,7 @@ BufferedReader::ReadLine() ...@@ -65,7 +59,7 @@ BufferedReader::ReadLine()
} }
} while (Fill(true)); } while (Fill(true));
if (last_error.IsDefined() || !eof || buffer.IsEmpty()) if (!eof || buffer.IsEmpty())
return nullptr; return nullptr;
auto w = buffer.Write(); auto w = buffer.Write();
......
...@@ -23,12 +23,10 @@ ...@@ -23,12 +23,10 @@
#include "check.h" #include "check.h"
#include "Compiler.h" #include "Compiler.h"
#include "util/DynamicFifoBuffer.hxx" #include "util/DynamicFifoBuffer.hxx"
#include "util/Error.hxx"
#include <stddef.h> #include <stddef.h>
class Reader; class Reader;
class Error;
class BufferedReader { class BufferedReader {
static constexpr size_t MAX_SIZE = 512 * 1024; static constexpr size_t MAX_SIZE = 512 * 1024;
...@@ -37,8 +35,6 @@ class BufferedReader { ...@@ -37,8 +35,6 @@ class BufferedReader {
DynamicFifoBuffer<char> buffer; DynamicFifoBuffer<char> buffer;
Error last_error;
bool eof; bool eof;
unsigned line_number; unsigned line_number;
...@@ -48,19 +44,6 @@ public: ...@@ -48,19 +44,6 @@ public:
:reader(_reader), buffer(4096), eof(false), :reader(_reader), buffer(4096), eof(false),
line_number(0) {} line_number(0) {}
gcc_pure
bool Check() const {
return !last_error.IsDefined();
}
bool Check(Error &error) const {
if (last_error.IsDefined()) {
error.Set(last_error);
return false;
} else
return true;
}
bool Fill(bool need_more); bool Fill(bool need_more);
gcc_pure gcc_pure
......
...@@ -20,57 +20,49 @@ ...@@ -20,57 +20,49 @@
#include "config.h" #include "config.h"
#include "FileReader.hxx" #include "FileReader.hxx"
#include "fs/FileInfo.hxx" #include "fs/FileInfo.hxx"
#include "util/Error.hxx" #include "system/Error.hxx"
#ifdef WIN32 #ifdef WIN32
FileReader::FileReader(Path _path, Error &error) FileReader::FileReader(Path _path)
:path(_path), :path(_path),
handle(CreateFile(path.c_str(), GENERIC_READ, FILE_SHARE_READ, handle(CreateFile(path.c_str(), GENERIC_READ, FILE_SHARE_READ,
nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
nullptr)) nullptr))
{ {
if (handle == INVALID_HANDLE_VALUE) { if (handle == INVALID_HANDLE_VALUE)
const auto path_utf8 = path.ToUTF8(); throw FormatLastError("Failed to open %s", path.ToUTF8().c_str());
error.FormatLastError("Failed to open %s", path_utf8.c_str());
}
} }
bool FileInfo
FileReader::GetFileInfo(FileInfo &info, Error &error) const FileReader::GetFileInfo() const
{ {
assert(IsDefined()); assert(IsDefined());
return ::GetFileInfo(path, info, error); return FileInfo(path);
} }
size_t size_t
FileReader::Read(void *data, size_t size, Error &error) FileReader::Read(void *data, size_t size)
{ {
assert(IsDefined()); assert(IsDefined());
DWORD nbytes; DWORD nbytes;
if (!ReadFile(handle, data, size, &nbytes, nullptr)) { if (!ReadFile(handle, data, size, &nbytes, nullptr))
const auto path_utf8 = path.ToUTF8(); throw FormatLastError("Failed to read from %s",
error.FormatLastError("Failed to read from %s", path.ToUTF8().c_str());
path_utf8.c_str());
nbytes = 0;
}
return nbytes; return nbytes;
} }
bool void
FileReader::Seek(off_t offset, Error &error) FileReader::Seek(off_t offset)
{ {
assert(IsDefined()); assert(IsDefined());
auto result = SetFilePointer(handle, offset, nullptr, FILE_BEGIN); auto result = SetFilePointer(handle, offset, nullptr, FILE_BEGIN);
const bool success = result != INVALID_SET_FILE_POINTER; if (result == INVALID_SET_FILE_POINTER)
if (!success) throw MakeLastError("Failed to seek");
error.SetLastError("Failed to seek");
return success;
} }
void void
...@@ -83,52 +75,49 @@ FileReader::Close() ...@@ -83,52 +75,49 @@ FileReader::Close()
#else #else
FileReader::FileReader(Path _path, Error &error) FileReader::FileReader(Path _path)
:path(_path) :path(_path)
{ {
fd.OpenReadOnly(path.c_str()); fd.OpenReadOnly(path.c_str());
if (!fd.IsDefined()) if (!fd.IsDefined())
error.FormatErrno("Failed to open %s", path.c_str()); throw FormatErrno("Failed to open %s", path.ToUTF8().c_str());
} }
bool FileInfo
FileReader::GetFileInfo(FileInfo &info, Error &error) const FileReader::GetFileInfo() const
{ {
assert(IsDefined()); assert(IsDefined());
FileInfo info;
const bool success = fstat(fd.Get(), &info.st) == 0; const bool success = fstat(fd.Get(), &info.st) == 0;
if (!success) if (!success)
error.FormatErrno("Failed to access %s", throw FormatErrno("Failed to access %s",
path.ToUTF8().c_str()); path.ToUTF8().c_str());
return success; return info;
} }
size_t size_t
FileReader::Read(void *data, size_t size, Error &error) FileReader::Read(void *data, size_t size)
{ {
assert(IsDefined()); assert(IsDefined());
ssize_t nbytes = fd.Read(data, size); ssize_t nbytes = fd.Read(data, size);
if (nbytes < 0) { if (nbytes < 0)
error.FormatErrno("Failed to read from %s", path.c_str()); throw FormatErrno("Failed to read from %s", path.ToUTF8().c_str());
nbytes = 0;
}
return nbytes; return nbytes;
} }
bool void
FileReader::Seek(off_t offset, Error &error) FileReader::Seek(off_t offset)
{ {
assert(IsDefined()); assert(IsDefined());
auto result = fd.Seek(offset); auto result = fd.Seek(offset);
const bool success = result >= 0; const bool success = result >= 0;
if (!success) if (!success)
error.SetErrno("Failed to seek"); throw MakeErrno("Failed to seek");
return success;
} }
void void
......
...@@ -48,7 +48,7 @@ class FileReader final : public Reader { ...@@ -48,7 +48,7 @@ class FileReader final : public Reader {
#endif #endif
public: public:
FileReader(Path _path, Error &error); FileReader(Path _path);
#ifdef WIN32 #ifdef WIN32
FileReader(FileReader &&other) FileReader(FileReader &&other)
...@@ -70,6 +70,7 @@ public: ...@@ -70,6 +70,7 @@ public:
} }
protected:
bool IsDefined() const { bool IsDefined() const {
#ifdef WIN32 #ifdef WIN32
return handle != INVALID_HANDLE_VALUE; return handle != INVALID_HANDLE_VALUE;
...@@ -78,6 +79,7 @@ public: ...@@ -78,6 +79,7 @@ public:
#endif #endif
} }
public:
#ifndef WIN32 #ifndef WIN32
FileDescriptor GetFD() const { FileDescriptor GetFD() const {
return fd; return fd;
...@@ -86,12 +88,13 @@ public: ...@@ -86,12 +88,13 @@ public:
void Close(); void Close();
bool GetFileInfo(FileInfo &info, Error &error) const; gcc_pure
FileInfo GetFileInfo() const;
bool Seek(off_t offset, Error &error); void Seek(off_t offset);
/* virtual methods from class Reader */ /* virtual methods from class Reader */
size_t Read(void *data, size_t size, Error &error) override; size_t Read(void *data, size_t size) override;
}; };
#endif #endif
...@@ -20,10 +20,8 @@ ...@@ -20,10 +20,8 @@
#include "config.h" #include "config.h"
#include "GunzipReader.hxx" #include "GunzipReader.hxx"
#include "lib/zlib/Domain.hxx" #include "lib/zlib/Domain.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
GunzipReader::GunzipReader(Reader &_next, Error &error) GunzipReader::GunzipReader(Reader &_next) throw(ZlibError)
:next(_next), eof(false) :next(_next), eof(false)
{ {
z.next_in = nullptr; z.next_in = nullptr;
...@@ -33,25 +31,17 @@ GunzipReader::GunzipReader(Reader &_next, Error &error) ...@@ -33,25 +31,17 @@ GunzipReader::GunzipReader(Reader &_next, Error &error)
z.opaque = Z_NULL; z.opaque = Z_NULL;
int result = inflateInit2(&z, 16 + MAX_WBITS); int result = inflateInit2(&z, 16 + MAX_WBITS);
if (result != Z_OK) { if (result != Z_OK)
z.opaque = this; throw ZlibError(result);
error.Set(zlib_domain, result, zError(result));
}
}
GunzipReader::~GunzipReader()
{
if (IsDefined())
inflateEnd(&z);
} }
inline bool inline bool
GunzipReader::FillBuffer(Error &error) GunzipReader::FillBuffer()
{ {
auto w = buffer.Write(); auto w = buffer.Write();
assert(!w.IsEmpty()); assert(!w.IsEmpty());
size_t nbytes = next.Read(w.data, w.size, error); size_t nbytes = next.Read(w.data, w.size);
if (nbytes == 0) if (nbytes == 0)
return false; return false;
...@@ -60,7 +50,7 @@ GunzipReader::FillBuffer(Error &error) ...@@ -60,7 +50,7 @@ GunzipReader::FillBuffer(Error &error)
} }
size_t size_t
GunzipReader::Read(void *data, size_t size, Error &error) GunzipReader::Read(void *data, size_t size)
{ {
if (eof) if (eof)
return 0; return 0;
...@@ -73,10 +63,8 @@ GunzipReader::Read(void *data, size_t size, Error &error) ...@@ -73,10 +63,8 @@ GunzipReader::Read(void *data, size_t size, Error &error)
auto r = buffer.Read(); auto r = buffer.Read();
if (r.IsEmpty()) { if (r.IsEmpty()) {
if (FillBuffer(error)) if (FillBuffer())
r = buffer.Read(); r = buffer.Read();
else if (error.IsDefined())
return 0;
else else
flush = Z_FINISH; flush = Z_FINISH;
} }
...@@ -88,10 +76,8 @@ GunzipReader::Read(void *data, size_t size, Error &error) ...@@ -88,10 +76,8 @@ GunzipReader::Read(void *data, size_t size, Error &error)
if (result == Z_STREAM_END) { if (result == Z_STREAM_END) {
eof = true; eof = true;
return size - z.avail_out; return size - z.avail_out;
} else if (result != Z_OK) { } else if (result != Z_OK)
error.Set(zlib_domain, result, zError(result)); throw ZlibError(result);
return 0;
}
buffer.Consume(r.size - z.avail_in); buffer.Consume(r.size - z.avail_in);
......
...@@ -23,13 +23,11 @@ ...@@ -23,13 +23,11 @@
#include "check.h" #include "check.h"
#include "Reader.hxx" #include "Reader.hxx"
#include "util/StaticFifoBuffer.hxx" #include "util/StaticFifoBuffer.hxx"
#include "lib/zlib/Error.hxx"
#include "Compiler.h" #include "Compiler.h"
#include <zlib.h> #include <zlib.h>
class Error;
class Domain;
/** /**
* A filter that decompresses data using zlib. * A filter that decompresses data using zlib.
*/ */
...@@ -44,25 +42,19 @@ class GunzipReader final : public Reader { ...@@ -44,25 +42,19 @@ class GunzipReader final : public Reader {
public: public:
/** /**
* Construct the filter. Call IsDefined() to check whether * Construct the filter.
* the constructor has succeeded. If not, #error will hold
* information about the failure.
*/ */
GunzipReader(Reader &_next, Error &error); GunzipReader(Reader &_next) throw(ZlibError);
~GunzipReader();
/** ~GunzipReader() {
* Check whether the constructor has succeeded. inflateEnd(&z);
*/
bool IsDefined() const {
return z.opaque == nullptr;
} }
/* virtual methods from class Reader */ /* virtual methods from class Reader */
virtual size_t Read(void *data, size_t size, Error &error) override; size_t Read(void *data, size_t size) override;
private: private:
bool FillBuffer(Error &error); bool FillBuffer();
}; };
#endif #endif
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
#include <string.h> #include <string.h>
const void * const void *
PeekReader::Peek(size_t size, Error &error) PeekReader::Peek(size_t size)
{ {
assert(size > 0); assert(size > 0);
assert(size < sizeof(buffer)); assert(size < sizeof(buffer));
...@@ -35,7 +35,7 @@ PeekReader::Peek(size_t size, Error &error) ...@@ -35,7 +35,7 @@ PeekReader::Peek(size_t size, Error &error)
do { do {
size_t nbytes = next.Read(buffer + buffer_size, size_t nbytes = next.Read(buffer + buffer_size,
size - buffer_size, error); size - buffer_size);
if (nbytes == 0) if (nbytes == 0)
return nullptr; return nullptr;
...@@ -46,7 +46,7 @@ PeekReader::Peek(size_t size, Error &error) ...@@ -46,7 +46,7 @@ PeekReader::Peek(size_t size, Error &error)
} }
size_t size_t
PeekReader::Read(void *data, size_t size, Error &error) PeekReader::Read(void *data, size_t size)
{ {
size_t buffer_remaining = buffer_size - buffer_position; size_t buffer_remaining = buffer_size - buffer_position;
if (buffer_remaining > 0) { if (buffer_remaining > 0) {
...@@ -56,5 +56,5 @@ PeekReader::Read(void *data, size_t size, Error &error) ...@@ -56,5 +56,5 @@ PeekReader::Read(void *data, size_t size, Error &error)
return nbytes; return nbytes;
} }
return next.Read(data, size, error); return next.Read(data, size);
} }
...@@ -44,10 +44,10 @@ public: ...@@ -44,10 +44,10 @@ public:
PeekReader(Reader &_next) PeekReader(Reader &_next)
:next(_next), buffer_size(0), buffer_position(0) {} :next(_next), buffer_size(0), buffer_position(0) {}
const void *Peek(size_t size, Error &error); const void *Peek(size_t size);
/* virtual methods from class Reader */ /* virtual methods from class Reader */
virtual size_t Read(void *data, size_t size, Error &error) override; virtual size_t Read(void *data, size_t size) override;
}; };
#endif #endif
...@@ -25,8 +25,6 @@ ...@@ -25,8 +25,6 @@
#include <stddef.h> #include <stddef.h>
class Error;
/** /**
* An interface that can read bytes from a stream until the stream * An interface that can read bytes from a stream until the stream
* ends. * ends.
...@@ -43,10 +41,10 @@ public: ...@@ -43,10 +41,10 @@ public:
* Read data from the stream. * Read data from the stream.
* *
* @return the number of bytes read into the given buffer or 0 * @return the number of bytes read into the given buffer or 0
* on error/end-of-stream * on end-of-stream
*/ */
gcc_nonnull_all gcc_nonnull_all
virtual size_t Read(void *data, size_t size, Error &error) = 0; virtual size_t Read(void *data, size_t size) = 0;
}; };
#endif #endif
...@@ -26,22 +26,18 @@ ...@@ -26,22 +26,18 @@
#include <assert.h> #include <assert.h>
TextFile::TextFile(Path path_fs, Error &error) TextFile::TextFile(Path path_fs)
:file_reader(new FileReader(path_fs, error)), :file_reader(new FileReader(path_fs)),
#ifdef ENABLE_ZLIB #ifdef ENABLE_ZLIB
gunzip_reader(file_reader->IsDefined() gunzip_reader(new AutoGunzipReader(*file_reader)),
? new AutoGunzipReader(*file_reader)
: nullptr),
#endif #endif
buffered_reader(file_reader->IsDefined() buffered_reader(new BufferedReader(*
? new BufferedReader(*
#ifdef ENABLE_ZLIB #ifdef ENABLE_ZLIB
gunzip_reader gunzip_reader
#else #else
file_reader file_reader
#endif #endif
) ))
: nullptr)
{ {
} }
...@@ -61,11 +57,3 @@ TextFile::ReadLine() ...@@ -61,11 +57,3 @@ TextFile::ReadLine()
return buffered_reader->ReadLine(); return buffered_reader->ReadLine();
} }
bool
TextFile::Check(Error &error) const
{
assert(buffered_reader != nullptr);
return buffered_reader->Check(error);
}
...@@ -23,10 +23,7 @@ ...@@ -23,10 +23,7 @@
#include "check.h" #include "check.h"
#include "Compiler.h" #include "Compiler.h"
#include <stddef.h>
class Path; class Path;
class Error;
class FileReader; class FileReader;
class AutoGunzipReader; class AutoGunzipReader;
class BufferedReader; class BufferedReader;
...@@ -41,32 +38,20 @@ class TextFile { ...@@ -41,32 +38,20 @@ class TextFile {
BufferedReader *const buffered_reader; BufferedReader *const buffered_reader;
public: public:
TextFile(Path path_fs, Error &error); TextFile(Path path_fs);
TextFile(const TextFile &other) = delete; TextFile(const TextFile &other) = delete;
~TextFile(); ~TextFile();
bool HasFailed() const {
return gcc_unlikely(buffered_reader == nullptr);
}
/** /**
* Reads a line from the input file, and strips trailing * Reads a line from the input file, and strips trailing
* space. There is a reasonable maximum line length, only to * space. There is a reasonable maximum line length, only to
* prevent denial of service. * prevent denial of service.
* *
* Use Check() after nullptr has been returned to check * @return a pointer to the line, or nullptr on end-of-file
* whether an error occurred or end-of-file has been reached.
*
* @return a pointer to the line, or nullptr on end-of-file or error
*/ */
char *ReadLine(); char *ReadLine();
/**
* Check whether a ReadLine() call has thrown an error.
*/
bool Check(Error &error) const;
}; };
#endif #endif
...@@ -61,14 +61,10 @@ InputStream * ...@@ -61,14 +61,10 @@ InputStream *
OpenFileInputStream(Path path, OpenFileInputStream(Path path,
Mutex &mutex, Cond &cond, Mutex &mutex, Cond &cond,
Error &error) Error &error)
{ try {
FileReader reader(path, error); FileReader reader(path);
if (!reader.IsDefined())
return nullptr;
FileInfo info; const FileInfo info = reader.GetFileInfo();
if (!reader.GetFileInfo(info, error))
return nullptr;
if (!info.IsRegular()) { if (!info.IsRegular()) {
error.Format(file_domain, "Not a regular file: %s", error.Format(file_domain, "Not a regular file: %s",
...@@ -84,6 +80,9 @@ OpenFileInputStream(Path path, ...@@ -84,6 +80,9 @@ OpenFileInputStream(Path path,
return new FileInputStream(path.ToUTF8().c_str(), return new FileInputStream(path.ToUTF8().c_str(),
std::move(reader), info.GetSize(), std::move(reader), info.GetSize(),
mutex, cond); mutex, cond);
} catch (const std::exception &e) {
error.Set(e);
return nullptr;
} }
static InputStream * static InputStream *
...@@ -98,23 +97,24 @@ input_file_open(gcc_unused const char *filename, ...@@ -98,23 +97,24 @@ input_file_open(gcc_unused const char *filename,
bool bool
FileInputStream::Seek(offset_type new_offset, Error &error) FileInputStream::Seek(offset_type new_offset, Error &error)
{ try {
if (!reader.Seek((off_t)new_offset, error)) reader.Seek((off_t)new_offset);
return false;
offset = new_offset; offset = new_offset;
return true; return true;
} catch (const std::exception &e) {
error.Set(e);
return false;
} }
size_t size_t
FileInputStream::Read(void *ptr, size_t read_size, Error &error) FileInputStream::Read(void *ptr, size_t read_size, Error &error)
{ try {
ssize_t nbytes = reader.Read(ptr, read_size, error); size_t nbytes = reader.Read(ptr, read_size);
if (nbytes < 0)
return 0;
offset += nbytes; offset += nbytes;
return (size_t)nbytes; return nbytes;
} catch (const std::exception &e) {
error.Set(e);
return 0;
} }
const InputPlugin input_plugin_file = { const InputPlugin input_plugin_file = {
......
...@@ -110,10 +110,7 @@ try { ...@@ -110,10 +110,7 @@ try {
config_global_init(); config_global_init();
Error error; Error error;
if (!ReadConfigFile(config_path, error)) { ReadConfigFile(config_path);
cerr << error.GetMessage() << endl;
return EXIT_FAILURE;
}
TagLoadConfig(); TagLoadConfig();
......
...@@ -65,10 +65,7 @@ try { ...@@ -65,10 +65,7 @@ try {
config_global_init(); config_global_init();
Error error; Error error;
if (!ReadConfigFile(config_path, error)) { ReadConfigFile(config_path);
LogError(error);
return EXIT_FAILURE;
}
const ScopeIOThread io_thread; const ScopeIOThread io_thread;
......
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
#include "config.h" #include "config.h"
#include "config/ConfigGlobal.hxx" #include "config/ConfigGlobal.hxx"
#include "fs/Path.hxx" #include "fs/Path.hxx"
#include "util/Error.hxx"
#include "Log.hxx" #include "Log.hxx"
#include <assert.h> #include <assert.h>
...@@ -39,11 +38,7 @@ try { ...@@ -39,11 +38,7 @@ try {
config_global_init(); config_global_init();
Error error; ReadConfigFile(config_path);
if (!ReadConfigFile(config_path, error)) {
LogError(error);
return EXIT_FAILURE;
}
ConfigOption option = ParseConfigOptionName(name); ConfigOption option = ParseConfigOptionName(name);
const char *value = option != ConfigOption::MAX const char *value = option != ConfigOption::MAX
......
...@@ -69,7 +69,6 @@ load_filter(const char *name) ...@@ -69,7 +69,6 @@ load_filter(const char *name)
int main(int argc, char **argv) int main(int argc, char **argv)
try { try {
struct audio_format_string af_string; struct audio_format_string af_string;
Error error2;
char buffer[4096]; char buffer[4096];
if (argc < 3 || argc > 4) { if (argc < 3 || argc > 4) {
...@@ -84,8 +83,7 @@ try { ...@@ -84,8 +83,7 @@ try {
/* read configuration file (mpd.conf) */ /* read configuration file (mpd.conf) */
config_global_init(); config_global_init();
if (!ReadConfigFile(config_path, error2)) ReadConfigFile(config_path);
FatalError(error2);
/* parse the audio format */ /* parse the audio format */
......
...@@ -28,32 +28,32 @@ ...@@ -28,32 +28,32 @@
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
static bool static void
Copy(OutputStream &dest, Reader &src, Error &error) Copy(OutputStream &dest, Reader &src)
{ {
while (true) { while (true) {
char buffer[4096]; char buffer[4096];
size_t nbytes = src.Read(buffer, sizeof(buffer), error); size_t nbytes = src.Read(buffer, sizeof(buffer));
if (nbytes == 0) if (nbytes == 0)
return !error.IsDefined(); break;
dest.Write(buffer, nbytes); dest.Write(buffer, nbytes);
} }
} }
static bool static void
CopyGunzip(OutputStream &dest, Reader &_src, Error &error) CopyGunzip(OutputStream &dest, Reader &_src)
{ {
GunzipReader src(_src, error); GunzipReader src(_src);
return src.IsDefined() && Copy(dest, src, error); Copy(dest, src);
} }
static bool static void
CopyGunzip(FILE *_dest, Path src_path, Error &error) CopyGunzip(FILE *_dest, Path src_path)
{ {
StdioOutputStream dest(_dest); StdioOutputStream dest(_dest);
FileReader src(src_path, error); FileReader src(src_path);
return src.IsDefined() && CopyGunzip(dest, src, error); CopyGunzip(dest, src);
} }
int int
...@@ -67,12 +67,7 @@ main(int argc, gcc_unused char **argv) ...@@ -67,12 +67,7 @@ main(int argc, gcc_unused char **argv)
Path path = Path::FromFS(argv[1]); Path path = Path::FromFS(argv[1]);
try { try {
Error error; CopyGunzip(stdout, path);
if (!CopyGunzip(stdout, path, error)) {
fprintf(stderr, "%s\n", error.GetMessage());
return EXIT_FAILURE;
}
return EXIT_SUCCESS; return EXIT_SUCCESS;
} catch (const std::exception &e) { } catch (const std::exception &e) {
LogError(e); LogError(e);
......
...@@ -59,10 +59,7 @@ try { ...@@ -59,10 +59,7 @@ try {
Error error; Error error;
config_global_init(); config_global_init();
if (!ReadConfigFile(config_path, error)) { ReadConfigFile(config_path);
LogError(error);
return EXIT_FAILURE;
}
/* initialize the core */ /* initialize the core */
......
...@@ -161,10 +161,7 @@ try { ...@@ -161,10 +161,7 @@ try {
/* read configuration file (mpd.conf) */ /* read configuration file (mpd.conf) */
config_global_init(); config_global_init();
if (!ReadConfigFile(config_path, error)) { ReadConfigFile(config_path);
LogError(error);
return EXIT_FAILURE;
}
EventLoop event_loop; EventLoop event_loop;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment