1. 完成基本的测试项的构建
- 测试打开文件读取文件 - 测试打开目录读物目录 - 测试文件的读写功能 - 测试目录创建和删除 - 测试目录或者文件的访问 2. 将fd挪到fs impl里面完成!
This commit is contained in:
parent
82960cfe31
commit
017c52ce13
673
src/fs_impl/mod.rs
Normal file → Executable file
673
src/fs_impl/mod.rs
Normal file → Executable file
|
@ -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<dyn
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
enum FileHandle {
|
||||
#[default]
|
||||
DEFAULT,
|
||||
FILE(File),
|
||||
DIR(ReadDir)
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct FileFdMgnt {
|
||||
// key is fd, value is FileHandle
|
||||
files: HashMap<u64, File>,
|
||||
files: HashMap<u64, FileHandle>,
|
||||
curr_fd: u64,
|
||||
}
|
||||
|
||||
|
@ -58,161 +65,23 @@ impl FileFdMgnt {
|
|||
}
|
||||
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()?;
|
||||
println!("push a fd: {}", fd);
|
||||
self.files.insert(fd, handle);
|
||||
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)
|
||||
}
|
||||
}
|
||||
pub struct FSImpl{
|
||||
file_fds: Arc<Mutex<FileFdMgnt>>,
|
||||
}
|
||||
|
||||
impl FSImpl {
|
||||
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);
|
||||
}
|
||||
// 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<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 {
|
||||
|
@ -236,15 +105,321 @@ fn get_file_mode_mask(path: &str) -> u32 {
|
|||
}
|
||||
permissions
|
||||
}
|
||||
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 })
|
||||
#[derive(Debug, Default)]
|
||||
pub struct FSImpl{
|
||||
file_fds: Arc<Mutex<FileFdMgnt>>,
|
||||
}
|
||||
|
||||
pub fn frmdir(&self, path: &String) -> Result<i32, Box<dyn Error>> {
|
||||
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<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]
|
||||
|
@ -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<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
133
src/lib.rs
Normal file → Executable file
|
@ -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<Mutex<FileFdMgnt>>,
|
||||
pub fs: FSImpl,
|
||||
}
|
||||
|
||||
impl LwsVfsIns {
|
||||
pub fn new(json: &str) -> Result<LwsVfsIns, Box<dyn Error>> {
|
||||
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<String> = 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<Rmdir>) -> Result<Response<Rmdir>, 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<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
2
test/pattern/read.txt
Executable file
|
@ -0,0 +1,2 @@
|
|||
1234567
|
||||
abcdefg
|
Loading…
Reference in New Issue
Block a user