Files
RedBear-OS/local/patches/relibc/P3-open-memstream.patch.bak
vasilito 5851974b20 feat: build system transition to release fork + archive hardening
Release fork infrastructure:
- REDBEAR_RELEASE=0.1.1 with offline enforcement (fetch/distclean/unfetch blocked)
- 195 BLAKE3-verified source archives in standard format
- Atomic provisioning via provision-release.sh (staging + .complete sentry)
- 5-phase improvement plan: restore format auto-detection, source tree
  validation (validate-source-trees.py), archive-map.json, REPO_BINARY fallback

Archive normalization:
- Removed 87 duplicate/unversioned archives from shared pool
- Regenerated all archives in consistent format with source/ + recipe.toml
- BLAKE3SUMS and manifest.json generated from stable tarball set

Patch management:
- verify-patches.sh: pre-sync dry-run report (OK/REVERSED/CONFLICT)
- 121 upstream-absorbed patches moved to absorbed/ directories
- 43 active patches verified clean against rebased sources
- Stress test: base updated to upstream HEAD, relibc reset and patched

Compilation fixes:
- relibc: Vec imports in redox-rt (proc.rs, lib.rs, sys.rs)
- relibc: unsafe from_raw_parts in mod.rs (2024 edition)
- fetch.rs: rev comparison handles short/full hash prefixes
- kibi recipe: corrected rev mismatch

New scripts: restore-sources.sh, provision-release.sh, verify-sources-archived.sh,
check-upstream-releases.sh, validate-source-trees.py, verify-patches.sh,
repair-archive-format.sh, generate-manifest.py

Documentation: AGENTS.md, README.md, local/AGENTS.md updated for release fork model
2026-05-02 01:41:17 +01:00

182 lines
4.7 KiB
Plaintext

diff --git a/src/header/stdio/mod.rs b/src/header/stdio/mod.rs
--- a/src/header/stdio/mod.rs
+++ b/src/header/stdio/mod.rs
@@ -46,4 +46,7 @@
pub use self::getdelim::*;
mod getdelim;
+pub use self::open_memstream::*;
+mod open_memstream;
+
mod ext;
diff --git a/src/header/stdio/open_memstream.rs b/src/header/stdio/open_memstream.rs
new file mode 100644
--- /dev/null
+++ b/src/header/stdio/open_memstream.rs
@@ -0,0 +1,124 @@
+use alloc::{boxed::Box, vec, vec::Vec};
+use core::ptr;
+
+use super::{
+ Buffer, FILE,
+ constants::{BUFSIZ, F_NORD},
+};
+use crate::{
+ error::{Errno, ResultExtPtrMut},
+ fs::File,
+ header::{
+ errno::{EFAULT, ENOMEM},
+ fcntl, pthread, stdlib, unistd,
+ },
+ io::{self, BufWriter, Write},
+ platform::{
+ ERRNO,
+ types::{c_char, size_t},
+ },
+};
+
+struct MemstreamWriter {
+ bufp: *mut *mut c_char,
+ sizep: *mut size_t,
+ current: *mut c_char,
+ buffer: Vec<u8>,
+}
+
+unsafe impl Send for MemstreamWriter {}
+
+impl MemstreamWriter {
+ fn new(bufp: *mut *mut c_char, sizep: *mut size_t) -> Self {
+ Self {
+ bufp,
+ sizep,
+ current: ptr::null_mut(),
+ buffer: Vec::new(),
+ }
+ }
+
+ fn sync_output(&mut self) -> io::Result<()> {
+ let size = self.buffer.len();
+ let alloc_size = size
+ .checked_add(1)
+ .ok_or_else(|| io::Error::from_raw_os_error(ENOMEM))?;
+
+ let raw = if self.current.is_null() {
+ unsafe { stdlib::malloc(alloc_size) }
+ } else {
+ unsafe { stdlib::realloc(self.current.cast(), alloc_size) }
+ };
+ if raw.is_null() {
+ return Err(io::Error::from_raw_os_error(ENOMEM));
+ }
+
+ let raw = raw.cast::<c_char>();
+ if size != 0 {
+ unsafe { ptr::copy_nonoverlapping(self.buffer.as_ptr(), raw.cast::<u8>(), size) };
+ }
+ unsafe {
+ *raw.add(size) = 0;
+ *self.bufp = raw;
+ *self.sizep = size;
+ }
+ self.current = raw;
+ Ok(())
+ }
+}
+
+impl Write for MemstreamWriter {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ self.buffer
+ .try_reserve(buf.len())
+ .map_err(|_| io::Error::from_raw_os_error(ENOMEM))?;
+ self.buffer.extend_from_slice(buf);
+ Ok(buf.len())
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ self.sync_output()
+ }
+}
+
+fn create_memstream(bufp: *mut *mut c_char, sizep: *mut size_t) -> Result<Box<FILE>, Errno> {
+ if bufp.is_null() || sizep.is_null() {
+ return Err(Errno(EFAULT));
+ }
+
+ unsafe {
+ *bufp = ptr::null_mut();
+ *sizep = 0;
+ }
+
+ let mut fds = [0; 2];
+ if unsafe { unistd::pipe2(fds.as_mut_ptr(), fcntl::O_CLOEXEC) } != 0 {
+ return Err(Errno(ERRNO.get()));
+ }
+ let _ = unistd::close(fds[0]);
+
+ let file = File::new(fds[1]);
+ let writer = Box::new(BufWriter::new(MemstreamWriter::new(bufp, sizep)));
+ let mutex_attr = pthread::RlctMutexAttr {
+ ty: pthread::PTHREAD_MUTEX_RECURSIVE,
+ ..Default::default()
+ };
+
+ Ok(Box::new(FILE {
+ lock: pthread::RlctMutex::new(&mutex_attr).unwrap(),
+ file,
+ flags: F_NORD,
+ read_buf: Buffer::Owned(vec![0; BUFSIZ as usize]),
+ read_pos: 0,
+ read_size: 0,
+ unget: Vec::new(),
+ writer,
+ pid: None,
+ orientation: 0,
+ }))
+}
+
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn open_memstream(bufp: *mut *mut c_char, sizep: *mut size_t) -> *mut FILE {
+ create_memstream(bufp, sizep).or_errno_null_mut()
+}
diff --git a/tests/Makefile.tests.mk b/tests/Makefile.tests.mk
--- a/tests/Makefile.tests.mk
+++ b/tests/Makefile.tests.mk
@@ -85,6 +85,7 @@ VARIED_NAMES=\
stdio/fseek \
stdio/fwrite \
stdio/getc_unget \
- stdio/getline \
+ stdio/getline \
+ stdio/open_memstream \
stdio/mutex \
stdio/popen \
diff --git a/tests/stdio/open_memstream.c b/tests/stdio/open_memstream.c
new file mode 100644
--- /dev/null
+++ b/tests/stdio/open_memstream.c
@@ -0,0 +1,24 @@
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main(void) {
+ char *buf = NULL;
+ size_t size = 0;
+
+ FILE *stream = open_memstream(&buf, &size);
+ assert(stream != NULL);
+ assert(fputs("hello", stream) >= 0);
+ assert(fflush(stream) == 0);
+ assert(size == 5);
+ assert(strcmp(buf, "hello") == 0);
+ assert(fputc('!', stream) != EOF);
+ assert(fclose(stream) == 0);
+ assert(size == 6);
+ assert(strcmp(buf, "hello!") == 0);
+
+ free(buf);
+ puts("open_memstream ok");
+ return 0;
+}