Skip to main content

vfsi_sync/
native.rs

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