dir_view/
dir_utf8.rs

1use crate::{ReadDirViewUtf8, ViewKind};
2use camino::{Utf8Path, Utf8PathBuf};
3#[cfg(feature = "cap-fs-ext")]
4use cap_fs_ext::{AccessType, SystemTimeSpec};
5use cap_std::fs_utf8::{Dir, DirBuilder, File, Metadata, OpenOptions, Permissions};
6use cap_std::io_lifetimes::AsFilelike;
7#[cfg(unix)]
8use cap_std::os::unix::net::{UnixDatagram, UnixListener, UnixStream};
9use cap_std::AmbientAuthority;
10#[cfg(target_os = "wasi")]
11use rustix::fs::OpenOptionsExt;
12use std::{fmt, io};
13
14/// A view of a [`Dir`].
15///
16/// This provides the same API as `Dir`, but imposes restrictions according
17/// to the view kind.
18pub struct DirViewUtf8 {
19    pub(crate) dir: Dir,
20    pub(crate) view_kind: ViewKind,
21}
22
23impl DirViewUtf8 {
24    /// Constructs a new instance of `Self` from the given [`Dir`] and
25    /// [`ViewKind`].
26    #[inline]
27    pub fn from_dir(dir: Dir, view_kind: ViewKind) -> Self {
28        Self { dir, view_kind }
29    }
30
31    /// Attempts to open a file in read-only mode.
32    ///
33    /// This corresponds to [`std::fs::File::open`], but only accesses paths
34    /// relative to `self`.
35    #[inline]
36    pub fn open<P: AsRef<Utf8Path>>(&self, path: P) -> io::Result<File> {
37        self.dir.open(path)
38    }
39
40    /// Opens a file at `path` with the options specified by `options`.
41    ///
42    /// This corresponds to [`std::fs::OpenOptions::open`].
43    ///
44    /// Instead of being a method on `OpenOptions`, this is a method on `Dir`,
45    /// and it only accesses paths relative to `self`.
46    #[inline]
47    pub fn open_with<P: AsRef<Utf8Path>>(
48        &self,
49        path: P,
50        options: &OpenOptions,
51    ) -> io::Result<File> {
52        // Override any flag that allows writing.
53        let mut options = options.clone();
54        options.append(false);
55        options.truncate(false);
56        options.write(false);
57        options.create(false);
58        options.create_new(false);
59        self.dir.open_with(path, &options)
60    }
61
62    /// Attempts to open a directory.
63    #[inline]
64    pub fn open_dir<P: AsRef<Utf8Path>>(&self, path: P) -> io::Result<Self> {
65        Ok(Self {
66            dir: self.dir.open_dir(path)?,
67            view_kind: self.view_kind,
68        })
69    }
70
71    /// Creates a new, empty directory at the provided path.
72    ///
73    /// This corresponds to [`std::fs::create_dir`], but only accesses paths
74    /// relative to `self`.
75    #[inline]
76    pub fn create_dir<P: AsRef<Utf8Path>>(&self, path: P) -> io::Result<()> {
77        self.check_mutation()?;
78        self.dir.create_dir(path)
79    }
80
81    /// Recursively create a directory and all of its parent components if they
82    /// are missing.
83    ///
84    /// This corresponds to [`std::fs::create_dir_all`], but only accesses
85    /// paths relative to `self`.
86    #[inline]
87    pub fn create_dir_all<P: AsRef<Utf8Path>>(&self, path: P) -> io::Result<()> {
88        self.check_mutation()?;
89        self.dir.create_dir_all(path)
90    }
91
92    /// Creates the specified directory with the options configured in this
93    /// builder.
94    ///
95    /// This corresponds to [`std::fs::DirBuilder::create`].
96    #[cfg(not(target_os = "wasi"))]
97    #[inline]
98    pub fn create_dir_with<P: AsRef<Utf8Path>>(
99        &self,
100        path: P,
101        dir_builder: &DirBuilder,
102    ) -> io::Result<()> {
103        self.check_mutation()?;
104        self.dir.create_dir_with(path, dir_builder)
105    }
106
107    /// Opens a file in write-only mode.
108    ///
109    /// This corresponds to [`std::fs::File::create`], but only accesses paths
110    /// relative to `self`.
111    #[inline]
112    pub fn create<P: AsRef<Utf8Path>>(&self, path: P) -> io::Result<File> {
113        self.check_mutation()?;
114        self.dir.create(path)
115    }
116
117    /// Returns the canonical form of a path with all intermediate components
118    /// normalized and symbolic links resolved.
119    ///
120    /// This corresponds to [`std::fs::canonicalize`], but instead of returning
121    /// an absolute path, returns a path relative to the directory
122    /// represented by `self`.
123    #[inline]
124    pub fn canonicalize<P: AsRef<Utf8Path>>(&self, path: P) -> io::Result<Utf8PathBuf> {
125        self.dir.canonicalize(path)
126    }
127
128    /// Copies the contents of one file to another. This function will also
129    /// copy the permission bits of the original file to the destination
130    /// file.
131    ///
132    /// This corresponds to [`std::fs::copy`], but only accesses paths
133    /// relative to `self`.
134    #[inline]
135    pub fn copy<P: AsRef<Utf8Path>, Q: AsRef<Utf8Path>>(
136        &self,
137        from: P,
138        to_dir: &Self,
139        to: Q,
140    ) -> io::Result<u64> {
141        to_dir.check_mutation()?;
142        self.dir.copy(from, &to_dir.dir, to)
143    }
144
145    /// Creates a new hard link on a filesystem.
146    ///
147    /// This corresponds to [`std::fs::hard_link`], but only accesses paths
148    /// relative to `self`.
149    #[inline]
150    pub fn hard_link<P: AsRef<Utf8Path>, Q: AsRef<Utf8Path>>(
151        &self,
152        src: P,
153        dst_dir: &Self,
154        dst: Q,
155    ) -> io::Result<()> {
156        self.check_mutation()?;
157        dst_dir.check_mutation()?;
158        self.dir.hard_link(src, &dst_dir.dir, dst)
159    }
160
161    /// Given a path, query the file system to get information about a file,
162    /// directory, etc.
163    ///
164    /// This corresponds to [`std::fs::metadata`], but only accesses paths
165    /// relative to `self`.
166    #[inline]
167    pub fn metadata<P: AsRef<Utf8Path>>(&self, path: P) -> io::Result<cap_std::fs::Metadata> {
168        self.dir.metadata(path)
169    }
170
171    /// Queries metadata about the underlying directory.
172    ///
173    /// This is similar to [`std::fs::File::metadata`], but for `Dir` rather
174    /// than for `File`.
175    #[inline]
176    pub fn dir_metadata(&self) -> io::Result<Metadata> {
177        self.dir.dir_metadata()
178    }
179
180    /// Returns an iterator over the entries within `self`.
181    #[inline]
182    pub fn entries(&self) -> io::Result<ReadDirViewUtf8> {
183        Ok(ReadDirViewUtf8 {
184            read_dir: self.dir.entries()?,
185            view_kind: self.view_kind,
186        })
187    }
188
189    /// Returns an iterator over the entries within a directory.
190    ///
191    /// This corresponds to [`std::fs::read_dir`], but only accesses paths
192    /// relative to `self`.
193    #[inline]
194    pub fn read_dir<P: AsRef<Utf8Path>>(&self, path: P) -> io::Result<ReadDirViewUtf8> {
195        Ok(ReadDirViewUtf8 {
196            read_dir: self.dir.read_dir(path)?,
197            view_kind: self.view_kind,
198        })
199    }
200
201    /// Read the entire contents of a file into a bytes vector.
202    ///
203    /// This corresponds to [`std::fs::read`], but only accesses paths
204    /// relative to `self`.
205    #[inline]
206    pub fn read<P: AsRef<Utf8Path>>(&self, path: P) -> io::Result<Vec<u8>> {
207        self.dir.read(path)
208    }
209
210    /// Reads a symbolic link, returning the file that the link points to.
211    ///
212    /// This corresponds to [`std::fs::read_link`], but only accesses paths
213    /// relative to `self`.
214    #[inline]
215    pub fn read_link<P: AsRef<Utf8Path>>(&self, path: P) -> io::Result<Utf8PathBuf> {
216        self.dir.read_link(path)
217    }
218
219    /// Read the entire contents of a file into a string.
220    ///
221    /// This corresponds to [`std::fs::read_to_string`], but only accesses
222    /// paths relative to `self`.
223    #[inline]
224    pub fn read_to_string<P: AsRef<Utf8Path>>(&self, path: P) -> io::Result<String> {
225        self.dir.read_to_string(path)
226    }
227
228    /// Removes an empty directory.
229    ///
230    /// This corresponds to [`std::fs::remove_dir`], but only accesses paths
231    /// relative to `self`.
232    #[inline]
233    pub fn remove_dir<P: AsRef<Utf8Path>>(&self, path: P) -> io::Result<()> {
234        self.check_mutation()?;
235        self.dir.remove_dir(path)
236    }
237
238    /// Removes a directory at this path, after removing all its contents. Use
239    /// carefully!
240    ///
241    /// This corresponds to [`std::fs::remove_dir_all`], but only accesses
242    /// paths relative to `self`.
243    #[inline]
244    pub fn remove_dir_all<P: AsRef<Utf8Path>>(&self, path: P) -> io::Result<()> {
245        self.check_mutation()?;
246        self.dir.remove_dir_all(path)
247    }
248
249    /// Remove the directory referenced by `self` and consume `self`.
250    ///
251    /// Even though this implementation works in terms of handles as much as
252    /// possible, removal is not guaranteed to be atomic with respect to a
253    /// concurrent rename of the directory.
254    #[inline]
255    pub fn remove_open_dir(self) -> io::Result<()> {
256        self.check_mutation()?;
257        self.dir.remove_open_dir()
258    }
259
260    /// Removes the directory referenced by `self`, after removing all its
261    /// contents, and consume `self`. Use carefully!
262    ///
263    /// Even though this implementation works in terms of handles as much as
264    /// possible, removal is not guaranteed to be atomic with respect to a
265    /// concurrent rename of the directory.
266    #[inline]
267    pub fn remove_open_dir_all(self) -> io::Result<()> {
268        self.check_mutation()?;
269        self.dir.remove_open_dir_all()
270    }
271
272    /// Removes a file from a filesystem.
273    ///
274    /// This corresponds to [`std::fs::remove_file`], but only accesses paths
275    /// relative to `self`.
276    #[inline]
277    pub fn remove_file<P: AsRef<Utf8Path>>(&self, path: P) -> io::Result<()> {
278        self.check_mutation()?;
279        self.dir.remove_file(path)
280    }
281
282    /// Rename a file or directory to a new name, replacing the original file
283    /// if to already exists.
284    ///
285    /// This corresponds to [`std::fs::rename`], but only accesses paths
286    /// relative to `self`.
287    #[inline]
288    pub fn rename<P: AsRef<Utf8Path>, Q: AsRef<Utf8Path>>(
289        &self,
290        from: P,
291        to_dir: &Self,
292        to: Q,
293    ) -> io::Result<()> {
294        self.check_mutation()?;
295        to_dir.check_mutation()?;
296        self.dir.rename(from, &to_dir.dir, to)
297    }
298
299    /// Changes the permissions found on a file or a directory.
300    ///
301    /// This corresponds to [`std::fs::set_permissions`], but only accesses
302    /// paths relative to `self`. Also, on some platforms, this function
303    /// may fail if the file or directory cannot be opened for reading or
304    /// writing first.
305    #[cfg(not(target_os = "wasi"))]
306    #[inline]
307    pub fn set_permissions<P: AsRef<Utf8Path>>(
308        &self,
309        path: P,
310        perm: Permissions,
311    ) -> io::Result<()> {
312        self.check_mutation()?;
313        self.dir.set_permissions(path, perm)
314    }
315
316    /// Query the metadata about a file without following symlinks.
317    ///
318    /// This corresponds to [`std::fs::symlink_metadata`], but only accesses
319    /// paths relative to `self`.
320    #[inline]
321    pub fn symlink_metadata<P: AsRef<Utf8Path>>(&self, path: P) -> io::Result<Metadata> {
322        self.dir.symlink_metadata(path)
323    }
324
325    /// Write a slice as the entire contents of a file.
326    ///
327    /// This corresponds to [`std::fs::write`], but only accesses paths
328    /// relative to `self`.
329    #[inline]
330    pub fn write<P: AsRef<Utf8Path>, C: AsRef<[u8]>>(
331        &self,
332        path: P,
333        contents: C,
334    ) -> io::Result<()> {
335        self.check_mutation()?;
336        self.dir.write(path, contents)
337    }
338
339    /// Creates a new symbolic link on a filesystem.
340    ///
341    /// The `original` argument provides the target of the symlink. The `link`
342    /// argument provides the name of the created symlink.
343    ///
344    /// Despite the argument ordering, `original` is not resolved relative to
345    /// `self` here. `link` is resolved relative to `self`, and `original` is
346    /// not resolved within this function.
347    ///
348    /// The `link` path is resolved when the symlink is dereferenced, relative
349    /// to the directory that contains it.
350    ///
351    /// This corresponds to [`std::os::unix::fs::symlink`], but only accesses
352    /// paths relative to `self`.
353    ///
354    /// [`std::os::unix::fs::symlink`]: https://doc.rust-lang.org/std/os/unix/fs/fn.symlink.html
355    #[cfg(not(windows))]
356    #[inline]
357    pub fn symlink<P: AsRef<Utf8Path>, Q: AsRef<Utf8Path>>(
358        &self,
359        original: P,
360        link: Q,
361    ) -> io::Result<()> {
362        self.check_mutation()?;
363        self.dir.symlink(original, link)
364    }
365
366    /// Creates a new file symbolic link on a filesystem.
367    ///
368    /// The `original` argument provides the target of the symlink. The `link`
369    /// argument provides the name of the created symlink.
370    ///
371    /// Despite the argument ordering, `original` is not resolved relative to
372    /// `self` here. `link` is resolved relative to `self`, and `original` is
373    /// not resolved within this function.
374    ///
375    /// The `link` path is resolved when the symlink is dereferenced, relative
376    /// to the directory that contains it.
377    ///
378    /// This corresponds to [`std::os::windows::fs::symlink_file`], but only
379    /// accesses paths relative to `self`.
380    ///
381    /// [`std::os::windows::fs::symlink_file`]: https://doc.rust-lang.org/std/os/windows/fs/fn.symlink_file.html
382    #[cfg(windows)]
383    #[inline]
384    pub fn symlink_file<P: AsRef<Utf8Path>, Q: AsRef<Utf8Path>>(
385        &self,
386        original: P,
387        link: Q,
388    ) -> io::Result<()> {
389        self.check_mutation()?;
390        self.dir.symlink_file(original, link)
391    }
392
393    /// Creates a new directory symlink on a filesystem.
394    ///
395    /// The `original` argument provides the target of the symlink. The `link`
396    /// argument provides the name of the created symlink.
397    ///
398    /// Despite the argument ordering, `original` is not resolved relative to
399    /// `self` here. `link` is resolved relative to `self`, and `original` is
400    /// not resolved within this function.
401    ///
402    /// The `link` path is resolved when the symlink is dereferenced, relative
403    /// to the directory that contains it.
404    ///
405    /// This corresponds to [`std::os::windows::fs::symlink_dir`], but only
406    /// accesses paths relative to `self`.
407    ///
408    /// [`std::os::windows::fs::symlink_dir`]: https://doc.rust-lang.org/std/os/windows/fs/fn.symlink_dir.html
409    #[cfg(windows)]
410    #[inline]
411    pub fn symlink_dir<P: AsRef<Utf8Path>, Q: AsRef<Utf8Path>>(
412        &self,
413        original: P,
414        link: Q,
415    ) -> io::Result<()> {
416        self.check_mutation()?;
417        self.dir.symlink_dir(original, link)
418    }
419
420    /// Creates a new `UnixListener` bound to the specified socket.
421    ///
422    /// This corresponds to [`std::os::unix::net::UnixListener::bind`], but
423    /// only accesses paths relative to `self`.
424    ///
425    /// XXX: This function is not yet implemented.
426    ///
427    /// [`std::os::unix::net::UnixListener::bind`]: https://doc.rust-lang.org/std/os/unix/net/struct.UnixListener.html#method.bind
428    #[cfg(unix)]
429    #[inline]
430    pub fn bind_unix_listener<P: AsRef<Utf8Path>>(&self, path: P) -> io::Result<UnixListener> {
431        self.dir.bind_unix_listener(path)
432    }
433
434    /// Connects to the socket named by path.
435    ///
436    /// This corresponds to [`std::os::unix::net::UnixStream::connect`], but
437    /// only accesses paths relative to `self`.
438    ///
439    /// XXX: This function is not yet implemented.
440    ///
441    /// [`std::os::unix::net::UnixStream::connect`]: https://doc.rust-lang.org/std/os/unix/net/struct.UnixStream.html#method.connect
442    #[cfg(unix)]
443    #[inline]
444    pub fn connect_unix_stream<P: AsRef<Utf8Path>>(&self, path: P) -> io::Result<UnixStream> {
445        self.dir.connect_unix_stream(path)
446    }
447
448    /// Creates a Unix datagram socket bound to the given path.
449    ///
450    /// This corresponds to [`std::os::unix::net::UnixDatagram::bind`], but
451    /// only accesses paths relative to `self`.
452    ///
453    /// XXX: This function is not yet implemented.
454    ///
455    /// [`std::os::unix::net::UnixDatagram::bind`]: https://doc.rust-lang.org/std/os/unix/net/struct.UnixDatagram.html#method.bind
456    #[cfg(unix)]
457    #[inline]
458    pub fn bind_unix_datagram<P: AsRef<Utf8Path>>(&self, path: P) -> io::Result<UnixDatagram> {
459        self.dir.bind_unix_datagram(path)
460    }
461
462    /// Connects the socket to the specified address.
463    ///
464    /// This corresponds to [`std::os::unix::net::UnixDatagram::connect`], but
465    /// only accesses paths relative to `self`.
466    ///
467    /// XXX: This function is not yet implemented.
468    ///
469    /// [`std::os::unix::net::UnixDatagram::connect`]: https://doc.rust-lang.org/std/os/unix/net/struct.UnixDatagram.html#method.connect
470    #[cfg(unix)]
471    #[inline]
472    pub fn connect_unix_datagram<P: AsRef<Utf8Path>>(
473        &self,
474        unix_datagram: &UnixDatagram,
475        path: P,
476    ) -> io::Result<()> {
477        self.dir.connect_unix_datagram(unix_datagram, path)
478    }
479
480    /// Sends data on the socket to the specified address.
481    ///
482    /// This corresponds to [`std::os::unix::net::UnixDatagram::send_to`], but
483    /// only accesses paths relative to `self`.
484    ///
485    /// XXX: This function is not yet implemented.
486    ///
487    /// [`std::os::unix::net::UnixDatagram::send_to`]: https://doc.rust-lang.org/std/os/unix/net/struct.UnixDatagram.html#method.send_to
488    #[cfg(unix)]
489    #[inline]
490    pub fn send_to_unix_datagram_addr<P: AsRef<Utf8Path>>(
491        &self,
492        unix_datagram: &UnixDatagram,
493        buf: &[u8],
494        path: P,
495    ) -> io::Result<usize> {
496        self.dir
497            .send_to_unix_datagram_addr(unix_datagram, buf, path)
498    }
499
500    /// Creates a new `Dir` instance that shares the same underlying file
501    /// handle as the existing `Dir` instance.
502    #[inline]
503    pub fn try_clone(&self) -> io::Result<Self> {
504        Ok(Self {
505            dir: self.dir.try_clone()?,
506            view_kind: self.view_kind,
507        })
508    }
509
510    /// Returns `true` if the path points at an existing entity.
511    ///
512    /// This corresponds to [`std::path::Path::exists`], but only
513    /// accesses paths relative to `self`.
514    #[inline]
515    pub fn exists<P: AsRef<Utf8Path>>(&self, path: P) -> bool {
516        self.dir.exists(path)
517    }
518
519    /// Returns `true` if the path points at an existing entity.
520    ///
521    /// This corresponds to [`std::fs::try_exists`], but only
522    /// accesses paths relative to `self`.
523    ///
524    /// # API correspondence with `std`
525    ///
526    /// This API is not yet stable in `std`, but is likely to be. For more
527    /// information, see the [tracker issue](https://github.com/rust-lang/rust/issues/83186).
528    #[inline]
529    pub fn try_exists<P: AsRef<Utf8Path>>(&self, path: P) -> io::Result<bool> {
530        self.dir.try_exists(path)
531    }
532
533    /// Returns `true` if the path exists on disk and is pointing at a regular
534    /// file.
535    ///
536    /// This corresponds to [`std::path::Path::is_file`], but only
537    /// accesses paths relative to `self`.
538    #[inline]
539    pub fn is_file<P: AsRef<Utf8Path>>(&self, path: P) -> bool {
540        self.dir.is_file(path)
541    }
542
543    /// Checks if `path` is a directory.
544    ///
545    /// This is similar to [`std::path::Path::is_dir`] in that it checks if
546    /// `path` relative to `Dir` is a directory. This function will
547    /// traverse symbolic links to query information about the destination
548    /// file. In case of broken symbolic links, this will return `false`.
549    #[inline]
550    pub fn is_dir<P: AsRef<Utf8Path>>(&self, path: P) -> bool {
551        self.dir.is_dir(path)
552    }
553
554    /// Constructs a new instance of `Self` by opening the given path as a
555    /// directory using the host process' ambient authority.
556    ///
557    /// # Ambient Authority
558    ///
559    /// This function is not sandboxed and may access any path that the host
560    /// process has access to.
561    #[inline]
562    pub fn open_ambient_dir<P: AsRef<Utf8Path>>(
563        path: P,
564        view_kind: ViewKind,
565        ambient_authority: AmbientAuthority,
566    ) -> io::Result<Self> {
567        Ok(Self {
568            dir: Dir::open_ambient_dir(path, ambient_authority)?,
569            view_kind,
570        })
571    }
572
573    /// Constructs a new instance of `Self` by opening the parent directory
574    /// (aka "..") of `self`, using the host process' ambient authority.
575    ///
576    /// # Ambient Authority
577    ///
578    /// This function accesses a directory outside of the `self` subtree.
579    #[inline]
580    pub fn open_parent_dir(
581        &self,
582        view_kind: ViewKind,
583        ambient_authority: AmbientAuthority,
584    ) -> io::Result<Self> {
585        Ok(Self {
586            dir: self.dir.open_parent_dir(ambient_authority)?,
587            view_kind,
588        })
589    }
590
591    /// Construct a new instance of `Self` from existing directory file
592    /// descriptor.
593    ///
594    /// This can be useful when interacting with other libraries and or C/C++
595    /// code which has invoked `openat(..., O_DIRECTORY)` external to this
596    /// crate.
597    pub fn reopen_dir<Filelike: AsFilelike>(
598        dir: &Filelike,
599        view_kind: ViewKind,
600    ) -> io::Result<Self> {
601        Ok(Self {
602            dir: Dir::reopen_dir(dir)?,
603            view_kind,
604        })
605    }
606
607    fn check_mutation(&self) -> io::Result<()> {
608        match self.view_kind {
609            ViewKind::Full => Ok(()),
610            ViewKind::Readonly => Err(Self::readonly()),
611        }
612    }
613
614    fn readonly() -> io::Error {
615        io::Error::new(
616            io::ErrorKind::PermissionDenied,
617            "attempt to modify a directory tree through a read-only `DirViewUtf8`",
618        )
619    }
620}
621
622impl fmt::Debug for DirViewUtf8 {
623    // Like libstd's version, but doesn't print the path.
624    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
625        let mut b = f.debug_struct("DirViewUtf8");
626        b.field("dir", &self.dir);
627        #[cfg(windows)]
628        b.field("view_kind", &self.view_kind);
629        b.finish()
630    }
631}
632
633#[cfg(feature = "cap-fs-ext")]
634impl cap_fs_ext::DirExtUtf8 for DirViewUtf8 {
635    fn set_atime<P: AsRef<Utf8Path>>(&self, path: P, atime: SystemTimeSpec) -> io::Result<()> {
636        self.check_mutation()?;
637        cap_fs_ext::DirExtUtf8::set_atime(&self.dir, path, atime)
638    }
639
640    fn set_mtime<P: AsRef<Utf8Path>>(&self, path: P, mtime: SystemTimeSpec) -> io::Result<()> {
641        self.check_mutation()?;
642        cap_fs_ext::DirExtUtf8::set_mtime(&self.dir, path, mtime)
643    }
644
645    fn set_times<P: AsRef<Utf8Path>>(
646        &self,
647        path: P,
648        atime: Option<SystemTimeSpec>,
649        mtime: Option<SystemTimeSpec>,
650    ) -> io::Result<()> {
651        self.check_mutation()?;
652        cap_fs_ext::DirExtUtf8::set_times(&self.dir, path, atime, mtime)
653    }
654
655    fn set_symlink_times<P: AsRef<Utf8Path>>(
656        &self,
657        path: P,
658        atime: Option<SystemTimeSpec>,
659        mtime: Option<SystemTimeSpec>,
660    ) -> io::Result<()> {
661        self.check_mutation()?;
662        cap_fs_ext::DirExtUtf8::set_symlink_times(&self.dir, path, atime, mtime)
663    }
664
665    fn symlink<P: AsRef<Utf8Path>, Q: AsRef<Utf8Path>>(&self, src: P, dst: Q) -> io::Result<()> {
666        self.check_mutation()?;
667        cap_fs_ext::DirExtUtf8::symlink(&self.dir, src, dst)
668    }
669
670    fn symlink_file<P: AsRef<Utf8Path>, Q: AsRef<Utf8Path>>(
671        &self,
672        src: P,
673        dst: Q,
674    ) -> io::Result<()> {
675        self.check_mutation()?;
676        cap_fs_ext::DirExtUtf8::symlink_file(&self.dir, src, dst)
677    }
678
679    fn symlink_dir<P: AsRef<Utf8Path>, Q: AsRef<Utf8Path>>(
680        &self,
681        src: P,
682        dst: Q,
683    ) -> io::Result<()> {
684        self.check_mutation()?;
685        cap_fs_ext::DirExtUtf8::symlink_dir(&self.dir, src, dst)
686    }
687
688    fn open_dir_nofollow<P: AsRef<Utf8Path>>(&self, path: P) -> io::Result<Self>
689    where
690        Self: Sized,
691    {
692        Ok(Self {
693            dir: self.dir.open_dir_nofollow(path)?,
694            view_kind: self.view_kind,
695        })
696    }
697
698    fn remove_file_or_symlink<P: AsRef<Utf8Path>>(&self, path: P) -> io::Result<()> {
699        self.check_mutation()?;
700        cap_fs_ext::DirExtUtf8::remove_file_or_symlink(&self.dir, path)
701    }
702
703    fn access<P: AsRef<Utf8Path>>(&self, path: P, type_: AccessType) -> io::Result<()> {
704        cap_fs_ext::DirExtUtf8::access(&self.dir, path, type_)
705    }
706
707    fn access_symlink<P: AsRef<Utf8Path>>(&self, path: P, type_: AccessType) -> io::Result<()> {
708        cap_fs_ext::DirExtUtf8::access_symlink(&self.dir, path, type_)
709    }
710
711    fn set_symlink_permissions<P: AsRef<Utf8Path>>(
712        &self,
713        path: P,
714        perm: Permissions,
715    ) -> io::Result<()> {
716        self.check_mutation()?;
717        cap_fs_ext::DirExtUtf8::set_symlink_permissions(&self.dir, path, perm)
718    }
719}