opendal_service_compfs/
backend.rs1use std::io::Cursor;
19use std::sync::Arc;
20
21use compio::dispatcher::Dispatcher;
22use compio::fs::OpenOptions;
23
24use super::COMPFS_SCHEME;
25use super::config::CompfsConfig;
26use super::core::CompfsCore;
27use super::deleter::CompfsDeleter;
28use super::reader::*;
29use opendal_core::raw::*;
30use opendal_core::*;
31
32#[derive(Debug, Default)]
34pub struct CompfsBuilder {
35 pub(super) config: CompfsConfig,
36}
37
38impl CompfsBuilder {
39 pub fn root(mut self, root: &str) -> Self {
41 self.config.root = if root.is_empty() {
42 None
43 } else {
44 Some(root.to_string())
45 };
46
47 self
48 }
49}
50
51impl Builder for CompfsBuilder {
52 type Config = CompfsConfig;
53
54 fn build(self) -> Result<impl Service> {
55 let root = match self.config.root {
56 Some(root) => Ok(root),
57 None => Err(Error::new(
58 ErrorKind::ConfigInvalid,
59 "root is not specified",
60 )),
61 }?;
62
63 if let Err(e) = std::fs::metadata(&root)
65 && e.kind() == std::io::ErrorKind::NotFound
66 {
67 std::fs::create_dir_all(&root).map_err(|e| {
68 Error::new(ErrorKind::Unexpected, "create root dir failed")
69 .with_operation("Builder::build")
70 .with_context("root", root.as_str())
71 .set_source(e)
72 })?;
73 }
74
75 let dispatcher = Dispatcher::new().map_err(|_| {
76 Error::new(
77 ErrorKind::Unexpected,
78 "failed to initiate compio dispatcher",
79 )
80 })?;
81 let core = CompfsCore {
82 info: ServiceInfo::new(COMPFS_SCHEME, &root, ""),
83 capability: Capability {
84 stat: true,
85
86 read: true,
87
88 write: true,
89 write_can_empty: true,
90 write_can_multi: true,
91 create_dir: true,
92 delete: true,
93
94 list: true,
95
96 copy: true,
97 rename: true,
98
99 shared: true,
100
101 ..Default::default()
102 },
103 root: root.into(),
104 dispatcher,
105 buf_pool: oio::PooledBuf::new(16),
106 };
107 Ok(CompfsBackend {
108 core: Arc::new(core),
109 })
110 }
111}
112
113#[derive(Clone, Debug)]
114pub struct CompfsBackend {
115 pub(crate) core: Arc<CompfsCore>,
116}
117
118impl Service for CompfsBackend {
119 type Reader = oio::PositionReader<CompfsReader>;
120 type Writer = CompfsLazyWriter;
121 type Lister = CompfsLazyLister;
122 type Deleter = oio::OneShotDeleter<CompfsDeleter>;
123 type Copier = oio::OneShotCopier;
124
125 fn info(&self) -> ServiceInfo {
126 self.core.info.clone()
127 }
128
129 fn capability(&self) -> Capability {
130 self.core.capability
131 }
132
133 async fn create_dir(
134 &self,
135 _ctx: &OperationContext,
136 path: &str,
137 _: OpCreateDir,
138 ) -> Result<RpCreateDir> {
139 let path = self.core.prepare_path(path)?;
140
141 self.core
142 .exec(move || async move { compio::fs::create_dir_all(path).await })
143 .await?;
144
145 Ok(RpCreateDir::default())
146 }
147
148 async fn stat(&self, _ctx: &OperationContext, path: &str, _: OpStat) -> Result<RpStat> {
149 let path = self.core.prepare_path(path)?;
150 let meta = self
151 .core
152 .exec(move || async move { compio::fs::metadata(path).await })
153 .await?;
154 let ty = meta.file_type();
155 let mode = if ty.is_dir() {
156 EntryMode::DIR
157 } else if ty.is_file() {
158 EntryMode::FILE
159 } else {
160 EntryMode::Unknown
161 };
162 let last_mod = Timestamp::try_from(meta.modified().map_err(new_std_io_error)?)?;
163 let ret = Metadata::new(mode)
164 .with_last_modified(last_mod)
165 .with_content_length(meta.len());
166 Ok(RpStat::new(ret))
167 }
168
169 fn delete(&self, _ctx: &OperationContext) -> Result<Self::Deleter> {
170 let output: oio::OneShotDeleter<CompfsDeleter> = {
171 Ok(oio::OneShotDeleter::new(CompfsDeleter::new(
172 self.core.clone(),
173 )))
174 }?;
175
176 Ok(output)
177 }
178
179 fn copy(
180 &self,
181 _ctx: &OperationContext,
182 from: &str,
183 to: &str,
184 _: OpCopy,
185 _opts: OpCopier,
186 ) -> Result<Self::Copier> {
187 let core = self.core.clone();
188 let from = self.core.prepare_path(from)?;
189 let to = self.core.prepare_path(to)?;
190
191 Ok(oio::OneShotCopier::new(async move {
192 core.exec(move || async move {
193 let from = OpenOptions::new().read(true).open(from).await?;
194 if let Some(parent) = to.parent() {
195 compio::fs::create_dir_all(parent).await?;
196 }
197 let to = OpenOptions::new()
198 .write(true)
199 .create(true)
200 .truncate(true)
201 .open(to)
202 .await?;
203
204 let (mut from, mut to) = (Cursor::new(from), Cursor::new(to));
205 compio::io::copy(&mut from, &mut to).await?;
206
207 Ok(Metadata::default())
208 })
209 .await
210 }))
211 }
212
213 async fn rename(
214 &self,
215 _ctx: &OperationContext,
216 from: &str,
217 to: &str,
218 _: OpRename,
219 ) -> Result<RpRename> {
220 let from = self.core.prepare_path(from)?;
221 let to = self.core.prepare_path(to)?;
222
223 self.core
224 .exec(move || async move {
225 if let Some(parent) = to.parent() {
226 compio::fs::create_dir_all(parent).await?;
227 }
228 compio::fs::rename(from, to).await
229 })
230 .await?;
231
232 Ok(RpRename::default())
233 }
234 fn read(&self, _ctx: &OperationContext, path: &str, _: OpRead) -> Result<Self::Reader> {
235 Ok(oio::PositionReader::new(CompfsReader::new(
236 self.core.clone(),
237 self.core.prepare_path(path)?,
238 )))
239 }
240
241 fn write(&self, _ctx: &OperationContext, path: &str, args: OpWrite) -> Result<Self::Writer> {
242 Ok(CompfsLazyWriter::new(
243 self.core.clone(),
244 self.core.prepare_path(path)?,
245 args,
246 ))
247 }
248
249 fn list(&self, _ctx: &OperationContext, path: &str, _: OpList) -> Result<Self::Lister> {
250 Ok(CompfsLazyLister::new(
251 self.core.clone(),
252 self.core.prepare_path(path)?,
253 ))
254 }
255
256 async fn presign(
257 &self,
258 _ctx: &OperationContext,
259 _path: &str,
260 _args: OpPresign,
261 ) -> Result<RpPresign> {
262 Err(Error::new(
263 ErrorKind::Unsupported,
264 "operation is not supported",
265 ))
266 }
267}