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 type Composer = ();
125
126 fn info(&self) -> ServiceInfo {
127 self.core.info.clone()
128 }
129
130 fn capability(&self) -> Capability {
131 self.core.capability
132 }
133
134 async fn create_dir(
135 &self,
136 _ctx: &OperationContext,
137 path: &str,
138 _: OpCreateDir,
139 ) -> Result<RpCreateDir> {
140 let path = self.core.prepare_path(path)?;
141
142 self.core
143 .exec(move || async move { compio::fs::create_dir_all(path).await })
144 .await?;
145
146 Ok(RpCreateDir::default())
147 }
148
149 async fn stat(&self, _ctx: &OperationContext, path: &str, _: OpStat) -> Result<RpStat> {
150 let path = self.core.prepare_path(path)?;
151 let meta = self
152 .core
153 .exec(move || async move { compio::fs::metadata(path).await })
154 .await?;
155 let ty = meta.file_type();
156 let mode = if ty.is_dir() {
157 EntryMode::DIR
158 } else if ty.is_file() {
159 EntryMode::FILE
160 } else {
161 EntryMode::Unknown
162 };
163 let last_mod = Timestamp::try_from(meta.modified().map_err(new_std_io_error)?)?;
164 let mut ret = match mode {
165 EntryMode::FILE => MetadataBuilder::file(meta.len()),
166 EntryMode::DIR => MetadataBuilder::dir(),
167 EntryMode::Unknown => MetadataBuilder::unknown(),
168 };
169 ret.last_modified(last_mod);
170 Ok(RpStat::new(ret.build()))
171 }
172
173 fn delete(&self, _ctx: &OperationContext) -> Result<Self::Deleter> {
174 let output: oio::OneShotDeleter<CompfsDeleter> = {
175 Ok(oio::OneShotDeleter::new(CompfsDeleter::new(
176 self.core.clone(),
177 )))
178 }?;
179
180 Ok(output)
181 }
182
183 fn copy(
184 &self,
185 _ctx: &OperationContext,
186 from: &str,
187 to: &str,
188 _: OpCopy,
189 ) -> Result<Self::Copier> {
190 let core = self.core.clone();
191 let from = self.core.prepare_path(from)?;
192 let to = self.core.prepare_path(to)?;
193
194 Ok(oio::OneShotCopier::new(async move {
195 core.exec(move || async move {
196 let from = OpenOptions::new().read(true).open(from).await?;
197 if let Some(parent) = to.parent() {
198 compio::fs::create_dir_all(parent).await?;
199 }
200 let to = OpenOptions::new()
201 .write(true)
202 .create(true)
203 .truncate(true)
204 .open(to)
205 .await?;
206
207 let (mut from, mut to) = (Cursor::new(from), Cursor::new(to));
208 let size = compio::io::copy(&mut from, &mut to).await?;
209
210 let metadata = MetadataBuilder::file(size);
211 Ok(metadata.build())
212 })
213 .await
214 }))
215 }
216
217 async fn rename(
218 &self,
219 _ctx: &OperationContext,
220 from: &str,
221 to: &str,
222 _: OpRename,
223 ) -> Result<RpRename> {
224 let from = self.core.prepare_path(from)?;
225 let to = self.core.prepare_path(to)?;
226
227 self.core
228 .exec(move || async move {
229 if let Some(parent) = to.parent() {
230 compio::fs::create_dir_all(parent).await?;
231 }
232 compio::fs::rename(from, to).await
233 })
234 .await?;
235
236 Ok(RpRename::default())
237 }
238 fn read(&self, _ctx: &OperationContext, path: &str, _: OpRead) -> Result<Self::Reader> {
239 Ok(oio::PositionReader::new(CompfsReader::new(
240 self.core.clone(),
241 self.core.prepare_path(path)?,
242 )))
243 }
244
245 fn write(&self, _ctx: &OperationContext, path: &str, args: OpWrite) -> Result<Self::Writer> {
246 Ok(CompfsLazyWriter::new(
247 self.core.clone(),
248 self.core.prepare_path(path)?,
249 args,
250 ))
251 }
252
253 fn list(&self, _ctx: &OperationContext, path: &str, _: OpList) -> Result<Self::Lister> {
254 Ok(CompfsLazyLister::new(
255 self.core.clone(),
256 self.core.prepare_path(path)?,
257 ))
258 }
259
260 async fn presign(
261 &self,
262 _ctx: &OperationContext,
263 _path: &str,
264 _args: OpPresign,
265 ) -> Result<RpPresign> {
266 Err(Error::new(
267 ErrorKind::Unsupported,
268 "operation is not supported",
269 ))
270 }
271}