Skip to main content

compio_fs\dirfd/
mod.rs

1use std::{io, path::Path};
2
3use compio_buf::{BufResult, IoBuf, buf_try};
4use compio_io::{AsyncReadAtExt, AsyncWriteAtExt};
5
6use crate::{DirBuilder, File, Metadata, OpenOptions};
7
8#[cfg(unix)]
9#[path = "unix.rs"]
10mod sys;
11
12#[cfg(windows)]
13#[path = "windows.rs"]
14mod sys;
15
16/// A reference to an open directory on a filesystem.
17///
18/// ## Platform specific
19/// * Windows: the operations are forwarded to `cap-primitives`. They will treat
20///   self as the root of the filesystem.
21/// * Unix: the operatiosn are forwarded to syscalls directly. They don't limit
22///   the path to be under self. If the path is absolute, the directory
23///   represented by self will be ignored.
24#[derive(Debug, Clone)]
25pub struct Dir {
26    inner: sys::Dir,
27}
28
29impl Dir {
30    /// Opens a directory at the specified path and returns a reference to it.
31    pub async fn open(path: impl AsRef<Path>) -> io::Result<Self> {
32        Ok(Dir {
33            inner: sys::Dir::open(path).await?,
34        })
35    }
36
37    /// Opens a file at `path` with the options specified by `options`.
38    pub async fn open_file_with(
39        &self,
40        path: impl AsRef<Path>,
41        options: &OpenOptions,
42    ) -> io::Result<File> {
43        self.inner.open_file_with(path, options).await
44    }
45
46    /// Attempts to open a file in read-only mode.
47    pub async fn open_file(&self, path: impl AsRef<Path>) -> io::Result<File> {
48        self.open_file_with(path, OpenOptions::new().read(true))
49            .await
50    }
51
52    /// Opens a file in write-only mode.
53    pub async fn create_file(&self, path: impl AsRef<Path>) -> io::Result<File> {
54        self.open_file_with(
55            path,
56            OpenOptions::new().write(true).create(true).truncate(true),
57        )
58        .await
59    }
60
61    /// Attempts to open a directory.
62    pub async fn open_dir(&self, path: impl AsRef<Path>) -> io::Result<Self> {
63        Ok(Self {
64            inner: self.inner.open_dir(path).await?,
65        })
66    }
67
68    /// Creates the specified directory with the options configured in this
69    /// builder.
70    pub async fn create_dir_with(
71        &self,
72        path: impl AsRef<Path>,
73        builder: &DirBuilder,
74    ) -> io::Result<()> {
75        self.inner.create_dir_with(path, builder).await
76    }
77
78    /// Creates a new, empty directory at the provided path.
79    pub async fn create_dir(&self, path: impl AsRef<Path>) -> io::Result<()> {
80        self.create_dir_with(path, &DirBuilder::new()).await
81    }
82
83    /// Recursively create a directory and all of its parent components if they
84    /// are missing.
85    pub async fn create_dir_all(&self, path: impl AsRef<Path>) -> io::Result<()> {
86        self.create_dir_with(path, DirBuilder::new().recursive(true))
87            .await
88    }
89
90    /// Queries metadata about the underlying directory.
91    pub async fn dir_metadata(&self) -> io::Result<Metadata> {
92        self.inner.dir_metadata().await
93    }
94
95    /// Given a path, query the file system to get information about a file,
96    /// directory, etc.
97    pub async fn metadata(&self, path: impl AsRef<Path>) -> io::Result<Metadata> {
98        self.inner.metadata(path).await
99    }
100
101    /// Query the metadata about a file without following symlinks.
102    pub async fn symlink_metadata(&self, path: impl AsRef<Path>) -> io::Result<Metadata> {
103        self.inner.symlink_metadata(path).await
104    }
105
106    /// Creates a new hard link on a filesystem.
107    pub async fn hard_link(
108        &self,
109        source: impl AsRef<Path>,
110        target_dir: &Self,
111        target: impl AsRef<Path>,
112    ) -> io::Result<()> {
113        self.inner
114            .hard_link(source, &target_dir.inner, target)
115            .await
116    }
117
118    /// Creates a new symbolic link on a filesystem.
119    ///
120    /// The `original` argument provides the target of the symlink. The `link`
121    /// argument provides the name of the created symlink.
122    ///
123    /// Despite the argument ordering, `original` is not resolved relative to
124    /// self here. `link` is resolved relative to self, and `original` is
125    /// not resolved within this function.
126    #[cfg(unix)]
127    pub async fn symlink(
128        &self,
129        original: impl AsRef<Path>,
130        link: impl AsRef<Path>,
131    ) -> io::Result<()> {
132        self.inner.symlink(original, link).await
133    }
134
135    /// Creates a new file symbolic link on a filesystem.
136    ///
137    /// The `original` argument provides the target of the symlink. The `link`
138    /// argument provides the name of the created symlink.
139    ///
140    /// Despite the argument ordering, `original` is not resolved relative to
141    /// self here. `link` is resolved relative to self, and `original` is
142    /// not resolved within this function.
143    #[cfg(windows)]
144    pub async fn symlink_file(
145        &self,
146        original: impl AsRef<Path>,
147        link: impl AsRef<Path>,
148    ) -> io::Result<()> {
149        self.inner.symlink_file(original, link).await
150    }
151
152    /// Creates a new directory symlink on a filesystem.
153    ///
154    /// The `original` argument provides the target of the symlink. The `link`
155    /// argument provides the name of the created symlink.
156    ///
157    /// Despite the argument ordering, `original` is not resolved relative to
158    /// self here. `link` is resolved relative to self, and `original` is
159    /// not resolved within this function.
160    #[cfg(windows)]
161    pub async fn symlink_dir(
162        &self,
163        original: impl AsRef<Path>,
164        link: impl AsRef<Path>,
165    ) -> io::Result<()> {
166        self.inner.symlink_dir(original, link).await
167    }
168
169    /// Rename a file or directory to a new name, replacing the original file if
170    /// it already exists.
171    pub async fn rename(
172        &self,
173        from: impl AsRef<Path>,
174        to_dir: &Self,
175        to: impl AsRef<Path>,
176    ) -> io::Result<()> {
177        self.inner.rename(from, &to_dir.inner, to).await
178    }
179
180    /// Removes a file from a filesystem.
181    pub async fn remove_file(&self, path: impl AsRef<Path>) -> io::Result<()> {
182        self.inner.remove_file(path).await
183    }
184
185    /// Removes an empty directory.
186    pub async fn remove_dir(&self, path: impl AsRef<Path>) -> io::Result<()> {
187        self.inner.remove_dir(path).await
188    }
189
190    /// Read the entire contents of a file into a bytes vector.
191    pub async fn read(&self, path: impl AsRef<Path>) -> io::Result<Vec<u8>> {
192        let file = self.open_file(path).await?;
193        let BufResult(res, buf) = file.read_to_end_at(Vec::new(), 0).await;
194        res?;
195        Ok(buf)
196    }
197
198    /// Write a buffer as the entire contents of a file.
199    pub async fn write<B: IoBuf>(&self, path: impl AsRef<Path>, buf: B) -> BufResult<(), B> {
200        let (mut file, buf) = buf_try!(self.create_file(path).await, buf);
201        file.write_all_at(buf, 0).await
202    }
203}
204
205compio_driver::impl_raw_fd!(Dir, std::fs::File, inner);