summaryrefslogtreecommitdiff
path: root/src/filesystem/trait_impl.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/filesystem/trait_impl.rs')
-rw-r--r--src/filesystem/trait_impl.rs332
1 files changed, 254 insertions, 78 deletions
diff --git a/src/filesystem/trait_impl.rs b/src/filesystem/trait_impl.rs
index 5523c8c..e030f04 100644
--- a/src/filesystem/trait_impl.rs
+++ b/src/filesystem/trait_impl.rs
@@ -1,19 +1,22 @@
+use crate::block_device::BLOCK_SIZE;
+use crate::disk::block::DataBlock;
use crate::disk::inode::InodeMode;
use crate::utils::permissions::get_groups;
use crate::utils::permissions::{check_access, clear_suid_sgid};
use crate::utils::{from_filetype, from_systime, time_now, to_fileattr, to_filetype};
use crate::{AyaFS, TTL};
use fuser::TimeOrNow::{Now, SpecificTime};
-use fuser::{Filesystem, FileType, KernelConfig, ReplyAttr, ReplyData, ReplyDirectory, ReplyEmpty, ReplyEntry, ReplyOpen, ReplyWrite, Request, TimeOrNow};
-use libc::{c_int, EACCES, EBADF, EEXIST, EFAULT, EINVAL, EIO, EISDIR, ENAMETOOLONG, ENOENT, ENOSPC, ENOSYS, ENOTDIR, ENOTEMPTY, EPERM, IPOPT_OFFSET, link, O_ACCMODE, O_RDONLY, O_RDWR, O_WRONLY, R_OK, S_ISGID, S_ISUID, S_IXGRP, S_IXOTH, S_IXUSR, W_OK, write};
+use fuser::{
+ FileType, Filesystem, KernelConfig, ReplyAttr, ReplyData, ReplyDirectory, ReplyEmpty,
+ ReplyEntry, ReplyOpen, ReplyWrite, Request, TimeOrNow,
+};
+use libc::{c_int, link, write, EACCES, EBADF, EEXIST, EFAULT, EINVAL, EIO, EISDIR, ENAMETOOLONG, ENOENT, ENOSPC, ENOSYS, ENOTDIR, ENOTEMPTY, EPERM, IPOPT_OFFSET, O_ACCMODE, O_RDONLY, O_RDWR, O_WRONLY, R_OK, S_ISGID, S_ISUID, S_IXGRP, S_IXOTH, S_IXUSR, W_OK, RENAME_NOREPLACE, RENAME_EXCHANGE};
use log::debug;
use std::ffi::{OsStr, OsString};
use std::os::unix::ffi::OsStrExt;
use std::path::Path;
use std::slice;
use std::time::SystemTime;
-use crate::block_device::BLOCK_SIZE;
-use crate::disk::block::DataBlock;
impl AyaFS {}
@@ -79,11 +82,11 @@ impl Filesystem for AyaFS {
atime: Option<TimeOrNow>,
mtime: Option<TimeOrNow>,
_ctime: Option<SystemTime>,
- fh: Option<u64>, // 当 setattr 被 ftruncate invoke 时会提供 fh
- _crtime: Option<SystemTime>, // 忽略
- _chgtime: Option<SystemTime>, // 忽略
+ fh: Option<u64>, // 当 setattr 被 ftruncate invoke 时会提供 fh
+ _crtime: Option<SystemTime>, // 忽略
+ _chgtime: Option<SystemTime>, // 忽略
_bkuptime: Option<SystemTime>, // 忽略
- _flags: Option<u32>, // 忽略
+ _flags: Option<u32>, // 忽略
reply: ReplyAttr,
) {
if let Some(inode) = self.get_inode_mut(ino as usize) {
@@ -160,7 +163,8 @@ impl Filesystem for AyaFS {
debug!("ftruncate on inode {:#x?} size {:?}", ino, size);
if let Some(file_handle) = fh {
let mut inode = inode.clone();
- let (inode_index, _read, write) = self.file_handle_map.get(&file_handle).unwrap();
+ let (inode_index, _read, write) =
+ self.file_handle_map.get(&file_handle).unwrap();
assert_eq!(ino as usize, *inode_index);
if !write {
reply.error(EACCES);
@@ -170,14 +174,7 @@ impl Filesystem for AyaFS {
self.update_inode(*inode_index, inode);
}
} else {
- if !check_access(
- req.uid(),
- req.gid(),
- inode.uid,
- inode.gid,
- inode.mode,
- W_OK,
- ) {
+ if !check_access(req.uid(), req.gid(), inode.uid, inode.gid, inode.mode, W_OK) {
reply.error(EACCES);
} else {
inode.size = size as u32;
@@ -256,7 +253,14 @@ impl Filesystem for AyaFS {
}
}
- fn symlink(&mut self, req: &Request<'_>, parent: u64, link_name: &OsStr, target: &Path, reply: ReplyEntry) {
+ fn symlink(
+ &mut self,
+ req: &Request<'_>,
+ parent: u64,
+ link_name: &OsStr,
+ target: &Path,
+ reply: ReplyEntry,
+ ) {
debug!(
"symlink(parent: {}, name: {:?}, target: {:?})",
parent, link_name, target
@@ -291,7 +295,7 @@ impl Filesystem for AyaFS {
parent_inode.uid,
parent_inode.gid,
parent_inode.mode,
- W_OK
+ W_OK,
) {
reply.error(EACCES);
return;
@@ -309,10 +313,7 @@ impl Filesystem for AyaFS {
let target = target.as_os_str();
let mut parent_inode = parent_inode.clone();
- if self
- .lookup_name(parent, &parent_inode, link_name)
- .is_ok()
- {
+ if self.lookup_name(parent, &parent_inode, link_name).is_ok() {
reply.error(EEXIST);
return;
}
@@ -337,21 +338,37 @@ impl Filesystem for AyaFS {
let block_index = write_ptr / BLOCK_SIZE;
let offset = write_ptr % BLOCK_SIZE;
- let write_length_within_block = if BLOCK_SIZE - offset < target.len() - write_ptr {
- BLOCK_SIZE - offset
- } else {
- target.len() - write_ptr
- };
-
- if let Some(block) = self.access_block_mut::<DataBlock>(&child_inode, block_index) {
- block.block.0[offset .. offset + write_length_within_block]
- .copy_from_slice(&target.as_bytes()[write_ptr .. write_ptr + write_length_within_block]);
+ let write_length_within_block =
+ if BLOCK_SIZE - offset < target.len() - write_ptr {
+ BLOCK_SIZE - offset
+ } else {
+ target.len() - write_ptr
+ };
+
+ if let Some(block) =
+ self.access_block_mut::<DataBlock>(&child_inode, block_index)
+ {
+ block.block.0[offset..offset + write_length_within_block]
+ .copy_from_slice(
+ &target.as_bytes()
+ [write_ptr..write_ptr + write_length_within_block],
+ );
write_ptr += write_length_within_block;
} else {
- if let Some((_block_index, block_index_within_inode)) = self.allocate_block_for(&mut child_inode) {
- let block = self.access_block_mut::<DataBlock>(&child_inode, block_index_within_inode).unwrap();
- block.block.0[offset .. offset + write_length_within_block]
- .copy_from_slice(&target.as_bytes()[write_ptr .. write_ptr + write_length_within_block]);
+ if let Some((_block_index, block_index_within_inode)) =
+ self.allocate_block_for(&mut child_inode)
+ {
+ let block = self
+ .access_block_mut::<DataBlock>(
+ &child_inode,
+ block_index_within_inode,
+ )
+ .unwrap();
+ block.block.0[offset..offset + write_length_within_block]
+ .copy_from_slice(
+ &target.as_bytes()
+ [write_ptr..write_ptr + write_length_within_block],
+ );
write_ptr += write_length_within_block;
} else {
reply.error(ENOSPC);
@@ -399,14 +416,20 @@ impl Filesystem for AyaFS {
let path_length = inode.size as usize;
let mut path = vec![0u8; path_length];
if path_length < 60 {
- debug!("symlink path length is {}, reading directly from inode.direct", path_length);
+ debug!(
+ "symlink path length is {}, reading directly from inode.direct",
+ path_length
+ );
let copy_src = unsafe {
let src = (&inode.direct) as *const u32 as *const u8;
slice::from_raw_parts(src, path_length)
};
path.as_mut_slice().copy_from_slice(copy_src);
} else {
- debug!("symlink path length is {}, using original read", path_length);
+ debug!(
+ "symlink path length is {}, using original read",
+ path_length
+ );
let inode = inode.clone();
let mut read_ptr = 0usize;
while read_ptr < path_length {
@@ -420,8 +443,9 @@ impl Filesystem for AyaFS {
};
if let Some(block) = self.access_block::<DataBlock>(&inode, block_index) {
- (&mut path[read_ptr .. read_ptr + read_length_within_block])
- .copy_from_slice(&block.block.0[offset .. offset + read_length_within_block]);
+ (&mut path[read_ptr..read_ptr + read_length_within_block]).copy_from_slice(
+ &block.block.0[offset..offset + read_length_within_block],
+ );
read_ptr += read_length_within_block;
} else {
reply.error(EIO);
@@ -429,13 +453,142 @@ impl Filesystem for AyaFS {
}
}
}
- debug!("readlink path read is {:?}", OsStr::from_bytes(path.as_slice()));
+ debug!(
+ "readlink path read is {:?}",
+ OsStr::from_bytes(path.as_slice())
+ );
reply.data(path.as_slice());
} else {
reply.error(ENOENT);
}
}
+ fn rename(
+ &mut self,
+ req: &Request<'_>,
+ parent: u64,
+ name: &OsStr,
+ new_parent: u64,
+ new_name: &OsStr,
+ flags: u32,
+ reply: ReplyEmpty,
+ ) {
+ debug!(
+ "rename(parent: {}, name: {:?}, new_parent: {}, new_name: {:?})",
+ parent, name, new_parent, new_name
+ );
+
+ let parent = parent as usize;
+ let new_parent = new_parent as usize;
+ if let Some(parent_inode) = self.get_inode(parent) {
+ if !check_access(
+ req.uid(),
+ req.gid(),
+ parent_inode.uid,
+ parent_inode.gid,
+ parent_inode.mode,
+ R_OK,
+ ) {
+ reply.error(EACCES);
+ return;
+ }
+
+ if name.len() > 255 {
+ reply.error(ENAMETOOLONG);
+ return;
+ }
+
+ let mut parent_inode = parent_inode.clone();
+ match self.lookup_name(parent, &parent_inode, name) {
+ Ok((inode_index, entry_index, inode)) => {
+ if let Some(new_parent_inode) = self.get_inode(new_parent) {
+ if !check_access(
+ req.uid(),
+ req.gid(),
+ new_parent_inode.uid,
+ new_parent_inode.gid,
+ new_parent_inode.mode,
+ W_OK,
+ ) {
+ reply.error(EACCES);
+ return;
+ }
+ if new_name.len() > 255 {
+ reply.error(ENAMETOOLONG);
+ return;
+ }
+
+ let mut new_parent_inode = new_parent_inode.clone();
+ match self.lookup_name(new_parent, &new_parent_inode, new_name) {
+ Ok((new_inode_index, new_entry_index, new_inode)) => {
+ // 新文件存在
+ if flags & RENAME_NOREPLACE != 0 { // 指定 noreplace 之后不允许覆盖文件
+ reply.error(EEXIST);
+ return;
+ }
+ if flags & RENAME_EXCHANGE != 0 { // 交换两个文件
+ if let Err(err_code) = self.exchange_direntry(
+ parent,
+ &mut parent_inode,
+ name,
+ new_parent,
+ &mut new_parent_inode,
+ new_name
+ ) {
+ reply.error(err_code);
+ return;
+ }
+ } else { // 用新文件替换旧文件
+ let dir_entry = self.get_direntry_by_name(parent, &parent_inode, name)
+ .unwrap();
+ if let Err(err_code) = self.remove_direntry(parent, &mut parent_inode, name, entry_index) {
+ reply.error(err_code);
+ return;
+ }
+ if let Err(err_code) = self.remove_direntry(new_parent, &mut new_parent_inode, new_name, new_entry_index) {
+ reply.error(err_code);
+ return;
+ }
+ if let Err(err_code) = self.add_direntry_2(new_parent, &mut new_parent_inode, new_name, dir_entry) {
+ reply.error(err_code);
+ return;
+ }
+ }
+ reply.ok();
+ },
+ Err(ENOENT) => { // 新文件不存在, 删除旧的创建新的
+ let dir_entry = self.get_direntry_by_name(parent, &parent_inode, name)
+ .unwrap();
+ if let Err(err_code) = self.remove_direntry(parent, &mut parent_inode, name, entry_index) {
+ reply.error(err_code);
+ return;
+ }
+ if let Err(err_code) = self.add_direntry_2(new_parent, &mut new_parent_inode, new_name, dir_entry) {
+ reply.error(err_code);
+ return;
+ }
+ reply.ok();
+ },
+ Err(err_code) => {
+ // 其他 Err code
+ reply.error(err_code);
+ return;
+ }
+ }
+ } else {
+ reply.error(ENOENT);
+ }
+ },
+ Err(err_code) => {
+ reply.error(err_code);
+ return;
+ }
+ }
+ } else {
+ reply.error(ENOENT);
+ }
+ }
+
fn mknod(
&mut self,
req: &Request<'_>,
@@ -479,10 +632,7 @@ impl Filesystem for AyaFS {
let mut parent_inode = parent_inode.clone();
// 如果已经存在, 返回 already exists
- if self
- .lookup_name(parent, &parent_inode, name)
- .is_ok()
- {
+ if self.lookup_name(parent, &parent_inode, name).is_ok() {
reply.error(EEXIST);
return;
}
@@ -622,7 +772,7 @@ impl Filesystem for AyaFS {
self.lookup_name(parent as usize, &parent_inode, name)
{
let inode_index = inode_index as usize;
-
+
match inode.file_type() {
FileType::RegularFile => {
inode.n_links -= 1;
@@ -639,20 +789,19 @@ impl Filesystem for AyaFS {
// n_links > 0 -> 只是移除了一个 hard link, 将改动写回
self.update_inode(inode_index, inode);
}
- },
- FileType::Symlink => {
-
- },
+ }
+ FileType::Symlink => {}
FileType::Directory => {
reply.error(EISDIR);
return;
- },
- _ => { // Not implemented!
+ }
+ _ => {
+ // Not implemented!
reply.error(EIO);
return;
}
}
-
+
// 删除 dir entry
if let Err(err_code) =
self.remove_direntry(parent as usize, &mut parent_inode, name, entry_index)
@@ -834,15 +983,19 @@ impl Filesystem for AyaFS {
let current_block_index = current_point / BLOCK_SIZE;
let current_offset = current_point % BLOCK_SIZE;
- let read_length_within_block = if BLOCK_SIZE - current_offset < read_length - read_ptr {
- BLOCK_SIZE - current_offset // 可以读到 block 最后
- } else {
- read_length - read_ptr // 读到中途会停下来
- };
+ let read_length_within_block =
+ if BLOCK_SIZE - current_offset < read_length - read_ptr {
+ BLOCK_SIZE - current_offset // 可以读到 block 最后
+ } else {
+ read_length - read_ptr // 读到中途会停下来
+ };
if let Some(block) = self.access_block::<DataBlock>(&inode, current_block_index) {
- (&mut read_buffer[read_ptr .. read_ptr + read_length_within_block])
- .copy_from_slice(&block.block.0[current_offset .. current_offset + read_length_within_block]);
+ (&mut read_buffer[read_ptr..read_ptr + read_length_within_block])
+ .copy_from_slice(
+ &block.block.0
+ [current_offset..current_offset + read_length_within_block],
+ );
read_ptr += read_length_within_block;
} else {
reply.error(EIO);
@@ -877,7 +1030,12 @@ impl Filesystem for AyaFS {
reply.error(EACCES);
return;
}
- debug!("writing inode {:#x} (offset {} size {})", ino, offset, data.len());
+ debug!(
+ "writing inode {:#x} (offset {} size {})",
+ ino,
+ offset,
+ data.len()
+ );
let write_length = data.len();
let mut write_ptr = 0usize;
@@ -888,25 +1046,37 @@ impl Filesystem for AyaFS {
let current_block_index = current_point / BLOCK_SIZE;
let current_offset = current_point % BLOCK_SIZE;
- let write_length_within_block = if BLOCK_SIZE - current_offset < write_length - write_ptr {
- BLOCK_SIZE - current_offset // 可以写满 block
- } else {
- write_length - write_ptr // 写完 buffer 就停下来
- };
+ let write_length_within_block =
+ if BLOCK_SIZE - current_offset < write_length - write_ptr {
+ BLOCK_SIZE - current_offset // 可以写满 block
+ } else {
+ write_length - write_ptr // 写完 buffer 就停下来
+ };
// 当前块已分配, 直接往里写
- if let Some(block) = self.access_block_mut::<DataBlock>(&inode, current_block_index) {
- debug!("writing {} bytes in block {} within inode", write_length_within_block, current_block_index);
- (block.block.0[current_offset .. current_offset + write_length_within_block])
- .copy_from_slice(&data[write_ptr .. write_ptr + write_length_within_block]);
+ if let Some(block) = self.access_block_mut::<DataBlock>(&inode, current_block_index)
+ {
+ debug!(
+ "writing {} bytes in block {} within inode",
+ write_length_within_block, current_block_index
+ );
+ (block.block.0[current_offset..current_offset + write_length_within_block])
+ .copy_from_slice(&data[write_ptr..write_ptr + write_length_within_block]);
write_ptr += write_length_within_block;
- } else { // 当前块未分配,尝试分配
- if let Some((block_index, block_index_within_inode)) = self.allocate_block_for(&mut inode) {
+ } else {
+ // 当前块未分配,尝试分配
+ if let Some((block_index, block_index_within_inode)) =
+ self.allocate_block_for(&mut inode)
+ {
debug!("writing {} bytes in allocated block {} within inode, block index is {}", write_length_within_block, block_index_within_inode, block_index);
// 能分配, 往里写
- let block = self.access_block_mut::<DataBlock>(&inode, block_index_within_inode).unwrap();
- (block.block.0[current_offset .. current_offset + write_length_within_block])
- .copy_from_slice(&data[write_ptr .. write_ptr + write_length_within_block]);
+ let block = self
+ .access_block_mut::<DataBlock>(&inode, block_index_within_inode)
+ .unwrap();
+ (block.block.0[current_offset..current_offset + write_length_within_block])
+ .copy_from_slice(
+ &data[write_ptr..write_ptr + write_length_within_block],
+ );
write_ptr += write_length_within_block;
} else {
// 分配不了, 没空间了
@@ -1004,7 +1174,10 @@ impl Filesystem for AyaFS {
return;
}
- debug!("reading dir entries from inode {:#x} with offset {}", ino, offset);
+ debug!(
+ "reading dir entries from inode {:#x} with offset {}",
+ ino, offset
+ );
let inode = inode.clone();
self.load_direntry_map(ino as usize, &inode).unwrap();
@@ -1016,12 +1189,15 @@ impl Filesystem for AyaFS {
.enumerate()
.skip(offset as usize)
{
- debug!(" entry {} from inode {:#x} with name {:?}", entry_index, dir_entry.inode, name);
+ debug!(
+ " entry {} from inode {:#x} with name {:?}",
+ entry_index, dir_entry.inode, name
+ );
if reply.add(
dir_entry.inode as u64,
entry_index as i64 + 1,
to_filetype(dir_entry.file_type).expect("not 0x0!"),
- name
+ name,
) {
break;
}