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 <sys/select.h>
34#include <sys/stat.h>
35#include <sys/time.h>
36#include <unistd.h>
37
38namespace Core {
39
40IODevice::IODevice(Object* parent)
41 : Object(parent)
42{
43}
44
45IODevice::~IODevice()
46{
47}
48
49const char* IODevice::error_string() const
50{
51 return strerror(m_error);
52}
53
54int IODevice::read(u8* buffer, int length)
55{
56 auto read_buffer = read(length);
57 if (read_buffer.is_null())
58 return 0;
59 memcpy(buffer, read_buffer.data(), length);
60 return read_buffer.size();
61}
62
63ByteBuffer IODevice::read(size_t max_size)
64{
65 if (m_fd < 0)
66 return {};
67 if (!max_size)
68 return {};
69 auto buffer = ByteBuffer::create_uninitialized(max_size);
70 auto* buffer_ptr = (char*)buffer.data();
71 size_t remaining_buffer_space = buffer.size();
72 size_t taken_from_buffered = 0;
73 if (!m_buffered_data.is_empty()) {
74 taken_from_buffered = min(remaining_buffer_space, m_buffered_data.size());
75 memcpy(buffer_ptr, m_buffered_data.data(), taken_from_buffered);
76 Vector<u8> new_buffered_data;
77 new_buffered_data.append(m_buffered_data.data() + taken_from_buffered, m_buffered_data.size() - taken_from_buffered);
78 m_buffered_data = move(new_buffered_data);
79 remaining_buffer_space -= taken_from_buffered;
80 buffer_ptr += taken_from_buffered;
81 }
82 if (!remaining_buffer_space)
83 return buffer;
84 int nread = ::read(m_fd, buffer_ptr, remaining_buffer_space);
85 if (nread < 0) {
86 if (taken_from_buffered) {
87 buffer.trim(taken_from_buffered);
88 return buffer;
89 }
90 set_error(errno);
91 return {};
92 }
93 if (nread == 0) {
94 set_eof(true);
95 if (taken_from_buffered) {
96 buffer.trim(taken_from_buffered);
97 return buffer;
98 }
99 return {};
100 }
101 buffer.trim(taken_from_buffered + nread);
102 return buffer;
103}
104
105bool IODevice::can_read_from_fd() const
106{
107 // FIXME: Can we somehow remove this once CSocket is implemented using non-blocking sockets?
108 fd_set rfds;
109 FD_ZERO(&rfds);
110 FD_SET(m_fd, &rfds);
111 struct timeval timeout {
112 0, 0
113 };
114 int rc = Core::safe_syscall(select, m_fd + 1, &rfds, nullptr, nullptr, &timeout);
115 if (rc < 0) {
116 // NOTE: We don't set m_error here.
117 perror("IODevice::can_read: select");
118 return false;
119 }
120 return FD_ISSET(m_fd, &rfds);
121}
122
123bool IODevice::can_read_line()
124{
125 if (m_eof && !m_buffered_data.is_empty())
126 return true;
127 if (m_buffered_data.contains_slow('\n'))
128 return true;
129 if (!can_read_from_fd())
130 return false;
131 populate_read_buffer();
132 return m_buffered_data.contains_slow('\n');
133}
134
135bool IODevice::can_read() const
136{
137 return !m_buffered_data.is_empty() || can_read_from_fd();
138}
139
140ByteBuffer IODevice::read_all()
141{
142 off_t file_size = 0;
143 struct stat st;
144 int rc = fstat(fd(), &st);
145 if (rc == 0)
146 file_size = st.st_size;
147
148 Vector<u8> data;
149 data.ensure_capacity(file_size);
150
151 if (!m_buffered_data.is_empty()) {
152 data.append(m_buffered_data.data(), m_buffered_data.size());
153 m_buffered_data.clear();
154 }
155
156 while (true) {
157 char read_buffer[4096];
158 int nread = ::read(m_fd, read_buffer, sizeof(read_buffer));
159 if (nread < 0) {
160 set_error(errno);
161 break;
162 }
163 if (nread == 0) {
164 set_eof(true);
165 break;
166 }
167 data.append((const u8*)read_buffer, nread);
168 }
169 if (data.is_empty())
170 return {};
171 return ByteBuffer::copy(data.data(), data.size());
172}
173
174ByteBuffer IODevice::read_line(size_t max_size)
175{
176 if (m_fd < 0)
177 return {};
178 if (!max_size)
179 return {};
180 if (!can_read_line())
181 return {};
182 if (m_eof) {
183 if (m_buffered_data.size() > max_size) {
184 dbgprintf("IODevice::read_line: At EOF but there's more than max_size(%d) buffered\n", max_size);
185 return {};
186 }
187 auto buffer = ByteBuffer::copy(m_buffered_data.data(), m_buffered_data.size());
188 m_buffered_data.clear();
189 return buffer;
190 }
191 auto line = ByteBuffer::create_uninitialized(max_size + 1);
192 size_t line_index = 0;
193 while (line_index < max_size) {
194 u8 ch = m_buffered_data[line_index];
195 line[line_index++] = ch;
196 if (ch == '\n') {
197 Vector<u8> new_buffered_data;
198 new_buffered_data.append(m_buffered_data.data() + line_index, m_buffered_data.size() - line_index);
199 m_buffered_data = move(new_buffered_data);
200 line[line_index] = '\0';
201 line.trim(line_index + 1);
202 return line;
203 }
204 }
205 return {};
206}
207
208bool IODevice::populate_read_buffer()
209{
210 if (m_fd < 0)
211 return false;
212 u8 buffer[1024];
213 int nread = ::read(m_fd, buffer, sizeof(buffer));
214 if (nread < 0) {
215 set_error(errno);
216 return false;
217 }
218 if (nread == 0) {
219 set_eof(true);
220 return false;
221 }
222 m_buffered_data.append(buffer, nread);
223 return true;
224}
225
226bool IODevice::close()
227{
228 if (fd() < 0 || mode() == NotOpen)
229 return false;
230 int rc = ::close(fd());
231 if (rc < 0) {
232 set_error(errno);
233 return false;
234 }
235 set_fd(-1);
236 set_mode(IODevice::NotOpen);
237 return true;
238}
239
240bool IODevice::seek(i64 offset, SeekMode mode, off_t* pos)
241{
242 int m = SEEK_SET;
243 switch (mode) {
244 case SeekMode::SetPosition:
245 m = SEEK_SET;
246 break;
247 case SeekMode::FromCurrentPosition:
248 m = SEEK_CUR;
249 break;
250 case SeekMode::FromEndPosition:
251 m = SEEK_END;
252 break;
253 }
254 off_t rc = lseek(m_fd, offset, m);
255 if (rc < 0) {
256 set_error(errno);
257 if (pos)
258 *pos = -1;
259 return false;
260 }
261 m_buffered_data.clear();
262 m_eof = false;
263 if (pos)
264 *pos = rc;
265 return true;
266}
267
268bool IODevice::write(const u8* data, int size)
269{
270 int rc = ::write(m_fd, data, size);
271 if (rc < 0) {
272 perror("IODevice::write: write");
273 set_error(errno);
274 return false;
275 }
276 return rc == size;
277}
278
279int IODevice::printf(const char* format, ...)
280{
281 va_list ap;
282 va_start(ap, format);
283 // FIXME: We're not propagating write() failures to client here!
284 int ret = printf_internal([this](char*&, char ch) {
285 write((const u8*)&ch, 1);
286 },
287 nullptr, format, ap);
288 va_end(ap);
289 return ret;
290}
291
292void IODevice::set_fd(int fd)
293{
294 if (m_fd == fd)
295 return;
296
297 m_fd = fd;
298 did_update_fd(fd);
299}
300
301bool IODevice::write(const StringView& v)
302{
303 return write((const u8*)v.characters_without_null_termination(), v.length());
304}
305
306}