use super::*;
impl PassthroughFs {
pub fn create(
&self,
parent: u64,
name: &OsStr,
mode: u32,
flags: u32,
) -> Result<(u64, crate::fuse::FuseAttr, u64)> {
let path = self.get_path(parent, name)?;
let mut opts = OpenOptions::new();
Self::apply_flags(&mut opts, flags);
opts.create(true);
opts.mode(mode & 0o7777);
let file = opts.open(&path).map_err(FsError::io)?;
let metadata = file.metadata().map_err(FsError::io)?;
self.invalidate_negative_cache(&path);
let relative = self.relative_path(&path);
let kernel_ino = metadata.ino();
let inode = self.alloc_inode();
{
let mut inodes = self
.inodes
.write()
.map_err(|_| FsError::Cache("failed to acquire inode lock".to_string()))?;
inodes.insert(
inode,
InodeData::new(relative, FileType::Regular, kernel_ino),
);
}
let handle = self.alloc_handle();
{
let mut handles = self
.handles
.write()
.map_err(|_| FsError::Cache("failed to acquire handle lock".to_string()))?;
handles.insert(handle, HandleData { file, inode, flags });
}
Ok((inode, Self::metadata_to_attr(inode, &metadata), handle))
}
pub fn mkdir(
&self,
parent: u64,
name: &OsStr,
mode: u32,
) -> Result<(u64, crate::fuse::FuseAttr)> {
let path = self.get_path(parent, name)?;
std::fs::create_dir(&path).map_err(FsError::io)?;
std::fs::set_permissions(&path, std::fs::Permissions::from_mode(mode & 0o7777))
.map_err(FsError::io)?;
self.invalidate_negative_cache(&path);
let metadata = std::fs::symlink_metadata(&path).map_err(FsError::io)?;
let relative = self.relative_path(&path);
let kernel_ino = metadata.ino();
let inode = self.alloc_inode();
{
let mut inodes = self
.inodes
.write()
.map_err(|_| FsError::Cache("failed to acquire inode lock".to_string()))?;
inodes.insert(
inode,
InodeData::new(relative, FileType::Directory, kernel_ino),
);
}
Ok((inode, Self::metadata_to_attr(inode, &metadata)))
}
pub fn symlink(
&self,
parent: u64,
name: &OsStr,
target: &Path,
) -> Result<(u64, crate::fuse::FuseAttr)> {
let path = self.get_path(parent, name)?;
std::os::unix::fs::symlink(target, &path).map_err(FsError::io)?;
self.invalidate_negative_cache(&path);
let metadata = std::fs::symlink_metadata(&path).map_err(FsError::io)?;
let relative = self.relative_path(&path);
let kernel_ino = metadata.ino();
let inode = self.alloc_inode();
{
let mut inodes = self
.inodes
.write()
.map_err(|_| FsError::Cache("failed to acquire inode lock".to_string()))?;
inodes.insert(
inode,
InodeData::new(relative, FileType::Symlink, kernel_ino),
);
}
Ok((inode, Self::metadata_to_attr(inode, &metadata)))
}
pub fn link(
&self,
inode: u64,
new_parent: u64,
new_name: &OsStr,
) -> Result<(u64, crate::fuse::FuseAttr)> {
let source_path = self.inode_path(inode)?;
let new_path = self.get_path(new_parent, new_name)?;
std::fs::hard_link(&source_path, &new_path).map_err(FsError::io)?;
self.invalidate_negative_cache(&new_path);
let metadata = std::fs::symlink_metadata(&new_path).map_err(FsError::io)?;
{
let inodes = self
.inodes
.read()
.map_err(|_| FsError::Cache("failed to acquire inode lock".to_string()))?;
if let Some(data) = inodes.get(&inode) {
data.inc_ref();
}
}
Ok((inode, Self::metadata_to_attr(inode, &metadata)))
}
#[allow(clippy::cast_possible_truncation)]
pub fn mknod(
&self,
parent: u64,
name: &OsStr,
mode: u32,
rdev: u64,
) -> Result<(u64, crate::fuse::FuseAttr)> {
let path = self.get_path(parent, name)?;
let path_cstr = std::ffi::CString::new(path.as_os_str().as_bytes())
.map_err(|_| FsError::InvalidPath("invalid path".to_string()))?;
let ret = unsafe {
libc::mknod(
path_cstr.as_ptr(),
mode as libc::mode_t,
rdev as libc::dev_t,
)
};
if ret != 0 {
return Err(FsError::io(std::io::Error::last_os_error()));
}
self.invalidate_negative_cache(&path);
let metadata = std::fs::symlink_metadata(&path).map_err(FsError::io)?;
let file_type = FileType::from_mode(metadata.mode());
let relative = self.relative_path(&path);
let kernel_ino = metadata.ino();
let inode = self.alloc_inode();
{
let mut inodes = self
.inodes
.write()
.map_err(|_| FsError::Cache("failed to acquire inode lock".to_string()))?;
inodes.insert(inode, InodeData::new(relative, file_type, kernel_ino));
}
Ok((inode, Self::metadata_to_attr(inode, &metadata)))
}
pub fn unlink(&self, parent: u64, name: &OsStr) -> Result<()> {
let path = self.get_path(parent, name)?;
std::fs::remove_file(&path).map_err(FsError::io)?;
Ok(())
}
pub fn rmdir(&self, parent: u64, name: &OsStr) -> Result<()> {
let path = self.get_path(parent, name)?;
std::fs::remove_dir(&path).map_err(FsError::io)
}
pub fn rename(
&self,
parent: u64,
name: &OsStr,
new_parent: u64,
new_name: &OsStr,
_flags: u32,
) -> Result<()> {
let old_path = self.get_path(parent, name)?;
let new_path = self.get_path(new_parent, new_name)?;
std::fs::rename(&old_path, &new_path).map_err(FsError::io)?;
self.invalidate_negative_cache(&old_path);
self.invalidate_negative_cache(&new_path);
let old_relative = self.relative_path(&old_path);
let new_relative = self.relative_path(&new_path);
{
let mut inodes = self
.inodes
.write()
.map_err(|_| FsError::Cache("failed to acquire inode lock".to_string()))?;
for data in inodes.values_mut() {
if data.path == old_relative {
data.path = new_relative;
break;
}
}
}
Ok(())
}
}