Format the codebase
This commit is contained in:
+27
-22
@@ -1,28 +1,29 @@
|
||||
use std::fs;
|
||||
use std::io;
|
||||
use std::path::Path;
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
use std::path::Path;
|
||||
|
||||
use crate::{BLOCK_SIZE, Disk, Extent, FileSystem, Node};
|
||||
use crate::{Disk, Extent, FileSystem, Node, BLOCK_SIZE};
|
||||
|
||||
fn syscall_err(err: syscall::Error) -> io::Error {
|
||||
io::Error::from_raw_os_error(err.errno)
|
||||
}
|
||||
|
||||
pub fn archive_at<D: Disk, P: AsRef<Path>>(fs: &mut FileSystem<D>, parent_path: P, parent_block: u64) -> io::Result<()> {
|
||||
pub fn archive_at<D: Disk, P: AsRef<Path>>(
|
||||
fs: &mut FileSystem<D>,
|
||||
parent_path: P,
|
||||
parent_block: u64,
|
||||
) -> io::Result<()> {
|
||||
for entry_res in fs::read_dir(parent_path)? {
|
||||
let entry = entry_res?;
|
||||
|
||||
let metadata = entry.metadata()?;
|
||||
let file_type = metadata.file_type();
|
||||
|
||||
let name = entry.file_name().into_string().map_err(|_|
|
||||
io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"filename is not valid UTF-8"
|
||||
)
|
||||
)?;
|
||||
let name = entry.file_name().into_string().map_err(|_| {
|
||||
io::Error::new(io::ErrorKind::InvalidData, "filename is not valid UTF-8")
|
||||
})?;
|
||||
|
||||
let mode_type = if file_type.is_dir() {
|
||||
Node::MODE_DIR
|
||||
@@ -33,18 +34,20 @@ pub fn archive_at<D: Disk, P: AsRef<Path>>(fs: &mut FileSystem<D>, parent_path:
|
||||
} else {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("Does not support parsing {:?}", file_type)
|
||||
format!("Does not support parsing {:?}", file_type),
|
||||
));
|
||||
};
|
||||
|
||||
let mode = mode_type | (metadata.mode() as u16 & Node::MODE_PERM);
|
||||
let mut node = fs.create_node(
|
||||
mode,
|
||||
&name,
|
||||
parent_block,
|
||||
metadata.ctime() as u64,
|
||||
metadata.ctime_nsec() as u32
|
||||
).map_err(syscall_err)?;
|
||||
let mut node = fs
|
||||
.create_node(
|
||||
mode,
|
||||
&name,
|
||||
parent_block,
|
||||
metadata.ctime() as u64,
|
||||
metadata.ctime_nsec() as u32,
|
||||
)
|
||||
.map_err(syscall_err)?;
|
||||
node.1.uid = metadata.uid();
|
||||
node.1.gid = metadata.gid();
|
||||
fs.write_at(node.0, &node.1).map_err(syscall_err)?;
|
||||
@@ -59,8 +62,9 @@ pub fn archive_at<D: Disk, P: AsRef<Path>>(fs: &mut FileSystem<D>, parent_path:
|
||||
0,
|
||||
&data,
|
||||
metadata.mtime() as u64,
|
||||
metadata.mtime_nsec() as u32
|
||||
).map_err(syscall_err)?;
|
||||
metadata.mtime_nsec() as u32,
|
||||
)
|
||||
.map_err(syscall_err)?;
|
||||
} else if file_type.is_symlink() {
|
||||
let destination = fs::read_link(path)?;
|
||||
let data = destination.as_os_str().as_bytes();
|
||||
@@ -69,12 +73,13 @@ pub fn archive_at<D: Disk, P: AsRef<Path>>(fs: &mut FileSystem<D>, parent_path:
|
||||
0,
|
||||
&data,
|
||||
metadata.mtime() as u64,
|
||||
metadata.mtime_nsec() as u32
|
||||
).map_err(syscall_err)?;
|
||||
metadata.mtime_nsec() as u32,
|
||||
)
|
||||
.map_err(syscall_err)?;
|
||||
} else {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("Does not support creating {:?}", file_type)
|
||||
format!("Does not support creating {:?}", file_type),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
+20
-8
@@ -2,11 +2,11 @@ extern crate redoxfs;
|
||||
extern crate syscall;
|
||||
extern crate uuid;
|
||||
|
||||
use std::{env, fs, process};
|
||||
use std::io::Read;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
use std::{env, fs, process};
|
||||
|
||||
use redoxfs::{DiskSparse, FileSystem, archive};
|
||||
use redoxfs::{archive, DiskSparse, FileSystem};
|
||||
use uuid::Uuid;
|
||||
|
||||
fn main() {
|
||||
@@ -44,12 +44,18 @@ fn main() {
|
||||
Ok(mut file) => match file.read_to_end(&mut bootloader) {
|
||||
Ok(_) => (),
|
||||
Err(err) => {
|
||||
println!("redoxfs-ar: failed to read bootloader {}: {}", bootloader_path, err);
|
||||
println!(
|
||||
"redoxfs-ar: failed to read bootloader {}: {}",
|
||||
bootloader_path, err
|
||||
);
|
||||
process::exit(1);
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
println!("redoxfs-ar: failed to open bootloader {}: {}", bootloader_path, err);
|
||||
println!(
|
||||
"redoxfs-ar: failed to open bootloader {}: {}",
|
||||
bootloader_path, err
|
||||
);
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
@@ -67,7 +73,10 @@ fn main() {
|
||||
};
|
||||
|
||||
if let Err(err) = fs.disk.file.set_len(size) {
|
||||
println!("redoxfs-ar: failed to truncate {} to {}: {}", disk_path, size, err);
|
||||
println!(
|
||||
"redoxfs-ar: failed to truncate {} to {}: {}",
|
||||
disk_path, size, err
|
||||
);
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
@@ -76,12 +85,15 @@ fn main() {
|
||||
"redoxfs-ar: created filesystem on {}, reserved {} blocks, size {} MB, uuid {}",
|
||||
disk_path,
|
||||
fs.block,
|
||||
fs.header.1.size/1000/1000,
|
||||
fs.header.1.size / 1000 / 1000,
|
||||
uuid.hyphenated()
|
||||
);
|
||||
},
|
||||
}
|
||||
Err(err) => {
|
||||
println!("redoxfs-ar: failed to create filesystem on {}: {}", disk_path, err);
|
||||
println!(
|
||||
"redoxfs-ar: failed to create filesystem on {}: {}",
|
||||
disk_path, err
|
||||
);
|
||||
process::exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
+25
-8
@@ -1,10 +1,10 @@
|
||||
extern crate redoxfs;
|
||||
extern crate uuid;
|
||||
|
||||
use std::{env, fs, process, time};
|
||||
use std::io::Read;
|
||||
use std::{env, fs, process, time};
|
||||
|
||||
use redoxfs::{FileSystem, DiskFile};
|
||||
use redoxfs::{DiskFile, FileSystem};
|
||||
use uuid::Uuid;
|
||||
|
||||
fn main() {
|
||||
@@ -34,25 +34,42 @@ fn main() {
|
||||
Ok(mut file) => match file.read_to_end(&mut bootloader) {
|
||||
Ok(_) => (),
|
||||
Err(err) => {
|
||||
println!("redoxfs-mkfs: failed to read bootloader {}: {}", bootloader_path, err);
|
||||
println!(
|
||||
"redoxfs-mkfs: failed to read bootloader {}: {}",
|
||||
bootloader_path, err
|
||||
);
|
||||
process::exit(1);
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
println!("redoxfs-mkfs: failed to open bootloader {}: {}", bootloader_path, err);
|
||||
println!(
|
||||
"redoxfs-mkfs: failed to open bootloader {}: {}",
|
||||
bootloader_path, err
|
||||
);
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let ctime = time::SystemTime::now().duration_since(time::UNIX_EPOCH).unwrap();
|
||||
let ctime = time::SystemTime::now()
|
||||
.duration_since(time::UNIX_EPOCH)
|
||||
.unwrap();
|
||||
match FileSystem::create_reserved(disk, &bootloader, ctime.as_secs(), ctime.subsec_nanos()) {
|
||||
Ok(filesystem) => {
|
||||
let uuid = Uuid::from_bytes(&filesystem.header.1.uuid).unwrap();
|
||||
println!("redoxfs-mkfs: created filesystem on {}, reserved {} blocks, size {} MB, uuid {}", disk_path, filesystem.block, filesystem.header.1.size/1000/1000, uuid.hyphenated());
|
||||
},
|
||||
println!(
|
||||
"redoxfs-mkfs: created filesystem on {}, reserved {} blocks, size {} MB, uuid {}",
|
||||
disk_path,
|
||||
filesystem.block,
|
||||
filesystem.header.1.size / 1000 / 1000,
|
||||
uuid.hyphenated()
|
||||
);
|
||||
}
|
||||
Err(err) => {
|
||||
println!("redoxfs-mkfs: failed to create filesystem on {}: {}", disk_path, err);
|
||||
println!(
|
||||
"redoxfs-mkfs: failed to create filesystem on {}: {}",
|
||||
disk_path, err
|
||||
);
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
+94
-63
@@ -15,7 +15,7 @@ use std::io::{Read, Write};
|
||||
use std::os::unix::io::{FromRawFd, RawFd};
|
||||
use std::process;
|
||||
|
||||
use redoxfs::{DiskCache, DiskFile, mount};
|
||||
use redoxfs::{mount, DiskCache, DiskFile};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[cfg(target_os = "redox")]
|
||||
@@ -33,7 +33,7 @@ fn setsig() {
|
||||
|
||||
let sig_action = SigAction {
|
||||
sa_handler: unmount_handler,
|
||||
sa_mask: [0,0],
|
||||
sa_mask: [0, 0],
|
||||
sa_flags: 0,
|
||||
};
|
||||
|
||||
@@ -94,17 +94,19 @@ fn disk_paths(paths: &mut Vec<String>) {
|
||||
|
||||
let mut schemes = vec![];
|
||||
match fs::read_dir(":") {
|
||||
Ok(entries) => for entry_res in entries {
|
||||
if let Ok(entry) = entry_res {
|
||||
if let Ok(path) = entry.path().into_os_string().into_string() {
|
||||
let scheme = path.trim_start_matches(':').trim_matches('/');
|
||||
if scheme.starts_with("disk") {
|
||||
println!("redoxfs: found scheme {}", scheme);
|
||||
schemes.push(format!("{}:", scheme));
|
||||
Ok(entries) => {
|
||||
for entry_res in entries {
|
||||
if let Ok(entry) = entry_res {
|
||||
if let Ok(path) = entry.path().into_os_string().into_string() {
|
||||
let scheme = path.trim_start_matches(':').trim_matches('/');
|
||||
if scheme.starts_with("disk") {
|
||||
println!("redoxfs: found scheme {}", scheme);
|
||||
schemes.push(format!("{}:", scheme));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
Err(err) => {
|
||||
println!("redoxfs: failed to list schemes: {}", err);
|
||||
}
|
||||
@@ -112,14 +114,16 @@ fn disk_paths(paths: &mut Vec<String>) {
|
||||
|
||||
for scheme in schemes {
|
||||
match fs::read_dir(&scheme) {
|
||||
Ok(entries) => for entry_res in entries {
|
||||
if let Ok(entry) = entry_res {
|
||||
if let Ok(path) = entry.path().into_os_string().into_string() {
|
||||
println!("redoxfs: found path {}", path);
|
||||
paths.push(path);
|
||||
Ok(entries) => {
|
||||
for entry_res in entries {
|
||||
if let Ok(entry) = entry_res {
|
||||
if let Ok(path) = entry.path().into_os_string().into_string() {
|
||||
println!("redoxfs: found path {}", path);
|
||||
paths.push(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
Err(err) => {
|
||||
println!("redoxfs: failed to list '{}': {}", scheme, err);
|
||||
}
|
||||
@@ -136,11 +140,11 @@ fn daemon(disk_id: &DiskId, mountpoint: &str, block_opt: Option<u64>, mut write:
|
||||
match *disk_id {
|
||||
DiskId::Path(ref path) => {
|
||||
paths.push(path.clone());
|
||||
},
|
||||
}
|
||||
DiskId::Uuid(ref uuid) => {
|
||||
disk_paths(&mut paths);
|
||||
uuid_opt = Some(uuid.clone());
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
for path in paths {
|
||||
@@ -148,15 +152,28 @@ fn daemon(disk_id: &DiskId, mountpoint: &str, block_opt: Option<u64>, mut write:
|
||||
match DiskFile::open(&path).map(|image| DiskCache::new(image)) {
|
||||
Ok(disk) => match redoxfs::FileSystem::open(disk, block_opt) {
|
||||
Ok(filesystem) => {
|
||||
println!("redoxfs: opened filesystem on {} with uuid {}", path,
|
||||
Uuid::from_bytes(&filesystem.header.1.uuid).unwrap().hyphenated());
|
||||
println!(
|
||||
"redoxfs: opened filesystem on {} with uuid {}",
|
||||
path,
|
||||
Uuid::from_bytes(&filesystem.header.1.uuid)
|
||||
.unwrap()
|
||||
.hyphenated()
|
||||
);
|
||||
|
||||
let matches = if let Some(uuid) = uuid_opt {
|
||||
if &filesystem.header.1.uuid == uuid.as_bytes() {
|
||||
println!("redoxfs: filesystem on {} matches uuid {}", path, uuid.hyphenated());
|
||||
println!(
|
||||
"redoxfs: filesystem on {} matches uuid {}",
|
||||
path,
|
||||
uuid.hyphenated()
|
||||
);
|
||||
true
|
||||
} else {
|
||||
println!("redoxfs: filesystem on {} does not match uuid {}", path, uuid.hyphenated());
|
||||
println!(
|
||||
"redoxfs: filesystem on {} does not match uuid {}",
|
||||
path,
|
||||
uuid.hyphenated()
|
||||
);
|
||||
false
|
||||
}
|
||||
} else {
|
||||
@@ -167,31 +184,38 @@ fn daemon(disk_id: &DiskId, mountpoint: &str, block_opt: Option<u64>, mut write:
|
||||
match mount(filesystem, &mountpoint, |mounted_path| {
|
||||
capability_mode();
|
||||
|
||||
println!("redoxfs: mounted filesystem on {} to {}", path, mounted_path.display());
|
||||
println!(
|
||||
"redoxfs: mounted filesystem on {} to {}",
|
||||
path,
|
||||
mounted_path.display()
|
||||
);
|
||||
let _ = write.write(&[0]);
|
||||
}) {
|
||||
Ok(()) => {
|
||||
process::exit(0);
|
||||
},
|
||||
}
|
||||
Err(err) => {
|
||||
println!("redoxfs: failed to mount {} to {}: {}", path, mountpoint, err);
|
||||
println!(
|
||||
"redoxfs: failed to mount {} to {}: {}",
|
||||
path, mountpoint, err
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(err) => println!("redoxfs: failed to open filesystem {}: {}", path, err)
|
||||
}
|
||||
Err(err) => println!("redoxfs: failed to open filesystem {}: {}", path, err),
|
||||
},
|
||||
Err(err) => println!("redoxfs: failed to open image {}: {}", path, err)
|
||||
Err(err) => println!("redoxfs: failed to open image {}: {}", path, err),
|
||||
}
|
||||
}
|
||||
|
||||
match *disk_id {
|
||||
DiskId::Path(ref path) => {
|
||||
println!("redoxfs: not able to mount path {}", path);
|
||||
},
|
||||
}
|
||||
DiskId::Uuid(ref uuid) => {
|
||||
println!("redoxfs: not able to mount uuid {}", uuid.hyphenated());
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
let _ = write.write(&[1]);
|
||||
@@ -202,11 +226,16 @@ fn print_uuid(path: &str) {
|
||||
match DiskFile::open(&path).map(|image| DiskCache::new(image)) {
|
||||
Ok(disk) => match redoxfs::FileSystem::open(disk, None) {
|
||||
Ok(filesystem) => {
|
||||
println!("{}", Uuid::from_bytes(&filesystem.header.1.uuid).unwrap().hyphenated());
|
||||
},
|
||||
Err(err) => println!("redoxfs: failed to open filesystem {}: {}", path, err)
|
||||
println!(
|
||||
"{}",
|
||||
Uuid::from_bytes(&filesystem.header.1.uuid)
|
||||
.unwrap()
|
||||
.hyphenated()
|
||||
);
|
||||
}
|
||||
Err(err) => println!("redoxfs: failed to open filesystem {}: {}", path, err),
|
||||
},
|
||||
Err(err) => println!("redoxfs: failed to open image {}: {}", path, err)
|
||||
Err(err) => println!("redoxfs: failed to open image {}: {}", path, err),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,39 +243,41 @@ fn main() {
|
||||
let mut args = env::args().skip(1);
|
||||
|
||||
let disk_id = match args.next() {
|
||||
Some(arg) => if arg == "--uuid" {
|
||||
let uuid = match args.next() {
|
||||
Some(arg) => match Uuid::parse_str(&arg) {
|
||||
Ok(uuid) => uuid,
|
||||
Err(err) => {
|
||||
println!("redoxfs: invalid uuid '{}': {}", arg, err);
|
||||
Some(arg) => {
|
||||
if arg == "--uuid" {
|
||||
let uuid = match args.next() {
|
||||
Some(arg) => match Uuid::parse_str(&arg) {
|
||||
Ok(uuid) => uuid,
|
||||
Err(err) => {
|
||||
println!("redoxfs: invalid uuid '{}': {}", arg, err);
|
||||
usage();
|
||||
process::exit(1);
|
||||
}
|
||||
},
|
||||
None => {
|
||||
println!("redoxfs: no uuid provided");
|
||||
usage();
|
||||
process::exit(1);
|
||||
}
|
||||
},
|
||||
None => {
|
||||
println!("redoxfs: no uuid provided");
|
||||
usage();
|
||||
process::exit(1);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
DiskId::Uuid(uuid)
|
||||
} else if arg == "--get-uuid" {
|
||||
match args.next() {
|
||||
Some(arg) => {
|
||||
print_uuid(&arg);
|
||||
process::exit(1);
|
||||
},
|
||||
None => {
|
||||
println!("redoxfs: no disk provided");
|
||||
usage();
|
||||
process::exit(1);
|
||||
},
|
||||
};
|
||||
} else {
|
||||
DiskId::Path(arg)
|
||||
},
|
||||
DiskId::Uuid(uuid)
|
||||
} else if arg == "--get-uuid" {
|
||||
match args.next() {
|
||||
Some(arg) => {
|
||||
print_uuid(&arg);
|
||||
process::exit(1);
|
||||
}
|
||||
None => {
|
||||
println!("redoxfs: no disk provided");
|
||||
usage();
|
||||
process::exit(1);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
DiskId::Path(arg)
|
||||
}
|
||||
}
|
||||
None => {
|
||||
println!("redoxfs: no disk provided");
|
||||
usage();
|
||||
|
||||
+9
-9
@@ -1,9 +1,9 @@
|
||||
use std::{cmp, ptr};
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
use std::{cmp, ptr};
|
||||
use syscall::error::Result;
|
||||
|
||||
use BLOCK_SIZE;
|
||||
use disk::Disk;
|
||||
use BLOCK_SIZE;
|
||||
|
||||
fn copy_memory(src: &[u8], dest: &mut [u8]) -> usize {
|
||||
let len = cmp::min(src.len(), dest.len());
|
||||
@@ -45,16 +45,16 @@ impl<T: Disk> Disk for DiskCache<T> {
|
||||
|
||||
let mut read = 0;
|
||||
let mut failed = false;
|
||||
for i in 0..(buffer.len() + BLOCK_SIZE as usize - 1)/(BLOCK_SIZE as usize) {
|
||||
for i in 0..(buffer.len() + BLOCK_SIZE as usize - 1) / (BLOCK_SIZE as usize) {
|
||||
let block_i = block + i as u64;
|
||||
|
||||
let buffer_i = i * BLOCK_SIZE as usize;
|
||||
let buffer_j = cmp::min(buffer_i + BLOCK_SIZE as usize, buffer.len());
|
||||
let buffer_slice = &mut buffer[buffer_i .. buffer_j];
|
||||
let buffer_slice = &mut buffer[buffer_i..buffer_j];
|
||||
|
||||
if let Some(cache_buf) = self.cache.get_mut(&block_i) {
|
||||
read += copy_memory(cache_buf, buffer_slice);
|
||||
}else{
|
||||
} else {
|
||||
failed = true;
|
||||
break;
|
||||
}
|
||||
@@ -64,12 +64,12 @@ impl<T: Disk> Disk for DiskCache<T> {
|
||||
self.inner.read_at(block, buffer)?;
|
||||
|
||||
read = 0;
|
||||
for i in 0..(buffer.len() + BLOCK_SIZE as usize - 1)/(BLOCK_SIZE as usize) {
|
||||
for i in 0..(buffer.len() + BLOCK_SIZE as usize - 1) / (BLOCK_SIZE as usize) {
|
||||
let block_i = block + i as u64;
|
||||
|
||||
let buffer_i = i * BLOCK_SIZE as usize;
|
||||
let buffer_j = cmp::min(buffer_i + BLOCK_SIZE as usize, buffer.len());
|
||||
let buffer_slice = &buffer[buffer_i .. buffer_j];
|
||||
let buffer_slice = &buffer[buffer_i..buffer_j];
|
||||
|
||||
let mut cache_buf = [0; BLOCK_SIZE as usize];
|
||||
read += copy_memory(buffer_slice, &mut cache_buf);
|
||||
@@ -87,12 +87,12 @@ impl<T: Disk> Disk for DiskCache<T> {
|
||||
self.inner.write_at(block, buffer)?;
|
||||
|
||||
let mut written = 0;
|
||||
for i in 0..(buffer.len() + BLOCK_SIZE as usize - 1)/(BLOCK_SIZE as usize) {
|
||||
for i in 0..(buffer.len() + BLOCK_SIZE as usize - 1) / (BLOCK_SIZE as usize) {
|
||||
let block_i = block + i as u64;
|
||||
|
||||
let buffer_i = i * BLOCK_SIZE as usize;
|
||||
let buffer_j = cmp::min(buffer_i + BLOCK_SIZE as usize, buffer.len());
|
||||
let buffer_slice = &buffer[buffer_i .. buffer_j];
|
||||
let buffer_slice = &buffer[buffer_i..buffer_j];
|
||||
|
||||
let mut cache_buf = [0; BLOCK_SIZE as usize];
|
||||
written += copy_memory(buffer_slice, &mut cache_buf);
|
||||
|
||||
+18
-16
@@ -1,39 +1,41 @@
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::{Read, Write, Seek, SeekFrom};
|
||||
use std::io::{Read, Seek, SeekFrom, Write};
|
||||
use std::path::Path;
|
||||
use syscall::error::{Error, Result, EIO};
|
||||
|
||||
use BLOCK_SIZE;
|
||||
use disk::Disk;
|
||||
use BLOCK_SIZE;
|
||||
|
||||
macro_rules! try_disk {
|
||||
($expr:expr) => (match $expr {
|
||||
Ok(val) => val,
|
||||
Err(err) => {
|
||||
eprintln!("Disk I/O Error: {}", err);
|
||||
return Err(Error::new(EIO));
|
||||
($expr:expr) => {
|
||||
match $expr {
|
||||
Ok(val) => val,
|
||||
Err(err) => {
|
||||
eprintln!("Disk I/O Error: {}", err);
|
||||
return Err(Error::new(EIO));
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
pub struct DiskFile {
|
||||
pub file: File
|
||||
pub file: File,
|
||||
}
|
||||
|
||||
impl DiskFile {
|
||||
pub fn open<P: AsRef<Path>>(path: P) -> Result<DiskFile> {
|
||||
let file = try_disk!(OpenOptions::new().read(true).write(true).open(path));
|
||||
Ok(DiskFile {
|
||||
file: file
|
||||
})
|
||||
Ok(DiskFile { file: file })
|
||||
}
|
||||
|
||||
pub fn create<P: AsRef<Path>>(path: P, size: u64) -> Result<DiskFile> {
|
||||
let file = try_disk!(OpenOptions::new().read(true).write(true).create(true).open(path));
|
||||
let file = try_disk!(OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.create(true)
|
||||
.open(path));
|
||||
try_disk!(file.set_len(size));
|
||||
Ok(DiskFile {
|
||||
file: file
|
||||
})
|
||||
Ok(DiskFile { file: file })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+16
-12
@@ -1,20 +1,22 @@
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::{Read, Write, Seek, SeekFrom};
|
||||
use std::io::{Read, Seek, SeekFrom, Write};
|
||||
use std::path::Path;
|
||||
use std::u64;
|
||||
use syscall::error::{Error, Result, EIO};
|
||||
|
||||
use BLOCK_SIZE;
|
||||
use disk::Disk;
|
||||
use BLOCK_SIZE;
|
||||
|
||||
macro_rules! try_disk {
|
||||
($expr:expr) => (match $expr {
|
||||
Ok(val) => val,
|
||||
Err(err) => {
|
||||
eprintln!("Disk I/O Error: {}", err);
|
||||
return Err(Error::new(EIO));
|
||||
($expr:expr) => {
|
||||
match $expr {
|
||||
Ok(val) => val,
|
||||
Err(err) => {
|
||||
eprintln!("Disk I/O Error: {}", err);
|
||||
return Err(Error::new(EIO));
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
pub struct DiskSparse {
|
||||
@@ -23,10 +25,12 @@ pub struct DiskSparse {
|
||||
|
||||
impl DiskSparse {
|
||||
pub fn create<P: AsRef<Path>>(path: P) -> Result<DiskSparse> {
|
||||
let file = try_disk!(OpenOptions::new().read(true).write(true).create(true).open(path));
|
||||
Ok(DiskSparse {
|
||||
file
|
||||
})
|
||||
let file = try_disk!(OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.create(true)
|
||||
.open(path));
|
||||
Ok(DiskSparse { file })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+15
-7
@@ -1,14 +1,14 @@
|
||||
use std::{fmt, mem, ops, slice};
|
||||
|
||||
use BLOCK_SIZE;
|
||||
use Extent;
|
||||
use BLOCK_SIZE;
|
||||
|
||||
/// An extra node
|
||||
#[repr(packed)]
|
||||
pub struct ExNode {
|
||||
pub prev: u64,
|
||||
pub next: u64,
|
||||
pub extents: [Extent; (BLOCK_SIZE as usize - 16)/16],
|
||||
pub extents: [Extent; (BLOCK_SIZE as usize - 16) / 16],
|
||||
}
|
||||
|
||||
impl ExNode {
|
||||
@@ -16,18 +16,24 @@ impl ExNode {
|
||||
ExNode {
|
||||
prev: 0,
|
||||
next: 0,
|
||||
extents: [Extent::default(); (BLOCK_SIZE as usize - 16)/16],
|
||||
extents: [Extent::default(); (BLOCK_SIZE as usize - 16) / 16],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn size(&self) -> u64 {
|
||||
self.extents.iter().fold(0, |size, extent| size + extent.length)
|
||||
self.extents
|
||||
.iter()
|
||||
.fold(0, |size, extent| size + extent.length)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ExNode {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let extents: Vec<&Extent> = self.extents.iter().filter(|extent| -> bool { extent.length > 0 }).collect();
|
||||
let extents: Vec<&Extent> = self
|
||||
.extents
|
||||
.iter()
|
||||
.filter(|extent| -> bool { extent.length > 0 })
|
||||
.collect();
|
||||
unsafe {
|
||||
f.debug_struct("ExNode")
|
||||
.field("prev", &self.prev)
|
||||
@@ -42,7 +48,8 @@ impl ops::Deref for ExNode {
|
||||
type Target = [u8];
|
||||
fn deref(&self) -> &[u8] {
|
||||
unsafe {
|
||||
slice::from_raw_parts(self as *const ExNode as *const u8, mem::size_of::<ExNode>()) as &[u8]
|
||||
slice::from_raw_parts(self as *const ExNode as *const u8, mem::size_of::<ExNode>())
|
||||
as &[u8]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,7 +57,8 @@ impl ops::Deref for ExNode {
|
||||
impl ops::DerefMut for ExNode {
|
||||
fn deref_mut(&mut self) -> &mut [u8] {
|
||||
unsafe {
|
||||
slice::from_raw_parts_mut(self as *mut ExNode as *mut u8, mem::size_of::<ExNode>()) as &mut [u8]
|
||||
slice::from_raw_parts_mut(self as *mut ExNode as *mut u8, mem::size_of::<ExNode>())
|
||||
as &mut [u8]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+10
-7
@@ -5,14 +5,17 @@ use BLOCK_SIZE;
|
||||
pub struct BlockIter {
|
||||
block: u64,
|
||||
length: u64,
|
||||
i: u64
|
||||
i: u64,
|
||||
}
|
||||
|
||||
impl Iterator<> for BlockIter {
|
||||
impl Iterator for BlockIter {
|
||||
type Item = (u64, u64);
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.i < (self.length + BLOCK_SIZE - 1)/BLOCK_SIZE {
|
||||
let ret = Some((self.block + self.i, min(BLOCK_SIZE, self.length - self.i * BLOCK_SIZE)));
|
||||
if self.i < (self.length + BLOCK_SIZE - 1) / BLOCK_SIZE {
|
||||
let ret = Some((
|
||||
self.block + self.i,
|
||||
min(BLOCK_SIZE, self.length - self.i * BLOCK_SIZE),
|
||||
));
|
||||
self.i += 1;
|
||||
ret
|
||||
} else {
|
||||
@@ -33,14 +36,14 @@ impl Extent {
|
||||
pub fn default() -> Extent {
|
||||
Extent {
|
||||
block: 0,
|
||||
length: 0
|
||||
length: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(block: u64, length: u64) -> Extent {
|
||||
Extent {
|
||||
block: block,
|
||||
length: length
|
||||
length: length,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +51,7 @@ impl Extent {
|
||||
BlockIter {
|
||||
block: self.block,
|
||||
length: self.length,
|
||||
i: 0
|
||||
i: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+86
-31
@@ -1,15 +1,15 @@
|
||||
use std::cmp::min;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
use syscall::error::{Result, Error, EEXIST, EISDIR, EINVAL, ENOENT, ENOSPC, ENOTDIR, ENOTEMPTY};
|
||||
use syscall::error::{Error, Result, EEXIST, EINVAL, EISDIR, ENOENT, ENOSPC, ENOTDIR, ENOTEMPTY};
|
||||
|
||||
use {BLOCK_SIZE, Disk, ExNode, Extent, Header, Node};
|
||||
use {Disk, ExNode, Extent, Header, Node, BLOCK_SIZE};
|
||||
|
||||
/// A file system
|
||||
pub struct FileSystem<D: Disk> {
|
||||
pub disk: D,
|
||||
pub block: u64,
|
||||
pub header: (u64, Header)
|
||||
pub header: (u64, Header),
|
||||
}
|
||||
|
||||
impl<D: Disk> FileSystem<D> {
|
||||
@@ -29,7 +29,7 @@ impl<D: Disk> FileSystem<D> {
|
||||
return Ok(FileSystem {
|
||||
disk: disk,
|
||||
block: block,
|
||||
header: header
|
||||
header: header,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -45,16 +45,24 @@ impl<D: Disk> FileSystem<D> {
|
||||
/// Create a file system on a disk, with reserved data at the beginning
|
||||
/// Reserved data will be zero padded up to the nearest block
|
||||
/// We need to pass ctime and ctime_nsec in order to initialize the unix timestamps
|
||||
pub fn create_reserved(mut disk: D, reserved: &[u8], ctime: u64, ctime_nsec: u32) -> Result<Self> {
|
||||
pub fn create_reserved(
|
||||
mut disk: D,
|
||||
reserved: &[u8],
|
||||
ctime: u64,
|
||||
ctime_nsec: u32,
|
||||
) -> Result<Self> {
|
||||
let size = disk.size()?;
|
||||
let block_offset = (reserved.len() as u64 + BLOCK_SIZE - 1)/BLOCK_SIZE;
|
||||
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)?);
|
||||
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));
|
||||
@@ -75,7 +83,7 @@ impl<D: Disk> FileSystem<D> {
|
||||
Ok(FileSystem {
|
||||
disk: disk,
|
||||
block: block_offset,
|
||||
header: header
|
||||
header: header,
|
||||
})
|
||||
} else {
|
||||
Err(Error::new(ENOSPC))
|
||||
@@ -97,7 +105,7 @@ impl<D: Disk> FileSystem<D> {
|
||||
let mut free = self.node(free_block)?;
|
||||
let mut block_option = None;
|
||||
for extent in free.1.extents.iter_mut() {
|
||||
if extent.length/BLOCK_SIZE >= length {
|
||||
if extent.length / BLOCK_SIZE >= length {
|
||||
block_option = Some(extent.block);
|
||||
extent.length -= length * BLOCK_SIZE;
|
||||
extent.block += length;
|
||||
@@ -129,7 +137,11 @@ impl<D: Disk> FileSystem<D> {
|
||||
Ok((block, node))
|
||||
}
|
||||
|
||||
pub fn child_nodes(&mut self, children: &mut Vec<(u64, Node)>, parent_block: u64) -> Result<()> {
|
||||
pub fn child_nodes(
|
||||
&mut self,
|
||||
children: &mut Vec<(u64, Node)>,
|
||||
parent_block: u64,
|
||||
) -> Result<()> {
|
||||
if parent_block == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
@@ -189,13 +201,15 @@ impl<D: Disk> FileSystem<D> {
|
||||
extent.block = block;
|
||||
extent.length = length;
|
||||
break;
|
||||
} else if length % BLOCK_SIZE == 0 && extent.block == block + length/BLOCK_SIZE {
|
||||
} else if length % BLOCK_SIZE == 0 && extent.block == block + length / BLOCK_SIZE {
|
||||
//At beginning
|
||||
inserted = true;
|
||||
extent.block = block;
|
||||
extent.length += length;
|
||||
break;
|
||||
} else if extent.length % BLOCK_SIZE == 0 && extent.block + extent.length/BLOCK_SIZE == block {
|
||||
} else if extent.length % BLOCK_SIZE == 0
|
||||
&& extent.block + extent.length / BLOCK_SIZE == block
|
||||
{
|
||||
//At end
|
||||
inserted = true;
|
||||
extent.length += length;
|
||||
@@ -222,7 +236,14 @@ impl<D: Disk> FileSystem<D> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_node(&mut self, mode: u16, name: &str, parent_block: u64, ctime: u64, ctime_nsec: u32) -> Result<(u64, Node)> {
|
||||
pub fn create_node(
|
||||
&mut self,
|
||||
mode: u16,
|
||||
name: &str,
|
||||
parent_block: u64,
|
||||
ctime: u64,
|
||||
ctime_nsec: u32,
|
||||
) -> Result<(u64, Node)> {
|
||||
if name.contains(':') {
|
||||
Err(Error::new(EINVAL))
|
||||
} else if self.find_node(name, parent_block).is_ok() {
|
||||
@@ -247,12 +268,16 @@ impl<D: Disk> FileSystem<D> {
|
||||
let mut replace_option = None;
|
||||
let mut parent = self.node(parent_block)?;
|
||||
for extent in parent.1.extents.iter_mut() {
|
||||
if block >= extent.block && block + length <= extent.block + extent.length/BLOCK_SIZE {
|
||||
if block >= extent.block && block + length <= extent.block + extent.length / BLOCK_SIZE
|
||||
{
|
||||
//Inside
|
||||
removed = true;
|
||||
|
||||
let left = Extent::new(extent.block, (block - extent.block) * BLOCK_SIZE);
|
||||
let right = Extent::new(block + length, ((extent.block + extent.length/BLOCK_SIZE) - (block + length)) * BLOCK_SIZE);
|
||||
let right = Extent::new(
|
||||
block + length,
|
||||
((extent.block + extent.length / BLOCK_SIZE) - (block + length)) * BLOCK_SIZE,
|
||||
);
|
||||
|
||||
if left.length > 0 {
|
||||
*extent = left;
|
||||
@@ -289,7 +314,7 @@ impl<D: Disk> FileSystem<D> {
|
||||
if node.1.is_dir() {
|
||||
let mut children = Vec::new();
|
||||
self.child_nodes(&mut children, node.0)?;
|
||||
if ! children.is_empty() {
|
||||
if !children.is_empty() {
|
||||
return Err(Error::new(ENOTEMPTY));
|
||||
}
|
||||
}
|
||||
@@ -322,7 +347,7 @@ impl<D: Disk> FileSystem<D> {
|
||||
break;
|
||||
} else {
|
||||
changed = true;
|
||||
let allocated = ((extent.length + BLOCK_SIZE - 1)/BLOCK_SIZE) * BLOCK_SIZE;
|
||||
let allocated = ((extent.length + BLOCK_SIZE - 1) / BLOCK_SIZE) * BLOCK_SIZE;
|
||||
if allocated >= length {
|
||||
extent.length = length;
|
||||
length = 0;
|
||||
@@ -342,7 +367,7 @@ impl<D: Disk> FileSystem<D> {
|
||||
if node.1.next > 0 {
|
||||
self.node_ensure_len(node.1.next, length)
|
||||
} else {
|
||||
let new_block = self.allocate((length + BLOCK_SIZE - 1)/BLOCK_SIZE)?;
|
||||
let new_block = self.allocate((length + BLOCK_SIZE - 1) / BLOCK_SIZE)?;
|
||||
self.insert_blocks(new_block, length, block)?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -362,8 +387,8 @@ impl<D: Disk> FileSystem<D> {
|
||||
let mut node = self.node(block)?;
|
||||
for extent in node.1.extents.iter_mut() {
|
||||
if extent.length > length {
|
||||
let start = (length + BLOCK_SIZE - 1)/BLOCK_SIZE;
|
||||
let end = (extent.length + BLOCK_SIZE - 1)/BLOCK_SIZE;
|
||||
let start = (length + BLOCK_SIZE - 1) / BLOCK_SIZE;
|
||||
let end = (extent.length + BLOCK_SIZE - 1) / BLOCK_SIZE;
|
||||
if end > start {
|
||||
self.deallocate(extent.block + start, (end - start) * BLOCK_SIZE)?;
|
||||
}
|
||||
@@ -386,7 +411,13 @@ impl<D: Disk> FileSystem<D> {
|
||||
}
|
||||
}
|
||||
|
||||
fn node_extents(&mut self, block: u64, mut offset: u64, mut len: usize, extents: &mut Vec<Extent>) -> Result<()> {
|
||||
fn node_extents(
|
||||
&mut self,
|
||||
block: u64,
|
||||
mut offset: u64,
|
||||
mut len: usize,
|
||||
extents: &mut Vec<Extent>,
|
||||
) -> Result<()> {
|
||||
if block == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
@@ -446,7 +477,10 @@ impl<D: Disk> FileSystem<D> {
|
||||
self.read_at(block, &mut sector)?;
|
||||
|
||||
let sector_size = min(sector.len() as u64, length) as usize;
|
||||
for (s_b, b) in sector[byte_offset..sector_size].iter().zip(buf[i..].iter_mut()) {
|
||||
for (s_b, b) in sector[byte_offset..sector_size]
|
||||
.iter()
|
||||
.zip(buf[i..].iter_mut())
|
||||
{
|
||||
*b = *s_b;
|
||||
i += 1;
|
||||
}
|
||||
@@ -457,13 +491,14 @@ impl<D: Disk> FileSystem<D> {
|
||||
byte_offset = 0;
|
||||
}
|
||||
|
||||
let length_aligned = ((min(length, (buf.len() - i) as u64)/BLOCK_SIZE) * BLOCK_SIZE) as usize;
|
||||
let length_aligned =
|
||||
((min(length, (buf.len() - i) as u64) / BLOCK_SIZE) * BLOCK_SIZE) as usize;
|
||||
|
||||
if length_aligned > 0 {
|
||||
let extent_buf = &mut buf[i..i + length_aligned];
|
||||
self.read_at(block, extent_buf)?;
|
||||
i += length_aligned;
|
||||
block += (length_aligned as u64)/BLOCK_SIZE;
|
||||
block += (length_aligned as u64) / BLOCK_SIZE;
|
||||
length -= length_aligned as u64;
|
||||
}
|
||||
|
||||
@@ -482,7 +517,10 @@ impl<D: Disk> FileSystem<D> {
|
||||
}
|
||||
|
||||
assert_eq!(length, 0);
|
||||
assert_eq!(block, extent.block + (extent.length + BLOCK_SIZE - 1)/BLOCK_SIZE);
|
||||
assert_eq!(
|
||||
block,
|
||||
extent.block + (extent.length + BLOCK_SIZE - 1) / BLOCK_SIZE
|
||||
);
|
||||
}
|
||||
|
||||
if i > 0 {
|
||||
@@ -502,11 +540,21 @@ impl<D: Disk> FileSystem<D> {
|
||||
Ok(i)
|
||||
}
|
||||
|
||||
pub fn write_node(&mut self, block: u64, offset: u64, buf: &[u8], mtime: u64, mtime_nsec: u32) -> Result<usize> {
|
||||
pub fn write_node(
|
||||
&mut self,
|
||||
block: u64,
|
||||
offset: u64,
|
||||
buf: &[u8],
|
||||
mtime: u64,
|
||||
mtime_nsec: u32,
|
||||
) -> Result<usize> {
|
||||
let block_offset = offset / BLOCK_SIZE;
|
||||
let mut byte_offset = (offset % BLOCK_SIZE) as usize;
|
||||
|
||||
self.node_ensure_len(block, block_offset as u64 * BLOCK_SIZE + (byte_offset + buf.len()) as u64)?;
|
||||
self.node_ensure_len(
|
||||
block,
|
||||
block_offset as u64 * BLOCK_SIZE + (byte_offset + buf.len()) as u64,
|
||||
)?;
|
||||
|
||||
let mut extents = Vec::new();
|
||||
self.node_extents(block, block_offset, byte_offset + buf.len(), &mut extents)?;
|
||||
@@ -521,7 +569,10 @@ impl<D: Disk> FileSystem<D> {
|
||||
self.read_at(block, &mut sector)?;
|
||||
|
||||
let sector_size = min(sector.len() as u64, length) as usize;
|
||||
for (s_b, b) in sector[byte_offset..sector_size].iter_mut().zip(buf[i..].iter()) {
|
||||
for (s_b, b) in sector[byte_offset..sector_size]
|
||||
.iter_mut()
|
||||
.zip(buf[i..].iter())
|
||||
{
|
||||
*s_b = *b;
|
||||
i += 1;
|
||||
}
|
||||
@@ -534,13 +585,14 @@ impl<D: Disk> FileSystem<D> {
|
||||
byte_offset = 0;
|
||||
}
|
||||
|
||||
let length_aligned = ((min(length, (buf.len() - i) as u64)/BLOCK_SIZE) * BLOCK_SIZE) as usize;
|
||||
let length_aligned =
|
||||
((min(length, (buf.len() - i) as u64) / BLOCK_SIZE) * BLOCK_SIZE) as usize;
|
||||
|
||||
if length_aligned > 0 {
|
||||
let extent_buf = &buf[i..i + length_aligned];
|
||||
self.write_at(block, extent_buf)?;
|
||||
i += length_aligned;
|
||||
block += (length_aligned as u64)/BLOCK_SIZE;
|
||||
block += (length_aligned as u64) / BLOCK_SIZE;
|
||||
length -= length_aligned as u64;
|
||||
}
|
||||
|
||||
@@ -561,7 +613,10 @@ impl<D: Disk> FileSystem<D> {
|
||||
}
|
||||
|
||||
assert_eq!(length, 0);
|
||||
assert_eq!(block, extent.block + (extent.length + BLOCK_SIZE - 1)/BLOCK_SIZE);
|
||||
assert_eq!(
|
||||
block,
|
||||
extent.block + (extent.length + BLOCK_SIZE - 1) / BLOCK_SIZE
|
||||
);
|
||||
}
|
||||
|
||||
if i > 0 {
|
||||
|
||||
+8
-6
@@ -1,5 +1,5 @@
|
||||
use std::{fmt, mem, slice};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::{fmt, mem, slice};
|
||||
|
||||
use uuid::Uuid;
|
||||
|
||||
@@ -22,7 +22,7 @@ pub struct Header {
|
||||
/// Block of free space node
|
||||
pub free: u64,
|
||||
/// Padding
|
||||
pub padding: [u8; BLOCK_SIZE as usize - 56]
|
||||
pub padding: [u8; BLOCK_SIZE as usize - 56],
|
||||
}
|
||||
|
||||
impl Header {
|
||||
@@ -34,7 +34,7 @@ impl Header {
|
||||
size: 0,
|
||||
root: 0,
|
||||
free: 0,
|
||||
padding: [0; BLOCK_SIZE as usize - 56]
|
||||
padding: [0; BLOCK_SIZE as usize - 56],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ impl Header {
|
||||
size: size,
|
||||
root: root,
|
||||
free: free,
|
||||
padding: [0; BLOCK_SIZE as usize - 56]
|
||||
padding: [0; BLOCK_SIZE as usize - 56],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +75,8 @@ impl Deref for Header {
|
||||
type Target = [u8];
|
||||
fn deref(&self) -> &[u8] {
|
||||
unsafe {
|
||||
slice::from_raw_parts(self as *const Header as *const u8, mem::size_of::<Header>()) as &[u8]
|
||||
slice::from_raw_parts(self as *const Header as *const u8, mem::size_of::<Header>())
|
||||
as &[u8]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -83,7 +84,8 @@ impl Deref for Header {
|
||||
impl DerefMut for Header {
|
||||
fn deref_mut(&mut self) -> &mut [u8] {
|
||||
unsafe {
|
||||
slice::from_raw_parts_mut(self as *mut Header as *mut u8, mem::size_of::<Header>()) as &mut [u8]
|
||||
slice::from_raw_parts_mut(self as *mut Header as *mut u8, mem::size_of::<Header>())
|
||||
as &mut [u8]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+194
-78
@@ -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
@@ -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
@@ -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
@@ -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)
|
||||
|
||||
+24
-10
@@ -1,8 +1,8 @@
|
||||
use std::{fmt, mem, ops, slice, str};
|
||||
|
||||
use BLOCK_SIZE;
|
||||
use super::Extent;
|
||||
use syscall;
|
||||
use BLOCK_SIZE;
|
||||
|
||||
/// A file/folder node
|
||||
#[repr(packed)]
|
||||
@@ -19,7 +19,7 @@ pub struct Node {
|
||||
pub name: [u8; 226],
|
||||
pub parent: u64,
|
||||
pub next: u64,
|
||||
pub extents: [Extent; (BLOCK_SIZE as usize - 288)/16],
|
||||
pub extents: [Extent; (BLOCK_SIZE as usize - 288) / 16],
|
||||
}
|
||||
|
||||
impl Node {
|
||||
@@ -47,11 +47,17 @@ impl Node {
|
||||
name: [0; 226],
|
||||
parent: 0,
|
||||
next: 0,
|
||||
extents: [Extent::default(); (BLOCK_SIZE as usize - 288)/16],
|
||||
extents: [Extent::default(); (BLOCK_SIZE as usize - 288) / 16],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(mode: u16, name: &str, parent: u64, ctime: u64, ctime_nsec: u32) -> syscall::Result<Node> {
|
||||
pub fn new(
|
||||
mode: u16,
|
||||
name: &str,
|
||||
parent: u64,
|
||||
ctime: u64,
|
||||
ctime_nsec: u32,
|
||||
) -> syscall::Result<Node> {
|
||||
let mut bytes = [0; 226];
|
||||
if name.len() > bytes.len() {
|
||||
return Err(syscall::Error::new(syscall::ENAMETOOLONG));
|
||||
@@ -73,7 +79,7 @@ impl Node {
|
||||
name: bytes,
|
||||
parent: parent,
|
||||
next: 0,
|
||||
extents: [Extent::default(); (BLOCK_SIZE as usize - 288)/16],
|
||||
extents: [Extent::default(); (BLOCK_SIZE as usize - 288) / 16],
|
||||
})
|
||||
}
|
||||
|
||||
@@ -129,7 +135,7 @@ impl Node {
|
||||
// If self.mode is 101100110, >> 6 would be 000000101
|
||||
// 0o7 is octal for 111, or, when expanded to 9 digits is 000000111
|
||||
perm |= (self.mode >> 6) & 0o7;
|
||||
// Since we erased the GID and OTHER bits when >>6'ing, |= will keep those bits in place.
|
||||
// Since we erased the GID and OTHER bits when >>6'ing, |= will keep those bits in place.
|
||||
}
|
||||
if self.gid == gid || gid == 0 {
|
||||
perm |= (self.mode >> 3) & 0o7;
|
||||
@@ -142,13 +148,19 @@ impl Node {
|
||||
}
|
||||
|
||||
pub fn size(&self) -> u64 {
|
||||
self.extents.iter().fold(0, |size, extent| size + extent.length)
|
||||
self.extents
|
||||
.iter()
|
||||
.fold(0, |size, extent| size + extent.length)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Node {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let extents: Vec<&Extent> = self.extents.iter().filter(|extent| -> bool { extent.length > 0 }).collect();
|
||||
let extents: Vec<&Extent> = self
|
||||
.extents
|
||||
.iter()
|
||||
.filter(|extent| -> bool { extent.length > 0 })
|
||||
.collect();
|
||||
unsafe {
|
||||
f.debug_struct("Node")
|
||||
.field("mode", &self.mode)
|
||||
@@ -170,7 +182,8 @@ impl ops::Deref for Node {
|
||||
type Target = [u8];
|
||||
fn deref(&self) -> &[u8] {
|
||||
unsafe {
|
||||
slice::from_raw_parts(self as *const Node as *const u8, mem::size_of::<Node>()) as &[u8]
|
||||
slice::from_raw_parts(self as *const Node as *const u8, mem::size_of::<Node>())
|
||||
as &[u8]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -178,7 +191,8 @@ impl ops::Deref for Node {
|
||||
impl ops::DerefMut for Node {
|
||||
fn deref_mut(&mut self) -> &mut [u8] {
|
||||
unsafe {
|
||||
slice::from_raw_parts_mut(self as *mut Node as *mut u8, mem::size_of::<Node>()) as &mut [u8]
|
||||
slice::from_raw_parts_mut(self as *mut Node as *mut u8, mem::size_of::<Node>())
|
||||
as &mut [u8]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+25
-26
@@ -1,14 +1,14 @@
|
||||
use std::{fs, sync, thread, time};
|
||||
use std::ops::DerefMut;
|
||||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
use std::{fs, sync, thread, time};
|
||||
|
||||
use crate::{DiskSparse, FileSystem};
|
||||
|
||||
fn with_redoxfs<T, F>(callback: F)
|
||||
-> T where
|
||||
T: Send + Sync + 'static,
|
||||
F: FnMut(&Path) -> T + Send + Sync + 'static
|
||||
fn with_redoxfs<T, F>(callback: F) -> T
|
||||
where
|
||||
T: Send + Sync + 'static,
|
||||
F: FnMut(&Path) -> T + Send + Sync + 'static,
|
||||
{
|
||||
let disk_path = "image.bin";
|
||||
let mount_path = "image";
|
||||
@@ -17,13 +17,14 @@ fn with_redoxfs<T, F>(callback: F)
|
||||
let disk = DiskSparse::create(dbg!(disk_path)).unwrap();
|
||||
|
||||
if cfg!(not(target_os = "redox")) {
|
||||
if ! Path::new(mount_path).exists() {
|
||||
if !Path::new(mount_path).exists() {
|
||||
dbg!(fs::create_dir(dbg!(mount_path))).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
let ctime = dbg!(time::SystemTime::now().duration_since(time::UNIX_EPOCH)).unwrap();
|
||||
let fs = FileSystem::create_reserved(disk, &[], ctime.as_secs(), ctime.subsec_nanos()).unwrap();
|
||||
let fs =
|
||||
FileSystem::create_reserved(disk, &[], ctime.as_secs(), ctime.subsec_nanos()).unwrap();
|
||||
|
||||
let callback_mutex = sync::Arc::new(sync::Mutex::new(callback));
|
||||
let join_handle = crate::mount(fs, dbg!(mount_path), move |real_path| {
|
||||
@@ -45,20 +46,19 @@ fn with_redoxfs<T, F>(callback: F)
|
||||
.arg(mount_path)
|
||||
.status()
|
||||
} else {
|
||||
Command::new("umount")
|
||||
.arg(mount_path)
|
||||
.status()
|
||||
Command::new("umount").arg(mount_path).status()
|
||||
};
|
||||
|
||||
let status = dbg!(status_res).unwrap();
|
||||
if ! status.success() {
|
||||
if !status.success() {
|
||||
panic!("umount failed");
|
||||
}
|
||||
}
|
||||
|
||||
res
|
||||
})
|
||||
}).unwrap();
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
join_handle.join().unwrap()
|
||||
};
|
||||
@@ -92,23 +92,24 @@ fn mmap() {
|
||||
let path = dbg!(path.join("test"));
|
||||
|
||||
let mmap_inner = |write: bool| {
|
||||
let fd = dbg!(
|
||||
syscall::open(
|
||||
path.as_os_str().as_bytes(),
|
||||
syscall::O_CREAT | syscall::O_RDWR | syscall::O_CLOEXEC
|
||||
)
|
||||
).unwrap();
|
||||
let fd = dbg!(syscall::open(
|
||||
path.as_os_str().as_bytes(),
|
||||
syscall::O_CREAT | syscall::O_RDWR | syscall::O_CLOEXEC
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
let map = unsafe {
|
||||
slice::from_raw_parts_mut(
|
||||
dbg!(
|
||||
syscall::fmap(fd, &syscall::Map {
|
||||
dbg!(syscall::fmap(
|
||||
fd,
|
||||
&syscall::Map {
|
||||
offset: 0,
|
||||
size: 128,
|
||||
flags: syscall::PROT_READ | syscall::PROT_WRITE
|
||||
})
|
||||
).unwrap() as *mut u8,
|
||||
128
|
||||
}
|
||||
))
|
||||
.unwrap() as *mut u8,
|
||||
128,
|
||||
)
|
||||
};
|
||||
|
||||
@@ -124,9 +125,7 @@ fn mmap() {
|
||||
|
||||
//TODO: add msync
|
||||
unsafe {
|
||||
assert_eq!(dbg!(
|
||||
syscall::funmap(map.as_mut_ptr() as usize)
|
||||
), Ok(0));
|
||||
assert_eq!(dbg!(syscall::funmap(map.as_mut_ptr() as usize)), Ok(0));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user