1. 完成基本的测试项的构建

- 测试打开文件读取文件
    - 测试打开目录读物目录
    - 测试文件的读写功能
    - 测试目录创建和删除
    - 测试目录或者文件的访问
2. 将fd挪到fs impl里面完成!
This commit is contained in:
Ekko.bao 2024-07-14 15:55:59 +08:00
parent 82960cfe31
commit 017c52ce13
3 changed files with 589 additions and 219 deletions

673
src/fs_impl/mod.rs Normal file → Executable file
View File

@ -1,7 +1,7 @@
use std::fs; use std::fs::{self, File, ReadDir};
use std::error::Error; use std::error::Error;
use std::io::{self, ErrorKind, Seek as ioSeek, SeekFrom}; use std::io::{self, Seek as ioSeek, SeekFrom, Write};
use crate::lws_vfs::{FileInfo, Fstat}; use crate::lws_vfs::{FileInfo, Fstat};
@ -24,11 +24,18 @@ fn from_metadata(sta: &mut Fstat, metadata: &fs::Metadata) -> Result<(), Box<dyn
Ok(()) Ok(())
} }
#[derive(Debug, Default)]
enum FileHandle {
#[default]
DEFAULT,
FILE(File),
DIR(ReadDir)
}
#[derive(Debug, Default)] #[derive(Debug, Default)]
struct FileFdMgnt { struct FileFdMgnt {
// key is fd, value is FileHandle // key is fd, value is FileHandle
files: HashMap<u64, File>, files: HashMap<u64, FileHandle>,
curr_fd: u64, curr_fd: u64,
} }
@ -58,161 +65,23 @@ impl FileFdMgnt {
} }
Ok(self.curr_fd) Ok(self.curr_fd)
} }
pub fn push(&mut self, handle: File) -> Result<u64, Box<dyn Error>> { pub fn push(&mut self, handle: FileHandle) -> Result<u64, Box<dyn Error>> {
let fd = self.gen_fd()?; let fd = self.gen_fd()?;
println!("push a fd: {}", fd);
self.files.insert(fd, handle); self.files.insert(fd, handle);
Ok(fd) Ok(fd)
} }
pub fn pop(&mut self, fd: u64) -> Option<File> { pub fn pop(&mut self, fd: u64) -> Option<FileHandle> {
println!("pop a fd: {}", fd);
self.files.remove(&fd) self.files.remove(&fd)
} }
} // pub fn get(&mut self, fd: u64) -> Option<&FileHandle> {
pub struct FSImpl{ // self.files.get(&fd)
file_fds: Arc<Mutex<FileFdMgnt>>, // }
} pub fn get_mut(&mut self, fd: u64) -> Option<&mut FileHandle> {
println!("get a fd: {}", fd);
impl FSImpl { self.files.get_mut(&fd)
pub fn fgetattr(&self, path: &String, sta: &mut Fstat, _fi: &mut FileInfo) -> Result<i32, Box<dyn Error>> {
let metadata = fs::metadata(path)?;
from_metadata(sta, &metadata)?;
let perm = get_file_mode_mask(path);
sta.fst_mode = perm as u64;
Ok(0)
}
pub fn fopen(&self, path: &String, _fi: &mut FileInfo) -> Result<fs::File, Box<dyn Error>> {
return Ok(fs::File::open(path)?);
}
pub fn fread(
&self, path: &String,
buffer: &mut Vec<u8>,
_size: &mut usize,
offsize: usize,
_fi: &mut FileInfo,
) -> Result<i32, Box<dyn Error>> {
let mut file = fs::File::open(path)?;
match file.seek_read(buffer, offsize as u64) {
Ok(size) => {
println!(
"size is:{}, buffer is {}",
size,
String::from_utf8(buffer.to_vec()).unwrap()
);
buffer.resize(size, 0)
}
Err(_) => {
buffer.resize(file.stream_position()? as usize - offsize, 0);
}
} }
Ok(0)
}
pub fn fwrite(
&self, path: &String,
buffer: &Vec<u8>,
size: &mut usize,
offsize: usize,
_fi: &mut FileInfo,
) -> Result<i32, Box<dyn Error>> {
let mut file = fs::File::options().write(true).create(true).open(path)?;
match file.seek_write(buffer, offsize as u64) {
Ok(written) => {
*size = written as usize;
}
Err(_) => {
*size = file.stream_position()? as usize - offsize;
}
}
Ok(0)
}
pub fn freaddir(
&self, path: &String,
buffer: &mut Vec<String>,
_size: usize,
_offset: usize,
_fi: &mut FileInfo,
) -> Result<i32, Box<dyn Error>> {
let mut readed = fs::read_dir(path)?;
loop {
match readed.next() {
Some(Ok(entry)) => {
let name = entry.file_name().into_string().unwrap();
buffer.push(name);
}
Some(Err(e)) => {
return Err(Box::new(e));
}
None => {
break;
}
}
}
Ok(0)
}
pub fn fmkdir(&self, path: &String, _mode: u32) -> Result<i32, Box<dyn Error>> {
fs::create_dir(path)?;
Ok(0)
}
pub fn fchown(&self, _path: &String, _uid: u32, _gid: u32) -> Result<i32, Box<dyn Error>> {
Ok(-1)
}
pub fn ftruncate(&self, path: &String, size: u64) -> Result<i32, Box<dyn Error>> {
let mut file = fs::File::options().write(true)
.truncate(true)
.open(path)?;
file.seek(SeekFrom::Start(size))?;
file.set_len(size)?;
Ok(0)
}
pub fn futimens(&self, path: &String, a: &Vec<u64>, m: &Vec<u64>) -> Result<i32, Box<dyn Error>> {
use std::ptr::null_mut;
use winapi::ctypes::c_void;
use winapi::shared::minwindef::DWORD;
use winapi::shared::minwindef::FILETIME;
use winapi::um::fileapi::SetFileTime;
fn system_time_to_file_time(seconds: u64, nanoseconds: u32) -> FILETIME {
let total_nanoseconds = (seconds * 1_000_000_000) + nanoseconds as u64;
let total_100_nanoseconds = total_nanoseconds / 100;
FILETIME {
dwLowDateTime: total_100_nanoseconds as DWORD,
dwHighDateTime: (total_100_nanoseconds >> 32) as DWORD,
}
}
let file = fs::File::options().write(true).open(path)?;
let handle = file.as_raw_handle();
let atime = system_time_to_file_time(a[0], a[1] as u32);
let mtime = system_time_to_file_time(m[0], m[1] as u32);
let result = unsafe { SetFileTime(handle as *mut c_void, null_mut(), &atime, &mtime) };
if result != 0 {
Ok(0)
} else {
Err(Box::new(io::Error::last_os_error()))
}
}
pub fn frelease(&self, _path: &String, _fi: &mut FileInfo) -> Result<i32, Box<dyn Error>> {
if let Some(fh) == self.file_fds.lock().unwrap().pop(fi.fh){
drop(fh);
Ok(0)
} else {
Ok(-1)
}
}
pub fn fsetxattr(
&self, _path: &String,
_name: &str,
_value: &Vec<u8>,
_size: usize,
_flags: u32,
) -> Result<i32, Box<dyn Error>> {
Ok(-1)
}
pub fn fgetxattr(&self, _path: &String, _name: &str, _size: usize) -> Result<i32, Box<dyn Error>> {
Ok(-1)
} }
fn get_file_mode_mask(path: &str) -> u32 { fn get_file_mode_mask(path: &str) -> u32 {
@ -236,15 +105,321 @@ fn get_file_mode_mask(path: &str) -> u32 {
} }
permissions permissions
} }
pub fn faccess(&self, path: &String, mask: u32) -> Result<i32, Box<dyn Error>> { #[derive(Debug, Default)]
let permissions = get_file_mode_mask(path); pub struct FSImpl{
Ok(if permissions & mask != 0 { 0 } else { -1 }) file_fds: Arc<Mutex<FileFdMgnt>>,
} }
pub fn frmdir(&self, path: &String) -> Result<i32, Box<dyn Error>> { impl FSImpl {
fs::remove_dir(path)?;
Ok(0) pub fn new() -> FSImpl {
} FSImpl {
file_fds: Arc::new(Mutex::new(FileFdMgnt::new())),
}
}
pub fn fgetattr(&self, path: &String, sta: &mut Fstat, _fi: &mut FileInfo) -> Result<i32, Box<dyn Error>> {
let metadata = fs::metadata(path)?;
from_metadata(sta, &metadata)?;
let perm = get_file_mode_mask(path);
sta.fst_mode = perm as u64;
Ok(0)
}
pub fn fopen(&self, path: &String, fi: &mut FileInfo) -> Result<i32, Box<dyn Error>> {
let f = fs::File::open(path)?;
let fd = self.file_fds.lock().unwrap().push(FileHandle::FILE(f))?;
fi.fh = fd;
return Ok(0);
}
pub fn fread(
&self, path: &String,
buffer: &mut Vec<u8>,
_size: &mut usize,
offsize: usize,
fi: &mut FileInfo,
) -> Result<i32, Box<dyn Error>> {
let fd = fi.fh;
let mut fds = self.file_fds.lock().unwrap();
let fh: File;
let mut file = if let Some(FileHandle::FILE(f)) = fds.get_mut(fd) {
f
} else {
fh = fs::File::open(path)?;
&fh
};
match file.seek_read(buffer, offsize as u64) {
Ok(size) => {
println!(
"size is:{}, buffer is {}",
size,
String::from_utf8(buffer.to_vec()).unwrap()
);
buffer.resize(size, 0);
}
Err(_) => {
buffer.resize(file.stream_position()? as usize - offsize, 0);
}
}
Ok(0)
}
pub fn fwrite(
&self, path: &String,
buffer: &Vec<u8>,
size: &mut usize,
offsize: usize,
fi: &mut FileInfo,
) -> Result<i32, Box<dyn Error>> {
let fd = fi.fh;
let mut fds = self.file_fds.lock().unwrap();
let fh: File;
let mut file = if let Some(FileHandle::FILE(f)) = fds.get_mut(fd) {
f
} else {
fh = fs::File::options().write(true).create(true).open(path)?;
&fh
};
match file.seek_write(buffer, offsize as u64) {
Ok(written) => {
*size = written as usize;
}
Err(_) => {
*size = file.stream_position()? as usize - offsize;
}
}
Ok(0)
}
/** Read directory
*
* This supersedes the old getdir() interface. New applications
* should use this.
*
* The filesystem may choose between two modes of operation:
*
* 1) The readdir implementation ignores the offset parameter, and
* passes zero to the filler function's offset. The filler
* function will not return '1' (unless an error happens), so the
* whole directory is read in a single readdir operation. This
* works just like the old getdir() method.
*
* 2) The readdir implementation keeps track of the offsets of the
* directory entries. It uses the offset parameter and always
* passes non-zero offset to the filler function. When the buffer
* is full (or an error happens) the filler function will return
* '1'.
*
* Introduced in version 2.3
*/
pub fn freaddir(&self, path: &String, buffer: &mut Vec<String>, _size: usize, _offset: usize, fi: &mut FileInfo,
) -> Result<i32, Box<dyn Error>> {
let mut fh = self.file_fds.lock().unwrap();
let mut collect = move |entry:&mut ReadDir| -> Result<i32, Box<dyn Error>> {
loop {
match entry.next() {
Some(Ok(entry)) => {
let name = entry.file_name().into_string().unwrap();
buffer.push(name);
}
Some(Err(e)) => {
return Err(Box::new(e));
}
None => {
break;
}
}
}
Ok(0)
};
match fh.get_mut(fi.fh){
Some(dir) => {
if let FileHandle::DIR(entry) = dir {
collect(entry)
} else {
collect( &mut fs::read_dir(path)?)
}
},
_ => {
collect( &mut fs::read_dir(path)?)
},
}
}
pub fn fmkdir(&self, path: &String, _mode: u32) -> Result<i32, Box<dyn Error>> {
fs::create_dir(path)?;
Ok(0)
}
pub fn fchown(&self, _path: &String, _uid: u32, _gid: u32) -> Result<i32, Box<dyn Error>> {
Ok(-1)
}
pub fn ftruncate(&self, path: &String, size: u64) -> Result<i32, Box<dyn Error>> {
let mut file = fs::File::options().write(true)
.truncate(true)
.open(path)?;
file.seek(SeekFrom::Start(size))?;
file.set_len(size)?;
Ok(0)
}
pub fn futimens(&self, path: &String, a: &Vec<u64>, m: &Vec<u64>) -> Result<i32, Box<dyn Error>> {
use std::ptr::null_mut;
use winapi::ctypes::c_void;
use winapi::shared::minwindef::DWORD;
use winapi::shared::minwindef::FILETIME;
use winapi::um::fileapi::SetFileTime;
fn system_time_to_file_time(seconds: u64, nanoseconds: u32) -> FILETIME {
let total_nanoseconds = (seconds * 1_000_000_000) + nanoseconds as u64;
let total_100_nanoseconds = total_nanoseconds / 100;
FILETIME {
dwLowDateTime: total_100_nanoseconds as DWORD,
dwHighDateTime: (total_100_nanoseconds >> 32) as DWORD,
}
}
let file = fs::File::options().write(true).open(path)?;
let handle = file.as_raw_handle();
let atime = system_time_to_file_time(a[0], a[1] as u32);
let mtime = system_time_to_file_time(m[0], m[1] as u32);
let result = unsafe { SetFileTime(handle as *mut c_void, null_mut(), &atime, &mtime) };
if result != 0 {
Ok(0)
} else {
Err(Box::new(io::Error::last_os_error()))
}
}
pub fn frelease(&self, _path: &String, fi: &mut FileInfo) -> Result<i32, Box<dyn Error>> {
if let Some(fh) = self.file_fds.lock().unwrap().pop(fi.fh) {
drop(fh);
Ok(0)
} else {
Ok(-1)
}
}
pub fn fsetxattr(
&self, _path: &String,
_name: &str,
_value: &Vec<u8>,
_size: usize,
_flags: u32,
) -> Result<i32, Box<dyn Error>> {
Ok(-1)
}
pub fn fgetxattr(&self, _path: &String, _name: &str, _size: usize) -> Result<i32, Box<dyn Error>> {
Ok(-1)
}
pub fn faccess(&self, path: &String, mask: u32) -> Result<i32, Box<dyn Error>> {
let permissions = get_file_mode_mask(path);
Ok(if permissions & mask != 0 { 0 } else { -1 })
}
pub fn frmdir(&self, path: &String) -> Result<i32, Box<dyn Error>> {
fs::remove_dir(path)?;
Ok(0)
}
/** Possibly flush cached data
*
* BIG NOTE: This is not equivalent to fsync(). It's not a
* request to sync dirty data.
*
* Flush is called on each close() of a file descriptor. So if a
* filesystem wants to return write errors in close() and the file
* has cached dirty data, this is a good place to write back data
* and return any errors. Since many applications ignore close()
* errors this is not always useful.
*
* NOTE: The flush() method may be called more than once for each
* open(). This happens if more than one file descriptor refers
* to an opened file due to dup(), dup2() or fork() calls. It is
* not possible to determine if a flush is final, so each flush
* should be treated equally. Multiple write-flush sequences are
* relatively rare, so this shouldn't be a problem.
*
* Filesystems shouldn't assume that flush will always be called
* after some writes, or that if will be called at all.
*
* Changed in version 2.2
*/
pub fn fflush(&self, _path: &String, fi: &mut FileInfo) -> Result<i32, Box<dyn Error>> {
let fd = fi.fh;
let mut fmap = self.file_fds.lock().unwrap();
let file = fmap.get_mut(fd).unwrap();
match file {
FileHandle::FILE(fh) => {
fh.flush()?;
Ok(0)
}
_ => {
Ok(-1)
}
}
}
/**
* Create and open a file
*
* If the file does not exist, first create it with the specified
* mode, and then open it.
*
* If this method is not implemented or under Linux kernel
* versions earlier than 2.6.15, the mknod() and open() methods
* will be called instead.
*
* Introduced in version 2.5
*/
pub fn fcreate(&self, path:&String, mode:u32, fi:&mut FileInfo) -> Result<i32, Box<dyn Error>> {
let file = File::options().write(true).access_mode(mode).create(true).open(path)?;
let fd = self.file_fds.lock().unwrap().push(FileHandle::FILE(file))?;
fi.fh = fd;
Ok(0)
}
/**
* Remove a file
*
* If that file was the last link to a file and no processes have
* the file open the file is deleted and the space it was using is
* made available for reuse.
*
* If the file is open, the file may remain in existence until the
* last file descriptor referring to it is closed.
*
* Introduced in version 2.2
*/
pub fn funlink(&self, path: &String) ->Result<i32, Box<dyn Error>>{
fs::remove_file(path)?;
Ok(0)
}
/** Open directory
*
* Unless the 'default_permissions' mount option is given,
* this method should check if opendir is permitted for this
* directory. Optionally opendir may also return an arbitrary
* filehandle in the fuse_file_info structure, which will be
* passed to readdir, releasedir and fsyncdir.
*
* Introduced in version 2.3
*/
pub fn fopendir(&self, path:&String, fi:&mut FileInfo) -> Result<i32, Box<dyn Error>> {
let entries = fs::read_dir(path)?;
let fd = self.file_fds.lock().unwrap().push(FileHandle::DIR(entries))?;
fi.fh = fd;
Ok(0)
}
/** Release directory
*
* Introduced in version 2.3
*/
pub fn freleasedir(&self, _path: &String, fi: &mut FileInfo) -> Result<i32, Box<dyn Error>> {
let fd = fi.fh;
if let Some(FileHandle::DIR(_entries)) = self.file_fds.lock().unwrap().pop(fd) {
Ok(0)
} else {
Ok(-1)
}
}
} }
#[test] #[test]
@ -260,25 +435,26 @@ fn test_fread() {
let ref_buffer = b"This is a test file."; let ref_buffer = b"This is a test file.";
let _ = file.seek_write(ref_buffer, 0); let _ = file.seek_write(ref_buffer, 0);
let fs = FSImpl::new();
let mut fi = FileInfo::default(); let mut fi = FileInfo::default();
//read from file middle //read from file middle
let mut size = 4; let mut size = 4;
let mut offsize: usize = 5; let mut offsize: usize = 5;
let mut buffer = vec![0; size]; let mut buffer = vec![0; size];
let _ = fread(&path, &mut buffer, &mut size, offsize, &mut fi); let _ = fs.fread(&path, &mut buffer, &mut size, offsize, &mut fi);
assert_eq!(buffer.len(), 4); assert_eq!(buffer.len(), 4);
assert_eq!(buffer, b"is a"); assert_eq!(buffer, b"is a");
//read from file head //read from file head
offsize = 0; offsize = 0;
let _ = fread(&path, &mut buffer, &mut size, offsize, &mut fi); let _ = fs.fread(&path, &mut buffer, &mut size, offsize, &mut fi);
assert_eq!(buffer.len(), 4); assert_eq!(buffer.len(), 4);
assert_eq!(buffer, b"This"); assert_eq!(buffer, b"This");
// read from the file tail, read len > file remain // read from the file tail, read len > file remain
offsize = ref_buffer.len() - 2; offsize = ref_buffer.len() - 2;
let _ = fread(&path, &mut buffer, &mut size, offsize, &mut fi); let _ = fs.fread(&path, &mut buffer, &mut size, offsize, &mut fi);
assert_eq!(buffer.len(), 2); assert_eq!(buffer.len(), 2);
assert_eq!(buffer, b"e."); assert_eq!(buffer, b"e.");
@ -290,18 +466,20 @@ fn test_fwrite() {
use crate::fs_impl::*; use crate::fs_impl::*;
let path = String::from("test_fwrite.txt"); let path = String::from("test_fwrite.txt");
let _ = fs::remove_file(&path); let _ = fs::remove_file(&path);
let mut buffer = Vec::from("This is a test file"); let buffer = Vec::from("This is a test file");
let mut size = buffer.len(); let mut size = buffer.len();
let fs = FSImpl::new();
//write from file head //write from file head
let mut offsize: usize = 0; let mut offsize: usize = 0;
let mut fi = FileInfo::default(); let mut fi = FileInfo::default();
let _ = fwrite(&path, &buffer, &mut size, offsize, &mut fi); let _ = fs.fwrite(&path, &buffer, &mut size, offsize, &mut fi);
assert_eq!(size, buffer.len()); assert_eq!(size, buffer.len());
//write from file middle //write from file middle
offsize = 5; offsize = 5;
let _ = fwrite(&path, &buffer, &mut size, offsize, &mut fi); let _ = fs.fwrite(&path, &buffer, &mut size, offsize, &mut fi);
assert_eq!(size, buffer.len()); assert_eq!(size, buffer.len());
let file_metadata = fs::metadata(&path).unwrap(); let file_metadata = fs::metadata(&path).unwrap();
let file_size = file_metadata.len(); let file_size = file_metadata.len();
@ -309,7 +487,7 @@ fn test_fwrite() {
//write from file ended //write from file ended
offsize = file_size as usize + 10; offsize = file_size as usize + 10;
let _ = fwrite(&path, &buffer, &mut size, offsize, &mut fi); let _ = fs.fwrite(&path, &buffer, &mut size, offsize, &mut fi);
assert_eq!(size, buffer.len()); assert_eq!(size, buffer.len());
let file_metadata = fs::metadata(&path).unwrap(); let file_metadata = fs::metadata(&path).unwrap();
let file_size = file_metadata.len(); let file_size = file_metadata.len();
@ -323,14 +501,17 @@ fn test_dir() {
use std::path::Path; use std::path::Path;
let path = String::from("test_dir"); let path = String::from("test_dir");
let sub_path = String::from("test_dir/test_sub_dir"); let sub_path = String::from("test_dir/test_sub_dir");
let fs = FSImpl::new();
//创建父目录 //创建父目录
let _ = fmkdir(&path, 0); let _ = fs.fmkdir(&path, 0);
//创建子目录 //创建子目录
let _ = fmkdir(&sub_path, 0); let _ = fs.fmkdir(&sub_path, 0);
assert_eq!(true, Path::new(&sub_path).is_dir()); assert_eq!(true, Path::new(&sub_path).is_dir());
assert_eq!(true, Path::new(&path).is_dir()); assert_eq!(true, Path::new(&path).is_dir());
//一次性创建多级目录 //一次性创建多级目录
let ret = fmkdir(&String::from("patent/child"), 0); let ret = fs.fmkdir(&String::from("patent/child"), 0);
assert_ne!( assert_ne!(
match ret { match ret {
Ok(ret) => ret, Ok(ret) => ret,
@ -338,28 +519,136 @@ fn test_dir() {
}, },
0 0
); );
fs::remove_dir_all(path); let _ = fs::remove_dir_all(path);
} }
// let result = fwrite(&path, &buffer, &mut size, offsize, &mut fi);
// println!("result: {:?}", result); #[test]
// println!("size: {:?}", size); fn test_access() {
// println!("buffer: {:?}", buffer); let path = String::from("target/debug/build");
// let result = freaddir(&path, &mut vec![], 0, 0, &mut fi); let fs = FSImpl::new();
// println!("result: {:?}", result); //access a existed file
// println!("buffer: {:?}", buffer); let ret = fs.faccess(&path, 0o777);
// let result = fmkdir(&path, 0); assert_eq!(match ret {
// println!("result: {:?}", result); Ok(ret) => ret,
// let result = fchown(&path, 0, 0); Err(_) => -1,
// println!("result: {:?}", result); }, 0);
// let result = ftruncate(&path, 100); }
// println!("result: {:?}", result); #[test]
// let result = futimens(&path, &vec![100, 0], &vec![100, 0]); fn test_access_ne() {
// println!("result: {:?}", result); let path = String::from("target/xxx");
// let result = frelease(&path, &mut fi); let fs = FSImpl::new();
// println!("result: {:?}", result); //acess a not exist file
// let result = fsetxattr(&path, "test", &vec![1,2,3], 3, 0); let ret = fs.faccess(&path, 0o777);
// println!("result: {:?}", result); assert_ne!(match ret {
// let result = fgetxattr(&path, "test", 100); Ok(ret) => ret,
// println!("result: {:?}", result); Err(_) => -1,
// let result = faccess(&path, 0o777); }, 0);
// println!("result: {:?}", result); }
#[test]
fn test_mkdir_not_existed_multi_level() {
let path = String::from("test_mkdir_not_existed_multi_level/sub/sub");
let fs = FSImpl::new();
//mkdir a multi not existed level dir
let ret = fs.fmkdir(&path, 0);
assert_ne!(match ret {
Ok(ret) => ret,
Err(_) => -1,
}, 0);
let _ = fs::remove_dir_all(path);
}
#[test]
fn test_mkdir_not_existed_level() {
let path = String::from("test_mkdir_not_existed_level");
let fs = FSImpl::new();
//mkdir a not existed single level dir
let ret = fs.fmkdir(&path, 0);
assert_eq!(match ret {
Ok(ret) => ret,
Err(_) => -1,
}, 0);
let path = String::from("test_mkdir_not_existed_level/sub");
let fs = FSImpl::new();
//mkdir a existed multi level dir
let ret = fs.fmkdir(&path, 0);
assert_eq!(match ret {
Ok(ret) => ret,
Err(_) => -1,
}, 0);
let _ = fs::remove_dir_all(&String::from("test_mkdir_not_existed_level"));
}
#[test]
fn test_mkdir_existed() {
let path = String::from("target");
let fs = FSImpl::new();
//mkdir a existed dir
let ret = fs.fmkdir(&path, 0);
assert_eq!(match ret {
Ok(ret) => ret,
Err(_) => -1,
}, -1);
}
#[test]
fn test_read_a_file_flow() {
let path = String::from("test/pattern/read.txt");
let fs = FSImpl::new();
let mut size = 5;
let mut buffer = vec![0; size];
let mut offset = 0;
let mut fi = vec![FileInfo::default(), FileInfo::default()];
let get_ret = |ret: Result<i32, Box<dyn Error>> | match ret {
Ok(ret) => ret,
Err(_) => -1,
};
let ret= fs.fopen(&path, &mut fi[0]);
println!("fopen file ok fd = {}", fi[0].fh);
assert_eq!(get_ret(ret), 0);
let ret = fs.fread(&path, &mut buffer, &mut size,offset, &mut fi[0]);
assert_eq!(get_ret(ret), 0);
assert_eq!(buffer, Vec::from("12345"));
let ret= fs.fopen(&path, &mut fi[1]);
println!("fopen file ok fd = {}", fi[1].fh);
assert_eq!(get_ret(ret), 0);
offset = 9;
let ret = fs.fread(&path, &mut buffer, &mut size,offset, &mut fi[1]);
assert_eq!(get_ret(ret), 0);
assert_eq!(buffer, Vec::from("abcde"));
let ret = fs.frelease(&path, &mut fi[0]);
assert_eq!(get_ret(ret), 0);
let ret = fs.frelease(&path, &mut fi[1]);
assert_eq!(get_ret(ret), 0);
}
#[test]
fn test_read_a_dir_flow() {
let path = String::from("./src");
let fs = FSImpl::new();
let size = 0;
let mut buffer: Vec<String> = vec![];
let offset = 0;
let mut fi = vec![FileInfo::default(), FileInfo::default()];
let get_ret = |ret: Result<i32, Box<dyn Error>> | match ret {
Ok(ret) => ret,
Err(_) => -1,
};
let ret= fs.fopendir(&path, &mut fi[0]);
println!("fopen dir ok fd = {}", fi[0].fh);
assert_eq!(get_ret(ret), 0);
let ret = fs.freaddir(&path, &mut buffer, size, offset, &mut fi[0]);
assert_eq!(get_ret(ret), 0);
println!("buffer = {:?}", buffer);
let ret = fs.freleasedir(&path, &mut fi[0]);
assert_eq!(get_ret(ret), 0);
}

133
src/lib.rs Normal file → Executable file
View File

@ -1,13 +1,16 @@
use lws_vfs::lws_vfs_server::LwsVfs; use lws_vfs::lws_vfs_server::LwsVfs;
use lws_vfs::{ use lws_vfs::{
Access, Chown, FileInfo, Flush, Fstat, Getattr, Getxattr, HelloReply, HelloRequest, Mkdir, Access, Chown, FileInfo, Flush, Fstat, Getattr, Getxattr, HelloReply, HelloRequest, Mkdir,
Open, Read, Readdir, Release, Rmdir, Setxattr, Truncate, Utimens, Write, Flush, Open, Read, Readdir, Release, Rmdir, Setxattr, Truncate, Utimens, Write, Create, Unlink, Opendir, Releasedir
}; };
use self::fs_impl::FSImpl;
use serde_json::{self, Value}; use serde_json::{self, Value};
use std::error::Error; use std::error::Error;
use std::fs::File; use std::fs::File;
use std::io::{BufReader, Read as _}; use std::io::Read as _;
use tonic::{Request, Response, Status}; use tonic::{Request, Response, Status};
use std::collections::HashMap;
mod fs_impl; mod fs_impl;
pub mod lws_vfs { pub mod lws_vfs {
tonic::include_proto!("lws_vfs"); tonic::include_proto!("lws_vfs");
@ -69,14 +72,14 @@ impl Config {
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct LwsVfsIns { pub struct LwsVfsIns {
pub config: Config, pub config: Config,
file_fds: Arc<Mutex<FileFdMgnt>>, pub fs: FSImpl,
} }
impl LwsVfsIns { impl LwsVfsIns {
pub fn new(json: &str) -> Result<LwsVfsIns, Box<dyn Error>> { pub fn new(json: &str) -> Result<LwsVfsIns, Box<dyn Error>> {
Ok(LwsVfsIns { Ok(LwsVfsIns {
config: Config::new(json)?, config: Config::new(json)?,
file_fds: Arc::new(Mutex::new(FileFdMgnt::new())), fs: FSImpl::new(),
}) })
} }
fn lpath(&self, path: &String) -> String { fn lpath(&self, path: &String) -> String {
@ -112,7 +115,7 @@ impl LwsVfs for LwsVfsIns {
let path = &self.lpath(&request.path); let path = &self.lpath(&request.path);
let mut fstat = Fstat::default(); let mut fstat = Fstat::default();
let mut fi = FileInfo::default(); let mut fi = FileInfo::default();
let ret = match fs_impl::fgetattr(path, &mut fstat, &mut fi) { let ret = match self.fs.fgetattr(path, &mut fstat, &mut fi) {
Ok(ret) => ret, Ok(ret) => ret,
Err(e) => { Err(e) => {
println!("Error getting file metadata: {:?}", e); println!("Error getting file metadata: {:?}", e);
@ -131,14 +134,8 @@ impl LwsVfs for LwsVfsIns {
let request = request.into_inner(); let request = request.into_inner();
let path = &self.lpath(&request.path); let path = &self.lpath(&request.path);
let mut fi = request.fi.unwrap(); let mut fi = request.fi.unwrap();
let ret = match fs_impl::fopen(path, &mut fi) { let ret = match self.fs.fopen(path, &mut fi) {
Ok(file) => { Ok(_) => {
match self.file_fds.lock().unwrap().push(file) {
Ok(fd) => fi.fh = fd,
Err(e) => {
println!("Error pushing file[{}]: {:?}", path, e);
}
};
0 0
} }
Err(e) => { Err(e) => {
@ -164,7 +161,7 @@ impl LwsVfs for LwsVfsIns {
unsafe { unsafe {
buff.set_len(size); buff.set_len(size);
} }
match fs_impl::fread(path, &mut buff, &mut size, offset, &mut fi) { match self.fs.fread(path, &mut buff, &mut size, offset, &mut fi) {
Ok(ret) => { Ok(ret) => {
let reply = Read { let reply = Read {
path: request.path, path: request.path,
@ -197,7 +194,7 @@ impl LwsVfs for LwsVfsIns {
let buff = request.buff; let buff = request.buff;
let mut size = request.size as usize; let mut size = request.size as usize;
let offset = request.offset as usize; let offset = request.offset as usize;
let ret = match fs_impl::fwrite(path, &buff, &mut size, offset, &mut fi) { let ret = match self.fs.fwrite(path, &buff, &mut size, offset, &mut fi) {
Ok(ret) => ret, Ok(ret) => ret,
Err(e) => { Err(e) => {
println!("Error fwrite file[{}]: {:?}", path, e); println!("Error fwrite file[{}]: {:?}", path, e);
@ -215,7 +212,7 @@ impl LwsVfs for LwsVfsIns {
let request = request.into_inner(); let request = request.into_inner();
let path = &self.lpath(&request.path); let path = &self.lpath(&request.path);
let mask = request.mask; let mask = request.mask;
let ret = match fs_impl::faccess(path, mask) { let ret = match self.fs.faccess(path, mask) {
Ok(ret) => ret, Ok(ret) => ret,
Err(e) => { Err(e) => {
println!("Error access file[{}]: {:?}", path, e); println!("Error access file[{}]: {:?}", path, e);
@ -237,7 +234,7 @@ impl LwsVfs for LwsVfsIns {
let value = req.value; let value = req.value;
let size = req.size as usize; let size = req.size as usize;
let flags = req.flags; let flags = req.flags;
let ret = match fs_impl::fsetxattr(path, name, &value, size, flags) { let ret = match self.fs.fsetxattr(path, name, &value, size, flags) {
Ok(ret) => ret, Ok(ret) => ret,
Err(e) => { Err(e) => {
println!("Error: setxattr file[{}]: {:?}", path, e); println!("Error: setxattr file[{}]: {:?}", path, e);
@ -255,7 +252,7 @@ impl LwsVfs for LwsVfsIns {
let path = &self.lpath(&req.path); let path = &self.lpath(&req.path);
let name = req.name.as_ref(); let name = req.name.as_ref();
let size = req.size as usize; let size = req.size as usize;
let ret = match fs_impl::fgetxattr(path, name, size) { let ret = match self.fs.fgetxattr(path, name, size) {
Ok(ret) => ret, Ok(ret) => ret,
Err(e) => { Err(e) => {
println!("Error: getxattr file[{}]: {:?}", path, e); println!("Error: getxattr file[{}]: {:?}", path, e);
@ -276,7 +273,7 @@ impl LwsVfs for LwsVfsIns {
let offset = request.offset as usize; let offset = request.offset as usize;
let mut dirs: Vec<String> = Vec::new(); let mut dirs: Vec<String> = Vec::new();
let size = 0; let size = 0;
let ret = match fs_impl::freaddir(path, &mut dirs, size, offset, &mut fi) { let ret = match self.fs.freaddir(path, &mut dirs, size, offset, &mut fi) {
Ok(ret) => ret, Ok(ret) => ret,
Err(e) => { Err(e) => {
println!("Error: readdir file[{}]: {:?}", path, e); println!("Error: readdir file[{}]: {:?}", path, e);
@ -294,7 +291,7 @@ impl LwsVfs for LwsVfsIns {
let request = request.into_inner(); let request = request.into_inner();
let path = &self.lpath(&request.path); let path = &self.lpath(&request.path);
let mode = request.mode; let mode = request.mode;
let ret = match fs_impl::fmkdir(&path, mode) { let ret = match self.fs.fmkdir(&path, mode) {
Ok(ret) => ret, Ok(ret) => ret,
Err(e) => { Err(e) => {
println!("Error: mkdir [{}]: {:?}", path, e); println!("Error: mkdir [{}]: {:?}", path, e);
@ -311,7 +308,7 @@ impl LwsVfs for LwsVfsIns {
let request = request.into_inner(); let request = request.into_inner();
let path = &self.lpath(&request.path); let path = &self.lpath(&request.path);
let size = request.size as u64; let size = request.size as u64;
let ret = match fs_impl::ftruncate(path, size) { let ret = match self.fs.ftruncate(path, size) {
Ok(ret) => ret, Ok(ret) => ret,
Err(e) => { Err(e) => {
println!("Error: truncate file[{}]: {:?}", path, e); println!("Error: truncate file[{}]: {:?}", path, e);
@ -330,7 +327,7 @@ impl LwsVfs for LwsVfsIns {
let path = &self.lpath(&request.path); let path = &self.lpath(&request.path);
let a_time = vec![request.ts[0].tv_sec as u64, request.ts[0].tv_nsec as u64]; let a_time = vec![request.ts[0].tv_sec as u64, request.ts[0].tv_nsec as u64];
let m_time = vec![request.ts[1].tv_sec as u64, request.ts[1].tv_nsec as u64]; let m_time = vec![request.ts[1].tv_sec as u64, request.ts[1].tv_nsec as u64];
let ret = match fs_impl::futimens(path, &a_time, &m_time) { let ret = match self.fs.futimens(path, &a_time, &m_time) {
Ok(ret) => ret, Ok(ret) => ret,
Err(e) => { Err(e) => {
println!("Error: futimens file[{}]: {:?}", path, e); println!("Error: futimens file[{}]: {:?}", path, e);
@ -349,7 +346,7 @@ impl LwsVfs for LwsVfsIns {
let path = &self.lpath(&request.path); let path = &self.lpath(&request.path);
let uid = request.uid as u32; let uid = request.uid as u32;
let gid = request.gid as u32; let gid = request.gid as u32;
let ret = match fs_impl::fchown(path, uid, gid) { let ret = match self.fs.fchown(path, uid, gid) {
Ok(ret) => ret, Ok(ret) => ret,
Err(e) => { Err(e) => {
println!("Error: chown file[{}]: {:?}", path, e); println!("Error: chown file[{}]: {:?}", path, e);
@ -366,8 +363,7 @@ impl LwsVfs for LwsVfsIns {
let request = request.into_inner(); let request = request.into_inner();
let path = &self.lpath(&request.path); let path = &self.lpath(&request.path);
let mut fi = request.fi.unwrap(); let mut fi = request.fi.unwrap();
self.file_fds.lock().unwrap().pop(fi.fh); let ret = match self.fs.frelease(path, &mut fi) {
let ret = match fs_impl::frelease(path, &mut fi) {
Ok(ret) => ret, Ok(ret) => ret,
Err(e) => { Err(e) => {
println!("Error: release file[{}]: {:?}", path, e); println!("Error: release file[{}]: {:?}", path, e);
@ -383,7 +379,7 @@ impl LwsVfs for LwsVfsIns {
async fn frmdir(&self, request: Request<Rmdir>) -> Result<Response<Rmdir>, Status> { async fn frmdir(&self, request: Request<Rmdir>) -> Result<Response<Rmdir>, Status> {
let request = request.into_inner(); let request = request.into_inner();
let path = &self.lpath(&request.path); let path = &self.lpath(&request.path);
let ret = match fs_impl::frmdir(path) { let ret = match self.fs.frmdir(path) {
Ok(ret) => ret, Ok(ret) => ret,
Err(e) => { Err(e) => {
println!("Error: rmdir [{}]: {:?}", path, e); println!("Error: rmdir [{}]: {:?}", path, e);
@ -401,6 +397,89 @@ impl LwsVfs for LwsVfsIns {
let request = request.into_inner(); let request = request.into_inner();
let path = &self.lpath(&request.path); let path = &self.lpath(&request.path);
let mut fi = request.fi.unwrap(); let mut fi = request.fi.unwrap();
self.file_fds.lock().unwrap().pop(fi.fh); let ret = match self.fs.fflush(path, &mut fi) {
Ok(ret) => ret,
Err(e) => {
println!("Error: flush file[{}]: {:?}", path, e);
-1
}
};
let reply = Flush {
ret,
..Flush::default()
};
Ok(Response::new(reply))
}
async fn fcreate(&self, request: Request<Create>) -> Result<Response<Create>, Status> {
let request = request.into_inner();
let path = &self.lpath(&request.path);
let mode = request.mode as u32;
let mut fi = request.fi.unwrap();
let ret = match self.fs.fcreate(path, mode, &mut fi) {
Ok(ret) => ret,
Err(e) => {
println!("Error: create file[{}]: {:?}", path, e);
-1
}
};
let reply = Create {
ret,
..Create::default()
};
Ok(Response::new(reply))
}
async fn funlink(&self, request: Request<Unlink>) -> Result<Response<Unlink>, Status> {
let request = request.into_inner();
let path = &self.lpath(&request.path);
let ret = match self.fs.funlink(path) {
Ok(ret) => ret,
Err(e) => {
println!("Error: unlink file[{}]: {:?}", path, e);
-1
}
};
let reply = Unlink {
ret,
path: request.path,
};
Ok(Response::new(reply))
}
async fn fopendir(&self,request: Request<Opendir>) -> Result<Response<Opendir>, Status> {
let request = request.into_inner();
let path = &self.lpath(&request.path);
let mut fi = request.fi.unwrap();
let ret = match self.fs.fopendir(path, &mut fi) {
Ok(ret) => ret,
Err(e) => {
println!("Error: opendir file[{}]: {:?}", path, e);
-1
}
};
let reply = Opendir {
ret,
..Opendir::default()
};
Ok(Response::new(reply))
}
async fn freleasedir(&self, request: Request<Releasedir>) -> Result<Response<Releasedir>, Status> {
let request = request.into_inner();
let path = &self.lpath(&request.path);
let mut fi = request.fi.unwrap();
let ret = match self.fs.freleasedir(path, &mut fi) {
Ok(ret) => ret,
Err(e) => {
println!("Error: releasedir file[{}]: {:?}", path, e);
-1
}
};
let reply = Releasedir {
ret,
..Releasedir::default()
};
Ok(Response::new(reply))
} }
} }

2
test/pattern/read.txt Executable file
View File

@ -0,0 +1,2 @@
1234567
abcdefg