Serenity Operating System
at portability 306 lines 8.3 kB view raw
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}