From c706428ed6d500caaed2b0e44da3088053949a9e Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Tue, 26 Oct 2021 00:59:43 +0300 Subject: [PATCH] feat(vfs): CoW for memfs, init start --- Cargo.lock | 10 +++++++ Cargo.toml | 1 + Makefile | 10 ++++--- fs/memfs/Cargo.toml | 5 ++++ fs/memfs/src/bvec.rs | 43 +++++++++++++++++++++++++++++ fs/memfs/src/lib.rs | 61 +++++++++++++++++++++++++++++++++++------- fs/vfs/Cargo.toml | 1 + fs/vfs/src/file.rs | 43 +++++++++++++++++++++++------ fs/vfs/src/ioctx.rs | 7 ++--- fs/vfs/src/lib.rs | 1 - fs/vfs/src/node.rs | 48 ++++++++++++++++++++++++++++++++- fs/vfs/src/util.rs | 15 ----------- kernel/Cargo.toml | 1 + kernel/src/dev/fdt.rs | 4 +-- kernel/src/proc/elf.rs | 40 +++++++++++++++++++-------- kernel/src/proc/mod.rs | 12 +++------ kernel/src/util.rs | 9 ------- libcommon/Cargo.toml | 9 +++++++ libcommon/src/lib.rs | 42 +++++++++++++++++++++++++++++ libcommon/src/sync.rs | 0 20 files changed, 291 insertions(+), 71 deletions(-) delete mode 100644 fs/vfs/src/util.rs create mode 100644 libcommon/Cargo.toml create mode 100644 libcommon/src/lib.rs create mode 100644 libcommon/src/sync.rs diff --git a/Cargo.lock b/Cargo.lock index 8880cd5..b7ba37c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -108,6 +108,7 @@ dependencies = [ "cortex-a", "error", "fdt-rs", + "libcommon", "memfs", "tock-registers", "vfs", @@ -119,6 +120,13 @@ version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b2f96d100e1cf1929e7719b7edb3b90ab5298072638fccd77be9ce942ecdfce" +[[package]] +name = "libcommon" +version = "0.1.0" +dependencies = [ + "error", +] + [[package]] name = "libusr" version = "0.1.0" @@ -128,6 +136,7 @@ name = "memfs" version = "0.1.0" dependencies = [ "error", + "libcommon", "vfs", ] @@ -259,6 +268,7 @@ version = "0.1.0" dependencies = [ "error", "hashbrown", + "libcommon", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index c92c1ed..f6808aa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ edition = "2018" members = [ "fs/vfs", "fs/memfs", + "libcommon", "kernel", "libusr", "init", diff --git a/Makefile b/Makefile index 18c42c3..d69519f 100644 --- a/Makefile +++ b/Makefile @@ -55,13 +55,10 @@ endif .PHONY: address error etc kernel src -all: kernel +all: kernel initrd kernel: cd kernel && cargo build $(CARGO_BUILD_OPTS) - cd init && cargo build --target=../etc/$(ARCH)-osdev5.json -Z build-std=core,alloc,compiler_builtins - echo "This is a test file" >$(O)/test.txt - cd $(O) && tar cf initrd.img test.txt ifeq ($(ARCH),aarch64) $(LLVM_BASE)/llvm-strip -o $(O)/kernel.strip $(O)/kernel $(LLVM_BASE)/llvm-size $(O)/kernel.strip @@ -80,6 +77,11 @@ ifeq ($(MACH),orangepi3) $(O)/uImage endif +initrd: + cd init && cargo build --target=../etc/$(ARCH)-osdev5.json -Z build-std=core,alloc,compiler_builtins + cp target/$(ARCH)-osdev5/debug/init $(O) + cd $(O) && tar cf initrd.img init + test: cd fs/vfs && cargo test cd fs/memfs && cargo test diff --git a/fs/memfs/Cargo.toml b/fs/memfs/Cargo.toml index d261a18..2c7d297 100644 --- a/fs/memfs/Cargo.toml +++ b/fs/memfs/Cargo.toml @@ -8,3 +8,8 @@ edition = "2021" [dependencies] vfs = { path = "../vfs" } error = { path = "../../error" } +libcommon = { path = "../../libcommon" } + +[features] +cow = [] +default = ["cow"] diff --git a/fs/memfs/src/bvec.rs b/fs/memfs/src/bvec.rs index 9354953..6653009 100644 --- a/fs/memfs/src/bvec.rs +++ b/fs/memfs/src/bvec.rs @@ -12,6 +12,8 @@ pub struct Bvec<'a, A: BlockAllocator + Copy> { l0: [MaybeUninit>; L0_BLOCKS], l1: [MaybeUninit>; L1_BLOCKS], l2: MaybeUninit>, + #[cfg(feature = "cow")] + cow_source: *const u8, alloc: A, } impl<'a, A: BlockAllocator + Copy> Bvec<'a, A> { @@ -23,6 +25,8 @@ impl<'a, A: BlockAllocator + Copy> Bvec<'a, A> { l1: MaybeUninit::uninit_array(), l2: MaybeUninit::uninit(), alloc, + #[cfg(feature = "cow")] + cow_source: core::ptr::null_mut() }; for it in res.l0.iter_mut() { it.write(BlockRef::null()); @@ -33,7 +37,31 @@ impl<'a, A: BlockAllocator + Copy> Bvec<'a, A> { res.l2.write(BlockRef::null()); res } + + #[cfg(feature = "cow")] + pub unsafe fn setup_cow(&mut self, src: *const u8, size: usize) { + self.cow_source = src; + self.size = size; + } + + pub const fn size(&self) -> usize { + self.size + } + + #[cfg(feature = "cow")] + pub fn drop_cow(&mut self) { + assert!(!self.cow_source.is_null()); + let src_slice = unsafe { core::slice::from_raw_parts(self.cow_source, self.size) }; + self.cow_source = core::ptr::null_mut(); + + self.resize((self.size + 4095) / 4096).unwrap(); + self.write(0, src_slice).unwrap(); + } + pub fn resize(&mut self, cap: usize) -> Result<(), Errno> { + #[cfg(feature = "cow")] + assert!(self.cow_source.is_null()); + if cap <= self.capacity { let mut curr = self.capacity; while curr != cap { @@ -126,6 +154,12 @@ impl<'a, A: BlockAllocator + Copy> Bvec<'a, A> { if pos > self.size { return Err(Errno::InvalidArgument); } + + #[cfg(feature = "cow")] + if !self.cow_source.is_null() { + self.drop_cow(); + } + let mut rem = data.len(); let mut doff = 0usize; if pos + rem > self.size { @@ -150,7 +184,16 @@ impl<'a, A: BlockAllocator + Copy> Bvec<'a, A> { if pos > self.size { return Err(Errno::InvalidArgument); } + let mut rem = min(self.size - pos, data.len()); + + #[cfg(feature = "cow")] + if !self.cow_source.is_null() { + let cow_data = unsafe { core::slice::from_raw_parts(self.cow_source, self.size) }; + data[..rem].copy_from_slice(&cow_data[pos..pos + rem]); + return Ok(rem); + } + let mut doff = 0usize; while rem > 0 { let index = pos / block::SIZE; diff --git a/fs/memfs/src/lib.rs b/fs/memfs/src/lib.rs index 5529fb6..6b275f8 100644 --- a/fs/memfs/src/lib.rs +++ b/fs/memfs/src/lib.rs @@ -13,7 +13,9 @@ extern crate std; use alloc::{boxed::Box, rc::Rc}; use core::cell::RefCell; +use core::ffi::c_void; use error::Errno; +use libcommon::path_component_left; use vfs::{node::VnodeData, Filesystem, Vnode, VnodeImpl, VnodeKind, VnodeRef}; pub mod block; @@ -34,6 +36,12 @@ pub struct FileInode<'a, A: BlockAllocator + Copy + 'static> { pub struct DirInode; +struct SetupFileParam { + data: &'static [u8] +} + +const FILE_SETUP_COW: u64 = 0x1001; + impl<'a, A: BlockAllocator + Copy + 'static> VnodeImpl for FileInode<'a, A> { fn create(&mut self, _parent: VnodeRef, _node: VnodeRef) -> Result<(), Errno> { panic!() @@ -51,17 +59,35 @@ impl<'a, A: BlockAllocator + Copy + 'static> VnodeImpl for FileInode<'a, A> { Ok(()) } - fn read(&mut self, node: VnodeRef, pos: usize, data: &mut [u8]) -> Result { + fn read(&mut self, _node: VnodeRef, pos: usize, data: &mut [u8]) -> Result { self.data.read(pos, data) } - fn write(&mut self, node: VnodeRef, pos: usize, data: &[u8]) -> Result { + fn write(&mut self, _node: VnodeRef, pos: usize, data: &[u8]) -> Result { self.data.write(pos, data) } fn truncate(&mut self, _node: VnodeRef, size: usize) -> Result<(), Errno> { self.data.resize((size + 4095) / 4096) } + + fn size(&mut self, _node: VnodeRef) -> Result { + Ok(self.data.size()) + } + + fn ioctl(&mut self, node: VnodeRef, cmd: u64, value: *mut c_void) -> Result { + match cmd { + #[cfg(feature = "cow")] + FILE_SETUP_COW => { + let data = unsafe { (value as *mut SetupFileParam).as_ref().unwrap() }; + unsafe { + self.data.setup_cow(data.data.as_ptr(), data.data.len()); + } + Ok(0) + }, + _ => Err(Errno::InvalidArgument) + } + } } impl VnodeImpl for DirInode { @@ -92,6 +118,14 @@ impl VnodeImpl for DirInode { fn truncate(&mut self, _node: VnodeRef, _size: usize) -> Result<(), Errno> { todo!() } + + fn size(&mut self, _node: VnodeRef) -> Result { + todo!() + } + + fn ioctl(&mut self, node: VnodeRef, cmd: u64, value: *mut c_void) -> Result { + todo!() + } } impl Filesystem for Ramfs { @@ -100,7 +134,7 @@ impl Filesystem for Ramfs { } fn create_node(self: Rc, name: &str, kind: VnodeKind) -> Result { - let mut node = Vnode::new(name, kind); + let mut node = Vnode::new(name, kind, Vnode::SEEKABLE); let data: Box = match kind { VnodeKind::Regular => Box::new(FileInode { data: Bvec::new(self.alloc), @@ -134,7 +168,7 @@ impl Ramfs { kind: VnodeKind, do_create: bool, ) -> Result { - let (element, rest) = vfs::util::path_component_left(path); + let (element, rest) = path_component_left(path); assert!(!element.is_empty()); let node_kind = if rest.is_empty() { @@ -177,7 +211,6 @@ impl Ramfs { // 2. Setup data blocks for block in TarIterator::new(base, base.add(size)) { if block.is_file() { - let size = block.size(); let node = self.clone().make_path( root.clone(), block.path()?, @@ -185,10 +218,20 @@ impl Ramfs { false, )?; - node.truncate(size).unwrap(); - let res = node.write(0, block.data()).unwrap(); - if res != size { - panic!("Expected to write {}B, got {}B", size, res); + #[cfg(feature = "cow")] + { + let mut param = SetupFileParam { + data: block.data() + }; + node.ioctl(FILE_SETUP_COW, &mut param as *mut _ as *mut _)?; + } + #[cfg(not(feature = "cow"))] + { + let size = block.size(); + node.truncate(size)?; + if node.write(0, block.data())? != size { + return Err(Errno::InvalidArgument); + } } } } diff --git a/fs/vfs/Cargo.toml b/fs/vfs/Cargo.toml index 699e224..b963dce 100644 --- a/fs/vfs/Cargo.toml +++ b/fs/vfs/Cargo.toml @@ -7,4 +7,5 @@ edition = "2021" [dependencies] error = { path = "../../error" } +libcommon = { path = "../../libcommon" } hashbrown = "0.11.*" diff --git a/fs/vfs/src/file.rs b/fs/vfs/src/file.rs index 1fb1374..0c35b52 100644 --- a/fs/vfs/src/file.rs +++ b/fs/vfs/src/file.rs @@ -1,7 +1,9 @@ use crate::VnodeRef; use alloc::rc::Rc; use core::cell::RefCell; +use core::cmp::min; use error::Errno; +use libcommon::{Read, Seek, SeekDir, Write}; struct NormalFile { vnode: VnodeRef, @@ -16,14 +18,8 @@ pub struct File { inner: FileInner, } -impl File { - pub fn normal(vnode: VnodeRef, pos: usize) -> Self { - Self { - inner: FileInner::Normal(NormalFile { vnode, pos }), - } - } - - pub fn read(&mut self, data: &mut [u8]) -> Result { +impl Read for File { + fn read(&mut self, data: &mut [u8]) -> Result { match &mut self.inner { FileInner::Normal(inner) => { let count = inner.vnode.read(inner.pos, data)?; @@ -35,6 +31,37 @@ impl File { } } +impl Seek for File { + fn seek(&mut self, off: isize, whence: SeekDir) -> Result { + match &mut self.inner { + FileInner::Normal(inner) => { + if !inner.vnode.is_seekable() { + return Err(Errno::InvalidArgument); + } + + let size = inner.vnode.size()?; + let pos = match whence { + SeekDir::Set => min(off as usize, size), + _ => todo!(), + }; + + inner.pos = pos; + + Ok(pos) + } + _ => unimplemented!(), + } + } +} + +impl File { + pub fn normal(vnode: VnodeRef, pos: usize) -> Self { + Self { + inner: FileInner::Normal(NormalFile { vnode, pos }), + } + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/fs/vfs/src/ioctx.rs b/fs/vfs/src/ioctx.rs index 672d549..a4985df 100644 --- a/fs/vfs/src/ioctx.rs +++ b/fs/vfs/src/ioctx.rs @@ -1,5 +1,6 @@ -use crate::{util, FileMode, VnodeRef}; +use crate::{FileMode, VnodeRef}; use error::Errno; +use libcommon::{path_component_left, path_component_right}; pub struct Ioctx { root: VnodeRef, @@ -19,7 +20,7 @@ impl Ioctx { let mut rest = path; loop { - (element, rest) = util::path_component_left(rest); + (element, rest) = path_component_left(rest); if !at.is_directory() { return Err(Errno::NotADirectory); @@ -62,7 +63,7 @@ impl Ioctx { } pub fn mkdir(&self, at: Option, path: &str, mode: FileMode) -> Result<(), Errno> { - let (parent, name) = util::path_component_right(path); + let (parent, name) = path_component_right(path); let parent_node = self.find(at, parent)?; parent_node.mkdir(name, mode).map(|_| ()) diff --git a/fs/vfs/src/lib.rs b/fs/vfs/src/lib.rs index be89b53..2d01a4e 100644 --- a/fs/vfs/src/lib.rs +++ b/fs/vfs/src/lib.rs @@ -13,4 +13,3 @@ pub mod ioctx; pub use ioctx::Ioctx; pub mod file; pub use file::File; -pub mod util; diff --git a/fs/vfs/src/node.rs b/fs/vfs/src/node.rs index 70d4c69..d85b5d8 100644 --- a/fs/vfs/src/node.rs +++ b/fs/vfs/src/node.rs @@ -1,6 +1,7 @@ use crate::{File, FileMode, Filesystem}; use alloc::{borrow::ToOwned, boxed::Box, rc::Rc, string::String, vec::Vec}; use core::cell::{RefCell, RefMut}; +use core::ffi::c_void; use core::fmt; use error::Errno; @@ -34,6 +35,7 @@ pub struct Vnode { props: RefCell, kind: VnodeKind, + flags: u32, pub data: RefCell>, } @@ -48,13 +50,19 @@ pub trait VnodeImpl { fn truncate(&mut self, node: VnodeRef, size: usize) -> Result<(), Errno>; fn read(&mut self, node: VnodeRef, pos: usize, data: &mut [u8]) -> Result; fn write(&mut self, node: VnodeRef, pos: usize, data: &[u8]) -> Result; + + fn size(&mut self, node: VnodeRef) -> Result; + fn ioctl(&mut self, node: VnodeRef, cmd: u64, value: *mut c_void) -> Result; } impl Vnode { - pub fn new(name: &str, kind: VnodeKind) -> VnodeRef { + pub const SEEKABLE: u32 = 1 << 0; + + pub fn new(name: &str, kind: VnodeKind, flags: u32) -> VnodeRef { Rc::new(Self { name: name.to_owned(), kind, + flags, props: RefCell::new(VnodeProps { mode: FileMode::empty(), }), @@ -78,6 +86,10 @@ impl Vnode { self.kind == VnodeKind::Directory } + pub fn is_seekable(&self) -> bool { + self.flags & Self::SEEKABLE != 0 + } + #[inline(always)] pub const fn kind(&self) -> VnodeKind { self.kind @@ -218,6 +230,22 @@ impl Vnode { Err(Errno::NotImplemented) } } + + pub fn size(self: &VnodeRef) -> Result { + if let Some(ref mut data) = *self.data.borrow_mut() { + data.node.size(self.clone()) + } else { + Err(Errno::NotImplemented) + } + } + + pub fn ioctl(self: &VnodeRef, cmd: u64, value: *mut c_void) -> Result { + if let Some(ref mut data) = *self.data.borrow_mut() { + data.node.ioctl(self.clone(), cmd, value) + } else { + Err(Errno::NotImplemented) + } + } } impl fmt::Debug for Vnode { @@ -262,6 +290,24 @@ mod tests { fn truncate(&mut self, _node: VnodeRef, _size: usize) -> Result<(), Errno> { Err(Errno::NotImplemented) } + + fn ioctl( + &mut self, + _node: VnodeRef, + _cmd: u64, + _value: *mut c_void, + ) -> Result { + Err(Errno::NotImplemented) + } + + fn seek( + &mut self, + _node: VnodeRef, + _pos: usize, + _whence: SeekWhence, + ) -> Result { + Err(Errno::NotImplemented) + } } impl Filesystem for DummyFs { diff --git a/fs/vfs/src/util.rs b/fs/vfs/src/util.rs deleted file mode 100644 index ba03dd5..0000000 --- a/fs/vfs/src/util.rs +++ /dev/null @@ -1,15 +0,0 @@ -pub fn path_component_left(path: &str) -> (&str, &str) { - if let Some((left, right)) = path.split_once('/') { - (left, right.trim_start_matches('/')) - } else { - (path, "") - } -} - -pub fn path_component_right(path: &str) -> (&str, &str) { - if let Some((left, right)) = path.rsplit_once('/') { - (left.trim_end_matches('/'), right) - } else { - (path, "") - } -} diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index b506e17..10d95f5 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -13,6 +13,7 @@ test = false error = { path = "../error" } vfs = { path = "../fs/vfs" } memfs = { path = "../fs/memfs" } +libcommon = { path = "../libcommon" } cfg-if = "1.x.x" tock-registers = "0.7.x" fdt-rs = { version = "0.x.x", default-features = false } diff --git a/kernel/src/dev/fdt.rs b/kernel/src/dev/fdt.rs index 7365dcc..9b278fd 100644 --- a/kernel/src/dev/fdt.rs +++ b/kernel/src/dev/fdt.rs @@ -1,11 +1,11 @@ use crate::debug::Level; -use crate::util; use error::Errno; use fdt_rs::prelude::*; use fdt_rs::{ base::DevTree, index::{DevTreeIndex, DevTreeIndexNode, DevTreeIndexProp}, }; +use libcommon::path_component_left; #[repr(align(16))] struct Wrap { @@ -74,7 +74,7 @@ fn dump_node(level: Level, node: &INode, depth: usize) { } fn find_node<'a>(at: INode<'a>, path: &str) -> Option> { - let (item, path) = util::path_component_left(path); + let (item, path) = path_component_left(path); if item == "" { assert_eq!(path, ""); Some(at) diff --git a/kernel/src/proc/elf.rs b/kernel/src/proc/elf.rs index 9a9ffb3..f9f49c5 100644 --- a/kernel/src/proc/elf.rs +++ b/kernel/src/proc/elf.rs @@ -5,7 +5,9 @@ use crate::mem::{ phys::{self, PageUsage}, virt::{MapAttributes, Space}, }; +use core::mem::{size_of, MaybeUninit}; use error::Errno; +use libcommon::{Read, Seek, SeekDir}; trait Elf { type Addr; @@ -86,12 +88,12 @@ fn map_flags(elf_flags: usize) -> MapAttributes { unsafe fn load_bytes( space: &mut Space, dst_virt: usize, - read: F, + mut read: F, size: usize, flags: usize, ) -> Result<(), Errno> where - F: Fn(usize, &mut [u8]) -> Result<(), Errno>, + F: FnMut(usize, &mut [u8]) -> Result<(), Errno>, { let dst_page_off = dst_virt & 0xFFF; let dst_page = dst_virt & !0xFFF; @@ -125,17 +127,32 @@ where Ok(()) } +unsafe fn read_struct(src: &mut F, pos: usize) -> Result { + let mut storage: MaybeUninit = MaybeUninit::uninit(); + let size = size_of::(); + src.seek(pos as isize, SeekDir::Set)?; + let res = src.read(core::slice::from_raw_parts_mut( + storage.as_mut_ptr() as *mut u8, + size, + ))?; + if res != size { + Err(Errno::InvalidArgument) + } else { + Ok(storage.assume_init()) + } +} + /// -pub fn load_elf(space: &mut Space, elf_base: *const u8) -> Result { - let ehdr: &Ehdr = unsafe { &*(elf_base as *const _) }; +pub fn load_elf(space: &mut Space, source: &mut F) -> Result { + let ehdr: Ehdr = unsafe { read_struct(source, 0).unwrap() }; if &ehdr.ident[0..4] != b"\x7FELF" { return Err(Errno::InvalidArgument); } for i in 0..(ehdr.phnum as usize) { - let phdr: &Phdr = unsafe { - &*(elf_base.add(ehdr.phoff as usize + ehdr.phentsize as usize * i) as *const _) + let phdr: Phdr = unsafe { + read_struct(source, ehdr.phoff as usize + ehdr.phentsize as usize * i).unwrap() }; if phdr.typ == 1 @@ -154,11 +171,12 @@ pub fn load_elf(space: &mut Space, elf_base: *const u8) -> Result space, phdr.vaddr as usize, |off, dst| { - let src = elf_base.add(phdr.offset as usize + off); - assert!(off + dst.len() <= phdr.filesz as usize); - let src_slice = core::slice::from_raw_parts(src, dst.len()); - dst.copy_from_slice(src_slice); - Ok(()) + source.seek(phdr.offset as isize + off as isize, SeekDir::Set)?; + if source.read(dst)? == dst.len() { + Ok(()) + } else { + Err(Errno::InvalidArgument) + } }, phdr.filesz as usize, phdr.flags as usize, diff --git a/kernel/src/proc/mod.rs b/kernel/src/proc/mod.rs index 0399c49..3160628 100644 --- a/kernel/src/proc/mod.rs +++ b/kernel/src/proc/mod.rs @@ -66,21 +66,17 @@ pub unsafe fn enter(initrd: Option<(usize, usize)>) -> ! { let (start, end) = unsafe { *(initrd_ptr as *const (usize, usize)) }; let size = end - start; + infoln!("Constructing initrd filesystem in memory, this may take a while..."); let fs = Ramfs::open(start as *mut u8, size, MemfsBlockAlloc {}).unwrap(); + infoln!("Done constructing ramfs"); let root = fs.root().unwrap(); let ioctx = Ioctx::new(root); // Open a test file - let node = ioctx.find(None, "/test.txt").unwrap(); + let node = ioctx.find(None, "/init").unwrap(); let mut file = node.open().unwrap(); - let mut buf = [0u8; 16]; - while let Ok(count) = file.read(&mut buf) { - if count == 0 { - break; - } - debugln!("Read {} bytes: {:?}", count, &buf[0..count]); - } + Process::execve(|space| elf::load_elf(space, &mut file), 0).unwrap(); }, initrd as usize); } SCHED.enter(); diff --git a/kernel/src/util.rs b/kernel/src/util.rs index 1b7f99b..948c31c 100644 --- a/kernel/src/util.rs +++ b/kernel/src/util.rs @@ -51,12 +51,3 @@ impl InitOnce { } unsafe impl Sync for InitOnce {} - -/// -pub fn path_component_left(path: &str) -> (&str, &str) { - if let Some((left, right)) = path.split_once('/') { - (left, right.trim_start_matches('/')) - } else { - (path, "") - } -} diff --git a/libcommon/Cargo.toml b/libcommon/Cargo.toml new file mode 100644 index 0000000..a49a495 --- /dev/null +++ b/libcommon/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "libcommon" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +error = { path = "../error" } diff --git a/libcommon/src/lib.rs b/libcommon/src/lib.rs new file mode 100644 index 0000000..eb871e5 --- /dev/null +++ b/libcommon/src/lib.rs @@ -0,0 +1,42 @@ +#![no_std] + +use error::Errno; + +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum SeekDir { + Set, + End, + Current, +} + +pub trait Read { + fn read(&mut self, data: &mut [u8]) -> Result; +} + +pub trait Seek { + fn seek(&mut self, off: isize, whence: SeekDir) -> Result; +} + +pub trait Write { + fn write(&mut self, data: &[u8]) -> Result; +} + +pub fn path_component_left(path: &str) -> (&str, &str) { + if let Some((left, right)) = path.split_once('/') { + (left, right.trim_start_matches('/')) + } else { + (path, "") + } +} + +pub fn path_component_right(path: &str) -> (&str, &str) { + if let Some((left, right)) = path.rsplit_once('/') { + (left.trim_end_matches('/'), right) + } else { + (path, "") + } +} + +#[cfg(test)] +mod tests { +} diff --git a/libcommon/src/sync.rs b/libcommon/src/sync.rs new file mode 100644 index 0000000..e69de29