Skip to content

Commit fb73858

Browse files
jiangliubergwolf
authored andcommitted
ptfs: check mount id by using statx()
Import implementation of `statx()` and validate mount id when getting mount fd. Signed-off-by: Jiang Liu <[email protected]>
1 parent fa4471e commit fb73858

File tree

4 files changed

+64
-80
lines changed

4 files changed

+64
-80
lines changed

src/passthrough/file_status.rs

Lines changed: 0 additions & 54 deletions
This file was deleted.

src/passthrough/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ mod async_io;
4545
mod file_handle;
4646
mod inode_store;
4747
mod mount_fd;
48+
mod statx;
4849
mod sync_io;
4950

5051
type Inode = u64;

src/passthrough/mount_fd.rs

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use std::io::{self, Read, Seek};
88
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
99
use std::sync::{Arc, Mutex, RwLock, Weak};
1010

11-
use super::PassthroughFs;
11+
use super::statx::statx;
1212

1313
const MOUNT_INFO_FILE: &str = "/proc/self/mountinfo";
1414

@@ -195,9 +195,7 @@ impl MountFds {
195195
mount_point_file: &File,
196196
mount_point: &str,
197197
) -> MPRResult<libc::mode_t> {
198-
// liubo: TODO find mnt id
199-
/*
200-
let stx = statx(&mount_point_path, None).map_err(|e| {
198+
let stx = statx(mount_point_file, None).map_err(|e| {
201199
self.error_for(mount_id, e)
202200
.prefix(format!("Failed to stat mount point \"{mount_point}\""))
203201
})?;
@@ -210,13 +208,8 @@ impl MountFds {
210208
mount_point, stx.mnt_id, mount_id
211209
)));
212210
}
213-
*/
214-
let st = PassthroughFs::<()>::stat_fd(mount_point_file.as_raw_fd(), None).map_err(|e| {
215-
self.error_for(mount_id, e)
216-
.prefix(format!("Failed to stat mount point \"{mount_point}\""))
217-
})?;
218211

219-
Ok(st.st_mode)
212+
Ok(stx.st.st_mode)
220213
}
221214

222215
/// Given a mount ID, return the mount root path (by reading `/proc/self/mountinfo`)

src/passthrough/stat.rs renamed to src/passthrough/statx.rs

Lines changed: 60 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,60 @@ use std::io;
77
use std::mem::MaybeUninit;
88
use std::os::unix::io::AsRawFd;
99

10-
mod file_status;
11-
use crate::oslib;
12-
use file_status::{statx_st, STATX_BASIC_STATS, STATX_MNT_ID};
10+
use super::FileHandle;
11+
use crate::api::EMPTY_CSTR;
12+
13+
#[cfg(target_env = "gnu")]
14+
pub use libc::statx as statx_st;
15+
16+
#[cfg(target_env = "gnu")]
17+
pub use libc::{STATX_BASIC_STATS, STATX_MNT_ID};
18+
19+
// musl provides the 'struct statx', but without stx_mnt_id.
20+
// However, the libc crate does not provide libc::statx
21+
// if musl is used. So we add just the required struct and
22+
// constants to make it works.
23+
#[cfg(not(target_env = "gnu"))]
24+
#[repr(C)]
25+
pub struct statx_st_timestamp {
26+
pub tv_sec: i64,
27+
pub tv_nsec: u32,
28+
pub __statx_timestamp_pad1: [i32; 1],
29+
}
30+
31+
#[cfg(not(target_env = "gnu"))]
32+
#[repr(C)]
33+
pub struct statx_st {
34+
pub stx_mask: u32,
35+
pub stx_blksize: u32,
36+
pub stx_attributes: u64,
37+
pub stx_nlink: u32,
38+
pub stx_uid: u32,
39+
pub stx_gid: u32,
40+
pub stx_mode: u16,
41+
__statx_pad1: [u16; 1],
42+
pub stx_ino: u64,
43+
pub stx_size: u64,
44+
pub stx_blocks: u64,
45+
pub stx_attributes_mask: u64,
46+
pub stx_atime: statx_st_timestamp,
47+
pub stx_btime: statx_st_timestamp,
48+
pub stx_ctime: statx_st_timestamp,
49+
pub stx_mtime: statx_st_timestamp,
50+
pub stx_rdev_major: u32,
51+
pub stx_rdev_minor: u32,
52+
pub stx_dev_major: u32,
53+
pub stx_dev_minor: u32,
54+
pub stx_mnt_id: u64,
55+
__statx_pad2: u64,
56+
__statx_pad3: [u64; 12],
57+
}
1358

14-
const EMPTY_CSTR: &[u8] = b"\0";
59+
#[cfg(not(target_env = "gnu"))]
60+
pub const STATX_BASIC_STATS: libc::c_uint = 0x07ff;
61+
62+
#[cfg(not(target_env = "gnu"))]
63+
pub const STATX_MNT_ID: libc::c_uint = 0x1000;
1564

1665
pub type MountId = u64;
1766

@@ -84,12 +133,9 @@ impl SafeStatXAccess for statx_st {
84133
}
85134

86135
fn get_mount_id(dir: &impl AsRawFd, path: &CStr) -> Option<MountId> {
87-
let mut mount_id: libc::c_int = 0;
88-
let mut c_fh = oslib::CFileHandle::default();
89-
90-
oslib::name_to_handle_at(dir, path, &mut c_fh, &mut mount_id, libc::AT_EMPTY_PATH)
136+
FileHandle::from_name_at(dir.as_raw_fd(), path)
137+
.map(|v| v.mnt_id)
91138
.ok()
92-
.and(Some(mount_id as MountId))
93139
}
94140

95141
// Only works on Linux, and libc::SYS_statx is only defined for these
@@ -109,7 +155,7 @@ unsafe fn do_statx(
109155
libc::syscall(libc::SYS_statx, dirfd, pathname, flags, mask, statxbuf) as libc::c_int
110156
}
111157

112-
// Real statx() that depends on do_statx()
158+
/// Execute `statx()` to get extended status with mount id.
113159
pub fn statx(dir: &impl AsRawFd, path: Option<&CStr>) -> io::Result<StatExt> {
114160
let mut stx_ui = MaybeUninit::<statx_st>::zeroed();
115161

@@ -138,13 +184,11 @@ pub fn statx(dir: &impl AsRawFd, path: Option<&CStr>) -> io::Result<StatExt> {
138184
.mount_id()
139185
.or_else(|| get_mount_id(dir, path))
140186
.unwrap_or(0);
187+
let st = stx
188+
.stat64()
189+
.ok_or_else(|| io::Error::from_raw_os_error(libc::ENOSYS))?;
141190

142-
Ok(StatExt {
143-
st: stx
144-
.stat64()
145-
.ok_or_else(|| io::Error::from_raw_os_error(libc::ENOSYS))?,
146-
mnt_id,
147-
})
191+
Ok(StatExt { st, mnt_id })
148192
} else {
149193
Err(io::Error::last_os_error())
150194
}

0 commit comments

Comments
 (0)