diff --git a/src/stdio/src/lib.rs b/src/stdio/src/lib.rs index 0979a695d17fa3d5e393d9933a5e6c581e468b4c..4748fdfb38aa9a2e50019bc9c8a4ed72e2bb7403 100644 --- a/src/stdio/src/lib.rs +++ b/src/stdio/src/lib.rs @@ -311,12 +311,48 @@ pub unsafe extern "C" fn fread( } #[no_mangle] -pub extern "C" fn freopen( +pub unsafe extern "C" fn freopen( filename: *const c_char, mode: *const c_char, stream: *mut FILE, ) -> *mut FILE { - unimplemented!(); + let mut flags = helpers::parse_mode_flags(mode); + flockfile(stream); + + helpers::fflush_unlocked(stream); + if filename.is_null() { // Reopen stream in new mode + if flags & fcntl::O_CLOEXEC > 0 { + fcntl::sys_fcntl((*stream).fd, fcntl::F_SETFD, fcntl::FD_CLOEXEC); + } + flags &= !(fcntl::O_CREAT | fcntl::O_EXCL | fcntl::O_CLOEXEC); + if fcntl::sys_fcntl((*stream).fd, fcntl::F_SETFL, flags) < 0 { + funlockfile(stream); + fclose(stream); + return ptr::null_mut(); + } + } else { + let new = fopen(filename, mode); + if new.is_null() { + funlockfile(stream); + fclose(stream); + return ptr::null_mut(); + } + if (*new).fd == (*stream).fd { + (*new).fd = -1; + } else if platform::dup2((*new).fd, (*stream).fd) < 0 || fcntl::sys_fcntl((*stream).fd, fcntl::F_SETFL, flags&fcntl::O_CLOEXEC) < 0 { + fclose(new); + funlockfile(stream); + fclose(stream); + return ptr::null_mut(); + } + (*stream).flags = ((*stream).flags & constants::F_PERM) | (*new).flags; + (*stream).read = (*new).read; + (*stream).write = (*new).write; + (*stream).seek = (*new).seek; + fclose(new); + } + funlockfile(stream); + stream } /// Seek to an offset `offset` from `whence` diff --git a/tests/.gitignore b/tests/.gitignore index 10ba484ea85eeb53ee4bf7638f4e54244a4e31d6..64317b6cbec44deb707b355235417717a4511f1b 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -30,6 +30,7 @@ /stdlib/a64l /stdio/fwrite /stdio/all +/stdio/freopen /string/strncmp /string/strcspn /string/strchr diff --git a/tests/Makefile b/tests/Makefile index f5e47bb4e4f3b536975b95addf32e704bbe66817..92e3f70f46b2fa7a4859512b8eba477c0c9b2d78 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -24,6 +24,7 @@ EXPECT_BINS=\ sprintf \ stdio/fwrite \ stdio/all \ + stdio/freopen \ stdlib/strtol \ stdlib/a64l \ string/strncmp \ diff --git a/tests/stdio/freopen.c b/tests/stdio/freopen.c new file mode 100644 index 0000000000000000000000000000000000000000..7bf3b64f20c3fcdfe351b9465c60eae7692d9a9a --- /dev/null +++ b/tests/stdio/freopen.c @@ -0,0 +1,9 @@ +#include <stdio.h> + +int main(int argc, char ** argv) { + freopen("stdio/stdio.in", "r", stdin); + char in[6]; + fgets(in, 6, stdin); + printf("%s\n", in); // should print Hello + return 0; +}