IO, error handling

This commit is contained in:
Matthias Schiffer 2020-04-13 02:13:58 +02:00
parent fff906a78b
commit 5b449f4e1e
Signed by: neocturne
GPG key ID: 16EF3F64CB201D9C
6 changed files with 138 additions and 34 deletions

View file

@ -11,7 +11,7 @@ fn alloc<T>(len: usize) -> *mut T {
let align = mem::align_of::<T>(); let align = mem::align_of::<T>();
util::must_succeed( util::must_succeed(
unsafe { unsafe {
libc::memalign(align as libc::size_t, size as libc::size_t) libc::memalign(align, size)
} }
).cast() ).cast()
} }

29
safe_libc/src/errno.rs Normal file
View file

@ -0,0 +1,29 @@
use crate::string;
use core::fmt;
#[derive(Clone, Copy, Debug)]
#[repr(transparent)]
pub struct Errno(pub libc::c_int);
#[inline]
pub fn errno() -> Errno {
unsafe { Errno(*libc::__errno_location()) }
}
impl fmt::Display for Errno {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut buf = [0u8; 1024];
let cstr = unsafe {
if libc::strerror_r(self.0, buf.as_mut_ptr().cast(), buf.len()) != 0 {
return Err(fmt::Error);
}
string::CStr::from_bytes_with_nul_unchecked(&buf)
};
match cstr.to_str() {
Err(_) => Err(fmt::Error),
Ok(s) => f.write_str(s),
}
}
}

View file

@ -5,6 +5,7 @@ pub use libc::*;
mod util; mod util;
pub mod boxed; pub mod boxed;
pub mod errno;
pub mod stdio; pub mod stdio;
pub mod string; pub mod string;

View file

@ -1,47 +1,111 @@
use crate as libc; use crate::{self as libc, errno, string};
use crate::string;
use core::fmt; use core::fmt;
use core::ops::{Deref, DerefMut};
pub struct OStream { pub struct Error {
file: *mut libc::FILE pub errno: errno::Errno,
}
pub type Result<T> = core::result::Result<T, Error>;
#[inline]
fn check_io(ok: bool) -> Result<()> {
if ok {
Ok(())
} else {
Err(Error {
errno: errno::errno(),
})
}
}
pub struct BasicOStream(*mut libc::FILE);
unsafe impl Sync for BasicOStream {}
unsafe impl Send for BasicOStream {}
pub type Stdout = BasicOStream;
pub type Stderr = BasicOStream;
#[inline]
pub fn stdout() -> Stdout {
BasicOStream(unsafe { libc::stdout })
} }
#[inline] #[inline]
pub unsafe fn stdout() -> OStream { pub fn stderr() -> Stderr {
OStream { file: libc::stdout } BasicOStream(unsafe { libc::stderr })
} }
#[inline] impl BasicOStream {
pub unsafe fn stderr() -> OStream {
OStream { file: libc::stderr }
}
impl OStream {
#[inline] #[inline]
pub fn write(&mut self, b: &[u8]) { pub fn flush(&mut self) -> Result<()> {
unsafe { check_io(unsafe {
libc::fflush(self.0)
} == 0)
}
#[inline]
pub fn write(&mut self, b: &[u8]) -> Result<()> {
check_io(unsafe {
libc::fwrite( libc::fwrite(
b.as_ptr().cast(), b.as_ptr().cast(),
1, 1,
b.len(), b.len(),
self.file, self.0,
); )
} } == b.len())
} }
#[inline] #[inline]
pub fn puts(&mut self, s: &string::CStr) { pub fn puts(&mut self, s: &string::CStr) -> Result<()> {
unsafe { check_io(unsafe {
libc::fputs(s.as_ptr(), self.file); libc::fputs(s.as_ptr(), self.0)
} } != libc::EOF)
} }
} }
impl fmt::Write for OStream { impl fmt::Write for BasicOStream {
#[inline] #[inline]
fn write_str(&mut self, s: &str) -> fmt::Result { fn write_str(&mut self, s: &str) -> fmt::Result {
self.write(s.as_bytes()); if self.write(s.as_bytes()).is_err() {
return Err(fmt::Error);
}
Ok(()) Ok(())
} }
} }
pub struct OStream(BasicOStream);
impl OStream {
#[inline]
pub unsafe fn from_raw(file: *mut libc::FILE) -> OStream {
OStream(BasicOStream(file))
}
}
impl Drop for OStream {
#[inline]
fn drop(&mut self) {
unsafe {
libc::fclose((self.0).0);
}
}
}
impl Deref for OStream {
type Target = BasicOStream;
#[inline]
fn deref(&self) -> &BasicOStream {
&self.0
}
}
impl DerefMut for OStream {
#[inline]
fn deref_mut(&mut self) -> &mut BasicOStream {
&mut self.0
}
}

