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}