From 017c52ce13afc4e8e4b7299ea48c00ea2a34afb4 Mon Sep 17 00:00:00 2001 From: Begild Date: Sun, 14 Jul 2024 15:55:59 +0800 Subject: [PATCH] =?UTF-8?q?1.=20=E5=AE=8C=E6=88=90=E5=9F=BA=E6=9C=AC?= =?UTF-8?q?=E7=9A=84=E6=B5=8B=E8=AF=95=E9=A1=B9=E7=9A=84=E6=9E=84=E5=BB=BA?= =?UTF-8?q?=20=20=20=20=20-=20=E6=B5=8B=E8=AF=95=E6=89=93=E5=BC=80?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E8=AF=BB=E5=8F=96=E6=96=87=E4=BB=B6=20=20=20?= =?UTF-8?q?=20=20-=20=E6=B5=8B=E8=AF=95=E6=89=93=E5=BC=80=E7=9B=AE?= =?UTF-8?q?=E5=BD=95=E8=AF=BB=E7=89=A9=E7=9B=AE=E5=BD=95=20=20=20=20=20-?= =?UTF-8?q?=20=E6=B5=8B=E8=AF=95=E6=96=87=E4=BB=B6=E7=9A=84=E8=AF=BB?= =?UTF-8?q?=E5=86=99=E5=8A=9F=E8=83=BD=20=20=20=20=20-=20=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E7=9B=AE=E5=BD=95=E5=88=9B=E5=BB=BA=E5=92=8C=E5=88=A0?= =?UTF-8?q?=E9=99=A4=20=20=20=20=20-=20=E6=B5=8B=E8=AF=95=E7=9B=AE?= =?UTF-8?q?=E5=BD=95=E6=88=96=E8=80=85=E6=96=87=E4=BB=B6=E7=9A=84=E8=AE=BF?= =?UTF-8?q?=E9=97=AE=202.=20=E5=B0=86fd=E6=8C=AA=E5=88=B0fs=20impl?= =?UTF-8?q?=E9=87=8C=E9=9D=A2=E5=AE=8C=E6=88=90=EF=BC=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/fs_impl/mod.rs | 673 ++++++++++++++++++++++++++++++------------ src/lib.rs | 133 +++++++-- test/pattern/read.txt | 2 + 3 files changed, 589 insertions(+), 219 deletions(-) mode change 100644 => 100755 src/fs_impl/mod.rs mode change 100644 => 100755 src/lib.rs create mode 100755 test/pattern/read.txt diff --git a/src/fs_impl/mod.rs b/src/fs_impl/mod.rs old mode 100644 new mode 100755 index 95d50a2..b0c177d --- a/src/fs_impl/mod.rs +++ b/src/fs_impl/mod.rs @@ -1,7 +1,7 @@ -use std::fs; +use std::fs::{self, File, ReadDir}; 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}; @@ -24,11 +24,18 @@ fn from_metadata(sta: &mut Fstat, metadata: &fs::Metadata) -> Result<(), Box, + files: HashMap, curr_fd: u64, } @@ -58,161 +65,23 @@ impl FileFdMgnt { } Ok(self.curr_fd) } - pub fn push(&mut self, handle: File) -> Result> { + pub fn push(&mut self, handle: FileHandle) -> Result> { let fd = self.gen_fd()?; + println!("push a fd: {}", fd); self.files.insert(fd, handle); Ok(fd) } - pub fn pop(&mut self, fd: u64) -> Option { + pub fn pop(&mut self, fd: u64) -> Option { + println!("pop a fd: {}", fd); self.files.remove(&fd) } -} -pub struct FSImpl{ - file_fds: Arc>, -} - -impl FSImpl { -pub fn fgetattr(&self, path: &String, sta: &mut Fstat, _fi: &mut FileInfo) -> Result> { - 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> { - return Ok(fs::File::open(path)?); -} - -pub fn fread( - &self, path: &String, - buffer: &mut Vec, - _size: &mut usize, - offsize: usize, - _fi: &mut FileInfo, -) -> Result> { - 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); - } + // pub fn get(&mut self, fd: u64) -> Option<&FileHandle> { + // self.files.get(&fd) + // } + pub fn get_mut(&mut self, fd: u64) -> Option<&mut FileHandle> { + println!("get a fd: {}", fd); + self.files.get_mut(&fd) } - Ok(0) -} - -pub fn fwrite( - &self, path: &String, - buffer: &Vec, - size: &mut usize, - offsize: usize, - _fi: &mut FileInfo, -) -> Result> { - 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, - _size: usize, - _offset: usize, - _fi: &mut FileInfo, -) -> Result> { - 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> { - fs::create_dir(path)?; - Ok(0) -} -pub fn fchown(&self, _path: &String, _uid: u32, _gid: u32) -> Result> { - Ok(-1) -} -pub fn ftruncate(&self, path: &String, size: u64) -> Result> { - 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, m: &Vec) -> Result> { - 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> { - 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, - _size: usize, - _flags: u32, -) -> Result> { - Ok(-1) -} -pub fn fgetxattr(&self, _path: &String, _name: &str, _size: usize) -> Result> { - Ok(-1) } fn get_file_mode_mask(path: &str) -> u32 { @@ -236,15 +105,321 @@ fn get_file_mode_mask(path: &str) -> u32 { } permissions } -pub fn faccess(&self, path: &String, mask: u32) -> Result> { - let permissions = get_file_mode_mask(path); - Ok(if permissions & mask != 0 { 0 } else { -1 }) +#[derive(Debug, Default)] +pub struct FSImpl{ + file_fds: Arc>, } -pub fn frmdir(&self, path: &String) -> Result> { - fs::remove_dir(path)?; - Ok(0) -} +impl FSImpl { + + 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> { + 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> { + 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, + _size: &mut usize, + offsize: usize, + fi: &mut FileInfo, + ) -> Result> { + + 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, + size: &mut usize, + offsize: usize, + fi: &mut FileInfo, + ) -> Result> { + 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, _size: usize, _offset: usize, fi: &mut FileInfo, + ) -> Result> { + let mut fh = self.file_fds.lock().unwrap(); + let mut collect = move |entry:&mut ReadDir| -> Result> { + 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> { + fs::create_dir(path)?; + Ok(0) + } + pub fn fchown(&self, _path: &String, _uid: u32, _gid: u32) -> Result> { + Ok(-1) + } + pub fn ftruncate(&self, path: &String, size: u64) -> Result> { + 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, m: &Vec) -> Result> { + 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> { + 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, + _size: usize, + _flags: u32, + ) -> Result> { + Ok(-1) + } + pub fn fgetxattr(&self, _path: &String, _name: &str, _size: usize) -> Result> { + Ok(-1) + } + + pub fn faccess(&self, path: &String, mask: u32) -> Result> { + let permissions = get_file_mode_mask(path); + Ok(if permissions & mask != 0 { 0 } else { -1 }) + } + + pub fn frmdir(&self, path: &String) -> Result> { + 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> { + 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> { + 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>{ + 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> { + 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> { + let fd = fi.fh; + if let Some(FileHandle::DIR(_entries)) = self.file_fds.lock().unwrap().pop(fd) { + Ok(0) + } else { + Ok(-1) + } + } } #[test] @@ -260,25 +435,26 @@ fn test_fread() { let ref_buffer = b"This is a test file."; let _ = file.seek_write(ref_buffer, 0); + let fs = FSImpl::new(); let mut fi = FileInfo::default(); //read from file middle let mut size = 4; let mut offsize: usize = 5; 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, b"is a"); //read from file head 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, b"This"); // read from the file tail, read len > file remain 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, b"e."); @@ -290,18 +466,20 @@ fn test_fwrite() { use crate::fs_impl::*; let path = String::from("test_fwrite.txt"); 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 fs = FSImpl::new(); + //write from file head let mut offsize: usize = 0; 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()); //write from file middle 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()); let file_metadata = fs::metadata(&path).unwrap(); let file_size = file_metadata.len(); @@ -309,7 +487,7 @@ fn test_fwrite() { //write from file ended 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()); let file_metadata = fs::metadata(&path).unwrap(); let file_size = file_metadata.len(); @@ -323,14 +501,17 @@ fn test_dir() { use std::path::Path; let path = String::from("test_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(&path).is_dir()); //一次性创建多级目录 - let ret = fmkdir(&String::from("patent/child"), 0); + let ret = fs.fmkdir(&String::from("patent/child"), 0); assert_ne!( match ret { Ok(ret) => ret, @@ -338,28 +519,136 @@ fn test_dir() { }, 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); -// println!("size: {:?}", size); -// println!("buffer: {:?}", buffer); -// let result = freaddir(&path, &mut vec![], 0, 0, &mut fi); -// println!("result: {:?}", result); -// println!("buffer: {:?}", buffer); -// let result = fmkdir(&path, 0); -// println!("result: {:?}", result); -// let result = fchown(&path, 0, 0); -// println!("result: {:?}", result); -// let result = ftruncate(&path, 100); -// println!("result: {:?}", result); -// let result = futimens(&path, &vec![100, 0], &vec![100, 0]); -// println!("result: {:?}", result); -// let result = frelease(&path, &mut fi); -// println!("result: {:?}", result); -// let result = fsetxattr(&path, "test", &vec![1,2,3], 3, 0); -// println!("result: {:?}", result); -// let result = fgetxattr(&path, "test", 100); -// println!("result: {:?}", result); -// let result = faccess(&path, 0o777); -// println!("result: {:?}", result); + +#[test] +fn test_access() { + let path = String::from("target/debug/build"); + let fs = FSImpl::new(); + //access a existed file + let ret = fs.faccess(&path, 0o777); + assert_eq!(match ret { + Ok(ret) => ret, + Err(_) => -1, + }, 0); +} +#[test] +fn test_access_ne() { + let path = String::from("target/xxx"); + let fs = FSImpl::new(); + //acess a not exist file + let ret = fs.faccess(&path, 0o777); + assert_ne!(match ret { + Ok(ret) => ret, + Err(_) => -1, + }, 0); +} + +#[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> | 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 = vec![]; + let offset = 0; + let mut fi = vec![FileInfo::default(), FileInfo::default()]; + let get_ret = |ret: Result> | 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); +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs old mode 100644 new mode 100755 index a815016..39c6823 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,13 +1,16 @@ + use lws_vfs::lws_vfs_server::LwsVfs; use lws_vfs::{ 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 std::error::Error; use std::fs::File; -use std::io::{BufReader, Read as _}; +use std::io::Read as _; use tonic::{Request, Response, Status}; +use std::collections::HashMap; mod fs_impl; pub mod lws_vfs { tonic::include_proto!("lws_vfs"); @@ -69,14 +72,14 @@ impl Config { #[derive(Debug, Default)] pub struct LwsVfsIns { pub config: Config, - file_fds: Arc>, + pub fs: FSImpl, } impl LwsVfsIns { pub fn new(json: &str) -> Result> { Ok(LwsVfsIns { config: Config::new(json)?, - file_fds: Arc::new(Mutex::new(FileFdMgnt::new())), + fs: FSImpl::new(), }) } fn lpath(&self, path: &String) -> String { @@ -112,7 +115,7 @@ impl LwsVfs for LwsVfsIns { let path = &self.lpath(&request.path); let mut fstat = Fstat::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, Err(e) => { println!("Error getting file metadata: {:?}", e); @@ -131,14 +134,8 @@ impl LwsVfs for LwsVfsIns { let request = request.into_inner(); let path = &self.lpath(&request.path); let mut fi = request.fi.unwrap(); - let ret = match fs_impl::fopen(path, &mut fi) { - Ok(file) => { - match self.file_fds.lock().unwrap().push(file) { - Ok(fd) => fi.fh = fd, - Err(e) => { - println!("Error pushing file[{}]: {:?}", path, e); - } - }; + let ret = match self.fs.fopen(path, &mut fi) { + Ok(_) => { 0 } Err(e) => { @@ -164,7 +161,7 @@ impl LwsVfs for LwsVfsIns { unsafe { 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) => { let reply = Read { path: request.path, @@ -197,7 +194,7 @@ impl LwsVfs for LwsVfsIns { let buff = request.buff; let mut size = request.size 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, Err(e) => { println!("Error fwrite file[{}]: {:?}", path, e); @@ -215,7 +212,7 @@ impl LwsVfs for LwsVfsIns { let request = request.into_inner(); let path = &self.lpath(&request.path); let mask = request.mask; - let ret = match fs_impl::faccess(path, mask) { + let ret = match self.fs.faccess(path, mask) { Ok(ret) => ret, Err(e) => { println!("Error access file[{}]: {:?}", path, e); @@ -237,7 +234,7 @@ impl LwsVfs for LwsVfsIns { let value = req.value; let size = req.size as usize; 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, Err(e) => { println!("Error: setxattr file[{}]: {:?}", path, e); @@ -255,7 +252,7 @@ impl LwsVfs for LwsVfsIns { let path = &self.lpath(&req.path); let name = req.name.as_ref(); 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, Err(e) => { println!("Error: getxattr file[{}]: {:?}", path, e); @@ -276,7 +273,7 @@ impl LwsVfs for LwsVfsIns { let offset = request.offset as usize; let mut dirs: Vec = Vec::new(); 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, Err(e) => { println!("Error: readdir file[{}]: {:?}", path, e); @@ -294,7 +291,7 @@ impl LwsVfs for LwsVfsIns { let request = request.into_inner(); let path = &self.lpath(&request.path); let mode = request.mode; - let ret = match fs_impl::fmkdir(&path, mode) { + let ret = match self.fs.fmkdir(&path, mode) { Ok(ret) => ret, Err(e) => { println!("Error: mkdir [{}]: {:?}", path, e); @@ -311,7 +308,7 @@ impl LwsVfs for LwsVfsIns { let request = request.into_inner(); let path = &self.lpath(&request.path); 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, Err(e) => { println!("Error: truncate file[{}]: {:?}", path, e); @@ -330,7 +327,7 @@ impl LwsVfs for LwsVfsIns { 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 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, Err(e) => { println!("Error: futimens file[{}]: {:?}", path, e); @@ -349,7 +346,7 @@ impl LwsVfs for LwsVfsIns { let path = &self.lpath(&request.path); let uid = request.uid 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, Err(e) => { println!("Error: chown file[{}]: {:?}", path, e); @@ -366,8 +363,7 @@ impl LwsVfs for LwsVfsIns { let request = request.into_inner(); let path = &self.lpath(&request.path); let mut fi = request.fi.unwrap(); - self.file_fds.lock().unwrap().pop(fi.fh); - let ret = match fs_impl::frelease(path, &mut fi) { + let ret = match self.fs.frelease(path, &mut fi) { Ok(ret) => ret, Err(e) => { println!("Error: release file[{}]: {:?}", path, e); @@ -383,7 +379,7 @@ impl LwsVfs for LwsVfsIns { async fn frmdir(&self, request: Request) -> Result, Status> { let request = request.into_inner(); let path = &self.lpath(&request.path); - let ret = match fs_impl::frmdir(path) { + let ret = match self.fs.frmdir(path) { Ok(ret) => ret, Err(e) => { println!("Error: rmdir [{}]: {:?}", path, e); @@ -401,6 +397,89 @@ impl LwsVfs for LwsVfsIns { let request = request.into_inner(); let path = &self.lpath(&request.path); 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) -> Result, 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) -> Result, 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) -> Result, 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) -> Result, 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)) } } diff --git a/test/pattern/read.txt b/test/pattern/read.txt new file mode 100755 index 0000000..7abcbfc --- /dev/null +++ b/test/pattern/read.txt @@ -0,0 +1,2 @@ +1234567 +abcdefg \ No newline at end of file