Coverage Report

Created: 2025-10-13 06:42

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