Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion libcc2rs/src/fd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,13 @@ pub struct FdRegistry {
}

thread_local! {
static FD_REGISTRY: RefCell<FdRegistry> = const { RefCell::new(FdRegistry { fds: Vec::new() }) };
static FD_REGISTRY: RefCell<FdRegistry> = RefCell::new(FdRegistry {
fds: vec![
std::io::stdin().as_fd().try_clone_to_owned().ok(),
std::io::stdout().as_fd().try_clone_to_owned().ok(),
std::io::stderr().as_fd().try_clone_to_owned().ok(),
],
});
}

impl FdRegistry {
Expand Down
97 changes: 30 additions & 67 deletions libcc2rs/src/io.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2022-present INESC-ID.
// Distributed under the MIT license that can be found in the LICENSE file.

use crate::{AnyPtr, AsPointer, Ptr, Value};
use crate::{AnyPtr, AsPointer, CFile, Ptr, Value};
use std::cell::{RefCell, UnsafeCell};
use std::os::fd::{AsFd, FromRawFd, IntoRawFd};
use std::rc::Rc;
Expand Down Expand Up @@ -48,6 +48,24 @@ thread_local! {
};
}

thread_local! {
static C_STDIN: Value<CFile> = Rc::new(RefCell::new(CFile::new(0)));
static C_STDOUT: Value<CFile> = Rc::new(RefCell::new(CFile::new(1)));
static C_STDERR: Value<CFile> = Rc::new(RefCell::new(CFile::new(2)));
}

pub fn c_stdin() -> Ptr<CFile> {
C_STDIN.with(AsPointer::as_pointer)
}

pub fn c_stdout() -> Ptr<CFile> {
C_STDOUT.with(AsPointer::as_pointer)
}

pub fn c_stderr() -> Ptr<CFile> {
C_STDERR.with(AsPointer::as_pointer)
}

pub fn cin() -> Ptr<std::fs::File> {
SAFE_STDIN.with(AsPointer::as_pointer)
}
Expand Down Expand Up @@ -84,79 +102,24 @@ pub unsafe fn cerr_unsafe() -> *mut std::fs::File {
UNSAFE_STDERR.with(UnsafeCell::get)
}

