1#[cfg(unix)]
2#[path = "unix.rs"]
3mod sys;
4
5#[cfg(windows)]
6#[path = "windows.rs"]
7mod sys;
8
9use std::{io, path::Path};
10
11use compio_buf::{BufResult, IoBuf, buf_try};
12use compio_io::{AsyncReadAtExt, AsyncWriteAtExt};
13
14use crate::{File, metadata};
15
16pub async fn remove_file(path: impl AsRef<Path>) -> io::Result<()> {
18 sys::remove_file(path).await
19}
20
21pub async fn remove_dir(path: impl AsRef<Path>) -> io::Result<()> {
23 sys::remove_dir(path).await
24}
25
26pub async fn create_dir(path: impl AsRef<Path>) -> io::Result<()> {
28 DirBuilder::new().create(path).await
29}
30
31pub async fn create_dir_all(path: impl AsRef<Path>) -> io::Result<()> {
34 DirBuilder::new().recursive(true).create(path).await
35}
36
37pub async fn rename(from: impl AsRef<Path>, to: impl AsRef<Path>) -> io::Result<()> {
40 sys::rename(from, to).await
41}
42
43#[cfg(unix)]
45pub async fn symlink(original: impl AsRef<Path>, link: impl AsRef<Path>) -> io::Result<()> {
46 sys::symlink(original, link).await
47}
48
49#[cfg(windows)]
51pub async fn symlink_file(original: impl AsRef<Path>, link: impl AsRef<Path>) -> io::Result<()> {
52 sys::symlink_file(original, link).await
53}
54
55#[cfg(windows)]
57pub async fn symlink_dir(original: impl AsRef<Path>, link: impl AsRef<Path>) -> io::Result<()> {
58 sys::symlink_dir(original, link).await
59}
60
61pub async fn hard_link(original: impl AsRef<Path>, link: impl AsRef<Path>) -> io::Result<()> {
63 sys::hard_link(original, link).await
64}
65
66pub async fn write<P: AsRef<Path>, B: IoBuf>(path: P, buf: B) -> BufResult<(), B> {
71 let (mut file, buf) = buf_try!(File::create(path).await, buf);
72 file.write_all_at(buf, 0).await
73}
74
75pub async fn read<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
77 let file = File::open(path).await?;
78 let BufResult(res, buffer) = file.read_to_end_at(Vec::new(), 0).await;
79 res?;
80 Ok(buffer)
81}
82
83#[cfg(any(target_os = "linux", target_os = "android"))]
104pub async fn get_xattr<T: compio_buf::IoBufMut>(
105 path: impl AsRef<Path>,
106 name: impl AsRef<std::ffi::OsStr>,
107 buffer: T,
108) -> BufResult<usize, T> {
109 use std::{ffi::CString, os::unix::ffi::OsStrExt};
110
111 use compio_buf::{IntoInner, IoBufMutExt};
112 use compio_driver::op::{BufResultExt, GetXattr};
113
114 let (path, buffer) = buf_try!(crate::path_string(path), buffer);
115 let (name, mut buffer) = buf_try!(
116 CString::new(name.as_ref().as_bytes()).map_err(io::Error::from),
117 buffer
118 );
119 let query_size = buffer.buf_capacity() == 0;
120 let op = GetXattr::new(path, name, buffer);
121 let res = compio_runtime::submit(op).await.into_inner();
122 if query_size {
123 res
124 } else {
125 unsafe { res.map_advanced() }
130 }
131}
132
133pub struct DirBuilder {
135 inner: sys::DirBuilder,
136 recursive: bool,
137}
138
139impl Default for DirBuilder {
140 fn default() -> Self {
141 Self::new()
142 }
143}
144
145impl DirBuilder {
146 pub fn new() -> Self {
149 Self {
150 inner: sys::DirBuilder::new(),
151 recursive: false,
152 }
153 }
154
155 pub fn recursive(&mut self, recursive: bool) -> &mut Self {
159 self.recursive = recursive;
160 self
161 }
162
163 pub async fn create(&self, path: impl AsRef<Path>) -> io::Result<()> {
166 let path = path.as_ref();
167 if self.recursive {
168 self.create_dir_all(path).await
169 } else {
170 self.inner.create(path).await
171 }
172 }
173
174 async fn create_dir_all(&self, path: &Path) -> io::Result<()> {
175 if path == Path::new("") {
176 return Ok(());
177 }
178
179 match self.inner.create(path).await {
180 Ok(()) => return Ok(()),
181 Err(ref e) if e.kind() == io::ErrorKind::NotFound => {}
182 Err(_) if metadata(path).await.map(|m| m.is_dir()).unwrap_or_default() => return Ok(()),
183 Err(e) => return Err(e),
184 }
185 match path.parent() {
186 Some(p) => Box::pin(self.create_dir_all(p)).await?,
187 None => {
188 return Err(io::Error::other("failed to create whole tree"));
189 }
190 }
191 match self.inner.create(path).await {
192 Ok(()) => Ok(()),
193 Err(_) if metadata(path).await.map(|m| m.is_dir()).unwrap_or_default() => Ok(()),
194 Err(e) => Err(e),
195 }
196 }
197
198 #[cfg(dirfd)]
199 pub(crate) async fn create_at(&self, dir: &File, path: &Path) -> io::Result<()> {
200 if path.is_absolute() {
201 self.create(path).await
202 } else if self.recursive {
203 self.create_dir_all_at(dir, path).await
204 } else {
205 self.inner.create_at(dir, path).await
206 }
207 }
208
209 #[cfg(dirfd)]
210 async fn create_dir_all_at(&self, dir: &File, path: &Path) -> io::Result<()> {
211 use crate::metadata_at;
212
213 if path == Path::new("") {
214 return Ok(());
215 }
216 match self.inner.create_at(dir, path).await {
217 Ok(()) => return Ok(()),
218 Err(ref e) if e.kind() == io::ErrorKind::NotFound => {}
219 Err(_)
220 if metadata_at(dir, path)
221 .await
222 .map(|m| m.is_dir())
223 .unwrap_or_default() =>
224 {
225 return Ok(());
226 }
227 Err(e) => return Err(e),
228 }
229 match path.parent() {
230 Some(p) => Box::pin(self.create_dir_all_at(dir, p)).await?,
231 None => {
232 return Err(io::Error::other("failed to create whole tree"));
233 }
234 }
235 match self.inner.create_at(dir, path).await {
236 Ok(()) => Ok(()),
237 Err(_)
238 if metadata_at(dir, path)
239 .await
240 .map(|m| m.is_dir())
241 .unwrap_or_default() =>
242 {
243 Ok(())
244 }
245 Err(e) => Err(e),
246 }
247 }
248}
249
250#[cfg(unix)]
251impl std::os::unix::fs::DirBuilderExt for DirBuilder {
252 fn mode(&mut self, mode: u32) -> &mut Self {
253 self.inner.mode(mode);
254 self
255 }
256}