• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mendersoftware / mender / 1012473002

21 Sep 2023 02:17PM UTC coverage: 78.107% (-0.3%) from 78.44%
1012473002

push

gitlab-ci

lluiscampos
chore: log stdout output on errors when parsing UM yes/no commands

Signed-off-by: Lluis Campos <lluis.campos@northern.tech>

2 of 2 new or added lines in 1 file covered. (100.0%)

6468 of 8281 relevant lines covered (78.11%)

11106.28 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/common/io.hpp
1
// Copyright 2023 Northern.tech AS
2
//
3
//    Licensed under the Apache License, Version 2.0 (the "License");
4
//    you may not use this file except in compliance with the License.
5
//    You may obtain a copy of the License at
6
//
7
//        http://www.apache.org/licenses/LICENSE-2.0
8
//
9
//    Unless required by applicable law or agreed to in writing, software
10
//    distributed under the License is distributed on an "AS IS" BASIS,
11
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
//    See the License for the specific language governing permissions and
13
//    limitations under the License.
14

15
#ifndef MENDER_COMMON_IO_HPP
16
#define MENDER_COMMON_IO_HPP
17

18
#include <common/error.hpp>
19
#include <common/expected.hpp>
20

21
#include <cstdint>
22
#include <iterator>
23
#include <memory>
24
#include <system_error>
25
#include <vector>
26
#include <istream>
27
#include <sstream>
28
#include <string>
29
#include <algorithm>
30
#include <ostream>
31
#include <iostream>
32
#include <fstream>
33

