Skip to content

Added Vnode based VFS implementation #35

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 13 commits into
base: dev
Choose a base branch
from
16 changes: 9 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,23 @@ Welcome to **Hexium OS**, an experimental operating system written in Rust. This
- :electric_plug: Serial Support
- :brain: Memory Management
- :file_cabinet: In-memory File System
- :dart: Task State Segment (TSS)
- :dart: Task State Segment
- :wrench: Heap allocator
- :keyboard: Keyboard Driver
- :clock8: Multitasking
- :clock8: Multitasking (Unavailable)
- :card_file_box: Virtual Filesystem
- :x: Shell
- :x: ACPI/AML Shutdown
- :x: CpuId Support
- :x: Mouse Driver
- :x: Graphical Interface (GUI)
- :x: Graphical Interface
- :x: ELF Loader
- :x: Network Driver
- :x: Audio Driver
- :x: FAT32 Support
- :x: OpenGL-like API
- :x: Integrated Development Environment (IDE)
- :x: C/C++ Compiler
- :x: Rust Standard Library
- :x: Processes
- :x: Installation Setup
- :x: Web Browser
Expand All @@ -36,7 +37,9 @@ Welcome to **Hexium OS**, an experimental operating system written in Rust. This

## **⚙️ Building**

This project requires a nightly version of Rust because it uses some unstable features. You might need to run `rustup update nightly --force` to update to the latest nightly even if some components such as `rustfmt` are missing it.
This project requires a nightly version of Rust because it uses some unstable features. You might need to run `rustup update nightly --force` to update to the latest nightly even if some components such as `rustfmt` are missing it. Additionally, ensure you have `rustc` and `cargo` version 1.86 or higher installed.

You will also need `xorriso`, a tool for creating ISO images.

You can build the project by running:

Expand All @@ -58,12 +61,11 @@ make run

```bash
/initrd/ # The initial ramdisk
/userspace/ # Userspace programs
/kernel/src/ # Kernel source code
/kernel/target/ # Kernel output directory
/limine # Limine and UEFI binaries (generated)
/ovmf # Virtual firmware (generated)
/scripts # Build & helper scripts
/tools # Build & helper scripts/tools
```

[QEMU]: https://www.qemu.org/
2 changes: 1 addition & 1 deletion initrd/welcome.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Welcome to Hexium OS
Welcome to Hexium OS
72 changes: 0 additions & 72 deletions kernel/src/fs/memfs.rs

This file was deleted.

2 changes: 0 additions & 2 deletions kernel/src/fs/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
pub mod memfs;
pub mod ramfs;
pub mod vfs;
103 changes: 57 additions & 46 deletions kernel/src/fs/ramfs.rs
Original file line number Diff line number Diff line change
@@ -1,62 +1,58 @@
use crate::{
boot, fs::vfs::{FileSystem, FileType, VNode, VFS}, info, print, trace, utils
boot,
hal::vfs::{Vfs, VfsError, Vnode, VnodeOps, VnodeType},
print, trace, utils,
};
use alloc::sync::Arc;
use alloc::{
format,
string::{String, ToString},
};
use alloc::boxed::Box;
use alloc::string::{String, ToString};

pub struct RamFs {
//files: Vec<VNode>,
archive: &'static [u8],
}

impl RamFs {
pub fn new(archive: &'static [u8]) -> Self {
RamFs {
//files: Vec::new(),
archive,
}
RamFs { archive }
}
}

