Function cap_primitives::fs::open
source · pub fn open(start: &File, path: &Path, options: &OpenOptions) -> Result<File>
Expand description
Perform an openat
-like operation, ensuring that the resolution of the
path never escapes the directory tree rooted at start
.
Examples found in repository?
src/fs/open_dir.rs (line 16)
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
pub fn open_dir(start: &fs::File, path: &Path) -> io::Result<fs::File> {
open(start, path, &dir_options())
}
/// Like `open_dir`, but additionally request the ability to read the directory
/// entries.
#[cfg(not(windows))]
#[inline]
pub(crate) fn open_dir_for_reading(
start: &fs::File,
path: &Path,
follow: FollowSymlinks,
) -> io::Result<fs::File> {
open(start, path, readdir_options().follow(follow))
}
/// Similar to `open_dir`, but fails if the path names a symlink.
#[inline]
pub fn open_dir_nofollow(start: &fs::File, path: &Path) -> io::Result<fs::File> {
open(start, path, dir_options().follow(FollowSymlinks::No))
}
More examples
src/rustix/fs/copy_impl.rs (line 17)
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
fn open_from(start: &fs::File, path: &Path) -> io::Result<(fs::File, fs::Metadata)> {
let reader = open(start, path, OpenOptions::new().read(true))?;
let metadata = reader.metadata()?;
if !metadata.is_file() {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
"the source path is not an existing regular file",
));
}
Ok((reader, metadata))
}
#[cfg(not(target_os = "wasi"))]
fn open_to_and_set_permissions(
start: &fs::File,
path: &Path,
reader_metadata: fs::Metadata,
) -> io::Result<(fs::File, fs::Metadata)> {
use rustix::fs::OpenOptionsExt;
use std::os::unix::fs::PermissionsExt;
let perm = reader_metadata.permissions();
let writer = open(
start,
path,
OpenOptions::new()
// create the file with the correct mode right away
.mode(perm.mode())
.write(true)
.create(true)
.truncate(true),
)?;
let writer_metadata = writer.metadata()?;
if writer_metadata.is_file() {
// Set the correct file permissions, in case the file already existed.
// Don't set the permissions on already existing non-files like
// pipes/FIFOs or device nodes.
writer.set_permissions(perm)?;
}
Ok((writer, writer_metadata))
}
src/rustix/linux/fs/procfs.rs (lines 39-45)
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
pub(crate) fn set_permissions_through_proc_self_fd(
start: &fs::File,
path: &Path,
perm: fs::Permissions,
) -> io::Result<()> {
let opath = open(
start,
path,
OpenOptions::new()
.read(true)
.custom_flags(OFlags::PATH.bits() as i32),
)?;
let dirfd = proc_self_fd()?;
let mode = Mode::from_bits(perm.mode() as RawMode).ok_or_else(errors::invalid_flags)?;
Ok(chmodat(&dirfd, DecInt::from_fd(&opath), mode)?)
}
pub(crate) fn set_times_through_proc_self_fd(
start: &fs::File,
path: &Path,
atime: Option<SystemTimeSpec>,
mtime: Option<SystemTimeSpec>,
) -> io::Result<()> {
let opath = open(
start,
path,
OpenOptions::new()
.read(true)
.custom_flags(OFlags::PATH.bits() as i32),
)?;
// Don't pass `AT_SYMLINK_NOFOLLOW`, because we do actually want to follow
// the first symlink. We don't want to follow any subsequent symlinks, but
// omitting `O_NOFOLLOW` above ensures that the destination of the link
// isn't a symlink.
set_times_follow_unchecked(
proc_self_fd()?.as_fd(),
DecInt::from_fd(&opath).as_ref(),
atime,
mtime,
)
}
src/rustix/linux/fs/set_times_impl.rs (line 17)
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
pub(crate) fn set_times_impl(
start: &fs::File,
path: &Path,
atime: Option<SystemTimeSpec>,
mtime: Option<SystemTimeSpec>,
) -> io::Result<()> {
// Try `futimens` with a normal handle. Normal handles need some kind of
// access, so first try write.
match open(start, path, OpenOptions::new().write(true)) {
Ok(file) => {
return fs_set_times::SetTimes::set_times(
&file,
atime.map(SystemTimeSpec::into_std),
mtime.map(SystemTimeSpec::into_std),
)
}
Err(err) => match rustix::io::Errno::from_io_error(&err) {
Some(rustix::io::Errno::ACCESS) | Some(rustix::io::Errno::ISDIR) => (),
_ => return Err(err),
},
}
// Next try read.
match open(start, path, OpenOptions::new().read(true)) {
Ok(file) => {
return fs_set_times::SetTimes::set_times(
&file,
atime.map(SystemTimeSpec::into_std),
mtime.map(SystemTimeSpec::into_std),
)
}
Err(err) => match rustix::io::Errno::from_io_error(&err) {
Some(rustix::io::Errno::ACCESS) => (),
_ => return Err(err),
},
}
// If neither of those worked, turn to `/proc`.
set_times_through_proc_self_fd(start, path, atime, mtime)
}
src/rustix/linux/fs/set_permissions_impl.rs (line 29)
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
pub(crate) fn set_permissions_impl(
start: &fs::File,
path: &Path,
perm: Permissions,
) -> io::Result<()> {
let std_perm = perm.into_std(start)?;
// First try using `O_PATH` and doing a chmod on `/proc/self/fd/{}`
// (`fchmod` doesn't work on `O_PATH` file descriptors).
//
// This may fail, due to older Linux versions not supporting `O_PATH`, or
// due to procfs being unavailable, but if it does work, go with it, as
// `O_PATH` tells Linux that we don't actually need to read or write the
// file, which may avoid side effects associated with opening device files.
let result = set_permissions_through_proc_self_fd(start, path, std_perm.clone());
if let Ok(()) = result {
return Ok(());
}
// Then try `fchmod` with a normal handle. Normal handles need some kind of
// access, so first try read.
match open(start, path, OpenOptions::new().read(true)) {
Ok(file) => return set_file_permissions(&file, std_perm),
Err(err) => match rustix::io::Errno::from_io_error(&err) {
Some(rustix::io::Errno::ACCESS) => (),
_ => return Err(err),
},
}
// Next try write.
match open(start, path, OpenOptions::new().write(true)) {
Ok(file) => return set_file_permissions(&file, std_perm),
Err(err) => match rustix::io::Errno::from_io_error(&err) {
Some(rustix::io::Errno::ACCESS) | Some(rustix::io::Errno::ISDIR) => (),
_ => return Err(err),
},
}
// Nothing worked, so just return the original error.
result
}