Remove C++ I/O streams

This commit is contained in:
topjohnwu 2025-05-01 11:04:23 -07:00 committed by John Wu
parent 78d1200608
commit dc0acea47c
8 changed files with 20 additions and 362 deletions

View File

@ -18,7 +18,6 @@ LOCAL_SRC_FILES := \
files.cpp \
misc.cpp \
logging.cpp \
stream.cpp \
base-rs.cpp \
../external/cxx-rs/src/cxx.cc
include $(BUILD_STATIC_LIBRARY)

View File

@ -1,129 +0,0 @@
#pragma once
#include <sys/uio.h>
#include <cstdio>
#include <memory>
#include "../files.hpp"
#define ENABLE_IOV 0
struct out_stream {
virtual bool write(const void *buf, size_t len) = 0;
#if ENABLE_IOV
virtual ssize_t writev(const iovec *iov, int iovcnt);
#endif
virtual ~out_stream() = default;
};
using out_strm_ptr = std::unique_ptr<out_stream>;
// Delegates all operations to base stream
class filter_out_stream : public out_stream {
public:
filter_out_stream(out_strm_ptr &&base) : base(std::move(base)) {}
bool write(const void *buf, size_t len) override;
protected:
out_strm_ptr base;
};
// Buffered output stream, writing in chunks
class chunk_out_stream : public filter_out_stream {
public:
chunk_out_stream(out_strm_ptr &&base, size_t buf_sz, size_t chunk_sz)
: filter_out_stream(std::move(base)), chunk_sz(chunk_sz), data(buf_sz) {}
chunk_out_stream(out_strm_ptr &&base, size_t buf_sz = 4096)
: chunk_out_stream(std::move(base), buf_sz, buf_sz) {}
bool write(const void *buf, size_t len) final;
protected:
// Classes inheriting this class has to call finalize() in its destructor
void finalize();
virtual bool write_chunk(const void *buf, size_t len, bool final);
size_t chunk_sz;
private:
size_t buf_off = 0;
heap_data data;
};
struct in_stream {
virtual ssize_t read(void *buf, size_t len) = 0;
ssize_t readFully(void *buf, size_t len);
#if ENABLE_IOV
virtual ssize_t readv(const iovec *iov, int iovcnt);
#endif
virtual ~in_stream() = default;
};
// A stream is something that is writable and readable
struct stream : public out_stream, public in_stream {};
using stream_ptr = std::unique_ptr<stream>;
// Byte stream that dynamically allocates memory
class byte_stream : public stream {
public:
byte_stream(heap_data &data) : _data(data) {}
ssize_t read(void *buf, size_t len) override;
bool write(const void *buf, size_t len) override;
private:
heap_data &_data;
size_t _pos = 0;
size_t _cap = 0;
void resize(size_t new_sz, bool zero = false);
};
class rust_vec_stream : public stream {
public:
rust_vec_stream(rust::Vec<uint8_t> &data) : _data(data) {}
ssize_t read(void *buf, size_t len) override;
bool write(const void *buf, size_t len) override;
private:
rust::Vec<uint8_t> &_data;
size_t _pos = 0;
void ensure_size(size_t sz, bool zero = false);
};
class file_stream : public stream {
public:
bool write(const void *buf, size_t len) final;
protected:
virtual ssize_t do_write(const void *buf, size_t len) = 0;
};
// File stream but does not close the file descriptor at any time
class fd_stream : public file_stream {
public:
fd_stream(int fd) : fd(fd) {}
ssize_t read(void *buf, size_t len) override;
#if ENABLE_IOV
ssize_t readv(const iovec *iov, int iovcnt) override;
ssize_t writev(const iovec *iov, int iovcnt) override;
#endif
protected:
ssize_t do_write(const void *buf, size_t len) override;
private:
int fd;
};
/* ****************************************
* Bridge between stream class and C stdio
* ****************************************/
// stream_ptr -> sFILE
sFILE make_stream_fp(stream_ptr &&strm);
template <class T, class... Args>
sFILE make_stream_fp(Args &&... args) {
return make_stream_fp(stream_ptr(new T(std::forward<Args>(args)...)));
}

View File

@ -58,7 +58,6 @@ pub mod ffi {
fn set_log_level_state_cxx(level: LogLevelCxx, enabled: bool);
fn exit_on_error(b: bool);
fn cmdline_logging();
fn resize_vec(vec: &mut Vec<u8>, size: usize);
}
#[namespace = "rust"]
@ -80,12 +79,3 @@ fn set_log_level_state_cxx(level: ffi::LogLevelCxx, enabled: bool) {
set_log_level_state(level, enabled)
}
}
fn resize_vec(vec: &mut Vec<u8>, size: usize) {
if size > vec.len() {
vec.reserve(size - vec.len());
}
unsafe {
vec.set_len(size);
}
}

View File