impl FileSystem for RamFs {
fn mount(&mut self, _path: &str) -> Result<(), ()> {
info!("RamFs mounted");
Ok(())
}

fn unmount(&mut self) -> Result<(), String> {
info!("RamFs unmounted");
Ok(())
}

fn open(&self, path: &str) -> Result<VNode, String> {
if let Some((_size, _content)) = tar_lookup(self.archive, path) {
Ok(VNode::new(path.to_string(), FileType::File))
} else {
Err("File not found".to_string())
impl VnodeOps for RamFs {
fn lookup(&self, path: &str) -> Result<Vnode, VfsError> {
match tar_lookup(self.archive, path) {
Some((_size, _content, vtype)) => Ok(Vnode {
name: path.to_string(),
vtype,
ops: Arc::new(RamFs::new(self.archive)),
}),
None => Err(VfsError::NotFound),
}
}

fn read(&self, file: &VNode, buf: &mut [u8], offset: usize) -> Result<usize, String> {
if let Some((_size, content)) = tar_lookup(self.archive, &file.file_name) {
let len = buf.len().min(content.len().saturating_sub(offset));
buf[..len].copy_from_slice(&content[offset..offset + len]);
fn read(
&self,
file: &Vnode,
buf: &mut [u8],
offset: usize,
_length: usize,
) -> Result<usize, String> {
if let Some((size, content, _)) = tar_lookup(self.archive, &file.name) {
let start = offset.min(size);
let end = (offset + buf.len()).min(size);
let len = end - start;
if len > 0 {
buf[..len].copy_from_slice(&content[start..end]);
}
Ok(len)
} else {
Err("File not found".to_string())
}
}

fn write(&mut self, _file: &VNode, _buf: &[u8], _offset: usize) -> Result<usize, String> {
Err("Write operation not supported".to_string())
}

fn create(&mut self, _path: &str, _file_type: FileType) -> Result<VNode, String> {
Err("Create operation not supported".to_string())
}
}

pub fn init(vfs: &mut VFS) {
pub fn init(vfs: &Vfs) {
if let Some(module_response) = boot::MODULE_REQUEST.get_response() {
let modules = module_response.modules();
if !modules.is_empty() {
Expand All @@ -68,19 +64,26 @@ pub fn init(vfs: &mut VFS) {
}

let archive = unsafe {
core::slice::from_raw_parts(
modules[0].addr() as *const u8,
(modules[0].size() as u64).try_into().unwrap(),
)
core::slice::from_raw_parts(modules[0].addr() as *const u8, modules[0].size() as usize)
};
let ramfs = Box::new(RamFs::new(archive));
vfs.mount_fs(ramfs);
let ramfs = RamFs::new(archive);
vfs.mount("/ramdisk", Arc::new(ramfs));
}
}

pub fn tar_lookup<'a>(archive: &'a [u8], filename: &str) -> Option<(usize, &'a [u8])> {
pub fn tar_lookup<'a>(
archive: &'a [u8],
filename: &'a str,
) -> Option<(usize, &'a [u8], VnodeType)> {
let mut ptr = 0;

// Ensure filename starts with "./"
let normalized_filename = if filename.starts_with("./") {
filename.to_string()
} else {
format!("./{}", filename)
};

while ptr + 257 < archive.len() {
if &archive[ptr + 257..ptr + 262] != b"ustar" {
break;
Expand All @@ -90,16 +93,24 @@ pub fn tar_lookup<'a>(archive: &'a [u8], filename: &str) -> Option<(usize, &'a [
let name_len = header_filename.iter().position(|&x| x == 0).unwrap_or(100);
let file_name = &header_filename[..name_len];

let typeflag = archive[ptr + 156];
let vtype = if typeflag == b'5' {
VnodeType::Directory
} else {
VnodeType::Regular
};

let filesize = utils::octal_to_binrary(&archive[ptr + 124..ptr + 135]);

if file_name == filename.as_bytes() {
if file_name == normalized_filename.as_bytes() {
return Some((
filesize as usize,
&archive[ptr + 512..ptr + 512 + filesize as usize],
vtype,
));
}

ptr = ptr + ((((filesize as usize) + 511) / 512) + 1) * 512;
ptr += (((filesize as usize + 511) / 512) + 1) * 512;
}
None
}
77 changes: 0 additions & 77 deletions kernel/src/fs/vfs.rs

This file was deleted.

1 change: 1 addition & 0 deletions kernel/src/hal/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod vfs;
Loading
Loading