diff options
Diffstat (limited to 'openat/src/dir.rs')
| -rw-r--r-- | openat/src/dir.rs | 696 | 
1 files changed, 0 insertions, 696 deletions
| diff --git a/openat/src/dir.rs b/openat/src/dir.rs deleted file mode 100644 index eac2f38..0000000 --- a/openat/src/dir.rs +++ /dev/null @@ -1,696 +0,0 @@ -use std::io; -use std::mem; -use std::ffi::{OsString, CStr}; -use std::fs::{File, read_link}; -use std::os::unix::io::{AsRawFd, RawFd, FromRawFd, IntoRawFd}; -use std::os::unix::ffi::{OsStringExt}; -use std::path::{PathBuf}; - -use libc; -use crate::metadata::{self, Metadata}; -use crate::list::{DirIter, open_dir, open_dirfd}; - -use crate::{Dir, AsPath}; - -#[cfg(target_os="linux")] -const BASE_OPEN_FLAGS: libc::c_int = libc::O_PATH|libc::O_CLOEXEC; -#[cfg(target_os="freebsd")] -const BASE_OPEN_FLAGS: libc::c_int = libc::O_DIRECTORY|libc::O_CLOEXEC; -#[cfg(not(any(target_os="linux", target_os="freebsd")))] -const BASE_OPEN_FLAGS: libc::c_int = libc::O_CLOEXEC; - -impl Dir { -    /// Creates a directory descriptor that resolves paths relative to current -    /// working directory (AT_FDCWD) -    #[deprecated(since="0.1.15", note="\ -        Use `Dir::open(\".\")` instead. \ -        Dir::cwd() doesn't open actual file descriptor and uses magic value \ -        instead which resolves to current dir on any syscall invocation. \ -        This is usually counter-intuitive and yields a broken \ -        file descriptor when using `Dir::as_raw_fd`. \ -        Will be removed in version v0.2 of the library.")] -    pub fn cwd() -> Dir { -        Dir(libc::AT_FDCWD) -    } - -    /// Open a directory descriptor at specified path -    // TODO(tailhook) maybe accept only absolute paths? -    pub fn open<P: AsPath>(path: P) -> io::Result<Dir> { -        Dir::_open(to_cstr(path)?.as_ref()) -    } - -    fn _open(path: &CStr) -> io::Result<Dir> { -        let fd = unsafe { -            libc::open(path.as_ptr(), BASE_OPEN_FLAGS) -        }; -        if fd < 0 { -            Err(io::Error::last_os_error()) -        } else { -            Ok(Dir(fd)) -        } -    } - -    /// List subdirectory of this dir -    /// -    /// You can list directory itself with `list_self`. -    pub fn list_dir<P: AsPath>(&self, path: P) -> io::Result<DirIter> { -        open_dir(self, to_cstr(path)?.as_ref()) -    } - -    /// List this dir -    pub fn list_self(&self) -> io::Result<DirIter> { -        unsafe { -            open_dirfd(libc::dup(self.0)) -        } -    } - -    /// Open subdirectory -    /// -    /// Note that this method does not resolve symlinks by default, so you may have to call -    /// [`read_link`] to resolve the real path first. -    /// -    /// [`read_link`]: #method.read_link -    pub fn sub_dir<P: AsPath>(&self, path: P) -> io::Result<Dir> { -        self._sub_dir(to_cstr(path)?.as_ref()) -    } - -    fn _sub_dir(&self, path: &CStr) -> io::Result<Dir> { -        let fd = unsafe { -            libc::openat(self.0, -                        path.as_ptr(), -                        BASE_OPEN_FLAGS|libc::O_NOFOLLOW) -        }; -        if fd < 0 { -            Err(io::Error::last_os_error()) -        } else { -            Ok(Dir(fd)) -        } -    } - -    /// Read link in this directory -    pub fn read_link<P: AsPath>(&self, path: P) -> io::Result<PathBuf> { -        self._read_link(to_cstr(path)?.as_ref()) -    } - -    fn _read_link(&self, path: &CStr) -> io::Result<PathBuf> { -        let mut buf = vec![0u8; 4096]; -        let res = unsafe { -            libc::readlinkat(self.0, -                        path.as_ptr(), -                        buf.as_mut_ptr() as *mut libc::c_char, buf.len()) -        }; -        if res < 0 { -            Err(io::Error::last_os_error()) -        } else { -            buf.truncate(res as usize); -            Ok(OsString::from_vec(buf).into()) -        } -    } - -    /// Open file for reading in this directory -    /// -    /// Note that this method does not resolve symlinks by default, so you may have to call -    /// [`read_link`] to resolve the real path first. -    /// -    /// [`read_link`]: #method.read_link -    pub fn open_file<P: AsPath>(&self, path: P) -> io::Result<File> { -        self._open_file(to_cstr(path)?.as_ref(), -            libc::O_RDONLY, 0) -    } - -    /// Open file with specified flags relative to this directory -    pub fn open_file_ex<P: AsPath>(&self, path: P, flags: libc::c_int, mode: libc::mode_t) -> io::Result<File> { -        self._open_file(to_cstr(path)?.as_ref(), flags, mode) -    } - -    /// Open file for writing, create if necessary, truncate on open -    /// -    /// If there exists a symlink at the destination path, this method will fail. In that case, you -    /// will need to remove the symlink before calling this method. If you are on Linux, you can -    /// alternatively create an unnamed file with [`new_unnamed_file`] and then rename it, -    /// clobbering the symlink at the destination. -    /// -    /// [`new_unnamed_file`]: #method.new_unnamed_file -    pub fn write_file<P: AsPath>(&self, path: P, mode: libc::mode_t) -        -> io::Result<File> -    { -        self._open_file(to_cstr(path)?.as_ref(), -            libc::O_CREAT|libc::O_WRONLY|libc::O_TRUNC, -            mode) -    } - -    /// Open file for append, create if necessary -    /// -    /// If there exists a symlink at the destination path, this method will fail. In that case, you -    /// will need to call [`read_link`] to resolve the real path first. -    /// -    /// [`read_link`]: #method.read_link -    pub fn append_file<P: AsPath>(&self, path: P, mode: libc::mode_t) -        -> io::Result<File> -    { -        self._open_file(to_cstr(path)?.as_ref(), -            libc::O_CREAT|libc::O_WRONLY|libc::O_APPEND, -            mode) -    } - -    /// Create file for writing (and truncate) in this directory -    /// -    /// Deprecated alias for `write_file` -    /// -    /// If there exists a symlink at the destination path, this method will fail. In that case, you -    /// will need to remove the symlink before calling this method. If you are on Linux, you can -    /// alternatively create an unnamed file with [`new_unnamed_file`] and then rename it, -    /// clobbering the symlink at the destination. -    /// -    /// [`new_unnamed_file`]: #method.new_unnamed_file -    #[deprecated(since="0.1.7", note="please use `write_file` instead")] -    pub fn create_file<P: AsPath>(&self, path: P, mode: libc::mode_t) -        -> io::Result<File> -    { -        self._open_file(to_cstr(path)?.as_ref(), -            libc::O_CREAT|libc::O_WRONLY|libc::O_TRUNC, -            mode) -    } - -    /// Create a tmpfile in this directory which isn't linked to any filename -    /// -    /// This works by passing `O_TMPFILE` into the openat call. The flag is -    /// supported only on linux. So this function always returns error on -    /// such systems. -    /// -    /// **WARNING!** On glibc < 2.22 file permissions of the newly created file -    /// may be arbitrary. Consider chowning after creating a file. -    /// -    /// Note: It may be unclear why creating unnamed file requires a dir. There -    /// are two reasons: -    /// -    /// 1. It's created (and occupies space) on a real filesystem, so the -    ///    directory is a way to find out which filesystem to attach file to -    /// 2. This method is mostly needed to initialize the file then link it -    ///    using ``link_file_at`` to the real directory entry. When linking -    ///    it must be linked into the same filesystem. But because for most -    ///    programs finding out filesystem layout is an overkill the rule of -    ///    thumb is to create a file in the the target directory. -    /// -    /// Currently, we recommend to fallback on any error if this operation -    /// can't be accomplished rather than relying on specific error codes, -    /// because semantics of errors are very ugly. -    #[cfg(target_os="linux")] -    pub fn new_unnamed_file(&self, mode: libc::mode_t) -        -> io::Result<File> -    { -        self._open_file(unsafe { CStr::from_bytes_with_nul_unchecked(b".\0") }, -            libc::O_TMPFILE|libc::O_WRONLY, -            mode) -    } - -    /// Create a tmpfile in this directory which isn't linked to any filename -    /// -    /// This works by passing `O_TMPFILE` into the openat call. The flag is -    /// supported only on linux. So this function always returns error on -    /// such systems. -    /// -    /// Note: It may be unclear why creating unnamed file requires a dir. There -    /// are two reasons: -    /// -    /// 1. It's created (and occupies space) on a real filesystem, so the -    ///    directory is a way to find out which filesystem to attach file to -    /// 2. This method is mostly needed to initialize the file then link it -    ///    using ``link_file_at`` to the real directory entry. When linking -    ///    it must be linked into the same filesystem. But because for most -    ///    programs finding out filesystem layout is an overkill the rule of -    ///    thumb is to create a file in the the target directory. -    /// -    /// Currently, we recommend to fallback on any error if this operation -    /// can't be accomplished rather than relying on specific error codes, -    /// because semantics of errors are very ugly. -    #[cfg(not(target_os="linux"))] -    pub fn new_unnamed_file<P: AsPath>(&self, _mode: libc::mode_t) -        -> io::Result<File> -    { -        Err(io::Error::new(io::ErrorKind::Other, -            "creating unnamed tmpfiles is only supported on linux")) -    } - -    /// Link open file to a specified path -    /// -    /// This is used with ``new_unnamed_file()`` to create and initialize the -    /// file before linking it into a filesystem. This requires `/proc` to be -    /// mounted and works **only on linux**. -    /// -    /// On systems other than linux this always returns error. It's expected -    /// that in most cases this methos is not called if ``new_unnamed_file`` -    /// fails. But in obscure scenarios where `/proc` is not mounted this -    /// method may fail even on linux. So your code should be able to fallback -    /// to a named file if this method fails too. -    #[cfg(target_os="linux")] -    pub fn link_file_at<F: AsRawFd, P: AsPath>(&self, file: &F, path: P) -        -> io::Result<()> -    { -        let fd_path = format!("/proc/self/fd/{}", file.as_raw_fd()); -        _hardlink(&Dir(libc::AT_FDCWD), to_cstr(fd_path)?.as_ref(), -            &self, to_cstr(path)?.as_ref(), -            libc::AT_SYMLINK_FOLLOW) -    } - -    /// Link open file to a specified path -    /// -    /// This is used with ``new_unnamed_file()`` to create and initialize the -    /// file before linking it into a filesystem. This requires `/proc` to be -    /// mounted and works **only on linux**. -    /// -    /// On systems other than linux this always returns error. It's expected -    /// that in most cases this methos is not called if ``new_unnamed_file`` -    /// fails. But in obscure scenarios where `/proc` is not mounted this -    /// method may fail even on linux. So your code should be able to fallback -    /// to a named file if this method fails too. -    #[cfg(not(target_os="linux"))] -    pub fn link_file_at<F: AsRawFd, P: AsPath>(&self, _file: F, _path: P) -        -> io::Result<()> -    { -        Err(io::Error::new(io::ErrorKind::Other, -            "linking unnamed fd to directories is only supported on linux")) -    } - -    /// Create file if not exists, fail if exists -    /// -    /// This function checks existence and creates file atomically with -    /// respect to other threads and processes. -    /// -    /// Technically it means passing `O_EXCL` flag to open. -    pub fn new_file<P: AsPath>(&self, path: P, mode: libc::mode_t) -        -> io::Result<File> -    { -        self._open_file(to_cstr(path)?.as_ref(), -            libc::O_CREAT|libc::O_EXCL|libc::O_WRONLY, -            mode) -    } - -    /// Open file for reading and writing without truncation, create if needed -    /// -    /// If there exists a symlink at the destination path, this method will fail. In that case, you -    /// will need to call [`read_link`] to resolve the real path first. -    /// -    /// [`read_link`]: #method.read_link -    pub fn update_file<P: AsPath>(&self, path: P, mode: libc::mode_t) -        -> io::Result<File> -    { -        self._open_file(to_cstr(path)?.as_ref(), -            libc::O_CREAT|libc::O_RDWR, -            mode) -    } - -    fn _open_file(&self, path: &CStr, flags: libc::c_int, mode: libc::mode_t) -        -> io::Result<File> -    { -        unsafe { -            // Note: In below call to `openat`, *mode* must be cast to -            // `unsigned` because the optional `mode` argument to `openat` is -            // variadic in the signature. Since integers are not implicitly -            // promoted as they are in C this would break on Freebsd where -            // *mode_t* is an alias for `uint16_t`. -            let res = libc::openat(self.0, path.as_ptr(), -                            flags|libc::O_CLOEXEC|libc::O_NOFOLLOW, -                            mode as libc::c_uint); -            if res < 0 { -                Err(io::Error::last_os_error()) -            } else { -                Ok(File::from_raw_fd(res)) -            } -        } -    } - -    /// Make a symlink in this directory -    /// -    /// Note: the order of arguments differ from `symlinkat` -    pub fn symlink<P: AsPath, R: AsPath>(&self, path: P, value: R) -        -> io::Result<()> -    { -        self._symlink(to_cstr(path)?.as_ref(), to_cstr(value)?.as_ref()) -    } -    fn _symlink(&self, path: &CStr, link: &CStr) -> io::Result<()> { -        unsafe { -            let res = libc::symlinkat(link.as_ptr(), -                self.0, path.as_ptr()); -            if res < 0 { -                Err(io::Error::last_os_error()) -            } else { -                Ok(()) -            } -        } -    } - -    /// Create a subdirectory in this directory -    pub fn create_dir<P: AsPath>(&self, path: P, mode: libc::mode_t) -        -> io::Result<()> -    { -        self._create_dir(to_cstr(path)?.as_ref(), mode) -    } -    fn _create_dir(&self, path: &CStr, mode: libc::mode_t) -> io::Result<()> { -        unsafe { -            let res = libc::mkdirat(self.0, path.as_ptr(), mode); -            if res < 0 { -                Err(io::Error::last_os_error()) -            } else { -                Ok(()) -            } -        } -    } - -    /// Rename a file in this directory to another name (keeping same dir) -    pub fn local_rename<P: AsPath, R: AsPath>(&self, old: P, new: R) -        -> io::Result<()> -    { -        rename(self, to_cstr(old)?.as_ref(), self, to_cstr(new)?.as_ref()) -    } - -    /// Similar to `local_rename` but atomically swaps both paths -    /// -    /// Only supported on Linux. -    #[cfg(target_os="linux")] -    pub fn local_exchange<P: AsPath, R: AsPath>(&self, old: P, new: R) -        -> io::Result<()> -    { -        // Workaround https://github.com/tailhook/openat/issues/35 -        // AKA https://github.com/rust-lang/libc/pull/2116 -        // Unfortunately since we made this libc::c_int in our -        // public API, we can't easily change it right now. -        let flags = libc::RENAME_EXCHANGE as libc::c_int; -        rename_flags(self, to_cstr(old)?.as_ref(), -            self, to_cstr(new)?.as_ref(), -            flags) -    } - -    /// Remove a subdirectory in this directory -    /// -    /// Note only empty directory may be removed -    pub fn remove_dir<P: AsPath>(&self, path: P) -        -> io::Result<()> -    { -        self._unlink(to_cstr(path)?.as_ref(), libc::AT_REMOVEDIR) -    } -    /// Remove a file in this directory -    pub fn remove_file<P: AsPath>(&self, path: P) -        -> io::Result<()> -    { -        self._unlink(to_cstr(path)?.as_ref(), 0) -    } -    fn _unlink(&self, path: &CStr, flags: libc::c_int) -> io::Result<()> { -        unsafe { -            let res = libc::unlinkat(self.0, path.as_ptr(), flags); -            if res < 0 { -                Err(io::Error::last_os_error()) -            } else { -                Ok(()) -            } -        } -    } - -    /// Get the path of this directory (if possible) -    /// -    /// This uses symlinks in `/proc/self`, they sometimes may not be -    /// available so use with care. -    pub fn recover_path(&self) -> io::Result<PathBuf> { -        let fd = self.0; -        if fd != libc::AT_FDCWD { -            read_link(format!("/proc/self/fd/{}", fd)) -        } else { -            read_link("/proc/self/cwd") -        } -    } - -    /// Returns metadata of an entry in this directory -    /// -    /// If the destination path is a symlink, this will return the metadata of the symlink itself. -    /// If you would like to follow the symlink and return the metadata of the target, you will -    /// have to call [`read_link`] to resolve the real path first. -    /// -    /// [`read_link`]: #method.read_link -    pub fn metadata<P: AsPath>(&self, path: P) -> io::Result<Metadata> { -        self._stat(to_cstr(path)?.as_ref(), libc::AT_SYMLINK_NOFOLLOW) -    } -    fn _stat(&self, path: &CStr, flags: libc::c_int) -> io::Result<Metadata> { -        unsafe { -            let mut stat = mem::zeroed(); -            let res = libc::fstatat(self.0, path.as_ptr(), -                &mut stat, flags); -            if res < 0 { -                Err(io::Error::last_os_error()) -            } else { -                Ok(metadata::new(stat)) -            } -        } -    } - -    /// Returns the metadata of the directory itself. -    pub fn self_metadata(&self) -> io::Result<Metadata> { -        unsafe { -            let mut stat = mem::zeroed(); -            let res = libc::fstat(self.0, &mut stat); -            if res < 0 { -                Err(io::Error::last_os_error()) -            } else { -                Ok(metadata::new(stat)) -            } -        } -    } - -    /// Constructs a new `Dir` from a given raw file descriptor, -    /// ensuring it is a directory file descriptor first. -    /// -    /// This function **consumes ownership** of the specified file -    /// descriptor. The returned `Dir` will take responsibility for -    /// closing it when it goes out of scope. -    pub unsafe fn from_raw_fd_checked(fd: RawFd) -> io::Result<Self> { -        let mut stat = mem::zeroed(); -        let res = libc::fstat(fd, &mut stat); -        if res < 0 { -            Err(io::Error::last_os_error()) -        } else { -            match stat.st_mode & libc::S_IFMT { -                libc::S_IFDIR => Ok(Dir(fd)), -                _ => Err(io::Error::from_raw_os_error(libc::ENOTDIR)) -            } -        } -    } - -    /// Creates a new independently owned handle to the underlying directory. -    pub fn try_clone(&self) -> io::Result<Self> { -        let fd = unsafe { libc::dup(self.0) }; -        if fd == -1 { -            Err(io::Error::last_os_error()) -        } else { -            unsafe { Self::from_raw_fd_checked(fd) } -        } -    } -} - -/// Rename (move) a file between directories -/// -/// Files must be on a single filesystem anyway. This funtion does **not** -/// fallback to copying if needed. -pub fn rename<P, R>(old_dir: &Dir, old: P, new_dir: &Dir, new: R) -    -> io::Result<()> -    where P: AsPath, R: AsPath, -{ -    _rename(old_dir, to_cstr(old)?.as_ref(), new_dir, to_cstr(new)?.as_ref()) -} - -fn _rename(old_dir: &Dir, old: &CStr, new_dir: &Dir, new: &CStr) -    -> io::Result<()> -{ -    unsafe { -        let res = libc::renameat(old_dir.0, old.as_ptr(), -            new_dir.0, new.as_ptr()); -        if res < 0 { -            Err(io::Error::last_os_error()) -        } else { -            Ok(()) -        } -    } -} - -/// Create a hardlink to a file -/// -/// Files must be on a single filesystem even if they are in different -/// directories. -/// -/// Note: by default ``linkat`` syscall doesn't resolve symbolic links, and -/// it's also behavior of this function. It's recommended to resolve symlinks -/// manually if needed. -pub fn hardlink<P, R>(old_dir: &Dir, old: P, new_dir: &Dir, new: R) -    -> io::Result<()> -    where P: AsPath, R: AsPath, -{ -    _hardlink(old_dir, to_cstr(old)?.as_ref(), -              new_dir, to_cstr(new)?.as_ref(), -              0) -} - -fn _hardlink(old_dir: &Dir, old: &CStr, new_dir: &Dir, new: &CStr, -             flags: libc::c_int) -    -> io::Result<()> -{ -    unsafe { -        let res = libc::linkat(old_dir.0, old.as_ptr(), -            new_dir.0, new.as_ptr(), flags); -        if res < 0 { -            Err(io::Error::last_os_error()) -        } else { -            Ok(()) -        } -    } -} - -/// Rename (move) a file between directories with flags -/// -/// Files must be on a single filesystem anyway. This funtion does **not** -/// fallback to copying if needed. -/// -/// Only supported on Linux. -#[cfg(target_os="linux")] -pub fn rename_flags<P, R>(old_dir: &Dir, old: P, new_dir: &Dir, new: R, -    flags: libc::c_int) -    -> io::Result<()> -    where P: AsPath, R: AsPath, -{ -    _rename_flags(old_dir, to_cstr(old)?.as_ref(), -        new_dir, to_cstr(new)?.as_ref(), -        flags) -} - -#[cfg(target_os="linux")] -fn _rename_flags(old_dir: &Dir, old: &CStr, new_dir: &Dir, new: &CStr, -    flags: libc::c_int) -    -> io::Result<()> -{ -    unsafe { -        let res = libc::syscall( -            libc::SYS_renameat2, -            old_dir.0, old.as_ptr(), -            new_dir.0, new.as_ptr(), flags); -        if res < 0 { -            Err(io::Error::last_os_error()) -        } else { -            Ok(()) -        } -    } -} - -impl AsRawFd for Dir { -    #[inline] -    fn as_raw_fd(&self) -> RawFd { -        self.0 -    } -} - -impl FromRawFd for Dir { -    /// The user must guarantee that the passed in `RawFd` is in fact -    /// a directory file descriptor. -    #[inline] -    unsafe fn from_raw_fd(fd: RawFd) -> Dir { -        Dir(fd) -    } -} - -impl IntoRawFd for Dir { -    #[inline] -    fn into_raw_fd(self) -> RawFd { -        let result = self.0; -        mem::forget(self); -        return result; -    } -} - -impl Drop for Dir { -    fn drop(&mut self) { -        let fd = self.0; -        if fd != libc::AT_FDCWD { -            unsafe { -                libc::close(fd); -            } -        } -    } -} - -fn to_cstr<P: AsPath>(path: P) -> io::Result<P::Buffer> { -    path.to_path() -    .ok_or_else(|| { -        io::Error::new(io::ErrorKind::InvalidInput, -                       "nul byte in file name") -    }) -} - -#[cfg(test)] -mod test { -    use std::io::{Read}; -    use std::path::Path; -    use std::os::unix::io::{FromRawFd, IntoRawFd}; -    use crate::{Dir}; - -    #[test] -    fn test_open_ok() { -        assert!(Dir::open("src").is_ok()); -    } - -    #[test] -    #[cfg_attr(target_os="freebsd", should_panic(expected="Not a directory"))] -    fn test_open_file() { -        Dir::open("src/lib.rs").unwrap(); -    } - -    #[test] -    fn test_read_file() { -        let dir = Dir::open("src").unwrap(); -        let mut buf = String::new(); -        dir.open_file("lib.rs").unwrap() -            .read_to_string(&mut buf).unwrap(); -        assert!(buf.find("extern crate libc;").is_some()); -    } - -    #[test] -    fn test_from_into() { -        let dir = Dir::open("src").unwrap(); -        let dir = unsafe { Dir::from_raw_fd(dir.into_raw_fd()) }; -        let mut buf = String::new(); -        dir.open_file("lib.rs").unwrap() -            .read_to_string(&mut buf).unwrap(); -        assert!(buf.find("extern crate libc;").is_some()); -    } - -    #[test] -    #[should_panic(expected="No such file or directory")] -    fn test_open_no_dir() { -        Dir::open("src/some-non-existent-file").unwrap(); -    } - -    #[test] -    fn test_list() { -        let dir = Dir::open("src").unwrap(); -        let me = dir.list_dir(".").unwrap(); -        assert!(me.collect::<Result<Vec<_>, _>>().unwrap() -                .iter().find(|x| { -                    x.file_name() == Path::new("lib.rs").as_os_str() -                }) -                .is_some()); -    } - -    #[test] -    fn test_from_raw_fd_checked() { -        let fd = Dir::open(".").unwrap().into_raw_fd(); -        let dir = unsafe { Dir::from_raw_fd_checked(fd) }.unwrap(); -        let filefd = dir.open_file("src/lib.rs").unwrap().into_raw_fd(); -        match unsafe { Dir::from_raw_fd_checked(filefd) } { -            Ok(_) => assert!(false, "from_raw_fd_checked succeeded on a non-directory fd!"), -            Err(e) => assert_eq!(e.raw_os_error().unwrap(), libc::ENOTDIR) -        } -    } - -    #[test] -    fn test_try_clone() { -        let d = Dir::open(".").unwrap(); -        let d2 = d.try_clone().unwrap(); -        drop(d); -        let _file = d2.open_file("src/lib.rs").unwrap(); -    } -} | 
