cap_primitives/rustix/fs/
open_unchecked.rs

1use super::compute_oflags;
2use crate::fs::{stat_unchecked, OpenOptions, OpenUncheckedError};
3use crate::AmbientAuthority;
4use io_lifetimes::AsFilelike;
5use rustix::fs::{openat, Mode, CWD};
6use rustix::io;
7use std::fs;
8use std::path::Path;
9
10/// *Unsandboxed* function similar to `open`, but which does not perform
11/// sandboxing.
12pub(crate) fn open_unchecked(
13    start: &fs::File,
14    path: &Path,
15    options: &OpenOptions,
16) -> Result<fs::File, OpenUncheckedError> {
17    let oflags = compute_oflags(options).map_err(OpenUncheckedError::Other)?;
18
19    #[allow(clippy::useless_conversion)]
20    #[cfg(not(target_os = "wasi"))]
21    let mode = Mode::from_bits_truncate(options.ext.mode as _);
22    #[cfg(target_os = "wasi")]
23    let mode = Mode::empty();
24
25    let err = match openat(start, path, oflags, mode) {
26        Ok(file) => {
27            return Ok(fs::File::from(file));
28        }
29        Err(err) => err,
30    };
31    match err {
32        // `ELOOP` is the POSIX standard and most widely used error code to
33        // indicate that a symlink was found when `O_NOFOLLOW` was set.
34        #[cfg(not(any(target_os = "freebsd", target_os = "dragonfly", target_os = "netbsd")))]
35        io::Errno::LOOP => Err(OpenUncheckedError::Symlink(err.into(), ())),
36
37        // FreeBSD and similar (but not Darwin) use `EMLINK`.
38        #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
39        io::Errno::MLINK => Err(OpenUncheckedError::Symlink(err.into(), ())),
40
41        // NetBSD uses `EFTYPE`.
42        #[cfg(target_os = "netbsd")]
43        io::Errno::FTYPE => Err(OpenUncheckedError::Symlink(err.into(), ())),
44
45        io::Errno::NOENT => Err(OpenUncheckedError::NotFound(err.into())),
46        io::Errno::NOTDIR => {
47            if options.dir_required
48                && stat_unchecked(start, path, options.follow)
49                    .map(|m| m.file_type().is_symlink())
50                    .unwrap_or(false)
51            {
52                Err(OpenUncheckedError::Symlink(err.into(), ()))
53            } else {
54                Err(OpenUncheckedError::NotFound(err.into()))
55            }
56        }
57        _ => Err(OpenUncheckedError::Other(err.into())),
58    }
59}
60
61/// *Unsandboxed* function similar to `open`, but which does not perform
62/// sandboxing.
63#[inline]
64pub(crate) fn open_ambient_impl(
65    path: &Path,
66    options: &OpenOptions,
67    ambient_authority: AmbientAuthority,
68) -> Result<fs::File, OpenUncheckedError> {
69    let _ = ambient_authority;
70    open_unchecked(&CWD.as_filelike_view::<fs::File>(), path, options)
71}