Skip to main content

vfsi_sync/backend/
mod.rs

1//! Native synchronous backend contracts.
2//! `HandleBackend` supports owned handles; `VectorBackend` adds native vector engines
3//! and overridable workflows. Shared algorithms live in [`crate::backend::helpers`].
4//!
5//! These are execution hooks, not application traits. Use [`crate::Vfsi`] and
6//! [`crate::VfsiExt`] on a client for portable filesystem operations.
7//! The old root traits and scalar/vector namespace aliases are removed:
8//!
9//! ```compile_fail,E0432
10//! use vfsi_sync::FileSystem;
11//! ```
12//! ```compile_fail,E0432
13//! use vfsi_sync::Backend;
14//! ```
15//! ```compile_fail,E0432
16//! use vfsi_sync::HandleBackend;
17//! ```
18//! ```compile_fail,E0432
19//! use vfsi_sync::VectorBackend;
20//! ```
21//! ```compile_fail,E0432
22//! use vfsi_sync::sfsi;
23//! ```
24//! ```compile_fail,E0432
25//! use vfsi_sync::vfsi;
26//! ```
27//! ```compile_fail,E0432
28//! use vfsi_sync::backend_helpers;
29//! ```
30
31/// Shared execution defaults for backend implementers.
32#[doc(hidden)]
33pub mod helpers;
34
35use crate::*;
36use std::path::{Path, PathBuf};
37use vfsi_core::internal::ManyResults;
38
39/// Minimum contract for owned handles and descriptor lifecycle.
40/// This includes handle-level metadata/statistics hooks, but does not require
41/// namespace operations, directory enumeration, or native vector I/O.
42pub trait HandleBackend {
43    fn vstatfs_impl(&mut self, files: &[VfFile]) -> VfResult<Vec<FilesystemStats>> {
44        if files.is_empty() {
45            Ok(Vec::new())
46        } else {
47            Err(VfError::unsupported(0))
48        }
49    }
50
51    fn close_deferred(&mut self, file: &VfFile) -> VfResult<()> {
52        self.close_impl(file)
53    }
54
55    fn take_notifications(&mut self) -> Vec<Box<dyn FnOnce() + Send>> {
56        Vec::new()
57    }
58
59    fn capabilities(&self) -> Capabilities {
60        Capabilities::empty()
61    }
62
63    fn abs_path(&self, path: &Path) -> PathBuf {
64        path.to_path_buf()
65    }
66
67    fn open_path_impl(
68        &mut self,
69        _base: VfPathBase,
70        _pathname: &Path,
71        _flags: i32,
72        _mode: u32,
73    ) -> VfResult<VfFile> {
74        Err(VfError::unsupported(0))
75    }
76
77    /// One backend synchronization vector. POSIX backends may loop under one
78    /// lock because fsync has no vector syscall; protocol backends may batch.
79    fn vfsync_impl(&mut self, files: &[VfFile], mode: vfsi_core::api::SyncMode) -> VfRes {
80        for (index, file) in files.iter().enumerate() {
81            match mode {
82                vfsi_core::api::SyncMode::Data => self.sync_data(file),
83                vfsi_core::api::SyncMode::All => self.sync_all(file),
84            }
85            .map_err(|error| error.map_index(|_| index))?;
86        }
87        Ok(())
88    }
89
90    fn sync_data(&mut self, tcf: &VfFile) -> VfResult<()>;
91
92    fn sync_all(&mut self, tcf: &VfFile) -> VfResult<()> {
93        self.sync_data(tcf)
94    }
95
96    fn chdir(&mut self, _path: &Path) -> VfResult<()> {
97        Err(VfError::unsupported(0))
98    }
99
100    fn getcwd(&self) -> PathBuf {
101        PathBuf::from("/")
102    }
103
104    fn seek_raw_impl(&mut self, _tcf: &VfFile, _offset: i64, _whence: SeekFrom) -> VfResult<i64> {
105        Err(VfError::unsupported(0))
106    }
107
108    fn vf_path(&self, file: &VfFile) -> VfResult<PathBuf> {
109        crate::backend::helpers::vf_path_default(self, file)
110    }
111
112    fn open_raw_impl(&mut self, pathname: &Path, flags: i32, mode: u32) -> VfResult<VfFile> {
113        crate::backend::helpers::open_raw_impl_default(self, pathname, flags, mode)
114    }
115
116    fn read_raw_impl(&mut self, file: &VfFile, offset: u64, length: usize) -> VfResult<Vec<u8>> {
117        crate::backend::helpers::read_raw_impl_default(self, file, offset, length)
118    }
119
120    fn write_raw_impl(&mut self, file: &VfFile, offset: u64, data: &[u8]) -> VfResult<usize> {
121        crate::backend::helpers::write_raw_impl_default(self, file, offset, data)
122    }
123
124    fn read_file_impl(&mut self, file: &VfFile, max_bytes: usize) -> VfResult<Vec<u8>> {
125        crate::backend::helpers::read_file_impl_default(self, file, max_bytes)
126    }
127
128    fn open_impl(&mut self, request: &OpenOp) -> VfResult<VfFile>;
129
130    fn close_impl(&mut self, file: &VfFile) -> VfResult<()>;
131
132    fn read_impl(&mut self, request: &ReadOp) -> VfResult<ReadResult>;
133
134    fn read_into_impl(&mut self, request: &ReadOp, buffer: &mut [u8]) -> VfResult<ReadIntoResult> {
135        crate::backend::helpers::read_into_impl_default(self, request, buffer)
136    }
137
138    fn write_impl(&mut self, request: WriteOp<&VfFile, &[u8]>) -> VfResult<WriteResult>;
139
140    fn seek_impl(&mut self, file: &VfFile, position: std::io::SeekFrom) -> VfResult<u64>;
141
142    /// Query a raw backend target with the same field/symlink options used by
143    /// the application interface. Returned attributes retain target identity.
144    fn metadata_impl(
145        &mut self,
146        target: Target<'_, VfFile>,
147        options: vfsi_core::api::AttrsOptions,
148    ) -> VfResult<VfAttrs>;
149
150    /// Apply one shared attribute operation. Raw timestamps and masks are
151    /// converted by the backend, not exposed through a second mutation type.
152    fn set_attributes_impl(&mut self, update: &SetAttrsOp<Target<'_, VfFile>>) -> VfResult<()>;
153
154    /// Borrow an ordered batch without transferring request ownership.
155    /// Each operation carries its own final-symlink policy; native backends
156    /// batch contiguous equal-policy runs and validate all inputs before I/O.
157    fn vsetattrs_impl(&mut self, updates: &[SetAttrsOp<Target<'_, VfFile>>]) -> VfResult<()> {
158        crate::backend::helpers::vsetattrs_impl_default(self, updates)
159    }
160}
161
162/// Native vector engines and backend workflow overrides.
163///
164/// Vector replies preserve input order and cardinality. Indexed failures may
165/// follow partial effects; mutations do not promise rollback or safe replay.
166/// Optional operations report `Unsupported` and capability bits conservatively.
167/// Default workflows call shared helpers; native overrides retain batching,
168/// retained identity, resource limits, and protocol recovery behavior.
169///
170/// This trait is object-safe for C/Python dispatch. No blanket implementation
171/// synthesizes a complete backend from scalar methods.
172pub trait VectorBackend: HandleBackend {
173    // Vector I/O and strict opens.
174    fn vread_impl(&mut self, reads: &[ReadOp]) -> VfResult<Vec<ReadResult>>;
175
176    fn vread_into_impl(
177        &mut self,
178        reads: &[ReadOp],
179        buffers: &mut [&mut [u8]],
180    ) -> VfResult<Vec<ReadIntoResult>> {
181        crate::backend::helpers::vread_into_impl_default(self, reads, buffers)
182    }
183    /// Execute a borrowed ordered vector. Payloads and target storage remain
184    /// with the caller; implementations must not retain them after returning.
185    fn vwrite_impl(&mut self, writes: &[WriteOp<&VfFile, &[u8]>]) -> VfResult<Vec<WriteResult>> {
186        let _ = writes;
187        Err(VfError::unsupported(0))
188    }
189
190    /// Indexed partial outcomes for strict-open collection and cleanup.
191    /// This internal ownership seam is distinct from the strict typed boundary.
192    #[doc(hidden)]
193    fn vopen_outcomes_impl(
194        &mut self,
195        paths: &[&Path],
196        flags: &[i32],
197        modes: &[u32],
198    ) -> VfResult<ManyResults<VfFile>> {
199        crate::backend::helpers::vopen_outcomes_impl_default(self, paths, flags, modes)
200    }
201
202    fn before_open_cleanup(&mut self, _index: usize, _file: &VfFile) -> VfResult<()> {
203        crate::backend::helpers::before_open_cleanup_default(self, _index, _file)
204    }
205
206    fn vopen_raw_impl(
207        &mut self,
208        paths: &[&Path],
209        flags: &[i32],
210        modes: &[u32],
211    ) -> VfResult<Vec<VfFile>> {
212        crate::backend::helpers::vopen_raw_impl_default(self, paths, flags, modes)
213    }
214
215    fn vopen_raw_simple_impl(
216        &mut self,
217        paths: &[&Path],
218        flags: i32,
219        mode: u32,
220    ) -> VfResult<Vec<VfFile>> {
221        crate::backend::helpers::vopen_raw_simple_impl_default(self, paths, flags, mode)
222    }
223
224    fn vclose_impl(&mut self, files: &[VfFile]) -> VfRes {
225        crate::backend::helpers::vclose_impl_default(self, files)
226    }
227
228    /// Open every typed request or return an error, cleaning confirmed handles.
229    /// Creation and truncation effects are not rolled back.
230    fn vopen_impl(&mut self, requests: &[OpenOp]) -> VfResult<Vec<VfFile>> {
231        crate::backend::helpers::vopen_typed_default(self, requests)
232    }
233
234    // Path metadata and vector attribute engines.
235    fn vgetattrs_impl(&mut self, attrs: &mut [VfAttrs]) -> VfRes {
236        let _ = (attrs,);
237        Err(VfError::unsupported(0))
238    }
239
240    fn vgetattrs_nofollow_impl(&mut self, attrs: &mut [VfAttrs]) -> VfRes {
241        let _ = (attrs,);
242        Err(VfError::unsupported(0))
243    }
244
245    fn vsetattrs_raw_impl(&mut self, attrs: &[VfAttrs]) -> VfRes {
246        let _ = (attrs,);
247        Err(VfError::unsupported(0))
248    }
249
250    fn vsetattrs_raw_nofollow_impl(&mut self, attrs: &[VfAttrs]) -> VfRes {
251        let _ = (attrs,);
252        Err(VfError::unsupported(0))
253    }
254
255    fn stat_impl(&mut self, path: &Path) -> VfResult<VfAttrs> {
256        crate::backend::helpers::stat_impl_default(self, path)
257    }
258
259    fn lstat_impl(&mut self, path: &Path) -> VfResult<VfAttrs> {
260        crate::backend::helpers::lstat_impl_default(self, path)
261    }
262
263    fn fstat_impl(&mut self, tcf: &VfFile) -> VfResult<VfAttrs> {
264        crate::backend::helpers::fstat_impl_default(self, tcf)
265    }
266
267    fn exists_impl(&mut self, path: &Path) -> VfResult<bool> {
268        crate::backend::helpers::exists_impl_default(self, path)
269    }
270
271    fn file_type_impl(&mut self, path: &Path) -> VfResult<VfType> {
272        crate::backend::helpers::file_type_impl_default(self, path)
273    }
274
275    fn metadata_path_impl(&mut self, path: &std::path::Path, follow: bool) -> VfResult<Attrs> {
276        crate::backend::helpers::native_metadata_path_impl_default(self, path, follow)
277    }
278
279    fn set_metadata_path_impl(&mut self, op: &SetAttrsOp<&std::path::Path>) -> VfResult<()> {
280        crate::backend::helpers::native_set_metadata_path_impl_default(self, op)
281    }
282
283    // Paged directory enumeration.
284    fn listdir_impl(
285        &mut self,
286        dir: &Path,
287        masks: AttrMask,
288        max_count: usize,
289        recursive: bool,
290    ) -> VfResult<Vec<VfAttrs>> {
291        let _ = (dir, masks, max_count, recursive);
292        Err(VfError::unsupported(0))
293    }
294
295    /// False requires resolving every component without following symlinks;
296    /// validate-and-then-follow is not sufficient. Continuations retain the
297    /// originally opened directory. Unsupported guarantees must fail closed.
298    fn listdir_page_impl(
299        &mut self,
300        dir: &Path,
301        masks: AttrMask,
302        cursor: Option<DirPageCursor>,
303        page_size: usize,
304        max_entries: usize,
305        follow_symlinks: bool,
306    ) -> VfResult<(Vec<VfAttrs>, Option<DirPageCursor>)> {
307        crate::backend::helpers::listdir_page_impl_default(
308            self,
309            dir,
310            masks,
311            cursor,
312            page_size,
313            max_entries,
314            follow_symlinks,
315        )
316    }
317
318    fn directory_page_batch_size(&self) -> usize {
319        crate::backend::helpers::directory_page_batch_size_default(self)
320    }
321
322    fn vlistdir_pages_impl(
323        &mut self,
324        dirs: &[&Path],
325        masks: AttrMask,
326        cursors: Vec<Option<DirPageCursor>>,
327        page_size: usize,
328        max_entries: usize,
329        follow_symlinks: bool,
330    ) -> VfResult<Vec<BackendDirectoryPage>> {
331        crate::backend::helpers::vlistdir_pages_impl_default(
332            self,
333            dirs,
334            masks,
335            cursors,
336            page_size,
337            max_entries,
338            follow_symlinks,
339        )
340    }
341
342    fn create_dir_impl(&mut self, path: &std::path::Path, mode: u32) -> VfResult<()> {
343        crate::backend::helpers::native_create_dir_impl_default(self, path, mode)
344    }
345
346    fn read_dir_impl(
347        &mut self,
348        path: &std::path::Path,
349        options: ListDirOptions,
350    ) -> VfResult<Vec<DirEntry>> {
351        crate::backend::helpers::native_read_dir_impl_default(self, path, options)
352    }
353
354    /// Adapt full-metadata paging through the field-aware hook below.
355    fn read_dir_page_impl(
356        &mut self,
357        path: &std::path::Path,
358        cursor: Option<DirPageCursor>,
359        page_size: usize,
360        max_entries: usize,
361    ) -> VfResult<(Vec<DirEntry>, Option<DirPageCursor>)> {
362        crate::backend::helpers::native_read_dir_page_impl_default(
363            self,
364            path,
365            cursor,
366            page_size,
367            max_entries,
368        )
369    }
370
371    /// Adapt native attribute pages without materializing a full listing.
372    /// Specialized owned-page implementations should override this hook;
373    /// `read_dir_page_impl` forwards here with the full metadata mask.
374    fn read_dir_page_with_fields_impl(
375        &mut self,
376        path: &std::path::Path,
377        fields: AttrMask,
378        cursor: Option<DirPageCursor>,
379        page_size: usize,
380        max_entries: usize,
381    ) -> VfResult<(Vec<DirEntry>, Option<DirPageCursor>)> {
382        crate::backend::helpers::native_read_dir_page_with_fields_impl_default(
383            self,
384            path,
385            fields,
386            cursor,
387            page_size,
388            max_entries,
389        )
390    }
391
392    // Traversal workflows; overrides retain native batches and anchored seeds.
393    fn walk_impl(
394        &mut self,
395        root: &Path,
396        masks: AttrMask,
397        sort: &mut dyn FnMut(&Path, &mut Vec<VfAttrs>),
398    ) -> VfResult<Vec<WalkEntry>> {
399        crate::backend::helpers::walk_impl_default(self, root, masks, sort)
400    }
401
402    fn walk_with_options_impl(
403        &mut self,
404        root: &Path,
405        masks: AttrMask,
406        options: ListDirOptions,
407        sort: &mut dyn FnMut(&Path, &mut Vec<VfAttrs>),
408    ) -> VfResult<Vec<WalkEntry>> {
409        crate::backend::helpers::walk_with_options_impl_default(self, root, masks, options, sort)
410    }
411
412    fn vlistdirs_impl(
413        &mut self,
414        dirs: &[&Path],
415        masks: AttrMask,
416        max_entries: usize,
417        recursive: bool,
418        cb: &mut dyn FnMut(&VfAttrs, &Path) -> bool,
419    ) -> VfRes {
420        crate::backend::helpers::vlistdirs_impl_default(
421            self,
422            dirs,
423            masks,
424            max_entries,
425            recursive,
426            cb,
427        )
428    }
429
430    fn visit_dir_impl(
431        &mut self,
432        dir: &Path,
433        masks: AttrMask,
434        max_entries: usize,
435        cb: &mut dyn FnMut(&VfAttrs) -> bool,
436    ) -> VfRes {
437        crate::backend::helpers::visit_dir_impl_default(self, dir, masks, max_entries, cb)
438    }
439
440    // Namespace mutations and scalar adapters.
441    fn vrename_impl(&mut self, pairs: &[(VfFile, VfFile)]) -> VfRes {
442        let _ = (pairs,);
443        Err(VfError::unsupported(0))
444    }
445
446    /// Native atomic rename policy; never emulate no-replace with an existence check.
447    fn vrename_with_options_impl(
448        &mut self,
449        pairs: &[(VfFile, VfFile)],
450        options: vfsi_core::api::RenameOptions,
451    ) -> VfRes {
452        match options {
453            vfsi_core::api::RenameOptions::Replace => self.vrename_impl(pairs),
454            vfsi_core::api::RenameOptions::NoReplace | vfsi_core::api::RenameOptions::Exchange
455                if pairs.is_empty() =>
456            {
457                Ok(())
458            }
459            vfsi_core::api::RenameOptions::NoReplace | vfsi_core::api::RenameOptions::Exchange => {
460                Err(VfError::client(0, vfsi_core::VF_ERR_UNSUPPORTED))
461            }
462        }
463    }
464
465    fn vremove_impl(&mut self, files: &[VfFile]) -> VfRes {
466        let _ = (files,);
467        Err(VfError::unsupported(0))
468    }
469
470    fn vmkdir_impl(&mut self, dirs: &[VfAttrs]) -> VfRes {
471        let _ = (dirs,);
472        Err(VfError::unsupported(0))
473    }
474
475    fn unlink_impl(&mut self, pathname: &Path) -> VfResult<()> {
476        crate::backend::helpers::unlink_impl_default(self, pathname)
477    }
478
479    fn vunlink_impl(&mut self, pathnames: &[&Path]) -> VfRes {
480        crate::backend::helpers::vunlink_impl_default(self, pathnames)
481    }
482
483    fn mkdir_raw_impl(&mut self, path: &Path, mode: u32) -> VfResult<()> {
484        crate::backend::helpers::mkdir_raw_impl_default(self, path, mode)
485    }
486
487    fn ensure_dir_impl(&mut self, dir: &Path, mode: u32) -> VfResult<()> {
488        crate::backend::helpers::ensure_dir_impl_default(self, dir, mode)
489    }
490
491    fn remove_impl(&mut self, path: &std::path::Path, recursive: bool) -> VfResult<()> {
492        crate::backend::helpers::native_remove_impl_default(self, path, recursive)
493    }
494
495    fn remove_dir_contents_impl(&mut self, path: &std::path::Path) -> VfResult<()> {
496        crate::backend::helpers::native_remove_dir_contents_impl_default(self, path)
497    }
498
499    fn rename_impl(&mut self, from: &std::path::Path, to: &std::path::Path) -> VfResult<()> {
500        crate::backend::helpers::native_rename_impl_default(self, from, to)
501    }
502
503    // Links.
504    fn vsymlink_impl(&mut self, oldpaths: &[&Path], newpaths: &[&Path]) -> VfRes {
505        let _ = (oldpaths, newpaths);
506        Err(VfError::unsupported(0))
507    }
508
509    fn vreadlink_impl(&mut self, paths: &[&Path]) -> VfResult<Vec<Vec<u8>>> {
510        let _ = (paths,);
511        Err(VfError::unsupported(0))
512    }
513
514    fn vhardlink_impl(&mut self, oldpaths: &[&Path], newpaths: &[&Path]) -> VfRes {
515        let _ = (oldpaths, newpaths);
516        Err(VfError::unsupported(0))
517    }
518
519    fn symlink_raw_impl(&mut self, oldpath: &Path, newpath: &Path) -> VfResult<()> {
520        crate::backend::helpers::symlink_raw_impl_default(self, oldpath, newpath)
521    }
522
523    fn readlink_raw_impl(&mut self, path: &Path) -> VfResult<Vec<u8>> {
524        crate::backend::helpers::readlink_raw_impl_default(self, path)
525    }
526
527    fn symlink_impl(&mut self, target: &std::path::Path, link: &std::path::Path) -> VfResult<()> {
528        crate::backend::helpers::native_symlink_impl_default(self, target, link)
529    }
530
531    fn hard_link_impl(&mut self, source: &std::path::Path, link: &std::path::Path) -> VfResult<()> {
532        crate::backend::helpers::native_hard_link_impl_default(self, source, link)
533    }
534
535    fn read_link_impl(&mut self, path: &std::path::Path) -> VfResult<std::path::PathBuf> {
536        crate::backend::helpers::native_read_link_impl_default(self, path)
537    }
538
539    // Extent and tree copy.
540    fn vcopy_data_impl(&mut self, pairs: &[ExtentPair]) -> VfRes {
541        let _ = (pairs,);
542        Err(VfError::unsupported(0))
543    }
544
545    fn vcopy_impl(&mut self, pairs: &[ExtentPair], options: CopyOption) -> VfRes {
546        crate::backend::helpers::vcopy_impl_default(self, pairs, options)
547    }
548
549    fn copy_tree_impl(
550        &mut self,
551        src_dir: &Path,
552        dst: &Path,
553        symlinks: bool,
554        use_server_side_copy: bool,
555    ) -> VfRes {
556        let _ = (src_dir, dst, symlinks, use_server_side_copy);
557        Err(VfError::unsupported(0))
558    }
559
560    // Bounded whole-file reads and streams.
561    fn vread_all_impl(&mut self, files: &[VfFile]) -> VfResult<Vec<Vec<u8>>> {
562        crate::backend::helpers::vread_all_impl_default(self, files)
563    }
564
565    fn vread_all_with_options_impl(
566        &mut self,
567        files: &[VfFile],
568        options: ReadAllOptions,
569    ) -> VfResult<Vec<Vec<u8>>> {
570        crate::backend::helpers::vread_all_with_options_impl_default(self, files, options)
571    }
572
573    fn vstream_impl(
574        &mut self,
575        files: &[VfFile],
576        chunk_size: usize,
577        memory_limit: usize,
578        cb: &mut ReadStreamCallback<'_>,
579    ) -> VfRes {
580        crate::backend::helpers::vstream_impl_default(self, files, chunk_size, memory_limit, cb)
581    }
582
583    // Recursive removal and retained directory lifecycle.
584    fn before_remove_type(&mut self, _index: usize) -> VfResult<()> {
585        crate::backend::helpers::before_remove_type_default(self, _index)
586    }
587
588    fn remove_paths_impl(&mut self, objs: &[&Path], recursive: bool) -> VfRes {
589        crate::backend::helpers::remove_paths_impl_default(self, objs, recursive)
590    }
591
592    fn remove_paths_with_options_impl(
593        &mut self,
594        objs: &[&Path],
595        recursive: bool,
596        options: RemoveOptions,
597    ) -> VfRes {
598        crate::backend::helpers::remove_paths_with_options_impl_default(
599            self, objs, recursive, options,
600        )
601    }
602
603    fn open_dir_impl(&mut self, path: &Path) -> VfResult<VfDir> {
604        crate::backend::helpers::open_dir_impl_default(self, path)
605    }
606
607    fn remove_dir_contents_handle_impl(&mut self, dir: &VfDir) -> VfRes {
608        crate::backend::helpers::remove_dir_contents_handle_impl_default(self, dir)
609    }
610
611    fn remove_dir_contents_handle_with_options_impl(
612        &mut self,
613        dir: &VfDir,
614        options: RemoveOptions,
615    ) -> VfRes {
616        crate::backend::helpers::remove_dir_contents_handle_with_options_impl_default(
617            self, dir, options,
618        )
619    }
620
621    fn close_dir_impl(&mut self, _dir: &VfDir) -> VfResult<()> {
622        crate::backend::helpers::close_dir_impl_default(self, _dir)
623    }
624
625    fn remove_dir_contents_path_impl(&mut self, dir: &Path) -> VfRes {
626        crate::backend::helpers::remove_dir_contents_path_impl_default(self, dir)
627    }
628
629    fn remove_dir_contents_path_with_options_impl(
630        &mut self,
631        dir: &Path,
632        options: RemoveOptions,
633    ) -> VfRes {
634        crate::backend::helpers::remove_dir_contents_path_with_options_impl_default(
635            self, dir, options,
636        )
637    }
638
639    fn ensure_empty_dir_impl(&mut self, dir: &Path) -> VfRes {
640        crate::backend::helpers::ensure_empty_dir_impl_default(self, dir)
641    }
642
643    // Optional application-data-block writes.
644    fn vwrite_adb_impl(&mut self, patterns: &[Adb]) -> VfResult<Vec<usize>> {
645        let _ = (patterns,);
646        Err(VfError::unsupported(0))
647    }
648}
649pub(crate) fn metadata_mask() -> AttrMask {
650    AttrMask::MODE
651        | AttrMask::SIZE
652        | AttrMask::NLINK
653        | AttrMask::FILEID
654        | AttrMask::UID
655        | AttrMask::GID
656        | AttrMask::ATIME
657        | AttrMask::MTIME
658        | AttrMask::CTIME
659        | AttrMask::CHANGE
660}
661
662pub(crate) fn system_time_parts(time: std::time::SystemTime) -> VfResult<(i64, u32)> {
663    match time.duration_since(std::time::UNIX_EPOCH) {
664        Ok(duration) => Ok((
665            i64::try_from(duration.as_secs())
666                .map_err(|_| VfError::client(0, libc::EOVERFLOW as u32))?,
667            duration.subsec_nanos(),
668        )),
669        Err(error) => {
670            let duration = error.duration();
671            let seconds = i64::try_from(duration.as_secs())
672                .map_err(|_| VfError::client(0, libc::EOVERFLOW as u32))?;
673            if duration.subsec_nanos() == 0 {
674                Ok((-seconds, 0))
675            } else {
676                let seconds = seconds
677                    .checked_add(1)
678                    .ok_or_else(|| VfError::client(0, libc::EOVERFLOW as u32))?;
679                Ok((-seconds, 1_000_000_000 - duration.subsec_nanos()))
680            }
681        }
682    }
683}
684#[cfg(unix)]
685pub(crate) fn bytes_to_path(bytes: Vec<u8>) -> PathBuf {
686    use std::os::unix::ffi::OsStringExt;
687    std::ffi::OsString::from_vec(bytes).into()
688}
689#[cfg(not(unix))]
690pub(crate) fn bytes_to_path(bytes: Vec<u8>) -> PathBuf {
691    String::from_utf8_lossy(&bytes).into_owned().into()
692}
693pub(crate) fn translate_open_flags(requests: &[OpenOp]) -> VfResult<Vec<i32>> {
694    requests
695        .iter()
696        .enumerate()
697        .map(|(index, request)| {
698            vfsi_core::open_flags_to_libc(request.flags()).map_err(|error| error.with_index(index))
699        })
700        .collect()
701}