RedoxFS 0.5.0
Significant re-design to use copy-on-write and hashes for all data
This commit is contained in:
committed by
Jeremy Soller
parent
c98e63af87
commit
731b97262b
+200
-209
@@ -8,10 +8,7 @@ use std::os::unix::ffi::OsStrExt;
|
||||
use std::path::Path;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
use disk::Disk;
|
||||
use filesystem;
|
||||
use node::Node;
|
||||
use BLOCK_SIZE;
|
||||
use crate::{filesystem, Disk, Node, TreeData, TreePtr, BLOCK_SIZE};
|
||||
|
||||
use self::fuse::{
|
||||
FileAttr, FileType, Filesystem, ReplyAttr, ReplyCreate, ReplyData, ReplyDirectory, ReplyEmpty,
|
||||
@@ -51,7 +48,7 @@ where
|
||||
},
|
||||
)?;
|
||||
|
||||
let res = callback(&mountpoint);
|
||||
let res = callback(mountpoint);
|
||||
|
||||
session.run()?;
|
||||
|
||||
@@ -62,41 +59,48 @@ pub struct Fuse<D: Disk> {
|
||||
pub fs: filesystem::FileSystem<D>,
|
||||
}
|
||||
|
||||
fn node_attr(node: &(u64, Node)) -> FileAttr {
|
||||
fn node_attr(node: &TreeData<Node>) -> FileAttr {
|
||||
FileAttr {
|
||||
ino: node.0,
|
||||
size: node.1.extents[0].length,
|
||||
ino: node.id() as u64,
|
||||
size: node.data().size(),
|
||||
// Blocks is in 512 byte blocks, not in our block size
|
||||
blocks: (node.1.extents[0].length + BLOCK_SIZE - 1) / BLOCK_SIZE * (BLOCK_SIZE / 512),
|
||||
atime: NULL_TIME,
|
||||
blocks: (node.data().size() + BLOCK_SIZE - 1) / BLOCK_SIZE * (BLOCK_SIZE / 512),
|
||||
atime: Timespec {
|
||||
sec: node.data().atime().0 as i64,
|
||||
nsec: node.data().atime().1 as i32,
|
||||
},
|
||||
mtime: Timespec {
|
||||
sec: node.1.mtime as i64,
|
||||
nsec: node.1.mtime_nsec as i32,
|
||||
sec: node.data().mtime().0 as i64,
|
||||
nsec: node.data().mtime().1 as i32,
|
||||
},
|
||||
ctime: Timespec {
|
||||
sec: node.1.ctime as i64,
|
||||
nsec: node.1.ctime_nsec as i32,
|
||||
sec: node.data().ctime().0 as i64,
|
||||
nsec: node.data().ctime().1 as i32,
|
||||
},
|
||||
crtime: NULL_TIME,
|
||||
kind: if node.1.is_dir() {
|
||||
kind: if node.data().is_dir() {
|
||||
FileType::Directory
|
||||
} else if node.1.is_symlink() {
|
||||
} else if node.data().is_symlink() {
|
||||
FileType::Symlink
|
||||
} else {
|
||||
FileType::RegularFile
|
||||
},
|
||||
perm: node.1.mode & Node::MODE_PERM,
|
||||
nlink: 1,
|
||||
uid: node.1.uid,
|
||||
gid: node.1.gid,
|
||||
perm: node.data().mode() & Node::MODE_PERM,
|
||||
nlink: node.data().links(),
|
||||
uid: node.data().uid(),
|
||||
gid: node.data().gid(),
|
||||
rdev: 0,
|
||||
flags: 0,
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: Disk> Filesystem for Fuse<D> {
|
||||
fn lookup(&mut self, _req: &Request, parent_block: u64, name: &OsStr, reply: ReplyEntry) {
|
||||
match self.fs.find_node(name.to_str().unwrap(), parent_block) {
|
||||
fn lookup(&mut self, _req: &Request, parent_id: u64, name: &OsStr, reply: ReplyEntry) {
|
||||
let parent_ptr = TreePtr::new(parent_id as u32);
|
||||
match self
|
||||
.fs
|
||||
.tx(|tx| tx.find_node(parent_ptr, name.to_str().unwrap()))
|
||||
{
|
||||
Ok(node) => {
|
||||
reply.entry(&TTL, &node_attr(&node), 0);
|
||||
}
|
||||
@@ -106,8 +110,9 @@ impl<D: Disk> Filesystem for Fuse<D> {
|
||||
}
|
||||
}
|
||||
|
||||
fn getattr(&mut self, _req: &Request, block: u64, reply: ReplyAttr) {
|
||||
match self.fs.node(block) {
|
||||
fn getattr(&mut self, _req: &Request, node_id: u64, reply: ReplyAttr) {
|
||||
let node_ptr = TreePtr::<Node>::new(node_id as u32);
|
||||
match self.fs.tx(|tx| tx.read_tree(node_ptr)) {
|
||||
Ok(node) => {
|
||||
reply.attr(&TTL, &node_attr(&node));
|
||||
}
|
||||
@@ -120,7 +125,7 @@ impl<D: Disk> Filesystem for Fuse<D> {
|
||||
fn setattr(
|
||||
&mut self,
|
||||
_req: &Request,
|
||||
block: u64,
|
||||
node_id: u64,
|
||||
mode: Option<u32>,
|
||||
uid: Option<u32>,
|
||||
gid: Option<u32>,
|
||||
@@ -134,53 +139,57 @@ impl<D: Disk> Filesystem for Fuse<D> {
|
||||
_flags: Option<u32>,
|
||||
reply: ReplyAttr,
|
||||
) {
|
||||
let node_ptr = TreePtr::<Node>::new(node_id as u32);
|
||||
|
||||
let mut node = match self.fs.tx(|tx| tx.read_tree(node_ptr)) {
|
||||
Ok(ok) => ok,
|
||||
Err(err) => {
|
||||
reply.error(err.errno as i32);
|
||||
return;
|
||||
}
|
||||
};
|
||||
let mut node_changed = false;
|
||||
|
||||
if let Some(mode) = mode {
|
||||
match self.fs.node(block) {
|
||||
Ok(mut node) => {
|
||||
if node.1.mode & Node::MODE_PERM != mode as u16 & Node::MODE_PERM {
|
||||
// println!("Chmod {:?}:{:o}:{:o}", node.1.name(), node.1.mode, mode);
|
||||
node.1.mode =
|
||||
(node.1.mode & Node::MODE_TYPE) | (mode as u16 & Node::MODE_PERM);
|
||||
if let Err(err) = self.fs.write_at(node.0, &node.1) {
|
||||
reply.error(err.errno as i32);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
reply.error(err.errno as i32);
|
||||
return;
|
||||
}
|
||||
if node.data().mode() & Node::MODE_PERM != mode as u16 & Node::MODE_PERM {
|
||||
let new_mode =
|
||||
(node.data().mode() & Node::MODE_TYPE) | (mode as u16 & Node::MODE_PERM);
|
||||
node.data_mut().set_mode(new_mode);
|
||||
node_changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(uid) = uid {
|
||||
match self.fs.node(block) {
|
||||
Ok(mut node) => {
|
||||
if node.1.uid != uid {
|
||||
node.1.uid = uid;
|
||||
if let Err(err) = self.fs.write_at(node.0, &node.1) {
|
||||
reply.error(err.errno as i32);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
reply.error(err.errno as i32);
|
||||
return;
|
||||
}
|
||||
if node.data().uid() != uid {
|
||||
node.data_mut().set_uid(uid);
|
||||
node_changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(gid) = gid {
|
||||
match self.fs.node(block) {
|
||||
Ok(mut node) => {
|
||||
if node.1.gid != gid {
|
||||
node.1.gid = gid;
|
||||
if let Err(err) = self.fs.write_at(node.0, &node.1) {
|
||||
reply.error(err.errno as i32);
|
||||
return;
|
||||
}
|
||||
if node.data().gid() != gid {
|
||||
node.data_mut().set_gid(gid);
|
||||
node_changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(atime) = atime {
|
||||
node.data_mut()
|
||||
.set_atime(atime.sec as u64, atime.nsec as u32);
|
||||
node_changed = true;
|
||||
}
|
||||
|
||||
if let Some(mtime) = mtime {
|
||||
node.data_mut()
|
||||
.set_mtime(mtime.sec as u64, mtime.nsec as u32);
|
||||
node_changed = true;
|
||||
}
|
||||
|
||||
if let Some(size) = size {
|
||||
match self.fs.tx(|tx| tx.truncate_node_inner(&mut node, size)) {
|
||||
Ok(ok) => {
|
||||
if ok {
|
||||
node_changed = true;
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
@@ -190,67 +199,40 @@ impl<D: Disk> Filesystem for Fuse<D> {
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(size) = size {
|
||||
if let Err(err) = self.fs.node_set_len(block, size) {
|
||||
let attr = node_attr(&node);
|
||||
|
||||
if node_changed {
|
||||
if let Err(err) = self.fs.tx(|tx| tx.sync_tree(node)) {
|
||||
reply.error(err.errno as i32);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let need_update = atime.is_some() || mtime.is_some();
|
||||
if need_update {
|
||||
match self.fs.node(block) {
|
||||
Ok(mut node) => {
|
||||
if let Some(atime) = atime {
|
||||
node.1.atime = atime.sec as u64;
|
||||
node.1.atime_nsec = atime.nsec as u32;
|
||||
}
|
||||
|
||||
if let Some(mtime) = mtime {
|
||||
node.1.mtime = mtime.sec as u64;
|
||||
node.1.mtime_nsec = mtime.nsec as u32;
|
||||
}
|
||||
|
||||
if let Err(err) = self.fs.write_at(node.0, &node.1) {
|
||||
reply.error(err.errno as i32);
|
||||
return;
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
reply.error(err.errno as i32);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match self.fs.node(block) {
|
||||
Ok(node) => {
|
||||
reply.attr(&TTL, &node_attr(&node));
|
||||
}
|
||||
Err(err) => {
|
||||
reply.error(err.errno as i32);
|
||||
}
|
||||
}
|
||||
reply.attr(&TTL, &attr);
|
||||
}
|
||||
|
||||
fn read(
|
||||
&mut self,
|
||||
_req: &Request,
|
||||
block: u64,
|
||||
node_id: u64,
|
||||
_fh: u64,
|
||||
offset: i64,
|
||||
size: u32,
|
||||
reply: ReplyData,
|
||||
) {
|
||||
let node_ptr = TreePtr::<Node>::new(node_id as u32);
|
||||
|
||||
let atime = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
|
||||
let mut data = vec![0; size as usize];
|
||||
match self.fs.read_node(
|
||||
block,
|
||||
cmp::max(0, offset) as u64,
|
||||
&mut data,
|
||||
atime.as_secs(),
|
||||
atime.subsec_nanos(),
|
||||
) {
|
||||
match self.fs.tx(|tx| {
|
||||
tx.read_node(
|
||||
node_ptr,
|
||||
cmp::max(0, offset) as u64,
|
||||
&mut data,
|
||||
atime.as_secs(),
|
||||
atime.subsec_nanos(),
|
||||
)
|
||||
}) {
|
||||
Ok(count) => {
|
||||
reply.data(&data[..count]);
|
||||
}
|
||||
@@ -263,21 +245,25 @@ impl<D: Disk> Filesystem for Fuse<D> {
|
||||
fn write(
|
||||
&mut self,
|
||||
_req: &Request,
|
||||
block: u64,
|
||||
node_id: u64,
|
||||
_fh: u64,
|
||||
offset: i64,
|
||||
data: &[u8],
|
||||
_flags: u32,
|
||||
reply: ReplyWrite,
|
||||
) {
|
||||
let node_ptr = TreePtr::<Node>::new(node_id as u32);
|
||||
|
||||
let mtime = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
|
||||
match self.fs.write_node(
|
||||
block,
|
||||
cmp::max(0, offset) as u64,
|
||||
&data,
|
||||
mtime.as_secs(),
|
||||
mtime.subsec_nanos(),
|
||||
) {
|
||||
match self.fs.tx(|tx| {
|
||||
tx.write_node(
|
||||
node_ptr,
|
||||
cmp::max(0, offset) as u64,
|
||||
data,
|
||||
mtime.as_secs(),
|
||||
mtime.subsec_nanos(),
|
||||
)
|
||||
}) {
|
||||
Ok(count) => {
|
||||
reply.written(count as u32);
|
||||
}
|
||||
@@ -298,23 +284,25 @@ impl<D: Disk> Filesystem for Fuse<D> {
|
||||
fn readdir(
|
||||
&mut self,
|
||||
_req: &Request,
|
||||
parent_block: u64,
|
||||
parent_id: u64,
|
||||
_fh: u64,
|
||||
offset: i64,
|
||||
mut reply: ReplyDirectory,
|
||||
) {
|
||||
let parent_ptr = TreePtr::new(parent_id as u32);
|
||||
let mut children = Vec::new();
|
||||
match self.fs.child_nodes(&mut children, parent_block) {
|
||||
match self.fs.tx(|tx| tx.child_nodes(parent_ptr, &mut children)) {
|
||||
Ok(()) => {
|
||||
let mut i;
|
||||
let skip;
|
||||
if offset == 0 {
|
||||
skip = 0;
|
||||
i = 0;
|
||||
reply.add(parent_block - self.fs.header.0, i, FileType::Directory, ".");
|
||||
reply.add(parent_id, i, FileType::Directory, ".");
|
||||
i += 1;
|
||||
reply.add(
|
||||
parent_block - self.fs.header.0,
|
||||
//TODO: get parent?
|
||||
parent_id,
|
||||
i,
|
||||
FileType::Directory,
|
||||
"..",
|
||||
@@ -326,15 +314,24 @@ impl<D: Disk> Filesystem for Fuse<D> {
|
||||
}
|
||||
|
||||
for child in children.iter().skip(skip) {
|
||||
//TODO: make it possible to get file type from directory entry
|
||||
let node = match self.fs.tx(|tx| tx.read_tree(child.node_ptr())) {
|
||||
Ok(ok) => ok,
|
||||
Err(err) => {
|
||||
reply.error(err.errno as i32);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let full = reply.add(
|
||||
child.0 - self.fs.header.0,
|
||||
child.node_ptr().id() as u64,
|
||||
i,
|
||||
if child.1.is_dir() {
|
||||
if node.data().is_dir() {
|
||||
FileType::Directory
|
||||
} else {
|
||||
FileType::RegularFile
|
||||
},
|
||||
child.1.name().unwrap(),
|
||||
child.name().unwrap(),
|
||||
);
|
||||
|
||||
if full {
|
||||
@@ -354,20 +351,23 @@ impl<D: Disk> Filesystem for Fuse<D> {
|
||||
fn create(
|
||||
&mut self,
|
||||
_req: &Request,
|
||||
parent_block: u64,
|
||||
parent_id: u64,
|
||||
name: &OsStr,
|
||||
mode: u32,
|
||||
flags: u32,
|
||||
reply: ReplyCreate,
|
||||
) {
|
||||
let parent_ptr = TreePtr::<Node>::new(parent_id as u32);
|
||||
let ctime = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
|
||||
match self.fs.create_node(
|
||||
Node::MODE_FILE | (mode as u16 & Node::MODE_PERM),
|
||||
name.to_str().unwrap(),
|
||||
parent_block,
|
||||
ctime.as_secs(),
|
||||
ctime.subsec_nanos(),
|
||||
) {
|
||||
match self.fs.tx(|tx| {
|
||||
tx.create_node(
|
||||
parent_ptr,
|
||||
name.to_str().unwrap(),
|
||||
Node::MODE_FILE | (mode as u16 & Node::MODE_PERM),
|
||||
ctime.as_secs(),
|
||||
ctime.subsec_nanos(),
|
||||
)
|
||||
}) {
|
||||
Ok(node) => {
|
||||
// println!("Create {:?}:{:o}:{:o}", node.1.name(), node.1.mode, mode);
|
||||
reply.created(&TTL, &node_attr(&node), 0, 0, flags);
|
||||
@@ -381,19 +381,22 @@ impl<D: Disk> Filesystem for Fuse<D> {
|
||||
fn mkdir(
|
||||
&mut self,
|
||||
_req: &Request,
|
||||
parent_block: u64,
|
||||
parent_id: u64,
|
||||
name: &OsStr,
|
||||
mode: u32,
|
||||
reply: ReplyEntry,
|
||||
) {
|
||||
let parent_ptr = TreePtr::<Node>::new(parent_id as u32);
|
||||
let ctime = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
|
||||
match self.fs.create_node(
|
||||
Node::MODE_DIR | (mode as u16 & Node::MODE_PERM),
|
||||
name.to_str().unwrap(),
|
||||
parent_block,
|
||||
ctime.as_secs(),
|
||||
ctime.subsec_nanos(),
|
||||
) {
|
||||
match self.fs.tx(|tx| {
|
||||
tx.create_node(
|
||||
parent_ptr,
|
||||
name.to_str().unwrap(),
|
||||
Node::MODE_DIR | (mode as u16 & Node::MODE_PERM),
|
||||
ctime.as_secs(),
|
||||
ctime.subsec_nanos(),
|
||||
)
|
||||
}) {
|
||||
Ok(node) => {
|
||||
// println!("Mkdir {:?}:{:o}:{:o}", node.1.name(), node.1.mode, mode);
|
||||
reply.entry(&TTL, &node_attr(&node), 0);
|
||||
@@ -404,10 +407,11 @@ impl<D: Disk> Filesystem for Fuse<D> {
|
||||
}
|
||||
}
|
||||
|
||||
fn rmdir(&mut self, _req: &Request, parent_block: u64, name: &OsStr, reply: ReplyEmpty) {
|
||||
fn rmdir(&mut self, _req: &Request, parent_id: u64, name: &OsStr, reply: ReplyEmpty) {
|
||||
let parent_ptr = TreePtr::<Node>::new(parent_id as u32);
|
||||
match self
|
||||
.fs
|
||||
.remove_node(Node::MODE_DIR, name.to_str().unwrap(), parent_block)
|
||||
.tx(|tx| tx.remove_node(parent_ptr, name.to_str().unwrap(), Node::MODE_DIR))
|
||||
{
|
||||
Ok(()) => {
|
||||
reply.ok();
|
||||
@@ -418,10 +422,11 @@ impl<D: Disk> Filesystem for Fuse<D> {
|
||||
}
|
||||
}
|
||||
|
||||
fn unlink(&mut self, _req: &Request, parent_block: u64, name: &OsStr, reply: ReplyEmpty) {
|
||||
fn unlink(&mut self, _req: &Request, parent_id: u64, name: &OsStr, reply: ReplyEmpty) {
|
||||
let parent_ptr = TreePtr::<Node>::new(parent_id as u32);
|
||||
match self
|
||||
.fs
|
||||
.remove_node(Node::MODE_FILE, name.to_str().unwrap(), parent_block)
|
||||
.tx(|tx| tx.remove_node(parent_ptr, name.to_str().unwrap(), Node::MODE_FILE))
|
||||
{
|
||||
Ok(()) => {
|
||||
reply.ok();
|
||||
@@ -433,52 +438,44 @@ impl<D: Disk> Filesystem for Fuse<D> {
|
||||
}
|
||||
|
||||
fn statfs(&mut self, _req: &Request, _ino: u64, reply: ReplyStatfs) {
|
||||
let free = self.fs.header.1.free;
|
||||
match self.fs.node_len(free) {
|
||||
Ok(free_size) => {
|
||||
let bsize = BLOCK_SIZE;
|
||||
let blocks = self.fs.header.1.size / bsize;
|
||||
let bfree = free_size / bsize;
|
||||
reply.statfs(blocks, bfree, bfree, 0, 0, bsize as u32, 256, 0);
|
||||
}
|
||||
Err(err) => {
|
||||
reply.error(err.errno as i32);
|
||||
}
|
||||
}
|
||||
let bsize = BLOCK_SIZE;
|
||||
let blocks = self.fs.header.size() / bsize;
|
||||
let bfree = self.fs.allocator().free();
|
||||
reply.statfs(blocks, bfree, bfree, 0, 0, bsize as u32, 256, 0);
|
||||
}
|
||||
|
||||
fn symlink(
|
||||
&mut self,
|
||||
_req: &Request,
|
||||
parent_block: u64,
|
||||
parent_id: u64,
|
||||
name: &OsStr,
|
||||
link: &Path,
|
||||
reply: ReplyEntry,
|
||||
) {
|
||||
let parent_ptr = TreePtr::<Node>::new(parent_id as u32);
|
||||
let ctime = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
|
||||
match self.fs.create_node(
|
||||
Node::MODE_SYMLINK | 0o777,
|
||||
name.to_str().unwrap(),
|
||||
parent_block,
|
||||
ctime.as_secs(),
|
||||
ctime.subsec_nanos(),
|
||||
) {
|
||||
match self.fs.tx(|tx| {
|
||||
let node = tx.create_node(
|
||||
parent_ptr,
|
||||
name.to_str().unwrap(),
|
||||
Node::MODE_SYMLINK | 0o777,
|
||||
ctime.as_secs(),
|
||||
ctime.subsec_nanos(),
|
||||
)?;
|
||||
|
||||
let mtime = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
|
||||
tx.write_node(
|
||||
node.ptr(),
|
||||
0,
|
||||
link.as_os_str().as_bytes(),
|
||||
mtime.as_secs(),
|
||||
mtime.subsec_nanos(),
|
||||
)?;
|
||||
|
||||
Ok(node)
|
||||
}) {
|
||||
Ok(node) => {
|
||||
let mtime = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
|
||||
match self.fs.write_node(
|
||||
node.0,
|
||||
0,
|
||||
link.as_os_str().as_bytes(),
|
||||
mtime.as_secs(),
|
||||
mtime.subsec_nanos(),
|
||||
) {
|
||||
Ok(_count) => {
|
||||
reply.entry(&TTL, &node_attr(&node), 0);
|
||||
}
|
||||
Err(err) => {
|
||||
reply.error(err.errno as i32);
|
||||
}
|
||||
}
|
||||
reply.entry(&TTL, &node_attr(&node), 0);
|
||||
}
|
||||
Err(error) => {
|
||||
reply.error(error.errno as i32);
|
||||
@@ -486,13 +483,19 @@ impl<D: Disk> Filesystem for Fuse<D> {
|
||||
}
|
||||
}
|
||||
|
||||
fn readlink(&mut self, _req: &Request, ino: u64, reply: ReplyData) {
|
||||
fn readlink(&mut self, _req: &Request, node_id: u64, reply: ReplyData) {
|
||||
let node_ptr = TreePtr::<Node>::new(node_id as u32);
|
||||
let atime = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
|
||||
let mut data = vec![0; 4096];
|
||||
match self
|
||||
.fs
|
||||
.read_node(ino, 0, &mut data, atime.as_secs(), atime.subsec_nanos())
|
||||
{
|
||||
match self.fs.tx(|tx| {
|
||||
tx.read_node(
|
||||
node_ptr,
|
||||
0,
|
||||
&mut data,
|
||||
atime.as_secs(),
|
||||
atime.subsec_nanos(),
|
||||
)
|
||||
}) {
|
||||
Ok(count) => {
|
||||
reply.data(&data[..count]);
|
||||
}
|
||||
@@ -506,39 +509,27 @@ impl<D: Disk> Filesystem for Fuse<D> {
|
||||
&mut self,
|
||||
_req: &Request,
|
||||
orig_parent: u64,
|
||||
name: &OsStr,
|
||||
orig_name: &OsStr,
|
||||
new_parent: u64,
|
||||
new_name: &OsStr,
|
||||
reply: ReplyEmpty,
|
||||
) {
|
||||
let rename_inner = |fs: &mut filesystem::FileSystem<D>| -> syscall::Result<()> {
|
||||
let mut orig = fs.find_node(name.to_str().unwrap(), orig_parent)?;
|
||||
|
||||
if new_parent != orig_parent {
|
||||
fs.remove_blocks(orig.0, 1, orig_parent)?;
|
||||
}
|
||||
|
||||
if let Ok(node) = fs.find_node(new_name.to_str().unwrap(), new_parent) {
|
||||
if node.0 != orig.0 {
|
||||
fs.node_set_len(node.0, 0)?;
|
||||
fs.remove_blocks(node.0, 1, new_parent)?;
|
||||
fs.write_at(node.0, &Node::default())?;
|
||||
fs.deallocate(node.0, BLOCK_SIZE)?;
|
||||
}
|
||||
}
|
||||
|
||||
orig.1.set_name(&new_name.to_str().unwrap())?;
|
||||
orig.1.parent = new_parent;
|
||||
fs.write_at(orig.0, &orig.1)?;
|
||||
|
||||
if new_parent != orig_parent {
|
||||
fs.insert_blocks(orig.0, BLOCK_SIZE, new_parent)?;
|
||||
}
|
||||
let orig_parent_ptr = TreePtr::<Node>::new(orig_parent as u32);
|
||||
let orig_name = orig_name.to_str().expect("name is not utf-8");
|
||||
let new_parent_ptr = TreePtr::<Node>::new(new_parent as u32);
|
||||
let new_name = new_name.to_str().expect("name is not utf-8");
|
||||
|
||||
// TODO: improve performance
|
||||
match self.fs.tx(|tx| {
|
||||
let node = tx.find_node(orig_parent_ptr, orig_name)?;
|
||||
tx.link_node(new_parent_ptr, new_name, node.ptr())?;
|
||||
tx.remove_node(
|
||||
orig_parent_ptr,
|
||||
orig_name,
|
||||
node.data().mode() & Node::MODE_TYPE,
|
||||
)?;
|
||||
Ok(())
|
||||
};
|
||||
|
||||
match rename_inner(&mut self.fs) {
|
||||
}) {
|
||||
Ok(()) => reply.ok(),
|
||||
Err(err) => reply.error(err.errno as i32),
|
||||
}
|
||||
|
||||
@@ -2,11 +2,9 @@ use std::fs::File;
|
||||
use std::io::{self, Read, Write};
|
||||
use std::path::Path;
|
||||
use std::sync::atomic::Ordering;
|
||||
use syscall::{Packet, Scheme};
|
||||
use syscall::{Packet, SchemeMut};
|
||||
|
||||
use disk::Disk;
|
||||
use filesystem::FileSystem;
|
||||
use IS_UMT;
|
||||
use crate::{Disk, FileSystem, IS_UMT};
|
||||
|
||||
use self::scheme::FileScheme;
|
||||
|
||||
@@ -26,7 +24,7 @@ where
|
||||
let mounted_path = format!("{}:", mountpoint.display());
|
||||
let res = callback(Path::new(&mounted_path));
|
||||
|
||||
let scheme = FileScheme::new(format!("{}", mountpoint.display()), filesystem);
|
||||
let mut scheme = FileScheme::new(format!("{}", mountpoint.display()), filesystem);
|
||||
loop {
|
||||
if IS_UMT.load(Ordering::SeqCst) > 0 {
|
||||
break Ok(res);
|
||||
|
||||
+203
-209
@@ -10,57 +10,151 @@ use syscall::flag::{
|
||||
PROT_READ, PROT_WRITE, SEEK_CUR, SEEK_END, SEEK_SET,
|
||||
};
|
||||
|
||||
use disk::Disk;
|
||||
use filesystem::FileSystem;
|
||||
use crate::{Disk, Node, Transaction, TreePtr};
|
||||
|
||||
pub trait Resource<D: Disk> {
|
||||
fn block(&self) -> u64;
|
||||
fn dup(&self) -> Result<Box<Resource<D>>>;
|
||||
fn node_ptr(&self) -> TreePtr<Node>;
|
||||
|
||||
fn uid(&self) -> u32;
|
||||
|
||||
fn dup(&self) -> Result<Box<dyn Resource<D>>>;
|
||||
|
||||
fn set_path(&mut self, path: &str);
|
||||
fn read(&mut self, buf: &mut [u8], fs: &mut FileSystem<D>) -> Result<usize>;
|
||||
fn write(&mut self, buf: &[u8], fs: &mut FileSystem<D>) -> Result<usize>;
|
||||
fn seek(&mut self, offset: isize, whence: usize, fs: &mut FileSystem<D>) -> Result<isize>;
|
||||
fn fmap(&mut self, map: &Map, fs: &mut FileSystem<D>) -> Result<usize>;
|
||||
fn funmap(&mut self, address: usize, fs: &mut FileSystem<D>) -> Result<usize>;
|
||||
fn fchmod(&mut self, mode: u16, fs: &mut FileSystem<D>) -> Result<usize>;
|
||||
fn fchown(&mut self, uid: u32, gid: u32, fs: &mut FileSystem<D>) -> Result<usize>;
|
||||
|
||||
fn read(&mut self, buf: &mut [u8], tx: &mut Transaction<D>) -> Result<usize>;
|
||||
|
||||
fn write(&mut self, buf: &[u8], tx: &mut Transaction<D>) -> Result<usize>;
|
||||
|
||||
fn seek(&mut self, offset: isize, whence: usize, tx: &mut Transaction<D>) -> Result<isize>;
|
||||
|
||||
fn fmap(&mut self, map: &Map, tx: &mut Transaction<D>) -> Result<usize>;
|
||||
|
||||
fn funmap(&mut self, address: usize, tx: &mut Transaction<D>) -> Result<usize>;
|
||||
|
||||
fn fchmod(&mut self, mode: u16, tx: &mut Transaction<D>) -> Result<usize> {
|
||||
let mut node = tx.read_tree(self.node_ptr())?;
|
||||
|
||||
if node.data().uid() == self.uid() || self.uid() == 0 {
|
||||
let old_mode = node.data().mode();
|
||||
let new_mode = (old_mode & !MODE_PERM) | (mode & MODE_PERM);
|
||||
if old_mode != new_mode {
|
||||
node.data_mut().set_mode(new_mode);
|
||||
tx.sync_tree(node)?;
|
||||
}
|
||||
|
||||
Ok(0)
|
||||
} else {
|
||||
Err(Error::new(EPERM))
|
||||
}
|
||||
}
|
||||
|
||||
fn fchown(&mut self, uid: u32, gid: u32, tx: &mut Transaction<D>) -> Result<usize> {
|
||||
let mut node = tx.read_tree(self.node_ptr())?;
|
||||
|
||||
let old_uid = node.data().uid();
|
||||
if old_uid == self.uid() || self.uid() == 0 {
|
||||
let mut node_changed = false;
|
||||
|
||||
if uid as i32 != -1 {
|
||||
if uid != old_uid {
|
||||
node.data_mut().set_uid(uid);
|
||||
node_changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if gid as i32 != -1 {
|
||||
let old_gid = node.data().gid();
|
||||
if gid != old_gid {
|
||||
node.data_mut().set_gid(gid);
|
||||
node_changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if node_changed {
|
||||
tx.sync_tree(node)?;
|
||||
}
|
||||
|
||||
Ok(0)
|
||||
} else {
|
||||
Err(Error::new(EPERM))
|
||||
}
|
||||
}
|
||||
|
||||
fn fcntl(&mut self, cmd: usize, arg: usize) -> Result<usize>;
|
||||
fn path(&self, buf: &mut [u8]) -> Result<usize>;
|
||||
fn stat(&self, _stat: &mut Stat, fs: &mut FileSystem<D>) -> Result<usize>;
|
||||
fn sync(&mut self, fs: &mut FileSystem<D>) -> Result<usize>;
|
||||
fn truncate(&mut self, len: usize, fs: &mut FileSystem<D>) -> Result<usize>;
|
||||
fn utimens(&mut self, times: &[TimeSpec], fs: &mut FileSystem<D>) -> Result<usize>;
|
||||
|
||||
fn path(&self) -> &str;
|
||||
|
||||
fn stat(&self, stat: &mut Stat, tx: &mut Transaction<D>) -> Result<usize> {
|
||||
let node = tx.read_tree(self.node_ptr())?;
|
||||
|
||||
let ctime = node.data().ctime();
|
||||
let mtime = node.data().mtime();
|
||||
let atime = node.data().atime();
|
||||
*stat = Stat {
|
||||
st_dev: 0, // TODO
|
||||
st_ino: node.id() as u64,
|
||||
st_mode: node.data().mode(),
|
||||
st_nlink: node.data().links(),
|
||||
st_uid: node.data().uid(),
|
||||
st_gid: node.data().gid(),
|
||||
st_size: node.data().size(),
|
||||
st_mtime: mtime.0,
|
||||
st_mtime_nsec: mtime.1,
|
||||
st_atime: atime.0,
|
||||
st_atime_nsec: atime.1,
|
||||
st_ctime: ctime.0,
|
||||
st_ctime_nsec: ctime.1,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn sync(&mut self, tx: &mut Transaction<D>) -> Result<usize>;
|
||||
|
||||
fn truncate(&mut self, len: usize, tx: &mut Transaction<D>) -> Result<usize>;
|
||||
|
||||
fn utimens(&mut self, times: &[TimeSpec], tx: &mut Transaction<D>) -> Result<usize>;
|
||||
}
|
||||
|
||||
pub struct DirResource {
|
||||
path: String,
|
||||
block: u64,
|
||||
node_ptr: TreePtr<Node>,
|
||||
data: Option<Vec<u8>>,
|
||||
seek: isize,
|
||||
uid: u32,
|
||||
}
|
||||
|
||||
impl DirResource {
|
||||
pub fn new(path: String, block: u64, data: Option<Vec<u8>>, uid: u32) -> DirResource {
|
||||
pub fn new(
|
||||
path: String,
|
||||
node_ptr: TreePtr<Node>,
|
||||
data: Option<Vec<u8>>,
|
||||
uid: u32,
|
||||
) -> DirResource {
|
||||
DirResource {
|
||||
path: path,
|
||||
block: block,
|
||||
data: data,
|
||||
path,
|
||||
node_ptr,
|
||||
data,
|
||||
seek: 0,
|
||||
uid: uid,
|
||||
uid,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: Disk> Resource<D> for DirResource {
|
||||
fn block(&self) -> u64 {
|
||||
self.block
|
||||
fn node_ptr(&self) -> TreePtr<Node> {
|
||||
self.node_ptr
|
||||
}
|
||||
|
||||
fn dup(&self) -> Result<Box<Resource<D>>> {
|
||||
fn uid(&self) -> u32 {
|
||||
self.uid
|
||||
}
|
||||
|
||||
fn dup(&self) -> Result<Box<dyn Resource<D>>> {
|
||||
Ok(Box::new(DirResource {
|
||||
path: self.path.clone(),
|
||||
block: self.block,
|
||||
node_ptr: self.node_ptr,
|
||||
data: self.data.clone(),
|
||||
seek: self.seek,
|
||||
uid: self.uid,
|
||||
@@ -71,7 +165,7 @@ impl<D: Disk> Resource<D> for DirResource {
|
||||
self.path = path.to_string();
|
||||
}
|
||||
|
||||
fn read(&mut self, buf: &mut [u8], _fs: &mut FileSystem<D>) -> Result<usize> {
|
||||
fn read(&mut self, buf: &mut [u8], _tx: &mut Transaction<D>) -> Result<usize> {
|
||||
let data = self.data.as_ref().ok_or(Error::new(EISDIR))?;
|
||||
let size = data.len() as isize;
|
||||
let mut i = 0;
|
||||
@@ -83,11 +177,11 @@ impl<D: Disk> Resource<D> for DirResource {
|
||||
Ok(i)
|
||||
}
|
||||
|
||||
fn write(&mut self, _buf: &[u8], _fs: &mut FileSystem<D>) -> Result<usize> {
|
||||
fn write(&mut self, _buf: &[u8], _tx: &mut Transaction<D>) -> Result<usize> {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
|
||||
fn seek(&mut self, offset: isize, whence: usize, _fs: &mut FileSystem<D>) -> Result<isize> {
|
||||
fn seek(&mut self, offset: isize, whence: usize, _tx: &mut Transaction<D>) -> Result<isize> {
|
||||
let data = self.data.as_ref().ok_or(Error::new(EBADF))?;
|
||||
let size = data.len() as isize;
|
||||
self.seek = match whence {
|
||||
@@ -99,108 +193,47 @@ impl<D: Disk> Resource<D> for DirResource {
|
||||
Ok(self.seek)
|
||||
}
|
||||
|
||||
fn fmap(&mut self, _map: &Map, _fs: &mut FileSystem<D>) -> Result<usize> {
|
||||
fn fmap(&mut self, _map: &Map, _tx: &mut Transaction<D>) -> Result<usize> {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
fn funmap(&mut self, _address: usize, _fs: &mut FileSystem<D>) -> Result<usize> {
|
||||
fn funmap(&mut self, _address: usize, _tx: &mut Transaction<D>) -> Result<usize> {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
|
||||
fn fchmod(&mut self, mode: u16, fs: &mut FileSystem<D>) -> Result<usize> {
|
||||
let mut node = fs.node(self.block)?;
|
||||
|
||||
if node.1.uid == self.uid || self.uid == 0 {
|
||||
node.1.mode = (node.1.mode & !MODE_PERM) | (mode & MODE_PERM);
|
||||
|
||||
fs.write_at(node.0, &node.1)?;
|
||||
|
||||
Ok(0)
|
||||
} else {
|
||||
Err(Error::new(EPERM))
|
||||
}
|
||||
}
|
||||
|
||||
fn fchown(&mut self, uid: u32, gid: u32, fs: &mut FileSystem<D>) -> Result<usize> {
|
||||
let mut node = fs.node(self.block)?;
|
||||
|
||||
if node.1.uid == self.uid || self.uid == 0 {
|
||||
if uid as i32 != -1 {
|
||||
node.1.uid = uid;
|
||||
}
|
||||
|
||||
if gid as i32 != -1 {
|
||||
node.1.gid = gid;
|
||||
}
|
||||
|
||||
fs.write_at(node.0, &node.1)?;
|
||||
|
||||
Ok(0)
|
||||
} else {
|
||||
Err(Error::new(EPERM))
|
||||
}
|
||||
}
|
||||
|
||||
fn fcntl(&mut self, _cmd: usize, _arg: usize) -> Result<usize> {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
|
||||
fn path(&self, buf: &mut [u8]) -> Result<usize> {
|
||||
let path = self.path.as_bytes();
|
||||
|
||||
let mut i = 0;
|
||||
while i < buf.len() && i < path.len() {
|
||||
buf[i] = path[i];
|
||||
i += 1;
|
||||
}
|
||||
|
||||
Ok(i)
|
||||
fn path(&self) -> &str {
|
||||
&self.path
|
||||
}
|
||||
|
||||
fn stat(&self, stat: &mut Stat, fs: &mut FileSystem<D>) -> Result<usize> {
|
||||
let node = fs.node(self.block)?;
|
||||
|
||||
*stat = Stat {
|
||||
st_dev: 0, // TODO
|
||||
st_ino: node.0,
|
||||
st_mode: node.1.mode,
|
||||
st_nlink: 1,
|
||||
st_uid: node.1.uid,
|
||||
st_gid: node.1.gid,
|
||||
st_size: fs.node_len(self.block)?,
|
||||
st_mtime: node.1.mtime,
|
||||
st_mtime_nsec: node.1.mtime_nsec,
|
||||
st_atime: node.1.atime,
|
||||
st_atime_nsec: node.1.atime_nsec,
|
||||
st_ctime: node.1.ctime,
|
||||
st_ctime_nsec: node.1.ctime_nsec,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn sync(&mut self, _fs: &mut FileSystem<D>) -> Result<usize> {
|
||||
fn sync(&mut self, _tx: &mut Transaction<D>) -> Result<usize> {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
|
||||
fn truncate(&mut self, _len: usize, _fs: &mut FileSystem<D>) -> Result<usize> {
|
||||
fn truncate(&mut self, _len: usize, _tx: &mut Transaction<D>) -> Result<usize> {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
|
||||
fn utimens(&mut self, _times: &[TimeSpec], _fs: &mut FileSystem<D>) -> Result<usize> {
|
||||
fn utimens(&mut self, _times: &[TimeSpec], _tx: &mut Transaction<D>) -> Result<usize> {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Fmap {
|
||||
block: u64,
|
||||
node_ptr: TreePtr<Node>,
|
||||
offset: usize,
|
||||
flags: MapFlags,
|
||||
data: &'static mut [u8],
|
||||
}
|
||||
|
||||
impl Fmap {
|
||||
pub unsafe fn new<D: Disk>(block: u64, map: &Map, fs: &mut FileSystem<D>) -> Result<Self> {
|
||||
pub unsafe fn new<D: Disk>(
|
||||
node_ptr: TreePtr<Node>,
|
||||
map: &Map,
|
||||
tx: &mut Transaction<D>,
|
||||
) -> Result<Self> {
|
||||
extern "C" {
|
||||
fn memalign(align: usize, size: usize) -> *mut u8;
|
||||
fn free(ptr: *mut u8);
|
||||
@@ -216,8 +249,8 @@ impl Fmap {
|
||||
// Read buffer from disk
|
||||
let atime = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
|
||||
let buf = slice::from_raw_parts_mut(address, map.size);
|
||||
let count = match fs.read_node(
|
||||
block,
|
||||
let count = match tx.read_node(
|
||||
node_ptr,
|
||||
map.offset as u64,
|
||||
buf,
|
||||
atime.as_secs(),
|
||||
@@ -236,18 +269,18 @@ impl Fmap {
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
block,
|
||||
node_ptr,
|
||||
offset: map.offset,
|
||||
flags: map.flags,
|
||||
data: buf,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn sync<D: Disk>(&mut self, fs: &mut FileSystem<D>) -> Result<()> {
|
||||
pub fn sync<D: Disk>(&mut self, tx: &mut Transaction<D>) -> Result<()> {
|
||||
if self.flags & PROT_WRITE == PROT_WRITE {
|
||||
let mtime = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
|
||||
fs.write_node(
|
||||
self.block,
|
||||
tx.write_node(
|
||||
self.node_ptr,
|
||||
self.offset as u64,
|
||||
&self.data,
|
||||
mtime.as_secs(),
|
||||
@@ -272,7 +305,7 @@ impl Drop for Fmap {
|
||||
|
||||
pub struct FileResource {
|
||||
path: String,
|
||||
block: u64,
|
||||
node_ptr: TreePtr<Node>,
|
||||
flags: usize,
|
||||
seek: isize,
|
||||
uid: u32,
|
||||
@@ -280,10 +313,10 @@ pub struct FileResource {
|
||||
}
|
||||
|
||||
impl FileResource {
|
||||
pub fn new(path: String, block: u64, flags: usize, uid: u32) -> FileResource {
|
||||
pub fn new(path: String, node_ptr: TreePtr<Node>, flags: usize, uid: u32) -> FileResource {
|
||||
FileResource {
|
||||
path,
|
||||
block,
|
||||
node_ptr,
|
||||
flags,
|
||||
seek: 0,
|
||||
uid,
|
||||
@@ -293,14 +326,18 @@ impl FileResource {
|
||||
}
|
||||
|
||||
impl<D: Disk> Resource<D> for FileResource {
|
||||
fn block(&self) -> u64 {
|
||||
self.block
|
||||
fn node_ptr(&self) -> TreePtr<Node> {
|
||||
self.node_ptr
|
||||
}
|
||||
|
||||
fn dup(&self) -> Result<Box<Resource<D>>> {
|
||||
fn uid(&self) -> u32 {
|
||||
self.uid
|
||||
}
|
||||
|
||||
fn dup(&self) -> Result<Box<dyn Resource<D>>> {
|
||||
Ok(Box::new(FileResource {
|
||||
path: self.path.clone(),
|
||||
block: self.block,
|
||||
node_ptr: self.node_ptr,
|
||||
flags: self.flags,
|
||||
seek: self.seek,
|
||||
uid: self.uid,
|
||||
@@ -312,11 +349,11 @@ impl<D: Disk> Resource<D> for FileResource {
|
||||
self.path = path.to_string();
|
||||
}
|
||||
|
||||
fn read(&mut self, buf: &mut [u8], fs: &mut FileSystem<D>) -> Result<usize> {
|
||||
fn read(&mut self, buf: &mut [u8], tx: &mut Transaction<D>) -> Result<usize> {
|
||||
if self.flags & O_ACCMODE == O_RDWR || self.flags & O_ACCMODE == O_RDONLY {
|
||||
let atime = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
|
||||
let count = fs.read_node(
|
||||
self.block,
|
||||
let count = tx.read_node(
|
||||
self.node_ptr,
|
||||
self.seek as u64,
|
||||
buf,
|
||||
atime.as_secs(),
|
||||
@@ -329,14 +366,15 @@ impl<D: Disk> Resource<D> for FileResource {
|
||||
}
|
||||
}
|
||||
|
||||
fn write(&mut self, buf: &[u8], fs: &mut FileSystem<D>) -> Result<usize> {
|
||||
fn write(&mut self, buf: &[u8], tx: &mut Transaction<D>) -> Result<usize> {
|
||||
if self.flags & O_ACCMODE == O_RDWR || self.flags & O_ACCMODE == O_WRONLY {
|
||||
if self.flags & O_APPEND == O_APPEND {
|
||||
self.seek = fs.node_len(self.block)? as isize;
|
||||
let node = tx.read_tree(self.node_ptr)?;
|
||||
self.seek = node.data().size() as isize;
|
||||
}
|
||||
let mtime = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
|
||||
let count = fs.write_node(
|
||||
self.block,
|
||||
let count = tx.write_node(
|
||||
self.node_ptr,
|
||||
self.seek as u64,
|
||||
buf,
|
||||
mtime.as_secs(),
|
||||
@@ -349,18 +387,20 @@ impl<D: Disk> Resource<D> for FileResource {
|
||||
}
|
||||
}
|
||||
|
||||
fn seek(&mut self, offset: isize, whence: usize, fs: &mut FileSystem<D>) -> Result<isize> {
|
||||
let size = fs.node_len(self.block)? as isize;
|
||||
fn seek(&mut self, offset: isize, whence: usize, tx: &mut Transaction<D>) -> Result<isize> {
|
||||
self.seek = match whence {
|
||||
SEEK_SET => max(0, offset),
|
||||
SEEK_CUR => max(0, self.seek + offset),
|
||||
SEEK_END => max(0, size + offset),
|
||||
SEEK_END => {
|
||||
let node = tx.read_tree(self.node_ptr)?;
|
||||
max(0, node.data().size() as isize + offset)
|
||||
}
|
||||
_ => return Err(Error::new(EINVAL)),
|
||||
};
|
||||
Ok(self.seek)
|
||||
}
|
||||
|
||||
fn fmap(&mut self, map: &Map, fs: &mut FileSystem<D>) -> Result<usize> {
|
||||
fn fmap(&mut self, map: &Map, tx: &mut Transaction<D>) -> Result<usize> {
|
||||
let accmode = self.flags & O_ACCMODE;
|
||||
if map.flags.contains(PROT_READ) && !(accmode == O_RDWR || accmode == O_RDONLY) {
|
||||
return Err(Error::new(EBADF));
|
||||
@@ -370,15 +410,15 @@ impl<D: Disk> Resource<D> for FileResource {
|
||||
}
|
||||
//TODO: PROT_EXEC?
|
||||
|
||||
let map = unsafe { Fmap::new(self.block, map, fs)? };
|
||||
let map = unsafe { Fmap::new(self.node_ptr, map, tx)? };
|
||||
let address = map.data.as_ptr() as usize;
|
||||
self.fmaps.insert(address, map);
|
||||
Ok(address)
|
||||
}
|
||||
|
||||
fn funmap(&mut self, address: usize, fs: &mut FileSystem<D>) -> Result<usize> {
|
||||
fn funmap(&mut self, address: usize, tx: &mut Transaction<D>) -> Result<usize> {
|
||||
if let Some(mut fmap) = self.fmaps.remove(&address) {
|
||||
fmap.sync(fs)?;
|
||||
fmap.sync(tx)?;
|
||||
|
||||
Ok(0)
|
||||
} else {
|
||||
@@ -386,40 +426,6 @@ impl<D: Disk> Resource<D> for FileResource {
|
||||
}
|
||||
}
|
||||
|
||||
fn fchmod(&mut self, mode: u16, fs: &mut FileSystem<D>) -> Result<usize> {
|
||||
let mut node = fs.node(self.block)?;
|
||||
|
||||
if node.1.uid == self.uid || self.uid == 0 {
|
||||
node.1.mode = (node.1.mode & !MODE_PERM) | (mode & MODE_PERM);
|
||||
|
||||
fs.write_at(node.0, &node.1)?;
|
||||
|
||||
Ok(0)
|
||||
} else {
|
||||
Err(Error::new(EPERM))
|
||||
}
|
||||
}
|
||||
|
||||
fn fchown(&mut self, uid: u32, gid: u32, fs: &mut FileSystem<D>) -> Result<usize> {
|
||||
let mut node = fs.node(self.block)?;
|
||||
|
||||
if node.1.uid == self.uid || self.uid == 0 {
|
||||
if uid as i32 != -1 {
|
||||
node.1.uid = uid;
|
||||
}
|
||||
|
||||
if gid as i32 != -1 {
|
||||
node.1.gid = gid;
|
||||
}
|
||||
|
||||
fs.write_at(node.0, &node.1)?;
|
||||
|
||||
Ok(0)
|
||||
} else {
|
||||
Err(Error::new(EPERM))
|
||||
}
|
||||
}
|
||||
|
||||
fn fcntl(&mut self, cmd: usize, arg: usize) -> Result<usize> {
|
||||
match cmd {
|
||||
F_GETFL => Ok(self.flags),
|
||||
@@ -431,69 +437,57 @@ impl<D: Disk> Resource<D> for FileResource {
|
||||
}
|
||||
}
|
||||
|
||||
fn path(&self, buf: &mut [u8]) -> Result<usize> {
|
||||
let path = self.path.as_bytes();
|
||||
|
||||
let mut i = 0;
|
||||
while i < buf.len() && i < path.len() {
|
||||
buf[i] = path[i];
|
||||
i += 1;
|
||||
}
|
||||
|
||||
Ok(i)
|
||||
fn path(&self) -> &str {
|
||||
&self.path
|
||||
}
|
||||
|
||||
fn stat(&self, stat: &mut Stat, fs: &mut FileSystem<D>) -> Result<usize> {
|
||||
let node = fs.node(self.block)?;
|
||||
|
||||
*stat = Stat {
|
||||
st_dev: 0, // TODO
|
||||
st_ino: node.0,
|
||||
st_mode: node.1.mode,
|
||||
st_nlink: 1,
|
||||
st_uid: node.1.uid,
|
||||
st_gid: node.1.gid,
|
||||
st_size: fs.node_len(self.block)?,
|
||||
st_mtime: node.1.mtime,
|
||||
st_mtime_nsec: node.1.mtime_nsec,
|
||||
st_atime: node.1.atime,
|
||||
st_atime_nsec: node.1.atime_nsec,
|
||||
st_ctime: node.1.ctime,
|
||||
st_ctime_nsec: node.1.ctime_nsec,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn sync(&mut self, fs: &mut FileSystem<D>) -> Result<usize> {
|
||||
fn sync(&mut self, tx: &mut Transaction<D>) -> Result<usize> {
|
||||
for fmap in self.fmaps.values_mut() {
|
||||
fmap.sync(fs)?;
|
||||
fmap.sync(tx)?;
|
||||
}
|
||||
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn truncate(&mut self, len: usize, fs: &mut FileSystem<D>) -> Result<usize> {
|
||||
fn truncate(&mut self, len: usize, tx: &mut Transaction<D>) -> Result<usize> {
|
||||
if self.flags & O_ACCMODE == O_RDWR || self.flags & O_ACCMODE == O_WRONLY {
|
||||
fs.node_set_len(self.block, len as u64)?;
|
||||
let mtime = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
|
||||
tx.truncate_node(
|
||||
self.node_ptr,
|
||||
len as u64,
|
||||
mtime.as_secs(),
|
||||
mtime.subsec_nanos(),
|
||||
)?;
|
||||
Ok(0)
|
||||
} else {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
}
|
||||
|
||||
fn utimens(&mut self, times: &[TimeSpec], fs: &mut FileSystem<D>) -> Result<usize> {
|
||||
let mut node = fs.node(self.block)?;
|
||||
fn utimens(&mut self, times: &[TimeSpec], tx: &mut Transaction<D>) -> Result<usize> {
|
||||
let mut node = tx.read_tree(self.node_ptr)?;
|
||||
|
||||
if node.1.uid == self.uid || self.uid == 0 {
|
||||
if node.data().uid() == self.uid || self.uid == 0 {
|
||||
if let &[atime, mtime] = times {
|
||||
node.1.mtime = mtime.tv_sec as u64;
|
||||
node.1.mtime_nsec = mtime.tv_nsec as u32;
|
||||
node.1.atime = atime.tv_sec as u64;
|
||||
node.1.atime_nsec = atime.tv_nsec as u32;
|
||||
let mut node_changed = false;
|
||||
|
||||
fs.write_at(node.0, &node.1)?;
|
||||
let old_mtime = node.data().mtime();
|
||||
let new_mtime = (mtime.tv_sec as u64, mtime.tv_nsec as u32);
|
||||
if old_mtime != new_mtime {
|
||||
node.data_mut().set_mtime(new_mtime.0, new_mtime.1);
|
||||
node_changed = true;
|
||||
}
|
||||
|
||||
let old_atime = node.data().atime();
|
||||
let new_atime = (atime.tv_sec as u64, atime.tv_nsec as u32);
|
||||
if old_atime != new_atime {
|
||||
node.data_mut().set_atime(new_atime.0, new_atime.1);
|
||||
node_changed = true;
|
||||
}
|
||||
|
||||
if node_changed {
|
||||
tx.sync_tree(node)?;
|
||||
}
|
||||
}
|
||||
Ok(0)
|
||||
} else {
|
||||
|
||||
+266
-237
@@ -1,4 +1,3 @@
|
||||
use std::cell::RefCell;
|
||||
use std::collections::BTreeMap;
|
||||
use std::str;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
@@ -13,62 +12,65 @@ use syscall::flag::{
|
||||
EventFlags, MODE_PERM, O_ACCMODE, O_CREAT, O_DIRECTORY, O_EXCL, O_NOFOLLOW, O_RDONLY, O_RDWR,
|
||||
O_STAT, O_SYMLINK, O_TRUNC, O_WRONLY,
|
||||
};
|
||||
use syscall::scheme::Scheme;
|
||||
use syscall::scheme::SchemeMut;
|
||||
|
||||
use disk::Disk;
|
||||
use filesystem::FileSystem;
|
||||
use node::Node;
|
||||
use BLOCK_SIZE;
|
||||
use crate::{Disk, FileSystem, Node, Transaction, TreeData, TreePtr, BLOCK_SIZE};
|
||||
|
||||
use super::resource::{DirResource, FileResource, Resource};
|
||||
|
||||
pub struct FileScheme<D: Disk> {
|
||||
name: String,
|
||||
fs: RefCell<FileSystem<D>>,
|
||||
fs: FileSystem<D>,
|
||||
next_id: AtomicUsize,
|
||||
files: RefCell<BTreeMap<usize, Box<Resource<D>>>>,
|
||||
fmap: RefCell<BTreeMap<usize, usize>>,
|
||||
files: BTreeMap<usize, Box<dyn Resource<D>>>,
|
||||
fmap: BTreeMap<usize, usize>,
|
||||
}
|
||||
|
||||
impl<D: Disk> FileScheme<D> {
|
||||
pub fn new(name: String, fs: FileSystem<D>) -> FileScheme<D> {
|
||||
FileScheme {
|
||||
name: name,
|
||||
fs: RefCell::new(fs),
|
||||
fs: fs,
|
||||
next_id: AtomicUsize::new(1),
|
||||
files: RefCell::new(BTreeMap::new()),
|
||||
fmap: RefCell::new(BTreeMap::new()),
|
||||
files: BTreeMap::new(),
|
||||
fmap: BTreeMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_symlink(
|
||||
&self,
|
||||
fs: &mut FileSystem<D>,
|
||||
scheme_name: &str,
|
||||
tx: &mut Transaction<D>,
|
||||
uid: u32,
|
||||
gid: u32,
|
||||
url: &[u8],
|
||||
node: (u64, Node),
|
||||
nodes: &mut Vec<(u64, Node)>,
|
||||
url: &str,
|
||||
node: TreeData<Node>,
|
||||
nodes: &mut Vec<(TreeData<Node>, String)>,
|
||||
) -> Result<Vec<u8>> {
|
||||
let atime = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
|
||||
|
||||
let mut node = node;
|
||||
for _ in 0..32 {
|
||||
// XXX What should the limit be?
|
||||
let atime = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
|
||||
let mut buf = [0; 4096];
|
||||
let count = fs.read_node(node.0, 0, &mut buf, atime.as_secs(), atime.subsec_nanos())?;
|
||||
let scheme = format!("{}:", &self.name);
|
||||
let canon = canonicalize(
|
||||
&format!("{}{}", scheme, str::from_utf8(url).unwrap()).as_bytes(),
|
||||
&buf[0..count],
|
||||
);
|
||||
let count = tx.read_node(
|
||||
node.ptr(),
|
||||
0,
|
||||
&mut buf,
|
||||
atime.as_secs(),
|
||||
atime.subsec_nanos(),
|
||||
)?;
|
||||
let scheme = format!("{}:", scheme_name);
|
||||
let canon = canonicalize(&format!("{}{}", scheme, url).as_bytes(), &buf[0..count]);
|
||||
let path = str::from_utf8(&canon[scheme.len()..])
|
||||
.unwrap_or("")
|
||||
.trim_matches('/');
|
||||
nodes.clear();
|
||||
if let Some(next_node) = self.path_nodes(fs, path, uid, gid, nodes)? {
|
||||
if !next_node.1.is_symlink() {
|
||||
if let Some((next_node, next_node_name)) =
|
||||
Self::path_nodes(scheme_name, tx, path, uid, gid, nodes)?
|
||||
{
|
||||
if !next_node.data().is_symlink() {
|
||||
if canon.starts_with(scheme.as_bytes()) {
|
||||
nodes.push(next_node);
|
||||
nodes.push((next_node, next_node_name));
|
||||
return Ok(canon[scheme.len()..].to_vec());
|
||||
} else {
|
||||
return Err(Error::new(EXDEV));
|
||||
@@ -83,47 +85,51 @@ impl<D: Disk> FileScheme<D> {
|
||||
}
|
||||
|
||||
fn path_nodes(
|
||||
&self,
|
||||
fs: &mut FileSystem<D>,
|
||||
scheme_name: &str,
|
||||
tx: &mut Transaction<D>,
|
||||
path: &str,
|
||||
uid: u32,
|
||||
gid: u32,
|
||||
nodes: &mut Vec<(u64, Node)>,
|
||||
) -> Result<Option<(u64, Node)>> {
|
||||
nodes: &mut Vec<(TreeData<Node>, String)>,
|
||||
) -> Result<Option<(TreeData<Node>, String)>> {
|
||||
let mut parts = path.split('/').filter(|part| !part.is_empty());
|
||||
let mut part_opt = None;
|
||||
let mut block = fs.header.1.root;
|
||||
let mut part_opt: Option<&str> = None;
|
||||
let mut node_ptr = TreePtr::root();
|
||||
let mut node_name = String::new();
|
||||
loop {
|
||||
let node_res = match part_opt {
|
||||
None => fs.node(block),
|
||||
Some(part) => fs.find_node(part, block),
|
||||
None => tx.read_tree(node_ptr),
|
||||
Some(part) => {
|
||||
node_name = part.to_string();
|
||||
tx.find_node(node_ptr, part)
|
||||
}
|
||||
};
|
||||
|
||||
part_opt = parts.next();
|
||||
if part_opt.is_some() {
|
||||
if let Some(part) = part_opt {
|
||||
let node = node_res?;
|
||||
if !node.1.permission(uid, gid, Node::MODE_EXEC) {
|
||||
if !node.data().permission(uid, gid, Node::MODE_EXEC) {
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
if node.1.is_symlink() {
|
||||
let mut url = Vec::new();
|
||||
url.extend_from_slice(self.name.as_bytes());
|
||||
url.push(b':');
|
||||
for i in nodes.iter() {
|
||||
url.push(b'/');
|
||||
url.extend_from_slice(&i.1.name);
|
||||
if node.data().is_symlink() {
|
||||
let mut url = String::new();
|
||||
url.push_str(scheme_name);
|
||||
url.push(':');
|
||||
for (_parent, parent_name) in nodes.iter() {
|
||||
url.push('/');
|
||||
url.push_str(&parent_name);
|
||||
}
|
||||
self.resolve_symlink(fs, uid, gid, &url, node, nodes)?;
|
||||
block = nodes.last().unwrap().0;
|
||||
} else if !node.1.is_dir() {
|
||||
Self::resolve_symlink(scheme_name, tx, uid, gid, &url, node, nodes)?;
|
||||
node_ptr = nodes.last().unwrap().0.ptr();
|
||||
} else if !node.data().is_dir() {
|
||||
return Err(Error::new(ENOTDIR));
|
||||
} else {
|
||||
block = node.0;
|
||||
nodes.push(node);
|
||||
node_ptr = node.ptr();
|
||||
nodes.push((node, part.to_string()));
|
||||
}
|
||||
} else {
|
||||
match node_res {
|
||||
Ok(node) => return Ok(Some(node)),
|
||||
Ok(node) => return Ok(Some((node, node_name))),
|
||||
Err(err) => match err.errno {
|
||||
ENOENT => return Ok(None),
|
||||
_ => return Err(err),
|
||||
@@ -204,96 +210,110 @@ pub fn canonicalize(current: &[u8], path: &[u8]) -> Vec<u8> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: Disk> Scheme for FileScheme<D> {
|
||||
fn open(&self, url: &str, flags: usize, uid: u32, gid: u32) -> Result<usize> {
|
||||
impl<D: Disk> SchemeMut for FileScheme<D> {
|
||||
fn open(&mut self, url: &str, flags: usize, uid: u32, gid: u32) -> Result<usize> {
|
||||
let path = url.trim_matches('/');
|
||||
|
||||
// println!("Open '{}' {:X}", path, flags);
|
||||
|
||||
let mut fs = self.fs.borrow_mut();
|
||||
|
||||
//TODO: try to move things into one transaction
|
||||
let scheme_name = &self.name;
|
||||
let mut nodes = Vec::new();
|
||||
let node_opt = self.path_nodes(&mut fs, path, uid, gid, &mut nodes)?;
|
||||
let resource: Box<Resource<D>> = match node_opt {
|
||||
Some(node) => {
|
||||
let node_opt = self
|
||||
.fs
|
||||
.tx(|tx| Self::path_nodes(scheme_name, tx, path, uid, gid, &mut nodes))?;
|
||||
let resource: Box<dyn Resource<D>> = match node_opt {
|
||||
Some((node, _node_name)) => {
|
||||
if flags & (O_CREAT | O_EXCL) == O_CREAT | O_EXCL {
|
||||
return Err(Error::new(EEXIST));
|
||||
} else if node.1.is_dir() {
|
||||
} else if node.data().is_dir() {
|
||||
if flags & O_ACCMODE == O_RDONLY {
|
||||
if !node.1.permission(uid, gid, Node::MODE_READ) {
|
||||
// println!("dir not readable {:o}", node.1.mode);
|
||||
if !node.data().permission(uid, gid, Node::MODE_READ) {
|
||||
// println!("dir not readable {:o}", node.data().mode);
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
|
||||
let mut children = Vec::new();
|
||||
fs.child_nodes(&mut children, node.0)?;
|
||||
self.fs.tx(|tx| tx.child_nodes(node.ptr(), &mut children))?;
|
||||
|
||||
let mut data = Vec::new();
|
||||
for child in children.iter() {
|
||||
if let Ok(name) = child.1.name() {
|
||||
if let Some(child_name) = child.name() {
|
||||
if !data.is_empty() {
|
||||
data.push(b'\n');
|
||||
}
|
||||
data.extend_from_slice(&name.as_bytes());
|
||||
data.extend_from_slice(&child_name.as_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
Box::new(DirResource::new(path.to_string(), node.0, Some(data), uid))
|
||||
Box::new(DirResource::new(
|
||||
path.to_string(),
|
||||
node.ptr(),
|
||||
Some(data),
|
||||
uid,
|
||||
))
|
||||
} else if flags & O_WRONLY == O_WRONLY {
|
||||
// println!("{:X} & {:X}: EISDIR {}", flags, O_DIRECTORY, path);
|
||||
return Err(Error::new(EISDIR));
|
||||
} else {
|
||||
Box::new(DirResource::new(path.to_string(), node.0, None, uid))
|
||||
Box::new(DirResource::new(path.to_string(), node.ptr(), None, uid))
|
||||
}
|
||||
} else if node.1.is_symlink()
|
||||
} else if node.data().is_symlink()
|
||||
&& !(flags & O_STAT == O_STAT && flags & O_NOFOLLOW == O_NOFOLLOW)
|
||||
&& flags & O_SYMLINK != O_SYMLINK
|
||||
{
|
||||
let mut resolve_nodes = Vec::new();
|
||||
let resolved = self.resolve_symlink(
|
||||
&mut fs,
|
||||
uid,
|
||||
gid,
|
||||
url.as_bytes(),
|
||||
node,
|
||||
&mut resolve_nodes,
|
||||
)?;
|
||||
drop(fs);
|
||||
let resolved = self.fs.tx(|tx| {
|
||||
Self::resolve_symlink(
|
||||
scheme_name,
|
||||
tx,
|
||||
uid,
|
||||
gid,
|
||||
url,
|
||||
node,
|
||||
&mut resolve_nodes,
|
||||
)
|
||||
})?;
|
||||
let resolved_utf8 =
|
||||
str::from_utf8(&resolved).map_err(|_| Error::new(EINVAL))?;
|
||||
return self.open(resolved_utf8, flags, uid, gid);
|
||||
} else if !node.1.is_symlink() && flags & O_SYMLINK == O_SYMLINK {
|
||||
} else if !node.data().is_symlink() && flags & O_SYMLINK == O_SYMLINK {
|
||||
return Err(Error::new(EINVAL));
|
||||
} else {
|
||||
let node_ptr = node.ptr();
|
||||
|
||||
if flags & O_DIRECTORY == O_DIRECTORY {
|
||||
// println!("{:X} & {:X}: ENOTDIR {}", flags, O_DIRECTORY, path);
|
||||
return Err(Error::new(ENOTDIR));
|
||||
}
|
||||
|
||||
if (flags & O_ACCMODE == O_RDONLY || flags & O_ACCMODE == O_RDWR)
|
||||
&& !node.1.permission(uid, gid, Node::MODE_READ)
|
||||
&& !node.data().permission(uid, gid, Node::MODE_READ)
|
||||
{
|
||||
// println!("file not readable {:o}", node.1.mode);
|
||||
// println!("file not readable {:o}", node.data().mode);
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
|
||||
if (flags & O_ACCMODE == O_WRONLY || flags & O_ACCMODE == O_RDWR)
|
||||
&& !node.1.permission(uid, gid, Node::MODE_WRITE)
|
||||
&& !node.data().permission(uid, gid, Node::MODE_WRITE)
|
||||
{
|
||||
// println!("file not writable {:o}", node.1.mode);
|
||||
// println!("file not writable {:o}", node.data().mode);
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
|
||||
if flags & O_TRUNC == O_TRUNC {
|
||||
if !node.1.permission(uid, gid, Node::MODE_WRITE) {
|
||||
// println!("file not writable {:o}", node.1.mode);
|
||||
if !node.data().permission(uid, gid, Node::MODE_WRITE) {
|
||||
// println!("file not writable {:o}", node.data().mode);
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
|
||||
fs.node_set_len(node.0, 0)?;
|
||||
let mtime = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
|
||||
self.fs.tx(|tx| {
|
||||
tx.truncate_node(node_ptr, 0, mtime.as_secs(), mtime.subsec_nanos())
|
||||
})?;
|
||||
}
|
||||
|
||||
Box::new(FileResource::new(path.to_string(), node.0, flags, uid))
|
||||
Box::new(FileResource::new(path.to_string(), node_ptr, flags, uid))
|
||||
}
|
||||
}
|
||||
None => {
|
||||
@@ -305,8 +325,8 @@ impl<D: Disk> Scheme for FileScheme<D> {
|
||||
}
|
||||
}
|
||||
if !last_part.is_empty() {
|
||||
if let Some(parent) = nodes.last() {
|
||||
if !parent.1.permission(uid, gid, Node::MODE_WRITE) {
|
||||
if let Some((parent, _parent_name)) = nodes.last() {
|
||||
if !parent.data().permission(uid, gid, Node::MODE_WRITE) {
|
||||
// println!("dir not writable {:o}", parent.1.mode);
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
@@ -320,22 +340,28 @@ impl<D: Disk> Scheme for FileScheme<D> {
|
||||
Node::MODE_FILE
|
||||
};
|
||||
|
||||
let ctime = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
|
||||
let mut node = fs.create_node(
|
||||
mode_type | (flags as u16 & Node::MODE_PERM),
|
||||
&last_part,
|
||||
parent.0,
|
||||
ctime.as_secs(),
|
||||
ctime.subsec_nanos(),
|
||||
)?;
|
||||
node.1.uid = uid;
|
||||
node.1.gid = gid;
|
||||
fs.write_at(node.0, &node.1)?;
|
||||
let node_ptr = self.fs.tx(|tx| {
|
||||
let ctime = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
|
||||
let mut node = tx.create_node(
|
||||
parent.ptr(),
|
||||
&last_part,
|
||||
mode_type | (flags as u16 & Node::MODE_PERM),
|
||||
ctime.as_secs(),
|
||||
ctime.subsec_nanos(),
|
||||
)?;
|
||||
let node_ptr = node.ptr();
|
||||
if node.data().uid() != uid || node.data().gid() != gid {
|
||||
node.data_mut().set_uid(uid);
|
||||
node.data_mut().set_gid(gid);
|
||||
tx.sync_tree(node)?;
|
||||
}
|
||||
Ok(node_ptr)
|
||||
})?;
|
||||
|
||||
if dir {
|
||||
Box::new(DirResource::new(path.to_string(), node.0, None, uid))
|
||||
Box::new(DirResource::new(path.to_string(), node_ptr, None, uid))
|
||||
} else {
|
||||
Box::new(FileResource::new(path.to_string(), node.0, flags, uid))
|
||||
Box::new(FileResource::new(path.to_string(), node_ptr, flags, uid))
|
||||
}
|
||||
} else {
|
||||
return Err(Error::new(EPERM));
|
||||
@@ -350,196 +376,194 @@ impl<D: Disk> Scheme for FileScheme<D> {
|
||||
};
|
||||
|
||||
let id = self.next_id.fetch_add(1, Ordering::SeqCst);
|
||||
self.files.borrow_mut().insert(id, resource);
|
||||
self.files.insert(id, resource);
|
||||
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
fn chmod(&self, url: &str, mode: u16, uid: u32, gid: u32) -> Result<usize> {
|
||||
fn chmod(&mut self, url: &str, mode: u16, uid: u32, gid: u32) -> Result<usize> {
|
||||
let path = url.trim_matches('/');
|
||||
|
||||
// println!("Chmod '{}'", path);
|
||||
|
||||
let mut fs = self.fs.borrow_mut();
|
||||
let scheme_name = &self.name;
|
||||
self.fs.tx(|tx| {
|
||||
let mut nodes = Vec::new();
|
||||
if let Some((mut node, _node_name)) =
|
||||
Self::path_nodes(scheme_name, tx, path, uid, gid, &mut nodes)?
|
||||
{
|
||||
if node.data().uid() == uid || uid == 0 {
|
||||
let old_mode = node.data().mode();
|
||||
let new_mode = (old_mode & !MODE_PERM) | (mode & MODE_PERM);
|
||||
if old_mode != new_mode {
|
||||
node.data_mut().set_mode(new_mode);
|
||||
tx.sync_tree(node)?;
|
||||
}
|
||||
|
||||
let mut nodes = Vec::new();
|
||||
if let Some(mut node) = self.path_nodes(&mut fs, path, uid, gid, &mut nodes)? {
|
||||
if node.1.uid == uid || uid == 0 {
|
||||
node.1.mode = (node.1.mode & !MODE_PERM) | (mode & MODE_PERM);
|
||||
fs.write_at(node.0, &node.1)?;
|
||||
Ok(0)
|
||||
Ok(0)
|
||||
} else {
|
||||
Err(Error::new(EPERM))
|
||||
}
|
||||
} else {
|
||||
Err(Error::new(EPERM))
|
||||
Err(Error::new(ENOENT))
|
||||
}
|
||||
} else {
|
||||
Err(Error::new(ENOENT))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn rmdir(&self, url: &str, uid: u32, gid: u32) -> Result<usize> {
|
||||
fn rmdir(&mut self, url: &str, uid: u32, gid: u32) -> Result<usize> {
|
||||
let path = url.trim_matches('/');
|
||||
|
||||
// println!("Rmdir '{}'", path);
|
||||
|
||||
let mut fs = self.fs.borrow_mut();
|
||||
|
||||
let mut nodes = Vec::new();
|
||||
if let Some(child) = self.path_nodes(&mut fs, path, uid, gid, &mut nodes)? {
|
||||
if let Some(parent) = nodes.last() {
|
||||
if !parent.1.permission(uid, gid, Node::MODE_WRITE) {
|
||||
// println!("dir not writable {:o}", parent.1.mode);
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
|
||||
if child.1.is_dir() {
|
||||
if !child.1.permission(uid, gid, Node::MODE_WRITE) {
|
||||
let scheme_name = &self.name;
|
||||
self.fs.tx(|tx| {
|
||||
let mut nodes = Vec::new();
|
||||
if let Some((child, child_name)) =
|
||||
Self::path_nodes(scheme_name, tx, path, uid, gid, &mut nodes)?
|
||||
{
|
||||
if let Some((parent, _parent_name)) = nodes.last() {
|
||||
if !parent.data().permission(uid, gid, Node::MODE_WRITE) {
|
||||
// println!("dir not writable {:o}", parent.1.mode);
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
|
||||
if let Ok(child_name) = child.1.name() {
|
||||
fs.remove_node(Node::MODE_DIR, child_name, parent.0)
|
||||
if child.data().is_dir() {
|
||||
if !child.data().permission(uid, gid, Node::MODE_WRITE) {
|
||||
// println!("dir not writable {:o}", parent.1.mode);
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
|
||||
tx.remove_node(parent.ptr(), &child_name, Node::MODE_DIR)
|
||||
.and(Ok(0))
|
||||
} else {
|
||||
Err(Error::new(ENOENT))
|
||||
Err(Error::new(ENOTDIR))
|
||||
}
|
||||
} else {
|
||||
Err(Error::new(ENOTDIR))
|
||||
Err(Error::new(EPERM))
|
||||
}
|
||||
} else {
|
||||
Err(Error::new(EPERM))
|
||||
Err(Error::new(ENOENT))
|
||||
}
|
||||
} else {
|
||||
Err(Error::new(ENOENT))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn unlink(&self, url: &str, uid: u32, gid: u32) -> Result<usize> {
|
||||
fn unlink(&mut self, url: &str, uid: u32, gid: u32) -> Result<usize> {
|
||||
let path = url.trim_matches('/');
|
||||
|
||||
// println!("Unlink '{}'", path);
|
||||
|
||||
let mut fs = self.fs.borrow_mut();
|
||||
|
||||
let mut nodes = Vec::new();
|
||||
if let Some(child) = self.path_nodes(&mut fs, path, uid, gid, &mut nodes)? {
|
||||
if let Some(parent) = nodes.last() {
|
||||
if !parent.1.permission(uid, gid, Node::MODE_WRITE) {
|
||||
// println!("dir not writable {:o}", parent.1.mode);
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
|
||||
if !child.1.is_dir() {
|
||||
if child.1.uid != uid {
|
||||
// println!("file not owned by current user {}", parent.1.uid);
|
||||
let scheme_name = &self.name;
|
||||
self.fs.tx(|tx| {
|
||||
let mut nodes = Vec::new();
|
||||
if let Some((child, child_name)) =
|
||||
Self::path_nodes(scheme_name, tx, path, uid, gid, &mut nodes)?
|
||||
{
|
||||
if let Some((parent, _parent_name)) = nodes.last() {
|
||||
if !parent.data().permission(uid, gid, Node::MODE_WRITE) {
|
||||
// println!("dir not writable {:o}", parent.1.mode);
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
|
||||
if let Ok(child_name) = child.1.name() {
|
||||
if child.1.is_symlink() {
|
||||
fs.remove_node(Node::MODE_SYMLINK, child_name, parent.0)
|
||||
if !child.data().is_dir() {
|
||||
if child.data().uid() != uid {
|
||||
// println!("file not owned by current user {}", parent.1.uid);
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
|
||||
if child.data().is_symlink() {
|
||||
tx.remove_node(parent.ptr(), &child_name, Node::MODE_SYMLINK)
|
||||
.and(Ok(0))
|
||||
} else {
|
||||
fs.remove_node(Node::MODE_FILE, child_name, parent.0)
|
||||
tx.remove_node(parent.ptr(), &child_name, Node::MODE_FILE)
|
||||
.and(Ok(0))
|
||||
}
|
||||
} else {
|
||||
Err(Error::new(ENOENT))
|
||||
Err(Error::new(EISDIR))
|
||||
}
|
||||
} else {
|
||||
Err(Error::new(EISDIR))
|
||||
Err(Error::new(EPERM))
|
||||
}
|
||||
} else {
|
||||
Err(Error::new(EPERM))
|
||||
Err(Error::new(ENOENT))
|
||||
}
|
||||
} else {
|
||||
Err(Error::new(ENOENT))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/* Resource operations */
|
||||
#[allow(unused_variables)]
|
||||
fn dup(&self, old_id: usize, buf: &[u8]) -> Result<usize> {
|
||||
fn dup(&mut self, old_id: usize, buf: &[u8]) -> Result<usize> {
|
||||
// println!("Dup {}", old_id);
|
||||
|
||||
if !buf.is_empty() {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
|
||||
let mut files = self.files.borrow_mut();
|
||||
let resource = if let Some(old_resource) = files.get(&old_id) {
|
||||
let resource = if let Some(old_resource) = self.files.get(&old_id) {
|
||||
old_resource.dup()?
|
||||
} else {
|
||||
return Err(Error::new(EBADF));
|
||||
};
|
||||
|
||||
let id = self.next_id.fetch_add(1, Ordering::SeqCst);
|
||||
files.insert(id, resource);
|
||||
self.files.insert(id, resource);
|
||||
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn read(&self, id: usize, buf: &mut [u8]) -> Result<usize> {
|
||||
fn read(&mut self, id: usize, buf: &mut [u8]) -> Result<usize> {
|
||||
// println!("Read {}, {:X} {}", id, buf.as_ptr() as usize, buf.len());
|
||||
let mut files = self.files.borrow_mut();
|
||||
if let Some(file) = files.get_mut(&id) {
|
||||
file.read(buf, &mut self.fs.borrow_mut())
|
||||
if let Some(file) = self.files.get_mut(&id) {
|
||||
self.fs.tx(|tx| file.read(buf, tx))
|
||||
} else {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
}
|
||||
|
||||
fn write(&self, id: usize, buf: &[u8]) -> Result<usize> {
|
||||
fn write(&mut self, id: usize, buf: &[u8]) -> Result<usize> {
|
||||
// println!("Write {}, {:X} {}", id, buf.as_ptr() as usize, buf.len());
|
||||
let mut files = self.files.borrow_mut();
|
||||
if let Some(file) = files.get_mut(&id) {
|
||||
file.write(buf, &mut self.fs.borrow_mut())
|
||||
if let Some(file) = self.files.get_mut(&id) {
|
||||
self.fs.tx(|tx| file.write(buf, tx))
|
||||
} else {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
}
|
||||
|
||||
fn seek(&self, id: usize, pos: isize, whence: usize) -> Result<isize> {
|
||||
fn seek(&mut self, id: usize, pos: isize, whence: usize) -> Result<isize> {
|
||||
// println!("Seek {}, {} {}", id, pos, whence);
|
||||
let mut files = self.files.borrow_mut();
|
||||
if let Some(file) = files.get_mut(&id) {
|
||||
file.seek(pos, whence, &mut self.fs.borrow_mut())
|
||||
if let Some(file) = self.files.get_mut(&id) {
|
||||
self.fs.tx(|tx| file.seek(pos, whence, tx))
|
||||
} else {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
}
|
||||
|
||||
fn fchmod(&self, id: usize, mode: u16) -> Result<usize> {
|
||||
let mut files = self.files.borrow_mut();
|
||||
if let Some(file) = files.get_mut(&id) {
|
||||
file.fchmod(mode, &mut self.fs.borrow_mut())
|
||||
fn fchmod(&mut self, id: usize, mode: u16) -> Result<usize> {
|
||||
if let Some(file) = self.files.get_mut(&id) {
|
||||
self.fs.tx(|tx| file.fchmod(mode, tx))
|
||||
} else {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
}
|
||||
|
||||
fn fchown(&self, id: usize, uid: u32, gid: u32) -> Result<usize> {
|
||||
let mut files = self.files.borrow_mut();
|
||||
if let Some(file) = files.get_mut(&id) {
|
||||
file.fchown(uid, gid, &mut self.fs.borrow_mut())
|
||||
fn fchown(&mut self, id: usize, uid: u32, gid: u32) -> Result<usize> {
|
||||
if let Some(file) = self.files.get_mut(&id) {
|
||||
self.fs.tx(|tx| file.fchown(uid, gid, tx))
|
||||
} else {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
}
|
||||
|
||||
fn fcntl(&self, id: usize, cmd: usize, arg: usize) -> Result<usize> {
|
||||
let mut files = self.files.borrow_mut();
|
||||
if let Some(file) = files.get_mut(&id) {
|
||||
fn fcntl(&mut self, id: usize, cmd: usize, arg: usize) -> Result<usize> {
|
||||
if let Some(file) = self.files.get_mut(&id) {
|
||||
file.fcntl(cmd, arg)
|
||||
} else {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
}
|
||||
|
||||
fn fevent(&self, id: usize, _flags: EventFlags) -> Result<EventFlags> {
|
||||
let files = self.files.borrow_mut();
|
||||
if let Some(file) = files.get(&id) {
|
||||
fn fevent(&mut self, id: usize, _flags: EventFlags) -> Result<EventFlags> {
|
||||
if let Some(_file) = self.files.get(&id) {
|
||||
// EPERM is returned for files that are always readable or writable
|
||||
Err(Error::new(EPERM))
|
||||
} else {
|
||||
@@ -547,10 +571,9 @@ impl<D: Disk> Scheme for FileScheme<D> {
|
||||
}
|
||||
}
|
||||
|
||||
fn fpath(&self, id: usize, buf: &mut [u8]) -> Result<usize> {
|
||||
fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result<usize> {
|
||||
// println!("Fpath {}, {:X} {}", id, buf.as_ptr() as usize, buf.len());
|
||||
let files = self.files.borrow_mut();
|
||||
if let Some(file) = files.get(&id) {
|
||||
if let Some(file) = self.files.get(&id) {
|
||||
let name = self.name.as_bytes();
|
||||
|
||||
let mut i = 0;
|
||||
@@ -567,13 +590,23 @@ impl<D: Disk> Scheme for FileScheme<D> {
|
||||
i += 1;
|
||||
}
|
||||
|
||||
file.path(&mut buf[i..]).map(|count| i + count)
|
||||
let path = file.path().as_bytes();
|
||||
let mut j = 0;
|
||||
while i < buf.len() && j < path.len() {
|
||||
buf[i] = path[j];
|
||||
i += 1;
|
||||
j += 1;
|
||||
}
|
||||
|
||||
Ok(i)
|
||||
} else {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
}
|
||||
|
||||
fn frename(&self, id: usize, url: &str, uid: u32, gid: u32) -> Result<usize> {
|
||||
fn frename(&mut self, id: usize, url: &str, uid: u32, gid: u32) -> Result<usize> {
|
||||
unimplemented!();
|
||||
/*TODO: FRENAME
|
||||
let path = url.trim_matches('/');
|
||||
|
||||
// println!("Frename {}, {} from {}, {}", id, path, uid, gid);
|
||||
@@ -613,19 +646,19 @@ impl<D: Disk> Scheme for FileScheme<D> {
|
||||
}
|
||||
|
||||
if let Some(ref node) = node_opt {
|
||||
if !node.1.owner(uid) {
|
||||
if !node.data().owner(uid) {
|
||||
// println!("new dir not owned by caller {}", uid);
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
|
||||
if node.1.is_dir() {
|
||||
if node.data().is_dir() {
|
||||
if !orig.1.is_dir() {
|
||||
// println!("orig is file, new is dir");
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
|
||||
let mut children = Vec::new();
|
||||
fs.child_nodes(&mut children, node.0)?;
|
||||
fs.child_nodes(node.ptr(), &mut children)?;
|
||||
|
||||
if !children.is_empty() {
|
||||
// println!("new dir not empty");
|
||||
@@ -670,29 +703,23 @@ impl<D: Disk> Scheme for FileScheme<D> {
|
||||
} else {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
fn fstat(&self, id: usize, stat: &mut Stat) -> Result<usize> {
|
||||
fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result<usize> {
|
||||
// println!("Fstat {}, {:X}", id, stat as *mut Stat as usize);
|
||||
let files = self.files.borrow_mut();
|
||||
if let Some(file) = files.get(&id) {
|
||||
file.stat(stat, &mut self.fs.borrow_mut())
|
||||
if let Some(file) = self.files.get(&id) {
|
||||
self.fs.tx(|tx| file.stat(stat, tx))
|
||||
} else {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
}
|
||||
|
||||
fn fstatvfs(&self, id: usize, stat: &mut StatVfs) -> Result<usize> {
|
||||
let files = self.files.borrow_mut();
|
||||
if let Some(_file) = files.get(&id) {
|
||||
let mut fs = self.fs.borrow_mut();
|
||||
|
||||
let free = fs.header.1.free;
|
||||
let free_size = fs.node_len(free)?;
|
||||
|
||||
fn fstatvfs(&mut self, id: usize, stat: &mut StatVfs) -> Result<usize> {
|
||||
if let Some(_file) = self.files.get(&id) {
|
||||
stat.f_bsize = BLOCK_SIZE as u32;
|
||||
stat.f_blocks = fs.header.1.size / (stat.f_bsize as u64);
|
||||
stat.f_bfree = free_size / (stat.f_bsize as u64);
|
||||
stat.f_blocks = self.fs.header.size() / (stat.f_bsize as u64);
|
||||
stat.f_bfree = self.fs.allocator().free();
|
||||
stat.f_bavail = stat.f_bfree;
|
||||
|
||||
Ok(0)
|
||||
@@ -701,53 +728,48 @@ impl<D: Disk> Scheme for FileScheme<D> {
|
||||
}
|
||||
}
|
||||
|
||||
fn fsync(&self, id: usize) -> Result<usize> {
|
||||
fn fsync(&mut self, id: usize) -> Result<usize> {
|
||||
// println!("Fsync {}", id);
|
||||
let mut files = self.files.borrow_mut();
|
||||
if let Some(file) = files.get_mut(&id) {
|
||||
file.sync(&mut self.fs.borrow_mut())
|
||||
if let Some(file) = self.files.get_mut(&id) {
|
||||
self.fs.tx(|tx| file.sync(tx))
|
||||
} else {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
}
|
||||
|
||||
fn ftruncate(&self, id: usize, len: usize) -> Result<usize> {
|
||||
fn ftruncate(&mut self, id: usize, len: usize) -> Result<usize> {
|
||||
// println!("Ftruncate {}, {}", id, len);
|
||||
let mut files = self.files.borrow_mut();
|
||||
if let Some(file) = files.get_mut(&id) {
|
||||
file.truncate(len, &mut self.fs.borrow_mut())
|
||||
if let Some(file) = self.files.get_mut(&id) {
|
||||
self.fs.tx(|tx| file.truncate(len, tx))
|
||||
} else {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
}
|
||||
|
||||
fn futimens(&self, id: usize, times: &[TimeSpec]) -> Result<usize> {
|
||||
fn futimens(&mut self, id: usize, times: &[TimeSpec]) -> Result<usize> {
|
||||
// println!("Futimens {}, {}", id, times.len());
|
||||
let mut files = self.files.borrow_mut();
|
||||
if let Some(file) = files.get_mut(&id) {
|
||||
file.utimens(times, &mut self.fs.borrow_mut())
|
||||
if let Some(file) = self.files.get_mut(&id) {
|
||||
self.fs.tx(|tx| file.utimens(times, tx))
|
||||
} else {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
}
|
||||
|
||||
fn fmap(&self, id: usize, map: &Map) -> Result<usize> {
|
||||
fn fmap(&mut self, id: usize, map: &Map) -> Result<usize> {
|
||||
// println!("Fmap {}, {:?}", id, map);
|
||||
let mut files = self.files.borrow_mut();
|
||||
if let Some(file) = files.get_mut(&id) {
|
||||
let address = file.fmap(map, &mut self.fs.borrow_mut())?;
|
||||
self.fmap.borrow_mut().insert(address, id);
|
||||
if let Some(file) = self.files.get_mut(&id) {
|
||||
let address = self.fs.tx(|tx| file.fmap(map, tx))?;
|
||||
self.fmap.insert(address, id);
|
||||
Ok(address)
|
||||
} else {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
}
|
||||
|
||||
fn funmap_old(&self, address: usize) -> Result<usize> {
|
||||
if let Some(id) = self.fmap.borrow_mut().remove(&address) {
|
||||
let mut files = self.files.borrow_mut();
|
||||
if let Some(file) = files.get_mut(&id) {
|
||||
file.funmap(address, &mut self.fs.borrow_mut())
|
||||
fn funmap_old(&mut self, address: usize) -> Result<usize> {
|
||||
if let Some(id) = self.fmap.remove(&address) {
|
||||
if let Some(file) = self.files.get_mut(&id) {
|
||||
self.fs.tx(|tx| file.funmap(address, tx))
|
||||
} else {
|
||||
Err(Error::new(EINVAL))
|
||||
}
|
||||
@@ -756,16 +778,23 @@ impl<D: Disk> Scheme for FileScheme<D> {
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: implement
|
||||
fn funmap(&self, address: usize, length: usize) -> Result<usize> {
|
||||
//TODO: implement (length is ignored!)
|
||||
fn funmap(&mut self, address: usize, length: usize) -> Result<usize> {
|
||||
println!("redoxfs: funmap 0x{:X}, {}", address, length);
|
||||
Err(Error::new(ENOSYS))
|
||||
if let Some(id) = self.fmap.remove(&address) {
|
||||
if let Some(file) = self.files.get_mut(&id) {
|
||||
self.fs.tx(|tx| file.funmap(address, tx))
|
||||
} else {
|
||||
Err(Error::new(EINVAL))
|
||||
}
|
||||
} else {
|
||||
Err(Error::new(EINVAL))
|
||||
}
|
||||
}
|
||||
|
||||
fn close(&self, id: usize) -> Result<usize> {
|
||||
fn close(&mut self, id: usize) -> Result<usize> {
|
||||
// println!("Close {}", id);
|
||||
let mut files = self.files.borrow_mut();
|
||||
if files.remove(&id).is_some() {
|
||||
if self.files.remove(&id).is_some() {
|
||||
Ok(0)
|
||||
} else {
|
||||
Err(Error::new(EBADF))
|
||||
|
||||
Reference in New Issue
Block a user