summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSkyler Hawthorne <skylerhawthorne@gmail.com>2015-05-05 15:26:45 -0700
committerCarl Lerche <me@carllerche.com>2015-05-08 14:11:44 -0700
commitecbbf1a8176130ca845b23c3e9dfe37d45da3c13 (patch)
tree61e47f190a2bb64f3d20e41bb823f6219fa6ff36
parentd01c032b1c1fd5bf8cd26275ffece653af30426f (diff)
downloadnix-ecbbf1a8176130ca845b23c3e9dfe37d45da3c13.zip
Add lstat
-rw-r--r--src/sys/stat.rs19
-rw-r--r--test/test_stat.rs58
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<P: ?Sized + NixPath>(path: &P) -> Result<FileStat> {
Ok(dst)
}
+pub fn lstat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat> {
+ 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<FileStat> {
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<FileStat>) {
@@ -24,6 +29,28 @@ fn assert_stat_results(stat_result: Result<FileStat>) {
}
}
+fn assert_lstat_results(stat_result: Result<FileStat>) {
+ 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();
+}