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

This commit is contained in:
Max Kellermann
2015-12-16 11:05:33 +01:00
parent fe60c52c70
commit e6e7d6dbd6
33 changed files with 192 additions and 334 deletions

View File

@@ -23,6 +23,7 @@
#include "check.h"
#include "Path.hxx"
#include "util/Error.hxx"
#include "system/Error.hxx"
#include <stdint.h>
@@ -63,6 +64,20 @@ class FileInfo {
#endif
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 {
#ifdef WIN32
return (data.dwFileAttributes &

View File

@@ -200,20 +200,21 @@ ParseConfigLine(char *line, const char *dir_name, AllocatedPath &result_dir)
}
static AllocatedPath GetUserDir(const char *name)
{
try {
auto result = AllocatedPath::Null();
auto config_dir = GetUserConfigDir();
if (config_dir.IsNull())
return result;
auto dirs_file = AllocatedPath::Build(config_dir, "user-dirs.dirs");
TextFile input(dirs_file, IgnoreError());
if (input.HasFailed())
return result;
TextFile input(dirs_file);
char *line;
while ((line = input.ReadLine()) != nullptr)
if (ParseConfigLine(line, name, result))
return result;
return result;
} catch (const std::exception &e) {
return AllocatedPath::Null();
}
#endif

View File

@@ -20,7 +20,6 @@
#include "config.h"
#include "AutoGunzipReader.hxx"
#include "GunzipReader.hxx"
#include "util/Error.hxx"
AutoGunzipReader::~AutoGunzipReader()
{
@@ -35,36 +34,27 @@ IsGzip(const uint8_t data[4])
(data[3] & 0xe0) == 0;
}
inline bool
AutoGunzipReader::Detect(Error &error)
inline void
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 (error.IsDefined())
return false;
next = &peek;
return true;
return;
}
if (IsGzip(data)) {
gunzip = new GunzipReader(peek, error);
if (!gunzip->IsDefined())
return false;
next = gunzip;
} else
if (IsGzip(data))
next = gunzip = new GunzipReader(peek);
else
next = &peek;
return true;
}
size_t
AutoGunzipReader::Read(void *data, size_t size, Error &error)
AutoGunzipReader::Read(void *data, size_t size)
{
if (next == nullptr && !Detect(error))
return false;
if (next == nullptr)
Detect();
return next->Read(data, size, error);
assert(next != nullptr);
return next->Read(data, size);
}

View File

@@ -43,10 +43,10 @@ public:
~AutoGunzipReader();
/* 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:
bool Detect(Error &error);
void Detect();
};
#endif

View File

@@ -25,9 +25,6 @@
bool
BufferedReader::Fill(bool need_more)
{
if (gcc_unlikely(last_error.IsDefined()))
return false;
if (eof)
return !need_more;
@@ -41,11 +38,8 @@ BufferedReader::Fill(bool need_more)
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 (gcc_unlikely(last_error.IsDefined()))
return false;
eof = true;
return !need_more;
}
@@ -65,7 +59,7 @@ BufferedReader::ReadLine()
}
} while (Fill(true));
if (last_error.IsDefined() || !eof || buffer.IsEmpty())
if (!eof || buffer.IsEmpty())
return nullptr;
auto w = buffer.Write();

View File

@@ -23,12 +23,10 @@
#include "check.h"
#include "Compiler.h"
#include "util/DynamicFifoBuffer.hxx"
#include "util/Error.hxx"
#include <stddef.h>
class Reader;
class Error;
class BufferedReader {
static constexpr size_t MAX_SIZE = 512 * 1024;
@@ -37,8 +35,6 @@ class BufferedReader {
DynamicFifoBuffer<char> buffer;
Error last_error;
bool eof;
unsigned line_number;
@@ -48,19 +44,6 @@ public:
:reader(_reader), buffer(4096), eof(false),
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);
gcc_pure

View File

@@ -20,57 +20,49 @@
#include "config.h"
#include "FileReader.hxx"
#include "fs/FileInfo.hxx"
#include "util/Error.hxx"
#include "system/Error.hxx"
#ifdef WIN32
FileReader::FileReader(Path _path, Error &error)
FileReader::FileReader(Path _path)
:path(_path),
handle(CreateFile(path.c_str(), GENERIC_READ, FILE_SHARE_READ,
nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
nullptr))
{
if (handle == INVALID_HANDLE_VALUE) {
const auto path_utf8 = path.ToUTF8();
error.FormatLastError("Failed to open %s", path_utf8.c_str());
}
if (handle == INVALID_HANDLE_VALUE)
throw FormatLastError("Failed to open %s", path.ToUTF8().c_str());
}
bool
FileReader::GetFileInfo(FileInfo &info, Error &error) const
FileInfo
FileReader::GetFileInfo() const
{
assert(IsDefined());
return ::GetFileInfo(path, info, error);
return FileInfo(path);
}
size_t
FileReader::Read(void *data, size_t size, Error &error)
FileReader::Read(void *data, size_t size)
{
assert(IsDefined());
DWORD nbytes;
if (!ReadFile(handle, data, size, &nbytes, nullptr)) {
const auto path_utf8 = path.ToUTF8();
error.FormatLastError("Failed to read from %s",
path_utf8.c_str());
nbytes = 0;
}
if (!ReadFile(handle, data, size, &nbytes, nullptr))
throw FormatLastError("Failed to read from %s",
path.ToUTF8().c_str());
return nbytes;
}
bool
FileReader::Seek(off_t offset, Error &error)
void
FileReader::Seek(off_t offset)
{
assert(IsDefined());
auto result = SetFilePointer(handle, offset, nullptr, FILE_BEGIN);
const bool success = result != INVALID_SET_FILE_POINTER;
if (!success)
error.SetLastError("Failed to seek");
return success;
if (result == INVALID_SET_FILE_POINTER)
throw MakeLastError("Failed to seek");
}
void
@@ -83,52 +75,49 @@ FileReader::Close()
#else
FileReader::FileReader(Path _path, Error &error)
FileReader::FileReader(Path _path)
:path(_path)
{
fd.OpenReadOnly(path.c_str());
if (!fd.IsDefined())
error.FormatErrno("Failed to open %s", path.c_str());
throw FormatErrno("Failed to open %s", path.ToUTF8().c_str());
}
bool
FileReader::GetFileInfo(FileInfo &info, Error &error) const
FileInfo
FileReader::GetFileInfo() const
{
assert(IsDefined());
FileInfo info;
const bool success = fstat(fd.Get(), &info.st) == 0;
if (!success)
error.FormatErrno("Failed to access %s",
throw FormatErrno("Failed to access %s",
path.ToUTF8().c_str());
return success;
return info;
}
size_t
FileReader::Read(void *data, size_t size, Error &error)
FileReader::Read(void *data, size_t size)
{
assert(IsDefined());
ssize_t nbytes = fd.Read(data, size);
if (nbytes < 0) {
error.FormatErrno("Failed to read from %s", path.c_str());
nbytes = 0;
}
if (nbytes < 0)
throw FormatErrno("Failed to read from %s", path.ToUTF8().c_str());
return nbytes;
}
bool
FileReader::Seek(off_t offset, Error &error)
void
FileReader::Seek(off_t offset)
{
assert(IsDefined());
auto result = fd.Seek(offset);
const bool success = result >= 0;
if (!success)
error.SetErrno("Failed to seek");
return success;
throw MakeErrno("Failed to seek");
}
void

View File

@@ -48,7 +48,7 @@ class FileReader final : public Reader {
#endif
public:
FileReader(Path _path, Error &error);
FileReader(Path _path);
#ifdef WIN32
FileReader(FileReader &&other)
@@ -70,6 +70,7 @@ public:
}
protected:
bool IsDefined() const {
#ifdef WIN32
return handle != INVALID_HANDLE_VALUE;
@@ -78,6 +79,7 @@ public:
#endif
}
public:
#ifndef WIN32
FileDescriptor GetFD() const {
return fd;
@@ -86,12 +88,13 @@ public:
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 */
size_t Read(void *data, size_t size, Error &error) override;
size_t Read(void *data, size_t size) override;
};
#endif