pub fn fread_refcount(a0: AnyPtr, a1: usize, a2: usize, a3: Ptr<::std::fs::File>) -> usize {
pub fn fread_refcount(a0: AnyPtr, a1: usize, a2: usize, a3: Ptr<CFile>) -> usize {
let total = a1.saturating_mul(a2);
let mut dst = a0.reinterpret_cast::<u8>();

let f = (*a3.upgrade().deref())
.try_clone()
.expect("try_clone failed");
let mut reader = std::io::BufReader::with_capacity(64 * 1024, f);

let mut read_bytes: usize = 0;
let mut buffer: [u8; 8192] = [0; 8192];

while read_bytes < total {
let remaining = total - read_bytes;
let to_read = std::cmp::min(buffer.len(), remaining);

let n = match std::io::Read::read(&mut reader, &mut buffer[..to_read]) {
Ok(0) => break,
Ok(n) => n,
Err(ref e) if e.kind() == std::io::ErrorKind::Interrupted => continue,
Err(e) => panic!("Unhandled error in fread: {e}"),
};

for &byte in &buffer[..n] {
dst.write(byte);
dst += 1;
}

read_bytes += n;
if total == 0 {
return 0;
}

let dst = a0.reinterpret_cast::<u8>();
let read_bytes = dst.with_slice_mut(total, |buf| a3.with_mut(|f| f.read(buf)));
read_bytes / a1
}

pub fn fwrite_refcount(a0: AnyPtr, a1: usize, a2: usize, a3: Ptr<::std::fs::File>) -> usize {
pub fn fwrite_refcount(a0: AnyPtr, a1: usize, a2: usize, a3: Ptr<CFile>) -> usize {
let total = a1.saturating_mul(a2);
let mut src = a0.reinterpret_cast::<u8>();

let f = (*a3.upgrade().deref())
.try_clone()
.expect("try_clone failed");
let mut writer = std::io::BufWriter::with_capacity(64 * 1024, f);

let mut written_bytes: usize = 0;
let mut buffer: [u8; 8192] = [0; 8192];

while written_bytes < total {
let remaining = total - written_bytes;
let to_fill = std::cmp::min(buffer.len(), remaining);

for b in buffer.iter_mut().take(to_fill) {
*b = src.read();
src += 1;
}

let mut off = 0;
while off < to_fill {
match std::io::Write::write(&mut writer, &buffer[off..to_fill]) {
Ok(0) => break,
Ok(n) => off += n,
Err(ref e) if e.kind() == std::io::ErrorKind::Interrupted => continue,
Err(e) => panic!("Unhandled error in fwrite: {e}"),
}
}

if off == 0 {
break;
}

written_bytes += off;
if total == 0 {
return 0;
}

written_bytes / a1
let src = a0.reinterpret_cast::<u8>();
let written = src.with_slice(total, |bytes| a3.with_mut(|f| f.write(bytes)));
written / a1
}

unsafe extern "C" {
Expand Down
122 changes: 122 additions & 0 deletions libcc2rs/src/libc_shims/cfile.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
// Copyright (c) 2022-present INESC-ID.
// Distributed under the MIT license that can be found in the LICENSE file.

use crate::FdRegistry;

pub struct CFile {
pub fd: i32,
pub eof: bool,
pub err: bool,
}

impl CFile {
pub fn new(fd: i32) -> Self {
CFile {
fd,
eof: false,
err: false,
}
}

pub fn open(path: &str, mode: &str) -> Option<CFile> {
let flags = match mode {
"rb" => nix::fcntl::OFlag::O_RDONLY,
"wb" => nix::fcntl::OFlag::O_WRONLY
.union(nix::fcntl::OFlag::O_CREAT)
.union(nix::fcntl::OFlag::O_TRUNC),
m => panic!("fopen: unsupported mode {:?}", m),
};
match nix::fcntl::open(path, flags, nix::sys::stat::Mode::from_bits_truncate(0o666)) {
Ok(ofd) => Some(CFile::new(FdRegistry::register(ofd))),
Err(e) => {
crate::cpp2rust_errno().write(e as i32);
None
}
}
}

pub fn read(&mut self, buf: &mut [u8]) -> usize {
let mut n = 0;
while n < buf.len() {
match FdRegistry::with_fd(self.fd, |b| nix::unistd::read(b, &mut buf[n..])) {
Ok(0) => {
self.eof = true;
break;
}
Ok(k) => n += k,
Err(nix::errno::Errno::EINTR) => {}
Err(e) => {
self.err = true;
crate::cpp2rust_errno().write(e as i32);
break;
}
}
}
n
}

pub fn write(&mut self, buf: &[u8]) -> usize {
let mut n = 0;
while n < buf.len() {
match FdRegistry::with_fd(self.fd, |b| nix::unistd::write(b, &buf[n..])) {
Ok(0) => {
self.err = true;
break;
}
Ok(k) => n += k,
Err(nix::errno::Errno::EINTR) => {}
Err(e) => {
self.err = true;
crate::cpp2rust_errno().write(e as i32);
break;
}
}
}
n
}

pub fn seek(&mut self, offset: i64, whence: i32) -> i64 {
let w = match whence {
0 => nix::unistd::Whence::SeekSet,
1 => nix::unistd::Whence::SeekCur,
2 => nix::unistd::Whence::SeekEnd,
other => panic!("fseek: unsupported whence {}", other),
};
match FdRegistry::with_fd(self.fd, |b| nix::unistd::lseek(b, offset, w)) {
Ok(off) => {
self.eof = false;
off
}
Err(e) => {
crate::cpp2rust_errno().write(e as i32);
-1
}
}
}

pub fn tell(&self) -> i64 {
match FdRegistry::with_fd(self.fd, |b| {
nix::unistd::lseek(b, 0, nix::unistd::Whence::SeekCur)
}) {
Ok(off) => off,
Err(e) => {
crate::cpp2rust_errno().write(e as i32);
-1
}
}
}

pub fn getc(&mut self) -> i32 {
let mut b = [0u8; 1];
match self.read(&mut b) {
1 => b[0] as i32,
_ => -1,
}
}

pub fn close(&self) -> i32 {
FdRegistry::close(self.fd)
}
}

impl crate::ByteRepr for CFile {}
2 changes: 2 additions & 0 deletions libcc2rs/src/libc_shims/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) 2022-present INESC-ID.
// Distributed under the MIT license that can be found in the LICENSE file.

mod cfile;
mod dirent;
mod fdset;
mod ifaddrs;
Expand All @@ -13,6 +14,7 @@ mod stat;
mod termios;
mod time;

pub use cfile::*;
pub use dirent::*;
pub use fdset::*;
pub use ifaddrs::*;
Expand Down
6 changes: 6 additions & 0 deletions rules/stdio/src.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,9 @@ int f23(FILE *stream) { return getc(stream); }
int f24(FILE *stream, char *buf, int mode, size_t size) {
return setvbuf(stream, buf, mode, size);
}

int f25(void) { return SEEK_SET; }

int f26(void) { return SEEK_CUR; }

int f27(void) { return SEEK_END; }
Loading
Loading