Skip to content
This repository has been archived by the owner on Nov 7, 2024. It is now read-only.

lib: Add mountutil module #551

Merged
merged 1 commit into from
Oct 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 1 addition & 37 deletions lib/src/commit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
//! <https://github.com/ostreedev/ostree-rs-ext/issues/159>

use crate::container_utils::require_ostree_container;
use crate::mountutil::is_mountpoint;
use anyhow::Context;
use anyhow::Result;
use camino::Utf8Path;
use cap_std::fs::Dir;
use cap_std_ext::cap_std;
use cap_std_ext::dirext::CapStdExtDirExt;
use io_lifetimes::AsFd;
use rustix::fs::MetadataExt;
use std::borrow::Cow;
use std::convert::TryInto;
Expand Down Expand Up @@ -102,28 +102,6 @@ fn remove_all_on_mount_recurse(root: &Dir, rootdev: u64, path: &Path) -> Result<
Ok(skipped)
}

/// Try to (heuristically) determine if the provided path is a mount root.
fn is_mountpoint(root: &Dir, path: &Path) -> Result<Option<bool>> {
// https://github.com/systemd/systemd/blob/8fbf0a214e2fe474655b17a4b663122943b55db0/src/basic/mountpoint-util.c#L176
use rustix::fs::{AtFlags, StatxFlags};

// SAFETY(unwrap): We can infallibly convert an i32 into a u64.
let mountroot_flag: u64 = libc::STATX_ATTR_MOUNT_ROOT.try_into().unwrap();
match rustix::fs::statx(
root.as_fd(),
path,
AtFlags::NO_AUTOMOUNT | AtFlags::SYMLINK_NOFOLLOW,
StatxFlags::empty(),
) {
Ok(r) => {
let present = (r.stx_attributes_mask & mountroot_flag) > 0;
Ok(present.then(|| r.stx_attributes & mountroot_flag > 0))
}
Err(e) if e == rustix::io::Errno::NOSYS => Ok(None),
Err(e) => Err(e.into()),
}
}

fn clean_subdir(root: &Dir, rootdev: u64) -> Result<()> {
for entry in root.entries()? {
let entry = entry?;
Expand Down Expand Up @@ -207,20 +185,6 @@ mod tests {
use super::*;
use cap_std_ext::cap_tempfile;

#[test]
fn test_is_mountpoint() -> Result<()> {
let root = cap_std::fs::Dir::open_ambient_dir("/", cap_std::ambient_authority())?;
let supported = is_mountpoint(&root, Path::new("/")).unwrap();
match supported {
Some(r) => assert!(r),
// If the host doesn't support statx, ignore this for now
None => return Ok(()),
}
let tmpdir = cap_tempfile::TempDir::new(cap_std::ambient_authority())?;
assert!(!is_mountpoint(&tmpdir, Path::new(".")).unwrap().unwrap());
Ok(())
}

#[test]
fn commit() -> Result<()> {
let td = &cap_tempfile::tempdir(cap_std::ambient_authority())?;
Expand Down
1 change: 1 addition & 0 deletions lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ pub mod diff;
pub mod ima;
pub mod keyfileext;
pub(crate) mod logging;
pub mod mountutil;
pub mod refescape;
#[doc(hidden)]
pub mod repair;
Expand Down
54 changes: 54 additions & 0 deletions lib/src/mountutil.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
//! Helpers for interacting with mounts.

use std::os::fd::AsFd;
use std::path::Path;

use anyhow::Result;
use cap_std::fs::Dir;
use cap_std_ext::cap_std;

fn is_mountpoint_impl_statx(root: &Dir, path: &Path) -> Result<Option<bool>> {
// https://github.com/systemd/systemd/blob/8fbf0a214e2fe474655b17a4b663122943b55db0/src/basic/mountpoint-util.c#L176
use rustix::fs::{AtFlags, StatxFlags};

// SAFETY(unwrap): We can infallibly convert an i32 into a u64.
let mountroot_flag: u64 = libc::STATX_ATTR_MOUNT_ROOT.try_into().unwrap();
match rustix::fs::statx(
root.as_fd(),
path,
AtFlags::NO_AUTOMOUNT | AtFlags::SYMLINK_NOFOLLOW,
StatxFlags::empty(),
) {
Ok(r) => {
let present = (r.stx_attributes_mask & mountroot_flag) > 0;
Ok(present.then(|| r.stx_attributes & mountroot_flag > 0))
}
Err(e) if e == rustix::io::Errno::NOSYS => Ok(None),
Err(e) => Err(e.into()),
}
}

/// Try to (heuristically) determine if the provided path is a mount root.
pub fn is_mountpoint(root: &Dir, path: impl AsRef<Path>) -> Result<Option<bool>> {
is_mountpoint_impl_statx(root, path.as_ref())
}

#[cfg(test)]
mod tests {
use super::*;
use cap_std_ext::cap_tempfile;

#[test]
fn test_is_mountpoint() -> Result<()> {
let root = cap_std::fs::Dir::open_ambient_dir("/", cap_std::ambient_authority())?;
let supported = is_mountpoint(&root, Path::new("/")).unwrap();
match supported {
Some(r) => assert!(r),
// If the host doesn't support statx, ignore this for now
None => return Ok(()),
}
let tmpdir = cap_tempfile::TempDir::new(cap_std::ambient_authority())?;
assert!(!is_mountpoint(&tmpdir, Path::new(".")).unwrap().unwrap());
Ok(())
}
}
Loading