diff --git a/Cargo.lock b/Cargo.lock index 4951949c666d511ee11e78c546609c28bc8c25f3..c0c253e6e0e1bf2b9b7608bafb294e71112780fb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -443,6 +443,7 @@ dependencies = [ "cbindgen 0.5.2", "ctype 0.1.0", "errno 0.1.0", + "fcntl 0.1.0", "platform 0.1.0", "rand 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "string 0.1.0", diff --git a/src/stdlib/Cargo.toml b/src/stdlib/Cargo.toml index 5a79260722e217025b695cce13deebb619c35a04..61b603425d0dce0e8e64f5b422b2b127e897e05a 100644 --- a/src/stdlib/Cargo.toml +++ b/src/stdlib/Cargo.toml @@ -16,3 +16,4 @@ string = { path = "../string" } time = { path = "../time" } unistd = { path = "../unistd" } wchar = { path = "../wchar" } +fcntl = { path = "../fcntl" } diff --git a/src/stdlib/src/lib.rs b/src/stdlib/src/lib.rs index d38986988adcd686a45b5b2888fad76d971c8430..6b6645cf2ab8caa7fcdcc5cd1acd130533dd1eb0 100644 --- a/src/stdlib/src/lib.rs +++ b/src/stdlib/src/lib.rs @@ -5,6 +5,7 @@ extern crate ctype; extern crate errno; +extern crate fcntl; extern crate platform; extern crate rand; extern crate string; @@ -12,7 +13,7 @@ extern crate time; extern crate unistd; extern crate wchar; -use core::{ptr, str}; +use core::{ptr, slice, str}; use rand::distributions::Alphanumeric; use rand::prng::XorShiftRng; use rand::rngs::JitterRng; @@ -21,6 +22,7 @@ use string::*; use wchar::*; use errno::*; +use fcntl::*; use platform::types::*; mod sort; @@ -456,9 +458,57 @@ fn get_nstime() -> u64 { ts.tv_nsec as u64 } -// #[no_mangle] +#[no_mangle] +pub extern "C" fn mkostemps(name: *mut c_char, suffix_len: c_int, mut flags: c_int) -> c_int { + use core::iter; + let len = unsafe { strlen(name) } as c_int; + + if len < 6 || suffix_len > len - 6 { + unsafe { platform::errno = errno::EINVAL }; + return -1; + } + + for i in (len - suffix_len - 6)..(len - suffix_len) { + if unsafe { *name.offset(i as isize) } != b'X' as c_char { + unsafe { platform::errno = errno::EINVAL }; + return -1; + } + } + + flags -= flags & O_ACCMODE; + + let mut rng = JitterRng::new_with_timer(get_nstime); + rng.test_timer(); + + for _retries in 0..100 { + let char_iter = iter::repeat(()).map(|()| rng.sample(Alphanumeric)).take(6).enumerate(); + unsafe { + for (i, c) in char_iter { + *name.offset((len as isize) - (suffix_len as isize) - (i as isize) - 1) = c as c_char + } + } + + let fd = platform::open(name, flags | O_RDWR | O_CREAT | O_EXCL, 0600); + + if fd >= 0 { + return fd; + } + + unsafe { platform::errno = errno::EEXIST }; + } + + unsafe { + for i in 0..6 { + *name.offset((len as isize) - (suffix_len as isize) - (i as isize) - 1) = b'X' as c_char; + } + } + + -1 +} + +#[no_mangle] pub extern "C" fn mkstemp(name: *mut c_char) -> c_int { - unimplemented!(); + mkostemps(name, 0, 0) } // #[no_mangle] diff --git a/tests/.gitignore b/tests/.gitignore index 993638dc67a91577269417e70976eae4b607708b..0d8fa6e5e417f76c6e61379a5c6d4883a6359bb8 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -30,6 +30,7 @@ localtime math mem mktime +mkostemps pipe printf rename diff --git a/tests/Makefile b/tests/Makefile index d47f2c4a624e95b1b757dc2b7899eb64ac513aeb..e60abb595635caac880f525e523b4d5e159c6c29 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -22,6 +22,7 @@ EXPECT_BINS=\ math \ mem \ mktime \ + mkostemps \ pipe \ printf \ rename \ diff --git a/tests/expected/mkostemps.stderr b/tests/expected/mkostemps.stderr new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/expected/mkostemps.stdout b/tests/expected/mkostemps.stdout new file mode 100644 index 0000000000000000000000000000000000000000..f3562f6879de77c8da6c65a908ffed860f2c26e5 --- /dev/null +++ b/tests/expected/mkostemps.stdout @@ -0,0 +1,3 @@ +Start unchanged: 0 +End unchanged: 0 +Read & Write Successful diff --git a/tests/mkostemps.c b/tests/mkostemps.c new file mode 100644 index 0000000000000000000000000000000000000000..2ada5d1f48a6732b3bc689bf6251d1cf4ef3ab86 --- /dev/null +++ b/tests/mkostemps.c @@ -0,0 +1,27 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +int main(int argc, char** argv) { + char* file_name = (char*) calloc(18, sizeof(char)); + strcpy(file_name, "tempXXXXXX.suffix"); + int fd = mkostemps(file_name, 7, 0); + FILE* fp = fdopen(fd, "w+"); + printf("Start unchanged: %d\n", strncmp(file_name, "temp", 4)); + printf("End unchanged: %d\n", strcmp(file_name + 4 + 6, ".suffix")); + + char* write = "Writing to file"; + fputs(write, fp); + + char buffer[sizeof write]; + memset(buffer, 0, sizeof buffer); + fgets(buffer, strlen(buffer), fp); + if (strcmp(write, buffer)) { + printf("Read & Write Successful\n"); + } else { + printf("Read & Write Failed\n"); + } + fclose(fp); + remove(file_name); + return 0; +}