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}