Skip to content

Commit a5bed10

Browse files
committed
add clone_upgrade()/clone_downgrade(), fix list_self()
This up/downgrade cloning converts into normal/lite handles which was missing before. I hope this fixes #34 finally.
1 parent 9d48913 commit a5bed10

File tree

1 file changed

+49
-2
lines changed

1 file changed

+49
-2
lines changed

src/dir.rs

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use crate::{Dir, AsPath};
1717
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
1818
const BASE_OPEN_FLAGS: libc::c_int = libc::O_DIRECTORY | libc::O_CLOEXEC;
1919
// NOTE(cehteh): O_DIRECTORY is defined in posix, what is the reason for not using it?
20+
// TODO(cehteh): on systems that do not support O_DIRECTORY a runtime stat-check is required
2021
#[cfg(not(any(target_os = "linux", target_os = "freebsd")))]
2122
const BASE_OPEN_FLAGS: libc::c_int = libc::O_CLOEXEC;
2223

@@ -72,10 +73,11 @@ impl Dir {
7273
/// List this dir
7374
// TODO(cehteh): may be deprecated in favor of list()
7475
pub fn list_self(&self) -> io::Result<DirIter> {
75-
self.try_clone()?.list()
76+
self.clone_upgrade()?.list()
7677
}
7778

7879
/// Create a DirIter from a Dir
80+
/// Dir must not be a 'Lite' handle
7981
pub fn list(self) -> io::Result<DirIter> {
8082
let fd = self.0;
8183
std::mem::forget(self);
@@ -477,11 +479,21 @@ impl Dir {
477479
}
478480

479481
/// Creates a new independently owned handle to the underlying directory.
482+
/// The new handle has the same (Normal/Lite) semantics as the original handle.
480483
pub fn try_clone(&self) -> io::Result<Self> {
481484
Ok(Dir(clone_dirfd(self.0)?))
482485
}
483486

484-
//TODO(cehteh): clone/conversion full<->lite
487+
/// Creates a new 'Normal' independently owned handle to the underlying directory.
488+
pub fn clone_upgrade(&self) -> io::Result<Self> {
489+
Ok(Dir(clone_dirfd_upgrade(self.0)?))
490+
}
491+
492+
/// Creates a new 'Lite' independently owned handle to the underlying directory.
493+
pub fn clone_downgrade(&self) -> io::Result<Self> {
494+
Ok(Dir(clone_dirfd_downgrade(self.0)?))
495+
}
496+
485497
}
486498

487499
const CURRENT_DIRECTORY: [libc::c_char; 2] = [b'.' as libc::c_char, 0];
@@ -501,6 +513,41 @@ fn clone_dirfd(fd: libc::c_int) -> io::Result<libc::c_int> {
501513
}
502514
}
503515

516+
fn clone_dirfd_upgrade(fd: libc::c_int) -> io::Result<libc::c_int> {
517+
unsafe {
518+
match fd_type(fd)? {
519+
FdType::NormalDir | FdType::LiteDir => libc_ok(libc::openat(
520+
fd,
521+
&CURRENT_DIRECTORY as *const libc::c_char,
522+
BASE_OPEN_FLAGS,
523+
)),
524+
_ => Err(io::Error::from_raw_os_error(libc::ENOTDIR)),
525+
}
526+
}
527+
}
528+
529+
fn clone_dirfd_downgrade(fd: libc::c_int) -> io::Result<libc::c_int> {
530+
unsafe {
531+
match fd_type(fd)? {
532+
#[cfg(target_os = "linux")]
533+
FdType::NormalDir => libc_ok(libc::openat(
534+
fd,
535+
&CURRENT_DIRECTORY as *const libc::c_char,
536+
libc::O_PATH | BASE_OPEN_FLAGS,
537+
)),
538+
#[cfg(not(target_os = "linux"))]
539+
FdType::NormalDir => libc_ok(libc::openat(
540+
fd,
541+
&CURRENT_DIRECTORY as *const libc::c_char,
542+
libc::O_PATH | BASE_OPEN_FLAGS,
543+
)),
544+
#[cfg(target_os = "linux")]
545+
FdType::LiteDir => libc_ok(libc::dup(fd)),
546+
_ => Err(io::Error::from_raw_os_error(libc::ENOTDIR)),
547+
}
548+
}
549+
}
550+
504551
enum FdType {
505552
NormalDir,
506553
LiteDir,

0 commit comments

Comments
 (0)