1use std::fmt;
4use std::io::{self, Read, Seek, SeekFrom as IoSeekFrom, Write};
5use std::path::{Component, Path, PathBuf};
6use std::sync::{Arc, Mutex};
7use std::time::SystemTime;
8
9use crate::traits::{validate_read_into_results, validate_read_results, validate_write_results};
10use crate::{
11 AttrMask, Capabilities, CopyFileSystem, DEFAULT_READ_MAX_BYTES, DirEntry, DirectoryFileSystem,
12 FileSystem, LinkFileSystem, Metadata, MetadataFileSystem, MetadataQuery, MetadataUpdate,
13 NamespaceFileSystem, OpenFlags, OpenRequest, Permissions, ReadDirOptions, ReadOp, ReadResult,
14 ReadStreamOptions, SetAttributes, VecFs, VectorFileSystem, VfDir, VfError, VfFile, VfOffset,
15 VfResult, WriteOpRef, WriteResult,
16};
17
18fn io_error(error: VfError) -> io::Error {
19 error.into()
20}
21
22fn poisoned() -> VfError {
23 VfError::client(0, crate::ERR_IO)
24}
25
26fn wrong_result_count(operation: &str, expected: usize, actual: usize) -> VfError {
27 VfError::transport(
28 None,
29 format!("{operation} backend returned {actual} results for {expected} requests"),
30 )
31}
32
33pub struct FsClient<F> {
35 inner: Arc<Mutex<F>>,
36}
37
38impl<F> Clone for FsClient<F> {
39 fn clone(&self) -> Self {
40 Self {
41 inner: Arc::clone(&self.inner),
42 }
43 }
44}
45
46impl<F> fmt::Debug for FsClient<F> {
47 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
48 formatter.debug_struct("FsClient").finish_non_exhaustive()
49 }
50}
51
52impl<F> FsClient<F> {
53 pub fn new(filesystem: F) -> Self {
54 Self {
55 inner: Arc::new(Mutex::new(filesystem)),
56 }
57 }
58
59 fn lock(&self) -> VfResult<std::sync::MutexGuard<'_, F>> {
60 self.inner.lock().map_err(|_| poisoned())
61 }
62
63 pub fn into_inner(self) -> Result<F, Self> {
64 match Arc::try_unwrap(self.inner) {
65 Ok(mutex) => match mutex.into_inner() {
66 Ok(filesystem) => Ok(filesystem),
67 Err(poisoned) => Ok(poisoned.into_inner()),
68 },
69 Err(inner) => Err(Self { inner }),
70 }
71 }
72}
73
74impl<F: FileSystem> FsClient<F> {
75 pub fn open(&self, path: impl AsRef<Path>) -> VfResult<FsFile<F>> {
77 self.open_with(OpenRequest::new(path.as_ref(), OpenFlags::READ))
78 }
79
80 pub fn open_with(&self, request: OpenRequest) -> VfResult<FsFile<F>> {
81 let file = self.lock()?.open_one(&request)?;
82 Ok(FsFile {
83 inner: Arc::clone(&self.inner),
84 file: Some(file),
85 path: request.path,
86 })
87 }
88
89 pub fn open_options(&self) -> OpenOptions<'_, F> {
90 OpenOptions::new(self)
91 }
92
93 pub fn create(&self, path: impl AsRef<Path>) -> VfResult<FsFile<F>> {
94 self.open_with(OpenRequest::new(
95 path.as_ref(),
96 OpenFlags::WRITE | OpenFlags::CREATE | OpenFlags::TRUNCATE,
97 ))
98 }
99
100 pub fn read(&self, path: impl AsRef<Path>) -> VfResult<Vec<u8>> {
101 self.read_with_limit(path, DEFAULT_READ_MAX_BYTES)
102 }
103
104 pub fn read_with_limit(&self, path: impl AsRef<Path>, max_bytes: usize) -> VfResult<Vec<u8>> {
109 let path = path.as_ref();
110 let mut file = self.open(path)?;
111 let mut output = Vec::new();
112 let mut chunk = vec![0; 64 * 1024];
113 loop {
114 let remaining = max_bytes.saturating_sub(output.len());
115 let request = if remaining == 0 {
116 1
117 } else {
118 remaining.min(chunk.len())
119 };
120 let read = file.read_native(&mut chunk[..request])?;
121 if read == 0 {
122 break;
123 }
124 if read > remaining {
125 return Err(VfError::failure(0, libc::EFBIG as u32).with_context("read", path));
126 }
127 output.extend_from_slice(&chunk[..read]);
128 }
129 file.close()?;
130 Ok(output)
131 }
132
133 pub fn read_to_string(&self, path: impl AsRef<Path>) -> VfResult<String> {
134 self.read_to_string_with_limit(path, DEFAULT_READ_MAX_BYTES)
135 }
136
137 pub fn read_to_string_with_limit(
139 &self,
140 path: impl AsRef<Path>,
141 max_bytes: usize,
142 ) -> VfResult<String> {
143 let path = path.as_ref();
144 String::from_utf8(self.read_with_limit(path, max_bytes)?)
145 .map_err(|_| VfError::client(0, crate::ERR_INVAL).with_context("read_to_string", path))
146 }
147
148 pub fn write(&self, path: impl AsRef<Path>, data: &[u8]) -> VfResult<()> {
149 let path = path.as_ref();
150 let mut file = self.create(path)?;
151 let mut written = 0;
152 while written < data.len() {
153 let count = file.write_native(&data[written..])?;
154 if count == 0 {
155 return Err(VfError::client(0, crate::ERR_IO).with_context("write", path));
156 }
157 written += count;
158 }
159 file.close()
160 }
161}
162
163impl<F: FileSystem> FsClient<F> {
164 pub fn read_stream(
172 &self,
173 path: impl AsRef<Path>,
174 callback: impl FnMut(u64, &[u8]) -> VfResult<bool>,
175 ) -> VfResult<()> {
176 self.read_stream_with_options(path, ReadStreamOptions::default(), callback)
177 }
178
179 pub fn read_stream_with_options(
181 &self,
182 path: impl AsRef<Path>,
183 options: ReadStreamOptions,
184 mut callback: impl FnMut(u64, &[u8]) -> VfResult<bool>,
185 ) -> VfResult<()> {
186 let chunk_size = options.chunk_size_bytes();
187 if chunk_size == 0 {
188 return Err(VfError::failure(0, crate::ERR_INVAL));
189 }
190
191 let file = self.open(path)?;
192 let raw_file = file.raw()?.clone();
193 let operation = (|| -> VfResult<()> {
194 let mut offset = 0u64;
195 loop {
196 let request = ReadOp::at(raw_file.clone(), offset, chunk_size);
197 let result = {
198 let mut backend = self.lock()?;
199 let result = backend.read_one(&request)?;
200 validate_read_results(
201 "read_stream",
202 std::slice::from_ref(&request),
203 std::slice::from_ref(&result),
204 )?;
205 result
206 };
207 let length = result.data.len();
208 if !result.data.is_empty() && !callback(offset, &result.data)? {
209 return Ok(());
210 }
211 if result.eof {
212 return Ok(());
213 }
214 offset = offset
215 .checked_add(length as u64)
216 .ok_or_else(|| VfError::client(0, libc::EOVERFLOW as u32))?;
217 }
218 })();
219 let close = file.close();
220 match operation {
221 Err(error) => Err(error),
222 Ok(()) => close,
223 }
224 }
225}
226
227impl<F: MetadataFileSystem> FsClient<F> {
228 pub fn metadata(&self, path: impl AsRef<Path>) -> VfResult<Metadata> {
229 self.lock()?.metadata_path(path.as_ref(), true)
230 }
231
232 pub fn symlink_metadata(&self, path: impl AsRef<Path>) -> VfResult<Metadata> {
233 self.lock()?.metadata_path(path.as_ref(), false)
234 }
235
236 pub fn set_metadata(&self, path: impl AsRef<Path>) -> SetMetadata<'_, F> {
237 SetMetadata {
238 client: self,
239 path: path.as_ref().to_path_buf(),
240 update: MetadataUpdate::new(),
241 follow: true,
242 }
243 }
244}
245
246impl<F: DirectoryFileSystem> FsClient<F> {
247 pub fn create_dir(&self, path: impl AsRef<Path>) -> VfResult<()> {
248 self.create_dir_with_mode(path, 0o777)
249 }
250
251 pub fn create_dir_with_mode(&self, path: impl AsRef<Path>, mode: u32) -> VfResult<()> {
252 self.lock()?.create_dir_one(path.as_ref(), mode)
253 }
254
255 pub fn read_dir(&self, path: impl AsRef<Path>) -> VfResult<Vec<DirEntry>> {
256 self.read_dir_with_options(path, ReadDirOptions::default())
257 }
258
259 pub fn read_dir_with_options(
261 &self,
262 path: impl AsRef<Path>,
263 options: ReadDirOptions,
264 ) -> VfResult<Vec<DirEntry>> {
265 self.lock()?.read_dir_one(path.as_ref(), options)
266 }
267}
268
269impl<F: DirectoryFileSystem + MetadataFileSystem> FsClient<F> {
270 pub fn create_dir_all(&self, path: impl AsRef<Path>) -> VfResult<()> {
271 let path = path.as_ref();
272 let mut current = PathBuf::new();
273 for component in path.components() {
274 match component {
275 Component::RootDir => {
276 current.push(Path::new("/"));
277 continue;
278 }
279 Component::Normal(part) => current.push(part),
280 Component::CurDir => continue,
281 Component::ParentDir => {
282 current.push("..");
287 continue;
288 }
289 Component::Prefix(_) => return Err(VfError::client(0, crate::ERR_INVAL)),
290 }
291 match self.create_dir(¤t) {
292 Ok(()) => {}
293 Err(error) if error.err_no() == crate::ERR_EXIST => {
294 if !self.metadata(¤t)?.is_dir() {
295 return Err(VfError::client(0, crate::ERR_NOTDIR)
296 .with_context("create_dir_all", ¤t));
297 }
298 }
299 Err(error) => return Err(error),
300 }
301 }
302 Ok(())
303 }
304}
305
306impl<F: NamespaceFileSystem + MetadataFileSystem> FsClient<F> {
307 fn removal_metadata(&self, path: &Path, operation: &'static str) -> VfResult<Metadata> {
308 let mut filesystem = self.lock()?;
309 let follow = !filesystem.capabilities().contains(Capabilities::LSTAT);
310 filesystem
311 .metadata_path(path, follow)
312 .map_err(|error| error.with_context(operation, path))
313 }
314
315 pub fn remove_file(&self, path: impl AsRef<Path>) -> VfResult<()> {
316 let path = path.as_ref();
317 if self.removal_metadata(path, "remove_file")?.is_dir() {
318 return Err(VfError::client(0, crate::ERR_ISDIR).with_context("remove_file", path));
319 }
320 self.lock()?.remove_one(path, false)
321 }
322
323 pub fn remove_dir(&self, path: impl AsRef<Path>) -> VfResult<()> {
324 let path = path.as_ref();
325 if !self.removal_metadata(path, "remove_dir")?.is_dir() {
326 return Err(VfError::client(0, crate::ERR_NOTDIR).with_context("remove_dir", path));
327 }
328 self.lock()?.remove_one(path, false)
329 }
330
331 pub fn remove_dir_all(&self, path: impl AsRef<Path>) -> VfResult<()> {
332 let path = path.as_ref();
333 if !self.removal_metadata(path, "remove_dir_all")?.is_dir() {
334 return Err(VfError::client(0, crate::ERR_NOTDIR).with_context("remove_dir_all", path));
335 }
336 self.lock()?.remove_one(path, true)
337 }
338
339 pub fn remove_dir_contents(&self, path: impl AsRef<Path>) -> VfResult<()> {
341 let path = path.as_ref();
342 if !self.removal_metadata(path, "remove_dir_contents")?.is_dir() {
343 return Err(
344 VfError::client(0, crate::ERR_NOTDIR).with_context("remove_dir_contents", path)
345 );
346 }
347 self.lock()?.remove_dir_contents(path)
348 }
349
350 pub fn rename(&self, from: impl AsRef<Path>, to: impl AsRef<Path>) -> VfResult<()> {
351 self.lock()?.rename_one(from.as_ref(), to.as_ref())
352 }
353}
354
355impl<F: VecFs> FsClient<F> {
356 pub fn ensure_empty_dir(&self, path: impl AsRef<Path>) -> VfResult<()> {
359 self.lock()?.ensure_empty_dir(path.as_ref())
360 }
361
362 pub fn open_dir(&self, path: impl AsRef<Path>) -> VfResult<VfDir> {
366 self.lock()?.open_dir(path.as_ref())
367 }
368
369 pub fn remove_dir_contents_handle(&self, dir: &VfDir) -> VfResult<()> {
371 self.lock()?.rm_dir_contents(dir)
372 }
373
374 pub fn close_dir(&self, dir: &VfDir) -> VfResult<()> {
376 self.lock()?.close_dir(dir)
377 }
378}
379
380impl<F: LinkFileSystem> FsClient<F> {
381 pub fn symlink(&self, target: impl AsRef<Path>, link: impl AsRef<Path>) -> VfResult<()> {
382 self.lock()?.symlink_one(target.as_ref(), link.as_ref())
383 }
384
385 pub fn hard_link(&self, source: impl AsRef<Path>, link: impl AsRef<Path>) -> VfResult<()> {
386 self.lock()?.hard_link_one(source.as_ref(), link.as_ref())
387 }
388
389 pub fn read_link(&self, path: impl AsRef<Path>) -> VfResult<PathBuf> {
390 self.lock()?.read_link_one(path.as_ref())
391 }
392}
393
394impl<F: CopyFileSystem> FsClient<F> {
395 pub fn copy(&self, source: impl AsRef<Path>, destination: impl AsRef<Path>) -> VfResult<()> {
396 self.lock()?.copy_one(source.as_ref(), destination.as_ref())
397 }
398}
399
400impl<F: VecFs> FsClient<F> {
401 pub fn symlink_metadatav(&self, paths: &[&Path]) -> VfResult<Vec<Metadata>> {
404 let mut attrs: Vec<_> = paths
405 .iter()
406 .map(|path| crate::VfAttrs {
407 file: VfFile::from_os_path(path),
408 masks: AttrMask::MODE,
409 ..crate::VfAttrs::default()
410 })
411 .collect();
412 self.lock()?.lgetattrsv(&mut attrs).map_err(|error| {
413 error
414 .index_opt()
415 .and_then(|index| paths.get(index))
416 .map_or(error.clone(), |path| {
417 error.with_context("symlink_metadatav", path)
418 })
419 })?;
420 Ok(attrs.into_iter().map(Metadata::from).collect())
421 }
422}
423
424impl<F: VectorFileSystem> FsClient<F> {
425 pub fn openv(&self, requests: &[OpenRequest]) -> VfResult<Vec<FsFile<F>>> {
431 let mut filesystem = self.lock()?;
432 let files = filesystem.open_many(requests).map_err(|error| {
433 error
434 .index_opt()
435 .and_then(|index| requests.get(index))
436 .map_or(error.clone(), |request| {
437 error.with_context("openv", &request.path)
438 })
439 })?;
440 if files.len() != requests.len() {
441 let error = wrong_result_count("openv", requests.len(), files.len());
442 for file in &files {
443 let _ = filesystem.close_one(file);
444 }
445 return Err(error);
446 }
447 drop(filesystem);
448 Ok(files
449 .into_iter()
450 .zip(requests)
451 .map(|(file, request)| FsFile {
452 inner: Arc::clone(&self.inner),
453 file: Some(file),
454 path: request.path.clone(),
455 })
456 .collect())
457 }
458
459 pub fn closev(&self, mut files: Vec<FsFile<F>>) -> VfResult<()> {
465 for (index, file) in files.iter().enumerate() {
466 self.validate_owner(file, index)?;
467 }
468 let descriptors: Vec<VfFile> = files
469 .iter()
470 .map(|file| file.raw().cloned())
471 .collect::<VfResult<_>>()?;
472 self.lock()?.close_many(&descriptors).map_err(|error| {
473 error
474 .index_opt()
475 .and_then(|index| files.get(index))
476 .map_or(error.clone(), |file| {
477 error.with_context("closev", file.path())
478 })
479 })?;
480 for file in &mut files {
481 file.file = None;
482 }
483 Ok(())
484 }
485
486 pub fn readv(&self, requests: &[FsRead<'_, F>]) -> VfResult<Vec<ReadResult>> {
487 let reads = self.read_ops(requests)?;
488 let results = self.lock()?.read_many(&reads).map_err(|error| {
489 error
490 .index_opt()
491 .and_then(|index| requests.get(index))
492 .map_or(error.clone(), |request| {
493 error.with_context("readv", request.file.path())
494 })
495 })?;
496 if results.len() != requests.len() {
497 return Err(wrong_result_count("readv", requests.len(), results.len()));
498 }
499 validate_read_results("readv", &reads, &results).map_err(|error| {
500 error
501 .index_opt()
502 .and_then(|index| requests.get(index))
503 .map_or(error.clone(), |request| {
504 error.with_context("readv", request.file.path())
505 })
506 })?;
507 Ok(results)
508 }
509
510 fn read_ops(&self, requests: &[FsRead<'_, F>]) -> VfResult<Vec<ReadOp>> {
511 let mut reads = Vec::with_capacity(requests.len());
512 for (index, request) in requests.iter().enumerate() {
513 self.validate_owner(request.file, index)?;
514 reads.push(ReadOp::new(
515 request.file.raw()?.clone(),
516 request.offset,
517 request.length,
518 ));
519 }
520 Ok(reads)
521 }
522
523 pub fn readv_into(&self, requests: &mut [FsReadInto<'_, F>]) -> VfResult<Vec<usize>> {
524 let mut reads = Vec::with_capacity(requests.len());
525 for (index, request) in requests.iter().enumerate() {
526 self.validate_owner(request.file, index)?;
527 reads.push(ReadOp::new(
528 request.file.raw()?.clone(),
529 request.offset,
530 request.buffer.len(),
531 ));
532 }
533 let results = {
534 let mut buffers: Vec<&mut [u8]> = requests
535 .iter_mut()
536 .map(|request| &mut *request.buffer)
537 .collect();
538 self.lock()?.read_many_into(&reads, &mut buffers)
539 }
540 .map_err(|error| {
541 error
542 .index_opt()
543 .and_then(|index| requests.get(index))
544 .map_or(error.clone(), |request| {
545 error.with_context("readv_into", request.file.path())
546 })
547 })?;
548 validate_read_into_results("readv_into", &reads, &results).map_err(|error| {
549 error
550 .index_opt()
551 .and_then(|index| requests.get(index))
552 .map_or(error.clone(), |request| {
553 error.with_context("readv_into", request.file.path())
554 })
555 })?;
556 Ok(results.into_iter().map(|result| result.read).collect())
557 }
558
559 pub fn writev(&self, requests: &[FsWrite<'_, F>]) -> VfResult<Vec<WriteResult>> {
560 let writes = self.write_ops(requests)?;
561 let results = self.lock()?.write_many(&writes).map_err(|error| {
562 error
563 .index_opt()
564 .and_then(|index| requests.get(index))
565 .map_or(error.clone(), |request| {
566 error.with_context("writev", request.file.path())
567 })
568 })?;
569 if results.len() != requests.len() {
570 return Err(wrong_result_count("writev", requests.len(), results.len()));
571 }
572 validate_write_results("writev", &writes, &results).map_err(|error| {
573 error
574 .index_opt()
575 .and_then(|index| requests.get(index))
576 .map_or(error.clone(), |request| {
577 error.with_context("writev", request.file.path())
578 })
579 })?;
580 Ok(results)
581 }
582
583 fn write_ops<'a>(&self, requests: &'a [FsWrite<'a, F>]) -> VfResult<Vec<WriteOpRef<'a>>> {
584 let mut writes = Vec::with_capacity(requests.len());
585 for (index, request) in requests.iter().enumerate() {
586 self.validate_owner(request.file, index)?;
587 writes.push(WriteOpRef::new(
588 request.file.raw()?,
589 request.offset,
590 request.data,
591 ));
592 }
593 Ok(writes)
594 }
595
596 fn validate_owner(&self, file: &FsFile<F>, index: usize) -> VfResult<()> {
597 if Arc::ptr_eq(&self.inner, &file.inner) {
598 Ok(())
599 } else {
600 Err(VfError::client(index, crate::ERR_INVAL))
601 }
602 }
603}
604
605pub struct OpenOptions<'a, F: FileSystem> {
607 client: &'a FsClient<F>,
608 flags: OpenFlags,
609 mode: u32,
610}
611
612impl<F: FileSystem> Clone for OpenOptions<'_, F> {
613 fn clone(&self) -> Self {
614 Self {
615 client: self.client,
616 flags: self.flags,
617 mode: self.mode,
618 }
619 }
620}
621
622impl<F: FileSystem> fmt::Debug for OpenOptions<'_, F> {
623 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
624 formatter
625 .debug_struct("OpenOptions")
626 .field("flags", &self.flags)
627 .field("mode", &format_args!("{:#o}", self.mode))
628 .finish()
629 }
630}
631
632impl<'a, F: FileSystem> OpenOptions<'a, F> {
633 fn new(client: &'a FsClient<F>) -> Self {
634 Self {
635 client,
636 flags: OpenFlags::empty(),
637 mode: 0o666,
638 }
639 }
640
641 pub fn read(&mut self, enabled: bool) -> &mut Self {
642 self.flags.set(OpenFlags::READ, enabled);
643 self
644 }
645
646 pub fn write(&mut self, enabled: bool) -> &mut Self {
647 self.flags.set(OpenFlags::WRITE, enabled);
648 self
649 }
650
651 pub fn append(&mut self, enabled: bool) -> &mut Self {
652 self.flags.set(OpenFlags::APPEND, enabled);
653 self
654 }
655
656 pub fn truncate(&mut self, enabled: bool) -> &mut Self {
657 self.flags.set(OpenFlags::TRUNCATE, enabled);
658 self
659 }
660
661 pub fn create(&mut self, enabled: bool) -> &mut Self {
662 self.flags.set(OpenFlags::CREATE, enabled);
663 self
664 }
665
666 pub fn create_new(&mut self, enabled: bool) -> &mut Self {
667 self.flags.set(OpenFlags::CREATE_NEW, enabled);
668 self
669 }
670
671 pub fn mode(&mut self, mode: u32) -> &mut Self {
672 self.mode = mode;
673 self
674 }
675
676 pub fn open(&self, path: impl AsRef<Path>) -> VfResult<FsFile<F>> {
677 self.client
678 .open_with(OpenRequest::new(path.as_ref(), self.flags).mode(self.mode))
679 }
680}
681
682impl<F: VectorFileSystem> OpenOptions<'_, F> {
683 pub fn openv<P: AsRef<Path>>(&self, paths: &[P]) -> VfResult<Vec<FsFile<F>>> {
684 let requests: Vec<OpenRequest> = paths
685 .iter()
686 .map(|path| OpenRequest::new(path.as_ref(), self.flags).mode(self.mode))
687 .collect();
688 self.client.openv(&requests)
689 }
690}
691
692pub struct SetMetadata<'a, F: MetadataFileSystem> {
694 client: &'a FsClient<F>,
695 path: PathBuf,
696 update: MetadataUpdate,
697 follow: bool,
698}
699
700impl<F: MetadataFileSystem> Clone for SetMetadata<'_, F> {
701 fn clone(&self) -> Self {
702 Self {
703 client: self.client,
704 path: self.path.clone(),
705 update: self.update.clone(),
706 follow: self.follow,
707 }
708 }
709}
710
711impl<F: MetadataFileSystem> fmt::Debug for SetMetadata<'_, F> {
712 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
713 formatter
714 .debug_struct("SetMetadata")
715 .field("path", &self.path)
716 .field("update", &self.update)
717 .field("follow", &self.follow)
718 .finish_non_exhaustive()
719 }
720}
721
722impl<F: MetadataFileSystem> SetMetadata<'_, F> {
723 pub fn permissions(&mut self, permissions: Permissions) -> &mut Self {
724 self.update.permissions = Some(permissions);
725 self
726 }
727
728 pub fn len(&mut self, len: u64) -> &mut Self {
729 self.update.len = Some(len);
730 self
731 }
732
733 pub fn accessed(&mut self, accessed: SystemTime) -> &mut Self {
734 self.update.accessed = Some(accessed);
735 self
736 }
737
738 pub fn modified(&mut self, modified: SystemTime) -> &mut Self {
739 self.update.modified = Some(modified);
740 self
741 }
742
743 pub fn follow_symlinks(&mut self, follow: bool) -> &mut Self {
744 self.follow = follow;
745 self
746 }
747
748 pub fn apply(&self) -> VfResult<()> {
749 self.client
750 .lock()?
751 .set_metadata_path(&self.path, self.update.clone(), self.follow)
752 }
753}
754
755pub struct FsFile<F: FileSystem> {
761 inner: Arc<Mutex<F>>,
762 file: Option<VfFile>,
763 path: PathBuf,
764}
765
766impl<F: FileSystem> fmt::Debug for FsFile<F> {
767 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
768 formatter
769 .debug_struct("FsFile")
770 .field("path", &self.path)
771 .field("is_open", &self.file.is_some())
772 .finish()
773 }
774}
775
776impl<F: FileSystem> FsFile<F> {
777 fn raw(&self) -> VfResult<&VfFile> {
778 self.file
779 .as_ref()
780 .ok_or_else(|| VfError::client(0, crate::ERR_EBADF))
781 }
782
783 pub fn read_at(&self, buffer: &mut [u8], offset: u64) -> VfResult<usize> {
785 self.read_into(buffer, VfOffset::At(offset))
786 }
787
788 pub fn write_at(&self, buffer: &[u8], offset: u64) -> VfResult<usize> {
790 self.write_from(buffer, VfOffset::At(offset))
791 }
792
793 pub fn read_request_at(&self, offset: u64, length: usize) -> FsRead<'_, F> {
794 FsRead {
795 file: self,
796 offset: VfOffset::At(offset),
797 length,
798 }
799 }
800
801 pub fn path(&self) -> &Path {
802 &self.path
803 }
804
805 pub fn metadata(&self) -> VfResult<Metadata> {
807 let attributes = AttrMask::MODE
808 | AttrMask::SIZE
809 | AttrMask::NLINK
810 | AttrMask::FILEID
811 | AttrMask::UID
812 | AttrMask::GID
813 | AttrMask::ATIME
814 | AttrMask::MTIME
815 | AttrMask::CTIME
816 | AttrMask::CHANGE;
817 self.inner
818 .lock()
819 .map_err(|_| poisoned())?
820 .metadata(MetadataQuery::new(self.raw()?.clone(), attributes))
821 .map(Metadata::from)
822 .map_err(|error| error.with_context("metadata", &self.path))
823 }
824
825 pub fn set_len(&self, len: u64) -> VfResult<()> {
827 let mut update = SetAttributes::new(self.raw()?.clone());
828 update.size = Some(len);
829 self.inner
830 .lock()
831 .map_err(|_| poisoned())?
832 .set_attributes(update)
833 .map_err(|error| error.with_context("set_len", &self.path))
834 }
835
836 pub fn set_permissions(&self, permissions: Permissions) -> VfResult<()> {
838 let mut update = SetAttributes::new(self.raw()?.clone());
839 update.mode = Some(permissions.mode());
840 self.inner
841 .lock()
842 .map_err(|_| poisoned())?
843 .set_attributes(update)
844 .map_err(|error| error.with_context("set_permissions", &self.path))
845 }
846
847 pub fn write_request_at<'a>(&'a self, offset: u64, data: &'a [u8]) -> FsWrite<'a, F> {
848 FsWrite {
849 file: self,
850 offset: VfOffset::At(offset),
851 data,
852 }
853 }
854
855 pub fn read_request_at_into<'a>(
856 &'a self,
857 offset: u64,
858 buffer: &'a mut [u8],
859 ) -> FsReadInto<'a, F> {
860 FsReadInto {
861 file: self,
862 offset: VfOffset::At(offset),
863 buffer,
864 }
865 }
866
867 pub fn read_native(&mut self, buffer: &mut [u8]) -> VfResult<usize> {
868 self.read_into(buffer, VfOffset::Cur)
869 }
870
871 pub fn write_native(&mut self, buffer: &[u8]) -> VfResult<usize> {
872 self.write_from(buffer, VfOffset::Cur)
873 }
874
875 fn read_into(&self, buffer: &mut [u8], offset: VfOffset) -> VfResult<usize> {
876 if buffer.is_empty() {
877 return Ok(0);
878 }
879 let request = ReadOp::new(self.raw()?.clone(), offset, buffer.len());
880 let result = self
881 .inner
882 .lock()
883 .map_err(|_| poisoned())?
884 .read_one_into(&request, buffer)
885 .map_err(|error| error.with_context("read", &self.path))?;
886 validate_read_into_results(
887 "read",
888 std::slice::from_ref(&request),
889 std::slice::from_ref(&result),
890 )
891 .map_err(|error| error.with_context("read", &self.path))?;
892 Ok(result.read)
893 }
894
895 fn write_from(&self, buffer: &[u8], offset: VfOffset) -> VfResult<usize> {
896 if buffer.is_empty() {
897 return Ok(0);
898 }
899 let file = self.raw()?.clone();
900 let result = self
901 .inner
902 .lock()
903 .map_err(|_| poisoned())?
904 .write_one(WriteOpRef::new(&file, offset, buffer))
905 .map_err(|error| error.with_context("write", &self.path))?;
906 if result.written > buffer.len() {
907 return Err(VfError::client(0, crate::ERR_IO).with_context("write", &self.path));
908 }
909 Ok(result.written)
910 }
911
912 pub fn sync_data(&self) -> VfResult<()> {
913 self.inner
914 .lock()
915 .map_err(|_| poisoned())?
916 .sync_data(self.raw()?)
917 .map_err(|error| error.with_context("sync_data", &self.path))
918 }
919
920 pub fn sync_all(&self) -> VfResult<()> {
921 self.inner
922 .lock()
923 .map_err(|_| poisoned())?
924 .sync_all(self.raw()?)
925 .map_err(|error| error.with_context("sync_all", &self.path))
926 }
927
928 pub fn try_close(&mut self) -> VfResult<()> {
931 let Some(file) = self.file.as_ref() else {
932 return Ok(());
933 };
934 self.inner
935 .lock()
936 .map_err(|_| poisoned())?
937 .close_one(file)
938 .map_err(|error| error.with_context("close", &self.path))?;
939 self.file = None;
940 Ok(())
941 }
942
943 pub fn close(mut self) -> VfResult<()> {
946 self.try_close()
947 }
948
949 pub fn seek_native(&mut self, position: IoSeekFrom) -> VfResult<u64> {
951 self.inner
952 .lock()
953 .map_err(|_| poisoned())?
954 .seek_one(self.raw()?, position)
955 .map_err(|error| error.with_context("seek", &self.path))
956 }
957}
958
959impl<F: FileSystem> Read for FsFile<F> {
960 fn read(&mut self, buffer: &mut [u8]) -> io::Result<usize> {
961 self.read_native(buffer).map_err(io_error)
962 }
963}
964
965impl<F: FileSystem> Write for FsFile<F> {
966 fn write(&mut self, buffer: &[u8]) -> io::Result<usize> {
967 self.write_native(buffer).map_err(io_error)
968 }
969
970 fn flush(&mut self) -> io::Result<()> {
971 self.sync_data().map_err(io_error)
972 }
973}
974
975impl<F: FileSystem> Seek for FsFile<F> {
976 fn seek(&mut self, position: IoSeekFrom) -> io::Result<u64> {
977 self.seek_native(position).map_err(io_error)
978 }
979}
980
981pub struct FsRead<'a, F: FileSystem> {
983 file: &'a FsFile<F>,
984 offset: VfOffset,
985 length: usize,
986}
987
988pub struct FsWrite<'a, F: FileSystem> {
990 file: &'a FsFile<F>,
991 offset: VfOffset,
992 data: &'a [u8],
993}
994
995pub struct FsReadInto<'a, F: FileSystem> {
997 file: &'a FsFile<F>,
998 offset: VfOffset,
999 buffer: &'a mut [u8],
1000}
1001
1002impl<F: FileSystem> Drop for FsFile<F> {
1003 fn drop(&mut self) {
1004 if let Some(file) = self.file.take()
1005 && let Ok(mut filesystem) = self.inner.lock()
1006 {
1007 let _ = filesystem.close_one(&file);
1008 }
1009 }
1010}