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

Commit

Permalink
Merge pull request #551 from cgwalters/add-mountpoint-util-check
Browse files Browse the repository at this point in the history
lib: Add mountutil module
  • Loading branch information
jmarrero authored Oct 2, 2023
2 parents c242539 + 77164e5 commit e435628
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 37 deletions.
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(())
}
}

0 comments on commit e435628

Please sign in to comment.