+8
-7
@@ -48,11 +48,11 @@ impl<D: Disk> FileSystem<D> {
|
||||
let block_offset = (reserved.len() as u64 + BLOCK_SIZE - 1)/BLOCK_SIZE;
|
||||
|
||||
if size >= (block_offset + 4) * BLOCK_SIZE {
|
||||
let mut free = (2, Node::new(Node::MODE_FILE, "free", 0, ctime, ctime_nsec));
|
||||
let mut free = (2, Node::new(Node::MODE_FILE, "free", 0, ctime, ctime_nsec)?);
|
||||
free.1.extents[0] = Extent::new(4, size - (block_offset + 4) * BLOCK_SIZE);
|
||||
disk.write_at(block_offset + free.0, &free.1)?;
|
||||
|
||||
let root = (1, Node::new(Node::MODE_DIR | 0o755, "root", 0, ctime, ctime_nsec));
|
||||
let root = (1, Node::new(Node::MODE_DIR | 0o755, "root", 0, ctime, ctime_nsec)?);
|
||||
disk.write_at(block_offset + root.0, &root.1)?;
|
||||
|
||||
let header = (0, Header::new(size, root.0, free.0));
|
||||
@@ -171,7 +171,8 @@ impl<D: Disk> FileSystem<D> {
|
||||
self.find_node(name, parent.1.next)
|
||||
}
|
||||
|
||||
fn insert_blocks(&mut self, block: u64, length: u64, parent_block: u64) -> Result<()> {
|
||||
//TODO: Accept length in units of BLOCK_SIZE to match remove_blocks
|
||||
pub fn insert_blocks(&mut self, block: u64, length: u64, parent_block: u64) -> Result<()> {
|
||||
if parent_block == 0 {
|
||||
return Err(Error::new(ENOSPC));
|
||||
}
|
||||
@@ -222,7 +223,8 @@ impl<D: Disk> FileSystem<D> {
|
||||
if self.find_node(name, parent_block).is_ok() {
|
||||
Err(Error::new(EEXIST))
|
||||
} else {
|
||||
let node = (self.allocate(1)?, Node::new(mode, name, parent_block, ctime, ctime_nsec));
|
||||
let node_data = Node::new(mode, name, parent_block, ctime, ctime_nsec)?;
|
||||
let node = (self.allocate(1)?, node_data);
|
||||
self.write_at(node.0, &node.1)?;
|
||||
|
||||
self.insert_blocks(node.0, BLOCK_SIZE, parent_block)?;
|
||||
@@ -231,7 +233,7 @@ impl<D: Disk> FileSystem<D> {
|
||||
}
|
||||
}
|
||||
|
||||
fn remove_blocks(&mut self, block: u64, length: u64, parent_block: u64) -> Result<()> {
|
||||
pub fn remove_blocks(&mut self, block: u64, length: u64, parent_block: u64) -> Result<()> {
|
||||
if parent_block == 0 {
|
||||
return Err(Error::new(ENOENT));
|
||||
}
|
||||
@@ -270,8 +272,6 @@ impl<D: Disk> FileSystem<D> {
|
||||
self.insert_blocks(replace.block, replace.length, parent_block)?;
|
||||
}
|
||||
|
||||
self.deallocate(block, BLOCK_SIZE)?;
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
self.remove_blocks(block, length, parent.1.next)
|
||||
@@ -292,6 +292,7 @@ impl<D: Disk> FileSystem<D> {
|
||||
self.node_set_len(node.0, 0)?;
|
||||
self.remove_blocks(node.0, 1, parent_block)?;
|
||||
self.write_at(node.0, &Node::default())?;
|
||||
self.deallocate(node.0, BLOCK_SIZE)?;
|
||||
|
||||
Ok(())
|
||||
} else if node.1.is_dir() {
|
||||
|
||||
@@ -10,6 +10,7 @@ use disk::Disk;
|
||||
use filesystem::FileSystem;
|
||||
|
||||
pub trait Resource<D: Disk> {
|
||||
fn block(&self) -> u64;
|
||||
fn dup(&self) -> Result<Box<Resource<D>>>;
|
||||
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>;
|
||||
@@ -45,6 +46,10 @@ impl DirResource {
|
||||
}
|
||||
|
||||
impl<D: Disk> Resource<D> for DirResource {
|
||||
fn block(&self) -> u64 {
|
||||
self.block
|
||||
}
|
||||
|
||||
fn dup(&self) -> Result<Box<Resource<D>>> {
|
||||
Ok(Box::new(DirResource {
|
||||
path: self.path.clone(),
|
||||
@@ -187,6 +192,10 @@ impl FileResource {
|
||||
}
|
||||
|
||||
impl<D: Disk> Resource<D> for FileResource {
|
||||
fn block(&self) -> u64 {
|
||||
self.block
|
||||
}
|
||||
|
||||
fn dup(&self) -> Result<Box<Resource<D>>> {
|
||||
Ok(Box::new(FileResource {
|
||||
path: self.path.clone(),
|
||||
|
||||
@@ -5,7 +5,7 @@ use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
use syscall::data::{Stat, StatVfs, TimeSpec};
|
||||
use syscall::error::{Error, Result, EACCES, EEXIST, EISDIR, ENOTDIR, EPERM, ENOENT, EBADF, ELOOP, EINVAL};
|
||||
use syscall::error::{Error, Result, EACCES, EEXIST, EISDIR, ENOTDIR, ENOTEMPTY, EPERM, ENOENT, EBADF, ELOOP, EINVAL};
|
||||
use syscall::flag::{O_APPEND, O_CREAT, O_DIRECTORY, O_STAT, O_EXCL, O_TRUNC, O_ACCMODE, O_RDONLY, O_WRONLY, O_RDWR, MODE_PERM, O_SYMLINK, O_NOFOLLOW};
|
||||
use syscall::scheme::Scheme;
|
||||
|
||||
@@ -522,11 +522,97 @@ impl<D: Disk> Scheme for FileScheme<D> {
|
||||
fn frename(&self, id: usize, url: &[u8], uid: u32, gid: u32) -> Result<usize> {
|
||||
let path = str::from_utf8(url).unwrap_or("").trim_matches('/');
|
||||
|
||||
println!("Frename {}, {} from {}, {}", id, path, uid, gid);
|
||||
// println!("Frename {}, {} from {}, {}", id, path, uid, gid);
|
||||
|
||||
let files = self.files.lock();
|
||||
if let Some(_file) = files.get(&id) {
|
||||
// TODO
|
||||
Err(Error::new(EPERM))
|
||||
if let Some(file) = files.get(&id) {
|
||||
//TODO: Check for EINVAL
|
||||
// The new pathname contained a path prefix of the old, or, more generally,
|
||||
// an attempt was made to make a directory a subdirectory of itself.
|
||||
|
||||
let mut last_part = String::new();
|
||||
for part in path.split('/') {
|
||||
if ! part.is_empty() {
|
||||
last_part = part.to_string();
|
||||
}
|
||||
}
|
||||
if last_part.is_empty() {
|
||||
return Err(Error::new(EPERM));
|
||||
}
|
||||
|
||||
let mut fs = self.fs.borrow_mut();
|
||||
|
||||
let mut orig = fs.node(file.block())?;
|
||||
|
||||
if ! orig.1.owner(uid) {
|
||||
// println!("orig not owned by caller {}", uid);
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
|
||||
let mut nodes = Vec::new();
|
||||
let node_opt = self.path_nodes(&mut fs, path, uid, gid, &mut nodes)?;
|
||||
|
||||
if let Some(parent) = nodes.last() {
|
||||
if ! parent.1.owner(uid) {
|
||||
// println!("parent not owned by caller {}", uid);
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
|
||||
if let Some(ref node) = node_opt {
|
||||
if ! node.1.owner(uid) {
|
||||
// println!("new dir not owned by caller {}", uid);
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
|
||||
if node.1.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)?;
|
||||
|
||||
if ! children.is_empty() {
|
||||
// println!("new dir not empty");
|
||||
return Err(Error::new(ENOTEMPTY));
|
||||
}
|
||||
} else {
|
||||
if orig.1.is_dir() {
|
||||
// println!("orig is dir, new is file");
|
||||
return Err(Error::new(ENOTDIR));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let orig_parent = orig.1.parent;
|
||||
|
||||
orig.1.set_name(&last_part)?;
|
||||
orig.1.parent = parent.0;
|
||||
|
||||
if parent.0 != orig_parent {
|
||||
fs.remove_blocks(orig.0, 1, orig_parent)?;
|
||||
}
|
||||
|
||||
fs.write_at(orig.0, &orig.1)?;
|
||||
|
||||
if let Some(node) = node_opt {
|
||||
if node.0 != orig.0 {
|
||||
fs.node_set_len(node.0, 0)?;
|
||||
fs.remove_blocks(node.0, 1, parent.0)?;
|
||||
fs.write_at(node.0, &Node::default())?;
|
||||
fs.deallocate(node.0, BLOCK_SIZE)?;
|
||||
}
|
||||
}
|
||||
|
||||
if parent.0 != orig_parent {
|
||||
fs.insert_blocks(orig.0, BLOCK_SIZE, parent.0)?;
|
||||
}
|
||||
|
||||
Ok(0)
|
||||
} else {
|
||||
Err(Error::new(EPERM))
|
||||
}
|
||||
} else {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
|
||||
+25
-3
@@ -2,6 +2,7 @@ use std::{fmt, mem, ops, slice, str};
|
||||
|
||||
use BLOCK_SIZE;
|
||||
use super::Extent;
|
||||
use syscall;
|
||||
|
||||
/// A file/folder node
|
||||
#[repr(packed)]
|
||||
@@ -46,13 +47,16 @@ impl Node {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(mode: u16, name: &str, parent: u64, ctime: u64, ctime_nsec: u32) -> Node {
|
||||
pub fn new(mode: u16, name: &str, parent: u64, ctime: u64, ctime_nsec: u32) -> syscall::Result<Node> {
|
||||
let mut bytes = [0; 222];
|
||||
if name.len() > bytes.len() {
|
||||
return Err(syscall::Error::new(syscall::ENAMETOOLONG));
|
||||
}
|
||||
for (b, c) in bytes.iter_mut().zip(name.bytes()) {
|
||||
*b = c;
|
||||
}
|
||||
|
||||
Node {
|
||||
Ok(Node {
|
||||
mode: mode,
|
||||
uid: 0,
|
||||
gid: 0,
|
||||
@@ -64,7 +68,7 @@ impl Node {
|
||||
parent: parent,
|
||||
next: 0,
|
||||
extents: [Extent::default(); (BLOCK_SIZE as usize - 272)/16],
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn name(&self) -> Result<&str, str::Utf8Error> {
|
||||
@@ -80,6 +84,20 @@ impl Node {
|
||||
str::from_utf8(&self.name[..len])
|
||||
}
|
||||
|
||||
pub fn set_name(&mut self, name: &str) -> syscall::Result<()> {
|
||||
let mut bytes = [0; 222];
|
||||
if name.len() > bytes.len() {
|
||||
return Err(syscall::Error::new(syscall::ENAMETOOLONG));
|
||||
}
|
||||
for (b, c) in bytes.iter_mut().zip(name.bytes()) {
|
||||
*b = c;
|
||||
}
|
||||
|
||||
self.name = bytes;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn is_dir(&self) -> bool {
|
||||
self.mode & Node::MODE_TYPE == Node::MODE_DIR
|
||||
}
|
||||
@@ -92,6 +110,10 @@ impl Node {
|
||||
self.mode & Node::MODE_TYPE == Node::MODE_SYMLINK
|
||||
}
|
||||
|
||||
pub fn owner(&self, uid: u32) -> bool {
|
||||
uid == 0 || self.uid == uid
|
||||
}
|
||||
|
||||
pub fn permission(&self, uid: u32, gid: u32, op: u16) -> bool {
|
||||
let mut perm = self.mode & 0o7;
|
||||
if self.uid == uid {
|
||||
|
||||
Reference in New Issue
Block a user