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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#[cfg(unix)]
#[path = "unix.rs"]
mod sys;

#[cfg(windows)]
#[path = "windows.rs"]
mod sys;

use std::{io, path::Path};

use compio_buf::{buf_try, BufResult, IoBuf};
use compio_io::{AsyncReadAtExt, AsyncWriteAtExt};

use crate::{metadata, File};

/// Removes a file from the filesystem.
pub async fn remove_file(path: impl AsRef<Path>) -> io::Result<()> {
    sys::remove_file(path).await
}

/// Removes an empty directory.
pub async fn remove_dir(path: impl AsRef<Path>) -> io::Result<()> {
    sys::remove_dir(path).await
}

/// Creates a new, empty directory at the provided path.
pub async fn create_dir(path: impl AsRef<Path>) -> io::Result<()> {
    DirBuilder::new().create(path).await
}

/// Recursively create a directory and all of its parent components if they are
/// missing.
pub async fn create_dir_all(path: impl AsRef<Path>) -> io::Result<()> {
    DirBuilder::new().recursive(true).create(path).await
}

/// Rename a file or directory to a new name, replacing the original file if
/// `to` already exists.
pub async fn rename(from: impl AsRef<Path>, to: impl AsRef<Path>) -> io::Result<()> {
    sys::rename(from, to).await
}

/// Creates a new symbolic link on the filesystem.
#[cfg(unix)]
pub async fn symlink(original: impl AsRef<Path>, link: impl AsRef<Path>) -> io::Result<()> {
    sys::symlink(original, link).await
}

/// Creates a new symlink to a non-directory file on the filesystem.
#[cfg(windows)]
pub async fn symlink_file(original: impl AsRef<Path>, link: impl AsRef<Path>) -> io::Result<()> {
    sys::symlink_file(original, link).await
}

/// Creates a new symlink to a directory on the filesystem.
#[cfg(windows)]
pub async fn symlink_dir(original: impl AsRef<Path>, link: impl AsRef<Path>) -> io::Result<()> {
    sys::symlink_dir(original, link).await
}

/// Creates a new hard link on the filesystem.
pub async fn hard_link(original: impl AsRef<Path>, link: impl AsRef<Path>) -> io::Result<()> {
    sys::hard_link(original, link).await
}

/// Write a slice as the entire contents of a file.
///
/// This function will create a file if it does not exist,
/// and will entirely replace its contents if it does.
pub async fn write<P: AsRef<Path>, B: IoBuf>(path: P, buf: B) -> BufResult<(), B> {
    let (mut file, buf) = buf_try!(File::create(path).await, buf);
    file.write_all_at(buf, 0).await
}

/// Read the entire contents of a file into a bytes vector.
pub async fn read<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
    let file = File::open(path).await?;
    let BufResult(res, buffer) = file.read_to_end_at(Vec::new(), 0).await;
    res?;
    Ok(buffer)
}

/// A builder used to create directories in various manners.
pub struct DirBuilder {
    inner: sys::DirBuilder,
    recursive: bool,
}

impl Default for DirBuilder {
    fn default() -> Self {
        Self::new()
    }
}

impl DirBuilder {
    /// Creates a new set of options with default mode/security settings for all
    /// platforms and also non-recursive.
    pub fn new() -> Self {
        Self {
            inner: sys::DirBuilder::new(),
            recursive: false,
        }
    }

    /// Indicates that directories should be created recursively, creating all
    /// parent directories. Parents that do not exist are created with the same
    /// security and permissions settings.
    pub fn recursive(&mut self, recursive: bool) -> &mut Self {
        self.recursive = recursive;
        self
    }

    /// Creates the specified directory with the options configured in this
    /// builder.
    pub async fn create(&self, path: impl AsRef<Path>) -> io::Result<()> {
        let path = path.as_ref();
        if self.recursive {
            self.create_dir_all(path).await
        } else {
            self.inner.create(path).await
        }
    }

    async fn create_dir_all(&self, path: &Path) -> io::Result<()> {
        if path == Path::new("") {
            return Ok(());
        }

        match self.inner.create(path).await {
            Ok(()) => return Ok(()),
            Err(ref e) if e.kind() == io::ErrorKind::NotFound => {}
            Err(_) if metadata(path).await.map(|m| m.is_dir()).unwrap_or_default() => return Ok(()),
            Err(e) => return Err(e),
        }
        match path.parent() {
            Some(p) => Box::pin(self.create_dir_all(p)).await?,
            None => {
                return Err(io::Error::new(
                    io::ErrorKind::Other,
                    "failed to create whole tree",
                ));
            }
        }
        match self.inner.create(path).await {
            Ok(()) => Ok(()),
            Err(_) if metadata(path).await.map(|m| m.is_dir()).unwrap_or_default() => Ok(()),
            Err(e) => Err(e),
        }
    }
}

#[cfg(unix)]
impl std::os::unix::fs::DirBuilderExt for DirBuilder {
    fn mode(&mut self, mode: u32) -> &mut Self {
        self.inner.mode(mode);
        self
    }
}