Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • redox-os/redoxfs
  • jD91mZM2/redoxfs
  • microcolonel/redoxfs
  • rm-dr/redoxfs
  • deepaksirone/redoxfs
  • sevenEng/redoxfs
  • mortona/redoxfs
  • potatogim/redoxfs
  • 4lDO2/redoxfs
  • malandrakisgeo/redoxfs
  • ssd/redoxfs
  • dahc/redoxfs
  • ashton/redoxfs
  • usapmz/redoxfs
  • vadorovsky/redoxfs
  • bjorn3/redoxfs
  • rw_van/redoxfs
  • mkroening/redoxfs
  • emaxx-g/redoxfs
  • CILP/redoxfs
  • AnandSMain/redoxfs
  • aaronjanse/redoxfs
  • liamnprg/redoxfs
  • coolreader18/redoxfs
  • freewilll/redoxfs
  • adi-g15/redoxfs
  • andrey.turkin/redoxfs
  • matlik/redoxfs
28 results
Show changes
#[cfg(not(target_os = "redox"))] #[cfg(all(not(target_os = "redox"), not(fuzzing)))]
mod fuse; mod fuse;
#[cfg(all(not(target_os = "redox"), fuzzing))]
pub mod fuse;
#[cfg(not(target_os = "redox"))] #[cfg(not(target_os = "redox"))]
pub use self::fuse::mount; pub use self::fuse::mount;
......
use std::fs::File; use redox_scheme::{RequestKind, SignalBehavior, Socket, V2};
use std::io::{self, Read, Write}; use std::io;
use std::path::Path; use std::path::Path;
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
use syscall::{Packet, SchemeMut};
use crate::{Disk, FileSystem, IS_UMT}; use crate::{Disk, FileSystem, Transaction, IS_UMT};
use self::scheme::FileScheme; use self::scheme::FileScheme;
...@@ -15,41 +14,37 @@ pub fn mount<D, P, T, F>(filesystem: FileSystem<D>, mountpoint: P, mut callback: ...@@ -15,41 +14,37 @@ pub fn mount<D, P, T, F>(filesystem: FileSystem<D>, mountpoint: P, mut callback:
where where
D: Disk, D: Disk,
P: AsRef<Path>, P: AsRef<Path>,
F: FnMut(&Path) -> T, F: FnOnce(&Path) -> T,
{ {
let mountpoint = mountpoint.as_ref(); let mountpoint = mountpoint.as_ref();
let socket_path = format!(":{}", mountpoint.display()); let socket = Socket::<V2>::create(&format!("{}", mountpoint.display()))?;
let mut socket = File::create(&socket_path)?;
let mounted_path = format!("{}:", mountpoint.display()); let mounted_path = format!("{}:", mountpoint.display());
let res = callback(Path::new(&mounted_path)); let res = callback(Path::new(&mounted_path));
let mut scheme = FileScheme::new(format!("{}", mountpoint.display()), filesystem); let mut scheme = FileScheme::new(format!("{}", mountpoint.display()), filesystem);
loop { while IS_UMT.load(Ordering::SeqCst) == 0 {
if IS_UMT.load(Ordering::SeqCst) > 0 { let req = match socket.next_request(SignalBehavior::Restart)? {
break Ok(res); None => break,
} Some(req) => {
if let RequestKind::Call(r) = req.kind() {
let mut packet = Packet::default(); r
match socket.read(&mut packet) {
Ok(0) => break Ok(res),
Ok(_ok) => (),
Err(err) => {
if err.kind() == io::ErrorKind::Interrupted {
continue;
} else { } else {
break Err(err); // TODO: Redoxfs does not yet support asynchronous file IO. It might still make
// sense to implement cancellation for huge buffers, e.g. dd bs=1G
continue;
} }
} }
} };
let response = req.handle_scheme_mut(&mut scheme);
scheme.handle(&mut packet); if !socket.write_response(response, SignalBehavior::Restart)? {
break;
match socket.write(&packet) {
Ok(_ok) => (),
Err(err) => {
break Err(err);
}
} }
} }
// Squash allocations and sync on unmount
let _ = Transaction::new(&mut scheme.fs).commit(true);
Ok(res)
} }
use std::cmp::{max, min};
use std::slice; use std::slice;
use std::time::{SystemTime, UNIX_EPOCH}; use std::time::{SystemTime, UNIX_EPOCH};
use alloc::collections::BTreeMap; use alloc::collections::BTreeMap;
use libredox::call::MmapArgs;
use range_tree::RangeTree; use range_tree::RangeTree;
use syscall::{MAP_PRIVATE, PAGE_SIZE, EBADFD}; use syscall::data::{Stat, TimeSpec};
use syscall::data::{Map, Stat, TimeSpec}; use syscall::error::{Error, Result, EBADF, EINVAL, EISDIR, EPERM};
use syscall::error::{Error, Result, EBADF, EINVAL, EISDIR, ENOMEM, EPERM};
use syscall::flag::{ use syscall::flag::{
MapFlags, F_GETFL, F_SETFL, MODE_PERM, O_ACCMODE, O_APPEND, O_RDONLY, O_RDWR, O_WRONLY, MapFlags, 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, PROT_READ, PROT_WRITE,
}; };
use syscall::{EBADFD, PAGE_SIZE};
use crate::{Disk, Node, Transaction, TreePtr}; use crate::{Disk, Node, Transaction, TreePtr};
...@@ -28,15 +28,28 @@ pub trait Resource<D: Disk> { ...@@ -28,15 +28,28 @@ pub trait Resource<D: Disk> {
fn set_path(&mut self, path: &str); fn set_path(&mut self, path: &str);
fn read(&mut self, buf: &mut [u8], tx: &mut Transaction<D>) -> Result<usize>; fn read(&mut self, buf: &mut [u8], offset: u64, tx: &mut Transaction<D>) -> Result<usize>;
fn write(&mut self, buf: &[u8], tx: &mut Transaction<D>) -> Result<usize>; fn write(&mut self, buf: &[u8], offset: u64, tx: &mut Transaction<D>) -> Result<usize>;
fn seek(&mut self, offset: isize, whence: usize, tx: &mut Transaction<D>) -> Result<isize>; fn fsize(&mut self, tx: &mut Transaction<D>) -> Result<u64>;
fn fmap(&mut self, fmaps: &mut Fmaps, flags: MapFlags, size: usize, offset: u64, tx: &mut Transaction<D>) -> Result<usize>; fn fmap(
&mut self,
fmaps: &mut Fmaps,
flags: MapFlags,
size: usize,
offset: u64,
tx: &mut Transaction<D>,
) -> Result<usize>;
fn funmap(&mut self, fmaps: &mut Fmaps, offset: u64, size: usize, tx: &mut Transaction<D>) -> Result<usize>; fn funmap(
&mut self,
fmaps: &mut Fmaps,
offset: u64,
size: usize,
tx: &mut Transaction<D>,
) -> Result<usize>;
fn fchmod(&mut self, mode: u16, tx: &mut Transaction<D>) -> Result<usize> { fn fchmod(&mut self, mode: u16, tx: &mut Transaction<D>) -> Result<usize> {
let mut node = tx.read_tree(self.node_ptr())?; let mut node = tx.read_tree(self.node_ptr())?;
...@@ -129,7 +142,6 @@ pub struct DirResource { ...@@ -129,7 +142,6 @@ pub struct DirResource {
parent_ptr_opt: Option<TreePtr<Node>>, parent_ptr_opt: Option<TreePtr<Node>>,
node_ptr: TreePtr<Node>, node_ptr: TreePtr<Node>,
data: Option<Vec<u8>>, data: Option<Vec<u8>>,
seek: isize,
uid: u32, uid: u32,
} }
...@@ -146,7 +158,6 @@ impl DirResource { ...@@ -146,7 +158,6 @@ impl DirResource {
parent_ptr_opt, parent_ptr_opt,
node_ptr, node_ptr,
data, data,
seek: 0,
uid, uid,
} }
} }
...@@ -171,7 +182,6 @@ impl<D: Disk> Resource<D> for DirResource { ...@@ -171,7 +182,6 @@ impl<D: Disk> Resource<D> for DirResource {
parent_ptr_opt: self.parent_ptr_opt, parent_ptr_opt: self.parent_ptr_opt,
node_ptr: self.node_ptr, node_ptr: self.node_ptr,
data: self.data.clone(), data: self.data.clone(),
seek: self.seek,
uid: self.uid, uid: self.uid,
})) }))
} }
...@@ -180,38 +190,43 @@ impl<D: Disk> Resource<D> for DirResource { ...@@ -180,38 +190,43 @@ impl<D: Disk> Resource<D> for DirResource {
self.path = path.to_string(); self.path = path.to_string();
} }
fn read(&mut self, buf: &mut [u8], _tx: &mut Transaction<D>) -> Result<usize> { fn read(&mut self, buf: &mut [u8], offset: u64, _tx: &mut Transaction<D>) -> Result<usize> {
let data = self.data.as_ref().ok_or(Error::new(EISDIR))?; let data = self.data.as_ref().ok_or(Error::new(EISDIR))?;
let size = data.len() as isize; let src = usize::try_from(offset)
let mut i = 0; .ok()
while i < buf.len() && self.seek < size { .and_then(|o| data.get(o..))
buf[i] = data[self.seek as usize]; .unwrap_or(&[]);
i += 1;
self.seek += 1; let byte_count = core::cmp::min(src.len(), buf.len());
} buf[..byte_count].copy_from_slice(&src[..byte_count]);
Ok(i) Ok(byte_count)
} }
fn write(&mut self, _buf: &[u8], _tx: &mut Transaction<D>) -> Result<usize> { fn write(&mut self, _buf: &[u8], _offset: u64, _tx: &mut Transaction<D>) -> Result<usize> {
Err(Error::new(EBADF)) Err(Error::new(EBADF))
} }
fn seek(&mut self, offset: isize, whence: usize, _tx: &mut Transaction<D>) -> Result<isize> { fn fsize(&mut self, _tx: &mut Transaction<D>) -> Result<u64> {
let data = self.data.as_ref().ok_or(Error::new(EBADF))?; Ok(self.data.as_ref().ok_or(Error::new(EBADF))?.len() as u64)
let size = data.len() as isize;
self.seek = match whence {
SEEK_SET => max(0, min(size, offset)),
SEEK_CUR => max(0, min(size, self.seek + offset)),
SEEK_END => max(0, min(size, size + offset)),
_ => return Err(Error::new(EINVAL)),
};
Ok(self.seek)
} }
fn fmap(&mut self, _fmaps: &mut Fmaps, _flags: MapFlags, _size: usize, _offset: u64, _tx: &mut Transaction<D>) -> Result<usize> { fn fmap(
&mut self,
_fmaps: &mut Fmaps,
_flags: MapFlags,
_size: usize,
_offset: u64,
_tx: &mut Transaction<D>,
) -> Result<usize> {
Err(Error::new(EBADF)) Err(Error::new(EBADF))
} }
fn funmap(&mut self, _fmaps: &mut Fmaps, _offset: u64, _size: usize, _tx: &mut Transaction<D>) -> Result<usize> { fn funmap(
&mut self,
_fmaps: &mut Fmaps,
_offset: u64,
_size: usize,
_tx: &mut Transaction<D>,
) -> Result<usize> {
Err(Error::new(EBADF)) Err(Error::new(EBADF))
} }
...@@ -263,16 +278,11 @@ impl Fmap { ...@@ -263,16 +278,11 @@ impl Fmap {
let buf = slice::from_raw_parts_mut(address, unaligned_size); let buf = slice::from_raw_parts_mut(address, unaligned_size);
let count = match tx.read_node( let count = match tx.read_node(node_ptr, offset, buf, atime.as_secs(), atime.subsec_nanos())
node_ptr, {
offset,
buf,
atime.as_secs(),
atime.subsec_nanos(),
) {
Ok(ok) => ok, Ok(ok) => ok,
Err(err) => { Err(err) => {
let _ = syscall::funmap(address as usize, aligned_size); let _ = libredox::call::munmap(address.cast(), aligned_size);
return Err(err); return Err(err);
} }
}; };
...@@ -287,7 +297,14 @@ impl Fmap { ...@@ -287,7 +297,14 @@ impl Fmap {
}) })
} }
pub unsafe fn sync<D: Disk>(&mut self, node_ptr: TreePtr<Node>, base: *mut u8, offset: u64, size: usize, tx: &mut Transaction<D>) -> Result<()> { pub unsafe fn sync<D: Disk>(
&mut self,
node_ptr: TreePtr<Node>,
base: *mut u8,
offset: u64,
size: usize,
tx: &mut Transaction<D>,
) -> Result<()> {
if self.flags & PROT_WRITE == PROT_WRITE { if self.flags & PROT_WRITE == PROT_WRITE {
let mtime = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); let mtime = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
tx.write_node( tx.write_node(
...@@ -307,11 +324,12 @@ pub struct FileResource { ...@@ -307,11 +324,12 @@ pub struct FileResource {
parent_ptr_opt: Option<TreePtr<Node>>, parent_ptr_opt: Option<TreePtr<Node>>,
node_ptr: TreePtr<Node>, node_ptr: TreePtr<Node>,
flags: usize, flags: usize,
seek: isize,
uid: u32, uid: u32,
} }
#[derive(Debug)]
pub struct FileMmapInfo { pub struct FileMmapInfo {
base: *mut u8, base: *mut u8,
size: usize,
ranges: RangeTree<Fmap>, ranges: RangeTree<Fmap>,
pub open_fds: usize, pub open_fds: usize,
} }
...@@ -319,6 +337,7 @@ impl Default for FileMmapInfo { ...@@ -319,6 +337,7 @@ impl Default for FileMmapInfo {
fn default() -> Self { fn default() -> Self {
Self { Self {
base: core::ptr::null_mut(), base: core::ptr::null_mut(),
size: 0,
ranges: RangeTree::new(), ranges: RangeTree::new(),
open_fds: 0, open_fds: 0,
} }
...@@ -338,7 +357,6 @@ impl FileResource { ...@@ -338,7 +357,6 @@ impl FileResource {
parent_ptr_opt, parent_ptr_opt,
node_ptr, node_ptr,
flags, flags,
seek: 0,
uid, uid,
} }
} }
...@@ -363,7 +381,6 @@ impl<D: Disk> Resource<D> for FileResource { ...@@ -363,7 +381,6 @@ impl<D: Disk> Resource<D> for FileResource {
parent_ptr_opt: self.parent_ptr_opt, parent_ptr_opt: self.parent_ptr_opt,
node_ptr: self.node_ptr, node_ptr: self.node_ptr,
flags: self.flags, flags: self.flags,
seek: self.seek,
uid: self.uid, uid: self.uid,
})) }))
} }
...@@ -372,58 +389,53 @@ impl<D: Disk> Resource<D> for FileResource { ...@@ -372,58 +389,53 @@ impl<D: Disk> Resource<D> for FileResource {
self.path = path.to_string(); self.path = path.to_string();
} }
fn read(&mut self, buf: &mut [u8], tx: &mut Transaction<D>) -> Result<usize> { fn read(&mut self, buf: &mut [u8], offset: u64, tx: &mut Transaction<D>) -> Result<usize> {
if self.flags & O_ACCMODE == O_RDWR || self.flags & O_ACCMODE == O_RDONLY { if self.flags & O_ACCMODE != O_RDWR && self.flags & O_ACCMODE != O_RDONLY {
let atime = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); return Err(Error::new(EBADF));
let count = tx.read_node(
self.node_ptr,
self.seek as u64,
buf,
atime.as_secs(),
atime.subsec_nanos(),
)?;
self.seek += count as isize;
Ok(count)
} else {
Err(Error::new(EBADF))
} }
let atime = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
tx.read_node(
self.node_ptr,
offset,
buf,
atime.as_secs(),
atime.subsec_nanos(),
)
} }
fn write(&mut self, buf: &[u8], tx: &mut Transaction<D>) -> Result<usize> { fn write(&mut self, buf: &[u8], offset: u64, tx: &mut Transaction<D>) -> Result<usize> {
if self.flags & O_ACCMODE == O_RDWR || self.flags & O_ACCMODE == O_WRONLY { if self.flags & O_ACCMODE != O_RDWR && self.flags & O_ACCMODE != O_WRONLY {
if self.flags & O_APPEND == O_APPEND { return Err(Error::new(EBADF));
let node = tx.read_tree(self.node_ptr)?;
self.seek = node.data().size() as isize;
}
let mtime = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
let count = tx.write_node(
self.node_ptr,
self.seek as u64,
buf,
mtime.as_secs(),
mtime.subsec_nanos(),
)?;
self.seek += count as isize;
Ok(count)
} else {
Err(Error::new(EBADF))
} }
let effective_offset = if self.flags & O_APPEND == O_APPEND {
let node = tx.read_tree(self.node_ptr)?;
node.data().size()
} else {
offset
};
let mtime = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
tx.write_node(
self.node_ptr,
effective_offset,
buf,
mtime.as_secs(),
mtime.subsec_nanos(),
)
} }
fn seek(&mut self, offset: isize, whence: usize, tx: &mut Transaction<D>) -> Result<isize> { fn fsize(&mut self, tx: &mut Transaction<D>) -> Result<u64> {
self.seek = match whence { let node = tx.read_tree(self.node_ptr)?;
SEEK_SET => max(0, offset), Ok(node.data().size())
SEEK_CUR => max(0, self.seek + offset),
SEEK_END => {
let node = tx.read_tree(self.node_ptr)?;
max(0, node.data().size() as isize + offset)
}
_ => return Err(Error::new(EINVAL)),
};
Ok(self.seek)
} }
fn fmap(&mut self, fmaps: &mut Fmaps, flags: MapFlags, unaligned_size: usize, offset: u64, tx: &mut Transaction<D>) -> Result<usize> { fn fmap(
&mut self,
fmaps: &mut Fmaps,
flags: MapFlags,
unaligned_size: usize,
offset: u64,
tx: &mut Transaction<D>,
) -> Result<usize> {
//dbg!(&self.fmaps); //dbg!(&self.fmaps);
let accmode = self.flags & O_ACCMODE; let accmode = self.flags & O_ACCMODE;
if flags.contains(PROT_READ) && !(accmode == O_RDWR || accmode == O_RDONLY) { if flags.contains(PROT_READ) && !(accmode == O_RDWR || accmode == O_RDONLY) {
...@@ -441,33 +453,44 @@ impl<D: Disk> Resource<D> for FileResource { ...@@ -441,33 +453,44 @@ impl<D: Disk> Resource<D> for FileResource {
// TODO: Pass entry directory to Resource trait functions, since the node_ptr can be // TODO: Pass entry directory to Resource trait functions, since the node_ptr can be
// obtained by the caller. // obtained by the caller.
let fmap_info = fmaps.get_mut(&self.node_ptr.id()).ok_or(Error::new(EBADFD))?; let fmap_info = fmaps
.get_mut(&self.node_ptr.id())
let max_offset = fmap_info.ranges.end(); .ok_or(Error::new(EBADFD))?;
if offset + aligned_size as u64 > max_offset {
if fmap_info.base.is_null() { let new_size = (offset as usize + aligned_size).next_multiple_of(PAGE_SIZE);
fmap_info.base = unsafe { if new_size > fmap_info.size {
syscall::fmap(!0, &Map { fmap_info.base = if fmap_info.base.is_null() {
size: offset as usize + aligned_size, unsafe {
libredox::call::mmap(MmapArgs {
length: new_size,
// PRIVATE/SHARED doesn't matter once the pages are passed in the fmap // PRIVATE/SHARED doesn't matter once the pages are passed in the fmap
// handler. // handler.
flags: MapFlags::PROT_READ | MapFlags::PROT_WRITE | MapFlags::MAP_PRIVATE, prot: libredox::flag::PROT_READ | libredox::flag::PROT_WRITE,
flags: libredox::flag::MAP_PRIVATE,
offset: 0, offset: 0,
address: 0, fd: !0,
addr: core::ptr::null_mut(),
})? as *mut u8 })? as *mut u8
}; }
} else { } else {
let new_size = (offset as usize + aligned_size).next_multiple_of(PAGE_SIZE); unsafe {
let old_size = max_offset as usize; syscall::syscall5(
syscall::SYS_MREMAP,
fmap_info.base = unsafe { fmap_info.base as usize,
syscall::syscall5(syscall::SYS_MREMAP, fmap_info.base as usize, old_size, 0, new_size, syscall::MremapFlags::empty().bits() | (PROT_READ | PROT_WRITE).bits())? as *mut u8 fmap_info.size,
}; 0,
} new_size,
syscall::MremapFlags::empty().bits() | (PROT_READ | PROT_WRITE).bits(),
)? as *mut u8
}
};
fmap_info.size = new_size;
} }
let affected_fmaps = fmap_info.ranges.remove_and_unused(offset..offset + aligned_size as u64); let affected_fmaps = fmap_info
.ranges
.remove_and_unused(offset..offset + aligned_size as u64);
for (range, v_opt) in affected_fmaps { for (range, v_opt) in affected_fmaps {
//dbg!(&range); //dbg!(&range);
...@@ -475,9 +498,20 @@ impl<D: Disk> Resource<D> for FileResource { ...@@ -475,9 +498,20 @@ impl<D: Disk> Resource<D> for FileResource {
fmap.rc += 1; fmap.rc += 1;
fmap.flags |= flags; fmap.flags |= flags;
fmap_info.ranges.insert(range.start, range.end - range.start, fmap); fmap_info
.ranges
.insert(range.start, range.end - range.start, fmap);
} else { } else {
let map = unsafe { Fmap::new(self.node_ptr, flags, unaligned_size, offset, fmap_info.base, tx)? }; let map = unsafe {
Fmap::new(
self.node_ptr,
flags,
unaligned_size,
offset,
fmap_info.base,
tx,
)?
};
fmap_info.ranges.insert(offset, aligned_size as u64, map); fmap_info.ranges.insert(offset, aligned_size as u64, map);
} }
} }
...@@ -486,11 +520,20 @@ impl<D: Disk> Resource<D> for FileResource { ...@@ -486,11 +520,20 @@ impl<D: Disk> Resource<D> for FileResource {
Ok(fmap_info.base as usize + offset as usize) Ok(fmap_info.base as usize + offset as usize)
} }
fn funmap(&mut self, fmaps: &mut Fmaps, offset: u64, size: usize, tx: &mut Transaction<D>) -> Result<usize> { fn funmap(
let fmap_info = fmaps.get_mut(&self.node_ptr.id()).ok_or(Error::new(EBADFD))?; &mut self,
fmaps: &mut Fmaps,
offset: u64,
size: usize,
tx: &mut Transaction<D>,
) -> Result<usize> {
let fmap_info = fmaps
.get_mut(&self.node_ptr.id())
.ok_or(Error::new(EBADFD))?;
//dbg!(&self.fmaps); //dbg!(&self.fmaps);
//dbg!(self.fmaps.conflicts(offset..offset + size as u64).collect::<Vec<_>>()); //dbg!(self.fmaps.conflicts(offset..offset + size as u64).collect::<Vec<_>>());
#[allow(unused_mut)]
let mut affected_fmaps = fmap_info.ranges.remove(offset..offset + size as u64); let mut affected_fmaps = fmap_info.ranges.remove(offset..offset + size as u64);
for (range, mut fmap) in affected_fmaps { for (range, mut fmap) in affected_fmaps {
...@@ -498,11 +541,19 @@ impl<D: Disk> Resource<D> for FileResource { ...@@ -498,11 +541,19 @@ impl<D: Disk> Resource<D> for FileResource {
//log::info!("SYNCING {}..{}", range.start, range.end); //log::info!("SYNCING {}..{}", range.start, range.end);
unsafe { unsafe {
fmap.sync(self.node_ptr, fmap_info.base, range.start, (range.end - range.start) as usize, tx)?; fmap.sync(
self.node_ptr,
fmap_info.base,
range.start,
(range.end - range.start) as usize,
tx,
)?;
} }
if fmap.rc > 0 { if fmap.rc > 0 {
fmap_info.ranges.insert(range.start, range.end - range.start, fmap); fmap_info
.ranges
.insert(range.start, range.end - range.start, fmap);
} }
} }
//dbg!(&self.fmaps); //dbg!(&self.fmaps);
...@@ -529,7 +580,13 @@ impl<D: Disk> Resource<D> for FileResource { ...@@ -529,7 +580,13 @@ impl<D: Disk> Resource<D> for FileResource {
if let Some(fmap_info) = fmaps.get_mut(&self.node_ptr.id()) { if let Some(fmap_info) = fmaps.get_mut(&self.node_ptr.id()) {
for (range, fmap) in fmap_info.ranges.iter_mut() { for (range, fmap) in fmap_info.ranges.iter_mut() {
unsafe { unsafe {
fmap.sync(self.node_ptr, fmap_info.base, range.start, (range.end - range.start) as usize, tx)?; fmap.sync(
self.node_ptr,
fmap_info.base,
range.start,
(range.end - range.start) as usize,
tx,
)?;
} }
} }
} }
...@@ -615,9 +672,15 @@ impl range_tree::Value for Fmap { ...@@ -615,9 +672,15 @@ impl range_tree::Value for Fmap {
Err(self) Err(self)
} }
} }
fn split(self, prev_range: Option<core::ops::Range<Self::K>>, range: core::ops::Range<Self::K>, next_range: Option<core::ops::Range<Self::K>>) -> (Option<Self>, Self, Option<Self>) { #[allow(unused_variables)]
fn split(
self,
prev_range: Option<core::ops::Range<Self::K>>,
range: core::ops::Range<Self::K>,
next_range: Option<core::ops::Range<Self::K>>,
) -> (Option<Self>, Self, Option<Self>) {
( (
prev_range.map(|range| Fmap { prev_range.map(|_range| Fmap {
rc: self.rc, rc: self.rc,
flags: self.flags, flags: self.flags,
last_page_tail: 0, last_page_tail: 0,
...@@ -625,9 +688,13 @@ impl range_tree::Value for Fmap { ...@@ -625,9 +688,13 @@ impl range_tree::Value for Fmap {
Fmap { Fmap {
rc: self.rc, rc: self.rc,
flags: self.flags, flags: self.flags,
last_page_tail: if next_range.is_none() { self.last_page_tail } else { 0 }, last_page_tail: if next_range.is_none() {
self.last_page_tail
} else {
0
},
}, },
next_range.map(|range| Fmap { next_range.map(|_range| Fmap {
rc: self.rc, rc: self.rc,
flags: self.flags, flags: self.flags,
last_page_tail: self.last_page_tail, last_page_tail: self.last_page_tail,
......
This diff is collapsed.
use core::{fmt, mem, ops, slice}; use core::{fmt, mem, ops, slice};
use simple_endian::*; use endian_num::Le;
use crate::{BlockList, BlockPtr, BlockRaw}; use crate::{BlockLevel, BlockList, BlockPtr, BlockTrait, RecordRaw, BLOCK_SIZE, RECORD_LEVEL};
/// An index into a [`Node`]'s block table.
pub enum NodeLevel { pub enum NodeLevel {
L0(usize), L0(usize),
L1(usize, usize), L1(usize, usize),
...@@ -12,61 +13,66 @@ pub enum NodeLevel { ...@@ -12,61 +13,66 @@ pub enum NodeLevel {
} }
impl NodeLevel { impl NodeLevel {
// Warning: this uses constant block offsets, make sure to sync with Node // Warning: this uses constant record offsets, make sure to sync with Node
pub fn new(mut block_offset: u64) -> Option<Self> {
/// Return the [`NodeLevel`] of the record with the given index.
/// - the first 128 are level 0,
/// - the next 64*256 are level 1,
/// - ...and so on.
pub fn new(mut record_offset: u64) -> Option<Self> {
// 1 << 8 = 256, this is the number of entries in a BlockList // 1 << 8 = 256, this is the number of entries in a BlockList
const SHIFT: u64 = 8; const SHIFT: u64 = 8;
const NUM: u64 = 1 << SHIFT; const NUM: u64 = 1 << SHIFT;
const MASK: u64 = NUM - 1; const MASK: u64 = NUM - 1;
const L0: u64 = 128; const L0: u64 = 128;
if block_offset < L0 { if record_offset < L0 {
return Some(Self::L0((block_offset & MASK) as usize)); return Some(Self::L0((record_offset & MASK) as usize));
} else { } else {
block_offset -= L0; record_offset -= L0;
} }
const L1: u64 = 64 * NUM; const L1: u64 = 64 * NUM;
if block_offset < L1 { if record_offset < L1 {
return Some(Self::L1( return Some(Self::L1(
((block_offset >> SHIFT) & MASK) as usize, ((record_offset >> SHIFT) & MASK) as usize,
(block_offset & MASK) as usize, (record_offset & MASK) as usize,
)); ));
} else { } else {
block_offset -= L1; record_offset -= L1;
} }
const L2: u64 = 32 * NUM * NUM; const L2: u64 = 32 * NUM * NUM;
if block_offset < L2 { if record_offset < L2 {
return Some(Self::L2( return Some(Self::L2(
((block_offset >> (2 * SHIFT)) & MASK) as usize, ((record_offset >> (2 * SHIFT)) & MASK) as usize,
((block_offset >> SHIFT) & MASK) as usize, ((record_offset >> SHIFT) & MASK) as usize,
(block_offset & MASK) as usize, (record_offset & MASK) as usize,
)); ));
} else { } else {
block_offset -= L2; record_offset -= L2;
} }
const L3: u64 = 16 * NUM * NUM * NUM; const L3: u64 = 16 * NUM * NUM * NUM;
if block_offset < L3 { if record_offset < L3 {
return Some(Self::L3( return Some(Self::L3(
((block_offset >> (3 * SHIFT)) & MASK) as usize, ((record_offset >> (3 * SHIFT)) & MASK) as usize,
((block_offset >> (2 * SHIFT)) & MASK) as usize, ((record_offset >> (2 * SHIFT)) & MASK) as usize,
((block_offset >> SHIFT) & MASK) as usize, ((record_offset >> SHIFT) & MASK) as usize,
(block_offset & MASK) as usize, (record_offset & MASK) as usize,
)); ));
} else { } else {
block_offset -= L3; record_offset -= L3;
} }
const L4: u64 = 12 * NUM * NUM * NUM * NUM; const L4: u64 = 12 * NUM * NUM * NUM * NUM;
if block_offset < L4 { if record_offset < L4 {
Some(Self::L4( Some(Self::L4(
((block_offset >> (4 * SHIFT)) & MASK) as usize, ((record_offset >> (4 * SHIFT)) & MASK) as usize,
((block_offset >> (3 * SHIFT)) & MASK) as usize, ((record_offset >> (3 * SHIFT)) & MASK) as usize,
((block_offset >> (2 * SHIFT)) & MASK) as usize, ((record_offset >> (2 * SHIFT)) & MASK) as usize,
((block_offset >> SHIFT) & MASK) as usize, ((record_offset >> SHIFT) & MASK) as usize,
(block_offset & MASK) as usize, (record_offset & MASK) as usize,
)) ))
} else { } else {
None None
...@@ -74,38 +80,86 @@ impl NodeLevel { ...@@ -74,38 +80,86 @@ impl NodeLevel {
} }
} }
type BlockListL1 = BlockList<BlockRaw>; type BlockListL1 = BlockList<RecordRaw>;
type BlockListL2 = BlockList<BlockListL1>; type BlockListL2 = BlockList<BlockListL1>;
type BlockListL3 = BlockList<BlockListL2>; type BlockListL3 = BlockList<BlockListL2>;
type BlockListL4 = BlockList<BlockListL3>; type BlockListL4 = BlockList<BlockListL3>;
/// A file/folder node /// A file/folder node
#[repr(packed)] #[repr(C, packed)]
pub struct Node { pub struct Node {
pub mode: u16le, /// This node's type & permissions.
pub uid: u32le, /// - first four bits are permissions
pub gid: u32le, /// - next four bits are permissions for the file's user
pub links: u32le, /// - next four bits are permissions for the file's group
pub size: u64le, /// - last four bits are permissions for everyone else
pub ctime: u64le, pub mode: Le<u16>,
pub ctime_nsec: u32le,
pub mtime: u64le, /// The uid that owns this file
pub mtime_nsec: u32le, pub uid: Le<u32>,
pub atime: u64le,
pub atime_nsec: u32le, /// The gid that owns this file
pub padding: [u8; 6], pub gid: Le<u32>,
// 128 * BLOCK_SIZE (512 KiB, 4 KiB each)
pub level0: [BlockPtr<BlockRaw>; 128], /// The number of links to this file
// 64 * 256 * BLOCK_SIZE (64 MiB, 1 MiB each) /// (directory entries, symlinks, etc)
pub links: Le<u32>,
/// The length of this file, in bytes
pub size: Le<u64>,
pub ctime: Le<u64>,
pub ctime_nsec: Le<u32>,
pub mtime: Le<u64>,
pub mtime_nsec: Le<u32>,
pub atime: Le<u64>,
pub atime_nsec: Le<u32>,
pub record_level: Le<u32>,
pub padding: [u8; BLOCK_SIZE as usize - 4094],
/// The first 128 blocks of this file.
///
/// Total size: 128 * RECORD_SIZE (16 MiB, 128 KiB each)
pub level0: [BlockPtr<RecordRaw>; 128],
/// The next 64 * 256 blocks of this file,
/// stored behind 64 level one tables.
///
/// Total size: 64 * 256 * RECORD_SIZE (2 GiB, 32 MiB each)
pub level1: [BlockPtr<BlockListL1>; 64], pub level1: [BlockPtr<BlockListL1>; 64],
// 32 * 256 * 256 * BLOCK_SIZE (8 GiB, 256 MiB each)
/// The next 32 * 256 * 256 blocks of this file,
/// stored behind 32 level two tables.
/// Each level two table points to 256 level one tables.
///
/// Total size: 32 * 256 * 256 * RECORD_SIZE (256 GiB, 8 GiB each)
pub level2: [BlockPtr<BlockListL2>; 32], pub level2: [BlockPtr<BlockListL2>; 32],
// 16 * 256 * 256 * 256 * BLOCK_SIZE (1 TiB, 64 GiB each)
/// The next 16 * 256 * 256 * 256 blocks of this file,
/// stored behind 16 level three tables.
///
/// Total size: 16 * 256 * 256 * 256 * RECORD_SIZE (32 TiB, 2 TiB each)
pub level3: [BlockPtr<BlockListL3>; 16], pub level3: [BlockPtr<BlockListL3>; 16],
// 12 * 256 * 256 * 256 * 256 * BLOCK_SIZE (192 TiB, 16 TiB each)
/// The next 12 * 256 * 256 * 256 * 256 blocks of this file,
/// stored behind 12 level four tables.
///
/// Total size: 12 * 256 * 256 * 256 * 256 * RECORD_SIZE (6 PiB, 512 TiB each)
pub level4: [BlockPtr<BlockListL4>; 12], pub level4: [BlockPtr<BlockListL4>; 12],
} }
unsafe impl BlockTrait for Node {
fn empty(level: BlockLevel) -> Option<Self> {
if level.0 == 0 {
Some(Self::default())
} else {
None
}
}
}
impl Default for Node { impl Default for Node {
fn default() -> Self { fn default() -> Self {
Self { Self {
...@@ -120,7 +174,8 @@ impl Default for Node { ...@@ -120,7 +174,8 @@ impl Default for Node {
mtime_nsec: 0.into(), mtime_nsec: 0.into(),
atime: 0.into(), atime: 0.into(),
atime_nsec: 0.into(), atime_nsec: 0.into(),
padding: [0; 6], record_level: 0.into(),
padding: [0; BLOCK_SIZE as usize - 4094],
level0: [BlockPtr::default(); 128], level0: [BlockPtr::default(); 128],
level1: [BlockPtr::default(); 64], level1: [BlockPtr::default(); 64],
level2: [BlockPtr::default(); 32], level2: [BlockPtr::default(); 32],
...@@ -136,11 +191,13 @@ impl Node { ...@@ -136,11 +191,13 @@ impl Node {
pub const MODE_DIR: u16 = 0x4000; pub const MODE_DIR: u16 = 0x4000;
pub const MODE_SYMLINK: u16 = 0xA000; pub const MODE_SYMLINK: u16 = 0xA000;
/// Mask for node permission bits
pub const MODE_PERM: u16 = 0x0FFF; pub const MODE_PERM: u16 = 0x0FFF;
pub const MODE_EXEC: u16 = 0o1; pub const MODE_EXEC: u16 = 0o1;
pub const MODE_WRITE: u16 = 0o2; pub const MODE_WRITE: u16 = 0o2;
pub const MODE_READ: u16 = 0o4; pub const MODE_READ: u16 = 0o4;
/// Create a new, empty node with the given metadata
pub fn new(mode: u16, uid: u32, gid: u32, ctime: u64, ctime_nsec: u32) -> Self { pub fn new(mode: u16, uid: u32, gid: u32, ctime: u64, ctime_nsec: u32) -> Self {
Self { Self {
mode: mode.into(), mode: mode.into(),
...@@ -153,40 +210,62 @@ impl Node { ...@@ -153,40 +210,62 @@ impl Node {
mtime_nsec: ctime_nsec.into(), mtime_nsec: ctime_nsec.into(),
atime: ctime.into(), atime: ctime.into(),
atime_nsec: ctime_nsec.into(), atime_nsec: ctime_nsec.into(),
record_level: if mode & Self::MODE_TYPE == Self::MODE_FILE {
// Files take on record level
RECORD_LEVEL as u32
} else {
// Folders do not
0
}
.into(),
..Default::default() ..Default::default()
} }
} }
/// This node's type & permissions.
/// - first four bits are permissions
/// - next four bits are permissions for the file's user
/// - next four bits are permissions for the file's group
/// - last four bits are permissions for everyone else
pub fn mode(&self) -> u16 { pub fn mode(&self) -> u16 {
{ self.mode }.to_native() self.mode.to_ne()
} }
/// The uid that owns this file
pub fn uid(&self) -> u32 { pub fn uid(&self) -> u32 {
{ self.uid }.to_native() self.uid.to_ne()
} }
/// The gid that owns this file
pub fn gid(&self) -> u32 { pub fn gid(&self) -> u32 {
{ self.gid }.to_native() self.gid.to_ne()
} }
/// The number of links to this file
/// (directory entries, symlinks, etc)
pub fn links(&self) -> u32 { pub fn links(&self) -> u32 {
{ self.links }.to_native() self.links.to_ne()
} }
/// The length of this file, in bytes.
pub fn size(&self) -> u64 { pub fn size(&self) -> u64 {
{ self.size }.to_native() self.size.to_ne()
} }
pub fn ctime(&self) -> (u64, u32) { pub fn ctime(&self) -> (u64, u32) {
({ self.ctime }.to_native(), { self.ctime_nsec }.to_native()) (self.ctime.to_ne(), self.ctime_nsec.to_ne())
} }
pub fn mtime(&self) -> (u64, u32) { pub fn mtime(&self) -> (u64, u32) {
({ self.mtime }.to_native(), { self.mtime_nsec }.to_native()) (self.mtime.to_ne(), self.mtime_nsec.to_ne())
} }
pub fn atime(&self) -> (u64, u32) { pub fn atime(&self) -> (u64, u32) {
({ self.atime }.to_native(), { self.atime_nsec }.to_native()) (self.atime.to_ne(), self.atime_nsec.to_ne())
}
pub fn record_level(&self) -> BlockLevel {
BlockLevel(self.record_level.to_ne() as usize)
} }
pub fn set_mode(&mut self, mode: u16) { pub fn set_mode(&mut self, mode: u16) {
......
use alloc::{boxed::Box, vec};
use core::ops;
use crate::{BlockLevel, BlockTrait, RECORD_LEVEL};
//TODO: this is a box to prevent stack overflows
pub struct RecordRaw(Box<[u8]>);
unsafe impl BlockTrait for RecordRaw {
fn empty(level: BlockLevel) -> Option<Self> {
if level.0 <= RECORD_LEVEL {
Some(Self(vec![0; level.bytes() as usize].into_boxed_slice()))
} else {
None
}
}
}
impl Clone for RecordRaw {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl ops::Deref for RecordRaw {
type Target = [u8];
fn deref(&self) -> &[u8] {
&self.0
}
}
impl ops::DerefMut for RecordRaw {
fn deref_mut(&mut self) -> &mut [u8] {
&mut self.0
}
}
#[test]
fn record_raw_size_test() {
for level_i in 0..RECORD_LEVEL {
let level = BlockLevel(level_i);
assert_eq!(
RecordRaw::empty(level).unwrap().len(),
level.bytes() as usize
);
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
use failure::Error;
use std::{ use std::{
fs, fs,
io::{self}, io::{self},
...@@ -33,7 +31,7 @@ fn unmount_linux_path(mount_path: &str) -> io::Result<ExitStatus> { ...@@ -33,7 +31,7 @@ fn unmount_linux_path(mount_path: &str) -> io::Result<ExitStatus> {
)) ))
} }
pub fn unmount_path(mount_path: &str) -> Result<(), Error> { pub fn unmount_path(mount_path: &str) -> Result<(), io::Error> {
if cfg!(target_os = "redox") { if cfg!(target_os = "redox") {
fs::remove_file(format!(":{}", mount_path))? fs::remove_file(format!(":{}", mount_path))?
} else { } else {
...@@ -45,7 +43,10 @@ pub fn unmount_path(mount_path: &str) -> Result<(), Error> { ...@@ -45,7 +43,10 @@ pub fn unmount_path(mount_path: &str) -> Result<(), Error> {
let status = status_res?; let status = status_res?;
if !status.success() { if !status.success() {
return Err(io::Error::new(io::ErrorKind::Other, "redoxfs umount failed").into()); return Err(io::Error::new(
io::ErrorKind::Other,
"redoxfs umount failed",
));
} }
} }
......
...@@ -34,15 +34,22 @@ ls -lah image ...@@ -34,15 +34,22 @@ ls -lah image
mkdir image/test mkdir image/test
time cp -r src image/test/src time cp -r src image/test/src
dd if=/dev/urandom of=image/test/random bs=1M count=256 dd if=/dev/urandom of=image/test/random bs=1M count=256
dd if=image/test/random of=/dev/null bs=1M count=256 dd if=image/test/random of=/dev/null bs=1M count=256
time truncate --size=256M image/test/sparse
dd if=image/test/sparse of=/dev/null bs=1M count=256
dd if=/dev/zero of=image/test/zero bs=1M count=256 dd if=/dev/zero of=image/test/zero bs=1M count=256
dd if=image/test/zero of=/dev/null bs=1M count=256 dd if=image/test/zero of=/dev/null bs=1M count=256
ls -lah image/test ls -lah image/test
df -h image df -h image
rm image/test/random rm image/test/random
rm image/test/sparse
rm image/test/zero rm image/test/zero
rm -rf image/test/src rm -rf image/test/src
rmdir image/test rmdir image/test
......