summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrabite0 <rabite@posteo.de>2020-02-29 14:24:28 +0100
committerrabite0 <rabite@posteo.de>2020-02-29 14:24:28 +0100
commitb163a9f4b400b4b14d96beacce912be47fa00f8a (patch)
tree540c21be6b07269ea5459f543a903b9c723fe724
parentd18836d0bfbf108feb01055dd96ae72dc5c1ce41 (diff)
fix/add back link indicators
-rw-r--r--src/files.rs87
1 files changed, 58 insertions, 29 deletions
diff --git a/src/files.rs b/src/files.rs
index 4a2718e..f2c6210 100644
--- a/src/files.rs
+++ b/src/files.rs
@@ -513,10 +513,20 @@ pub fn from_getdents(fd: i32, path: &Path, nothidden: &AtomicUsize) -> Result<V
unsafe { std::mem::transmute::<&[u8], &OsStr>(bytes) }
};
+ // Avoid reallocation on push
+ let mut pathstr = std::ffi::OsString::with_capacity(path.as_os_str().len() +
+ name.len() +
+ 2);
+ pathstr.push(path.as_os_str());
+ pathstr.push("/");
+ pathstr.push(name);
+
+ let path = PathBuf::from(pathstr);
+
// See dirent.h
// Some file systems and Linux < 2.6.4 don't support d_type
- let kind = match d.d_type {
- 4 => Kind::Directory,
+ let (kind, target) = match d.d_type {
+ 4 => (Kind::Directory, None),
0 => {
use nix::sys::stat::*;
@@ -525,7 +535,7 @@ pub fn from_getdents(fd: i32, path: &Path, nothidden: &AtomicUsize) -> Result<V
// stat is faster with an open fd
let flags = nix::fcntl::AtFlags::AT_SYMLINK_NOFOLLOW;
let stat =
- match fstatat(fd, name, flags) {
+ match fstatat(fd, &path, flags) {
Ok(stat) => stat,
Err(_) => return DentStatus::Err(FileError::GetDents(path.to_string_lossy()
.to_string()))
@@ -534,28 +544,28 @@ pub fn from_getdents(fd: i32, path: &Path, nothidden: &AtomicUsize) -> Result<V
let mode = SFlag::from_bits_truncate(stat.st_mode);
match mode & SFlag::S_IFMT {
- SFlag::S_IFDIR => Kind::Directory,
- _ => Kind::File
+ SFlag::S_IFDIR => (Kind::Directory, None),
+ _ => (Kind::File, None)
}
}
- _ => Kind::File,
+ 10 => {
+ // This is a link
+ let target = nix::fcntl::readlinkat(fd, &path)
+ .map(PathBuf::from).ok();
+ let target_kind =
+ match path.is_dir() {
+ true => Kind::Directory,
+ false => Kind::File
+ };
+ (target_kind, target)
+ }
+ _ => (Kind::File, None)
};
- // Avoid reallocation on push
- let mut pathstr = std::ffi::OsString::with_capacity(path.as_os_str().len() +
- name.len() +
- 2);
- pathstr.push(path.as_os_str());
- pathstr.push("/");
- pathstr.push(name);
-
- let path = PathBuf::from(pathstr);
-
let name = name.to_str()
.map(|n| String::from(n))
.unwrap_or_else(|| name.to_string_lossy().to_string());
-
let hidden = name.as_bytes()[0] == b'.';
if !hidden {
@@ -569,7 +579,7 @@ pub fn from_getdents(fd: i32, path: &Path, nothidden: &AtomicUsize) -> Result<V
kind: kind,
path: path,
dirsize: None,
- target: None,
+ target: target,
meta: None,
selected: false,
tag: None,
@@ -627,16 +637,22 @@ impl Files {
#[cfg(not(target_os = "linux"))]
pub fn new_from_path_cancellable(path: &Path, stale: Stale) -> HResult<Files> {
+ use std::os::unix::io::AsRawFd;
+
let nonhidden = AtomicUsize::default();
- let direntries = Dir::open(path.clone(),
- OFlag::O_DIRECTORY,
- Mode::empty())
- .map_err(|e| FileError::OpenDir(e))?
+ let mut dir = Dir::open(path.clone(),
+ OFlag::O_DIRECTORY,
+ Mode::empty())
+ .map_err(|e| FileError::OpenDir(e))?;
+
+ let dirfd = dir.as_raw_fd();
+
+ let direntries = dir
.iter()
.stop_stale(stale.clone())
.map(|f| {
- let f = File::new_from_nixentry(f?, path);
+ let f = File::new_from_nixentry(f?, path, dirfd);
// Fast check to avoid iterating twice
if f.name.as_bytes()[0] != b'.' {
nonhidden.fetch_add(1, Ordering::Relaxed);
@@ -1149,7 +1165,9 @@ impl File {
}
}
- pub fn new_from_nixentry(direntry: Entry, path: &Path) -> File {
+ pub fn new_from_nixentry(direntry: Entry,
+ path: &Path,
+ dirfd: i32) -> File {
// Scary stuff to avoid some of the overhead in Rusts conversions
// Speedup is a solid ~10%
let name: &OsStr = unsafe {
@@ -1178,12 +1196,23 @@ impl File {
let hidden = name.as_bytes()[0] == b'.';
- let kind = match direntry.file_type() {
+ let (kind, target) = match direntry.file_type() {
Some(ftype) => match ftype {
- Type::Directory => Kind::Directory,
- _ => Kind::File
+ Type::Directory => (Kind::Directory, None),
+ Type::Symlink => {
+ // Read link target
+ let target = nix::fcntl::readlinkat(dirfd, &path)
+ .map(PathBuf::from).ok();
+ let target_kind =
+ match path.is_dir() {
+ true => Kind::Directory,
+ false => Kind::File
+ };
+ (target_kind, target)
+ }
+ _ => (Kind::File, None)
}
- _ => Kind::Placeholder
+ _ => (Kind::Placeholder, None)
};
File {
@@ -1192,7 +1221,7 @@ impl File {
kind: kind,
path: path,
dirsize: None,
- target: None,
+ target: target,
meta: None,
selected: false,
tag: None,