View File

@@ -20,10 +20,8 @@
#include "config.h"
#include "GunzipReader.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)
{
z.next_in = nullptr;
@@ -33,25 +31,17 @@ GunzipReader::GunzipReader(Reader &_next, Error &error)
z.opaque = Z_NULL;
int result = inflateInit2(&z, 16 + MAX_WBITS);
if (result != Z_OK) {
z.opaque = this;
error.Set(zlib_domain, result, zError(result));
}
}
GunzipReader::~GunzipReader()
{
if (IsDefined())
inflateEnd(&z);
if (result != Z_OK)
throw ZlibError(result);
}
inline bool
GunzipReader::FillBuffer(Error &error)
GunzipReader::FillBuffer()
{
auto w = buffer.Write();
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)
return false;
@@ -60,7 +50,7 @@ GunzipReader::FillBuffer(Error &error)
}
size_t
GunzipReader::Read(void *data, size_t size, Error &error)
GunzipReader::Read(void *data, size_t size)
{
if (eof)
return 0;
@@ -73,10 +63,8 @@ GunzipReader::Read(void *data, size_t size, Error &error)
auto r = buffer.Read();
if (r.IsEmpty()) {
if (FillBuffer(error))
if (FillBuffer())
r = buffer.Read();
else if (error.IsDefined())
return 0;
else
flush = Z_FINISH;
}
@@ -88,10 +76,8 @@ GunzipReader::Read(void *data, size_t size, Error &error)
if (result == Z_STREAM_END) {
eof = true;
return size - z.avail_out;
} else if (result != Z_OK) {
error.Set(zlib_domain, result, zError(result));
return 0;
}
} else if (result != Z_OK)
throw ZlibError(result);
buffer.Consume(r.size - z.avail_in);

