diff --git a/src/archive.rs b/src/archive.rs index 329d9b663b770e2dbcbf768b3ea3b1490733c263..1483e19b157ce0c90558335e63322f28bd8204da 100644 --- a/src/archive.rs +++ b/src/archive.rs @@ -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), )); } } diff --git a/src/bin/ar.rs b/src/bin/ar.rs index 1b7ac036bf52ed35b11b9f052770956638831e92..a4ac0096292d514ff5db8da2243c1659c0edd858 100644 --- a/src/bin/ar.rs +++ b/src/bin/ar.rs @@ -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); } }; diff --git a/src/bin/mkfs.rs b/src/bin/mkfs.rs index 6fb686ad219ece41ce4c705488eab48b08f49e7a..e3b96907d88e4e206faf8df14126dee890b448cb 100644 --- a/src/bin/mkfs.rs +++ b/src/bin/mkfs.rs @@ -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); } } diff --git a/src/bin/mount.rs b/src/bin/mount.rs index af9a786e1ca2c6ddabe28edf01e63c1bd8457a1b..235805df6c05dda81a09d0cec49b96ce06c36c9a 100644 --- a/src/bin/mount.rs +++ b/src/bin/mount.rs @@ -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(); diff --git a/src/disk/cache.rs b/src/disk/cache.rs index cf0f96a8f8483a9e0297d41c249e6e3949222710..400bc4bc45d07ae6632e15e1b58f52c013ae3351 100644 --- a/src/disk/cache.rs +++ b/src/disk/cache.rs @@ -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); diff --git a/src/disk/file.rs b/src/disk/file.rs index d36e012c70c4d0a2381e9d0801c91f44eba2c429..6014643f9430da7962c0542ee425511dda8a35b5 100644 --- a/src/disk/file.rs +++ b/src/disk/file.rs @@ -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 }) } } diff --git a/src/disk/sparse.rs b/src/disk/sparse.rs index da31f06f32b912d2c45535b593b0dac4eaf57b2a..8ed79bd79ed57dd1b674cda2d613697c14451754 100644 --- a/src/disk/sparse.rs +++ b/src/disk/sparse.rs @@ -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 }) } } diff --git a/src/ex_node.rs b/src/ex_node.rs index faa3e34fa004ee3ff8fe7cafb24d18db263274be..2683800bc34293716b7a0f0caa311e639c788d8b 100644 --- a/src/ex_node.rs +++ b/src/ex_node.rs @@ -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] } } } diff --git a/src/extent.rs b/src/extent.rs index 517faf3bf2c81a7d56d6e8b0835f7e6b80d94b7d..3f59a96796deb2d95b1fe088d2b43324814e40e2 100644 --- a/src/extent.rs +++ b/src/extent.rs @@ -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, } } } diff --git a/src/filesystem.rs b/src/filesystem.rs index e1e0bd7e86c09cb67d752e6ded81ad43ecebeda5..8b736249bf8de8964bbf9c63eb72ff9590a847b6 100644 --- a/src/filesystem.rs +++ b/src/filesystem.rs @@ -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 { diff --git a/src/header.rs b/src/header.rs index 0c4b77638cbfbffffd980410125b7c34f62980e0..d7eb01afa3ec337b137536daf5aaebc5e0e70945 100644 --- a/src/header.rs +++ b/src/header.rs @@ -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] } } } diff --git a/src/mount/fuse.rs b/src/mount/fuse.rs index b5335e4ed38da133852baaf22d8001468a2f4003..b7ec66ae5fa06ce7d7807e79f94e9dc44809bee9 100644 --- a/src/mount/fuse.rs +++ b/src/mount/fuse.rs @@ -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); } diff --git a/src/mount/redox/mod.rs b/src/mount/redox/mod.rs index a7329cb8efca6cbc02f4a52af0fc078f43d885c1..8decac6352b02f0721ea4c16840a2bf9c81115d9 100644 --- a/src/mount/redox/mod.rs +++ b/src/mount/redox/mod.rs @@ -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); + } } } diff --git a/src/mount/redox/resource.rs b/src/mount/redox/resource.rs index 49fa2aadd35a2e64b3f40bd830b9407f5330f070..c02670fa99280bc9e12206d7b4a28a1d548c5f77 100644 --- a/src/mount/redox/resource.rs +++ b/src/mount/redox/resource.rs @@ -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() + ); } } } diff --git a/src/mount/redox/scheme.rs b/src/mount/redox/scheme.rs index a935237cc6cbcfb0776ceca9357bc7c6fbd8afa8..d12398cbdb520f52559b3e235de9554169e98a57 100644 --- a/src/mount/redox/scheme.rs +++ b/src/mount/redox/scheme.rs @@ -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); - return Err(Error::new(EACCES)); - } + 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 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'); + 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()); } - 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)); + 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 { - 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_DIRECTORY == O_DIRECTORY { + // println!("{:X} & {:X}: ENOTDIR {}", flags, O_DIRECTORY, path); + return Err(Error::new(ENOTDIR)); + } - 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_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_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) diff --git a/src/node.rs b/src/node.rs index f85a341cd7bf844095d18a8665bc4bedd707005e..a224c48384088dbcc42613869fe5c8c823d86963 100644 --- a/src/node.rs +++ b/src/node.rs @@ -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] } } } diff --git a/src/tests.rs b/src/tests.rs index 62d06e8e913dffb84be63a115588f66ea06b4658..17291df3e82cc4932ad81d692e724fc7a52eaa99 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -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)); } };