View file

@ -1,12 +1,11 @@
use crate as libc; use crate::{self as libc, util, boxed::CBox};
use crate::util;
use crate::boxed::CBox;
use core::slice; use core::slice;
use core::ops::{Deref, DerefMut}; use core::ops::{Deref, DerefMut};
//pub struct FromBytesWithNulError {} //pub struct FromBytesWithNulError {}
#[repr(transparent)]
pub struct CStr { inner: libc::c_char } pub struct CStr { inner: libc::c_char }
impl CStr { impl CStr {
@ -43,7 +42,7 @@ impl CStr {
#[inline] #[inline]
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
unsafe { libc::strlen(self.as_ptr()) as usize } unsafe { libc::strlen(self.as_ptr()) }
} }
#[inline] #[inline]
@ -57,7 +56,7 @@ impl CStr {
} }
#[inline] #[inline]
pub fn as_bytes(&self) -> &[u8] { pub fn to_bytes(&self) -> &[u8] {
unsafe { slice::from_raw_parts( unsafe { slice::from_raw_parts(
self.as_ptr().cast(), self.as_ptr().cast(),
self.len(), self.len(),
@ -65,13 +64,23 @@ impl CStr {
} }
#[inline] #[inline]
pub fn as_mut_bytes(&mut self) -> &mut [u8] { pub fn to_mut_bytes(&mut self) -> &mut [u8] {
unsafe { slice::from_raw_parts_mut( unsafe { slice::from_raw_parts_mut(
self.as_mut_ptr().cast(), self.as_mut_ptr().cast(),
self.len(), self.len(),
) } ) }
} }
#[inline]
pub fn to_str(&self) -> Result<&str, core::str::Utf8Error> {
core::str::from_utf8(self.to_bytes())
}
#[inline]
pub fn to_mut_str(&mut self) -> Result<&mut str, core::str::Utf8Error> {
core::str::from_utf8_mut(self.to_mut_bytes())
}
#[inline] #[inline]
pub fn to_owned(self: &CStr) -> CString { pub fn to_owned(self: &CStr) -> CString {
CString::from(self) CString::from(self)
@ -127,7 +136,7 @@ impl From<&[u8]> for CString {
CString::from_raw_unchecked( CString::from_raw_unchecked(
util::must_succeed(libc::strndup( util::must_succeed(libc::strndup(
s.as_ptr().cast(), s.as_ptr().cast(),
s.len() as libc::size_t, s.len(),
)) ))
) )
} }

View file

@ -8,11 +8,11 @@ use core::fmt::Write;
#[no_mangle] #[no_mangle]
pub extern "C" fn main(_nargs: libc::c_int, _args: *const *const libc::c_char) -> libc::c_int { pub extern "C" fn main(_nargs: libc::c_int, _args: *const *const libc::c_char) -> libc::c_int {
let mut stdout = unsafe { libc::stdio::stdout() }; let mut stdout = libc::stdio::stdout();
{ {
let foo = cstr!("Foo!\n"); let foo = cstr!("Foo!\n");
stdout.puts(foo); let _ = stdout.puts(foo);
} }
{ {
@ -29,11 +29,12 @@ pub extern "C" fn main(_nargs: libc::c_int, _args: *const *const libc::c_char) -
let b = libc::boxed::CBox::new(42); let b = libc::boxed::CBox::new(42);
let _ = writeln!(stdout, "Bar: {}", b); let _ = writeln!(stdout, "Bar: {}", b);
} }
0 0
} }
#[panic_handler] #[panic_handler]
fn panic(info: &core::panic::PanicInfo) -> ! { fn panic(info: &core::panic::PanicInfo) -> ! {
let _ = writeln!(unsafe { libc::stdio::stderr() }, "Panic: {}", info); let _ = writeln!(libc::stdio::stderr(), "Panic: {}", info);
unsafe { libc::abort() } unsafe { libc::abort() }
} }