From b3db8a5a710aa0890c80241ffb3fd9792bf1cbe7 Mon Sep 17 00:00:00 2001 From: Chuyan Zhang Date: Wed, 29 Nov 2023 13:29:03 -0800 Subject: Add rename --- src/filesystem/trait_impl.rs | 332 +++++++++++++++++++++++++++++++++---------- 1 file changed, 254 insertions(+), 78 deletions(-) (limited to 'src/filesystem/trait_impl.rs') 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, mtime: Option, _ctime: Option, - fh: Option, // 当 setattr 被 ftruncate invoke 时会提供 fh - _crtime: Option, // 忽略 - _chgtime: Option, // 忽略 + fh: Option, // 当 setattr 被 ftruncate invoke 时会提供 fh + _crtime: Option, // 忽略 + _chgtime: Option, // 忽略 _bkuptime: Option, // 忽略 - _flags: Option, // 忽略 + _flags: Option, // 忽略 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::(&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::(&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::(&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::( + &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::(&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::(&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::(&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::(&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::(&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::(&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; } -- cgit v1.2.3-70-g09d2