cap_std/fs_utf8/
dir.rs

1use crate::fs::{OpenOptions, Permissions};
2use crate::fs_utf8::{from_utf8, to_utf8, DirBuilder, File, Metadata, ReadDir};
3#[cfg(unix)]
4use crate::os::unix::net::{UnixDatagram, UnixListener, UnixStream};
5use camino::{Utf8Path, Utf8PathBuf};
6use cap_primitives::AmbientAuthority;
7#[cfg(not(windows))]
8use io_extras::os::rustix::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
9use io_lifetimes::AsFilelike;
10#[cfg(not(windows))]
11use io_lifetimes::{AsFd, BorrowedFd, OwnedFd};
12#[cfg(windows)]
13use io_lifetimes::{AsHandle, BorrowedHandle, OwnedHandle};
14use std::{fmt, fs, io};
15#[cfg(windows)]
16use {
17    io_extras::os::windows::{
18        AsHandleOrSocket, AsRawHandleOrSocket, BorrowedHandleOrSocket, IntoRawHandleOrSocket,
19        OwnedHandleOrSocket, RawHandleOrSocket,
20    },
21    std::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle},
22};
23
24/// A reference to an open directory on a filesystem.
25///
26/// This does not directly correspond to anything in `std`, however its methods
27/// correspond to the [functions in `std::fs`] and the constructor methods for
28/// [`std::fs::File`].
29///
30/// Unlike `std::fs`, this API's `canonicalize` returns a relative path since
31/// absolute paths don't interoperate well with the capability model.
32///
33/// [functions in `std::fs`]: https://doc.rust-lang.org/std/fs/index.html#functions
34pub struct Dir {
35    cap_std: crate::fs::Dir,
36}
37
38impl Dir {
39    /// Constructs a new instance of `Self` from the given [`std::fs::File`].
40    ///
41    /// To prevent race conditions on Windows, the file must be opened without
42    /// `FILE_SHARE_DELETE`.
43    ///
44    /// This grants access the resources the `std::fs::File` instance already
45    /// has access to.
46    #[inline]
47    pub fn from_std_file(std_file: fs::File) -> Self {
48        Self::from_cap_std(crate::fs::Dir::from_std_file(std_file))
49    }
50
51    /// Constructs a new instance of `Self` from the given `cap_std::fs::Dir`.
52    #[inline]
53    pub fn from_cap_std(cap_std: crate::fs::Dir) -> Self {
54        Self { cap_std }
55    }
56
57    /// Return a view of this directory as a [`cap_std::fs::Dir`]. This
58    /// is often useful in order to write shared functions which can operate
59    /// on either type.
60    #[inline]
61    pub fn as_cap_std(&self) -> &crate::fs::Dir {
62        &self.cap_std
63    }
64
65    /// Attempts to open a file in read-only mode.
66    ///
67    /// This corresponds to [`std::fs::File::open`], but only accesses paths
68    /// relative to `self`.
69    #[inline]
70    pub fn open<P: AsRef<Utf8Path>>(&self, path: P) -> io::Result<File> {
71        let path = from_utf8(path.as_ref())?;
72        self.as_cap_std().open(path).map(File::from_cap_std)
73    }
74
75    /// Opens a file at `path` with the options specified by `options`.
76    ///
77    /// This corresponds to [`std::fs::OpenOptions::open`].
78    ///
79    /// Instead of being a method on `OpenOptions`, this is a method on `Dir`,
80    /// and it only accesses paths relative to `self`.
81    #[inline]
82    pub fn open_with<P: AsRef<Utf8Path>>(
83        &self,
84        path: P,
85        options: &OpenOptions,
86    ) -> io::Result<File> {
87        let path = from_utf8(path.as_ref())?;
88        self.cap_std
89            .open_with(path, options)
90            .map(File::from_cap_std)
91    }
92
93    /// Attempts to open a directory.
94    #[inline]
95    pub fn open_dir<P: AsRef<Utf8Path>>(&self, path: P) -> io::Result<Self> {
96        let path = from_utf8(path.as_ref())?;
97        self.as_ref().open_dir(path).map(Self::from_cap_std)
98    }
99
100    /// Creates a new, empty directory at the provided path.
101    ///
102    /// This corresponds to [`std::fs::create_dir`], but only accesses paths
103    /// relative to `self`.
104    #[inline]
105    pub fn create_dir<P: AsRef<Utf8Path>>(&self, path: P) -> io::Result<()> {
106        let path = from_utf8(path.as_ref())?;
107        self.cap_std.create_dir(path)
108    }
109
110    /// Recursively create a directory and all of its parent components if they
111    /// are missing.
112    ///
113    /// This corresponds to [`std::fs::create_dir_all`], but only accesses
114    /// paths relative to `self`.
115    #[inline]
116    pub fn create_dir_all<P: AsRef<Utf8Path>>(&self, path: P) -> io::Result<()> {
117        let path = from_utf8(path.as_ref())?;
118        self.cap_std.create_dir_all(path)
119    }
120
121    /// Creates the specified directory with the options configured in this
122    /// builder.
123    ///
124    /// This corresponds to [`std::fs::DirBuilder::create`].
125    #[cfg(not(target_os = "wasi"))]
126    #[inline]
127    pub fn create_dir_with<P: AsRef<Utf8Path>>(
128        &self,
129        path: P,
130        dir_builder: &DirBuilder,
131    ) -> io::Result<()> {
132        let path = from_utf8(path.as_ref())?;
133        self.cap_std.create_dir_with(path, dir_builder)
134    }
135
136    /// Opens a file in write-only mode.
137    ///
138    /// This corresponds to [`std::fs::File::create`], but only accesses paths
139    /// relative to `self`.
140    #[inline]
141    pub fn create<P: AsRef<Utf8Path>>(&self, path: P) -> io::Result<File> {
142        let path = from_utf8(path.as_ref())?;
143        self.cap_std.create(path).map(File::from_cap_std)
144    }
145
146    /// Returns the canonical form of a path with all intermediate components
147    /// normalized and symbolic links resolved.
148    ///
149    /// This corresponds to [`std::fs::canonicalize`], but instead of returning
150    /// an absolute path, returns a path relative to the directory
151    /// represented by `self`.
152    #[inline]
153    pub fn canonicalize<P: AsRef<Utf8Path>>(&self, path: P) -> io::Result<Utf8PathBuf> {
154        let path = from_utf8(path.as_ref())?;
155        self.cap_std.canonicalize(path).and_then(to_utf8)
156    }
157
158    /// Copies the contents of one file to another. This function will also
159    /// copy the permission bits of the original file to the destination
160    /// file.
161    ///
162    /// This corresponds to [`std::fs::copy`], but only accesses paths
163    /// relative to `self`.
164    #[inline]
165    pub fn copy<P: AsRef<Utf8Path>, Q: AsRef<Utf8Path>>(
166        &self,
167        from: P,
168        to_dir: &Self,
169        to: Q,
170    ) -> io::Result<u64> {
171        let from = from_utf8(from.as_ref())?;
172        let to = from_utf8(to.as_ref())?;
173        self.cap_std.copy(from, &to_dir.cap_std, to)
174    }
175
176    /// Creates a new hard link on a filesystem.
177    ///
178    /// This corresponds to [`std::fs::hard_link`], but only accesses paths
179    /// relative to `self`.
180    #[inline]
181    pub fn hard_link<P: AsRef<Utf8Path>, Q: AsRef<Utf8Path>>(
182        &self,
183        src: P,
184        dst_dir: &Self,
185        dst: Q,
186    ) -> io::Result<()> {
187        let src = from_utf8(src.as_ref())?;
188        let dst = from_utf8(dst.as_ref())?;
189        self.cap_std.hard_link(src, &dst_dir.cap_std, dst)
190    }
191
192    /// Given a path, query the file system to get information about a file,
193    /// directory, etc.
194    ///
195    /// This corresponds to [`std::fs::metadata`], but only accesses paths
196    /// relative to `self`.
197    #[inline]
198    pub fn metadata<P: AsRef<Utf8Path>>(&self, path: P) -> io::Result<Metadata> {
199        let path = from_utf8(path.as_ref())?;
200        self.cap_std.metadata(path)
201    }
202
203    /// Queries metadata about the underlying directory.
204    ///
205    /// This is similar to [`std::fs::File::metadata`], but for `Dir` rather
206    /// than for `File`.
207    #[inline]
208    pub fn dir_metadata(&self) -> io::Result<Metadata> {
209        self.cap_std.dir_metadata()
210    }
211
212    /// Returns an iterator over the entries within `self`.
213    #[inline]
214    pub fn entries(&self) -> io::Result<ReadDir> {
215        self.cap_std.entries().map(ReadDir::from_cap_std)
216    }
217
218    /// Returns an iterator over the entries within a directory.
219    ///
220    /// This corresponds to [`std::fs::read_dir`], but only accesses paths
221    /// relative to `self`.
222    #[inline]
223    pub fn read_dir<P: AsRef<Utf8Path>>(&self, path: P) -> io::Result<ReadDir> {
224        let path = from_utf8(path.as_ref())?;
225        self.cap_std.read_dir(path).map(ReadDir::from_cap_std)
226    }
227
228    /// Read the entire contents of a file into a bytes vector.
229    ///
230    /// This corresponds to [`std::fs::read`], but only accesses paths
231    /// relative to `self`.
232    #[inline]
233    pub fn read<P: AsRef<Utf8Path>>(&self, path: P) -> io::Result<Vec<u8>> {
234        let path = from_utf8(path.as_ref())?;
235        self.cap_std.read(path)
236    }
237
238    /// Reads a symbolic link, returning the file that the link points to.
239    ///
240    /// This corresponds to [`std::fs::read_link`], but only accesses paths
241    /// relative to `self`.  Unlike [`read_link_contents`], this method considers it an error if
242    /// the link's target is an absolute path.
243    #[inline]
244    pub fn read_link<P: AsRef<Utf8Path>>(&self, path: P) -> io::Result<Utf8PathBuf> {
245        let path = from_utf8(path.as_ref())?;
246        self.cap_std.read_link(path).and_then(to_utf8)
247    }
248
249    /// Reads a symbolic link, returning the file that the link points to.
250    ///
251    /// This corresponds to [`std::fs::read_link`]. but only accesses paths
252    /// relative to `self`.
253    #[inline]
254    pub fn read_link_contents<P: AsRef<Utf8Path>>(&self, path: P) -> io::Result<Utf8PathBuf> {
255        let path = from_utf8(path.as_ref())?;
256        self.cap_std.read_link_contents(path).and_then(to_utf8)
257    }
258
259    /// Read the entire contents of a file into a string.
260    ///
261    /// This corresponds to [`std::fs::read_to_string`], but only accesses
262    /// paths relative to `self`.
263    #[inline]
264    pub fn read_to_string<P: AsRef<Utf8Path>>(&self, path: P) -> io::Result<String> {
265        let path = from_utf8(path.as_ref())?;
266        self.cap_std.read_to_string(path)
267    }
268
269    /// Removes an empty directory.
270    ///
271    /// This corresponds to [`std::fs::remove_dir`], but only accesses paths
272    /// relative to `self`.
273    #[inline]
274    pub fn remove_dir<P: AsRef<Utf8Path>>(&self, path: P) -> io::Result<()> {
275        let path = from_utf8(path.as_ref())?;
276        self.cap_std.remove_dir(path)
277    }
278
279    /// Removes a directory at this path, after removing all its contents. Use
280    /// carefully!
281    ///
282    /// This corresponds to [`std::fs::remove_dir_all`], but only accesses
283    /// paths relative to `self`.
284    #[inline]
285    pub fn remove_dir_all<P: AsRef<Utf8Path>>(&self, path: P) -> io::Result<()> {
286        let path = from_utf8(path.as_ref())?;
287        self.cap_std.remove_dir_all(path)
288    }
289
290    /// Remove the directory referenced by `self` and consume `self`.
291    ///
292    /// Even though this implementation works in terms of handles as much as
293    /// possible, removal is not guaranteed to be atomic with respect to a
294    /// concurrent rename of the directory.
295    #[inline]
296    pub fn remove_open_dir(self) -> io::Result<()> {
297        self.cap_std.remove_open_dir()
298    }
299
300    /// Removes the directory referenced by `self`, after removing all its
301    /// contents, and consume `self`. Use carefully!
302    ///
303    /// Even though this implementation works in terms of handles as much as
304    /// possible, removal is not guaranteed to be atomic with respect to a
305    /// concurrent rename of the directory.
306    #[inline]
307    pub fn remove_open_dir_all(self) -> io::Result<()> {
308        self.cap_std.remove_open_dir_all()
309    }
310
311    /// Removes a file from a filesystem.
312    ///
313    /// This corresponds to [`std::fs::remove_file`], but only accesses paths
314    /// relative to `self`.
315    #[inline]
316    pub fn remove_file<P: AsRef<Utf8Path>>(&self, path: P) -> io::Result<()> {
317        let path = from_utf8(path.as_ref())?;
318        self.cap_std.remove_file(path)
319    }
320
321    /// Rename a file or directory to a new name, replacing the original file
322    /// if to already exists.
323    ///
324    /// This corresponds to [`std::fs::rename`], but only accesses paths
325    /// relative to `self`.
326    #[inline]
327    pub fn rename<P: AsRef<Utf8Path>, Q: AsRef<Utf8Path>>(
328        &self,
329        from: P,
330        to_dir: &Self,
331        to: Q,
332    ) -> io::Result<()> {
333        let from = from_utf8(from.as_ref())?;
334        let to = from_utf8(to.as_ref())?;
335        self.cap_std.rename(from, &to_dir.cap_std, to)
336    }
337
338    /// Changes the permissions found on a file or a directory.
339    ///
340    /// This corresponds to [`std::fs::set_permissions`], but only accesses
341    /// paths relative to `self`. Also, on some platforms, this function
342    /// may fail if the file or directory cannot be opened for reading or
343    /// writing first.
344    #[cfg(not(target_os = "wasi"))]
345    pub fn set_permissions<P: AsRef<Utf8Path>>(
346        &self,
347        path: P,
348        perm: Permissions,
349    ) -> io::Result<()> {
350        let path = from_utf8(path.as_ref())?;
351        self.cap_std.set_permissions(path, perm)
352    }
353
354    /// Query the metadata about a file without following symlinks.
355    ///
356    /// This corresponds to [`std::fs::symlink_metadata`], but only accesses
357    /// paths relative to `self`.
358    #[inline]
359    pub fn symlink_metadata<P: AsRef<Utf8Path>>(&self, path: P) -> io::Result<Metadata> {
360        let path = from_utf8(path.as_ref())?;
361        self.cap_std.symlink_metadata(path)
362    }
363
364    /// Write a slice as the entire contents of a file.
365    ///
366    /// This corresponds to [`std::fs::write`], but only accesses paths
367    /// relative to `self`.
368    #[inline]
369    pub fn write<P: AsRef<Utf8Path>, C: AsRef<[u8]>>(
370        &self,
371        path: P,
372        contents: C,
373    ) -> io::Result<()> {
374        let path = from_utf8(path.as_ref())?;
375        self.cap_std.write(path, contents)
376    }
377
378    /// Creates a new symbolic link on a filesystem.
379    ///
380    /// The `original` argument provides the target of the symlink. The `link`
381    /// argument provides the name of the created symlink.
382    ///
383    /// Despite the argument ordering, `original` is not resolved relative to
384    /// `self` here. `link` is resolved relative to `self`, and `original` is
385    /// not resolved within this function.
386    ///
387    /// The `link` path is resolved when the symlink is dereferenced, relative
388    /// to the directory that contains it.
389    ///
390    /// This corresponds to [`std::os::unix::fs::symlink`], but only accesses
391    /// paths relative to `self`.
392    ///
393    /// Unlike [`symlink_contents`] this method will return an error if `original` is an absolute
394    /// path.
395    ///
396    /// [`std::os::unix::fs::symlink`]: https://doc.rust-lang.org/std/os/unix/fs/fn.symlink.html
397    #[cfg(not(windows))]
398    #[inline]
399    pub fn symlink<P: AsRef<Utf8Path>, Q: AsRef<Utf8Path>>(
400        &self,
401        original: P,
402        link: Q,
403    ) -> io::Result<()> {
404        let original = from_utf8(original.as_ref())?;
405        let link = from_utf8(link.as_ref())?;
406        self.cap_std.symlink(original, link)
407    }
408
409    /// Creates a new symbolic link on a filesystem.
410    ///
411    /// The `original` argument provides the target of the symlink. The `link`
412    /// argument provides the name of the created symlink.
413    ///
414    /// Despite the argument ordering, `original` is not resolved relative to
415    /// `self` here. `link` is resolved relative to `self`, and `original` is
416    /// not resolved within this function.
417    ///
418    /// The `link` path is resolved when the symlink is dereferenced, relative
419    /// to the directory that contains it.
420    ///
421    /// This corresponds to [`std::os::unix::fs::symlink`], but only accesses
422    /// paths relative to `self`.
423    ///
424    /// [`std::os::unix::fs::symlink`]: https://doc.rust-lang.org/std/os/unix/fs/fn.symlink.html
425    #[cfg(not(windows))]
426    #[inline]
427    pub fn symlink_contents<P: AsRef<Utf8Path>, Q: AsRef<Utf8Path>>(
428        &self,
429        original: P,
430        link: Q,
431    ) -> io::Result<()> {
432        let original = from_utf8(original.as_ref())?;
433        let link = from_utf8(link.as_ref())?;
434        self.cap_std.symlink_contents(original, link)
435    }
436
437    /// Creates a new file symbolic link on a filesystem.
438    ///
439    /// The `original` argument provides the target of the symlink. The `link`
440    /// argument provides the name of the created symlink.
441    ///
442    /// Despite the argument ordering, `original` is not resolved relative to
443    /// `self` here. `link` is resolved relative to `self`, and `original` is
444    /// not resolved within this function.
445    ///
446    /// The `link` path is resolved when the symlink is dereferenced, relative
447    /// to the directory that contains it.
448    ///
449    /// This corresponds to [`std::os::windows::fs::symlink_file`], but only
450    /// accesses paths relative to `self`.
451    ///
452    /// [`std::os::windows::fs::symlink_file`]: https://doc.rust-lang.org/std/os/windows/fs/fn.symlink_file.html
453    #[cfg(windows)]
454    #[inline]
455    pub fn symlink_file<P: AsRef<Utf8Path>, Q: AsRef<Utf8Path>>(
456        &self,
457        original: P,
458        link: Q,
459    ) -> io::Result<()> {
460        let original = from_utf8(original.as_ref())?;
461        let link = from_utf8(link.as_ref())?;
462        self.cap_std.symlink_file(original, link)
463    }
464
465    /// Creates a new directory symlink on a filesystem.
466    ///
467    /// The `original` argument provides the target of the symlink. The `link`
468    /// argument provides the name of the created symlink.
469    ///
470    /// Despite the argument ordering, `original` is not resolved relative to
471    /// `self` here. `link` is resolved relative to `self`, and `original` is
472    /// not resolved within this function.
473    ///
474    /// The `link` path is resolved when the symlink is dereferenced, relative
475    /// to the directory that contains it.
476    ///
477    /// This corresponds to [`std::os::windows::fs::symlink_dir`], but only
478    /// accesses paths relative to `self`.
479    ///
480    /// [`std::os::windows::fs::symlink_dir`]: https://doc.rust-lang.org/std/os/windows/fs/fn.symlink_dir.html
481    #[cfg(windows)]
482    #[inline]
483    pub fn symlink_dir<P: AsRef<Utf8Path>, Q: AsRef<Utf8Path>>(
484        &self,
485        original: P,
486        link: Q,
487    ) -> io::Result<()> {
488        let original = from_utf8(original.as_ref())?;
489        let link = from_utf8(link.as_ref())?;
490        self.cap_std.symlink_dir(original, link)
491    }
492
493    /// Creates a new `UnixListener` bound to the specified socket.
494    ///
495    /// This corresponds to [`std::os::unix::net::UnixListener::bind`], but
496    /// only accesses paths relative to `self`.
497    ///
498    /// XXX: This function is not yet implemented.
499    ///
500    /// [`std::os::unix::net::UnixListener::bind`]: https://doc.rust-lang.org/std/os/unix/net/struct.UnixListener.html#method.bind
501    #[doc(alias = "bind")]
502    #[cfg(unix)]
503    #[inline]
504    pub fn bind_unix_listener<P: AsRef<Utf8Path>>(&self, path: P) -> io::Result<UnixListener> {
505        let path = from_utf8(path.as_ref())?;
506        self.cap_std.bind_unix_listener(path)
507    }
508
509    /// Connects to the socket named by path.
510    ///
511    /// This corresponds to [`std::os::unix::net::UnixStream::connect`], but
512    /// only accesses paths relative to `self`.
513    ///
514    /// XXX: This function is not yet implemented.
515    ///
516    /// [`std::os::unix::net::UnixStream::connect`]: https://doc.rust-lang.org/std/os/unix/net/struct.UnixStream.html#method.connect
517    #[doc(alias = "connect")]
518    #[cfg(unix)]
519    #[inline]
520    pub fn connect_unix_stream<P: AsRef<Utf8Path>>(&self, path: P) -> io::Result<UnixStream> {
521        let path = from_utf8(path.as_ref())?;
522        self.cap_std.connect_unix_stream(path)
523    }
524
525    /// Creates a Unix datagram socket bound to the given path.
526    ///
527    /// This corresponds to [`std::os::unix::net::UnixDatagram::bind`], but
528    /// only accesses paths relative to `self`.
529    ///
530    /// XXX: This function is not yet implemented.
531    ///
532    /// [`std::os::unix::net::UnixDatagram::bind`]: https://doc.rust-lang.org/std/os/unix/net/struct.UnixDatagram.html#method.bind
533    #[doc(alias = "bind")]
534    #[cfg(unix)]
535    #[inline]
536    pub fn bind_unix_datagram<P: AsRef<Utf8Path>>(&self, path: P) -> io::Result<UnixDatagram> {
537        let path = from_utf8(path.as_ref())?;
538        self.cap_std.bind_unix_datagram(path)
539    }
540
541    /// Connects the socket to the specified address.
542    ///
543    /// This corresponds to [`std::os::unix::net::UnixDatagram::connect`], but
544    /// only accesses paths relative to `self`.
545    ///
546    /// XXX: This function is not yet implemented.
547    ///
548    /// [`std::os::unix::net::UnixDatagram::connect`]: https://doc.rust-lang.org/std/os/unix/net/struct.UnixDatagram.html#method.connect
549    #[doc(alias = "connect")]
550    #[cfg(unix)]
551    #[inline]
552    pub fn connect_unix_datagram<P: AsRef<Utf8Path>>(
553        &self,
554        unix_datagram: &UnixDatagram,
555        path: P,
556    ) -> io::Result<()> {
557        let path = from_utf8(path.as_ref())?;
558        self.cap_std.connect_unix_datagram(unix_datagram, path)
559    }
560
561    /// Sends data on the socket to the specified address.
562    ///
563    /// This corresponds to [`std::os::unix::net::UnixDatagram::send_to`], but
564    /// only accesses paths relative to `self`.
565    ///
566    /// XXX: This function is not yet implemented.
567    ///
568    /// [`std::os::unix::net::UnixDatagram::send_to`]: https://doc.rust-lang.org/std/os/unix/net/struct.UnixDatagram.html#method.send_to
569    #[doc(alias = "send_to")]
570    #[cfg(unix)]
571    #[inline]
572    pub fn send_to_unix_datagram_addr<P: AsRef<Utf8Path>>(
573        &self,
574        unix_datagram: &UnixDatagram,
575        buf: &[u8],
576        path: P,
577    ) -> io::Result<usize> {
578        let path = from_utf8(path.as_ref())?;
579        self.cap_std
580            .send_to_unix_datagram_addr(unix_datagram, buf, path)
581    }
582
583    /// Creates a new `Dir` instance that shares the same underlying file
584    /// handle as the existing `Dir` instance.
585    #[inline]
586    pub fn try_clone(&self) -> io::Result<Self> {
587        Ok(Self {
588            cap_std: self.cap_std.try_clone()?,
589        })
590    }
591
592    /// Returns `true` if the path points at an existing entity.
593    ///
594    /// This corresponds to [`std::path::Path::exists`], but only
595    /// accesses paths relative to `self`.
596    #[inline]
597    pub fn exists<P: AsRef<Utf8Path>>(&self, path: P) -> bool {
598        match from_utf8(path.as_ref()) {
599            Ok(path) => self.cap_std.exists(path),
600            Err(_) => false,
601        }
602    }
603
604    /// Returns `true` if the path points at an existing entity.
605    ///
606    /// This corresponds to [`std::path::Path::exists`], but only
607    /// accesses paths relative to `self`.
608    #[inline]
609    pub fn try_exists<P: AsRef<Utf8Path>>(&self, path: P) -> io::Result<bool> {
610        self.cap_std.try_exists(from_utf8(path.as_ref())?)
611    }
612
613    /// Returns `true` if the path exists on disk and is pointing at a regular
614    /// file.
615    ///
616    /// This corresponds to [`std::path::Path::is_file`], but only
617    /// accesses paths relative to `self`.
618    #[inline]
619    pub fn is_file<P: AsRef<Utf8Path>>(&self, path: P) -> bool {
620        match from_utf8(path.as_ref()) {
621            Ok(path) => self.cap_std.is_file(path),
622            Err(_) => false,
623        }
624    }
625
626    /// Checks if `path` is a directory.
627    ///
628    /// This is similar to [`std::path::Path::is_dir`] in that it checks if
629    /// `path` relative to `Dir` is a directory. This function will
630    /// traverse symbolic links to query information about the destination
631    /// file. In case of broken symbolic links, this will return `false`.
632    #[inline]
633    pub fn is_dir<P: AsRef<Utf8Path>>(&self, path: P) -> bool {
634        match from_utf8(path.as_ref()) {
635            Ok(path) => self.cap_std.is_dir(path),
636            Err(_) => false,
637        }
638    }
639
640    /// Constructs a new instance of `Self` by opening the given path as a
641    /// directory using the host process' ambient authority.
642    ///
643    /// # Ambient Authority
644    ///
645    /// This function is not sandboxed and may access any path that the host
646    /// process has access to.
647    #[inline]
648    pub fn open_ambient_dir<P: AsRef<Utf8Path>>(
649        path: P,
650        ambient_authority: AmbientAuthority,
651    ) -> io::Result<Self> {
652        let path = from_utf8(path.as_ref())?;
653        crate::fs::Dir::open_ambient_dir(path, ambient_authority).map(Self::from_cap_std)
654    }
655
656    /// Constructs a new instance of `Self` by opening the parent directory
657    /// (aka "..") of `self`, using the host process' ambient authority.
658    ///
659    /// # Ambient Authority
660    ///
661    /// This function accesses a directory outside of the `self` subtree.
662    #[inline]
663    pub fn open_parent_dir(&self, ambient_authority: AmbientAuthority) -> io::Result<Self> {
664        self.cap_std
665            .open_parent_dir(ambient_authority)
666            .map(Self::from_cap_std)
667    }
668
669    /// Recursively create a directory and all of its parent components if they
670    /// are missing, using the host process' ambient authority.
671    ///
672    /// # Ambient Authority
673    ///
674    /// This function is not sandboxed and may access any path that the host
675    /// process has access to.
676    #[inline]
677    pub fn create_ambient_dir_all<P: AsRef<Utf8Path>>(
678        path: P,
679        ambient_authority: AmbientAuthority,
680    ) -> io::Result<()> {
681        let _ = ambient_authority;
682        let path = from_utf8(path.as_ref())?;
683        fs::create_dir_all(path)
684    }
685
686    /// Construct a new instance of `Self` from existing directory file
687    /// descriptor.
688    ///
689    /// This can be useful when interacting with other libraries and or C/C++
690    /// code which has invoked `openat(..., O_DIRECTORY)` external to this
691    /// crate.
692    pub fn reopen_dir<Filelike: AsFilelike>(dir: &Filelike) -> io::Result<Self> {
693        cap_primitives::fs::open_dir(
694            &dir.as_filelike_view::<std::fs::File>(),
695            std::path::Component::CurDir.as_ref(),
696        )
697        .map(Self::from_std_file)
698    }
699}
700
701#[cfg(not(windows))]
702impl FromRawFd for Dir {
703    #[inline]
704    unsafe fn from_raw_fd(fd: RawFd) -> Self {
705        Self::from_std_file(fs::File::from_raw_fd(fd))
706    }
707}
708
709#[cfg(not(windows))]
710impl From<OwnedFd> for Dir {
711    #[inline]
712    fn from(fd: OwnedFd) -> Self {
713        Self::from_std_file(fs::File::from(fd))
714    }
715}
716
717#[cfg(windows)]
718impl FromRawHandle for Dir {
719    /// To prevent race conditions on Windows, the handle must be opened
720    /// without `FILE_SHARE_DELETE`.
721    #[inline]
722    unsafe fn from_raw_handle(handle: RawHandle) -> Self {
723        Self::from_std_file(fs::File::from_raw_handle(handle))
724    }
725}
726
727#[cfg(windows)]
728impl From<OwnedHandle> for Dir {
729    /// To prevent race conditions on Windows, the handle must be opened
730    /// without `FILE_SHARE_DELETE`.
731    #[inline]
732    fn from(handle: OwnedHandle) -> Self {
733        Self::from_std_file(fs::File::from(handle))
734    }
735}
736
737#[cfg(not(windows))]
738impl AsRawFd for Dir {
739    #[inline]
740    fn as_raw_fd(&self) -> RawFd {
741        self.cap_std.as_raw_fd()
742    }
743}
744
745#[cfg(not(windows))]
746impl AsFd for Dir {
747    #[inline]
748    fn as_fd(&self) -> BorrowedFd<'_> {
749        self.cap_std.as_fd()
750    }
751}
752
753// Safety: `FilelikeViewType` is implemented for `std::fs::File`.
754unsafe impl io_lifetimes::views::FilelikeViewType for Dir {}
755
756#[cfg(windows)]
757impl AsRawHandle for Dir {
758    #[inline]
759    fn as_raw_handle(&self) -> RawHandle {
760        self.cap_std.as_raw_handle()
761    }
762}
763
764#[cfg(windows)]
765impl AsHandle for Dir {
766    #[inline]
767    fn as_handle(&self) -> BorrowedHandle<'_> {
768        self.cap_std.as_handle()
769    }
770}
771
772#[cfg(windows)]
773impl AsRawHandleOrSocket for Dir {
774    #[inline]
775    fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket {
776        self.cap_std.as_raw_handle_or_socket()
777    }
778}
779
780#[cfg(windows)]
781impl AsHandleOrSocket for Dir {
782    #[inline]
783    fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> {
784        self.cap_std.as_handle_or_socket()
785    }
786}
787
788#[cfg(not(windows))]
789impl IntoRawFd for Dir {
790    #[inline]
791    fn into_raw_fd(self) -> RawFd {
792        self.cap_std.into_raw_fd()
793    }
794}
795
796#[cfg(not(windows))]
797impl From<Dir> for OwnedFd {
798    #[inline]
799    fn from(dir: Dir) -> OwnedFd {
800        dir.cap_std.into()
801    }
802}
803
804#[cfg(windows)]
805impl IntoRawHandle for Dir {
806    #[inline]
807    fn into_raw_handle(self) -> RawHandle {
808        self.cap_std.into_raw_handle()
809    }
810}
811
812#[cfg(windows)]
813impl From<Dir> for OwnedHandle {
814    #[inline]
815    fn from(dir: Dir) -> OwnedHandle {
816        dir.cap_std.into()
817    }
818}
819
820#[cfg(windows)]
821impl IntoRawHandleOrSocket for Dir {
822    #[inline]
823    fn into_raw_handle_or_socket(self) -> RawHandleOrSocket {
824        self.cap_std.into_raw_handle_or_socket()
825    }
826}
827
828#[cfg(windows)]
829impl From<Dir> for OwnedHandleOrSocket {
830    #[inline]
831    fn from(dir: Dir) -> Self {
832        dir.cap_std.into()
833    }
834}
835
836impl fmt::Debug for Dir {
837    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
838        self.cap_std.fmt(f)
839    }
840}
841
842impl AsRef<crate::fs::Dir> for Dir {
843    fn as_ref(&self) -> &crate::fs::Dir {
844        self.as_cap_std()
845    }
846}