Serenity Operating System
1/*
2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <AK/ByteBuffer.h>
28#include <AK/PrintfImplementation.h>
29#include <LibCore/IODevice.h>
30#include <LibCore/SyscallUtils.h>
31#include <errno.h>
32#include <stdio.h>
33#include <string.h>
34#include <sys/select.h>
35#include <sys/stat.h>
36#include <sys/time.h>
37#include <unistd.h>
38
39namespace Core {
40
41IODevice::IODevice(Object* parent)
42 : Object(parent)
43{
44}
45
46IODevice::~IODevice()
47{
48}
49
50const char* IODevice::error_string() const
51{
52 return strerror(m_error);
53}
54
55int IODevice::read(u8* buffer, int length)
56{
57 auto read_buffer = read(length);
58 if (read_buffer.is_null())
59 return 0;
60 memcpy(buffer, read_buffer.data(), length);
61 return read_buffer.size();
62}
63
64ByteBuffer IODevice::read(size_t max_size)
65{
66 if (m_fd < 0)
67 return {};
68 if (!max_size)
69 return {};
70 auto buffer = ByteBuffer::create_uninitialized(max_size);
71 auto* buffer_ptr = (char*)buffer.data();
72 size_t remaining_buffer_space = buffer.size();
73 size_t taken_from_buffered = 0;
74 if (!m_buffered_data.is_empty()) {
75 taken_from_buffered = min(remaining_buffer_space, m_buffered_data.size());
76 memcpy(buffer_ptr, m_buffered_data.data(), taken_from_buffered);
77 Vector<u8> new_buffered_data;
78 new_buffered_data.append(m_buffered_data.data() + taken_from_buffered, m_buffered_data.size() - taken_from_buffered);
79 m_buffered_data = move(new_buffered_data);
80 remaining_buffer_space -= taken_from_buffered;
81 buffer_ptr += taken_from_buffered;
82 }
83 if (!remaining_buffer_space)
84 return buffer;
85 int nread = ::read(m_fd, buffer_ptr, remaining_buffer_space);
86 if (nread < 0) {
87 if (taken_from_buffered) {
88 buffer.trim(taken_from_buffered);
89 return buffer;
90 }
91 set_error(errno);
92 return {};
93 }
94 if (nread == 0) {
95 set_eof(true);
96 if (taken_from_buffered) {
97 buffer.trim(taken_from_buffered);
98 return buffer;
99 }
100 return {};
101 }
102 buffer.trim(taken_from_buffered + nread);
103 return buffer;
104}
105
106bool IODevice::can_read_from_fd() const
107{
108 // FIXME: Can we somehow remove this once Core::Socket is implemented using non-blocking sockets?
109 fd_set rfds;
110 FD_ZERO(&rfds);
111 FD_SET(m_fd, &rfds);
112 struct timeval timeout {
113 0, 0
114 };
115 int rc = Core::safe_syscall(select, m_fd + 1, &rfds, nullptr, nullptr, &timeout);
116 if (rc < 0) {
117 // NOTE: We don't set m_error here.
118 perror("IODevice::can_read: select");
119 return false;
120 }
121 return FD_ISSET(m_fd, &rfds);
122}
123
124bool IODevice::can_read_line()
125{
126 if (m_eof && !m_buffered_data.is_empty())
127 return true;
128 if (m_buffered_data.contains_slow('\n'))
129 return true;
130 if (!can_read_from_fd())
131 return false;
132 populate_read_buffer();
133 return m_buffered_data.contains_slow('\n');
134}
135
136bool IODevice::can_read() const
137{
138 return !m_buffered_data.is_empty() || can_read_from_fd();
139}
140
141ByteBuffer IODevice::read_all()
142{
143 off_t file_size = 0;
144 struct stat st;
145 int rc = fstat(fd(), &st);
146 if (rc == 0)
147 file_size = st.st_size;
148
149 Vector<u8> data;
150 data.ensure_capacity(file_size);
151
152 if (!m_buffered_data.is_empty()) {
153 data.append(m_buffered_data.data(), m_buffered_data.size());
154 m_buffered_data.clear();
155 }
156
157 while (true) {
158 char read_buffer[4096];
159 int nread = ::read(m_fd, read_buffer, sizeof(read_buffer));
160 if (nread < 0) {
161 set_error(errno);
162 break;
163 }
164 if (nread == 0) {
165 set_eof(true);
166 break;
167 }
168 data.append((const u8*)read_buffer, nread);
169 }
170 if (data.is_empty())
171 return {};
172 return ByteBuffer::copy(data.data(), data.size());
173}
174
175ByteBuffer IODevice::read_line(size_t max_size)
176{
177 if (m_fd < 0)
178 return {};
179 if (!max_size)
180 return {};
181 if (!can_read_line())
182 return {};
183 if (m_eof) {
184 if (m_buffered_data.size() > max_size) {
185 dbgprintf("IODevice::read_line: At EOF but there's more than max_size(%zu) buffered\n", max_size);
186 return {};
187 }
188 auto buffer = ByteBuffer::copy(m_buffered_data.data(), m_buffered_data.size());
189 m_buffered_data.clear();
190 return buffer;
191 }
192 auto line = ByteBuffer::create_uninitialized(max_size + 1);
193 size_t line_index = 0;
194 while (line_index < max_size) {
195 u8 ch = m_buffered_data[line_index];
196 line[line_index++] = ch;
197 if (ch == '\n') {
198 Vector<u8> new_buffered_data;
199 new_buffered_data.append(m_buffered_data.data() + line_index, m_buffered_data.size() - line_index);
200 m_buffered_data = move(new_buffered_data);
201 line[line_index] = '\0';
202 line.trim(line_index + 1);
203 return line;
204 }
205 }
206 return {};
207}
208
209bool IODevice::populate_read_buffer()
210{
211 if (m_fd < 0)
212 return false;
213 u8 buffer[1024];
214 int nread = ::read(m_fd, buffer, sizeof(buffer));
215 if (nread < 0) {
216 set_error(errno);
217 return false;
218 }
219 if (nread == 0) {
220 set_eof(true);
221 return false;
222 }
223 m_buffered_data.append(buffer, nread);
224 return true;
225}
226
227bool IODevice::close()
228{
229 if (fd() < 0 || mode() == NotOpen)
230 return false;
231 int rc = ::close(fd());
232 if (rc < 0) {
233 set_error(errno);
234 return false;
235 }
236 set_fd(-1);
237 set_mode(IODevice::NotOpen);
238 return true;
239}
240
241bool IODevice::seek(i64 offset, SeekMode mode, off_t* pos)
242{
243 int m = SEEK_SET;
244 switch (mode) {
245 case SeekMode::SetPosition:
246 m = SEEK_SET;
247 break;
248 case SeekMode::FromCurrentPosition:
249 m = SEEK_CUR;
250 break;
251 case SeekMode::FromEndPosition:
252 m = SEEK_END;
253 break;
254 }
255 off_t rc = lseek(m_fd, offset, m);
256 if (rc < 0) {
257 set_error(errno);
258 if (pos)
259 *pos = -1;
260 return false;
261 }
262 m_buffered_data.clear();
263 m_eof = false;
264 if (pos)
265 *pos = rc;
266 return true;
267}
268
269bool IODevice::write(const u8* data, int size)
270{
271 int rc = ::write(m_fd, data, size);
272 if (rc < 0) {
273 perror("IODevice::write: write");
274 set_error(errno);
275 return false;
276 }
277 return rc == size;
278}
279
280int IODevice::printf(const char* format, ...)
281{
282 va_list ap;
283 va_start(ap, format);
284 // FIXME: We're not propagating write() failures to client here!
285 int ret = printf_internal([this](char*&, char ch) {
286 write((const u8*)&ch, 1);
287 },
288 nullptr, format, ap);
289 va_end(ap);
290 return ret;
291}
292
293void IODevice::set_fd(int fd)
294{
295 if (m_fd == fd)
296 return;
297
298 m_fd = fd;
299 did_update_fd(fd);
300}
301
302bool IODevice::write(const StringView& v)
303{
304 return write((const u8*)v.characters_without_null_termination(), v.length());
305}
306
307}