From ecbbf1a8176130ca845b23c3e9dfe37d45da3c13 Mon Sep 17 00:00:00 2001 From: Skyler Hawthorne Date: Tue, 5 May 2015 15:26:45 -0700 Subject: Add lstat --- src/sys/stat.rs | 19 ++++++++++++++++-- test/test_stat.rs | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 72 insertions(+), 5 deletions(-) diff --git a/src/sys/stat.rs b/src/sys/stat.rs index d98d20ec..cafb36d9 100644 --- a/src/sys/stat.rs +++ b/src/sys/stat.rs @@ -1,7 +1,7 @@ pub use libc::dev_t; pub use libc::stat as FileStat; -use {Error, Result, NixPath, AsExtStr,from_ffi}; +use {Error, Result, NixPath, AsExtStr, from_ffi}; use errno::Errno; use fcntl::Fd; use libc::mode_t; @@ -10,7 +10,7 @@ use std::mem; mod ffi { use libc::{c_char, c_int, mode_t, dev_t}; - pub use libc::{stat, fstat}; + pub use libc::{stat, fstat, lstat}; extern { pub fn mknod(pathname: *const c_char, mode: mode_t, dev: dev_t) -> c_int; @@ -94,6 +94,21 @@ pub fn stat(path: &P) -> Result { Ok(dst) } +pub fn lstat(path: &P) -> Result { + let mut dst = unsafe { mem::uninitialized() }; + let res = try!(path.with_nix_path(|osstr| { + unsafe { + ffi::lstat(osstr.as_ext_str(), &mut dst as *mut FileStat) + } + })); + + if res < 0 { + return Err(Error::Sys(Errno::last())); + } + + Ok(dst) +} + pub fn fstat(fd: Fd) -> Result { let mut dst = unsafe { mem::uninitialized() }; let res = unsafe { ffi::fstat(fd, &mut dst as *mut FileStat) }; diff --git a/test/test_stat.rs b/test/test_stat.rs index abc58b4d..44091a7c 100644 --- a/test/test_stat.rs +++ b/test/test_stat.rs @@ -1,9 +1,14 @@ -use nix::sys::stat::{stat, fstat}; +use std::fs; +use std::str; + +use libc::consts::os::posix88; + +use nix::sys::stat::{stat, fstat, lstat}; use nix::fcntl::open; use nix::unistd::{close, unlink}; -use nix::fcntl::O_CREAT; -use nix::sys::stat::{FileStat, S_IWUSR}; +use nix::fcntl::{O_CREAT, O_RDONLY}; +use nix::sys::stat::{FileStat, S_IWUSR, S_IRUSR}; use nix::Result; fn assert_stat_results(stat_result: Result) { @@ -24,6 +29,28 @@ fn assert_stat_results(stat_result: Result) { } } +fn assert_lstat_results(stat_result: Result) { + match stat_result { + Ok(stats) => { + assert!(stats.st_dev > 0); // must be positive integer, exact number machine dependent + assert!(stats.st_ino > 0); // inode is positive integer, exact number machine dependent + assert!(stats.st_mode > 0); // must be positive integer + assert!(stats.st_mode & posix88::S_IFMT + == posix88::S_IFLNK); // should be a link + assert!(stats.st_nlink == 1); // there links created, must be 1 + assert!(stats.st_uid > 0); // must be positive integer + assert!(stats.st_gid > 0); // must be positive integer + assert!(stats.st_rdev == 0); // no special device + assert!(stats.st_size > 0); // size is > 0 because it points to another file + assert!(stats.st_blksize > 0); // must be positive integer, exact number machine dependent + + // st_blocks depends on whether the machine's file system uses fast + // or slow symlinks, so just make sure it's not negative + assert!(stats.st_blocks >= 0); + } + Err(_) => panic!("stat call failed") // if stats system call fails, something is seriously wrong on that machine + } +} #[test] fn test_stat_and_fstat() { @@ -39,3 +66,28 @@ fn test_stat_and_fstat() { close(fd).unwrap(); unlink(filename).unwrap(); } + +#[test] +fn test_stat_fstat_lstat() { + let filename = b"target/bar.txt".as_ref(); + let linkname = b"target/barlink".as_ref(); + + open(filename, O_CREAT, S_IWUSR | S_IRUSR).unwrap(); // create empty file + fs::soft_link("bar.txt", str::from_utf8(linkname).unwrap()).unwrap(); + let fd = open(linkname, O_RDONLY, S_IRUSR).unwrap(); + + // should be the same result as calling stat, + // since it's a regular file + let stat_result = lstat(filename); + assert_stat_results(stat_result); + + let lstat_result = lstat(linkname); + assert_lstat_results(lstat_result); + + let fstat_result = fstat(fd); + assert_stat_results(fstat_result); + + close(fd).unwrap(); + unlink(linkname).unwrap(); + unlink(filename).unwrap(); +} -- cgit v1.2.3