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