1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/openeuler-stratovirt

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
В этом репозитории не указан файл с открытой лицензией (LICENSE). При использовании обратитесь к конкретному описанию проекта и его зависимостям в коде.
Клонировать/Скачать
fs.rs 59 КБ
Копировать Редактировать Исходные данные Просмотреть построчно История
Li HuaChao Отправлено 2 лет назад f39d566
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965
// Copyright (c) 2022 Huawei Technologies Co.,Ltd. All rights reserved.
//
// StratoVirt is licensed under Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan
// PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
// http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.
/// The map length used to extend the file/inode map.
const MAP_EXTEND_LENGTH: usize = 256;
const F_RDLCK: u32 = 0;
const F_WDLCK: u32 = 1;
const F_UNLCK: u32 = 2;
const RLIMIT_NOFILE_MIN: u64 = 20;
/// The inode 0 is reserved, 1 is root inode.
const ROOT_INODE: usize = 1;
use super::fs_ops::*;
use super::fuse_msg::*;
use crate::cmdline::FsConfig;
use anyhow::{bail, Context, Result};
use std::collections::{BTreeMap, HashMap};
use std::ffi::CString;
use std::fs::{read_to_string, File};
use std::mem;
use std::os::unix::io::{AsRawFd, RawFd};
use util::byte_code::ByteCode;
use util::num_ops::round_up;
/// Used as the key of the inode.
#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq)]
struct StatKey {
/// Inode number.
ino: libc::ino64_t,
/// ID of device containing file.
dev: libc::dev_t,
}
/// The entry of the inode/file.
struct Entry<T> {
/// The value stored in the Entry.
value: Option<T>,
/// If the entry is used or not.
used: bool,
/// The next free entry.
free_next: usize,
}
/// The map used to store inodes/files.
struct Map<T> {
/// The vector used to store Entry.
list: Vec<Entry<T>>,
/// The first free entry in list.
free_head: usize,
}
impl<T> Map<T> {
fn new() -> Self {
Map {
list: Vec::new(),
free_head: ROOT_INODE,
}
}
fn destroy_map(&mut self) {
self.list = Vec::new();
self.free_head = ROOT_INODE;
}
/// Add MAP_EXTEND_LENGTH elems to the map.
fn extend_map(&mut self) {
let mut next = self.list.len();
for _ in 0..MAP_EXTEND_LENGTH {
next += 1;
self.list.push(Entry {
value: None,
used: false,
free_next: next,
});
}
}
/// Add entry to the map.
fn get_map(&mut self, value: T) -> usize {
let id = self.free_head;
if id == ROOT_INODE || id == self.list.len() {
self.extend_map();
}
match self.list.get_mut(id) {
Some(e) => {
e.value = Some(value);
e.used = true;
self.free_head = e.free_next;
id
}
None => 0,
}
}
/// Delete entry from the map.
fn put_map(&mut self, id: usize) {
if id >= self.list.len() {
return;
}
if let Some(e) = self.list.get_mut(id) {
if !e.used {
return;
}
e.value = None;
e.used = false;
e.free_next = self.free_head;
self.free_head = id
}
}
fn get_value(&self, id: usize) -> Option<&T> {
if let Some(e) = self.list.get(id) {
e.value.as_ref()
} else {
None
}
}
fn get_value_mut(&mut self, id: usize) -> Option<&mut T> {
if let Some(e) = self.list.get_mut(id) {
e.value.as_mut()
} else {
None
}
}
}
/// Used to lock file.
struct FileLock {
/// The owner of the lock
lock_owner: u64,
/// The file which is locked
file: File,
}
impl FileLock {
fn new(file: File, lock_owner: u64) -> Self {
FileLock { lock_owner, file }
}
}
impl Clone for FileLock {
fn clone(&self) -> Self {
FileLock {
lock_owner: self.lock_owner,
file: self.file.try_clone().unwrap(),
}
}
}
/// The inode info.
struct Inode {
/// The inode file.
file: File,
/// The refcount of the inode.
nlookup: u64,
/// Store the map index of the inode.
node_id: usize,
/// the file type.
file_type: u32,
/// The key of the inode.
key: StatKey,
/// The locks on the file of the Inode.
locks: HashMap<u64, FileLock>,
}
impl Inode {
fn new(file: File, nlookup: u64, node_id: usize, file_type: u32, key: StatKey) -> Self {
Inode {
file,
nlookup,
node_id,
file_type,
key,
locks: HashMap::new(),
}
}
fn as_raw_fd(&self) -> RawFd {
self.file.as_raw_fd()
}
}
impl Clone for Inode {
fn clone(&self) -> Self {
Inode {
file: self.file.try_clone().unwrap(),
nlookup: self.nlookup,
node_id: self.node_id,
file_type: self.file_type,
key: self.key,
locks: self.locks.clone(),
}
}
}
fn array_to_cstring(
#[cfg(target_arch = "x86_64")] array: &[i8],
#[cfg(target_arch = "aarch64")] array: &[u8],
) -> Result<(usize, CString)> {
let mut vec = Vec::new();
for item in array {
if *item == 0 {
break;
}
vec.push(*item as u8);
}
let len = vec.len();
if len == 0 {
bail!("convert array to CString failed")
}
let cstring = match CString::new(vec) {
Ok(c) => c,
Err(_) => bail!("convert array to CString failed"),
};
Ok((len, cstring))
}
fn path_is_dot(path: &CString) -> bool {
let bytes = path.as_bytes();
if bytes.len() == 1 && bytes[0] == b'.' {
return true;
}
false
}
fn path_is_dotdot(path: &CString) -> bool {
let bytes = path.as_bytes();
if bytes.len() == 2 && bytes[0] == b'.' && bytes[1] == b'.' {
return true;
}
false
}
/// Set file resources limits for the process. The limit value
/// must be more than or equal to 20 to ensure that the process
/// can start normally. The limit value must be less than or equal
/// to the value of "/proc/sys/fs/file-max" and "/proc/sys/fs/nr_open".
///
/// # Arguments
///
/// * `limit` - The limit value which needs to be set.
pub fn set_rlimit_nofile(limit: u64) -> Result<()> {
if limit < RLIMIT_NOFILE_MIN {
bail!(
"The limit {} exceeds minimum of files {}",
limit,
RLIMIT_NOFILE_MIN
);
}
let max_file_str =
read_to_string("/proc/sys/fs/file-max").with_context(|| "Failed to read file-max")?;
let max_file = max_file_str
.trim()
.parse::<u64>()
.with_context(|| "Failed to convert the string of max files")?;
if limit > max_file {
bail!("The limit {} exceeds maximum of files {}", limit, max_file);
}
let nr_open_str =
read_to_string("/proc/sys/fs/nr_open").with_context(|| "Failed to read nr_open")?;
let max_file = nr_open_str
.trim()
.parse::<u64>()
.with_context(|| "Failed to convert the string of nr_open")?;
if limit > max_file {
bail!(
"The limit {} exceeds maximum of nr_open {}",
limit,
max_file
);
}
let ret = set_rlimit(limit, limit);
if ret != FUSE_OK {
bail!("Failed to set rlimit, err: {}", ret);
}
Ok(())
}
/// The management structure of filesystem that contains the management of inodes
/// and the information of files in host directory which needs to be shared.
pub struct FileSystem {
root_inode: Inode,
inodes: BTreeMap<StatKey, Inode>,
inode_key_map: Map<StatKey>,
file_map: Map<File>,
proc_dir: File,
}
impl FileSystem {
/// Create a filesystem management structure.
///
/// # Arguments
///
/// * `source_dir` - The path of the host directory which needs to be shared.
pub fn new(fs_config: FsConfig) -> Result<Self> {
let root_dir = fs_config.root_dir.clone();
let (root_file_opt, ret) = open(CString::new(root_dir).unwrap(), libc::O_PATH);
if ret != FUSE_OK {
bail!("Failed to open root file {}", fs_config.root_dir);
}
let root_file = root_file_opt.unwrap();
let (stat, ret) = fstat_at(
&root_file,
CString::new("").unwrap(),
libc::AT_EMPTY_PATH | libc::AT_SYMLINK_NOFOLLOW,
);
if ret != FUSE_OK {
bail!("Failed to get stat of root file {}", fs_config.root_dir);
}
let key = StatKey {
ino: stat.st_ino,
dev: stat.st_dev,
};
let mut inode_key_map = Map::new();
let root_id = inode_key_map.get_map(key);
// The default folder nlookup is 2
let root_inode = Inode::new(root_file, 2, root_id, libc::S_IFDIR, key);
let mut inodes = BTreeMap::new();
inodes.insert(key, root_inode.clone());
Ok(FileSystem {
root_inode,
inodes,
inode_key_map,
file_map: Map::new(),
proc_dir: fs_config.proc_dir_opt.unwrap(),
})
}
fn find_inode(&self, node_id: usize) -> Option<&Inode> {
match self.inode_key_map.get_value(node_id) {
Some(k) => self.inodes.get(k),
_ => None,
}
}
fn find_mut_inode(&mut self, node_id: usize) -> Option<&mut Inode> {
match self.inode_key_map.get_value(node_id) {
Some(k) => self.inodes.get_mut(k),
_ => None,
}
}
fn unref_inode(&mut self, inode: &mut Inode, count: u64) {
if count > inode.nlookup {
inode.nlookup = 0;
} else {
inode.nlookup -= count;
}
if inode.nlookup == 0 {
self.inodes.remove(&inode.key);
self.inode_key_map.put_map(inode.node_id);
} else if let Some(inode_) = self.find_mut_inode(inode.node_id) {
inode_.nlookup = inode.nlookup;
}
}
fn create_file_lock(&mut self, node_id: usize, owner: u64) -> (Option<File>, i32) {
let proc_file = self.proc_dir.try_clone().unwrap();
let inode = match self.find_mut_inode(node_id) {
Some(inode_) => inode_,
None => return (None, libc::EBADF as i32),
};
if let Some(lock) = inode.locks.get_mut(&owner) {
return (Some(lock.file.try_clone().unwrap()), FUSE_OK);
}
if inode.file_type & libc::S_IFDIR == 0 && inode.file_type & libc::S_IFREG == 0 {
return (None, libc::EBADF as i32);
}
let (file_opt, ret) = open_at(
&proc_file,
CString::new(format!("{}", inode.as_raw_fd())).unwrap(),
libc::O_RDWR,
0,
);
if ret != FUSE_OK {
return (None, ret);
}
let file = file_opt.unwrap().try_clone().unwrap();
let file_lock = FileLock::new(file.try_clone().unwrap(), owner);
inode.locks.insert(owner, file_lock);
(Some(file), FUSE_OK)
}
fn delete_file_lock(&mut self, node_id: usize, owner: u64) -> i32 {
let inode = match self.find_mut_inode(node_id) {
Some(inode_) => inode_,
None => return libc::EBADF as i32,
};
inode.locks.remove(&owner);
FUSE_OK
}
fn internal_lookup(
&mut self,
parent_inode: &Inode,
name: CString,
node_id: &mut u64,
fuse_attr: &mut FuseAttr,
) -> i32 {
let mut son_name = name.clone();
if parent_inode.node_id == self.root_inode.node_id && path_is_dotdot(&name) {
son_name = CString::new(".").unwrap();
}
let (stat, ret) = fstat_at(
&parent_inode.file,
son_name.clone(),
libc::AT_EMPTY_PATH | libc::AT_SYMLINK_NOFOLLOW,
);
if ret != FUSE_OK {
return ret;
}
let key = StatKey {
ino: stat.st_ino,
dev: stat.st_dev,
};
if let Some(inode) = self.inodes.get_mut(&key) {
inode.nlookup += 1;
*node_id = inode.node_id as u64;
} else {
let (file_opt, ret) = open_at(
&parent_inode.file,
son_name,
libc::O_PATH | libc::O_NOFOLLOW,
0,
);
if ret != FUSE_OK {
return ret;
}
let map_id = self.inode_key_map.get_map(key);
if let Some(file) = file_opt {
self.inodes.insert(
key,
Inode::new(file, 1, map_id, stat.st_mode & libc::S_IFMT, key),
);
}
*node_id = map_id as u64;
};
*fuse_attr = FuseAttr::from_stat(stat);
FUSE_OK
}
/// Look up the directory or file information by name and reply attributes.
///
/// # Arguments
///
/// * `parent_nodeid` - The parent node id that is the starting directory to look up.
/// * `name` - The name that needs to be looked up.
/// * `node_id` - The node id that needs to be looked up by name.
/// * `fuse_attr` - The attributes that needs to be looked up by name.
pub fn lookup(
&mut self,
parent_nodeid: usize,
name: CString,
node_id: &mut u64,
fuse_attr: &mut FuseAttr,
) -> i32 {
let inode = match self.find_inode(parent_nodeid) {
Some(i) => i.clone(),
_ => {
return libc::EBADF as i32;
}
};
self.internal_lookup(&inode, name, node_id, fuse_attr)
}
/// When the nlookup of inode is reduced to 0, delete the inode from the management structure.
///
/// # Arguments
///
/// * `node_id` - The node id used to find the inode.
/// * `nlookup` - The number of nlookup for inode needs to be reduced.
pub fn forget(&mut self, node_id: usize, nlookup: u64) -> i32 {
let mut inode = match self.find_inode(node_id) {
Some(i) => i.clone(),
_ => {
return libc::EBADF as i32;
}
};
self.unref_inode(&mut inode, nlookup);
FUSE_OK
}
/// Get the attributes of a file or directory.
///
/// # Arguments
///
/// * `node_id` - The node id used to find the inode.
/// * `fuse_attr` - The attributes will be returned by the found inode.
pub fn getattr(&mut self, node_id: usize, fuse_attr: &mut FuseAttr) -> i32 {
let inode = match self.find_inode(node_id) {
Some(i) => i.clone(),
_ => {
return libc::EBADF as i32;
}
};
let (stat, ret) = fstat_at(
&inode.file,
CString::new("").unwrap(),
libc::AT_EMPTY_PATH | libc::AT_SYMLINK_NOFOLLOW,
);
if ret != FUSE_OK {
return ret;
}
*fuse_attr = FuseAttr::from_stat(stat);
FUSE_OK
}
/// Set the attributes of a file or directory.
///
/// # Arguments
///
/// * `node_id` - The node id used to find the inode.
/// * `attr` - The attributes will be set to the found inode.
/// * `fuse_attr` - The attributes will be returned by the found inode.
pub fn setattr(
&mut self,
node_id: usize,
attr: &FuseSetattrIn,
fuse_attr: &mut FuseAttr,
) -> i32 {
if attr.valid & FUSE_SET_ATTR_MODE != 0 {
if attr.valid & FATTR_FH != 0 {
match self.file_map.get_value(attr.fh as usize) {
Some(file) => {
let ret = fchmod(file, attr.mode);
if ret != FUSE_OK {
return ret;
}
}
_ => {
return libc::EBADF as i32;
}
};
} else {
match self.find_inode(node_id) {
Some(i) => {
let ret = fchmod_at(
&self.proc_dir,
CString::new(format!("{}", &i.file.as_raw_fd())).unwrap(),
attr.mode,
);
if ret != FUSE_OK {
return ret;
}
}
_ => {
return libc::EBADF as i32;
}
};
}
}
if attr.valid & (FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID) != 0 {
let uid = if attr.valid & FUSE_SET_ATTR_UID != 0 {
attr.uid
} else {
u32::MAX
};
let gid = if attr.valid & FUSE_SET_ATTR_GID != 0 {
attr.gid
} else {
u32::MAX
};
match self.find_inode(node_id) {
Some(i) => {
let ret = fchown_at(
&i.file,
CString::new("").unwrap(),
uid,
gid,
libc::AT_EMPTY_PATH | libc::AT_SYMLINK_NOFOLLOW,
);
if ret != FUSE_OK {
return ret;
}
}
_ => {
return libc::EBADF as i32;
}
};
}
if attr.valid & FUSE_SET_ATTR_SIZE != 0 {
if attr.valid & FATTR_FH != 0 {
match self.file_map.get_value(attr.fh as usize) {
Some(file) => {
let ret = ftruncate(file, attr.size);
if ret != FUSE_OK {
return ret;
}
}
_ => {
return libc::EBADF as i32;
}
};
} else {
match self.find_inode(node_id) {
Some(i) => {
if i.file_type & libc::S_IFREG == 0 && i.file_type & libc::S_IFDIR == 0 {
return libc::EBADF as i32;
}
let (file_opt, ret) = open_at(
&self.proc_dir,
CString::new(format!("{}", &i.file.as_raw_fd())).unwrap(),
libc::O_RDWR,
0,
);
if ret != FUSE_OK {
return ret;
}
if let Some(file) = file_opt {
let ret = ftruncate(&file, attr.size);
if ret != FUSE_OK {
return ret;
}
}
}
_ => {
return libc::EBADF as i32;
}
};
}
}
if attr.valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME) != 0 {
let (a_sec, a_nsec) = if attr.valid & FUSE_SET_ATTR_ATIME_NOW != 0 {
(0, libc::UTIME_NOW)
} else if attr.valid & FUSE_SET_ATTR_ATIME != 0 {
(attr.atime, attr.atimensec as i64)
} else {
(0, libc::UTIME_OMIT)
};
let (m_sec, m_nsec) = if attr.valid & FUSE_SET_ATTR_MTIME_NOW != 0 {
(0, libc::UTIME_NOW)
} else if attr.valid & FUSE_SET_ATTR_MTIME != 0 {
(attr.mtime, attr.mtimensec as i64)
} else {
(0, libc::UTIME_OMIT)
};
if attr.valid & FATTR_FH != 0 {
match self.file_map.get_value(attr.fh as usize) {
Some(file) => {
let ret = futimens(file, a_sec, a_nsec, m_sec, m_nsec);
if ret != FUSE_OK {
return ret;
}
}
_ => {
return libc::EBADF as i32;
}
};
} else {
match self.find_inode(node_id) {
Some(i) => {
let ret = utimensat(
&self.proc_dir,
CString::new(format!("{}", &i.file.as_raw_fd())).unwrap(),
a_sec,
a_nsec,
m_sec,
m_nsec,
0,
);
if ret != FUSE_OK {
return ret;
}
}
_ => {
return libc::EBADF as i32;
}
};
}
}
self.getattr(node_id, fuse_attr)
}
/// Get the contexts of the symbolic link into the buffer.
///
/// # Arguments
///
/// * `node_id` - The node id used to find the inode.
/// * `buff` - The buffer is saved by the contexts of the symbolic link.
pub fn readlink(&self, node_id: usize, buff: &mut Vec<u8>) -> i32 {
let inode = match self.find_inode(node_id) {
Some(i) => i.clone(),
None => {
return libc::EBADF as i32;
}
};
let (buf_opt, ret) = readlinkat(&inode.file, CString::new("").unwrap());
if ret != FUSE_OK {
return ret;
}
if let Some(mut buf) = buf_opt {
buff.append(&mut buf);
} else {
return libc::EBADF as i32;
}
FUSE_OK
}
/// Get the contexts of the symbolic link into the buffer.
///
/// # Arguments
///
/// * `in_header` - The in_header of fuse message used to get uid and gid.
/// * `name` - The target link name used to create a symbolic link.
/// * `link_name` - The link name that will be created a symbolic link.
/// * `node_id` - The node id that is found by name.
/// * `fuse_attr` - The attributes will be returned by the found inode.
pub fn symlink(
&mut self,
in_header: &FuseInHeader,
name: CString,
link_name: CString,
node_id: &mut u64,
fuse_attr: &mut FuseAttr,
) -> i32 {
let parent_inode = match self.find_inode(in_header.nodeid as usize) {
Some(i) => i.clone(),
_ => {
return libc::EBADF as i32;
}
};
let mut old_uid = 0_u32;
let mut old_gid = 0_u32;
let ret = change_uid_gid(in_header.uid, in_header.gid, &mut old_uid, &mut old_gid);
if ret != FUSE_OK {
return ret;
}
let ret = symlinkat(&parent_inode.file, name.clone(), link_name);
recover_uid_gid(old_uid, old_gid);
if ret != FUSE_OK {
return ret;
}
self.internal_lookup(&parent_inode, name, node_id, fuse_attr)
}
/// Create a file system node(file, device special file or named pipe) by the path name
/// with the mode and dev in the mknod information.
///
/// # Arguments
///
/// * `in_header` - The in_header of fuse message used to get uid and gid.
/// * `mknod_in` - The information of mknod to get the permissions and dev.
/// * `name` - The path name used to create a file system node.
/// * `node_id` - The node id that is found by name.
/// * `fuse_attr` - The attributes will be returned by the found inode.
pub fn mknod(
&mut self,
in_header: &FuseInHeader,
mknod_in: &FuseMknodIn,
name: CString,
node_id: &mut u64,
fuse_attr: &mut FuseAttr,
) -> i32 {
let parent_inode = match self.find_inode(in_header.nodeid as usize) {
Some(i) => i.clone(),
_ => {
return libc::EBADF as i32;
}
};
let mut old_uid = 0_u32;
let mut old_gid = 0_u32;
let ret = change_uid_gid(in_header.uid, in_header.gid, &mut old_uid, &mut old_gid);
if ret != FUSE_OK {
return ret;
}
let ret = mknodat(
&parent_inode.file,
name.clone(),
mknod_in.mode & !mknod_in.umask,
mknod_in.rdev,
);
recover_uid_gid(old_uid, old_gid);
if ret != FUSE_OK {
return ret;
}
self.internal_lookup(&parent_inode, name, node_id, fuse_attr)
}
/// Create a directory by the name with the permissions in the mkdir information.
///
/// # Arguments
///
/// * `in_header` - The in_header of fuse message used to get uid and gid.
/// * `mkdir_in` - The information of mkdir used to get permissions.
/// * `name` - The path name that will be created a directory.
/// * `node_id` - The node id that is found by the path name.
/// * `fuse_attr` - The attributes will be returned by the found inode.
pub fn mkdir(
&mut self,
in_header: &FuseInHeader,
mkdir_in: &FuseMkdirIn,
name: CString,
node_id: &mut u64,
fuse_attr: &mut FuseAttr,
) -> i32 {
let parent_dir = match self.find_inode(in_header.nodeid as usize) {
Some(i) => i.clone(),
_ => {
return libc::EBADF as i32;
}
};
let mut old_uid = 0_u32;
let mut old_gid = 0_u32;
let ret = change_uid_gid(in_header.uid, in_header.gid, &mut old_uid, &mut old_gid);
if ret != FUSE_OK {
return ret;
}
let ret = mkdir_at(
&parent_dir.file,
name.clone(),
mkdir_in.mode & !mkdir_in.umask,
);
recover_uid_gid(old_uid, old_gid);
if ret != FUSE_OK {
return ret;
}
self.internal_lookup(&parent_dir, name, node_id, fuse_attr)
}
/// Delete a name from the host filesystem.
///
/// # Arguments
///
/// * `parent_nodeid` - The parent node id that is the starting directory to look up
/// in the management of filesystem.
/// * `name` - The name will be deleted.
pub fn unlink(&mut self, parent_nodeid: usize, name: CString) -> i32 {
let parent_inode = match self.find_inode(parent_nodeid) {
Some(i) => i.clone(),
None => return libc::EBADF as i32,
};
let (stat, ret) = fstat_at(
&parent_inode.file,
name.clone(),
libc::AT_EMPTY_PATH | libc::AT_SYMLINK_NOFOLLOW,
);
if ret != FUSE_OK {
return ret;
}
let key = StatKey {
ino: stat.st_ino,
dev: stat.st_dev,
};
match self.inodes.get(&key) {
Some(i) => i.clone(),
None => return libc::EIO as i32,
};
let ret = unlinkat(&parent_inode.file, name, 0);
if ret != FUSE_OK {
return ret;
}
FUSE_OK
}
/// Delete a directory from the host filesystem by the path name.
///
/// # Arguments
///
/// * `parent_nodeid` - The parent node id that is the starting directory to look up
/// in the management of filesystem.
/// * `name` - The path name of the directory will be deleted.
pub fn rmdir(&mut self, parent_nodeid: usize, name: CString) -> i32 {
let parent_inode = match self.find_inode(parent_nodeid) {
Some(i) => i.clone(),
None => return libc::EBADF as i32,
};
let (stat, ret) = fstat_at(
&parent_inode.file,
name.clone(),
libc::AT_EMPTY_PATH | libc::AT_SYMLINK_NOFOLLOW,
);
if ret != FUSE_OK {
return ret;
}
let key = StatKey {
ino: stat.st_ino,
dev: stat.st_dev,
};
match self.inodes.get(&key) {
Some(i) => i.clone(),
None => return libc::EIO as i32,
};
let ret = unlinkat(&parent_inode.file, name, libc::AT_REMOVEDIR);
if ret != FUSE_OK {
return ret;
}
FUSE_OK
}
/// Rename the old path name to the new path name in the host filesystem..
///
/// # Arguments
///
/// * `parent_nodeid` - The parent node id that is the starting directory to look up
/// for old path name in the management of filesystem.
/// * `oldname` - The old path name that is relative to the directory of parent node.
/// * `newparent_nodeid` - The new parent node id that is the starting directory to
/// look up for new path name in the management of filesystem.
/// * `newname` - The new path name that is relative to the directory of new parent node.
pub fn rename(
&self,
parent_nodeid: usize,
oldname: CString,
newparent_nodeid: usize,
newname: CString,
) -> i32 {
let parent_inode = match self.find_inode(parent_nodeid) {
Some(i) => i.clone(),
None => {
return libc::EBADF as i32;
}
};
let newparent_inode = match self.find_inode(newparent_nodeid) {
Some(i) => i.clone(),
None => {
return libc::EBADF as i32;
}
};
let (stat, ret) = fstat_at(
&parent_inode.file,
oldname.clone(),
libc::AT_EMPTY_PATH | libc::AT_SYMLINK_NOFOLLOW,
);
if ret != FUSE_OK {
return ret;
}
let key = StatKey {
ino: stat.st_ino,
dev: stat.st_dev,
};
match self.inodes.get(&key) {
Some(_) => {}
None => return libc::EIO as i32,
};
rename(&parent_inode.file, oldname, &newparent_inode.file, newname)
}
/// Create a new link to an existing file for the host filesystem.
///
/// # Arguments
///
/// * `parent_nodeid` - The parent node id that is the starting directory to look up.
/// * `old_nodeid` - The old node id in the management of filesystem.
/// * `name` - The path name that is relative to the directory of parent node.
/// * `node_id` - The node id that is found by the path name in the management of filesystem.
/// * `fuse_attr` - The attributes will be returned by the found inode.
pub fn link(
&mut self,
parent_nodeid: usize,
old_nodeid: usize,
name: CString,
node_id: &mut u64,
fuse_attr: &mut FuseAttr,
) -> i32 {
let proc_file = self.proc_dir.try_clone().unwrap();
let parent_inode = match self.find_inode(parent_nodeid) {
Some(i) => i.clone(),
None => return libc::EBADF as i32,
};
let inode = match self.find_mut_inode(old_nodeid) {
Some(inode_) => inode_,
None => return libc::EBADF as i32,
};
let ret = linkat(
&proc_file,
CString::new(format!("{}", inode.as_raw_fd())).unwrap(),
&parent_inode.file,
name,
libc::AT_SYMLINK_FOLLOW,
);
if ret != FUSE_OK {
return ret;
}
let (stat, ret) = fstat_at(
&inode.file,
CString::new("").unwrap(),
libc::AT_EMPTY_PATH | libc::AT_SYMLINK_NOFOLLOW,
);
if ret != FUSE_OK {
return ret;
}
*fuse_attr = FuseAttr::from_stat(stat);
*node_id = inode.node_id as u64;
inode.nlookup += 1;
FUSE_OK
}
/// Open the file with the node id in the management of filesystem.
///
/// # Arguments
///
/// * `node_id` - The node id used to look up the inode.
/// * `flags` - The flags used to open the file.
/// * `fh` - The file handler is returned in the management of filesystem.
pub fn open(&mut self, node_id: usize, flags: u32, fh: &mut u64) -> i32 {
// File creation should be done with create and mknod fuse messages.
if (flags & (libc::O_CREAT as u32 | libc::O_TMPFILE as u32)) != 0 {
return libc::EINVAL;
}
let (inode_fd, file_type) = match self.find_inode(node_id) {
Some(i) => (i.as_raw_fd(), i.file_type),
None => {
return libc::EBADF as i32;
}
};
if file_type & libc::S_IFREG == 0 && file_type & libc::S_IFDIR == 0 {
return libc::EBADF as i32;
}
let (file_opt, ret) = open_at(
&self.proc_dir,
CString::new(format!("{}", inode_fd)).unwrap(),
(flags as i32) & !libc::O_NOFOLLOW,
0,
);
if ret != FUSE_OK {
return ret;
}
if let Some(file) = file_opt {
*fh = self.file_map.get_map(file.try_clone().unwrap()) as u64;
}
FUSE_OK
}
/// Read the file descriptor by file hander in the management of filesystem.
///
/// # Arguments
///
/// * `fh` - The file handler in the management of filesystem.
/// * `fd` - The file descriptor in the host filesystem.
pub fn read(&mut self, fh: usize, fd: &mut RawFd) -> i32 {
match self.file_map.get_value(fh) {
Some(file) => {
*fd = file.as_raw_fd();
}
_ => {
return libc::EBADF as i32;
}
}
FUSE_OK
}
/// write the file descriptor by file hander in the management of filesystem.
///
/// # Arguments
///
/// * `fh` - The file handler in the management of filesystem.
/// * `fd` - The file descriptor in the host filesystem.
pub fn write(&mut self, fh: usize, fd: &mut RawFd) -> i32 {
match self.file_map.get_value(fh) {
Some(file) => {
*fd = file.as_raw_fd();
}
_ => {
return libc::EBADF as i32;
}
}
FUSE_OK
}
/// Get the information about a mounted filesystem.
///
/// # Arguments
///
/// * `node_id` - The node id used to look up the inode.
/// * `fuse_statfs` - The information about the mounted filesystem is
/// returned by the found inode.
pub fn statfs(&mut self, node_id: usize, fuse_statfs: &mut FuseStatfsOut) -> i32 {
let inode = match self.find_inode(node_id) {
Some(i) => i.clone(),
None => {
return libc::EBADF as i32;
}
};
let (stat, ret) = fstat_vfs(&inode.file);
if ret != FUSE_OK {
return ret;
}
*fuse_statfs = FuseStatfsOut::from_stat(stat);
FUSE_OK
}
/// Release the file with file handler in the management of filesystem.
///
/// # Arguments
///
/// * `fh` - The file handler in the management of filesystem.
pub fn release(&mut self, fh: usize) -> i32 {
self.file_map.put_map(fh);
FUSE_OK
}
/// Transfer the file data to the storage device with file handler in
/// the management of filesystem.
///
/// # Arguments
///
/// * `fh` - The file handler in the management of filesystem.
/// * `datasync` - The datasync indicates whether to use the fdatasync
/// or fsync interface.
pub fn fsyncfile(&self, fh: usize, datasync: bool) -> i32 {
let mut ret = FUSE_OK;
if fh == u64::max_value() as usize {
let (inode_fd, file_type) = match self.find_inode(fh) {
Some(i) => (i.as_raw_fd(), i.file_type),
None => {
return libc::EBADF as i32;
}
};
if file_type & libc::S_IFREG == 0 && file_type & libc::S_IFDIR == 0 {
return libc::EBADF as i32;
}
let (file_opt, ret_) = open_at(
&self.proc_dir,
CString::new(format!("{}", inode_fd)).unwrap(),
libc::O_RDWR,
0,
);
if ret_ != FUSE_OK {
return ret;
}
if let Some(file) = file_opt {
ret = fsync(&file, datasync);
} else {
return libc::EBADF as i32;
}
} else {
match self.file_map.get_value(fh) {
Some(file) => {
ret = fsync(file, datasync);
}
_ => {
return libc::EBADF as i32;
}
}
}
ret
}
/// Set an extended attribute identified by name and associated with the node id
/// in the management of filesystem.
///
/// # Arguments
///
/// * `node_id` - The node id used to look up the inode.
/// * `name` - The name associated with inode.
/// * `value` - The value of the extended attribute.
/// * `size` - The size of the value string.
/// * `flags` - The flags used to set an extended attribute.
pub fn setxattr(
&self,
node_id: usize,
name: CString,
value: CString,
size: u32,
flags: u32,
) -> i32 {
let inode = match self.find_inode(node_id) {
Some(i) => i.clone(),
None => {
return libc::EBADF as i32;
}
};
if inode.file_type & libc::S_IFREG != 0 || inode.file_type & libc::S_IFDIR != 0 {
let (file_opt, ret_) = open_at(
&self.proc_dir,
CString::new(format!("{}", &inode.file.as_raw_fd())).unwrap(),
libc::O_RDONLY,
0,
);
if ret_ != FUSE_OK {
return ret_;
}
if let Some(file) = file_opt {
fset_xattr(&file, name, value, size, flags)
} else {
libc::EBADF as i32
}
} else {
if fchdir(&self.proc_dir) != FUSE_OK {
panic!("setxattr: failed to change process directoy");
}
let ret_ = set_xattr(
CString::new(format!("{}", &inode.file.as_raw_fd())).unwrap(),
name,
value,
size,
flags,
);
if fchdir(&self.root_inode.file) != FUSE_OK {
panic!("setxattr: failed to change directoy of root inode");
}
ret_
}
}
/// Get an extended attribute identified by name and associated with the node id
/// in the management of filesystem.
///
/// # Arguments
///
/// * `node_id` - The node id used to look up the inode.
/// * `name` - The name associated with inode.
/// * `size` - The size of the buffer.
/// * `buff` - The buffer of the extended attribute.
pub fn getxattr(&self, node_id: usize, name: CString, size: u32, buff: &mut Vec<u8>) -> i32 {
let inode = match self.find_inode(node_id) {
Some(i) => i.clone(),
None => {
return libc::EBADF as i32;
}
};
if inode.file_type & libc::S_IFREG != 0 || inode.file_type & libc::S_IFDIR != 0 {
let (file_opt, ret) = open_at(
&self.proc_dir,
CString::new(format!("{}", &inode.file.as_raw_fd())).unwrap(),
libc::O_RDONLY,
0,
);
if ret != FUSE_OK {
return ret;
}
if let Some(file) = file_opt {
let (buf_opt, ret) = fget_xattr(&file, name, size as usize);
if ret != FUSE_OK {
return ret;
}
if let Some(mut buf) = buf_opt {
buff.append(&mut buf);
}
} else {
return libc::EBADF as i32;
}
} else {
if fchdir(&self.proc_dir) != FUSE_OK {
panic!("getxattr: failed to change process directoy");
}
let (buf_opt, ret) = get_xattr(
CString::new(format!("{}", &inode.file.as_raw_fd())).unwrap(),
name,
size as usize,
);
if fchdir(&self.root_inode.file) != FUSE_OK {
panic!("getxattr: failed to change directoy of root inode");
}
if ret != FUSE_OK {
return ret;
}
if let Some(mut buf) = buf_opt {
buff.append(&mut buf);
}
}
FUSE_OK
}
/// List extended attribute names associated with the node id
/// in the management of filesystem.
///
/// # Arguments
///
/// * `node_id` - The node id used to look up the inode.
/// * `size` - The size of the buffer.
/// * `buff` - The buffer of the extended attribute.
pub fn listxattr(&self, node_id: usize, size: u32, buff: &mut Vec<u8>) -> i32 {
let inode = match self.find_inode(node_id) {
Some(i) => i.clone(),
None => {
return libc::EBADF as i32;
}
};
if inode.file_type & libc::S_IFREG != 0 || inode.file_type & libc::S_IFDIR != 0 {
let (file_opt, ret) = open_at(
&self.proc_dir,
CString::new(format!("{}", &inode.file.as_raw_fd())).unwrap(),
libc::O_RDONLY,
0,
);
if ret != FUSE_OK {
return ret;
}
if let Some(file) = file_opt {
let (buf_opt, ret) = flist_xattr(&file, size as usize);
if ret != FUSE_OK {
return ret;
}
if let Some(mut buf) = buf_opt {
buff.append(&mut buf);
}
} else {
return libc::EBADF as i32;
}
} else {
if fchdir(&self.proc_dir) != FUSE_OK {
panic!("listxattr: failed to change process directoy");
}
let (buf_opt, ret) = list_xattr(
CString::new(format!("{}", &inode.file.as_raw_fd())).unwrap(),
size as usize,
);
if fchdir(&self.root_inode.file) != FUSE_OK {
panic!("listxattr: failed to change directoy of root inode");
}
if ret != FUSE_OK {
return ret;
}
if let Some(mut buf) = buf_opt {
buff.append(&mut buf);
}
}
FUSE_OK
}
/// Remove an extended attribute identified by name and associated with the node id
/// in the management of filesystem.
///
/// # Arguments
///
/// * `node_id` - The node id used to look up the inode in the management of filesystem.
/// * `name` - The name associated with inode.
pub fn removexattr(&self, node_id: usize, name: CString) -> i32 {
let inode = match self.find_inode(node_id) {
Some(i) => i.clone(),
None => {
return libc::EBADF as i32;
}
};
if inode.file_type & libc::S_IFREG != 0 || inode.file_type & libc::S_IFDIR != 0 {
let (file_opt, ret) = open_at(
&self.proc_dir,
CString::new(format!("{}", &inode.file.as_raw_fd())).unwrap(),
libc::O_RDONLY,
0,
);
if ret != FUSE_OK {
return ret;
}
if let Some(file) = file_opt {
let ret = fremove_xattr(&file, name);
if ret != FUSE_OK {
return ret;
}
} else {
return libc::EBADF as i32;
}
} else {
if fchdir(&self.proc_dir) != FUSE_OK {
panic!("removexattr: failed to change process directoy");
}
let ret = remove_xattr(
CString::new(format!("{}", &inode.file.as_raw_fd())).unwrap(),
name,
);
if fchdir(&self.root_inode.file) != FUSE_OK {
panic!("removexattr: failed to change directoy of root inode");
}
if ret != FUSE_OK {
return ret;
}
}
FUSE_OK
}
/// Delete the file lock by the node id in the management of filesystem.
///
/// # Arguments
///
/// * `node_id` - The node id used to look up the inode in the management of filesystem.
/// * `owner` - The name associated with inode.
pub fn flush(&mut self, node_id: usize, owner: u64) -> i32 {
self.delete_file_lock(node_id, owner)
}
/// Initialize fuse message for getting supported features in the process.
///
/// # Arguments
///
/// * `flags` - The supported features in StratoVirt.
/// * `support_flags` - The supported features in the process.
pub fn init(&self, flags: u32, support_flags: &mut u32) {
if flags & FUSE_MAX_PAGES != 0 {
*support_flags |= FUSE_MAX_PAGES;
}
if flags & FUSE_CAP_ASYNC_READ != 0 {
*support_flags |= FUSE_ASYNC_READ;
}
if flags & FUSE_CAP_PARALLEL_DIROPS != 0 {
*support_flags |= FUSE_PARALLEL_DIROPS;
}
if flags & FUSE_CAP_POSIX_LOCKS != 0 {
*support_flags |= FUSE_POSIX_LOCKS;
}
if flags & FUSE_CAP_ATOMIC_O_TRUNC != 0 {
*support_flags |= FUSE_ATOMIC_O_TRUNC;
}
if flags & FUSE_CAP_EXPORT_SUPPORT != 0 {
*support_flags |= FUSE_EXPORT_SUPPORT;
}
if flags & FUSE_CAP_DONT_MASK != 0 {
*support_flags |= FUSE_DONT_MASK;
}
if flags & FUSE_CAP_FLOCK_LOCKS != 0 {
*support_flags |= FUSE_FLOCK_LOCKS;
}
if flags & FUSE_CAP_AUTO_INVAL_DATA != 0 {
*support_flags |= FUSE_AUTO_INVAL_DATA;
}
if flags & FUSE_CAP_READDIRPLUS != 0 {
*support_flags |= FUSE_DO_READDIRPLUS;
}
if flags & FUSE_CAP_READDIRPLUS_AUTO != 0 {
*support_flags |= FUSE_READDIRPLUS_AUTO;
}
if flags & FUSE_CAP_ASYNC_DIO != 0 {
*support_flags |= FUSE_ASYNC_DIO;
}
if flags & FUSE_CAP_POSIX_ACL != 0 {
*support_flags |= FUSE_POSIX_ACL;
}
umask(0o000);
}
/// Open a directory with the node id in the management of filesystem.
///
/// # Arguments
///
/// * `node_id` - The node id used to look up the inode in the management of filesystem.
/// * `dir_fh` - The directory handler is returned in the management of filesystem.
pub fn opendir(&mut self, node_id: usize, dir_fh: &mut u64) -> i32 {
let inode = match self.find_inode(node_id) {
Some(i) => i.clone(),
None => {
return libc::EBADF as i32;
}
};
let (file_opt, ret) = open_at(&inode.file, CString::new(".").unwrap(), libc::O_RDONLY, 0);
if ret != FUSE_OK {
return ret;
}
if let Some(file) = file_opt {
*dir_fh = self.file_map.get_map(file) as u64;
return FUSE_OK;
}
libc::EBADF as i32
}
/// read a directory stream with the directory handler in the host filesystem.
///
/// # Arguments
///
/// * `node_id` - The node id used to look up the inode in the management of filesystem.
/// * `dh` - The directory handler in the management of filesystem.
/// * `size` - The size of the buffer.
/// * `offset` - The offset indicates it opens a directory stream with the offset.
/// * `plus` - The plus indicates it uses FuseDirentplus struct to the buffer.
/// * `buff` - The buffer of all FuseDirent structs or FuseDirentplus structs.
pub fn readdir(
&mut self,
node_id: usize,
dh: usize,
size: u32,
offset: u64,
plus: bool,
buff: &mut Vec<u8>,
) -> i32 {
let dir_inode = match self.find_inode(node_id) {
Some(i) => i.clone(),
None => {
return libc::EBADF as i32;
}
};
let mut dirp = match self.file_map.get_value_mut(dh) {
Some(file) => {
let (dirp_opt, ret) = fdopen_dir(file.as_raw_fd());
if ret != FUSE_OK {
return libc::EBADF as i32;
}
dirp_opt.unwrap()
}
_ => {
return libc::EBADF as i32;
}
};
seek_dir(&mut dirp, offset);
let mut remain = size;
let mut son_nodeid = 0_u64;
loop {
let (dirent_opt, ret) = read_dir(&mut dirp);
if ret != FUSE_OK {
return ret;
}
let direntp = dirent_opt.unwrap();
if direntp.is_null() {
break;
}
// The above code has checked the validity of direntp, so it is safe for *direntp.
let dirent = unsafe { *direntp };
let (name_len, son_name) = match array_to_cstring(&dirent.d_name[..]) {
Ok(v) => v,
Err(_) => {
continue;
}
};
let only_entry_size = if plus {
mem::size_of::<FuseDirentplus>()
} else {
mem::size_of::<FuseDirent>()
};
let (entry_size, gap) = match round_up((only_entry_size + name_len) as u64, 8) {
Some(v) => (v as u32, v as usize - (only_entry_size + name_len)),
_ => {
return libc::EINVAL as i32;
}
};
if entry_size > remain {
if son_nodeid != 0 {
self.forget(son_nodeid as usize, 1);
}
break;
}
let mut fuse_dirent = FuseDirent {
ino: dirent.d_ino,
off: dirent.d_off as u64,
namelen: name_len as u32,
type_: dirent.d_type as u32 & (libc::S_IFMT >> 12),
name: [0u8; 0],
};
if dir_inode.node_id == self.root_inode.node_id && path_is_dotdot(&son_name) {
fuse_dirent.ino = self.root_inode.key.ino;
fuse_dirent.type_ = libc::DT_DIR as u32 & (libc::S_IFMT >> 12);
}
if plus {
son_nodeid = 0;
let mut son_attr = FuseAttr::default();
if !path_is_dot(&son_name) && !path_is_dotdot(&son_name) {
let ret = self.internal_lookup(
&dir_inode,
son_name.clone(),
&mut son_nodeid,
&mut son_attr,
);
if ret != FUSE_OK {
return ret;
}
}
buff.extend_from_slice(
FuseDirentplus {
entry_out: FuseEntryOut {
nodeid: son_nodeid as u64,
generation: 0,
entry_valid: 0,
entry_valid_nsec: 0,
attr_valid: 0,
attr_valid_nsec: 0,
attr: son_attr,
},
dirent: fuse_dirent,
}
.as_bytes(),
);
} else {
buff.extend_from_slice(fuse_dirent.as_bytes());
};
buff.extend_from_slice(son_name.as_bytes());
if gap > 0 {
buff.append(&mut vec![0u8; gap]);
}
remain -= entry_size;
}
FUSE_OK
}
/// Release a directory in the management of filesystem.
///
/// # Arguments
///
/// * `dir_fh` - The directory handler in the management of filesystem.
pub fn releasedir(&mut self, dir_fh: usize) -> i32 {
self.file_map.put_map(dir_fh);
FUSE_OK
}
/// Transfer the directory data to the storage device with directory handler in
/// the management of filesystem.
///
/// # Arguments
///
/// * `dir_fh` - The directory handler in the management of filesystem.
/// * `datasync` - The datasync indicates whether to use the fdatasync
/// or fsync interface.
pub fn fsyncdir(&self, dir_fh: usize, datasync: bool) -> i32 {
if let Some(file) = self.file_map.get_value(dir_fh) {
let ret = fsync(file, datasync);
if ret != FUSE_OK {
return ret;
}
} else {
return libc::EBADF as i32;
}
FUSE_OK
}
/// Create the POSIX file lock with the node id in the management of filesystem.
///
/// # Arguments
///
/// * `node_id` - The node id used to look up the inode in the management of filesystem.
/// * `owner` - The unique index for file lock in the inode.
/// * `file_lock_in` - The information of file lock will be set.
/// * `file_lock_out` - The information of file lock will be returned.
pub fn getlk(
&mut self,
node_id: usize,
owner: u64,
file_lock_in: &FuseFileLock,
file_lock_out: &mut FuseFileLock,
) -> i32 {
let (file_opt, ret) = self.create_file_lock(node_id, owner);
if ret != FUSE_OK {
return ret;
}
let ret = fcntl_flock(
&file_opt.unwrap(),
libc::F_GETLK,
file_lock_in,
file_lock_out,
);
if ret != FUSE_OK {
return ret;
}
FUSE_OK
}
/// Lock the file or unlock the file by POSIX lock with the node id in
/// the management of filesystem.
///
/// # Arguments
///
/// * `node_id` - The node id used to look up the inode in the management of filesystem.
/// * `owner` - The unique index for file lock in the inode.
/// * `is_blocking` - The is_blocking indicates whether to use a blocking lock.
/// * `file_lock_in` - The information of file lock will be set.
pub fn setlk(
&mut self,
node_id: usize,
owner: u64,
is_blocking: bool,
file_lock_in: &FuseFileLock,
) -> i32 {
if is_blocking {
return libc::EOPNOTSUPP as i32;
}
let (file_opt, ret) = self.create_file_lock(node_id, owner);
if ret != FUSE_OK {
return ret;
}
let mut file_lock_out = FuseFileLock::default();
let ret = fcntl_flock(
&file_opt.unwrap(),
libc::F_SETLK,
file_lock_in,
&mut file_lock_out,
);
if ret != FUSE_OK {
return ret;
}
FUSE_OK
}
/// Lock the file or unlock the file by BSD lock with file handler in
/// the management of filesystem.
///
/// # Arguments
///
/// * `fh` - The file handler in the management of filesystem.
/// * `lock_type` - The lock type contains the type of read lock, write lock and unlocking.
/// * `is_blocking` - The is_blocking indicates whether to use a blocking lock.
pub fn flock(&self, fh: usize, lock_type: u32, is_blocking: bool) -> i32 {
let mut operation: i32 = 0;
if lock_type == F_RDLCK {
operation = libc::LOCK_SH;
} else if lock_type == F_WDLCK {
operation = libc::LOCK_EX;
} else if lock_type == F_UNLCK {
operation = libc::LOCK_UN;
}
if !is_blocking {
operation |= libc::LOCK_NB;
}
if let Some(file) = self.file_map.get_value(fh) {
let ret = flock(file, operation);
if ret != FUSE_OK {
return ret;
}
} else {
return libc::EBADF as i32;
}
FUSE_OK
}
/// Create a file with name in the management of filesystem.
///
/// # Arguments
///
/// * `in_header` - The in_header of fuse message used to get uid and gid.
/// * `create_in` - The information of creating a file contains the flags, mode and umask.
/// * `name` - The string of name used to create a file.
/// * `fh` - The file handler is returned in the management of filesystem.
/// * `node_id` - The node id that is found by the name in the management of filesystem.
/// * `fuse_attr` - The attributes will be returned by the found inode.
pub fn create(
&mut self,
in_header: &FuseInHeader,
create_in: &FuseCreateIn,
name: CString,
fh: &mut u64,
node_id: &mut u64,
fuse_attr: &mut FuseAttr,
) -> i32 {
let parent_dir = match self.find_inode(in_header.nodeid as usize) {
Some(i) => i.clone(),
_ => {
return libc::EBADF as i32;
}
};
let mut old_uid = 0_u32;
let mut old_gid = 0_u32;
let ret = change_uid_gid(in_header.uid, in_header.gid, &mut old_uid, &mut old_gid);
if ret != FUSE_OK {
return ret;
}
let (file_opt, ret) = open_at(
&parent_dir.file,
name.clone(),
(create_in.flags as i32 | libc::O_CREAT) & !libc::O_NOFOLLOW,
create_in.mode & !(create_in.umask & 0o777),
);
recover_uid_gid(old_uid, old_gid);
if ret != FUSE_OK {
return ret;
}
if let Some(file) = file_opt {
*fh = self.file_map.get_map(file.try_clone().unwrap()) as u64;
}
self.internal_lookup(&parent_dir, name, node_id, fuse_attr)
}
/// Destroy the management of filesystem, except for the root inode.
pub fn destroy(&mut self) -> i32 {
let root_key = self.root_inode.key;
self.inode_key_map.destroy_map();
self.file_map.destroy_map();
self.inodes = BTreeMap::new();
// Need to add root_inode back to the inode table and inode_key_map table for
// the filesystem function
let root_id = self.inode_key_map.get_map(root_key);
self.root_inode.node_id = root_id;
self.inodes.insert(root_key, self.root_inode.clone());
FUSE_OK
}
/// Allocate the disk space with file handler in the management of filesystem.
///
/// # Arguments
///
/// * `fh` - The file handler in the management of filesystem.
/// * `mode` - The mode determines the operation to be performed on the given range.
/// * `offset` - The offset in the file.
/// * `length` - The length that needs to be allocated.
pub fn fallocate(&self, fh: usize, mode: u32, offset: u64, length: u64) -> i32 {
if let Some(file) = self.file_map.get_value(fh) {
let ret = fallocate(file, mode, offset, length);
if ret != FUSE_OK {
return ret;
}
} else {
return libc::EBADF as i32;
}
FUSE_OK
}
/// Reposition the file offset of the open file with file handler
/// in the management of filesystem.
///
/// # Arguments
///
/// * `fh` - The file handler in the management of filesystem.
/// * `offset` - The offset in the file used together with the whence.
/// * `whence` - The whence determines the operation to be performed in the file.
/// * `outoffset` - The offset from the beginning of the file is returned.
pub fn lseek(&self, fh: usize, offset: u64, whence: u32, outoffset: &mut u64) -> i32 {
if let Some(file) = self.file_map.get_value(fh) {
let (offset_tmp, ret) = lseek(file, offset, whence);
if ret != FUSE_OK {
return ret;
}
*outoffset = offset_tmp;
} else {
return libc::EBADF as i32;
}
FUSE_OK
}
}

Опубликовать ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://gitlife.ru/oschina-mirror/openeuler-stratovirt.git
git@gitlife.ru:oschina-mirror/openeuler-stratovirt.git
oschina-mirror
openeuler-stratovirt
openeuler-stratovirt
v2.2.0-rc6