34
namespace mender {
35
namespace common {
36
namespace io {
37

38
using namespace std;
39

40
namespace expected = mender::common::expected;
41

42
using mender::common::error::Error;
43
using mender::common::error::NoError;
44

45
using mender::common::expected::ExpectedSize;
46

47
namespace paths {
48
extern const string Stdin;
49
}
50

51
class Reader {
52
public:
53
        virtual ~Reader() {};
×
54

55
        virtual ExpectedSize Read(vector<uint8_t>::iterator start, vector<uint8_t>::iterator end) = 0;
56

57
        unique_ptr<istream> GetStream();
58
};
59
using ReaderPtr = shared_ptr<Reader>;
60
using ExpectedReaderPtr = expected::expected<ReaderPtr, Error>;
61

62
class Writer {
63
public:
64
        virtual ~Writer() {};
65

66
        virtual ExpectedSize Write(
67
                vector<uint8_t>::const_iterator start, vector<uint8_t>::const_iterator end) = 0;
68
};
69
using WriterPtr = shared_ptr<Writer>;
70
using ExpectedWriterPtr = expected::expected<WriterPtr, Error>;
71

72
class ReadWriter : virtual public Reader, virtual public Writer {};
73
using ReadWriterPtr = shared_ptr<ReadWriter>;
74
using ExpectedReadWriterPtr = expected::expected<ReadWriterPtr, Error>;
75

76
class Canceller {
77
public:
78
        virtual ~Canceller() {
79
        }
80

81
        virtual void Cancel() = 0;
82
};
83

84
enum class Repeat {
85
        Yes,
86
        No,
87
};
88

89
using AsyncIoHandler = function<void(ExpectedSize)>;
90
using RepeatedAsyncIoHandler = function<Repeat(ExpectedSize)>;
91

92
class AsyncReader : virtual public Canceller {
93
public:
94
        // Note: iterators generally need to remain valid until either the handler or `Cancel()` is
95
        // called.
96
        virtual error::Error AsyncRead(
97
                vector<uint8_t>::iterator start, vector<uint8_t>::iterator end, AsyncIoHandler handler) = 0;
98

99
        // Calls AsyncRead repeatedly with the same iterators and handler, until the stream is
100
        // exhausted or an error occurs. All errors will be returned through the handler, even
101
        // initial errors from AsyncRead.
102
        void RepeatedAsyncRead(
103
                vector<uint8_t>::iterator start,
104
                vector<uint8_t>::iterator end,
105
                RepeatedAsyncIoHandler handler);
106
};
107
using AsyncReaderPtr = shared_ptr<AsyncReader>;
108

109
class AsyncWriter : virtual public Canceller {
110
public:
111
        // Note: iterators generally need to remain valid until either the handler or `Cancel()` is
112
        // called.
113
        virtual error::Error AsyncWrite(
114
                vector<uint8_t>::const_iterator start,
115
                vector<uint8_t>::const_iterator end,
116
                AsyncIoHandler handler) = 0;
117
};
118
using AsyncWriterPtr = shared_ptr<AsyncWriter>;
119

120
class AsyncReadWriter : virtual public AsyncReader, virtual public AsyncWriter {};
121
using AsyncReadWriterPtr = shared_ptr<AsyncReadWriter>;
122

123
using ExpectedAsyncReaderPtr = expected::expected<AsyncReaderPtr, error::Error>;
124
using ExpectedAsyncWriterPtr = expected::expected<AsyncWriterPtr, error::Error>;
125
using ExpectedAsyncReadWriterPtr = expected::expected<AsyncReadWriterPtr, error::Error>;
126

127
/**
128
 * Stream the data from `src` to `dst` until encountering EOF or an error.
129
 */
130
Error Copy(Writer &dst, Reader &src);
131

132
/**
133
 * Stream the data from `src` to `dst` until encountering EOF or an error, using `buffer` as an
134
 * intermediate. The block size will be the size of `buffer`.
135
 */
136
Error Copy(Writer &dst, Reader &src, vector<uint8_t> &buffer);
137

138
/**
139
 * Stream the data from `src` to `dst` until encountering EOF or an error. The reading end is async,
140
 * the writing end is not, so it should be "quick", otherwise it may still stall.
141
 */
142
void AsyncCopy(Writer &dst, AsyncReader &src, function<void(Error)> finished_handler);
143
void AsyncCopy(WriterPtr dst, AsyncReaderPtr src, function<void(Error)> finished_handler);
144

145
class StreamReader : virtual public Reader {
146
protected:
147
        shared_ptr<std::istream> is_;
148

149
public:
150
        StreamReader(std::istream &stream) :
151
                // For references, initialize a shared_ptr with a null deleter, since we don't own
152
                // the object.
153
                is_ {&stream, [](std::istream *stream) {}} {
154
        }
155
        StreamReader(shared_ptr<std::istream> stream) :
156
                is_ {stream} {
157
        }
158
        ExpectedSize Read(vector<uint8_t>::iterator start, vector<uint8_t>::iterator end) override;
159
};
160

161
using ExpectedIfstream = expected::expected<ifstream, error::Error>;
162
using ExpectedSharedIfstream = expected::expected<shared_ptr<ifstream>, error::Error>;
163
using ExpectedOfstream = expected::expected<ofstream, error::Error>;
164
using ExpectedSharedOfstream = expected::expected<shared_ptr<ofstream>, error::Error>;
165
ExpectedIfstream OpenIfstream(const string &path);
166
ExpectedSharedIfstream OpenSharedIfstream(const string &path);
167
ExpectedOfstream OpenOfstream(const string &path, bool append = false);
168
ExpectedSharedOfstream OpenSharedOfstream(const string &path, bool append = false);
169

170
class FileReader : virtual public StreamReader {
171
public:
172
        FileReader(const string &path) :
173
                StreamReader(shared_ptr<std::istream>()),
174
                path_ {path} {};
175

176
        ExpectedSize Read(vector<uint8_t>::iterator start, vector<uint8_t>::iterator end) override {
177
                // We cannot open the stream in the constructor because it can fail and
178
                // there's no way to report that error. However, the check below is
179
                // cheap compared to the I/O that happens in this function, so a very
180
                // little overhead.
181
                if (!is_) {
182
                        auto ex_is = OpenSharedIfstream(path_);
183
                        if (!ex_is) {
184
                                return expected::unexpected(ex_is.error());
185
                        }
186
                        is_ = ex_is.value();
187
                }
188
                return StreamReader::Read(start, end);
189
        }
190

191
        error::Error Rewind();
192

193
private:
194
        string path_;
195
};
196

197
/* Discards all data written to it */
198
class Discard : virtual public Writer {
199
        ExpectedSize Write(
200
                vector<uint8_t>::const_iterator start, vector<uint8_t>::const_iterator end) override {
201
                return end - start;
202
        }
203
};
204

205
class StringReader : virtual public Reader {
206
private:
207
        std::stringstream s_;
208
        unique_ptr<StreamReader> reader_;
209

210
public:
211
        StringReader(const string &str) :
212
                s_ {str},
213
                reader_ {new StreamReader(s_)} {
214
        }
215
        StringReader(string &&str) :
216
                s_ {str},
217
                reader_ {new StreamReader(s_)} {
218
        }
219
        StringReader(StringReader &&sr) :
220
                s_ {std::move(sr.s_)},
221
                reader_ {new StreamReader(s_)} {
222
        }
223
        StringReader &operator=(StringReader &&sr) {
224
                s_ = std::move(sr.s_);
225
                reader_.reset(new StreamReader(s_));
226
                return *this;
227
        }
228

229
        ExpectedSize Read(vector<uint8_t>::iterator start, vector<uint8_t>::iterator end) override {
230
                return reader_->Read(start, end);
231
        }
232
};
233

234
using Vsize = vector<uint8_t>::size_type;
235

236
class ByteWriter : virtual public Writer {
237
private:
238
        shared_ptr<vector<uint8_t>> receiver_;
239
        Vsize bytes_written_ {0};
240
        bool unlimited_ {false};
241

242
public:
243
        ByteWriter(vector<uint8_t> &receiver) :
244
                receiver_ {&receiver, [](vector<uint8_t> *vec) {}} {
245
        }
246

247
        ByteWriter(shared_ptr<vector<uint8_t>> receiver) :
248
                receiver_ {receiver} {
249
        }
250

251
        // Will extend the vector if necessary. Probably a bad idea in production code, but useful
252
        // in tests.
253
        void SetUnlimited(bool enabled);
254

255
        ExpectedSize Write(
256
                vector<uint8_t>::const_iterator start, vector<uint8_t>::const_iterator end) override;
257
};
258

259
class StreamWriter : virtual public Writer {
260
private:
261
        shared_ptr<std::ostream> os_;
262

263
public:
264
        StreamWriter(std::ostream &stream) :
265
                os_ {&stream, [](std::ostream *str) {}} {
266
        }
267
        StreamWriter(shared_ptr<std::ostream> stream) :
268
                os_ {stream} {
269
        }
270
        ExpectedSize Write(
271
                vector<uint8_t>::const_iterator start, vector<uint8_t>::const_iterator end) override;
272
};
273

274
error::Error WriteStringIntoOfstream(ofstream &os, const string &data);
275

276
expected::ExpectedSize FileSize(const string &path);
277

278
} // namespace io
279
} // namespace common
280
} // namespace mender
281

282
#endif // MENDER_COMMON_IO_HPP
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc