Skip to content

Is dir feature #43

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 23 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
2be51a3
add accessors for the underlying stat data
cehteh Apr 17, 2021
bba0687
FIX: make use of SimpleType::Unknown in simple_type()
cehteh Apr 18, 2021
c502cc2
FIX: use u32 for the 'dev' values
cehteh Apr 18, 2021
c8f364d
Changes to make macos happy
cehteh Apr 18, 2021
39fc803
FIX: replace ino_t with u64 to comply with statx
cehteh Apr 19, 2021
815357e
Add/Refactor Dir::list() -> DirIter ctor
cehteh Apr 19, 2021
8647f93
FIX: fixes previous commit, adds special O_PATH funcs
cehteh Apr 20, 2021
d567fb1
rename *_path to *_lite, improve docs, provide impl for non linux
cehteh Apr 21, 2021
e5e9c5b
New: clone_dirfd() may fix #34, ADD: FdType machinery, libc_ok()
cehteh Apr 21, 2021
9d48913
cosmetics: use libc_ok() where applicable
cehteh Apr 21, 2021
fcf92fa
add clone_upgrade()/clone_downgrade(), fix list_self()
cehteh Apr 21, 2021
abef3ec
Store inode in Entry, add accessor
cehteh Apr 19, 2021
ffe5d3f
use types from 'struct stat' instead 'struct statx'
cehteh Apr 21, 2021
726958c
Merge branch 'entry_metadata_feature' into cehteh
cehteh Apr 22, 2021
954a9cc
Merge branch 'list_feature' into cehteh
cehteh Apr 22, 2021
6b4d359
start abstracting OS capabilities into features
cehteh Apr 22, 2021
076ba5c
WIP: Add new 'conf_test' for build time configuration, o_path check
cehteh Apr 27, 2021
69acef0
add conf_tests for o_directory|search|tmpfile
cehteh Apr 27, 2021
34905a5
add the remaining tests (for now), remove a misleading note
cehteh Apr 27, 2021
c8fed25
FIX: The unnamed_tmp_file_link test needs o_tmpfile and link_file_at
cehteh Apr 27, 2021
7cf2583
WIP/FIX: test osx fcntl() returning O_DIRECTORY
cehteh Apr 27, 2021
c43ab67
notice about O_SEARCH when cloning
cehteh Apr 28, 2021
4b90fcb
add 'is_dir()' check, remove the 'test_open_file()' test
cehteh Apr 28, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -14,9 +14,28 @@ version = "0.1.21"
authors = ["[email protected]"]
edition = "2018"

[features]
default = []
linux = ["o_path", "o_directory", "o_tmpfile", "statx", "proc_self_fd", "link_file_at", "rename_exchange", "renameat_flags"]
#NOTE(cehteh): eventually provide some baseline configs for other OS'es (for cross compilation)
o_path = []
o_directory = []
o_tmpfile = []
o_search = []
fcntl_o_directory = []
proc_self_fd = []
link_file_at = []
renameat_flags = []
rename_exchange = []
statx = []

[dependencies]
libc = "0.2.34"

[build-dependencies]
libc = "0.2.34"
conf_test = "0.1"

[dev-dependencies]
argparse = "0.2.1"
tempfile = "3.0.3"
5 changes: 5 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
use conf_test::ConfTest;

fn main() {
ConfTest::run();
}
16 changes: 16 additions & 0 deletions conf_tests/fcntl_o_directory.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
extern crate libc;

fn main() {
unsafe {
let conf_tests = std::ffi::CString::new("conf_tests").unwrap();
let fd = libc::open(conf_tests.as_ptr(), libc::O_DIRECTORY | libc::O_RDONLY);

let flags = libc::fcntl(fd, libc::F_GETFL);

if flags != -1 && flags & libc::O_DIRECTORY != 0 {
std::process::exit(0);
} else {
std::process::exit(1);
}
}
}
13 changes: 13 additions & 0 deletions conf_tests/link_file_at.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
extern crate libc;

fn main() {
//NOTE(cehteh): same as the proc_self_fd test, maybe we need something smarter in future
unsafe {
let conf_tests = std::ffi::CString::new("/proc/self/fd/0").unwrap();
if libc::open(conf_tests.as_ptr(), libc::O_RDONLY) != -1 {
std::process::exit(0);
} else {
std::process::exit(1);
}
}
}
8 changes: 8 additions & 0 deletions conf_tests/o_directory.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
extern crate libc;

fn main() {
unsafe {
let conf_tests = std::ffi::CString::new("conf_tests").unwrap();
libc::open(conf_tests.as_ptr(), libc::O_DIRECTORY);
}
}
8 changes: 8 additions & 0 deletions conf_tests/o_path.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
extern crate libc;

fn main () {
unsafe {
let conf_tests = std::ffi::CString::new("conf_tests").unwrap();
libc::open(conf_tests.as_ptr(), libc::O_PATH);
}
}
8 changes: 8 additions & 0 deletions conf_tests/o_search.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
extern crate libc;

fn main() {
unsafe {
let conf_tests = std::ffi::CString::new("conf_tests").unwrap();
libc::open(conf_tests.as_ptr(), libc::O_SEARCH);
}
}
10 changes: 10 additions & 0 deletions conf_tests/o_tmpfile.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
extern crate libc;

fn main () {
unsafe {
let conf_tests = std::ffi::CString::new("conf_tests").unwrap();
libc::open(conf_tests.as_ptr(),
libc::O_TMPFILE | libc::O_RDWR,
libc::S_IRUSR | libc::S_IWUSR);
}
}
12 changes: 12 additions & 0 deletions conf_tests/proc_self_fd.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
extern crate libc;

fn main() {
unsafe {
let conf_tests = std::ffi::CString::new("/proc/self/fd/0").unwrap();
if libc::open(conf_tests.as_ptr(), libc::O_RDONLY) != -1 {
std::process::exit(0);
} else {
std::process::exit(1);
}
}
}
5 changes: 5 additions & 0 deletions conf_tests/rename_exchange.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
extern crate libc;

fn main() {
let does_rename_exchange_exist = libc::RENAME_EXCHANGE;
}
5 changes: 5 additions & 0 deletions conf_tests/renameat_flags.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
extern crate libc;

fn main() {
let does_renameat2_exist = libc::SYS_renameat2;
}
4 changes: 3 additions & 1 deletion examples/exchange.rs
Original file line number Diff line number Diff line change
@@ -32,8 +32,10 @@ fn main() {
}
let parent = path1.parent().expect("path must have parent directory");
let dir = Dir::open(parent).expect("can open directory");
#[cfg(feature = "rename_exchange")]
dir.local_exchange(
path1.file_name().expect("path1 must have filename"),
path2.file_name().expect("path2 must have filename"),
).expect("can rename");
)
.expect("can rename");
}
407 changes: 286 additions & 121 deletions src/dir.rs

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions src/filetype.rs
Original file line number Diff line number Diff line change
@@ -7,6 +7,8 @@ use std::fs::Metadata;
/// this simplified enum that works for many appalications.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SimpleType {
/// Entry is of unknown type
Unknown,
/// Entry is a symlink
Symlink,
/// Entry is a directory
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -73,6 +73,7 @@ pub struct Dir(RawFd);
pub struct Entry {
name: CString,
file_type: Option<SimpleType>,
ino: libc::ino_t,
}

#[cfg(test)]
19 changes: 6 additions & 13 deletions src/list.rs
Original file line number Diff line number Diff line change
@@ -5,8 +5,7 @@ use std::os::unix::ffi::OsStrExt;

use libc;

use crate::{Dir, Entry, SimpleType};

use crate::{Entry, SimpleType};

// We have such weird constants because C types are ugly
const DOT: [libc::c_char; 2] = [b'.' as libc::c_char, 0];
@@ -37,6 +36,10 @@ impl Entry {
pub fn simple_type(&self) -> Option<SimpleType> {
self.file_type
}
/// Returns the inode number of this entry
pub fn inode(&self) -> libc::ino_t {
self.ino
}
}

#[cfg(any(target_os="linux", target_os="fuchsia"))]
@@ -104,17 +107,6 @@ pub fn open_dirfd(fd: libc::c_int) -> io::Result<DirIter> {
}
}

pub fn open_dir(dir: &Dir, path: &CStr) -> io::Result<DirIter> {
let dir_fd = unsafe {
libc::openat(dir.0, path.as_ptr(), libc::O_DIRECTORY|libc::O_CLOEXEC)
};
if dir_fd < 0 {
Err(io::Error::last_os_error())
} else {
open_dirfd(dir_fd)
}
}

impl Iterator for DirIter {
type Item = io::Result<Entry>;
fn next(&mut self) -> Option<Self::Item> {
@@ -136,6 +128,7 @@ impl Iterator for DirIter {
libc::DT_LNK => Some(SimpleType::Symlink),
_ => Some(SimpleType::Other),
},
ino: e.d_ino,
}));
}
}
105 changes: 103 additions & 2 deletions src/metadata.rs
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@ use std::fs::Permissions;
use std::os::unix::fs::PermissionsExt;

use libc;
use std::time::{Duration, SystemTime, UNIX_EPOCH};

use crate::SimpleType;

@@ -17,11 +18,11 @@ pub struct Metadata {
impl Metadata {
/// Returns simplified type of the directory entry
pub fn simple_type(&self) -> SimpleType {
let typ = self.stat.st_mode & libc::S_IFMT;
match typ {
match self.file_type().unwrap_or(0) as libc::mode_t {
libc::S_IFREG => SimpleType::File,
libc::S_IFDIR => SimpleType::Dir,
libc::S_IFLNK => SimpleType::Symlink,
0 => SimpleType::Unknown,
_ => SimpleType::Other,
}
}
@@ -45,12 +46,112 @@ impl Metadata {
pub fn len(&self) -> u64 {
self.stat.st_size as u64
}
/// Return low level file type, if available
pub fn file_type(&self) -> Option<libc::mode_t> {
Some(self.stat.st_mode & libc::S_IFMT)
}
/// Return device node, if available
pub fn ino(&self) -> Option<libc::ino_t> {
Some(self.stat.st_ino)
}
/// Return device node major of the file, if available
pub fn dev_major(&self) -> Option<u32> {
Some(major(self.stat.st_dev))
}
/// Return device node minor of the file, if available
pub fn dev_minor(&self) -> Option<u32> {
Some(minor(self.stat.st_dev))
}
/// Return device node major of an device descriptor, if available
pub fn rdev_major(&self) -> Option<u32> {
match self.file_type()? as libc::mode_t {
libc::S_IFBLK | libc::S_IFCHR => Some(major(self.stat.st_rdev)),
_ => None,
}
}
/// Return device node minor of an device descriptor, if available
pub fn rdev_minor(&self) -> Option<u32> {
match self.file_type()? as libc::mode_t {
libc::S_IFBLK | libc::S_IFCHR => Some(minor(self.stat.st_rdev)),
_ => None,
}
}
/// Return preferered I/O Blocksize, if available
pub fn blksize(&self) -> Option<libc::blksize_t> {
Some(self.stat.st_blksize)
}
/// Return the number of 512 bytes blocks, if available
pub fn blocks(&self) -> Option<libc::blkcnt_t> {
Some(self.stat.st_blocks)
}
/// Returns file size (same as len() but Option), if available
pub fn size(&self) -> Option<libc::off_t> {
Some(self.stat.st_size)
}
/// Returns number of hard-links, if available
pub fn nlink(&self) -> Option<libc::nlink_t> {
Some(self.stat.st_nlink)
}
/// Returns user id, if available
pub fn uid(&self) -> Option<libc::uid_t> {
Some(self.stat.st_uid)
}
/// Returns group id, if available
pub fn gid(&self) -> Option<libc::gid_t> {
Some(self.stat.st_gid)
}
/// Returns mode bits, if available
pub fn file_mode(&self) -> Option<libc::mode_t> {
Some(self.stat.st_mode & 0o7777)
}
/// Returns last access time, if available
pub fn atime(&self) -> Option<SystemTime> {
Some(unix_systemtime(self.stat.st_atime, self.stat.st_atime_nsec))
}
/// Returns creation, if available
pub fn btime(&self) -> Option<SystemTime> {
None
}
/// Returns last status change time, if available
pub fn ctime(&self) -> Option<SystemTime> {
Some(unix_systemtime(self.stat.st_ctime, self.stat.st_ctime_nsec))
}
/// Returns last modification time, if available
pub fn mtime(&self) -> Option<SystemTime> {
Some(unix_systemtime(self.stat.st_mtime, self.stat.st_mtime_nsec))
}
}

pub fn new(stat: libc::stat) -> Metadata {
Metadata { stat: stat }
}

fn unix_systemtime(sec: libc::time_t, nsec: i64) -> SystemTime {
UNIX_EPOCH + Duration::from_secs(sec as u64) + Duration::from_nanos(nsec as u64)
}

#[cfg(not(target_os = "macos"))]
pub fn major(dev: libc::dev_t) -> u32 {
unsafe { libc::major(dev) }
}

#[cfg(not(target_os = "macos"))]
pub fn minor(dev: libc::dev_t) -> u32 {
unsafe { libc::minor(dev) }
}

// major/minor are not in rust's darwin libc (why)
// see https://github.com/apple/darwin-xnu/blob/main/bsd/sys/types.h
#[cfg(target_os = "macos")]
pub fn major(dev: libc::dev_t) -> u32 {
(dev as u32 >> 24) & 0xff
}

#[cfg(target_os = "macos")]
pub fn minor(dev: libc::dev_t) -> u32 {
dev as u32 & 0xffffff
}

#[cfg(test)]
mod test {
use super::*;
2 changes: 1 addition & 1 deletion tests/tmpfile.rs
Original file line number Diff line number Diff line change
@@ -6,7 +6,7 @@ use std::os::unix::fs::PermissionsExt;
use openat::Dir;

#[test]
#[cfg(target_os="linux")]
#[cfg(all(feature = "o_tmpfile", feature = "link_file_at"))]
fn unnamed_tmp_file_link() -> Result<(), io::Error> {
let tmp = tempfile::tempdir()?;
let dir = Dir::open(tmp.path())?;