File: exceptions.h

package info (click to toggle)
securefs 0.11.1%2Bds-3
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 1,684 kB
  • sloc: cpp: 11,757; python: 486; sh: 11; makefile: 7
file content (247 lines) | stat: -rw-r--r-- 6,664 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
#pragma once
#include "myutils.h"

#include <cerrno>
#include <exception>
#include <memory>
#include <stdint.h>
#include <string.h>
#include <string>
#include <utility>

namespace securefs
{
class ExceptionBase : public std::exception
{
private:
    mutable std::string m_cached_msg;
    // Mutable fields are not thread safe in `const` functions.
    // But who accesses exception objects concurrently anyway?

protected:
    ExceptionBase();

public:
    ~ExceptionBase() override;
    virtual std::string message() const = 0;
    virtual int error_number() const noexcept { return EPERM; }
    const char* what() const noexcept override;
};

class UnreachableCodeException : public ExceptionBase
{
private:
    const char* m_func;
    const char* m_file;
    int m_line;

public:
    explicit UnreachableCodeException(const char* func, const char* file, int line)
        : m_func(func), m_file(file), m_line(line)
    {
    }

    std::string message() const override
    {
        return strprintf(
            "Unreachable code executed in function \"%s\" at %s:%d", m_func, m_file, m_line);
    }
};

#define UNREACHABLE() throw securefs::UnreachableCodeException(__FUNCTION__, __FILE__, __LINE__)

class VFSException : public ExceptionBase
{
private:
    int m_errno;

public:
    explicit VFSException(int errc) : m_errno(errc) {}
    ~VFSException() override;

    int error_number() const noexcept override { return m_errno; }

    std::string message() const override;
};

[[noreturn]] void throwVFSException(int errc);

class SystemException : public ExceptionBase
{
};

class POSIXException : public SystemException
{
private:
    int m_errno;
    std::string m_msg;

public:
    explicit POSIXException(int errc, std::string msg) : m_errno(errc), m_msg(std::move(msg)) {}
    ~POSIXException() override;

    int error_number() const noexcept override { return m_errno; }

    std::string message() const override;
};

// This macro is needed because errno expands to a function, which has unspecified evaluation order
// with respect to other function calls, and those other function calls may modify errno, resulting
// in incorrect error reporting
#define THROW_POSIX_EXCEPTION(errc, msg)                                                           \
    do                                                                                             \
    {                                                                                              \
        int code = errc;                                                                           \
        ::securefs::throwPOSIXExceptionDoNotUseDirectly(code, msg);                                \
    } while (0)

[[noreturn]] void throwPOSIXExceptionDoNotUseDirectly(int err, std::string msg);

class VerificationException : public ExceptionBase
{
};

class InvalidFormatException : public ExceptionBase
{
};

class InvalidArgumentException : public ExceptionBase
{
private:
    std::string m_msg;

public:
    explicit InvalidArgumentException(std::string why) { m_msg.swap(why); }
    ~InvalidArgumentException() override;

    std::string message() const override { return m_msg; }

    int error_number() const noexcept override { return EINVAL; }
};

[[noreturn]] void throwInvalidArgumentException(const char* why);
[[noreturn]] void throwInvalidArgumentException(std::string why);

class CorruptedMetaDataException : public InvalidFormatException
{
private:
    id_type m_id;
    const char* m_reason;

public:
    explicit CorruptedMetaDataException(const id_type& id, const char* reason) : m_reason(reason)
    {
        memcpy(m_id.data(), id.data(), id.size());
    }

    std::string message() const override
    {
        return strprintf("Metadata for ID %s is corrupted (%s)",
                         hexify(m_id.data(), m_id.size()).c_str(),
                         m_reason);
    }
};

class MessageVerificationException : public VerificationException
{
private:
    id_type m_id;
    offset_type m_off;

public:
    explicit MessageVerificationException(const id_type& id, offset_type off) : m_off(off)
    {
        memcpy(m_id.data(), id.data(), id.size());
    }

    std::string message() const override
    {
        return strprintf("Message for ID %s at offset %lld does not match the checksum",
                         hexify(m_id.data(), m_id.size()).c_str(),
                         (long long)m_off);
    }
};

class XattrVerificationException : public VerificationException
{
private:
    id_type m_id;
    std::string m_name;

public:
    explicit XattrVerificationException(const id_type& id, std::string name)
    {
        memcpy(m_id.data(), id.data(), id.size());
        m_name.swap(name);
    }

    std::string message() const override
    {
        return strprintf("Extended attribute for ID %s and name \"%s\" has wrong checksum",
                         hexify(m_id.data(), m_id.size()).c_str(),
                         m_name.c_str());
    }
};

class LiteMessageVerificationException : public VerificationException
{
public:
    std::string message() const override { return "File content has invalid checksum"; }
};

class StreamTooLongException : public ExceptionBase
{
private:
    int64_t m_max_size;
    int64_t m_size;

public:
    explicit StreamTooLongException(int64_t max_size, int64_t size)
        : m_max_size(max_size), m_size(size)
    {
    }

    std::string message() const override
    {
        return strprintf("Operation on stream at point %lld, which exceeds its maximum size %lld",
                         (long long)m_size,
                         (long long)m_max_size);
    }
    int error_number() const noexcept override { return EFBIG; }
};

class InvalidCastException : public ExceptionBase
{
private:
    const char* from_name;
    const char* to_name;

public:
    explicit InvalidCastException(const char* from_name, const char* to_name)
        : from_name(from_name), to_name(to_name)
    {
    }

    std::string message() const override
    {
        return strprintf("Invalid cast from %s to %s", from_name, to_name);
    }
};

class FileTypeInconsistencyException : public ExceptionBase
{
public:
    std::string message() const override
    {
        return "A file object has inconsistent type. This indicates that a bug or corruption in "
               "the filesystem has happened.";
    }
};

[[noreturn]] void throwFileTypeInconsistencyException();

[[noreturn]] void throw_runtime_error(const char*);
[[noreturn]] void throw_runtime_error(const std::string&);

std::unique_ptr<const char, void (*)(const char*)> get_type_name(const std::exception& e) noexcept;
}    // namespace securefs