Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/fuse/src/mount.rs
5394 views
1
// Copyright 2020 The ChromiumOS Authors
2
// Use of this source code is governed by a BSD-style license that can be
3
// found in the LICENSE file.
4
5
use std::ffi::CString;
6
use std::ffi::OsStr;
7
use std::fmt;
8
use std::io;
9
use std::os::unix::ffi::OsStrExt;
10
use std::os::unix::io::RawFd;
11
12
/// Mount options to pass to mount(2) for a FUSE filesystem. See the [official document](
13
/// https://www.kernel.org/doc/html/latest/filesystems/fuse.html#mount-options) for the
14
/// descriptions.
15
pub enum MountOption<'a> {
16
FD(RawFd),
17
RootMode(u32),
18
UserId(libc::uid_t),
19
GroupId(libc::gid_t),
20
DefaultPermissions,
21
AllowOther,
22
MaxRead(u32),
23
BlockSize(u32),
24
// General mount options that are not specific to FUSE. Note that the value is not checked
25
// or interpreted by this library, but by kernel.
26
Extra(&'a str),
27
}
28
29
// Implement Display for ToString to convert to actual mount options.
30
impl fmt::Display for MountOption<'_> {
31
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
32
match &self {
33
MountOption::FD(fd) => write!(f, "fd={fd}"),
34
MountOption::RootMode(mode) => write!(f, "rootmode={mode:o}"),
35
MountOption::UserId(uid) => write!(f, "user_id={uid}"),
36
MountOption::GroupId(gid) => write!(f, "group_id={gid}"),
37
MountOption::DefaultPermissions => write!(f, "default_permissions"),
38
MountOption::AllowOther => write!(f, "allow_other"),
39
MountOption::MaxRead(size) => write!(f, "max_read={size}"),
40
MountOption::BlockSize(size) => write!(f, "blksize={size}"),
41
MountOption::Extra(text) => write!(f, "{text}"),
42
}
43
}
44
}
45
46
fn join_mount_options(options: &[MountOption]) -> String {
47
if !options.is_empty() {
48
let mut concat = options[0].to_string();
49
for opt in &options[1..] {
50
concat.push(',');
51
concat.push_str(&opt.to_string());
52
}
53
concat
54
} else {
55
String::new()
56
}
57
}
58
59
/// Initiates a FUSE mount at `mountpoint` directory with `flags` and `options` via mount(2). The
60
/// caller should provide a file descriptor (backed by /dev/fuse) with `MountOption::FD`. After
61
/// this function completes, the FUSE filesystem can start to handle the requests, e.g. via
62
/// `fuse::worker::start_message_loop()`.
63
///
64
/// This operation requires CAP_SYS_ADMIN privilege, but the privilege can be dropped afterward.
65
pub fn mount<P: AsRef<OsStr>>(
66
mountpoint: P,
67
name: &str,
68
flags: libc::c_ulong,
69
options: &[MountOption],
70
) -> Result<(), io::Error> {
71
let mount_name = CString::new(name.as_bytes())?;
72
let fs_type = CString::new(String::from("fuse.") + name)?;
73
let mountpoint = CString::new(mountpoint.as_ref().as_bytes())?;
74
let mount_options = CString::new(join_mount_options(options))?;
75
76
// SAFETY:
77
// Safe because pointer arguments all points to null-terminiated CStrings.
78
let retval = unsafe {
79
libc::mount(
80
mount_name.as_ptr(),
81
mountpoint.as_ptr(),
82
fs_type.as_ptr(),
83
flags,
84
mount_options.as_ptr() as *const std::ffi::c_void,
85
)
86
};
87
if retval < 0 {
88
Err(io::Error::last_os_error())
89
} else {
90
Ok(())
91
}
92
}
93
94
#[cfg(test)]
95
mod tests {
96
use super::*;
97
98
#[test]
99
fn basic_options_concatenate_in_order() {
100
assert_eq!("".to_string(), join_mount_options(&[]));
101
102
assert_eq!(
103
"fd=42".to_string(),
104
join_mount_options(&[MountOption::FD(42),])
105
);
106
107
assert_eq!(
108
"fd=42,rootmode=40111,allow_other,user_id=12,group_id=34,max_read=4096".to_string(),
109
join_mount_options(&[
110
MountOption::FD(42),
111
MountOption::RootMode(
112
libc::S_IFDIR | libc::S_IXUSR | libc::S_IXGRP | libc::S_IXOTH
113
),
114
MountOption::AllowOther,
115
MountOption::UserId(12),
116
MountOption::GroupId(34),
117
MountOption::MaxRead(4096),
118
])
119
);
120
121
assert_eq!(
122
"fd=42,default_permissions,user_id=12,group_id=34,max_read=4096".to_string(),
123
join_mount_options(&[
124
MountOption::FD(42),
125
MountOption::DefaultPermissions,
126
MountOption::UserId(12),
127
MountOption::GroupId(34),
128
MountOption::MaxRead(4096),
129
])
130
);
131
132
assert_eq!(
133
"option1=a,option2=b".to_string(),
134
join_mount_options(&[MountOption::Extra("option1=a,option2=b"),])
135
);
136
}
137
}
138
139