IO, error handling
This commit is contained in:
parent
fff906a78b
commit
5b449f4e1e
6 changed files with 138 additions and 34 deletions
|
@ -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
29
safe_libc/src/errno.rs
Normal 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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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(),
|
||||||
))
|
))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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() }
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue