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
use crate::handle::HandleRights;
use crate::sys::sys_impl::oshandle::RawOsHandle;
use crate::wasi::Result;
use std::cell::{Cell, RefCell, RefMut};
use std::io;
use yanix::dir::Dir;

#[derive(Debug)]
/// A directory in the operating system's file system. Its impl of `Handle` is
/// in `sys::osdir`. This type is exposed to all other modules as
/// `sys::osdir::OsDir` when configured.
///
/// # Constructing `OsDir`
///
/// `OsDir` can currently only be constructed from `std::fs::File` using
/// the `std::convert::TryFrom` trait:
///
/// ```rust,no_run
/// use std::fs::OpenOptions;
/// use std::convert::TryFrom;
/// use wasi_common::OsDir;
///
/// let dir = OpenOptions::new().read(true).open("some_dir").unwrap();
/// let os_dir = OsDir::try_from(dir).unwrap();
/// ```
pub struct OsDir {
    pub(crate) rights: Cell<HandleRights>,
    pub(crate) handle: RawOsHandle,
    // When the client makes a `fd_readdir` syscall on this descriptor,
    // we will need to cache the `libc::DIR` pointer manually in order
    // to be able to seek on it later. While on Linux, this is handled
    // by the OS, BSD Unixes require the client to do this caching.
    //
    // This comes directly from the BSD man pages on `readdir`:
    //   > Values returned by telldir() are good only for the lifetime
    //   > of the DIR pointer, dirp, from which they are derived.
    //   > If the directory is closed and then reopened, prior values
    //   > returned by telldir() will no longer be valid.
    stream_ptr: RefCell<Dir>,
}

impl OsDir {
    pub(crate) fn new(rights: HandleRights, handle: RawOsHandle) -> io::Result<Self> {
        let rights = Cell::new(rights);
        // We need to duplicate the handle, because `opendir(3)`:
        //     Upon successful return from fdopendir(), the file descriptor is under
        //     control of the system, and if any attempt is made to close the file
        //     descriptor, or to modify the state of the associated description other
        //     than by means of closedir(), readdir(), readdir_r(), or rewinddir(),
        //     the behaviour is undefined.
        let stream_ptr = Dir::from(handle.try_clone()?)?;
        let stream_ptr = RefCell::new(stream_ptr);
        Ok(Self {
            rights,
            handle,
            stream_ptr,
        })
    }
    /// Returns the `Dir` stream pointer associated with this `OsDir`. Duck
    /// typing: sys::unix::fd::readdir expects the configured OsDir to have
    /// this method.
    pub(crate) fn stream_ptr(&self) -> Result<RefMut<Dir>> {
        Ok(self.stream_ptr.borrow_mut())
    }
}