@ -147,17 +147,12 @@ struct byte_data : public byte_view {
rust::Vec<size_t> patch(byte_view from, byte_view to);
};
class byte_stream;
struct heap_data : public byte_data {
ALLOW_MOVE_ONLY(heap_data)
heap_data() = default;
explicit heap_data(size_t sz) : byte_data(calloc(sz, 1), sz) {}
~heap_data() { free(_buf); }
// byte_stream needs to reallocate the internal buffer
friend byte_stream;
};
struct owned_fd {

View File

@ -1,201 +0,0 @@
#include <unistd.h>
#include <cstddef>
#include <base.hpp>
#include <stream.hpp>
using namespace std;
static int strm_read(void *v, char *buf, int len) {
auto strm = static_cast<stream *>(v);
return strm->read(buf, len);
}
static int strm_write(void *v, const char *buf, int len) {
auto strm = static_cast<stream *>(v);
if (!strm->write(buf, len))
return -1;
return len;
}
static int strm_close(void *v) {
auto strm = static_cast<stream *>(v);
delete strm;
return 0;
}
sFILE make_stream_fp(stream_ptr &&strm) {
auto fp = make_file(funopen(strm.release(), strm_read, strm_write, nullptr, strm_close));
setbuf(fp.get(), nullptr);
return fp;
}
ssize_t in_stream::readFully(void *buf, size_t len) {
size_t read_sz = 0;
ssize_t ret;
do {
ret = read((byte *) buf + read_sz, len - read_sz);
if (ret < 0) {
if (errno == EINTR)
continue;
return ret;
}
read_sz += ret;
} while (read_sz != len && ret != 0);
return read_sz;
}
bool filter_out_stream::write(const void *buf, size_t len) {
return base->write(buf, len);
}
bool chunk_out_stream::write(const void *_in, size_t len) {
auto in = static_cast<const uint8_t *>(_in);
while (len) {
if (buf_off + len >= chunk_sz) {
// Enough input for a chunk
const uint8_t *src;
if (buf_off) {
src = data.buf();
auto copy = chunk_sz - buf_off;
memcpy(data.buf() + buf_off, in, copy);
in += copy;
len -= copy;
buf_off = 0;
} else {
src = in;
in += chunk_sz;
len -= chunk_sz;
}
if (!write_chunk(src, chunk_sz, false))
return false;
} else {
// Buffer internally
memcpy(data.buf() + buf_off, in, len);
buf_off += len;
break;
}
}
return true;
}
bool chunk_out_stream::write_chunk(const void *buf, size_t len, bool) {
return base->write(buf, len);
}
void chunk_out_stream::finalize() {
if (buf_off) {
if (!write_chunk(data.buf(), buf_off, true)) {
LOGE("Error in finalize, file truncated\n");
}
buf_off = 0;
}
}
ssize_t byte_stream::read(void *buf, size_t len) {
len = std::min((size_t) len, _data._sz- _pos);
memcpy(buf, _data.buf() + _pos, len);
_pos += len;
return len;
}
bool byte_stream::write(const void *buf, size_t len) {
resize(_pos + len);
memcpy(_data.buf() + _pos, buf, len);
_pos += len;
_data._sz= std::max(_data.sz(), _pos);
return true;
}
void byte_stream::resize(size_t new_sz, bool zero) {
bool resize = false;
size_t old_cap = _cap;
while (new_sz > _cap) {
_cap = _cap ? (_cap << 1) - (_cap >> 1) : 1 << 12;
resize = true;
}
if (resize) {
_data._buf = static_cast<uint8_t *>(::realloc(_data._buf, _cap));
if (zero)
memset(_data.buf() + old_cap, 0, _cap - old_cap);
}
}
ssize_t rust_vec_stream::read(void *buf, size_t len) {
len = std::min<size_t>(len, _data.size() - _pos);
memcpy(buf, _data.data() + _pos, len);
_pos += len;
return len;
}
bool rust_vec_stream::write(const void *buf, size_t len) {
ensure_size(_pos + len);
memcpy(_data.data() + _pos, buf, len);
_pos += len;
return true;
}
void rust_vec_stream::ensure_size(size_t sz, bool zero) {
size_t old_sz = _data.size();
if (sz > old_sz) {
resize_vec(_data, sz);
if (zero)
memset(_data.data() + old_sz, 0, sz - old_sz);
}
}
ssize_t fd_stream::read(void *buf, size_t len) {
return ::read(fd, buf, len);
}
ssize_t fd_stream::do_write(const void *buf, size_t len) {
return ::write(fd, buf, len);
}
bool file_stream::write(const void *buf, size_t len) {
size_t write_sz = 0;
ssize_t ret;
do {
ret = do_write((byte *) buf + write_sz, len - write_sz);
if (ret < 0) {
if (errno == EINTR)
continue;
return false;
}
write_sz += ret;
} while (write_sz != len && ret != 0);
return true;
}
#if ENABLE_IOV
ssize_t in_stream::readv(const iovec *iov, int iovcnt) {
size_t read_sz = 0;
for (int i = 0; i < iovcnt; ++i) {
auto ret = readFully(iov[i].iov_base, iov[i].iov_len);
if (ret < 0)
return ret;
read_sz += ret;
}
return read_sz;
}
ssize_t out_stream::writev(const iovec *iov, int iovcnt) {
size_t write_sz = 0;
for (int i = 0; i < iovcnt; ++i) {
if (!write(iov[i].iov_base, iov[i].iov_len))
return write_sz;
write_sz += iov[i].iov_len;
}
return write_sz;
}
ssize_t fd_stream::readv(const iovec *iov, int iovcnt) {
return ::readv(fd, iov, iovcnt);
}
ssize_t fd_stream::writev(const iovec *iov, int iovcnt) {
return ::writev(fd, iov, iovcnt);
}
#endif // ENABLE_IOV

View File

@ -10,7 +10,6 @@
#ifdef __cplusplus
#include <base.hpp>
#include <stream.hpp>
#include <sepolicy.hpp>
#include "init-rs.hpp"

View File

@ -17,7 +17,7 @@ static vector<string> rc_list;
#define NEW_INITRC_DIR "/system/etc/init/hw"
#define INIT_RC "init.rc"
static bool unxz(out_stream &strm, rust::Slice<const uint8_t> bytes) {
static bool unxz(int fd, rust::Slice<const uint8_t> bytes) {
uint8_t out[8192];
xz_crc32_init();
size_t size = bytes.size();
@ -36,7 +36,7 @@ static bool unxz(out_stream &strm, rust::Slice<const uint8_t> bytes) {
ret = xz_dec_run(dec, &b);
if (ret != XZ_OK && ret != XZ_STREAM_END)
return false;
strm.write(out, b.out_pos);
write(fd, out, b.out_pos);
b.out_pos = 0;
} while (b.in_pos != size);
return true;
@ -241,24 +241,21 @@ static void extract_files(bool sbin) {
mmap_data magisk(magisk_xz);
unlink(magisk_xz);
int fd = xopen("magisk", O_WRONLY | O_CREAT, 0755);
fd_stream ch(fd);
unxz(ch, magisk);
unxz(fd, magisk);
close(fd);
}
if (access(stub_xz, F_OK) == 0) {
mmap_data stub(stub_xz);
unlink(stub_xz);
int fd = xopen("stub.apk", O_WRONLY | O_CREAT, 0);
fd_stream ch(fd);
unxz(ch, stub);
unxz(fd, stub);
close(fd);
}
if (access(init_ld_xz, F_OK) == 0) {
mmap_data init_ld(init_ld_xz);
unlink(init_ld_xz);
int fd = xopen("init-ld", O_WRONLY | O_CREAT, 0);
fd_stream ch(fd);
unxz(ch, init_ld);
unxz(fd, init_ld);
close(fd);
}
}
@ -407,8 +404,7 @@ int magisk_proxy_main(int, char *argv[]) {
static void unxz_init(const char *init_xz, const char *init) {
LOGD("unxz %s -> %s\n", init_xz, init);
int fd = xopen(init, O_WRONLY | O_CREAT, 0777);
fd_stream ch(fd);
unxz(ch, mmap_data{init_xz});
unxz(fd, mmap_data{init_xz});
close(fd);
clone_attr(init_xz, init);
unlink(init_xz);

View File

@ -8,8 +8,8 @@
#include <cil/cil.h>
#include <base.hpp>
#include <stream.hpp>
using namespace std;
#define SHALEN 64
static bool cmp_sha256(const char *a, const char *b) {
@ -230,20 +230,29 @@ sepol_impl::~sepol_impl() {
free(db);
}
static int vec_write(void *v, const char *buf, int len) {
auto vec = static_cast<vector<char> *>(v);
vec->insert(vec->end(), buf, buf + len);
return len;
}
bool SePolicy::to_file(::rust::Utf8CStr file) const noexcept {
// No partial writes are allowed to /sys/fs/selinux/load, thus the reason why we
// first dump everything into memory, then directly call write system call
heap_data data;
auto fp = make_stream_fp<byte_stream>(data);
vector<char> out;
FILE *fp = funopen(&out, nullptr, vec_write, nullptr, nullptr);
// Since we're directly writing to memory, disable buffering
setbuf(fp, nullptr);
policy_file_t pf;
policy_file_init(&pf);
pf.type = PF_USE_STDIO;
pf.fp = fp.get();
pf.fp = fp;
if (policydb_write(impl->db, &pf)) {
LOGE("Fail to create policy image\n");
return false;
}
fclose(fp);
int fd = xopen(file.data(), O_WRONLY | O_CREAT | O_CLOEXEC, 0644);
if (fd < 0)
@ -251,7 +260,7 @@ bool SePolicy::to_file(::rust::Utf8CStr file) const noexcept {
if (struct stat st{}; xfstat(fd, &st) == 0 && st.st_size > 0) {
ftruncate(fd, 0);
}
xwrite(fd, data.buf(), data.sz());
xwrite(fd, out.data(), out.size());
close(fd);
return true;