Format the codebase

This commit is contained in:
Xavier L'Heureux
2020-01-20 15:00:26 -05:00
parent a6af6a9289
commit 58f2d28ff5
17 changed files with 804 additions and 463 deletions
+194 -78
View File
@@ -8,23 +8,30 @@ use std::os::unix::ffi::OsStrExt;
use std::path::Path;
use std::time::{SystemTime, UNIX_EPOCH};
use BLOCK_SIZE;
use disk::Disk;
use filesystem;
use node::Node;
use BLOCK_SIZE;
use self::fuse::{FileType, FileAttr, Filesystem, Request, ReplyData, ReplyEntry, ReplyAttr, ReplyCreate, ReplyDirectory, ReplyEmpty, ReplyStatfs, ReplyWrite, Session};
use self::fuse::{
FileAttr, FileType, Filesystem, ReplyAttr, ReplyCreate, ReplyData, ReplyDirectory, ReplyEmpty,
ReplyEntry, ReplyStatfs, ReplyWrite, Request, Session,
};
use self::time::Timespec;
const TTL: Timespec = Timespec { sec: 1, nsec: 0 }; // 1 second
const TTL: Timespec = Timespec { sec: 1, nsec: 0 }; // 1 second
const NULL_TIME: Timespec = Timespec { sec: 0, nsec: 0 };
pub fn mount<D, P, T, F>(filesystem: filesystem::FileSystem<D>, mountpoint: P, mut callback: F)
-> io::Result<T> where
D: Disk,
P: AsRef<Path>,
F: FnMut(&Path) -> T
pub fn mount<D, P, T, F>(
filesystem: filesystem::FileSystem<D>,
mountpoint: P,
mut callback: F,
) -> io::Result<T>
where
D: Disk,
P: AsRef<Path>,
F: FnMut(&Path) -> T,
{
let mountpoint = mountpoint.as_ref();
@@ -32,21 +39,16 @@ pub fn mount<D, P, T, F>(filesystem: filesystem::FileSystem<D>, mountpoint: P, m
// while building the Redox OS kernel. This means that we need to write on
// a filesystem that belongs to `root`, which in turn means that we need to
// be `root`, thus that we need to allow `root` to have access.
let defer_permissions = [
OsStr::new("-o"),
OsStr::new("defer_permissions"),
];
let defer_permissions = [OsStr::new("-o"), OsStr::new("defer_permissions")];
let mut session = Session::new(
Fuse {
fs: filesystem
},
Fuse { fs: filesystem },
mountpoint,
if cfg!(target_os = "macos") {
&defer_permissions
} else {
&[]
}
},
)?;
let res = callback(&mountpoint);
@@ -65,7 +67,7 @@ fn node_attr(node: &(u64, Node)) -> FileAttr {
ino: node.0,
size: node.1.extents[0].length,
// 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),
blocks: (node.1.extents[0].length + BLOCK_SIZE - 1) / BLOCK_SIZE * (BLOCK_SIZE / 512),
atime: NULL_TIME,
mtime: Timespec {
sec: node.1.mtime as i64,
@@ -97,7 +99,7 @@ impl<D: Disk> Filesystem for Fuse<D> {
match self.fs.find_node(name.to_str().unwrap(), parent_block) {
Ok(node) => {
reply.entry(&TTL, &node_attr(&node), 0);
},
}
Err(err) => {
reply.error(err.errno as i32);
}
@@ -108,28 +110,43 @@ impl<D: Disk> Filesystem for Fuse<D> {
match self.fs.node(block) {
Ok(node) => {
reply.attr(&TTL, &node_attr(&node));
},
}
Err(err) => {
reply.error(err.errno as i32);
}
}
}
fn setattr(&mut self, _req: &Request, block: u64, mode: Option<u32>,
uid: Option<u32>, gid: Option<u32>, size: Option<u64>,
atime: Option<Timespec>, mtime: Option<Timespec>, _fh: Option<u64>,
_crtime: Option<Timespec>, _chgtime: Option<Timespec>, _bkuptime: Option<Timespec>,
_flags: Option<u32>, reply: ReplyAttr) {
fn setattr(
&mut self,
_req: &Request,
block: u64,
mode: Option<u32>,
uid: Option<u32>,
gid: Option<u32>,
size: Option<u64>,
atime: Option<Timespec>,
mtime: Option<Timespec>,
_fh: Option<u64>,
_crtime: Option<Timespec>,
_chgtime: Option<Timespec>,
_bkuptime: Option<Timespec>,
_flags: Option<u32>,
reply: ReplyAttr,
) {
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;
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;
@@ -139,13 +156,15 @@ impl<D: Disk> Filesystem for Fuse<D> {
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;
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;
@@ -155,13 +174,15 @@ impl<D: Disk> Filesystem for Fuse<D> {
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;
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;
}
}
},
}
Err(err) => {
reply.error(err.errno as i32);
return;
@@ -194,7 +215,7 @@ impl<D: Disk> Filesystem for Fuse<D> {
reply.error(err.errno as i32);
return;
}
},
}
Err(err) => {
reply.error(err.errno as i32);
return;
@@ -205,31 +226,57 @@ impl<D: Disk> Filesystem for Fuse<D> {
match self.fs.node(block) {
Ok(node) => {
reply.attr(&TTL, &node_attr(&node));
},
}
Err(err) => {
reply.error(err.errno as i32);
}
}
}
fn read(&mut self, _req: &Request, block: u64, _fh: u64, offset: i64, size: u32, reply: ReplyData) {
fn read(
&mut self,
_req: &Request,
block: u64,
_fh: u64,
offset: i64,
size: u32,
reply: ReplyData,
) {
let mut data = vec![0; size as usize];
match self.fs.read_node(block, cmp::max(0, offset) as u64, &mut data) {
match self
.fs
.read_node(block, cmp::max(0, offset) as u64, &mut data)
{
Ok(count) => {
reply.data(&data[..count]);
},
}
Err(err) => {
reply.error(err.errno as i32);
}
}
}
fn write(&mut self, _req: &Request, block: u64, _fh: u64, offset: i64, data: &[u8], _flags: u32, reply: ReplyWrite) {
fn write(
&mut self,
_req: &Request,
block: u64,
_fh: u64,
offset: i64,
data: &[u8],
_flags: u32,
reply: ReplyWrite,
) {
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.write_node(
block,
cmp::max(0, offset) as u64,
&data,
mtime.as_secs(),
mtime.subsec_nanos(),
) {
Ok(count) => {
reply.written(count as u32);
},
}
Err(err) => {
reply.error(err.errno as i32);
}
@@ -244,7 +291,14 @@ impl<D: Disk> Filesystem for Fuse<D> {
reply.ok();
}
fn readdir(&mut self, _req: &Request, parent_block: u64, _fh: u64, offset: i64, mut reply: ReplyDirectory) {
fn readdir(
&mut self,
_req: &Request,
parent_block: u64,
_fh: u64,
offset: i64,
mut reply: ReplyDirectory,
) {
let mut children = Vec::new();
match self.fs.child_nodes(&mut children, parent_block) {
Ok(()) => {
@@ -255,7 +309,12 @@ impl<D: Disk> Filesystem for Fuse<D> {
i = 0;
reply.add(parent_block - self.fs.header.0, i, FileType::Directory, ".");
i += 1;
reply.add(parent_block - self.fs.header.0, i, FileType::Directory, "..");
reply.add(
parent_block - self.fs.header.0,
i,
FileType::Directory,
"..",
);
i += 1;
} else {
i = offset + 1;
@@ -263,11 +322,16 @@ impl<D: Disk> Filesystem for Fuse<D> {
}
for child in children.iter().skip(skip) {
let full = reply.add(child.0 - self.fs.header.0, i, if child.1.is_dir() {
FileType::Directory
} else {
FileType::RegularFile
}, child.1.name().unwrap());
let full = reply.add(
child.0 - self.fs.header.0,
i,
if child.1.is_dir() {
FileType::Directory
} else {
FileType::RegularFile
},
child.1.name().unwrap(),
);
if full {
break;
@@ -276,33 +340,60 @@ impl<D: Disk> Filesystem for Fuse<D> {
i += 1;
}
reply.ok();
},
}
Err(err) => {
reply.error(err.errno as i32);
}
}
}
fn create(&mut self, _req: &Request, parent_block: u64, name: &OsStr, mode: u32, flags: u32, reply: ReplyCreate) {
fn create(
&mut self,
_req: &Request,
parent_block: u64,
name: &OsStr,
mode: u32,
flags: u32,
reply: ReplyCreate,
) {
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.create_node(
Node::MODE_FILE | (mode as u16 & Node::MODE_PERM),
name.to_str().unwrap(),
parent_block,
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);
},
}
Err(error) => {
reply.error(error.errno as i32);
}
}
}
fn mkdir(&mut self, _req: &Request, parent_block: u64, name: &OsStr, mode: u32, reply: ReplyEntry) {
fn mkdir(
&mut self,
_req: &Request,
parent_block: u64,
name: &OsStr,
mode: u32,
reply: ReplyEntry,
) {
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.create_node(
Node::MODE_DIR | (mode as u16 & Node::MODE_PERM),
name.to_str().unwrap(),
parent_block,
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);
},
}
Err(error) => {
reply.error(error.errno as i32);
}
@@ -310,10 +401,13 @@ impl<D: Disk> Filesystem for Fuse<D> {
}
fn rmdir(&mut self, _req: &Request, parent_block: u64, name: &OsStr, reply: ReplyEmpty) {
match self.fs.remove_node(Node::MODE_DIR, name.to_str().unwrap(), parent_block) {
match self
.fs
.remove_node(Node::MODE_DIR, name.to_str().unwrap(), parent_block)
{
Ok(()) => {
reply.ok();
},
}
Err(err) => {
reply.error(err.errno as i32);
}
@@ -321,10 +415,13 @@ impl<D: Disk> Filesystem for Fuse<D> {
}
fn unlink(&mut self, _req: &Request, parent_block: u64, name: &OsStr, reply: ReplyEmpty) {
match self.fs.remove_node(Node::MODE_FILE, name.to_str().unwrap(), parent_block) {
match self
.fs
.remove_node(Node::MODE_FILE, name.to_str().unwrap(), parent_block)
{
Ok(()) => {
reply.ok();
},
}
Err(err) => {
reply.error(err.errno as i32);
}
@@ -336,30 +433,49 @@ impl<D: Disk> Filesystem for Fuse<D> {
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;
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);
}
}
}
fn symlink(&mut self, _req: &Request, parent_block: u64, name: &OsStr, link: &Path, reply: ReplyEntry) {
fn symlink(
&mut self,
_req: &Request,
parent_block: u64,
name: &OsStr,
link: &Path,
reply: ReplyEntry,
) {
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.create_node(
Node::MODE_SYMLINK | 0o777,
name.to_str().unwrap(),
parent_block,
ctime.as_secs(),
ctime.subsec_nanos(),
) {
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()) {
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);
}
}
},
}
Err(error) => {
reply.error(error.errno as i32);
}
@@ -371,7 +487,7 @@ impl<D: Disk> Filesystem for Fuse<D> {
match self.fs.read_node(ino, 0, &mut data) {
Ok(count) => {
reply.data(&data[..count]);
},
}
Err(err) => {
reply.error(err.errno as i32);
}
+13 -11
View File
@@ -1,23 +1,23 @@
use syscall::{Packet, Scheme};
use std::fs::File;
use std::io::{self, Read, Write};
use std::path::Path;
use std::sync::atomic::Ordering;
use syscall::{Packet, Scheme};
use IS_UMT;
use disk::Disk;
use filesystem::FileSystem;
use IS_UMT;
use self::scheme::FileScheme;
pub mod resource;
pub mod scheme;
pub fn mount<D, P, T, F>(filesystem: FileSystem<D>, mountpoint: P, mut callback: F)
-> io::Result<T> where
D: Disk,
P: AsRef<Path>,
F: FnMut(&Path) -> T
pub fn mount<D, P, T, F>(filesystem: FileSystem<D>, mountpoint: P, mut callback: F) -> io::Result<T>
where
D: Disk,
P: AsRef<Path>,
F: FnMut(&Path) -> T,
{
let mountpoint = mountpoint.as_ref();
let socket_path = format!(":{}", mountpoint.display());
@@ -36,10 +36,12 @@ pub fn mount<D, P, T, F>(filesystem: FileSystem<D>, mountpoint: P, mut callback:
match socket.read(&mut packet) {
Ok(0) => break Ok(res),
Ok(_ok) => (),
Err(err) => if err.kind() == io::ErrorKind::Interrupted {
continue;
} else {
break Err(err);
Err(err) => {
if err.kind() == io::ErrorKind::Interrupted {
continue;
} else {
break Err(err);
}
}
}
+43 -19
View File
@@ -1,11 +1,14 @@
use std::cmp::{min, max};
use std::cmp::{max, min};
use std::collections::BTreeMap;
use std::slice;
use std::time::{SystemTime, UNIX_EPOCH};
use syscall::data::{Map, Stat, TimeSpec};
use syscall::error::{Error, Result, EBADF, EINVAL, EISDIR, ENOMEM, EPERM};
use syscall::flag::{O_ACCMODE, O_APPEND, O_RDONLY, O_WRONLY, O_RDWR, F_GETFL, F_SETFL, MODE_PERM, PROT_READ, PROT_WRITE, SEEK_SET, SEEK_CUR, SEEK_END};
use syscall::flag::{
F_GETFL, F_SETFL, MODE_PERM, O_ACCMODE, O_APPEND, O_RDONLY, O_RDWR, O_WRONLY, PROT_READ,
PROT_WRITE, SEEK_CUR, SEEK_END, SEEK_SET,
};
use disk::Disk;
use filesystem::FileSystem;
@@ -60,7 +63,7 @@ impl<D: Disk> Resource<D> for DirResource {
block: self.block,
data: self.data.clone(),
seek: self.seek,
uid: self.uid
uid: self.uid,
}))
}
@@ -87,9 +90,15 @@ impl<D: Disk> Resource<D> for DirResource {
let data = self.data.as_ref().ok_or(Error::new(EBADF))?;
self.seek = match whence {
SEEK_SET => max(0, min(data.len() as isize, offset as isize)) as usize,
SEEK_CUR => max(0, min(data.len() as isize, self.seek as isize + offset as isize)) as usize,
SEEK_END => max(0, min(data.len() as isize, data.len() as isize + offset as isize)) as usize,
_ => return Err(Error::new(EINVAL))
SEEK_CUR => max(
0,
min(data.len() as isize, self.seek as isize + offset as isize),
) as usize,
SEEK_END => max(
0,
min(data.len() as isize, data.len() as isize + offset as isize),
) as usize,
_ => return Err(Error::new(EINVAL)),
};
Ok(self.seek)
@@ -106,7 +115,7 @@ impl<D: Disk> Resource<D> for DirResource {
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);
node.1.mode = (node.1.mode & !MODE_PERM) | (mode & MODE_PERM);
fs.write_at(node.0, &node.1)?;
@@ -235,7 +244,13 @@ impl Fmap {
pub fn sync<D: Disk>(&mut self, fs: &mut FileSystem<D>) -> Result<()> {
if self.flags & PROT_WRITE == PROT_WRITE {
let mtime = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
fs.write_node(self.block, self.offset as u64, &self.data, mtime.as_secs(), mtime.subsec_nanos())?;
fs.write_node(
self.block,
self.offset as u64,
&self.data,
mtime.as_secs(),
mtime.subsec_nanos(),
)?;
}
Ok(())
}
@@ -311,7 +326,13 @@ impl<D: Disk> Resource<D> for FileResource {
self.seek = fs.node_len(self.block)?;
}
let mtime = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
let count = fs.write_node(self.block, self.seek, buf, mtime.as_secs(), mtime.subsec_nanos())?;
let count = fs.write_node(
self.block,
self.seek,
buf,
mtime.as_secs(),
mtime.subsec_nanos(),
)?;
self.seek += count as u64;
Ok(count)
} else {
@@ -326,7 +347,7 @@ impl<D: Disk> Resource<D> for FileResource {
SEEK_SET => max(0, offset as i64) as u64,
SEEK_CUR => max(0, self.seek as i64 + offset as i64) as u64,
SEEK_END => max(0, size as i64 + offset as i64) as u64,
_ => return Err(Error::new(EINVAL))
_ => return Err(Error::new(EINVAL)),
};
Ok(self.seek as usize)
@@ -334,10 +355,10 @@ impl<D: Disk> Resource<D> for FileResource {
fn fmap(&mut self, map: &Map, fs: &mut FileSystem<D>) -> Result<usize> {
let accmode = self.flags & O_ACCMODE;
if map.flags & PROT_READ > 0 && ! (accmode == O_RDWR || accmode == O_RDONLY) {
if map.flags & PROT_READ > 0 && !(accmode == O_RDWR || accmode == O_RDONLY) {
return Err(Error::new(EBADF));
}
if map.flags & PROT_WRITE > 0 && ! (accmode == O_RDWR || accmode == O_WRONLY) {
if map.flags & PROT_WRITE > 0 && !(accmode == O_RDWR || accmode == O_WRONLY) {
return Err(Error::new(EBADF));
}
//TODO: PROT_EXEC?
@@ -362,7 +383,7 @@ impl<D: Disk> Resource<D> for FileResource {
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);
node.1.mode = (node.1.mode & !MODE_PERM) | (mode & MODE_PERM);
fs.write_at(node.0, &node.1)?;
@@ -396,10 +417,10 @@ impl<D: Disk> Resource<D> for FileResource {
match cmd {
F_GETFL => Ok(self.flags),
F_SETFL => {
self.flags = (self.flags & O_ACCMODE) | (arg & ! O_ACCMODE);
self.flags = (self.flags & O_ACCMODE) | (arg & !O_ACCMODE);
Ok(0)
},
_ => Err(Error::new(EINVAL))
}
_ => Err(Error::new(EINVAL)),
}
}
@@ -460,7 +481,6 @@ impl<D: Disk> Resource<D> for FileResource {
if node.1.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;
@@ -477,8 +497,12 @@ impl<D: Disk> Resource<D> for FileResource {
impl Drop for FileResource {
fn drop(&mut self) {
if ! self.fmaps.is_empty() {
eprintln!("redoxfs: file {} still has {} fmaps!", self.path, self.fmaps.len());
if !self.fmaps.is_empty() {
eprintln!(
"redoxfs: file {} still has {} fmaps!",
self.path,
self.fmaps.len()
);
}
}
}
+177 -130
View File
@@ -5,16 +5,22 @@ use std::sync::atomic::{AtomicUsize, Ordering};
use std::time::{SystemTime, UNIX_EPOCH};
use syscall::data::{Map, Stat, StatVfs, TimeSpec};
use syscall::error::{Error, Result, EACCES, EEXIST, EISDIR, ENOTDIR, ENOTEMPTY, EPERM, ENOENT, EBADF, ELOOP, EINVAL, EXDEV};
use syscall::flag::{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::error::{
Error, Result, EACCES, EBADF, EEXIST, EINVAL, EISDIR, ELOOP, ENOENT, ENOTDIR, ENOTEMPTY, EPERM,
EXDEV,
};
use syscall::flag::{
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 BLOCK_SIZE;
use disk::Disk;
use filesystem::FileSystem;
use node::Node;
use BLOCK_SIZE;
use super::resource::{Resource, DirResource, FileResource};
use super::resource::{DirResource, FileResource, Resource};
pub struct FileScheme<D: Disk> {
name: String,
@@ -35,14 +41,28 @@ impl<D: Disk> FileScheme<D> {
}
}
fn resolve_symlink(&self, fs: &mut FileSystem<D>, uid: u32, gid: u32, url: &[u8], node: (u64, Node), nodes: &mut Vec<(u64, Node)>) -> Result<Vec<u8>> {
fn resolve_symlink(
&self,
fs: &mut FileSystem<D>,
uid: u32,
gid: u32,
url: &[u8],
node: (u64, Node),
nodes: &mut Vec<(u64, Node)>,
) -> Result<Vec<u8>> {
let mut node = node;
for _ in 0..32 { // XXX What should the limit be?
for _ in 0..32 {
// XXX What should the limit be?
let mut buf = [0; 4096];
let count = fs.read_node(node.0, 0, &mut buf)?;
let scheme = format!("{}:", &self.name);
let canon = canonicalize(&format!("{}{}", scheme, str::from_utf8(url).unwrap()).as_bytes(), &buf[0..count]);
let path = str::from_utf8(&canon[scheme.len()..]).unwrap_or("").trim_matches('/');
let canon = canonicalize(
&format!("{}{}", scheme, str::from_utf8(url).unwrap()).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() {
@@ -61,8 +81,15 @@ impl<D: Disk> FileScheme<D> {
Err(Error::new(ELOOP))
}
fn path_nodes(&self, fs: &mut FileSystem<D>, path: &str, uid: u32, gid: u32, nodes: &mut Vec<(u64, Node)>) -> Result<Option<(u64, Node)>> {
let mut parts = path.split('/').filter(|part| ! part.is_empty());
fn path_nodes(
&self,
fs: &mut FileSystem<D>,
path: &str,
uid: u32,
gid: u32,
nodes: &mut Vec<(u64, Node)>,
) -> Result<Option<(u64, Node)>> {
let mut parts = path.split('/').filter(|part| !part.is_empty());
let mut part_opt = None;
let mut block = fs.header.1.root;
loop {
@@ -74,7 +101,7 @@ impl<D: Disk> FileScheme<D> {
part_opt = parts.next();
if part_opt.is_some() {
let node = node_res?;
if ! node.1.permission(uid, gid, Node::MODE_EXEC) {
if !node.1.permission(uid, gid, Node::MODE_EXEC) {
return Err(Error::new(EACCES));
}
if node.1.is_symlink() {
@@ -87,7 +114,7 @@ impl<D: Disk> FileScheme<D> {
}
self.resolve_symlink(fs, uid, gid, &url, node, nodes)?;
block = nodes.last().unwrap().0;
} else if ! node.1.is_dir() {
} else if !node.1.is_dir() {
return Err(Error::new(ENOTDIR));
} else {
block = node.0;
@@ -98,8 +125,8 @@ impl<D: Disk> FileScheme<D> {
Ok(node) => return Ok(Some(node)),
Err(err) => match err.errno {
ENOENT => return Ok(None),
_ => return Err(err)
}
_ => return Err(err),
},
}
}
}
@@ -118,7 +145,7 @@ pub fn canonicalize(current: &[u8], path: &[u8]) -> Vec<u8> {
let mut canon = if !path.starts_with(b"/") {
let mut c = cwd.to_vec();
if ! c.ends_with(b"/") {
if !c.ends_with(b"/") {
c.push(b'/');
}
c
@@ -134,7 +161,8 @@ pub fn canonicalize(current: &[u8], path: &[u8]) -> Vec<u8> {
// NOTE: assumes the scheme does not include anything like "../" or "./"
let mut result = {
let parts = canon.split(|&c| c == b'/')
let parts = canon
.split(|&c| c == b'/')
.filter(|&part| part != b".")
.rev()
.scan(0, |nskip, part| {
@@ -154,22 +182,20 @@ pub fn canonicalize(current: &[u8], path: &[u8]) -> Vec<u8> {
})
.filter_map(|x| x)
.collect::<Vec<_>>();
parts
.iter()
.rev()
.fold(Vec::new(), |mut vec, &part| {
vec.extend_from_slice(part);
vec.push(b'/');
vec
})
parts.iter().rev().fold(Vec::new(), |mut vec, &part| {
vec.extend_from_slice(part);
vec.push(b'/');
vec
})
};
result.pop(); // remove extra '/'
// replace with the root of the scheme if it's empty
if result.len() == 0 {
let pos = canon.iter()
.position(|&b| b == b':')
.map_or(canon.len(), |p| p + 1);
let pos = canon
.iter()
.position(|&b| b == b':')
.map_or(canon.len(), |p| p + 1);
canon.truncate(pos);
canon
} else {
@@ -188,111 +214,129 @@ impl<D: Disk> Scheme for FileScheme<D> {
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) => if flags & (O_CREAT | O_EXCL) == O_CREAT | O_EXCL {
return Err(Error::new(EEXIST));
} else if node.1.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);
Some(node) => {
if flags & (O_CREAT | O_EXCL) == O_CREAT | O_EXCL {
return Err(Error::new(EEXIST));
} else if node.1.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);
return Err(Error::new(EACCES));
}
let mut children = Vec::new();
fs.child_nodes(&mut children, node.0)?;
let mut data = Vec::new();
for child in children.iter() {
if let Ok(name) = child.1.name() {
if !data.is_empty() {
data.push(b'\n');
}
data.extend_from_slice(&name.as_bytes());
}
}
Box::new(DirResource::new(path.to_string(), node.0, 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))
}
} else if node.1.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, node, &mut resolve_nodes)?;
drop(fs);
return self.open(&resolved, flags, uid, gid);
} else if !node.1.is_symlink() && flags & O_SYMLINK == O_SYMLINK {
return Err(Error::new(EINVAL));
} else {
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)
{
// println!("file not readable {:o}", node.1.mode);
return Err(Error::new(EACCES));
}
let mut children = Vec::new();
fs.child_nodes(&mut children, node.0)?;
let mut data = Vec::new();
for child in children.iter() {
if let Ok(name) = child.1.name() {
if ! data.is_empty() {
data.push(b'\n');
}
data.extend_from_slice(&name.as_bytes());
}
}
Box::new(DirResource::new(path.to_string(), node.0, 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))
}
} else if node.1.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, node, &mut resolve_nodes)?;
drop(fs);
return self.open(&resolved, flags, uid, gid);
} else if !node.1.is_symlink() && flags & O_SYMLINK == O_SYMLINK {
return Err(Error::new(EINVAL));
} else {
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) {
// println!("file not readable {:o}", node.1.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) {
// println!("file not writable {:o}", node.1.mode);
return Err(Error::new(EACCES));
}
if flags & O_TRUNC == O_TRUNC {
if ! node.1.permission(uid, gid, Node::MODE_WRITE) {
if (flags & O_ACCMODE == O_WRONLY || flags & O_ACCMODE == O_RDWR)
&& !node.1.permission(uid, gid, Node::MODE_WRITE)
{
// println!("file not writable {:o}", node.1.mode);
return Err(Error::new(EACCES));
}
fs.node_set_len(node.0, 0)?;
}
Box::new(FileResource::new(path.to_string(), node.0, flags, uid))
},
None => if flags & O_CREAT == O_CREAT {
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() {
if let Some(parent) = nodes.last() {
if ! parent.1.permission(uid, gid, Node::MODE_WRITE) {
// println!("dir not writable {:o}", parent.1.mode);
if flags & O_TRUNC == O_TRUNC {
if !node.1.permission(uid, gid, Node::MODE_WRITE) {
// println!("file not writable {:o}", node.1.mode);
return Err(Error::new(EACCES));
}
let dir = flags & O_DIRECTORY == O_DIRECTORY;
let mode_type = if dir {
Node::MODE_DIR
} else if flags & O_SYMLINK == O_SYMLINK {
Node::MODE_SYMLINK
} else {
Node::MODE_FILE
};
fs.node_set_len(node.0, 0)?;
}
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)?;
Box::new(FileResource::new(path.to_string(), node.0, flags, uid))
}
}
None => {
if flags & O_CREAT == O_CREAT {
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() {
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 dir {
Box::new(DirResource::new(path.to_string(), node.0, None, uid))
let dir = flags & O_DIRECTORY == O_DIRECTORY;
let mode_type = if dir {
Node::MODE_DIR
} else if flags & O_SYMLINK == O_SYMLINK {
Node::MODE_SYMLINK
} else {
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)?;
if dir {
Box::new(DirResource::new(path.to_string(), node.0, None, uid))
} else {
Box::new(FileResource::new(path.to_string(), node.0, flags, uid))
}
} else {
Box::new(FileResource::new(path.to_string(), node.0, flags, uid))
return Err(Error::new(EPERM));
}
} else {
return Err(Error::new(EPERM));
}
} else {
return Err(Error::new(EPERM));
return Err(Error::new(ENOENT));
}
} else {
return Err(Error::new(ENOENT));
}
};
@@ -312,7 +356,7 @@ impl<D: Disk> Scheme for FileScheme<D> {
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);
node.1.mode = (node.1.mode & !MODE_PERM) | (mode & MODE_PERM);
fs.write_at(node.0, &node.1)?;
Ok(0)
} else {
@@ -333,19 +377,20 @@ impl<D: Disk> Scheme for FileScheme<D> {
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) {
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) {
if !child.1.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).and(Ok(0))
fs.remove_node(Node::MODE_DIR, child_name, parent.0)
.and(Ok(0))
} else {
Err(Error::new(ENOENT))
}
@@ -370,12 +415,12 @@ impl<D: Disk> Scheme for FileScheme<D> {
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) {
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.is_dir() {
if child.1.uid != uid {
// println!("file not owned by current user {}", parent.1.uid);
return Err(Error::new(EACCES));
@@ -383,9 +428,11 @@ impl<D: Disk> Scheme for FileScheme<D> {
if let Ok(child_name) = child.1.name() {
if child.1.is_symlink() {
fs.remove_node(Node::MODE_SYMLINK, child_name, parent.0).and(Ok(0))
fs.remove_node(Node::MODE_SYMLINK, child_name, parent.0)
.and(Ok(0))
} else {
fs.remove_node(Node::MODE_FILE, child_name, parent.0).and(Ok(0))
fs.remove_node(Node::MODE_FILE, child_name, parent.0)
.and(Ok(0))
}
} else {
Err(Error::new(ENOENT))
@@ -406,7 +453,7 @@ impl<D: Disk> Scheme for FileScheme<D> {
fn dup(&self, old_id: usize, buf: &[u8]) -> Result<usize> {
// println!("Dup {}", old_id);
if ! buf.is_empty() {
if !buf.is_empty() {
return Err(Error::new(EINVAL));
}
@@ -530,7 +577,7 @@ impl<D: Disk> Scheme for FileScheme<D> {
let mut last_part = String::new();
for part in path.split('/') {
if ! part.is_empty() {
if !part.is_empty() {
last_part = part.to_string();
}
}
@@ -542,7 +589,7 @@ impl<D: Disk> Scheme for FileScheme<D> {
let mut orig = fs.node(file.block())?;
if ! orig.1.owner(uid) {
if !orig.1.owner(uid) {
// println!("orig not owned by caller {}", uid);
return Err(Error::new(EACCES));
}
@@ -551,19 +598,19 @@ impl<D: Disk> Scheme for FileScheme<D> {
let node_opt = self.path_nodes(&mut fs, path, uid, gid, &mut nodes)?;
if let Some(parent) = nodes.last() {
if ! parent.1.owner(uid) {
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) {
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() {
if !orig.1.is_dir() {
// println!("orig is file, new is dir");
return Err(Error::new(EACCES));
}
@@ -571,7 +618,7 @@ impl<D: Disk> Scheme for FileScheme<D> {
let mut children = Vec::new();
fs.child_nodes(&mut children, node.0)?;
if ! children.is_empty() {
if !children.is_empty() {
// println!("new dir not empty");
return Err(Error::new(ENOTEMPTY));
}
@@ -636,8 +683,8 @@ impl<D: Disk> Scheme for FileScheme<D> {
let free_size = fs.node_len(free)?;
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 = fs.header.1.size / (stat.f_bsize as u64);
stat.f_bfree = free_size / (stat.f_bsize as u64);
stat.f_bavail = stat.f_bfree;
Ok(0)