1use crate::traits::{validate_read_into_results, validate_read_results, validate_write_results};
7use crate::*;
8
9pub trait FileSystem {
11 fn capabilities(&self) -> Capabilities;
12 fn read_file(&mut self, file: &VfFile, max_bytes: usize) -> VfResult<Vec<u8>> {
15 let mut output = Vec::new();
16 loop {
17 let remaining = max_bytes.saturating_sub(output.len());
18 let request = ReadOp::new(
19 file.clone(),
20 VfOffset::At(output.len() as u64),
21 remaining.clamp(1, 1024 * 1024),
22 );
23 let result = self.read_one(&request)?;
24 validate_read_results(
25 "read_file",
26 std::slice::from_ref(&request),
27 std::slice::from_ref(&result),
28 )?;
29 if result.data.len() > remaining {
30 return Err(VfError::client(0, libc::EFBIG as u32));
31 }
32 if result.data.is_empty() && !result.eof {
33 return Err(VfError::client(0, ERR_IO));
34 }
35 output.extend_from_slice(&result.data);
36 if result.eof {
37 return Ok(output);
38 }
39 }
40 }
41 fn open_one(&mut self, request: &OpenRequest) -> VfResult<VfFile>;
42 fn close_one(&mut self, file: &VfFile) -> VfResult<()>;
43 fn sync_data(&mut self, file: &VfFile) -> VfResult<()>;
44 fn sync_all(&mut self, file: &VfFile) -> VfResult<()>;
45 fn read_one(&mut self, request: &ReadOp) -> VfResult<ReadResult>;
46 fn read_one_into(&mut self, request: &ReadOp, buffer: &mut [u8]) -> VfResult<ReadIntoResult> {
48 if request.length != buffer.len() {
49 return Err(VfError::client(0, ERR_INVAL));
50 }
51 let result = self.read_one(request)?;
52 if result.data.len() > buffer.len() {
53 return Err(VfError::client(0, ERR_IO));
54 }
55 validate_read_results(
56 "read_one_into",
57 std::slice::from_ref(request),
58 std::slice::from_ref(&result),
59 )?;
60 buffer[..result.data.len()].copy_from_slice(&result.data);
61 Ok(ReadIntoResult {
62 file: result.file,
63 offset: result.offset,
64 read: result.data.len(),
65 eof: result.eof,
66 })
67 }
68 fn write_one(&mut self, request: WriteOpRef<'_>) -> VfResult<WriteResult>;
69 fn seek_one(&mut self, file: &VfFile, position: std::io::SeekFrom) -> VfResult<u64>;
70 fn metadata(&mut self, query: MetadataQuery) -> VfResult<VfAttrs>;
71 fn set_attributes(&mut self, update: SetAttributes) -> VfResult<()>;
72}
73
74pub trait MetadataFileSystem: FileSystem {
76 fn metadata_path(&mut self, path: &std::path::Path, follow: bool) -> VfResult<Metadata>;
77 fn set_metadata_path(
78 &mut self,
79 path: &std::path::Path,
80 update: MetadataUpdate,
81 follow: bool,
82 ) -> VfResult<()>;
83}
84
85pub trait DirectoryFileSystem: FileSystem {
87 fn create_dir_one(&mut self, path: &std::path::Path, mode: u32) -> VfResult<()>;
88 fn read_dir_one(
89 &mut self,
90 path: &std::path::Path,
91 options: ReadDirOptions,
92 ) -> VfResult<Vec<DirEntry>>;
93
94 fn read_dir_page(
97 &mut self,
98 path: &std::path::Path,
99 cursor: Option<DirPageCursor>,
100 page_size: usize,
101 max_entries: usize,
102 ) -> VfResult<(Vec<DirEntry>, Option<DirPageCursor>)>;
103}
104
105pub trait NamespaceFileSystem: FileSystem {
107 fn remove_one(&mut self, path: &std::path::Path, recursive: bool) -> VfResult<()>;
108 fn remove_dir_contents(&mut self, path: &std::path::Path) -> VfResult<()>;
110 fn rename_one(&mut self, from: &std::path::Path, to: &std::path::Path) -> VfResult<()>;
111}
112
113pub trait LinkFileSystem: FileSystem {
115 fn symlink_one(&mut self, target: &std::path::Path, link: &std::path::Path) -> VfResult<()>;
116 fn hard_link_one(&mut self, source: &std::path::Path, link: &std::path::Path) -> VfResult<()>;
117 fn read_link_one(&mut self, path: &std::path::Path) -> VfResult<std::path::PathBuf>;
118}
119
120pub trait CopyFileSystem: FileSystem {
122 fn copy_one(&mut self, source: &std::path::Path, destination: &std::path::Path)
123 -> VfResult<()>;
124}
125
126pub trait NativeFileSystem:
128 FileSystem
129 + MetadataFileSystem
130 + DirectoryFileSystem
131 + NamespaceFileSystem
132 + LinkFileSystem
133 + CopyFileSystem
134{
135}
136
137impl<T> NativeFileSystem for T where
138 T: FileSystem
139 + MetadataFileSystem
140 + DirectoryFileSystem
141 + NamespaceFileSystem
142 + LinkFileSystem
143 + CopyFileSystem
144 + ?Sized
145{
146}
147
148pub trait VectorFileSystem: FileSystem {
152 #[doc(hidden)]
159 fn open_many(&mut self, requests: &[OpenRequest]) -> VfResult<Vec<VfFile>>;
160
161 #[doc(hidden)]
163 fn close_many(&mut self, files: &[VfFile]) -> VfResult<()>;
164
165 #[doc(hidden)]
167 fn read_many(&mut self, requests: &[ReadOp]) -> VfResult<Vec<ReadResult>>;
168
169 fn read_many_into(
172 &mut self,
173 requests: &[ReadOp],
174 buffers: &mut [&mut [u8]],
175 ) -> VfResult<Vec<ReadIntoResult>> {
176 if requests.len() != buffers.len() {
177 return Err(VfError::client(0, ERR_INVAL));
178 }
179 for (index, (request, buffer)) in requests.iter().zip(buffers.iter()).enumerate() {
180 if request.length != buffer.len() {
181 return Err(VfError::client(index, ERR_INVAL));
182 }
183 }
184 let results = self.read_many(requests)?;
185 validate_read_results("read_many_into", requests, &results)?;
186 Ok(results
187 .into_iter()
188 .zip(buffers.iter_mut())
189 .map(|(result, buffer)| {
190 buffer[..result.data.len()].copy_from_slice(&result.data);
191 ReadIntoResult {
192 file: result.file,
193 offset: result.offset,
194 read: result.data.len(),
195 eof: result.eof,
196 }
197 })
198 .collect())
199 }
200
201 #[doc(hidden)]
203 fn write_many(&mut self, requests: &[WriteOpRef<'_>]) -> VfResult<Vec<WriteResult>>;
204}
205
206fn metadata_mask() -> AttrMask {
207 AttrMask::MODE
208 | AttrMask::SIZE
209 | AttrMask::NLINK
210 | AttrMask::FILEID
211 | AttrMask::UID
212 | AttrMask::GID
213 | AttrMask::ATIME
214 | AttrMask::MTIME
215 | AttrMask::CTIME
216 | AttrMask::CHANGE
217}
218
219impl<T: VecFs + ?Sized> FileSystem for T {
220 fn capabilities(&self) -> Capabilities {
221 self.typed_capabilities()
222 }
223
224 fn read_file(&mut self, file: &VfFile, max_bytes: usize) -> VfResult<Vec<u8>> {
225 self.read_allv_with_options(
226 std::slice::from_ref(file),
227 ReadAllOptions::new().max_total_bytes(max_bytes),
228 )
229 .and_then(|mut results| {
230 if results.len() != 1 {
231 return Err(VfError::transport(
232 None,
233 "read_file backend returned an invalid result count",
234 ));
235 }
236 let data = results.pop().expect("validated result count");
237 if data.len() > max_bytes {
238 return Err(VfError::client(0, libc::EFBIG as u32));
239 }
240 Ok(data)
241 })
242 }
243
244 fn open_one(&mut self, request: &OpenRequest) -> VfResult<VfFile> {
245 self.open(
246 request.path.as_path(),
247 vfsi_core::open_flags_to_libc(request.flags)?,
248 request.mode,
249 )
250 .map_err(|error| error.with_context("open", &request.path))
251 }
252
253 fn close_one(&mut self, file: &VfFile) -> VfResult<()> {
254 self.close(file)
255 }
256 fn sync_data(&mut self, file: &VfFile) -> VfResult<()> {
257 VecFs::sync_data(self, file)
258 }
259 fn sync_all(&mut self, file: &VfFile) -> VfResult<()> {
260 VecFs::sync_all(self, file)
261 }
262
263 fn read_one(&mut self, request: &ReadOp) -> VfResult<ReadResult> {
264 let mut results = self.readv(std::slice::from_ref(request))?;
265 validate_read_results("read_one", std::slice::from_ref(request), &results)?;
266 Ok(results.pop().expect("validated one result"))
267 }
268
269 fn read_one_into(&mut self, request: &ReadOp, buffer: &mut [u8]) -> VfResult<ReadIntoResult> {
270 let mut results = self.readv_into(std::slice::from_ref(request), &mut [buffer])?;
271 validate_read_into_results("read_one_into", std::slice::from_ref(request), &results)?;
272 Ok(results.pop().expect("validated one result"))
273 }
274
275 fn write_one(&mut self, request: WriteOpRef<'_>) -> VfResult<WriteResult> {
276 let mut results = self.writev_borrowed(std::slice::from_ref(&request))?;
277 validate_write_results("write_one", std::slice::from_ref(&request), &results)?;
278 Ok(results.pop().expect("validated one result"))
279 }
280
281 fn seek_one(&mut self, file: &VfFile, position: std::io::SeekFrom) -> VfResult<u64> {
282 let (offset, whence) = match position {
283 std::io::SeekFrom::Start(offset) => (
284 i64::try_from(offset).map_err(|_| VfError::failure(0, libc::EOVERFLOW as u32))?,
285 SeekFrom::Set,
286 ),
287 std::io::SeekFrom::End(offset) => (offset, SeekFrom::End),
288 std::io::SeekFrom::Current(offset) => (offset, SeekFrom::Cur),
289 };
290 u64::try_from(self.fseek(file, offset, whence)?).map_err(|_| VfError::failure(0, ERR_INVAL))
291 }
292
293 fn metadata(&mut self, query: MetadataQuery) -> VfResult<VfAttrs> {
294 let path = query.file.path().map(std::path::Path::to_path_buf);
295 let mut attrs = VfAttrs {
296 file: query.file,
297 masks: query.attributes,
298 ..VfAttrs::default()
299 };
300 let result = if query.follow_symlinks {
301 self.getattrsv(std::slice::from_mut(&mut attrs))
302 } else {
303 self.lgetattrsv(std::slice::from_mut(&mut attrs))
304 };
305 result.map_err(|error| match path {
306 Some(path) => error.with_context("metadata", path),
307 None => error,
308 })?;
309 Ok(attrs)
310 }
311
312 fn set_attributes(&mut self, update: SetAttributes) -> VfResult<()> {
313 let follow = update.follow_symlinks;
314 let attrs = update.into_legacy();
315 let path = attrs.file.path().map(std::path::Path::to_path_buf);
316 let result = if follow {
317 self.setattrsv(&[attrs])
318 } else {
319 self.lsetattrsv(&[attrs])
320 };
321 result.map_err(|error| match path {
322 Some(path) => error.with_context("set_attributes", path),
323 None => error,
324 })
325 }
326}
327
328impl<T: VecFs + ?Sized> MetadataFileSystem for T {
329 fn metadata_path(&mut self, path: &std::path::Path, follow: bool) -> VfResult<Metadata> {
330 let mut attributes = VfAttrs {
331 file: VfFile::from_os_path(path),
332 masks: metadata_mask(),
333 ..VfAttrs::default()
334 };
335 let result = if follow {
336 self.getattrsv(std::slice::from_mut(&mut attributes))
337 } else {
338 self.lgetattrsv(std::slice::from_mut(&mut attributes))
339 };
340 result
341 .map_err(|error| error.with_context("metadata", path))
342 .map(|()| vfsi_core::metadata_from_attrs(attributes))
343 }
344
345 fn set_metadata_path(
346 &mut self,
347 path: &std::path::Path,
348 update: MetadataUpdate,
349 follow: bool,
350 ) -> VfResult<()> {
351 let mut attributes = SetAttributes::new(VfFile::from_os_path(path));
352 attributes.follow_symlinks = follow;
353 attributes.mode = update.permissions.map(Permissions::mode);
354 attributes.size = update.len;
355 attributes.atime = update.accessed.map(system_time_parts).transpose()?;
356 attributes.mtime = update.modified.map(system_time_parts).transpose()?;
357 self.set_attributes(attributes)
358 .map_err(|error| error.with_context("set_metadata", path))
359 }
360}
361
362fn system_time_parts(time: std::time::SystemTime) -> VfResult<(i64, u32)> {
363 match time.duration_since(std::time::UNIX_EPOCH) {
364 Ok(duration) => Ok((
365 i64::try_from(duration.as_secs())
366 .map_err(|_| VfError::client(0, libc::EOVERFLOW as u32))?,
367 duration.subsec_nanos(),
368 )),
369 Err(error) => {
370 let duration = error.duration();
371 let seconds = i64::try_from(duration.as_secs())
372 .map_err(|_| VfError::client(0, libc::EOVERFLOW as u32))?;
373 if duration.subsec_nanos() == 0 {
374 Ok((-seconds, 0))
375 } else {
376 let seconds = seconds
377 .checked_add(1)
378 .ok_or_else(|| VfError::client(0, libc::EOVERFLOW as u32))?;
379 Ok((-seconds, 1_000_000_000 - duration.subsec_nanos()))
380 }
381 }
382 }
383}
384
385impl<T: VecFs + ?Sized> DirectoryFileSystem for T {
386 fn create_dir_one(&mut self, path: &std::path::Path, mode: u32) -> VfResult<()> {
387 self.mkdir(path, mode)
388 .map_err(|error| error.with_context("create_dir", path))
389 }
390
391 fn read_dir_one(
392 &mut self,
393 path: &std::path::Path,
394 options: ReadDirOptions,
395 ) -> VfResult<Vec<DirEntry>> {
396 let requested = options.entry_limit().saturating_add(1);
397 let entries = self
398 .listdir(path, metadata_mask(), requested, false)
399 .map_err(|error| error.with_context("read_dir", path))?;
400 if entries.len() > options.entry_limit() {
401 return Err(VfError::failure(options.entry_limit(), libc::EFBIG as u32)
402 .with_context("read_dir", path));
403 }
404 let mut path_bytes = 0usize;
405 entries
406 .into_iter()
407 .enumerate()
408 .map(|(index, attributes)| {
409 let entry_path = attributes
410 .file
411 .path()
412 .map(std::path::Path::to_path_buf)
413 .ok_or_else(|| VfError::client(index, ERR_IO).with_context("read_dir", path))?;
414 path_bytes = path_bytes
415 .checked_add(entry_path.as_os_str().len())
416 .ok_or_else(|| {
417 VfError::failure(index, libc::EFBIG as u32).with_context("read_dir", path)
418 })?;
419 if path_bytes > options.path_byte_limit() {
420 return Err(
421 VfError::failure(index, libc::EFBIG as u32).with_context("read_dir", path)
422 );
423 }
424 Ok(DirEntry::new(
425 entry_path,
426 vfsi_core::metadata_from_attrs(attributes),
427 ))
428 })
429 .collect()
430 }
431
432 fn read_dir_page(
433 &mut self,
434 path: &std::path::Path,
435 cursor: Option<DirPageCursor>,
436 page_size: usize,
437 max_entries: usize,
438 ) -> VfResult<(Vec<DirEntry>, Option<DirPageCursor>)> {
439 let (attributes, next) = self
440 .listdir_page(path, metadata_mask(), cursor, page_size, max_entries)
441 .map_err(|error| error.with_context("visit_dir", path))?;
442 if attributes.len() > page_size {
443 return Err(VfError::transport(
444 None,
445 "listdir_page returned more entries than requested",
446 ));
447 }
448 let entries = attributes
449 .into_iter()
450 .enumerate()
451 .map(|(index, attributes)| {
452 let entry_path = attributes
453 .file
454 .path()
455 .map(std::path::Path::to_path_buf)
456 .ok_or_else(|| {
457 VfError::client(index, ERR_IO).with_context("visit_dir", path)
458 })?;
459 Ok(DirEntry::new(
460 entry_path,
461 vfsi_core::metadata_from_attrs(attributes),
462 ))
463 })
464 .collect::<VfResult<Vec<_>>>()?;
465 Ok((entries, next))
466 }
467}
468
469impl<T: VecFs + ?Sized> NamespaceFileSystem for T {
470 fn remove_one(&mut self, path: &std::path::Path, recursive: bool) -> VfResult<()> {
471 self.rm(&[path], recursive)
472 .map_err(|error| error.with_context("remove", path))
473 }
474
475 fn remove_dir_contents(&mut self, path: &std::path::Path) -> VfResult<()> {
476 self.rm_contents(path)
477 .map_err(|error| error.with_context("remove_dir_contents", path))
478 }
479
480 fn rename_one(&mut self, from: &std::path::Path, to: &std::path::Path) -> VfResult<()> {
481 self.renamev(&[(VfFile::from_os_path(from), VfFile::from_os_path(to))])
482 .map_err(|error| error.with_context("rename", from))
483 }
484}
485
486impl<T: VecFs + ?Sized> LinkFileSystem for T {
487 fn symlink_one(&mut self, target: &std::path::Path, link: &std::path::Path) -> VfResult<()> {
488 self.symlink(target, link)
489 .map_err(|error| error.with_context("symlink", link))
490 }
491
492 fn hard_link_one(&mut self, source: &std::path::Path, link: &std::path::Path) -> VfResult<()> {
493 self.hardlinkv(&[source], &[link])
494 .map_err(|error| error.with_context("hard_link", link))
495 }
496
497 fn read_link_one(&mut self, path: &std::path::Path) -> VfResult<std::path::PathBuf> {
498 self.readlink(path)
499 .map(bytes_to_path)
500 .map_err(|error| error.with_context("read_link", path))
501 }
502}
503
504#[cfg(unix)]
505fn bytes_to_path(bytes: Vec<u8>) -> std::path::PathBuf {
506 use std::os::unix::ffi::OsStringExt;
507 std::ffi::OsString::from_vec(bytes).into()
508}
509
510#[cfg(not(unix))]
511fn bytes_to_path(bytes: Vec<u8>) -> std::path::PathBuf {
512 String::from_utf8_lossy(&bytes).into_owned().into()
513}
514
515impl<T: VecFs + ?Sized> CopyFileSystem for T {
516 fn copy_one(
517 &mut self,
518 source: &std::path::Path,
519 destination: &std::path::Path,
520 ) -> VfResult<()> {
521 self.copyv(&[ExtentPair::from_os_paths(source, 0, destination, 0, None)])
522 .map_err(|error| error.with_context("copy", source))
523 }
524}
525
526impl<T: VecFs + ?Sized> VectorFileSystem for T {
527 fn open_many(&mut self, requests: &[OpenRequest]) -> VfResult<Vec<VfFile>> {
528 let paths: Vec<&std::path::Path> = requests
529 .iter()
530 .map(|request| request.path.as_path())
531 .collect();
532 let flags = translate_open_flags(requests)?;
533 let modes: Vec<u32> = requests.iter().map(|request| request.mode).collect();
534 VecFs::openv(self, &paths, &flags, &modes)
535 }
536
537 fn close_many(&mut self, files: &[VfFile]) -> VfResult<()> {
538 self.closev(files)
539 }
540
541 fn read_many(&mut self, requests: &[ReadOp]) -> VfResult<Vec<ReadResult>> {
542 self.readv(requests)
543 }
544
545 fn read_many_into(
546 &mut self,
547 requests: &[ReadOp],
548 buffers: &mut [&mut [u8]],
549 ) -> VfResult<Vec<ReadIntoResult>> {
550 self.readv_into(requests, buffers)
551 }
552
553 fn write_many(&mut self, requests: &[WriteOpRef<'_>]) -> VfResult<Vec<WriteResult>> {
554 self.writev_borrowed(requests)
555 }
556}
557
558fn translate_open_flags(requests: &[OpenRequest]) -> VfResult<Vec<i32>> {
559 requests
560 .iter()
561 .enumerate()
562 .map(|(index, request)| {
563 vfsi_core::open_flags_to_libc(request.flags).map_err(|error| error.with_index(index))
564 })
565 .collect()
566}
567
568#[cfg(test)]
569mod tests {
570 use super::*;
571
572 #[test]
573 fn invalid_open_flags_retain_their_request_index() {
574 let error = translate_open_flags(&[
575 OpenRequest::new("/valid", OpenFlags::READ),
576 OpenRequest::new("/invalid", OpenFlags::empty()),
577 ])
578 .unwrap_err();
579 assert_eq!(error.index(), Some(1));
580 }
581}