1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
//! # Handling Files Relative to File Descriptor
//!
//! Main concept here is a `Dir` which holds `O_PATH` file descriptor, you
//! can create it with:
//!
//! * `Dir::open("/some/path")` -- open this directory as a file descriptor
//! * `Dir::cwd()` -- current working directory
//!
//! *Note after opening file descriptors refer to same directory regardless of
//! where it's moved or mounted (with `pivot_root` or `mount --move`). It may
//! also be unmounted or be out of chroot and you will still be able to
//! access files relative to it.*
//!
//! *Note that `Dir::cwd()` always refers to the current working directory of
//! an application (and doesn't keep file descriptor too) and is sensitive
//! to `chdir`. But otherwise behaves the same (i.e. directory may be
//! moved and process is still in it). Anyway it's not more useful than
//! just using relative paths and traditional filesystem utilities.*
//!
//! Most other operations are done on `Dir` object and are executed relative
//! to it:
//!
//! * `Dir::list_dir()`
//! * `Dir::sub_dir()`
//! * `Dir::read_link()`
//! * `Dir::open_file()`
//! * `Dir::create_file()`
//! * `Dir::create_dir()`
//! * `Dir::symlink()`
//! * `Dir::local_rename()`
//!
//! Functions that expect path relative to the directory accept both the
//! traditional path-like objects, such as Path, PathBuf and &str, and
//! `Entry` type returned from `list_dir()`. The latter is faster as underlying
//! system call wants `CString` and we keep that in entry.
//!
//! Note that if path supplied to any method of dir is absolute the Dir file
//! descriptor is ignored.
//!
//! Also while all methods of dir accept any path if you want to prevent
//! certain symlink attacks and race condition you should only use
//! a single-component path. I.e. open one part of a chain at a time.
//!
#![warn(missing_docs)]

extern crate libc;

mod dir;
mod ffi;
mod list;
mod name;
mod filetype;
mod metadata;

pub use list::DirIter;
pub use name::AsPath;
pub use dir::rename;
pub use filetype::SimpleType;
pub use metadata::Metadata;

use std::ffi::CString;
use std::os::unix::io::RawFd;

/// A safe wrapper around directory file descriptor
///
/// Construct it either with ``Dir::cwd()`` or ``Dir::open(path)``
///
#[derive(Debug)]
pub struct Dir(DirFd);

#[derive(Debug)]
enum DirFd {
    Fd(RawFd),
    Cwd,
}

/// Entry returned by iterating over `DirIter` iterator
#[derive(Debug)]
pub struct Entry {
    name: CString,
    file_type: Option<SimpleType>,
}

#[cfg(test)]
mod test {
    use std::mem;
    use super::{Dir, DirFd};

    fn assert_sync<T: Sync>(x: T) -> T { x }
    fn assert_send<T: Send>(x: T) -> T { x }

    #[test]
    fn test() {
        let d = Dir(DirFd::Fd(3));
        let d = assert_sync(d);
        let d = assert_send(d);
        // don't execute close for our fake DirFd
        mem::forget(d);
    }
}