View File

@@ -23,13 +23,11 @@
#include "check.h"
#include "Reader.hxx"
#include "util/StaticFifoBuffer.hxx"
#include "lib/zlib/Error.hxx"
#include "Compiler.h"
#include <zlib.h>
class Error;
class Domain;
/**
* A filter that decompresses data using zlib.
*/
@@ -44,25 +42,19 @@ class GunzipReader final : public Reader {
public:
/**
* Construct the filter. Call IsDefined() to check whether
* the constructor has succeeded. If not, #error will hold
* information about the failure.
* Construct the filter.
*/
GunzipReader(Reader &_next, Error &error);
~GunzipReader();
GunzipReader(Reader &_next) throw(ZlibError);
/**
* Check whether the constructor has succeeded.
*/
bool IsDefined() const {
return z.opaque == nullptr;
~GunzipReader() {
inflateEnd(&z);
}
/* 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:
bool FillBuffer(Error &error);
bool FillBuffer();
};
#endif

View File

@@ -26,7 +26,7 @@
#include <string.h>
const void *
PeekReader::Peek(size_t size, Error &error)
PeekReader::Peek(size_t size)
{
assert(size > 0);
assert(size < sizeof(buffer));
@@ -35,7 +35,7 @@ PeekReader::Peek(size_t size, Error &error)
do {
size_t nbytes = next.Read(buffer + buffer_size,
size - buffer_size, error);
size - buffer_size);
if (nbytes == 0)
return nullptr;
@@ -46,7 +46,7 @@ PeekReader::Peek(size_t size, Error &error)
}
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;
if (buffer_remaining > 0) {
@@ -56,5 +56,5 @@ PeekReader::Read(void *data, size_t size, Error &error)
return nbytes;
}
return next.Read(data, size, error);
return next.Read(data, size);
}

View File

@@ -44,10 +44,10 @@ public:
PeekReader(Reader &_next)
: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 size_t Read(void *data, size_t size, Error &error) override;
virtual size_t Read(void *data, size_t size) override;
};
#endif

View File

@@ -25,8 +25,6 @@
#include <stddef.h>
class Error;
/**
* An interface that can read bytes from a stream until the stream
* ends.
@@ -43,10 +41,10 @@ public:
* Read data from the stream.
*
* @return the number of bytes read into the given buffer or 0
* on error/end-of-stream
* on end-of-stream
*/
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

View File

@@ -26,22 +26,18 @@
#include <assert.h>
TextFile::TextFile(Path path_fs, Error &error)
:file_reader(new FileReader(path_fs, error)),
TextFile::TextFile(Path path_fs)
:file_reader(new FileReader(path_fs)),
#ifdef ENABLE_ZLIB
gunzip_reader(file_reader->IsDefined()
? new AutoGunzipReader(*file_reader)
: nullptr),
gunzip_reader(new AutoGunzipReader(*file_reader)),
#endif
buffered_reader(file_reader->IsDefined()
? new BufferedReader(*
buffered_reader(new BufferedReader(*
#ifdef ENABLE_ZLIB
gunzip_reader
gunzip_reader
#else
file_reader
file_reader
#endif
)
: nullptr)
))
{
}
@@ -61,11 +57,3 @@ TextFile::ReadLine()
return buffered_reader->ReadLine();
}
bool
TextFile::Check(Error &error) const
{
assert(buffered_reader != nullptr);
return buffered_reader->Check(error);
}

View File

@@ -23,10 +23,7 @@
#include "check.h"
#include "Compiler.h"
#include <stddef.h>
class Path;
class Error;
class FileReader;
class AutoGunzipReader;
class BufferedReader;
@@ -41,32 +38,20 @@ class TextFile {
BufferedReader *const buffered_reader;
public:
TextFile(Path path_fs, Error &error);
TextFile(Path path_fs);
TextFile(const TextFile &other) = delete;
~TextFile();
bool HasFailed() const {
return gcc_unlikely(buffered_reader == nullptr);
}
/**
* Reads a line from the input file, and strips trailing
* space. There is a reasonable maximum line length, only to
* prevent denial of service.
*
* Use Check() after nullptr has been returned to check
* 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
* @return a pointer to the line, or nullptr on end-of-file
*/
char *ReadLine();
/**
* Check whether a ReadLine() call has thrown an error.
*/
bool Check(Error &error) const;
};
#endif