Implement frename fixing #37 and fix #11 by checking names

This commit is contained in:
Jeremy Soller
2017-12-29 14:08:36 -07:00
parent 2e6e272c72
commit 40e2a3e221
4 changed files with 133 additions and 15 deletions
+8 -7
View File
@@ -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() {
+9
View File
@@ -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(),
+91 -5
View File
@@ -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
View File
@@ -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 {