Serenity Operating System
at master 323 lines 7.7 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * Copyright (c) 2022, the SerenityOS developers. 4 * 5 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8#include <AK/ByteBuffer.h> 9#include <LibCore/IODevice.h> 10#include <errno.h> 11#include <stdio.h> 12#include <string.h> 13#include <sys/select.h> 14#include <sys/stat.h> 15#include <sys/time.h> 16#include <unistd.h> 17 18namespace Core { 19 20IODevice::IODevice(Object* parent) 21 : Object(parent) 22{ 23} 24 25char const* IODevice::error_string() const 26{ 27 return strerror(m_error); 28} 29 30int IODevice::read(u8* buffer, int length) 31{ 32 auto read_buffer = read(length); 33 memcpy(buffer, read_buffer.data(), length); 34 return read_buffer.size(); 35} 36 37ByteBuffer IODevice::read(size_t max_size) 38{ 39 if (m_fd < 0) 40 return {}; 41 if (!max_size) 42 return {}; 43 44 if (m_buffered_data.size() < max_size) 45 populate_read_buffer(max(max_size - m_buffered_data.size(), 1024)); 46 47 auto size = min(max_size, m_buffered_data.size()); 48 auto buffer_result = ByteBuffer::create_uninitialized(size); 49 if (buffer_result.is_error()) { 50 dbgln("IODevice::read: Not enough memory to allocate a buffer of {} bytes", size); 51 return {}; 52 } 53 auto buffer = buffer_result.release_value(); 54 auto* buffer_ptr = (char*)buffer.data(); 55 56 memcpy(buffer_ptr, m_buffered_data.data(), size); 57 m_buffered_data.remove(0, size); 58 59 return buffer; 60} 61 62bool IODevice::can_read_from_fd() const 63{ 64 // FIXME: Can we somehow remove this once Core::Socket is implemented using non-blocking sockets? 65 fd_set rfds {}; 66 FD_ZERO(&rfds); 67 FD_SET(m_fd, &rfds); 68 struct timeval timeout { 69 0, 0 70 }; 71 72 for (;;) { 73 if (select(m_fd + 1, &rfds, nullptr, nullptr, &timeout) < 0) { 74 if (errno == EINTR) 75 continue; 76 perror("IODevice::can_read_from_fd: select"); 77 return false; 78 } 79 break; 80 } 81 return FD_ISSET(m_fd, &rfds); 82} 83 84bool IODevice::can_read_line() const 85{ 86 if (m_eof && !m_buffered_data.is_empty()) 87 return true; 88 89 if (m_buffered_data.contains_slow('\n')) 90 return true; 91 92 if (!can_read_from_fd()) 93 return false; 94 95 while (true) { 96 // Populate buffer until a newline is found or we reach EOF. 97 98 auto previous_buffer_size = m_buffered_data.size(); 99 populate_read_buffer(); 100 auto new_buffer_size = m_buffered_data.size(); 101 102 if (m_error) 103 return false; 104 105 if (m_eof) 106 return !m_buffered_data.is_empty(); 107 108 if (m_buffered_data.contains_in_range('\n', previous_buffer_size, new_buffer_size - 1)) 109 return true; 110 } 111} 112 113bool IODevice::can_read() const 114{ 115 return !m_buffered_data.is_empty() || can_read_from_fd(); 116} 117 118ByteBuffer IODevice::read_all() 119{ 120 off_t file_size = 0; 121 struct stat st; 122 int rc = fstat(fd(), &st); 123 if (rc == 0) 124 file_size = st.st_size; 125 126 Vector<u8> data; 127 data.ensure_capacity(file_size); 128 129 if (!m_buffered_data.is_empty()) { 130 data.append(m_buffered_data.data(), m_buffered_data.size()); 131 m_buffered_data.clear(); 132 } 133 134 while (true) { 135 char read_buffer[4096]; 136 int nread = ::read(m_fd, read_buffer, sizeof(read_buffer)); 137 if (nread < 0) { 138 set_error(errno); 139 break; 140 } 141 if (nread == 0) { 142 set_eof(true); 143 break; 144 } 145 data.append((u8 const*)read_buffer, nread); 146 } 147 148 auto result = ByteBuffer::copy(data); 149 if (!result.is_error()) 150 return result.release_value(); 151 152 set_error(ENOMEM); 153 return {}; 154} 155 156DeprecatedString IODevice::read_line(size_t max_size) 157{ 158 if (m_fd < 0) 159 return {}; 160 if (!max_size) 161 return {}; 162 if (!can_read_line()) 163 return {}; 164 if (m_eof) { 165 if (m_buffered_data.size() > max_size) { 166 dbgln("IODevice::read_line: At EOF but there's more than max_size({}) buffered", max_size); 167 return {}; 168 } 169 auto line = DeprecatedString((char const*)m_buffered_data.data(), m_buffered_data.size(), Chomp); 170 m_buffered_data.clear(); 171 return line; 172 } 173 auto line_result = ByteBuffer::create_uninitialized(max_size + 1); 174 if (line_result.is_error()) { 175 dbgln("IODevice::read_line: Not enough memory to allocate a buffer of {} bytes", max_size + 1); 176 return {}; 177 } 178 auto line = line_result.release_value(); 179 size_t line_index = 0; 180 while (line_index < max_size) { 181 u8 ch = m_buffered_data[line_index]; 182 line[line_index++] = ch; 183 if (ch == '\n') { 184 Vector<u8> new_buffered_data; 185 new_buffered_data.append(m_buffered_data.data() + line_index, m_buffered_data.size() - line_index); 186 m_buffered_data = move(new_buffered_data); 187 line.resize(line_index); 188 return DeprecatedString::copy(line, Chomp); 189 } 190 } 191 return {}; 192} 193 194bool IODevice::populate_read_buffer(size_t size) const 195{ 196 if (m_fd < 0) 197 return false; 198 if (!size) 199 return false; 200 201 auto buffer_result = ByteBuffer::create_uninitialized(size); 202 if (buffer_result.is_error()) { 203 dbgln("IODevice::populate_read_buffer: Not enough memory to allocate a buffer of {} bytes", size); 204 return {}; 205 } 206 auto buffer = buffer_result.release_value(); 207 auto* buffer_ptr = (char*)buffer.data(); 208 209 int nread = ::read(m_fd, buffer_ptr, size); 210 if (nread < 0) { 211 set_error(errno); 212 return false; 213 } 214 if (nread == 0) { 215 set_eof(true); 216 return false; 217 } 218 m_buffered_data.append(buffer.data(), nread); 219 return true; 220} 221 222bool IODevice::close() 223{ 224 if (fd() < 0 || m_mode == OpenMode::NotOpen) 225 return false; 226 int rc = ::close(fd()); 227 if (rc < 0) { 228 set_error(errno); 229 return false; 230 } 231 set_fd(-1); 232 set_mode(OpenMode::NotOpen); 233 return true; 234} 235 236bool IODevice::seek(i64 offset, SeekMode mode, off_t* pos) 237{ 238 int m = SEEK_SET; 239 switch (mode) { 240 case SeekMode::SetPosition: 241 m = SEEK_SET; 242 break; 243 case SeekMode::FromCurrentPosition: 244 m = SEEK_CUR; 245 offset -= m_buffered_data.size(); 246 break; 247 case SeekMode::FromEndPosition: 248 m = SEEK_END; 249 break; 250 } 251 off_t rc = lseek(m_fd, offset, m); 252 if (rc < 0) { 253 set_error(errno); 254 if (pos) 255 *pos = -1; 256 return false; 257 } 258 m_buffered_data.clear(); 259 m_eof = false; 260 if (pos) 261 *pos = rc; 262 return true; 263} 264 265bool IODevice::truncate(off_t size) 266{ 267 int rc = ftruncate(m_fd, size); 268 if (rc < 0) { 269 set_error(errno); 270 return false; 271 } 272 return true; 273} 274 275bool IODevice::write(u8 const* data, int size) 276{ 277 int rc = ::write(m_fd, data, size); 278 if (rc < 0) { 279 set_error(errno); 280 perror("IODevice::write: write"); 281 return false; 282 } 283 return rc == size; 284} 285 286void IODevice::set_fd(int fd) 287{ 288 if (m_fd == fd) 289 return; 290 291 m_fd = fd; 292 did_update_fd(fd); 293} 294 295bool IODevice::write(StringView v) 296{ 297 return write((u8 const*)v.characters_without_null_termination(), v.length()); 298} 299 300LineIterator::LineIterator(IODevice& device, bool is_end) 301 : m_device(device) 302 , m_is_end(is_end) 303{ 304 if (!m_is_end) { 305 ++*this; 306 } 307} 308 309bool LineIterator::at_end() const 310{ 311 return m_device->eof(); 312} 313 314LineIterator& LineIterator::operator++() 315{ 316 m_buffer = m_device->read_line(); 317 return *this; 318} 319 320LineIterator LineRange::begin() { return m_device.line_begin(); } 321LineIterator LineRange::end() { return m_device.line_end(); } 322 323}