Serenity Operating System
at master 132 lines 3.6 kB view raw
1/* 2 * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org> 3 * Copyright (c) 2021, sin-ack <sin-ack@protonmail.com> 4 * 5 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8#include <AK/ByteBuffer.h> 9#include <AK/Format.h> 10#include <AK/Stream.h> 11 12namespace AK { 13 14ErrorOr<void> Stream::read_until_filled(Bytes buffer) 15{ 16 size_t nread = 0; 17 while (nread < buffer.size()) { 18 if (is_eof()) 19 return Error::from_string_view_or_print_error_and_return_errno("Reached end-of-file before filling the entire buffer"sv, EIO); 20 21 auto result = read_some(buffer.slice(nread)); 22 if (result.is_error()) { 23 if (result.error().is_errno() && result.error().code() == EINTR) { 24 continue; 25 } 26 27 return result.release_error(); 28 } 29 30 nread += result.value().size(); 31 } 32 33 return {}; 34} 35 36ErrorOr<ByteBuffer> Stream::read_until_eof(size_t block_size) 37{ 38 return read_until_eof_impl(block_size); 39} 40 41ErrorOr<ByteBuffer> Stream::read_until_eof_impl(size_t block_size, size_t expected_file_size) 42{ 43 ByteBuffer data; 44 data.ensure_capacity(expected_file_size); 45 46 size_t total_read = 0; 47 Bytes buffer; 48 while (!is_eof()) { 49 if (buffer.is_empty()) { 50 buffer = TRY(data.get_bytes_for_writing(block_size)); 51 } 52 53 auto nread = TRY(read_some(buffer)).size(); 54 total_read += nread; 55 buffer = buffer.slice(nread); 56 } 57 58 data.resize(total_read); 59 return data; 60} 61 62ErrorOr<void> Stream::discard(size_t discarded_bytes) 63{ 64 // Note: This was chosen arbitrarily. 65 // Note: This can't be PAGE_SIZE because it is defined to sysconf() on Lagom. 66 constexpr size_t continuous_read_size = 4096; 67 68 Array<u8, continuous_read_size> buffer; 69 70 while (discarded_bytes > 0) { 71 if (is_eof()) 72 return Error::from_string_view_or_print_error_and_return_errno("Reached end-of-file before reading all discarded bytes"sv, EIO); 73 74 auto slice = TRY(read_some(buffer.span().slice(0, min(discarded_bytes, continuous_read_size)))); 75 discarded_bytes -= slice.size(); 76 } 77 78 return {}; 79} 80 81ErrorOr<void> Stream::write_until_depleted(ReadonlyBytes buffer) 82{ 83 size_t nwritten = 0; 84 while (nwritten < buffer.size()) { 85 auto result = write_some(buffer.slice(nwritten)); 86 if (result.is_error()) { 87 if (result.error().is_errno() && result.error().code() == EINTR) { 88 continue; 89 } 90 91 return result.release_error(); 92 } 93 94 nwritten += result.value(); 95 } 96 97 return {}; 98} 99 100ErrorOr<size_t> SeekableStream::tell() const 101{ 102 // Seek with 0 and SEEK_CUR does not modify anything despite the const_cast, 103 // so it's safe to do this. 104 return const_cast<SeekableStream*>(this)->seek(0, SeekMode::FromCurrentPosition); 105} 106 107ErrorOr<size_t> SeekableStream::size() 108{ 109 auto original_position = TRY(tell()); 110 111 auto seek_result = seek(0, SeekMode::FromEndPosition); 112 if (seek_result.is_error()) { 113 // Let's try to restore the original position, just in case. 114 auto restore_result = seek(original_position, SeekMode::SetPosition); 115 if (restore_result.is_error()) { 116 dbgln("SeekableStream::size: Couldn't restore initial position, stream might have incorrect position now!"); 117 } 118 119 return seek_result.release_error(); 120 } 121 122 TRY(seek(original_position, SeekMode::SetPosition)); 123 return seek_result.value(); 124} 125 126ErrorOr<void> SeekableStream::discard(size_t discarded_bytes) 127{ 128 TRY(seek(discarded_bytes, SeekMode::FromCurrentPosition)); 129 return {}; 130} 131 132}