summaryrefslogtreecommitdiff
path: root/src/Handle.cc
blob: 0ec39be14f030e3c94c985932d05a7f284e19ad6 (plain)
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
#include <typeinfo>
#include "ev++.h"
#include "eio.h"
#include "Main.h"
#include "TaskMan.h"
#include "Handle.h"
#include "Printer.h"

#ifdef _WIN32
static const char * strerror_r(int errorno, char * buf, size_t bufsize) {
#ifdef _MSVC
    strerror_s(buf, bufsize, errorno);
    return buf;
#else
    return strerror(errorno);
#endif
}
#endif

class eioInterface : public Balau::AtStart {
  public:
      eioInterface() : AtStart(100) { }
    void repeatCB(ev::idle & w, int revents);
    void readyCB(ev::async & w, int revents);
    static void wantPoll();
    virtual void doStart();
    ev::idle m_repeat;
    ev::async m_ready;
};

static eioInterface eioIF;

void eioInterface::repeatCB(ev::idle & w, int revents) {
    if (eio_poll() != -1)
        w.stop();
}

void eioInterface::readyCB(ev::async & w, int revents) {
    if (eio_poll() == -1)
        m_repeat.start();
}

void eioInterface::doStart() {
    Balau::Printer::elog(Balau::E_HANDLE, "Starting the eio interface");

    Balau::TaskMan * taskMan = Balau::TaskMan::getTaskMan();
    Assert(taskMan);
    struct ev_loop * loop = taskMan->getLoop();

    m_repeat.set(loop);
    m_repeat.set<eioInterface, &eioInterface::repeatCB>(this);

    m_ready.set(loop);
    m_ready.set<eioInterface, &eioInterface::readyCB>(this);
    m_ready.start();

    eio_init(wantPoll, NULL);
}

void eioInterface::wantPoll() {
    eioIF.m_ready.send();
}

bool Balau::Handle::canSeek() { return false; }
bool Balau::Handle::canRead() { return false; }
bool Balau::Handle::canWrite() { return false; }
off_t Balau::Handle::getSize() { return -1; }
time_t Balau::Handle::getMTime() { return -1; }

ssize_t Balau::Handle::read(void * buf, size_t count) throw (GeneralException) {
    if (canRead())
        throw GeneralException(String("Handle ") + getName() + " can read, but read() not implemented (missing in class " + ClassName(this).c_str() + ")");
    else
        throw GeneralException("Handle can't read");
    return -1;
}

ssize_t Balau::Handle::write(const void * buf, size_t count) throw (GeneralException) {
    if (canWrite())
        throw GeneralException(String("Handle ") + getName() + " can write, but write() not implemented (missing in class " + ClassName(this).c_str() + ")");
    else
        throw GeneralException("Handle can't write");
    return -1;
}

void Balau::Handle::rseek(off_t offset, int whence) throw (GeneralException) {
    if (canSeek())
        throw GeneralException(String("Handle ") + getName() + " can seek, but rseek() not implemented (missing in class " + ClassName(this).c_str() + ")");
    else
        throw GeneralException("Handle can't seek");
}

void Balau::Handle::wseek(off_t offset, int whence) throw (GeneralException) {
    rseek(offset, whence);
}

off_t Balau::Handle::rtell() throw (GeneralException) {
    if (canSeek())
        throw GeneralException(String("Handle ") + getName() + " can seek, but rtell() not implemented (missing in class " + ClassName(this).c_str() + ")");
    else
        throw GeneralException("Handle can't seek");
}

off_t Balau::Handle::wtell() throw (GeneralException) {
    return rtell();
}

bool Balau::SeekableHandle::canSeek() { return true; }

void Balau::SeekableHandle::rseek(off_t offset, int whence) throw (GeneralException) {
    Assert(canRead() || canWrite());
    off_t size;
    if (!canRead())
        wseek(offset, whence);
    switch (whence) {
    case SEEK_SET:
        m_rOffset = offset;
        break;
    case SEEK_CUR:
        m_rOffset += offset;
        break;
    case SEEK_END:
        size = getSize();
        if (getSize() < 0)
            throw GeneralException("Can't seek from end in a Handle you don't know the max size");
        m_rOffset = size + offset;
        break;
    }
    if (m_rOffset < 0)
        m_rOffset = 0;
}

void Balau::SeekableHandle::wseek(off_t offset, int whence) throw (GeneralException) {
    Assert(canRead() || canWrite());
    off_t size;
    if (!canWrite())
        rseek(offset, whence);
    switch (whence) {
    case SEEK_SET:
        m_wOffset = offset;
        break;
    case SEEK_CUR:
        m_wOffset += offset;
        break;
    case SEEK_END:
        size = getSize();
        if (getSize() < 0)
            throw GeneralException("Can't seek from end in a Handle you don't know the max size");
        m_wOffset = size + offset;
        break;
    }
    if (m_wOffset < 0)
        m_wOffset = 0;
}

off_t Balau::SeekableHandle::rtell() throw (GeneralException) {
    Assert(canRead() || canWrite());
    if (!canRead())
        return wtell();
    return m_rOffset;
}

off_t Balau::SeekableHandle::wtell() throw (GeneralException) {
    Assert(canRead() || canWrite());
    if (!canWrite())
        return rtell();
    return m_wOffset;
}

bool Balau::SeekableHandle::isEOF() {
    return m_rOffset == getSize();
}

struct cbResults_t {
    Balau::Events::Custom evt;
    int result, errorno;
};

static int eioDone(eio_req * req) {
    cbResults_t * cbResults = (cbResults_t *) req->data;
    cbResults->result = req->result;
    cbResults->errorno = req->errorno;
    cbResults->evt.doSignal();
    return 0;
}

int Balau::FileSystem::mkdir(const char * path) throw (GeneralException) {
    cbResults_t cbResults;
    eio_req * r = eio_mkdir(path, 0755, 0, eioDone, &cbResults);
    Assert(r != 0);
    Task::yield(&cbResults.evt);

    char str[4096];
    if (cbResults.result < 0)
        throw GeneralException(String("Unable to create directory ") + path + ": " + strerror_r(cbResults.errorno, str, sizeof(str)) + " (err#" + cbResults.errorno + ")");

    return cbResults.result;
}