From 0478f7afaebd8b08aec13695f3bf1b7aa766da74 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Sat, 21 Jan 2017 20:45:52 +0100 Subject: [PATCH 1/4] Add `fs::Metadata` --- examples/stat.rs | 19 ++++++++++ src/fs.rs | 13 ------- src/linux/aarch64.rs | 31 +++++++++++++++- src/linux/arm.rs | 31 +++++++++++++++- src/linux/mips.rs | 32 ++++++++++++++++- src/linux/mips64.rs | 32 ++++++++++++++++- src/linux/mod.rs | 80 ++++++++++++++++++++++++++++++----------- src/linux/powerpc.rs | 31 ++++++++++++++-- src/linux/powerpc64.rs | 30 ++++++++++++++-- src/linux/sparc64.rs | 5 +++ src/linux/types.rs | 22 +++++++++++- src/linux/x86.rs | 36 ++++++++++++++++++- src/linux/x86_64.rs | 30 +++++++++++++++- src/sys/linux/fs.rs | 81 +++++++++++++++++++++++++++++------------- 14 files changed, 403 insertions(+), 70 deletions(-) create mode 100644 examples/stat.rs diff --git a/examples/stat.rs b/examples/stat.rs new file mode 100644 index 000000000..055b36c9e --- /dev/null +++ b/examples/stat.rs @@ -0,0 +1,19 @@ +use std::fs; +use std::fs::File; +use std::io::Write; +use std::process; + +pub fn main() { + let path = "/target/stat"; + let content = b"Test stat\n"; + let size = content.len() as u64; + let file = File::create(path).unwrap(); + (&file).write_all(b"Test stat\n").unwrap(); + let f = file.metadata().unwrap(); + let s = fs::metadata(path).unwrap(); + let l = fs::symlink_metadata(path).unwrap(); + println!("{} {} {} {}", size, f.len(), s.len(), l.len()); + if f.len() != size || s.len() != size || l.len() != size { + process::exit(1); + } +} diff --git a/src/fs.rs b/src/fs.rs index b07772a28..027d6f928 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -63,7 +63,6 @@ pub struct File { /// modification times, etc. /// /// [`metadata`]: fn.metadata.html -#[cfg(issue = "21")] #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] pub struct Metadata(fs_imp::FileAttr); @@ -156,7 +155,6 @@ pub struct OpenOptions(fs_imp::OpenOptions); /// `os::unix::PermissionsExt` trait. /// /// [`readonly`]: struct.Permissions.html#method.readonly -#[cfg(issue = "21")] #[derive(Clone, PartialEq, Eq, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Permissions(fs_imp::FilePermissions); @@ -165,7 +163,6 @@ pub struct Permissions(fs_imp::FilePermissions); /// It is returned by [`Metadata::file_type`] method. /// /// [`Metadata::file_type`]: struct.Metadata.html#method.file_type -#[cfg(issue = "21")] #[stable(feature = "file_type", since = "1.1.0")] #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub struct FileType(fs_imp::FileType); @@ -327,7 +324,6 @@ impl File { /// # Ok(()) /// # } /// ``` - #[cfg(issue = "18")] #[stable(feature = "rust1", since = "1.0.0")] pub fn metadata(&self) -> io::Result { self.inner.file_attr().map(Metadata) @@ -623,7 +619,6 @@ impl AsInnerMut for OpenOptions { fn as_inner_mut(&mut self) -> &mut fs_imp::OpenOptions { &mut self.0 } } -#[cfg(issue = "21")] impl Metadata { /// Returns the file type for this metadata. /// @@ -812,12 +807,10 @@ impl Metadata { } } -#[cfg(issue = "21")] impl AsInner for Metadata { fn as_inner(&self) -> &fs_imp::FileAttr { &self.0 } } -#[cfg(issue = "21")] impl Permissions { /// Returns whether these permissions describe a readonly file. /// @@ -868,7 +861,6 @@ impl Permissions { } } -#[cfg(issue = "21")] impl FileType { /// Test whether this file type represents a directory. /// @@ -925,19 +917,16 @@ impl FileType { pub fn is_symlink(&self) -> bool { self.0.is_symlink() } } -#[cfg(issue = "21")] impl AsInner for FileType { fn as_inner(&self) -> &fs_imp::FileType { &self.0 } } -#[cfg(issue = "21")] impl FromInner for Permissions { fn from_inner(f: fs_imp::FilePermissions) -> Permissions { Permissions(f) } } -#[cfg(issue = "21")] impl AsInner for Permissions { fn as_inner(&self) -> &fs_imp::FilePermissions { &self.0 } } @@ -1161,7 +1150,6 @@ pub fn remove_file>(path: P) -> io::Result<()> { /// # Ok(()) /// # } /// ``` -#[cfg(issue = "21")] #[stable(feature = "rust1", since = "1.0.0")] pub fn metadata>(path: P) -> io::Result { fs_imp::stat(path.as_ref()).map(Metadata) @@ -1195,7 +1183,6 @@ pub fn metadata>(path: P) -> io::Result { /// # Ok(()) /// # } /// ``` -#[cfg(issue = "21")] #[stable(feature = "symlink_metadata", since = "1.1.0")] pub fn symlink_metadata>(path: P) -> io::Result { fs_imp::lstat(path.as_ref()).map(Metadata) diff --git a/src/linux/aarch64.rs b/src/linux/aarch64.rs index 914b619c2..2c4c52de0 100644 --- a/src/linux/aarch64.rs +++ b/src/linux/aarch64.rs @@ -1,4 +1,7 @@ -use ctypes::{c_int, c_uint}; +#![allow(non_camel_case_types)] + +use ctypes::*; +use linux::types::*; pub const O_APPEND: c_int = 0o00002000; pub const O_CLOEXEC: c_int = 0o02000000; @@ -7,3 +10,29 @@ pub const O_EXCL: c_int = 0o00000200; pub const O_TRUNC: c_int = 0o00001000; pub const FIOCLEX: c_uint = 0x5451; + +#[derive(Clone, Copy)] +#[repr(C)] +pub struct stat64 { + pub st_dev: dev_t, + pub st_ino: ino64_t, + pub st_mode: mode_t, + pub st_nlink: nlink_t, + pub st_uid: uid_t, + pub st_gid: gid_t, + pub st_rdev: dev_t, + __pad1: dev_t, + pub st_size: off64_t, + pub st_blksize: blksize_t, + __pad2: c_int, + pub st_blocks: blkcnt64_t, + pub st_atime: time_t, + pub st_atime_nsec: c_long, + pub st_mtime: time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: time_t, + pub st_ctime_nsec: c_long, + __unused: [c_int; 2], +} + +type blksize_t = i32; diff --git a/src/linux/arm.rs b/src/linux/arm.rs index 914b619c2..b8a8a15bd 100644 --- a/src/linux/arm.rs +++ b/src/linux/arm.rs @@ -1,4 +1,7 @@ -use ctypes::{c_int, c_uint}; +#![allow(non_camel_case_types)] + +use ctypes::*; +use linux::types::*; pub const O_APPEND: c_int = 0o00002000; pub const O_CLOEXEC: c_int = 0o02000000; @@ -7,3 +10,29 @@ pub const O_EXCL: c_int = 0o00000200; pub const O_TRUNC: c_int = 0o00001000; pub const FIOCLEX: c_uint = 0x5451; + +#[derive(Clone, Copy)] +#[repr(C)] +pub struct stat64 { + pub st_dev: dev_t, + __pad1: c_uint, + __st_ino: ino_t, + pub st_mode: mode_t, + pub st_nlink: nlink_t, + pub st_uid: uid_t, + pub st_gid: gid_t, + pub st_rdev: dev_t, + __pad2: c_uint, + pub st_size: off64_t, + pub st_blksize: blksize_t, + pub st_blocks: blkcnt64_t, + pub st_atime: time_t, + pub st_atime_nsec: c_long, + pub st_mtime: time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: time_t, + pub st_ctime_nsec: c_long, + pub st_ino: ino64_t, +} + +pub type blksize_t = i32; diff --git a/src/linux/mips.rs b/src/linux/mips.rs index 584cc1818..c1984c8e2 100644 --- a/src/linux/mips.rs +++ b/src/linux/mips.rs @@ -1,4 +1,7 @@ -use ctypes::{c_int, c_uint}; +#![allow(non_camel_case_types)] + +use ctypes::*; +use linux::types::*; pub const O_APPEND: c_int = 0x0008; pub const O_CLOEXEC: c_int = 0o02000000; @@ -7,3 +10,30 @@ pub const O_EXCL: c_int = 0x0400; pub const O_TRUNC: c_int = 0x0200; pub const FIOCLEX: c_uint = 0x6601; + +#[derive(Clone, Copy)] +#[repr(C)] +pub struct stat64 { + pub st_dev: c_ulong, + __st_pad1: [c_long; 3], + pub st_ino: ino64_t, + pub st_mode: mode_t, + pub st_nlink: nlink_t, + pub st_uid: uid_t, + pub st_gid: gid_t, + pub st_rdev: c_ulong, + __st_pad2: [c_long; 2], + pub st_size: off64_t, + pub st_atime: time_t, + pub st_atime_nsec: c_long, + pub st_mtime: time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: time_t, + pub st_ctime_nsec: c_long, + pub st_blksize: blksize_t, + __st_pad3: c_long, + pub st_blocks: blkcnt64_t, + __st_pad5: [c_long; 14], +} + +pub type blksize_t = i32; diff --git a/src/linux/mips64.rs b/src/linux/mips64.rs index 584cc1818..68ea9fbf5 100644 --- a/src/linux/mips64.rs +++ b/src/linux/mips64.rs @@ -1,4 +1,7 @@ -use ctypes::{c_int, c_uint}; +#![allow(non_camel_case_types)] + +use ctypes::*; +use linux::types::*; pub const O_APPEND: c_int = 0x0008; pub const O_CLOEXEC: c_int = 0o02000000; @@ -7,3 +10,30 @@ pub const O_EXCL: c_int = 0x0400; pub const O_TRUNC: c_int = 0x0200; pub const FIOCLEX: c_uint = 0x6601; + +#[derive(Clone, Copy)] +#[repr(C)] +pub struct stat64 { + pub st_dev: c_ulong, + __st_pad1: [c_long; 2], + pub st_ino: ino64_t, + pub st_mode: mode_t, + pub st_nlink: nlink_t, + pub st_uid: uid_t, + pub st_gid: gid_t, + pub st_rdev: c_ulong, + __st_pad2: [c_long; 2], + pub st_size: off64_t, + pub st_atime: time_t, + pub st_atime_nsec: c_long, + pub st_mtime: time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: time_t, + pub st_ctime_nsec: c_long, + pub st_blksize: blksize_t, + __st_pad3: c_long, + pub st_blocks: blkcnt64_t, + __st_pad5: [c_long; 7], +} + +pub type blksize_t = i64; diff --git a/src/linux/mod.rs b/src/linux/mod.rs index 1a6c4a8e2..ba2dfead2 100644 --- a/src/linux/mod.rs +++ b/src/linux/mod.rs @@ -37,15 +37,14 @@ mod arch; pub mod types; use core::intrinsics; - -use ctypes::{c_char, c_int, c_uint, c_ulong, c_longlong, size_t, ssize_t}; -use self::types::umode_t; +use ctypes::{c_char, c_int, c_uint, c_ulong, size_t, ssize_t}; pub use self::arch::*; -pub use self::types::{clockid_t, time_t, timespec}; +pub use self::types::*; // include/uapi/linux/fcntl.h pub const AT_FDCWD: c_int = -100; +pub const AT_SYMLINK_NOFOLLOW: c_int = 0x100; // include/uapi/asm-generic/fcntl.h pub const O_ACCMODE: c_int = 0o00000003; @@ -54,6 +53,12 @@ pub const O_RDWR: c_int = 0o00000002; pub const O_WRONLY: c_int = 0o00000001; pub const O_LARGEFILE: c_int = 0o00100000; +// include/uapi/linux/stat.h +pub const S_IFREG: c_uint = 0o0100000; +pub const S_IFLNK: c_uint = 0o0120000; +pub const S_IFDIR: c_uint = 0o0040000; +pub const S_IFMT: c_uint = 0o00170000; + // include/uapi/linux/time.h pub const CLOCK_MONOTONIC: clockid_t = 1; pub const CLOCK_REALTIME: clockid_t = 0; @@ -190,28 +195,20 @@ pub unsafe fn pwrite64(fd: c_int, // fs/open.c #[inline(always)] -pub unsafe fn ftruncate64(fd: c_int, - length: loff_t) - -> ssize_t { +pub unsafe fn ftruncate64(fd: c_int, length: loff_t) -> ssize_t { #[cfg(all(target_pointer_width = "32", not(target_arch = "x86")))] #[inline(always)] - unsafe fn ftruncate64(fd: c_int, - length: loff_t) - -> ssize_t { + unsafe fn ftruncate64(fd: c_int, length: loff_t) -> ssize_t { syscall!(FTRUNCATE64, fd, 0, high(length), low(length)) as ssize_t } #[cfg(target_arch = "x86")] #[inline(always)] - unsafe fn ftruncate64(fd: c_int, - length: loff_t) - -> ssize_t { + unsafe fn ftruncate64(fd: c_int, length: loff_t) -> ssize_t { syscall!(FTRUNCATE64, fd, high(length), low(length)) as ssize_t } #[cfg(target_pointer_width = "64")] #[inline(always)] - unsafe fn ftruncate64(fd: c_int, - length: loff_t) - -> ssize_t { + unsafe fn ftruncate64(fd: c_int, length: loff_t) -> ssize_t { syscall!(FTRUNCATE, fd, length) as ssize_t } ftruncate64(fd, length) @@ -235,9 +232,50 @@ pub unsafe fn fdatasync(fd: c_int) -> ssize_t { syscall!(FDATASYNC, fd) as ssize_t } -#[allow(non_camel_case_types)] -pub type loff_t = c_longlong; +// fs/stat.c +#[inline(always)] +pub unsafe fn fstat64(fd: c_int, statbuf: *mut stat64) -> ssize_t { + #[cfg(target_pointer_width = "32")] + #[inline(always)] + unsafe fn fstat64(fd: c_int, statbuf: *mut stat64) -> ssize_t { + syscall!(FSTAT64, fd, statbuf) as ssize_t + } + #[cfg(target_pointer_width = "64")] + #[inline(always)] + unsafe fn fstat64(fd: c_int, statbuf: *mut stat64) -> ssize_t { + syscall!(FSTAT, fd, statbuf) as ssize_t + } + fstat64(fd, statbuf) +} + +// fs/stat.c +#[inline(always)] +pub unsafe fn stat64(filename: *const c_char, statbuf: *mut stat64) -> ssize_t { + #[cfg(target_pointer_width = "32")] + #[inline(always)] + unsafe fn stat64(filename: *const c_char, statbuf: *mut stat64) -> ssize_t { + syscall!(FSTATAT64, AT_FDCWD, filename, statbuf, 0) as ssize_t + } + #[cfg(target_pointer_width = "64")] + #[inline(always)] + unsafe fn stat64(filename: *const c_char, statbuf: *mut stat64) -> ssize_t { + syscall!(NEWFSTATAT, AT_FDCWD, filename, statbuf, 0) as ssize_t + } + stat64(filename, statbuf) +} -// TODO? -#[allow(non_camel_case_types)] -pub type mode_t = umode_t; +// fs/stat.c +#[inline(always)] +pub unsafe fn lstat64(filename: *const c_char, statbuf: *mut stat64) -> ssize_t { + #[cfg(target_pointer_width = "32")] + #[inline(always)] + unsafe fn lstat64(filename: *const c_char, statbuf: *mut stat64) -> ssize_t { + syscall!(FSTATAT64, AT_FDCWD, filename, statbuf, AT_SYMLINK_NOFOLLOW) as ssize_t + } + #[cfg(target_pointer_width = "64")] + #[inline(always)] + unsafe fn lstat64(filename: *const c_char, statbuf: *mut stat64) -> ssize_t { + syscall!(NEWFSTATAT, AT_FDCWD, filename, statbuf, AT_SYMLINK_NOFOLLOW) as ssize_t + } + lstat64(filename, statbuf) +} diff --git a/src/linux/powerpc.rs b/src/linux/powerpc.rs index 0a345cb09..1c4558979 100644 --- a/src/linux/powerpc.rs +++ b/src/linux/powerpc.rs @@ -1,6 +1,7 @@ -//! https://w3challs.com/syscalls/?arch=powerpc_32 +#![allow(non_camel_case_types)] -use ctypes::{c_int, c_uint}; +use ctypes::*; +use linux::types::*; pub const O_APPEND: c_int = 0o00002000; pub const O_CLOEXEC: c_int = 0o02000000; @@ -9,3 +10,29 @@ pub const O_EXCL: c_int = 0o00000200; pub const O_TRUNC: c_int = 0o00001000; pub const FIOCLEX: c_uint = 0x20006601; + +#[derive(Clone, Copy)] +#[repr(C)] +pub struct stat64 { + pub st_dev: dev_t, + pub st_ino: ino64_t, + pub st_mode: mode_t, + pub st_nlink: nlink_t, + pub st_uid: uid_t, + pub st_gid: gid_t, + pub st_rdev: dev_t, + __pad2: c_ushort, + pub st_size: off64_t, + pub st_blksize: blksize_t, + pub st_blocks: blkcnt64_t, + pub st_atime: time_t, + pub st_atime_nsec: c_long, + pub st_mtime: time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: time_t, + pub st_ctime_nsec: c_long, + __glibc_reserved4: c_ulong, + __glibc_reserved5: c_ulong, +} + +pub type blksize_t = i32; diff --git a/src/linux/powerpc64.rs b/src/linux/powerpc64.rs index f6f4c9279..41c8c09ea 100644 --- a/src/linux/powerpc64.rs +++ b/src/linux/powerpc64.rs @@ -1,6 +1,7 @@ -//! https://w3challs.com/syscalls/?arch=powerpc_64 +#![allow(non_camel_case_types)] -use ctypes::{c_int, c_uint}; +use ctypes::*; +use linux::types::*; pub const O_APPEND: c_int = 0o00002000; pub const O_CLOEXEC: c_int = 0o02000000; @@ -9,3 +10,28 @@ pub const O_EXCL: c_int = 0o00000200; pub const O_TRUNC: c_int = 0o00001000; pub const FIOCLEX: c_uint = 0x20006601; + +#[derive(Clone, Copy)] +#[repr(C)] +pub struct stat64 { + pub st_dev: dev_t, + pub st_ino: ino64_t, + pub st_nlink: nlink_t, + pub st_mode: mode_t, + pub st_uid: uid_t, + pub st_gid: gid_t, + __pad0: c_int, + pub st_rdev: dev_t, + pub st_size: off64_t, + pub st_blksize: blksize_t, + pub st_blocks: blkcnt64_t, + pub st_atime: time_t, + pub st_atime_nsec: c_long, + pub st_mtime: time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: time_t, + pub st_ctime_nsec: c_long, + __reserved: [c_long; 3], +} + +pub type blksize_t = i64; diff --git a/src/linux/sparc64.rs b/src/linux/sparc64.rs index 6e7d54366..7f7b95a4f 100644 --- a/src/linux/sparc64.rs +++ b/src/linux/sparc64.rs @@ -1,3 +1,8 @@ +#![allow(non_camel_case_types)] + +use ctypes::*; +use linux::types::*; + use ctypes::c_int; pub const O_APPEND: c_int = 0x0008; diff --git a/src/linux/types.rs b/src/linux/types.rs index 2e9a4aa01..c66ad9f6e 100644 --- a/src/linux/types.rs +++ b/src/linux/types.rs @@ -1,16 +1,28 @@ #![allow(non_camel_case_types)] -use ctypes::{c_int, c_long, c_ushort}; +use ctypes::{c_int, c_long, c_longlong, c_uint, c_ushort}; + +pub use super::arch::stat64; // include/linux/types.h pub type clockid_t = __kernel_clockid_t; +//pub type dev_t = __kernel_dev_t; +pub type loff_t = __kernel_loff_t; +pub type mode_t = __kernel_mode_t; +pub type nlink_t = u32; pub type time_t = __kernel_time_t; pub type umode_t = c_ushort; // include/uapi/asm-generic/posix_types.h type __kernel_clockid_t = c_int; +//type __kernel_dev_t = u32; +type __kernel_gid_t = c_uint; +type __kernel_loff_t = c_longlong; type __kernel_long_t = c_long; +type __kernel_mode_t = c_uint; +type __kernel_off64_t = c_longlong; type __kernel_time_t = __kernel_long_t; +type __kernel_uid_t = c_uint; // include/uapi/linux/time.h #[derive(Clone, Copy)] @@ -19,3 +31,11 @@ pub struct timespec { pub tv_sec: time_t, pub tv_nsec: c_long, } + +// Where from? +pub type blkcnt64_t = i64; +#[cfg(not(any(target_arch = "mips", target_arch = "mips64")))] pub type dev_t = u64; +pub type gid_t = __kernel_gid_t; +pub type ino64_t = c_longlong; +pub type off64_t = __kernel_off64_t; +pub type uid_t = __kernel_uid_t; diff --git a/src/linux/x86.rs b/src/linux/x86.rs index 914b619c2..b3641ba9e 100644 --- a/src/linux/x86.rs +++ b/src/linux/x86.rs @@ -1,4 +1,7 @@ -use ctypes::{c_int, c_uint}; +#![allow(non_camel_case_types)] + +use ctypes::*; +use linux::types::*; pub const O_APPEND: c_int = 0o00002000; pub const O_CLOEXEC: c_int = 0o02000000; @@ -7,3 +10,34 @@ pub const O_EXCL: c_int = 0o00000200; pub const O_TRUNC: c_int = 0o00001000; pub const FIOCLEX: c_uint = 0x5451; + +// include/linux/types.h +pub type ino_t = __kernel_ino_t; +// include/uapi/asm-generic/posix_types.h +type __kernel_ino_t = __kernel_long_t; + +#[derive(Clone, Copy)] +#[repr(C)] +pub struct stat64 { + pub st_dev: dev_t, + __pad1: c_uint, + __st_ino: ino_t, + pub st_mode: mode_t, + pub st_nlink: nlink_t, + pub st_uid: uid_t, + pub st_gid: gid_t, + pub st_rdev: dev_t, + __pad2: c_uint, + pub st_size: off64_t, + pub st_blksize: blksize_t, + pub st_blocks: blkcnt64_t, + pub st_atime: time_t, + pub st_atime_nsec: c_long, + pub st_mtime: time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: time_t, + pub st_ctime_nsec: c_long, + pub st_ino: ino64_t, +} + +pub type blksize_t = i32; diff --git a/src/linux/x86_64.rs b/src/linux/x86_64.rs index 914b619c2..d97de759e 100644 --- a/src/linux/x86_64.rs +++ b/src/linux/x86_64.rs @@ -1,4 +1,7 @@ -use ctypes::{c_int, c_uint}; +#![allow(non_camel_case_types)] + +use ctypes::*; +use linux::types::*; pub const O_APPEND: c_int = 0o00002000; pub const O_CLOEXEC: c_int = 0o02000000; @@ -7,3 +10,28 @@ pub const O_EXCL: c_int = 0o00000200; pub const O_TRUNC: c_int = 0o00001000; pub const FIOCLEX: c_uint = 0x5451; + +pub type blksize_t = i64; + +#[derive(Clone, Copy)] +#[repr(C)] +pub struct stat64 { + pub st_dev: dev_t, + pub st_ino: ino64_t, + pub st_nlink: nlink_t, + pub st_mode: mode_t, + pub st_uid: uid_t, + pub st_gid: gid_t, + __pad0: c_int, + pub st_rdev: dev_t, + pub st_size: off64_t, + pub st_blksize: blksize_t, + pub st_blocks: blkcnt64_t, + pub st_atime: time_t, + pub st_atime_nsec: c_long, + pub st_mtime: time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: time_t, + pub st_ctime_nsec: c_long, + __reserved: [c_long; 3], +} diff --git a/src/sys/linux/fs.rs b/src/sys/linux/fs.rs index f0c3b3e83..7a89e7c80 100644 --- a/src/sys/linux/fs.rs +++ b/src/sys/linux/fs.rs @@ -3,10 +3,11 @@ use ctypes::c_ushort; use ffi::{CString, CStr, OsString, OsStr}; use fmt; use io::{self, Error, SeekFrom}; -use linux::mode_t; +use linux::types::{mode_t, stat64}; use linux; +use mem; use path::{Path, PathBuf}; -use super::cvt_r; +use super::{cvt, cvt_r}; use sys::errno; use sys::ext::ffi::OsStrExt; use sys::fd::FileDesc; @@ -21,9 +22,6 @@ enum dirent64 { } pub struct File(FileDesc); -#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -#[allow(non_camel_case_types)] -pub enum stat64 { } #[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)] pub enum ReadDir { } #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] @@ -57,13 +55,25 @@ pub struct FileType { mode: mode_t } pub struct DirBuilder { mode: mode_t } impl FileAttr { - /* - pub fn size(&self) -> u64 { unimplemented!(); } - pub fn perm(&self) -> FilePermissions { unimplemented!(); } - pub fn file_type(&self) -> FileType { unimplemented!(); } - pub fn modified(&self) -> io::Result { unimplemented!(); } - pub fn accessed(&self) -> io::Result { unimplemented!(); } - */ + pub fn size(&self) -> u64 { self.stat.st_size as u64 } + pub fn perm(&self) -> FilePermissions { + FilePermissions { mode: self.stat.st_mode & 0o777 } + } + pub fn file_type(&self) -> FileType { + FileType { mode: self.stat.st_mode } + } + pub fn modified(&self) -> io::Result { + Ok(SystemTime::from(linux::timespec { + tv_sec: self.stat.st_mtime, + tv_nsec: self.stat.st_mtime_nsec, + })) + } + pub fn accessed(&self) -> io::Result { + Ok(SystemTime::from(linux::timespec { + tv_sec: self.stat.st_atime, + tv_nsec: self.stat.st_atime_nsec, + })) + } pub fn created(&self) -> io::Result { Err(io::Error::new(io::ErrorKind::Other, "creation time is not available on this platform \ @@ -75,20 +85,27 @@ impl AsInner for FileAttr { fn as_inner(&self) -> &stat64 { &self.stat } } -/* impl FilePermissions { - pub fn readonly(&self) -> bool { unimplemented!(); } - pub fn set_readonly(&mut self, readonly: bool) { unimplemented!(); } - pub fn mode(&self) -> u32 { unimplemented!(); } + pub fn readonly(&self) -> bool { self.mode & 0o222 == 0 } + pub fn set_readonly(&mut self, readonly: bool) { + if readonly { + self.mode &= !0o222; + } else { + self.mode |= 0o222; + } + } + pub fn mode(&self) -> u32 { self.mode as u32 } } impl FileType { - pub fn is_dir(&self) -> bool { unimplemented!(); } - pub fn is_file(&self) -> bool { unimplemented!(); } - pub fn is_symlink(&self) -> bool { unimplemented!(); } - pub fn is(&self, mode: mode_t) -> bool { unimplemented!(); } + pub fn is_dir(&self) -> bool { self.is(linux::S_IFDIR) } + pub fn is_file(&self) -> bool { self.is(linux::S_IFREG) } + pub fn is_symlink(&self) -> bool { self.is(linux::S_IFLNK) } + + pub fn is(&self, mode: mode_t) -> bool { self.mode & linux::S_IFMT == mode } } +/* impl FromInner for FilePermissions { fn from_inner(mode: u32) -> FilePermissions { unimplemented!(); @@ -234,11 +251,13 @@ impl File { Ok(File(fd)) } - /* pub fn file_attr(&self) -> io::Result { - unimplemented!(); + let mut stat: stat64 = unsafe { mem::zeroed() }; + cvt(unsafe { + linux::fstat64(self.0.raw(), &mut stat) + })?; + Ok(FileAttr { stat: stat }) } - */ pub fn fsync(&self) -> io::Result<()> { cvt_r(|| unsafe { linux::fsync(self.0.raw()) })?; @@ -367,15 +386,27 @@ pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> { pub fn link(src: &Path, dst: &Path) -> io::Result<()> { unimplemented!(); } +*/ pub fn stat(p: &Path) -> io::Result { - unimplemented!(); + let p = cstr(p)?; + let mut stat: stat64 = unsafe { mem::zeroed() }; + cvt(unsafe { + linux::stat64(p.as_ptr(), &mut stat) + })?; + Ok(FileAttr { stat: stat }) } pub fn lstat(p: &Path) -> io::Result { - unimplemented!(); + let p = cstr(p)?; + let mut stat: stat64 = unsafe { mem::zeroed() }; + cvt(unsafe { + linux::lstat64(p.as_ptr(), &mut stat) + })?; + Ok(FileAttr { stat: stat }) } +/* pub fn canonicalize(p: &Path) -> io::Result { unimplemented!(); } From bad33b6ef85c5af6ac95e3e7a61df9416c0179b0 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Sat, 21 Jan 2017 21:15:27 +0100 Subject: [PATCH 2/4] stat: Fix ARM and x86 build --- src/linux/arm.rs | 6 ++++++ src/linux/x86.rs | 1 + 2 files changed, 7 insertions(+) diff --git a/src/linux/arm.rs b/src/linux/arm.rs index b8a8a15bd..2360f3a58 100644 --- a/src/linux/arm.rs +++ b/src/linux/arm.rs @@ -11,6 +11,12 @@ pub const O_TRUNC: c_int = 0o00001000; pub const FIOCLEX: c_uint = 0x5451; +// include/linux/types.h +pub type ino_t = __kernel_ino_t; +// include/uapi/asm-generic/posix_types.h +type __kernel_ino_t = __kernel_long_t; +type __kernel_long_t = c_long; + #[derive(Clone, Copy)] #[repr(C)] pub struct stat64 { diff --git a/src/linux/x86.rs b/src/linux/x86.rs index b3641ba9e..2360f3a58 100644 --- a/src/linux/x86.rs +++ b/src/linux/x86.rs @@ -15,6 +15,7 @@ pub const FIOCLEX: c_uint = 0x5451; pub type ino_t = __kernel_ino_t; // include/uapi/asm-generic/posix_types.h type __kernel_ino_t = __kernel_long_t; +type __kernel_long_t = c_long; #[derive(Clone, Copy)] #[repr(C)] From 937e4f3e03959d515609d163eeafe307ec293dc7 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 21 Jan 2017 17:53:49 -0500 Subject: [PATCH 3/4] implement env::args closes #7 cc #69 --- ci/script.sh | 1 + examples/args.rs | 7 + src/env.rs | 1024 +++++++++++++++++++++++++++ src/lib.rs | 8 +- src/process.rs | 1 + src/rt.rs | 8 +- src/sys/linux/args.rs | 87 +++ src/sys/linux/env.rs | 185 +++++ src/sys/linux/ext/fs.rs | 2 +- src/sys/linux/fs.rs | 2 +- src/sys/linux/mod.rs | 4 +- src/sys/mod.rs | 24 - src/{sys/linux => sys_common}/io.rs | 0 src/sys_common/mod.rs | 55 ++ 14 files changed, 1377 insertions(+), 31 deletions(-) create mode 100644 examples/args.rs create mode 100644 src/env.rs create mode 100644 src/sys/linux/args.rs create mode 100644 src/sys/linux/env.rs rename src/{sys/linux => sys_common}/io.rs (100%) create mode 100644 src/sys_common/mod.rs diff --git a/ci/script.sh b/ci/script.sh index 6399cd442..5b05ceede 100644 --- a/ci/script.sh +++ b/ci/script.sh @@ -8,6 +8,7 @@ main() { fi local examples=( + args create format format diff --git a/examples/args.rs b/examples/args.rs new file mode 100644 index 000000000..18da16eb0 --- /dev/null +++ b/examples/args.rs @@ -0,0 +1,7 @@ +use std::env; + +fn main() { + for arg in env::args_os() { + println!("{:?}", arg); + } +} diff --git a/src/env.rs b/src/env.rs new file mode 100644 index 000000000..7794ff358 --- /dev/null +++ b/src/env.rs @@ -0,0 +1,1024 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Inspection and manipulation of the process's environment. +//! +//! This module contains methods to inspect various aspects such as +//! environment variables, process arguments, the current directory, and various +//! other important directories. + +#![stable(feature = "env", since = "1.0.0")] + +#[cfg(issue = "69")] +use error::Error; +#[cfg(issue = "69")] +use ffi::{OsStr, OsString}; +use ffi::OsString; +#[cfg(issue = "69")] +use fmt; +#[cfg(issue = "69")] +use io; +#[cfg(issue = "69")] +use path::{Path, PathBuf}; +use sys; +#[cfg(issue = "69")] +use sys::os as os_imp; + +/// Returns the current working directory as a `PathBuf`. +/// +/// # Errors +/// +/// Returns an `Err` if the current working directory value is invalid. +/// Possible cases: +/// +/// * Current directory does not exist. +/// * There are insufficient permissions to access the current directory. +/// +/// # Examples +/// +/// ``` +/// use std::env; +/// +/// // We assume that we are in a valid directory. +/// let p = env::current_dir().unwrap(); +/// println!("The current directory is {}", p.display()); +/// ``` +#[cfg(issue = "69")] +#[stable(feature = "env", since = "1.0.0")] +pub fn current_dir() -> io::Result { + os_imp::getcwd() +} + +/// Changes the current working directory to the specified path, returning +/// whether the change was completed successfully or not. +/// +/// # Examples +/// +/// ``` +/// use std::env; +/// use std::path::Path; +/// +/// let root = Path::new("/"); +/// assert!(env::set_current_dir(&root).is_ok()); +/// println!("Successfully changed working directory to {}!", root.display()); +/// ``` +#[cfg(issue = "69")] +#[stable(feature = "env", since = "1.0.0")] +pub fn set_current_dir>(p: P) -> io::Result<()> { + os_imp::chdir(p.as_ref()) +} + +/// An iterator over a snapshot of the environment variables of this process. +/// +/// This iterator is created through `std::env::vars()` and yields `(String, +/// String)` pairs. +#[cfg(issue = "69")] +#[stable(feature = "env", since = "1.0.0")] +pub struct Vars { inner: VarsOs } + +/// An iterator over a snapshot of the environment variables of this process. +/// +/// This iterator is created through `std::env::vars_os()` and yields +/// `(OsString, OsString)` pairs. +#[cfg(issue = "69")] +#[stable(feature = "env", since = "1.0.0")] +pub struct VarsOs { inner: os_imp::Env } + +/// Returns an iterator of (variable, value) pairs of strings, for all the +/// environment variables of the current process. +/// +/// The returned iterator contains a snapshot of the process's environment +/// variables at the time of this invocation. Modifications to environment +/// variables afterwards will not be reflected in the returned iterator. +/// +/// # Panics +/// +/// While iterating, the returned iterator will panic if any key or value in the +/// environment is not valid unicode. If this is not desired, consider using the +/// `env::vars_os` function. +/// +/// # Examples +/// +/// ``` +/// use std::env; +/// +/// // We will iterate through the references to the element returned by +/// // env::vars(); +/// for (key, value) in env::vars() { +/// println!("{}: {}", key, value); +/// } +/// ``` +#[cfg(issue = "69")] +#[stable(feature = "env", since = "1.0.0")] +pub fn vars() -> Vars { + Vars { inner: vars_os() } +} + +/// Returns an iterator of (variable, value) pairs of OS strings, for all the +/// environment variables of the current process. +/// +/// The returned iterator contains a snapshot of the process's environment +/// variables at the time of this invocation. Modifications to environment +/// variables afterwards will not be reflected in the returned iterator. +/// +/// # Examples +/// +/// ``` +/// use std::env; +/// +/// // We will iterate through the references to the element returned by +/// // env::vars_os(); +/// for (key, value) in env::vars_os() { +/// println!("{:?}: {:?}", key, value); +/// } +/// ``` +#[cfg(issue = "69")] +#[stable(feature = "env", since = "1.0.0")] +pub fn vars_os() -> VarsOs { + VarsOs { inner: os_imp::env() } +} + +#[cfg(issue = "69")] +#[stable(feature = "env", since = "1.0.0")] +impl Iterator for Vars { + type Item = (String, String); + fn next(&mut self) -> Option<(String, String)> { + self.inner.next().map(|(a, b)| { + (a.into_string().unwrap(), b.into_string().unwrap()) + }) + } + fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } +} + +#[cfg(issue = "69")] +#[stable(feature = "env", since = "1.0.0")] +impl Iterator for VarsOs { + type Item = (OsString, OsString); + fn next(&mut self) -> Option<(OsString, OsString)> { self.inner.next() } + fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } +} + +/// Fetches the environment variable `key` from the current process. +/// +/// The returned result is `Ok(s)` if the environment variable is present and is +/// valid unicode. If the environment variable is not present, or it is not +/// valid unicode, then `Err` will be returned. +/// +/// # Examples +/// +/// ``` +/// use std::env; +/// +/// let key = "HOME"; +/// match env::var(key) { +/// Ok(val) => println!("{}: {:?}", key, val), +/// Err(e) => println!("couldn't interpret {}: {}", key, e), +/// } +/// ``` +#[cfg(issue = "69")] +#[stable(feature = "env", since = "1.0.0")] +pub fn var>(key: K) -> Result { + _var(key.as_ref()) +} + +#[cfg(issue = "69")] +fn _var(key: &OsStr) -> Result { + match var_os(key) { + Some(s) => s.into_string().map_err(VarError::NotUnicode), + None => Err(VarError::NotPresent) + } +} + +/// Fetches the environment variable `key` from the current process, returning +/// `None` if the variable isn't set. +/// +/// # Examples +/// +/// ``` +/// use std::env; +/// +/// let key = "HOME"; +/// match env::var_os(key) { +/// Some(val) => println!("{}: {:?}", key, val), +/// None => println!("{} is not defined in the environment.", key) +/// } +/// ``` +#[cfg(issue = "69")] +#[stable(feature = "env", since = "1.0.0")] +pub fn var_os>(key: K) -> Option { + _var_os(key.as_ref()) +} + +#[cfg(issue = "69")] +fn _var_os(key: &OsStr) -> Option { + os_imp::getenv(key).unwrap_or_else(|e| { + panic!("failed to get environment variable `{:?}`: {}", key, e) + }) +} + +/// Possible errors from the `env::var` method. +#[cfg(issue = "69")] +#[derive(Debug, PartialEq, Eq, Clone)] +#[stable(feature = "env", since = "1.0.0")] +pub enum VarError { + /// The specified environment variable was not present in the current + /// process's environment. + #[stable(feature = "env", since = "1.0.0")] + NotPresent, + + /// The specified environment variable was found, but it did not contain + /// valid unicode data. The found data is returned as a payload of this + /// variant. + #[stable(feature = "env", since = "1.0.0")] + NotUnicode(#[stable(feature = "env", since = "1.0.0")] OsString), +} + +#[cfg(issue = "69")] +#[stable(feature = "env", since = "1.0.0")] +impl fmt::Display for VarError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + VarError::NotPresent => write!(f, "environment variable not found"), + VarError::NotUnicode(ref s) => { + write!(f, "environment variable was not valid unicode: {:?}", s) + } + } + } +} + +#[cfg(issue = "69")] +#[stable(feature = "env", since = "1.0.0")] +impl Error for VarError { + fn description(&self) -> &str { + match *self { + VarError::NotPresent => "environment variable not found", + VarError::NotUnicode(..) => "environment variable was not valid unicode", + } + } +} + +/// Sets the environment variable `k` to the value `v` for the currently running +/// process. +/// +/// Note that while concurrent access to environment variables is safe in Rust, +/// some platforms only expose inherently unsafe non-threadsafe APIs for +/// inspecting the environment. As a result extra care needs to be taken when +/// auditing calls to unsafe external FFI functions to ensure that any external +/// environment accesses are properly synchronized with accesses in Rust. +/// +/// Discussion of this unsafety on Unix may be found in: +/// +/// - [Austin Group Bugzilla](http://austingroupbugs.net/view.php?id=188) +/// - [GNU C library Bugzilla](https://sourceware.org/bugzilla/show_bug.cgi?id=15607#c2) +/// +/// # Panics +/// +/// This function may panic if `key` is empty, contains an ASCII equals sign +/// `'='` or the NUL character `'\0'`, or when the value contains the NUL +/// character. +/// +/// # Examples +/// +/// ``` +/// use std::env; +/// +/// let key = "KEY"; +/// env::set_var(key, "VALUE"); +/// assert_eq!(env::var(key), Ok("VALUE".to_string())); +/// ``` +#[cfg(issue = "69")] +#[stable(feature = "env", since = "1.0.0")] +pub fn set_var, V: AsRef>(k: K, v: V) { + _set_var(k.as_ref(), v.as_ref()) +} + +#[cfg(issue = "69")] +fn _set_var(k: &OsStr, v: &OsStr) { + os_imp::setenv(k, v).unwrap_or_else(|e| { + panic!("failed to set environment variable `{:?}` to `{:?}`: {}", + k, v, e) + }) +} + +/// Removes an environment variable from the environment of the currently running process. +/// +/// Note that while concurrent access to environment variables is safe in Rust, +/// some platforms only expose inherently unsafe non-threadsafe APIs for +/// inspecting the environment. As a result extra care needs to be taken when +/// auditing calls to unsafe external FFI functions to ensure that any external +/// environment accesses are properly synchronized with accesses in Rust. +/// +/// Discussion of this unsafety on Unix may be found in: +/// +/// - [Austin Group Bugzilla](http://austingroupbugs.net/view.php?id=188) +/// - [GNU C library Bugzilla](https://sourceware.org/bugzilla/show_bug.cgi?id=15607#c2) +/// +/// # Panics +/// +/// This function may panic if `key` is empty, contains an ASCII equals sign +/// `'='` or the NUL character `'\0'`, or when the value contains the NUL +/// character. +/// +/// # Examples +/// +/// ``` +/// use std::env; +/// +/// let key = "KEY"; +/// env::set_var(key, "VALUE"); +/// assert_eq!(env::var(key), Ok("VALUE".to_string())); +/// +/// env::remove_var(key); +/// assert!(env::var(key).is_err()); +/// ``` +#[cfg(issue = "69")] +#[stable(feature = "env", since = "1.0.0")] +pub fn remove_var>(k: K) { + _remove_var(k.as_ref()) +} + +#[cfg(issue = "69")] +fn _remove_var(k: &OsStr) { + os_imp::unsetenv(k).unwrap_or_else(|e| { + panic!("failed to remove environment variable `{:?}`: {}", k, e) + }) +} + +/// An iterator over `PathBuf` instances for parsing an environment variable +/// according to platform-specific conventions. +/// +/// This structure is returned from `std::env::split_paths`. +#[cfg(issue = "69")] +#[stable(feature = "env", since = "1.0.0")] +pub struct SplitPaths<'a> { inner: os_imp::SplitPaths<'a> } + +/// Parses input according to platform conventions for the `PATH` +/// environment variable. +/// +/// Returns an iterator over the paths contained in `unparsed`. +/// +/// # Examples +/// +/// ``` +/// use std::env; +/// +/// let key = "PATH"; +/// match env::var_os(key) { +/// Some(paths) => { +/// for path in env::split_paths(&paths) { +/// println!("'{}'", path.display()); +/// } +/// } +/// None => println!("{} is not defined in the environment.", key) +/// } +/// ``` +#[cfg(issue = "69")] +#[stable(feature = "env", since = "1.0.0")] +pub fn split_paths + ?Sized>(unparsed: &T) -> SplitPaths { + SplitPaths { inner: os_imp::split_paths(unparsed.as_ref()) } +} + +#[cfg(issue = "69")] +#[stable(feature = "env", since = "1.0.0")] +impl<'a> Iterator for SplitPaths<'a> { + type Item = PathBuf; + fn next(&mut self) -> Option { self.inner.next() } + fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } +} + +/// Error type returned from `std::env::join_paths` when paths fail to be +/// joined. +#[cfg(issue = "69")] +#[derive(Debug)] +#[stable(feature = "env", since = "1.0.0")] +pub struct JoinPathsError { + inner: os_imp::JoinPathsError +} + +/// Joins a collection of `Path`s appropriately for the `PATH` +/// environment variable. +/// +/// Returns an `OsString` on success. +/// +/// Returns an `Err` (containing an error message) if one of the input +/// `Path`s contains an invalid character for constructing the `PATH` +/// variable (a double quote on Windows or a colon on Unix). +/// +/// # Examples +/// +/// ``` +/// use std::env; +/// use std::path::PathBuf; +/// +/// if let Some(path) = env::var_os("PATH") { +/// let mut paths = env::split_paths(&path).collect::>(); +/// paths.push(PathBuf::from("/home/xyz/bin")); +/// let new_path = env::join_paths(paths).unwrap(); +/// env::set_var("PATH", &new_path); +/// } +/// ``` +#[cfg(issue = "69")] +#[stable(feature = "env", since = "1.0.0")] +pub fn join_paths(paths: I) -> Result + where I: IntoIterator, T: AsRef +{ + os_imp::join_paths(paths.into_iter()).map_err(|e| { + JoinPathsError { inner: e } + }) +} + +#[cfg(issue = "69")] +#[stable(feature = "env", since = "1.0.0")] +impl fmt::Display for JoinPathsError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.inner.fmt(f) + } +} + +#[cfg(issue = "69")] +#[stable(feature = "env", since = "1.0.0")] +impl Error for JoinPathsError { + fn description(&self) -> &str { self.inner.description() } +} + +/// Returns the path of the current user's home directory if known. +/// +/// # Unix +/// +/// Returns the value of the 'HOME' environment variable if it is set +/// and not equal to the empty string. Otherwise, it tries to determine the +/// home directory by invoking the `getpwuid_r` function on the UID of the +/// current user. +/// +/// # Windows +/// +/// Returns the value of the 'HOME' environment variable if it is +/// set and not equal to the empty string. Otherwise, returns the value of the +/// 'USERPROFILE' environment variable if it is set and not equal to the empty +/// string. If both do not exist, [`GetUserProfileDirectory`][msdn] is used to +/// return the appropriate path. +/// +/// [msdn]: https://msdn.microsoft.com/en-us/library/windows/desktop/bb762280(v=vs.85).aspx +/// +/// # Examples +/// +/// ``` +/// use std::env; +/// +/// match env::home_dir() { +/// Some(path) => println!("{}", path.display()), +/// None => println!("Impossible to get your home dir!"), +/// } +/// ``` +#[cfg(issue = "69")] +#[stable(feature = "env", since = "1.0.0")] +pub fn home_dir() -> Option { + os_imp::home_dir() +} + +/// Returns the path of a temporary directory. +/// +/// On Unix, returns the value of the `TMPDIR` environment variable if it is +/// set, otherwise for non-Android it returns `/tmp`. If Android, since there +/// is no global temporary folder (it is usually allocated per-app), it returns +/// `/data/local/tmp`. +/// +/// On Windows, returns the value of, in order, the `TMP`, `TEMP`, +/// `USERPROFILE` environment variable if any are set and not the empty +/// string. Otherwise, `temp_dir` returns the path of the Windows directory. +/// This behavior is identical to that of [`GetTempPath`][msdn], which this +/// function uses internally. +/// +/// [msdn]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa364992(v=vs.85).aspx +/// +/// ``` +/// use std::env; +/// use std::fs::File; +/// +/// # fn foo() -> std::io::Result<()> { +/// let mut dir = env::temp_dir(); +/// dir.push("foo.txt"); +/// +/// let f = try!(File::create(dir)); +/// # Ok(()) +/// # } +/// ``` +#[cfg(issue = "69")] +#[stable(feature = "env", since = "1.0.0")] +pub fn temp_dir() -> PathBuf { + os_imp::temp_dir() +} + +/// Returns the full filesystem path of the current running executable. +/// +/// The path returned is not necessarily a "real path" of the executable as +/// there may be intermediate symlinks. +/// +/// # Errors +/// +/// Acquiring the path of the current executable is a platform-specific operation +/// that can fail for a good number of reasons. Some errors can include, but not +/// be limited to, filesystem operations failing or general syscall failures. +/// +/// # Security +/// +/// The output of this function should not be used in anything that might have +/// security implications. For example: +/// +/// ``` +/// fn main() { +/// println!("{:?}", std::env::current_exe()); +/// } +/// ``` +/// +/// On Linux systems, if this is compiled as `foo`: +/// +/// ```bash +/// $ rustc foo.rs +/// $ ./foo +/// Ok("/home/alex/foo") +/// ``` +/// +/// And you make a symbolic link of the program: +/// +/// ```bash +/// $ ln foo bar +/// ``` +/// +/// When you run it, you won't get the original executable, you'll get the +/// symlink: +/// +/// ```bash +/// $ ./bar +/// Ok("/home/alex/bar") +/// ``` +/// +/// This sort of behavior has been known to [lead to privilege escalation] when +/// used incorrectly, for example. +/// +/// [lead to privilege escalation]: http://securityvulns.com/Wdocument183.html +/// +/// # Examples +/// +/// ``` +/// use std::env; +/// +/// match env::current_exe() { +/// Ok(exe_path) => println!("Path of this executable is: {}", +/// exe_path.display()), +/// Err(e) => println!("failed to get current exe path: {}", e), +/// }; +/// ``` +#[cfg(issue = "69")] +#[stable(feature = "env", since = "1.0.0")] +pub fn current_exe() -> io::Result { + os_imp::current_exe() +} + +/// An iterator over the arguments of a process, yielding a `String` value +/// for each argument. +/// +/// This structure is created through the `std::env::args` method. +#[stable(feature = "env", since = "1.0.0")] +pub struct Args { inner: ArgsOs } + +/// An iterator over the arguments of a process, yielding an `OsString` value +/// for each argument. +/// +/// This structure is created through the `std::env::args_os` method. +#[stable(feature = "env", since = "1.0.0")] +pub struct ArgsOs { inner: sys::args::Args } + +/// Returns the arguments which this program was started with (normally passed +/// via the command line). +/// +/// The first element is traditionally the path of the executable, but it can be +/// set to arbitrary text, and may not even exist. This means this property should +/// not be relied upon for security purposes. +/// +/// # Panics +/// +/// The returned iterator will panic during iteration if any argument to the +/// process is not valid unicode. If this is not desired, +/// use the `args_os` function instead. +/// +/// # Examples +/// +/// ``` +/// use std::env; +/// +/// // Prints each argument on a separate line +/// for argument in env::args() { +/// println!("{}", argument); +/// } +/// ``` +#[stable(feature = "env", since = "1.0.0")] +pub fn args() -> Args { + Args { inner: args_os() } +} + +/// Returns the arguments which this program was started with (normally passed +/// via the command line). +/// +/// The first element is traditionally the path of the executable, but it can be +/// set to arbitrary text, and it may not even exist, so this property should +/// not be relied upon for security purposes. +/// +/// # Examples +/// +/// ``` +/// use std::env; +/// +/// // Prints each argument on a separate line +/// for argument in env::args_os() { +/// println!("{:?}", argument); +/// } +/// ``` +#[stable(feature = "env", since = "1.0.0")] +pub fn args_os() -> ArgsOs { + ArgsOs { inner: sys::args::args() } +} + +#[stable(feature = "env", since = "1.0.0")] +impl Iterator for Args { + type Item = String; + fn next(&mut self) -> Option { + self.inner.next().map(|s| s.into_string().unwrap()) + } + fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } +} + +#[stable(feature = "env", since = "1.0.0")] +impl ExactSizeIterator for Args { + fn len(&self) -> usize { self.inner.len() } +} + +#[stable(feature = "env_iterators", since = "1.11.0")] +impl DoubleEndedIterator for Args { + fn next_back(&mut self) -> Option { + self.inner.next_back().map(|s| s.into_string().unwrap()) + } +} + +#[stable(feature = "env", since = "1.0.0")] +impl Iterator for ArgsOs { + type Item = OsString; + fn next(&mut self) -> Option { self.inner.next() } + fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } +} + +#[stable(feature = "env", since = "1.0.0")] +impl ExactSizeIterator for ArgsOs { + fn len(&self) -> usize { self.inner.len() } +} + +#[stable(feature = "env_iterators", since = "1.11.0")] +impl DoubleEndedIterator for ArgsOs { + fn next_back(&mut self) -> Option { self.inner.next_back() } +} +/// Constants associated with the current target +#[stable(feature = "env", since = "1.0.0")] +pub mod consts { + use sys::env::os; + + /// A string describing the architecture of the CPU that is currently + /// in use. + /// + /// Some possible values: + /// + /// - x86 + /// - x86_64 + /// - arm + /// - aarch64 + /// - mips + /// - mips64 + /// - powerpc + /// - powerpc64 + /// - s390x + #[stable(feature = "env", since = "1.0.0")] + pub const ARCH: &'static str = super::arch::ARCH; + + /// The family of the operating system. Example value is `unix`. + /// + /// Some possible values: + /// + /// - unix + /// - windows + #[stable(feature = "env", since = "1.0.0")] + pub const FAMILY: &'static str = os::FAMILY; + + /// A string describing the specific operating system in use. + /// Example value is `linux`. + /// + /// Some possible values: + /// + /// - linux + /// - macos + /// - ios + /// - freebsd + /// - dragonfly + /// - bitrig + /// - netbsd + /// - openbsd + /// - solaris + /// - android + /// - windows + #[stable(feature = "env", since = "1.0.0")] + pub const OS: &'static str = os::OS; + + /// Specifies the filename prefix used for shared libraries on this + /// platform. Example value is `lib`. + /// + /// Some possible values: + /// + /// - lib + /// - `""` (an empty string) + #[stable(feature = "env", since = "1.0.0")] + pub const DLL_PREFIX: &'static str = os::DLL_PREFIX; + + /// Specifies the filename suffix used for shared libraries on this + /// platform. Example value is `.so`. + /// + /// Some possible values: + /// + /// - .so + /// - .dylib + /// - .dll + #[stable(feature = "env", since = "1.0.0")] + pub const DLL_SUFFIX: &'static str = os::DLL_SUFFIX; + + /// Specifies the file extension used for shared libraries on this + /// platform that goes after the dot. Example value is `so`. + /// + /// Some possible values: + /// + /// - so + /// - dylib + /// - dll + #[stable(feature = "env", since = "1.0.0")] + pub const DLL_EXTENSION: &'static str = os::DLL_EXTENSION; + + /// Specifies the filename suffix used for executable binaries on this + /// platform. Example value is `.exe`. + /// + /// Some possible values: + /// + /// - .exe + /// - .nexe + /// - .pexe + /// - `""` (an empty string) + #[stable(feature = "env", since = "1.0.0")] + pub const EXE_SUFFIX: &'static str = os::EXE_SUFFIX; + + /// Specifies the file extension, if any, used for executable binaries + /// on this platform. Example value is `exe`. + /// + /// Some possible values: + /// + /// - exe + /// - `""` (an empty string) + #[stable(feature = "env", since = "1.0.0")] + pub const EXE_EXTENSION: &'static str = os::EXE_EXTENSION; +} + +#[cfg(target_arch = "x86")] +mod arch { + pub const ARCH: &'static str = "x86"; +} + +#[cfg(target_arch = "x86_64")] +mod arch { + pub const ARCH: &'static str = "x86_64"; +} + +#[cfg(target_arch = "arm")] +mod arch { + pub const ARCH: &'static str = "arm"; +} + +#[cfg(target_arch = "aarch64")] +mod arch { + pub const ARCH: &'static str = "aarch64"; +} + +#[cfg(target_arch = "mips")] +mod arch { + pub const ARCH: &'static str = "mips"; +} + +#[cfg(target_arch = "mips64")] +mod arch { + pub const ARCH: &'static str = "mips64"; +} + +#[cfg(target_arch = "powerpc")] +mod arch { + pub const ARCH: &'static str = "powerpc"; +} + +#[cfg(target_arch = "powerpc64")] +mod arch { + pub const ARCH: &'static str = "powerpc64"; +} + +#[cfg(target_arch = "s390x")] +mod arch { + pub const ARCH: &'static str = "s390x"; +} + +#[cfg(target_arch = "le32")] +mod arch { + pub const ARCH: &'static str = "le32"; +} + +#[cfg(target_arch = "asmjs")] +mod arch { + pub const ARCH: &'static str = "asmjs"; +} + +#[cfg(target_arch = "wasm32")] +mod arch { + pub const ARCH: &'static str = "wasm32"; +} + +#[cfg(test)] +mod tests { + use super::*; + + use iter::repeat; + use rand::{self, Rng}; + use ffi::{OsString, OsStr}; + use path::{Path, PathBuf}; + + fn make_rand_name() -> OsString { + let mut rng = rand::thread_rng(); + let n = format!("TEST{}", rng.gen_ascii_chars().take(10) + .collect::()); + let n = OsString::from(n); + assert!(var_os(&n).is_none()); + n + } + + fn eq(a: Option, b: Option<&str>) { + assert_eq!(a.as_ref().map(|s| &**s), b.map(OsStr::new).map(|s| &*s)); + } + + #[test] + fn test_set_var() { + let n = make_rand_name(); + set_var(&n, "VALUE"); + eq(var_os(&n), Some("VALUE")); + } + + #[test] + fn test_remove_var() { + let n = make_rand_name(); + set_var(&n, "VALUE"); + remove_var(&n); + eq(var_os(&n), None); + } + + #[test] + fn test_set_var_overwrite() { + let n = make_rand_name(); + set_var(&n, "1"); + set_var(&n, "2"); + eq(var_os(&n), Some("2")); + set_var(&n, ""); + eq(var_os(&n), Some("")); + } + + #[test] + #[cfg_attr(target_os = "emscripten", ignore)] + fn test_var_big() { + let mut s = "".to_string(); + let mut i = 0; + while i < 100 { + s.push_str("aaaaaaaaaa"); + i += 1; + } + let n = make_rand_name(); + set_var(&n, &s); + eq(var_os(&n), Some(&s)); + } + + #[test] + #[cfg_attr(target_os = "emscripten", ignore)] + fn test_self_exe_path() { + let path = current_exe(); + assert!(path.is_ok()); + let path = path.unwrap(); + + // Hard to test this function + assert!(path.is_absolute()); + } + + #[test] + #[cfg_attr(target_os = "emscripten", ignore)] + fn test_env_set_get_huge() { + let n = make_rand_name(); + let s = repeat("x").take(10000).collect::(); + set_var(&n, &s); + eq(var_os(&n), Some(&s)); + remove_var(&n); + eq(var_os(&n), None); + } + + #[test] + fn test_env_set_var() { + let n = make_rand_name(); + + let mut e = vars_os(); + set_var(&n, "VALUE"); + assert!(!e.any(|(k, v)| { + &*k == &*n && &*v == "VALUE" + })); + + assert!(vars_os().any(|(k, v)| { + &*k == &*n && &*v == "VALUE" + })); + } + + #[test] + fn test() { + assert!((!Path::new("test-path").is_absolute())); + + current_dir().unwrap(); + } + + #[test] + #[cfg(windows)] + fn split_paths_windows() { + fn check_parse(unparsed: &str, parsed: &[&str]) -> bool { + split_paths(unparsed).collect::>() == + parsed.iter().map(|s| PathBuf::from(*s)).collect::>() + } + + assert!(check_parse("", &mut [""])); + assert!(check_parse(r#""""#, &mut [""])); + assert!(check_parse(";;", &mut ["", "", ""])); + assert!(check_parse(r"c:\", &mut [r"c:\"])); + assert!(check_parse(r"c:\;", &mut [r"c:\", ""])); + assert!(check_parse(r"c:\;c:\Program Files\", + &mut [r"c:\", r"c:\Program Files\"])); + assert!(check_parse(r#"c:\;c:\"foo"\"#, &mut [r"c:\", r"c:\foo\"])); + assert!(check_parse(r#"c:\;c:\"foo;bar"\;c:\baz"#, + &mut [r"c:\", r"c:\foo;bar\", r"c:\baz"])); + } + + #[test] + #[cfg(unix)] + fn split_paths_unix() { + fn check_parse(unparsed: &str, parsed: &[&str]) -> bool { + split_paths(unparsed).collect::>() == + parsed.iter().map(|s| PathBuf::from(*s)).collect::>() + } + + assert!(check_parse("", &mut [""])); + assert!(check_parse("::", &mut ["", "", ""])); + assert!(check_parse("/", &mut ["/"])); + assert!(check_parse("/:", &mut ["/", ""])); + assert!(check_parse("/:/usr/local", &mut ["/", "/usr/local"])); + } + + #[test] + #[cfg(unix)] + fn join_paths_unix() { + fn test_eq(input: &[&str], output: &str) -> bool { + &*join_paths(input.iter().cloned()).unwrap() == + OsStr::new(output) + } + + assert!(test_eq(&[], "")); + assert!(test_eq(&["/bin", "/usr/bin", "/usr/local/bin"], + "/bin:/usr/bin:/usr/local/bin")); + assert!(test_eq(&["", "/bin", "", "", "/usr/bin", ""], + ":/bin:::/usr/bin:")); + assert!(join_paths(["/te:st"].iter().cloned()).is_err()); + } + + #[test] + #[cfg(windows)] + fn join_paths_windows() { + fn test_eq(input: &[&str], output: &str) -> bool { + &*join_paths(input.iter().cloned()).unwrap() == + OsStr::new(output) + } + + assert!(test_eq(&[], "")); + assert!(test_eq(&[r"c:\windows", r"c:\"], + r"c:\windows;c:\")); + assert!(test_eq(&["", r"c:\windows", "", "", r"c:\", ""], + r";c:\windows;;;c:\;")); + assert!(test_eq(&[r"c:\te;st", r"c:\"], + r#""c:\te;st";c:\"#)); + assert!(join_paths([r#"c:\te"st"#].iter().cloned()).is_err()); + } + } diff --git a/src/lib.rs b/src/lib.rs index 67082e0d0..9d0fb2471 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,7 +5,9 @@ #![feature(collections_bound)] #![feature(collections_range)] #![feature(compiler_builtins_lib)] +#![feature(const_fn)] #![feature(core_intrinsics)] +#![feature(drop_types_in_const)] #![feature(dropck_parametricity)] #![feature(fused)] #![feature(int_error_internals)] @@ -138,6 +140,8 @@ pub mod ascii; // Rust 1.14.0 pub mod collections; // Rust 1.14.0 +pub mod env; +// Rust 1.14.0 pub mod error; // Rust 1.14.0 pub mod ffi; @@ -161,9 +165,7 @@ mod ctypes; mod linux; mod panicking; mod sys; -mod sys_common { - pub use sys::*; -} +mod sys_common; mod libc { pub use ctypes::*; pub unsafe fn strlen(cs: *const c_char) -> size_t { diff --git a/src/process.rs b/src/process.rs index 7694f9e66..96c53edc3 100644 --- a/src/process.rs +++ b/src/process.rs @@ -4,5 +4,6 @@ use linux; #[stable(feature = "steed", since = "1.0.0")] pub fn exit(code: i32) -> ! { + ::sys_common::cleanup(); unsafe { linux::exit(code) } } diff --git a/src/rt.rs b/src/rt.rs index 30eb6f653..e18d9218e 100644 --- a/src/rt.rs +++ b/src/rt.rs @@ -198,7 +198,13 @@ pub extern "C" fn start(sp: &'static Stack) -> ! { fn main(argc: isize, argv: *const *const u8) -> isize; } - unsafe { ::linux::exit(main(sp.argc(), sp.argv()) as i32) } + let argc = sp.argc(); + let argv = sp.argv(); + + unsafe { + ::sys::args::init(argc, argv); + ::process::exit(main(sp.argc(), sp.argv()) as i32) + } } // This is how the `start` lang item actually works: diff --git a/src/sys/linux/args.rs b/src/sys/linux/args.rs new file mode 100644 index 000000000..72f38be80 --- /dev/null +++ b/src/sys/linux/args.rs @@ -0,0 +1,87 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Global initialization and retreival of command line arguments. +//! +//! On some platforms these are stored during runtime startup, +//! and on some they are retrieved from the system on demand. + +#![allow(dead_code)] // runtime init functions not used during testing + +use ffi::OsString; +use marker::PhantomData; +use vec; + +/// One-time global initialization. +pub unsafe fn init(argc: isize, argv: *const *const u8) { imp::init(argc, argv) } + +/// One-time global cleanup. +pub unsafe fn cleanup() { imp::cleanup() } + +/// Returns the command line arguments +pub fn args() -> Args { + imp::args() +} + +pub struct Args { + iter: vec::IntoIter, + _dont_send_or_sync_me: PhantomData<*mut ()>, +} + +impl Iterator for Args { + type Item = OsString; + fn next(&mut self) -> Option { self.iter.next() } + fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } +} + +impl ExactSizeIterator for Args { + fn len(&self) -> usize { self.iter.len() } +} + +impl DoubleEndedIterator for Args { + fn next_back(&mut self) -> Option { self.iter.next_back() } +} + +mod imp { + use ffi::{CStr, OsString}; + use sys::ext::ffi::OsStringExt; + use marker::PhantomData; + use super::Args; + use cell::UnsafeCell; + use libc; + + static mut ARGS: UnsafeCell>>> = UnsafeCell::new(None); + + pub unsafe fn init(argc: isize, argv: *const *const u8) { + let args = (0..argc).map(|i| { + CStr::from_ptr(*argv.offset(i) as *const libc::c_char).to_bytes().to_vec() + }).collect(); + + *ARGS.get() = Some(args); + } + + pub unsafe fn cleanup() { + *ARGS.get() = None; + } + + pub fn args() -> Args { + let bytes = clone().unwrap_or(Vec::new()); + let v: Vec = bytes.into_iter().map(|v| { + OsStringExt::from_vec(v) + }).collect(); + Args { iter: v.into_iter(), _dont_send_or_sync_me: PhantomData } + } + + fn clone() -> Option>> { + unsafe { + (*ARGS.get()).as_ref().cloned() + } + } +} diff --git a/src/sys/linux/env.rs b/src/sys/linux/env.rs new file mode 100644 index 000000000..e9c8beb52 --- /dev/null +++ b/src/sys/linux/env.rs @@ -0,0 +1,185 @@ + +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[cfg(target_os = "linux")] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "linux"; + pub const DLL_PREFIX: &'static str = "lib"; + pub const DLL_SUFFIX: &'static str = ".so"; + pub const DLL_EXTENSION: &'static str = "so"; + pub const EXE_SUFFIX: &'static str = ""; + pub const EXE_EXTENSION: &'static str = ""; +} + +#[cfg(target_os = "macos")] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "macos"; + pub const DLL_PREFIX: &'static str = "lib"; + pub const DLL_SUFFIX: &'static str = ".dylib"; + pub const DLL_EXTENSION: &'static str = "dylib"; + pub const EXE_SUFFIX: &'static str = ""; + pub const EXE_EXTENSION: &'static str = ""; +} + +#[cfg(target_os = "ios")] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "ios"; + pub const DLL_PREFIX: &'static str = "lib"; + pub const DLL_SUFFIX: &'static str = ".dylib"; + pub const DLL_EXTENSION: &'static str = "dylib"; + pub const EXE_SUFFIX: &'static str = ""; + pub const EXE_EXTENSION: &'static str = ""; +} + +#[cfg(target_os = "freebsd")] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "freebsd"; + pub const DLL_PREFIX: &'static str = "lib"; + pub const DLL_SUFFIX: &'static str = ".so"; + pub const DLL_EXTENSION: &'static str = "so"; + pub const EXE_SUFFIX: &'static str = ""; + pub const EXE_EXTENSION: &'static str = ""; +} + +#[cfg(target_os = "dragonfly")] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "dragonfly"; + pub const DLL_PREFIX: &'static str = "lib"; + pub const DLL_SUFFIX: &'static str = ".so"; + pub const DLL_EXTENSION: &'static str = "so"; + pub const EXE_SUFFIX: &'static str = ""; + pub const EXE_EXTENSION: &'static str = ""; +} + +#[cfg(target_os = "bitrig")] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "bitrig"; + pub const DLL_PREFIX: &'static str = "lib"; + pub const DLL_SUFFIX: &'static str = ".so"; + pub const DLL_EXTENSION: &'static str = "so"; + pub const EXE_SUFFIX: &'static str = ""; + pub const EXE_EXTENSION: &'static str = ""; +} + +#[cfg(target_os = "netbsd")] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "netbsd"; + pub const DLL_PREFIX: &'static str = "lib"; + pub const DLL_SUFFIX: &'static str = ".so"; + pub const DLL_EXTENSION: &'static str = "so"; + pub const EXE_SUFFIX: &'static str = ""; + pub const EXE_EXTENSION: &'static str = ""; +} + +#[cfg(target_os = "openbsd")] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "openbsd"; + pub const DLL_PREFIX: &'static str = "lib"; + pub const DLL_SUFFIX: &'static str = ".so"; + pub const DLL_EXTENSION: &'static str = "so"; + pub const EXE_SUFFIX: &'static str = ""; + pub const EXE_EXTENSION: &'static str = ""; +} + +#[cfg(target_os = "android")] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "android"; + pub const DLL_PREFIX: &'static str = "lib"; + pub const DLL_SUFFIX: &'static str = ".so"; + pub const DLL_EXTENSION: &'static str = "so"; + pub const EXE_SUFFIX: &'static str = ""; + pub const EXE_EXTENSION: &'static str = ""; +} + +#[cfg(target_os = "solaris")] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "solaris"; + pub const DLL_PREFIX: &'static str = "lib"; + pub const DLL_SUFFIX: &'static str = ".so"; + pub const DLL_EXTENSION: &'static str = "so"; + pub const EXE_SUFFIX: &'static str = ""; + pub const EXE_EXTENSION: &'static str = ""; +} + +#[cfg(all(target_os = "nacl", not(target_arch = "le32")))] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "nacl"; + pub const DLL_PREFIX: &'static str = "lib"; + pub const DLL_SUFFIX: &'static str = ".so"; + pub const DLL_EXTENSION: &'static str = "so"; + pub const EXE_SUFFIX: &'static str = ".nexe"; + pub const EXE_EXTENSION: &'static str = "nexe"; +} +#[cfg(all(target_os = "nacl", target_arch = "le32"))] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "pnacl"; + pub const DLL_PREFIX: &'static str = "lib"; + pub const DLL_SUFFIX: &'static str = ".pso"; + pub const DLL_EXTENSION: &'static str = "pso"; + pub const EXE_SUFFIX: &'static str = ".pexe"; + pub const EXE_EXTENSION: &'static str = "pexe"; +} + +#[cfg(target_os = "haiku")] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "haiku"; + pub const DLL_PREFIX: &'static str = "lib"; + pub const DLL_SUFFIX: &'static str = ".so"; + pub const DLL_EXTENSION: &'static str = "so"; + pub const EXE_SUFFIX: &'static str = ""; + pub const EXE_EXTENSION: &'static str = ""; +} + +#[cfg(all(target_os = "emscripten", target_arch = "asmjs"))] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "emscripten"; + pub const DLL_PREFIX: &'static str = "lib"; + pub const DLL_SUFFIX: &'static str = ".so"; + pub const DLL_EXTENSION: &'static str = "so"; + pub const EXE_SUFFIX: &'static str = ".js"; + pub const EXE_EXTENSION: &'static str = "js"; +} + +#[cfg(all(target_os = "emscripten", target_arch = "wasm32"))] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "emscripten"; + pub const DLL_PREFIX: &'static str = "lib"; + pub const DLL_SUFFIX: &'static str = ".so"; + pub const DLL_EXTENSION: &'static str = "so"; + pub const EXE_SUFFIX: &'static str = ".js"; + pub const EXE_EXTENSION: &'static str = "js"; +} + +#[cfg(target_os = "fuchsia")] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "fuchsia"; + pub const DLL_PREFIX: &'static str = "lib"; + pub const DLL_SUFFIX: &'static str = ".so"; + pub const DLL_EXTENSION: &'static str = "so"; + pub const EXE_SUFFIX: &'static str = ""; + pub const EXE_EXTENSION: &'static str = ""; +} diff --git a/src/sys/linux/ext/fs.rs b/src/sys/linux/ext/fs.rs index a3125726e..55cd01053 100644 --- a/src/sys/linux/ext/fs.rs +++ b/src/sys/linux/ext/fs.rs @@ -2,7 +2,7 @@ use fs; use io; -use sys::AsInner; +use sys_common::AsInner; #[unstable(feature = "file_offset", issue = "35918")] pub trait FileExt { diff --git a/src/sys/linux/fs.rs b/src/sys/linux/fs.rs index 7a89e7c80..7f976b05d 100644 --- a/src/sys/linux/fs.rs +++ b/src/sys/linux/fs.rs @@ -12,7 +12,7 @@ use sys::errno; use sys::ext::ffi::OsStrExt; use sys::fd::FileDesc; use sys::time::SystemTime; -use sys::{AsInner, FromInner}; +use sys_common::{AsInner, FromInner}; #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] enum Dir { } diff --git a/src/sys/linux/mod.rs b/src/sys/linux/mod.rs index f38baee4a..b049e0f80 100644 --- a/src/sys/linux/mod.rs +++ b/src/sys/linux/mod.rs @@ -1,9 +1,11 @@ +pub mod args; +// Rust 1.14.0 +pub mod env; pub mod ext; #[cfg_attr(not(issue = "21"), allow(unused))] pub mod fd; #[cfg_attr(not(issue = "21"), allow(unused))] pub mod fs; -pub mod io; pub mod memchr; // Rust 1.14.0 pub mod os_str; diff --git a/src/sys/mod.rs b/src/sys/mod.rs index df6498f8a..369b7e6a4 100644 --- a/src/sys/mod.rs +++ b/src/sys/mod.rs @@ -34,27 +34,3 @@ pub use self::imp::*; #[path = "linux/mod.rs"] mod imp; - - -#[doc(hidden)] -pub trait AsInner { - fn as_inner(&self) -> &Inner; -} - -/// A trait for viewing representations from std types -#[doc(hidden)] -pub trait AsInnerMut { - fn as_inner_mut(&mut self) -> &mut Inner; -} - -/// A trait for extracting representations from std types -#[doc(hidden)] -pub trait IntoInner { - fn into_inner(self) -> Inner; -} - -/// A trait for creating std types from internal representations -#[doc(hidden)] -pub trait FromInner { - fn from_inner(inner: Inner) -> Self; -} diff --git a/src/sys/linux/io.rs b/src/sys_common/io.rs similarity index 100% rename from src/sys/linux/io.rs rename to src/sys_common/io.rs diff --git a/src/sys_common/mod.rs b/src/sys_common/mod.rs new file mode 100644 index 000000000..1d0d0dde8 --- /dev/null +++ b/src/sys_common/mod.rs @@ -0,0 +1,55 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Platform-independent platform abstraction +//! +//! This is the platform-independent portion of the standard libraries +//! platform abstraction layer, whereas `std::sys` is the +//! platform-specific portion. +//! +//! The relationship between `std::sys_common`, `std::sys` and the +//! rest of `std` is complex, with dependencies going in all +//! directions: `std` depending on `sys_common`, `sys_common` +//! depending on `sys`, and `sys` depending on `sys_common` and `std`. +//! Ideally `sys_common` would be split into two and the dependencies +//! between them all would form a dag, facilitating the extraction of +//! `std::sys` from the standard library. + +pub mod io; + +#[doc(hidden)] +pub trait AsInner { + fn as_inner(&self) -> &Inner; +} + +/// A trait for viewing representations from std types +#[doc(hidden)] +pub trait AsInnerMut { + fn as_inner_mut(&mut self) -> &mut Inner; +} + +/// A trait for extracting representations from std types +#[doc(hidden)] +pub trait IntoInner { + fn into_inner(self) -> Inner; +} + +/// A trait for creating std types from internal representations +#[doc(hidden)] +pub trait FromInner { + fn from_inner(inner: Inner) -> Self; +} + +// FIXME(steed) use Once +pub fn cleanup() { + unsafe { + ::sys::args::cleanup() + } +} From 5729f13fea336309ab077c582c54ad35c1fa3964 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 21 Jan 2017 22:00:40 -0500 Subject: [PATCH 4/4] refactor to not depend on `drop_types_in_const` and to not need a cleanup routine --- ci/script.sh | 5 +++++ src/lib.rs | 1 - src/process.rs | 1 - src/sys/linux/args.rs | 29 ++++++++++++----------------- src/sys_common/mod.rs | 7 ------- 5 files changed, 17 insertions(+), 26 deletions(-) diff --git a/ci/script.sh b/ci/script.sh index 5b05ceede..d09f4fd79 100644 --- a/ci/script.sh +++ b/ci/script.sh @@ -23,6 +23,11 @@ main() { ) for example in ${examples[@]}; do + # FIXME(redox-os/ralloc#{44,45}) + if [ $example = args ]; then + continue + fi + cross run --target $TARGET --example $example done diff --git a/src/lib.rs b/src/lib.rs index 9d0fb2471..27ac0a534 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,7 +7,6 @@ #![feature(compiler_builtins_lib)] #![feature(const_fn)] #![feature(core_intrinsics)] -#![feature(drop_types_in_const)] #![feature(dropck_parametricity)] #![feature(fused)] #![feature(int_error_internals)] diff --git a/src/process.rs b/src/process.rs index 96c53edc3..7694f9e66 100644 --- a/src/process.rs +++ b/src/process.rs @@ -4,6 +4,5 @@ use linux; #[stable(feature = "steed", since = "1.0.0")] pub fn exit(code: i32) -> ! { - ::sys_common::cleanup(); unsafe { linux::exit(code) } } diff --git a/src/sys/linux/args.rs b/src/sys/linux/args.rs index 72f38be80..2b1b391f8 100644 --- a/src/sys/linux/args.rs +++ b/src/sys/linux/args.rs @@ -22,9 +22,6 @@ use vec; /// One-time global initialization. pub unsafe fn init(argc: isize, argv: *const *const u8) { imp::init(argc, argv) } -/// One-time global cleanup. -pub unsafe fn cleanup() { imp::cleanup() } - /// Returns the command line arguments pub fn args() -> Args { imp::args() @@ -56,32 +53,30 @@ mod imp { use super::Args; use cell::UnsafeCell; use libc; + use slice; - static mut ARGS: UnsafeCell>>> = UnsafeCell::new(None); + static mut ARGS: UnsafeCell> = UnsafeCell::new(None); pub unsafe fn init(argc: isize, argv: *const *const u8) { - let args = (0..argc).map(|i| { - CStr::from_ptr(*argv.offset(i) as *const libc::c_char).to_bytes().to_vec() - }).collect(); - - *ARGS.get() = Some(args); - } - - pub unsafe fn cleanup() { - *ARGS.get() = None; + *ARGS.get() = Some(slice::from_raw_parts(argv, argc as usize)); } pub fn args() -> Args { let bytes = clone().unwrap_or(Vec::new()); - let v: Vec = bytes.into_iter().map(|v| { - OsStringExt::from_vec(v) - }).collect(); + let v: Vec = bytes.into_iter().map(|v| { + OsStringExt::from_vec(v) + }).collect(); + Args { iter: v.into_iter(), _dont_send_or_sync_me: PhantomData } } fn clone() -> Option>> { unsafe { - (*ARGS.get()).as_ref().cloned() + (*ARGS.get()).as_ref().map(|args| { + args.iter().map(|arg| { + CStr::from_ptr(*arg as *const libc::c_char).to_bytes().to_owned() + }).collect() + }) } } } diff --git a/src/sys_common/mod.rs b/src/sys_common/mod.rs index 1d0d0dde8..76d530df5 100644 --- a/src/sys_common/mod.rs +++ b/src/sys_common/mod.rs @@ -46,10 +46,3 @@ pub trait IntoInner { pub trait FromInner { fn from_inner(inner: Inner) -> Self; } - -// FIXME(steed) use Once -pub fn cleanup() { - unsafe { - ::sys::args::cleanup() - } -}