1use std::ffi::OsString;
4use std::fmt::Debug;
5use std::io::Result;
6use std::path::{Path, PathBuf};
7use std::time::SystemTime;
8
9use tokio::io::{AsyncRead, AsyncSeek, AsyncWrite};
10
11pub mod mem;
12pub mod tokio_fs;
13
14pub mod prelude {
15 pub use crate::{
16 FloppyDirBuilder, FloppyDirEntry, FloppyDisk, FloppyDiskUnixExt, FloppyFile,
17 FloppyFileType, FloppyMetadata, FloppyOpenOptions, FloppyPermissions, FloppyReadDir,
18 FloppyUnixMetadata, FloppyUnixPermissions,
19 };
20
21 pub use crate::mem::MemFloppyDisk;
22 pub use crate::tokio_fs::TokioFloppyDisk;
23}
24
25#[async_trait::async_trait]
26pub trait FloppyDisk<'a>: Debug + std::marker::Unpin + std::marker::Sized + Send {
27 type DirBuilder: FloppyDirBuilder + Send + 'a;
28 type DirEntry: FloppyDirEntry<'a, Self> + Send + 'a;
29 type File: FloppyFile<'a, Self> + Send + 'a;
30 type FileType: FloppyFileType + Send + 'a;
31 type Metadata: FloppyMetadata<'a, Self> + Send + 'a;
32 type OpenOptions: FloppyOpenOptions<'a, Self> + Send + 'a;
33 type Permissions: FloppyPermissions + Send + 'a;
34 type ReadDir: FloppyReadDir<'a, Self> + Send + 'a;
35 async fn canonicalize<P: AsRef<Path> + Send>(&self, path: P) -> Result<PathBuf>;
38
39 async fn copy<P: AsRef<Path> + Send>(&self, from: P, to: P) -> Result<u64>;
40
41 async fn create_dir<P: AsRef<Path> + Send>(&self, path: P) -> Result<()>;
42
43 async fn create_dir_all<P: AsRef<Path> + Send>(&self, path: P) -> Result<()>;
44
45 async fn hard_link<P: AsRef<Path> + Send>(&self, src: P, dst: P) -> Result<()>;
46
47 async fn metadata<P: AsRef<Path> + Send>(&self, path: P) -> Result<Self::Metadata>;
48
49 async fn read<P: AsRef<Path> + Send>(&self, path: P) -> Result<Vec<u8>>;
50
51 async fn read_dir<P: AsRef<Path> + Send>(&self, path: P) -> Result<Self::ReadDir>;
52
53 async fn read_link<P: AsRef<Path> + Send>(&self, path: P) -> Result<PathBuf>;
54
55 async fn read_to_string<P: AsRef<Path> + Send>(&self, path: P) -> Result<String>;
56
57 async fn remove_dir<P: AsRef<Path> + Send>(&self, path: P) -> Result<()>;
58
59 async fn remove_dir_all<P: AsRef<Path> + Send>(&self, path: P) -> Result<()>;
60
61 async fn remove_file<P: AsRef<Path> + Send>(&self, path: P) -> Result<()>;
62
63 async fn rename<P: AsRef<Path> + Send>(&self, from: P, to: P) -> Result<()>;
64
65 async fn set_permissions<P: AsRef<Path> + Send>(
66 &self,
67 path: P,
68 perm: Self::Permissions,
69 ) -> Result<()>;
70
71 async fn symlink<P: AsRef<Path> + Send>(&self, src: P, dst: P) -> Result<()>;
72
73 async fn symlink_metadata<P: AsRef<Path> + Send>(&self, path: P) -> Result<Self::Metadata>;
74
75 async fn try_exists<P: AsRef<Path> + Send>(&self, path: P) -> Result<bool>;
76
77 async fn write<P: AsRef<Path> + Send>(
78 &self,
79 path: P,
80 contents: impl AsRef<[u8]> + Send,
81 ) -> Result<()>;
82
83 fn new_dir_builder(&'a self) -> Self::DirBuilder;
84
85 async fn find_in_dir<P: AsRef<Path> + Send, S: Into<String> + Send>(
88 &self,
89 path: P,
90 needle: S,
91 ) -> Result<Option<PathBuf>> {
92 let needle = needle.into();
93 let mut dir = self.read_dir(path).await?;
94 while let Some(entry) = dir.next_entry().await? {
95 let path = entry.path();
96 if let Some(file_name) = path.file_name() {
97 let file_name = file_name.to_string_lossy();
99 if file_name == needle
100 || file_name.starts_with(&needle)
101 || file_name.ends_with(&needle)
102 {
103 return Ok(Some(path));
104 }
105 }
106 }
107 Ok(None)
108 }
109}
110
111#[async_trait::async_trait]
112pub trait FloppyDiskUnixExt {
113 async fn chown<P: Into<PathBuf> + Send>(&self, path: P, uid: u32, gid: u32) -> Result<()>;
114}
115
116#[allow(clippy::len_without_is_empty)]
117#[async_trait::async_trait]
118pub trait FloppyMetadata<'a, Disk: FloppyDisk<'a>>: Debug + std::marker::Unpin + Send {
119 fn file_type(&self) -> Disk::FileType;
120 fn is_dir(&self) -> bool;
121 fn is_file(&self) -> bool;
122 fn is_symlink(&self) -> bool;
123 fn len(&self) -> u64;
124 fn permissions(&self) -> Disk::Permissions;
125 fn modified(&self) -> Result<SystemTime>;
126 fn accessed(&self) -> Result<SystemTime>;
127 fn created(&self) -> Result<SystemTime>;
128}
129
130#[async_trait::async_trait]
131pub trait FloppyUnixMetadata {
132 fn uid(&self) -> Result<u32>;
133 fn gid(&self) -> Result<u32>;
134}
135
136#[async_trait::async_trait]
137pub trait FloppyReadDir<'a, Disk: FloppyDisk<'a>>: Debug + std::marker::Unpin + Send {
138 async fn next_entry(&mut self) -> Result<Option<Disk::DirEntry>>;
139}
140
141pub trait FloppyPermissions: Debug + std::marker::Unpin + Send {
142 fn readonly(&self) -> bool;
143 fn set_readonly(&mut self, readonly: bool);
144}
145
146pub trait FloppyUnixPermissions: Debug + std::marker::Unpin + Send {
147 fn mode(&self) -> u32;
148 fn set_mode(&mut self, mode: u32);
149 fn from_mode(mode: u32) -> Self;
150}
151
152#[async_trait::async_trait]
153pub trait FloppyDirBuilder: Debug + std::marker::Unpin + Send {
154 fn recursive(&mut self, recursive: bool) -> &mut Self;
155 async fn create<P: AsRef<Path> + Send>(&self, path: P) -> Result<()>;
156 #[cfg(unix)]
157 fn mode(&mut self, mode: u32) -> &mut Self;
158}
159
160#[async_trait::async_trait]
161pub trait FloppyDirEntry<'a, Disk: FloppyDisk<'a>>: Debug + std::marker::Unpin + Send {
162 fn path(&self) -> PathBuf;
163 fn file_name(&self) -> OsString;
164 async fn metadata(&self) -> Result<Disk::Metadata>;
165 async fn file_type(&self) -> Result<Disk::FileType>;
166
167 #[cfg(unix)]
168 fn ino(&self) -> u64;
169}
170
171#[async_trait::async_trait]
172pub trait FloppyFile<'a, Disk: FloppyDisk<'a>>:
173 AsyncRead + AsyncWrite + AsyncSeek + Debug + std::marker::Unpin + Send
174{
175 async fn sync_all(&mut self) -> Result<()>;
176 async fn sync_data(&mut self) -> Result<()>;
177 async fn set_len(&mut self, size: u64) -> Result<()>;
178 async fn metadata(&self) -> Result<Disk::Metadata>;
179 async fn try_clone(&'a self) -> Result<Box<Disk::File>>;
180 async fn set_permissions(&self, perm: Disk::Permissions) -> Result<()>;
181 async fn permissions(&self) -> Result<Disk::Permissions>;
182}
183
184#[async_trait::async_trait]
185pub trait FloppyOpenOptions<'a, Disk: FloppyDisk<'a>>: Debug + std::marker::Unpin + Send {
186 fn new() -> Self;
187 fn read(self, read: bool) -> Self;
188 fn write(self, write: bool) -> Self;
189 fn append(self, append: bool) -> Self;
190 fn truncate(self, truncate: bool) -> Self;
191 fn create(self, create: bool) -> Self;
192 fn create_new(self, create_new: bool) -> Self;
193 async fn open<P: AsRef<Path> + Send>(&self, disk: &'a Disk, path: P) -> Result<Disk::File>;
194}
195
196pub trait FloppyFileType: Debug + std::marker::Unpin + Send {
197 fn is_dir(&self) -> bool;
198 fn is_file(&self) -> bool;
199 fn is_symlink(&self) -> bool;
200}
201
202