diff --git a/include/limits.h b/include/bits/limits.h similarity index 93% rename from include/limits.h rename to include/bits/limits.h index 1b2de46fc821197cdcd923a2459afa1ac1b2d76e..73d0bdc23b6af8699f98a662dcca682d108baf75 100644 --- a/include/limits.h +++ b/include/bits/limits.h @@ -1,3 +1,6 @@ +#ifndef _BITS_LIMIT_H +#define _BITS_LIMIT_H + #define MB_LEN_MAX 4 // unicode #define CHAR_BIT __CHAR_BIT__ @@ -28,4 +31,4 @@ #define USHRT_MAX ((1 << 16) - 1) #define WORD_BIT 32 -#define PATH_MAX 4096 +#endif diff --git a/src/header/limits/cbindgen.toml b/src/header/limits/cbindgen.toml new file mode 100644 index 0000000000000000000000000000000000000000..e25e6c67054a296c1e56543597a80fa3eb5b3788 --- /dev/null +++ b/src/header/limits/cbindgen.toml @@ -0,0 +1,8 @@ +sys_includes = [] +include_guard = "_LIMITS_H" +language = "C" +style = "Tag" +trailer = "#include <bits/limits.h>" + +[enum] +prefix_with_name = true diff --git a/src/header/limits/mod.rs b/src/header/limits/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..aab89f6ed35790a88226c56cd588ba87de00ce6c --- /dev/null +++ b/src/header/limits/mod.rs @@ -0,0 +1,3 @@ +//! limits.h implementation for relibc + +pub const PATH_MAX: usize = 4096; diff --git a/src/header/mod.rs b/src/header/mod.rs index e60e528f62f6845ea743ab57262098d2e3a1f3f8..c733f05d1d710e9a4738077e835d03f9881206cb 100644 --- a/src/header/mod.rs +++ b/src/header/mod.rs @@ -10,6 +10,7 @@ pub mod fnmatch; pub mod getopt; pub mod grp; pub mod inttypes; +pub mod limits; pub mod locale; pub mod netdb; pub mod netinet_in; diff --git a/src/header/stdlib/mod.rs b/src/header/stdlib/mod.rs index a4b5fa6ffa1c33943ca044de5ecd47485e3fe6c0..6573ac50dd8d02cd487b7b0bda7d8e2dd56c25d3 100644 --- a/src/header/stdlib/mod.rs +++ b/src/header/stdlib/mod.rs @@ -1,6 +1,6 @@ //! stdlib implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/stdlib.h.html -use core::{intrinsics, iter, mem, ptr}; +use core::{intrinsics, iter, mem, ptr, slice}; use rand::distributions::Alphanumeric; use rand::prng::XorShiftRng; use rand::rngs::JitterRng; @@ -12,6 +12,7 @@ use header::fcntl::*; use header::string::*; use header::time::constants::CLOCK_MONOTONIC; use header::time::timespec; +use header::limits; use header::wchar::*; use header::{ctype, errno, unistd}; use platform; @@ -572,9 +573,24 @@ pub unsafe extern "C" fn realloc(ptr: *mut c_void, size: size_t) -> *mut c_void platform::realloc(ptr, size) } -// #[no_mangle] -pub extern "C" fn realpath(file_name: *const c_char, resolved_name: *mut c_char) -> *mut c_char { - unimplemented!(); +#[no_mangle] +pub unsafe extern "C" fn realpath(pathname: *const c_char, resolved: *mut c_char) -> *mut c_char { + let mut path = [0; limits::PATH_MAX]; + { + let slice = if resolved.is_null() { + &mut path + } else { + slice::from_raw_parts_mut(resolved as *mut u8, 4096) + }; + if Sys::realpath(CStr::from_ptr(pathname), slice) < 0 { + return ptr::null_mut(); + } + } + if !resolved.is_null() { + resolved + } else { + strdup(path.as_ptr() as *const i8) + } } // #[no_mangle] diff --git a/src/header/unistd/mod.rs b/src/header/unistd/mod.rs index 816c2aed41d82684ac541c334f8d8d0455e65b16..80a6385544f4526ef95d3f35a8ec1c1ec52c7030 100644 --- a/src/header/unistd/mod.rs +++ b/src/header/unistd/mod.rs @@ -3,7 +3,7 @@ use core::{ptr, slice}; use c_str::CStr; -use header::sys_time; +use header::{limits, sys_time}; use header::time::timespec; use platform; use platform::types::*; @@ -35,8 +35,6 @@ pub const STDIN_FILENO: c_int = 0; pub const STDOUT_FILENO: c_int = 1; pub const STDERR_FILENO: c_int = 2; -const PATH_MAX: usize = 4096; - #[no_mangle] pub extern "C" fn _exit(status: c_int) { Sys::exit(status) @@ -190,7 +188,7 @@ pub extern "C" fn ftruncate(fildes: c_int, length: off_t) -> c_int { #[no_mangle] pub extern "C" fn getcwd(mut buf: *mut c_char, mut size: size_t) -> *mut c_char { let alloc = buf.is_null(); - let mut stack_buf = [0; PATH_MAX]; + let mut stack_buf = [0; limits::PATH_MAX]; if alloc { buf = stack_buf.as_mut_ptr(); size = stack_buf.len(); @@ -305,7 +303,7 @@ pub extern "C" fn getuid() -> uid_t { #[no_mangle] pub extern "C" fn getwd(path_name: *mut c_char) -> *mut c_char { - getcwd(path_name, PATH_MAX) + getcwd(path_name, limits::PATH_MAX) } #[no_mangle] diff --git a/src/platform/linux/mod.rs b/src/platform/linux/mod.rs index 5b3d8957335a5d1199dd1b72342ff0db1183fdde..a194e041d56bd7bd540b7e80f77b2201c9635682 100644 --- a/src/platform/linux/mod.rs +++ b/src/platform/linux/mod.rs @@ -1,11 +1,15 @@ -use core::fmt::Write; +use alloc::vec::Vec; +use core::fmt::Write as _WriteFmt; use core::{mem, ptr}; +use core_io::Write; use super::types::*; use super::{errno, FileWriter, Pal}; use c_str::CStr; +use fs::File; use header::dirent::dirent; use header::errno::{EINVAL, ENOSYS}; +use header::fcntl; use header::signal::SIGCHLD; use header::sys_ioctl::{winsize, TCGETS, TCSETS, TIOCGWINSZ}; // use header::sys_resource::rusage; @@ -302,6 +306,39 @@ impl Pal for Sys { e(unsafe { syscall!(READ, fildes, buf.as_mut_ptr(), buf.len()) }) as ssize_t } + fn realpath(pathname: &CStr, out: &mut [u8]) -> c_int { + fn readlink(pathname: &CStr, out: &mut [u8]) -> ssize_t { + e(unsafe { syscall!(READLINKAT, AT_FDCWD, pathname.as_ptr(), out.as_mut_ptr(), out.len()) }) as ssize_t + } + + let file = match File::open(pathname, fcntl::O_PATH) { + Ok(file) => file, + Err(_) => return -1 + }; + + if out.is_empty() { + return 0; + } + + let mut proc_path = b"/proc/self/fd/".to_vec(); + write!(proc_path, "{}", *file).unwrap(); + proc_path.push(0); + + let len = out.len() - 1; + let read = readlink(CStr::from_bytes_with_nul(&proc_path).unwrap(), &mut out[..len]); + if read < 0 { + return -1; + } + out[read as usize] = 0; + + // TODO: Should these checks from musl be ported? + // https://gitlab.com/bminor/musl/blob/master/src/misc/realpath.c#L33-38 + // I'm not exactly sure what they're checking... + // Seems to be a sanity check whether or not it's still the same file? + + 0 + } + fn rename(old: &CStr, new: &CStr) -> c_int { e(unsafe { syscall!(RENAMEAT, AT_FDCWD, old.as_ptr(), AT_FDCWD, new.as_ptr()) }) as c_int } diff --git a/src/platform/pal/mod.rs b/src/platform/pal/mod.rs index bd18cbabe1f8af8c066de3488eab114e632ba29c..f4fdd25f6bcf2362f18b50b0e8e329ff87c571be 100644 --- a/src/platform/pal/mod.rs +++ b/src/platform/pal/mod.rs @@ -112,6 +112,10 @@ pub trait Pal { fn read(fildes: c_int, buf: &mut [u8]) -> ssize_t; + //fn readlink(pathname: &CStr, out: &mut [u8]) -> ssize_t; + + fn realpath(pathname: &CStr, out: &mut [u8]) -> c_int; + fn rename(old: &CStr, new: &CStr) -> c_int; fn rmdir(path: &CStr) -> c_int; diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs index 7dcd9484fe10801c5e66b6a36472c7ad56703029..9767de086780aab772ff4673030895b5ab91d9aa 100644 --- a/src/platform/redox/mod.rs +++ b/src/platform/redox/mod.rs @@ -616,6 +616,15 @@ impl Pal for Sys { e(syscall::read(fd as usize, buf)) as ssize_t } + fn realpath(pathname: &CStr, out: &mut [u8]) -> c_int { + let file = match File::open(pathname, fcntl::O_PATH) { + Ok(fd) => fd, + Err(_) => return -1 + }; + + e(syscall::fpath(*file as usize, out)) as c_int + } + fn rename(oldpath: &CStr, newpath: &CStr) -> c_int { match syscall::open(oldpath.to_bytes(), O_WRONLY | O_CLOEXEC) { Ok(fd) => { diff --git a/tests/Makefile b/tests/Makefile index fb77b2d5ef8f53ebf7332815b8f299ad1745c3c1..71ee5e05da928b2225e39c6a0aabfdd6ed6c130c 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -85,6 +85,7 @@ BINS=\ stdlib/alloc \ stdlib/bsearch \ stdlib/mktemp \ + stdlib/realpath \ time/gettimeofday \ unistd/chdir \ unistd/getcwd \ diff --git a/tests/stdlib/realpath.c b/tests/stdlib/realpath.c new file mode 100644 index 0000000000000000000000000000000000000000..c6a679a4d508c28661492032ae33dfd94aa95bbd --- /dev/null +++ b/tests/stdlib/realpath.c @@ -0,0 +1,29 @@ +#include <errno.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +int main() { + char* path = realpath("stdlib/realpath.c", NULL); + if (!path) { + perror("realpath"); + return -1; + } + puts(path); + + free(path); + + path = malloc(PATH_MAX); + memset(path, 0, PATH_MAX); + + realpath("stdlib/realpath.c", path); + if (!path) { + perror("realpath"); + free(path); + return -1; + } + puts(path); + + free(path); +}