diff --git a/Cargo.toml b/Cargo.toml index c5eada0..e0b7bc5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ members = [ "os/application/shell", "os/application/uptime", "os/application/date", - "os/application/mkentry" + "os/application/mkdir" ] # [profile.release] diff --git a/Makefile.toml b/Makefile.toml index 371f9df..c0804d5 100644 --- a/Makefile.toml +++ b/Makefile.toml @@ -153,7 +153,7 @@ condition = { files_not_exist = [ "${INITRD_DIRECTORY}" ] } [tasks.initrd] cwd = "${INITRD_DIRECTORY}" command = "${TAR}" -args = [ "-cf", "${BOOTLOADER_DIRECTORY}/initrd.tar", "hello", "helloc", "shell", "uptime", "date", "mkentry" ] +args = [ "-cf", "${BOOTLOADER_DIRECTORY}/initrd.tar", "hello", "helloc", "shell", "uptime", "date", "mkdir" ] dependencies = [ "link-members" ] condition = { files_modified = { input = [ "${INITRD_DIRECTORY}/*" ], output = [ "${BOOTLOADER_DIRECTORY}/initrd.tar" ] } } diff --git a/docs/howto-add-a-syscall.md b/docs/howto-add-a-syscall.md new file mode 100644 index 0000000..07f40d6 --- /dev/null +++ b/docs/howto-add-a-syscall.md @@ -0,0 +1,30 @@ +## How to add a new system call + +### Work to be done in User Mode + +1. +You need to add an entry for your new syscall in: `os/library/syscall` +In `enum SysCall`. Insert your new system call name before `LastEntryMarker`. + +2. +For using your new System call, see examples in `os/library`. A system call is typically used within a runtime library function, not directly within an application. + +*Important: Check params before firing a syscall and abort if they are not valid.* + +3. +Return values for system calls are defined in `return_vals.rs`. This file is used by user and kernel mode parts. + + +### Work to be done in Kernel Mode + +1. +You need to add the counterpart implementation for your user mode system call in a file in `os/kernel/syscall`, e.g. `sys_naming.rs`. All syscall function names should start with the prefix `sys_`. + +*Important: It is of upmost important to have the correct signature and check params.* + +2. +Add your system call to the `SyscallTable` in `kernel/syscall/syscall_dispatcher.rs`. + +3. +The return value is `isize` and created by calling `convert_syscall_result_to_ret_code` which expects a `SyscallResult`, defined in `return_vals.rs` (see above). So kernel counterparts should use `SyscallResult` which is converted to `isize` when returning to user mode. + diff --git a/os/application/mkentry/Cargo.toml b/os/application/mkdir/Cargo.toml similarity index 91% rename from os/application/mkentry/Cargo.toml rename to os/application/mkdir/Cargo.toml index 16d6e03..5aecf45 100644 --- a/os/application/mkentry/Cargo.toml +++ b/os/application/mkdir/Cargo.toml @@ -2,13 +2,13 @@ cargo-features = ["edition2024"] [package] edition = "2024" -name = "mkentry" +name = "mkdir" version = "0.1.0" authors = ["Michael Schöttner , Fabian Ruhland "] [lib] crate-type = ["staticlib"] -path = "src/mkentry.rs" +path = "src/mkdir.rs" [dependencies] # Local dependencies diff --git a/os/application/mkentry/Makefile.toml b/os/application/mkdir/Makefile.toml similarity index 100% rename from os/application/mkentry/Makefile.toml rename to os/application/mkdir/Makefile.toml diff --git a/os/application/mkentry/src/mkentry.rs b/os/application/mkdir/src/mkdir.rs similarity index 68% rename from os/application/mkentry/src/mkentry.rs rename to os/application/mkdir/src/mkdir.rs index bc2a988..10672c6 100644 --- a/os/application/mkentry/src/mkentry.rs +++ b/os/application/mkdir/src/mkdir.rs @@ -5,7 +5,7 @@ extern crate alloc; #[allow(unused_imports)] use runtime::*; use terminal::{print, println}; -use naming::mkentry; +use naming::mkdir; #[unsafe(no_mangle)] pub fn main() { @@ -14,7 +14,7 @@ pub fn main() { println!("Arg[{}]: {}", i, arg); } - let res = mkentry("/home/schoettner", "test.txt", 1); + let res = mkdir("/home/schoettner"); - println!("app: mkentry {:?}", res); + println!("app: mkdir {:?}", res); } \ No newline at end of file diff --git a/os/kernel/src/boot.rs b/os/kernel/src/boot.rs index 0d7030d..5dc0c7c 100644 --- a/os/kernel/src/boot.rs +++ b/os/kernel/src/boot.rs @@ -9,7 +9,7 @@ */ use crate::interrupt::interrupt_dispatcher; -use crate::naming::name_service; +use crate::naming; use crate::syscall::syscall_dispatcher; use crate::process::thread::Thread; use alloc::format; @@ -247,7 +247,7 @@ pub extern "C" fn start(multiboot2_magic: u32, multiboot2_addr: *const BootInfor } // Init naming service - name_service::init(); + naming::api::init(); // Load initial ramdisk let initrd_tag = multiboot.module_tags() diff --git a/os/kernel/src/naming/api.rs b/os/kernel/src/naming/api.rs new file mode 100644 index 0000000..5167ad5 --- /dev/null +++ b/os/kernel/src/naming/api.rs @@ -0,0 +1,145 @@ +/* ╔═════════════════════════════════════════════════════════════════════════╗ + ║ Module: api ║ + ╟─────────────────────────────────────────────────────────────────────────╢ + ║ Descr.: Public interface of the name service (ns): ║ + ║ - mkdir: create a directory with all sub directories ║ + ║ - open: open a named object ║ + ║ - read: read bytes from an open object ║ + ║ - write: write bytes into an open object ║ + ║ - seek: set file pointer (for files) ║ + ║ - init: init ns, called once ║ + ║ - dump: print all entries on the screen (for debugging) ║ + ╟─────────────────────────────────────────────────────────────────────────╢ + ║ Author: Michael Schoettner, Univ. Duesseldorf, 9.9.2024 ║ + ╚═════════════════════════════════════════════════════════════════════════╝ +*/ + + +use alloc::string::String; +use syscall::return_vals::{OpenOptions, SeekOrigin, convert_syscall_result_to_ret_code}; + +use crate::naming::main; +use crate::naming::main::ns_get; +use crate::naming::open_objects::ns_get_oot; + + +/// +/// Description: +/// Init function of NS. Must be called once before using it. +/// +pub fn init() { + main::init(); +} + +/// +/// Description: Create a directory (including sub directories) for the given path +/// +/// Parameters: `path` The path +/// +/// Return: `SyscallResult` +/// +pub fn mkdir(path: &String) -> isize { + let result = ns_get().mkdir(path); + let sysret; + match result { + Ok(()) => sysret = Ok(0), // Convert the success case to a meaningful u64, e.g., 0 + Err(e) => sysret = Err(e), // Forward the error directly + } + return convert_syscall_result_to_ret_code(sysret); +} + +/// +/// Description: Open/create a named object +/// +/// Parameters: \ +/// `path` must be an absolute path \ +/// `flags` see below +/// +/// Return: `SyscallResult` +/// +pub fn open(path: &String, flags: OpenOptions) -> isize { + let res = ns_get().open(path, flags); + let sysret; + match res { + Ok(fptr) => { + sysret = ns_get_oot().lock().create_new_handle_for_filepointer(fptr); + }, + Err(e) => sysret = Err(e), + } + return convert_syscall_result_to_ret_code(sysret); + +/* match res { + Ok(fptr) => ns_get_oot().lock().create_new_handle_for_filepointer(fptr), + Err(e) => Err(e), + } + */ +} + +/// +/// Description: \ +/// Write bytes from the given buffer into the file (at the current position). \ +/// The number of bytes to be written is determined by the buffer size +/// +/// Parameters: \ +/// `fh` file handle \ +/// `buf` buffer from which bytes are copied into the file \ +/// +/// Return: `Ok(#bytes written)` or `Err(Errno)` +/// +pub fn write(fh: usize, buf: &[u8]) -> isize { + let sysret; + match ns_get_oot().lock().get(fh) { + Ok(fptr) => sysret = fptr.write(buf), + Err(e) => sysret = Err(e), + } + return convert_syscall_result_to_ret_code(sysret); +} + +/// +/// Description: Set file pointer. +/// +/// Parameters: \ +/// `fh` file handle \ +/// `offset` offset in bytes \ +/// `origin` point of origin +/// +/// Return: `Ok(size in bytes)` or `Err(errno)` +/// +pub fn seek(fh: usize, offset: usize, origin: SeekOrigin) -> isize { + let sysret; + match ns_get_oot().lock().get(fh) { + Ok(fptr) => sysret = fptr.seek(offset, origin), + Err(e) => sysret = Err(e), + } + return convert_syscall_result_to_ret_code(sysret); +} + +/// +/// Description: \ +/// Read bytes from the file (from current position) into the given buffer. \ +/// The number of bytes to be read is determined by the buffer size +/// +/// Parameters: \ +/// `fh` file handle \ +/// `buf` buffer to copy file bytes into \ +/// +/// Return: `Ok(#bytes read)` or `Err(errno)` +/// +pub fn read(fh: usize, buf: &mut [u8]) -> isize { + let sysret; + match ns_get_oot().lock().get(fh) { + Ok(fptr) => sysret = fptr.read(buf), + Err(e) => sysret = Err(e), + } + return convert_syscall_result_to_ret_code(sysret); +} + +/// +/// Description: Dump all named objects on the screen (for debugging) +/// +/// Return: `Ok(0)` or `Err(errno)` +/// +pub fn dump() -> i64 { + ns_get().dump(); + return 0; +} diff --git a/os/kernel/src/naming/directory.rs b/os/kernel/src/naming/directory.rs new file mode 100644 index 0000000..81332f1 --- /dev/null +++ b/os/kernel/src/naming/directory.rs @@ -0,0 +1,155 @@ +/* ╔═════════════════════════════════════════════════════════════════════════╗ + ║ Module: directory ║ + ╟─────────────────────────────────────────────────────────────────────────╢ + ║ Descr.: Implementation of a directoy in the naming service. ║ + ║ Following structs are defined and implemented: ║ + ║ - NsDirectoryWrapper: wraps a directory with a RwLock ║ + ║ - NsDirectory: directory storing named objects ║ + ║ Following traits are implemented: ║ + ║ - NsNode ║ + ║ - NsNodeDirectory ║ + ╟─────────────────────────────────────────────────────────────────────────╢ + ║ Author: Michael Schoettner, Univ. Duesseldorf, 7.9.2024 ║ + ╚═════════════════════════════════════════════════════════════════════════╝ +*/ +use alloc::boxed::Box; +use alloc::string::String; +use alloc::vec::Vec; +use core::any::Any; +use spin::RwLock; + +use syscall::return_vals::{OpenOptions, Errno}; + +use crate::naming::traits::*; +use crate::naming::file::NsFile; + + +/// Wraps a directory with a RwLock +#[derive(Debug)] +pub(super) struct NsDirectoryWrapper(pub(super) RwLock); + +impl NsDirectoryWrapper { + pub(super) fn new() -> Self { + NsDirectoryWrapper(RwLock::new(NsDirectory { + children: Vec::new(), + })) + } +} + +impl NsNode for NsDirectoryWrapper { + /// Returns the node type + fn get_type(&self) -> NsNodeType { + NsNodeType::Directory + } +} + +impl NsNodeDirectory for NsDirectoryWrapper { + + /// Create directories (including all sub directories) in the given path + fn mkdir(&self, components: &mut Vec<&str>) -> Result<(),Errno> { + if let Some(component) = components.pop() { + let node_name = String::from(component); + + // follow path recurively for existing sub directories + for (name, node) in &self.0.read().children { + if name == &node_name { + let opt_sub_dir = node.downcast_ref::(); + if let Some(sub_dir) = opt_sub_dir { + return sub_dir.mkdir(components); + } + } + } + + // otherweise create them + let directory = Box::new(NsDirectoryWrapper::new()); + let result = directory.mkdir(components); + self.0.write().children.push((node_name, directory)); + result + } else { + Ok(()) + } + } + + fn dump(&self, mut tabs: String) { + tabs.push_str(" "); + for (name, node) in &self.0.read().children { + if let Some(directory) = node.downcast_ref::() { + println!("{}{} ({:?})", tabs, name, self.get_type()); + directory.dump(tabs.clone()); + } else if let Some(file) = node.downcast_ref::() { + println!("{}{} ({:?})", tabs, name, file.get_type()); + } else { + println!("{}{} (Unknown))", tabs, name); + } + } + } + + fn open( + &self, + path: &mut Vec<&str>, + flags: OpenOptions, + ) -> Result, Errno> { + if let Some(path_part) = path.pop() { + let node_name = String::from(path_part); + + if path.is_empty() == true { + // reach endpoint => reach file + for (name, node) in &self.0.read().children { + if name == &node_name { + let opt_file = node.downcast_ref::(); + if let Some(file) = opt_file { + return file.get_handle(flags); + } + } + } + } + + if path.is_empty() == true { + if flags.contains(OpenOptions::CREATE) { + // Create file on demand + let file = Box::new(NsFile::new()); + let result = file.get_handle(flags); + self.0.write().children.push((node_name, file)); + + result + } else { + Err(Errno::EINVAL) + } + } else { + // traverse to the directories to the endpoint + for (name, node) in &self.0.read().children { + if name == &node_name { + let opt_dir = node.downcast_ref::(); + if let Some(directory) = opt_dir { + return directory.open(path, flags); + } + } + } + Err(Errno::EINVAL) + } + } else { + Err(Errno::EINVAL) + } + } +} + + +#[derive(Debug)] +pub(super) struct NsDirectory { + children: Vec<( + String, + Box, + )>, +} + + +/// Helper function to check if the argument is an abolute path +pub fn check_absolute_path(path: &String) -> bool { + if let Some(pos) = path.find('/') { + if pos == 0 { + return true; + } + } + + false +} diff --git a/os/kernel/src/naming/file.rs b/os/kernel/src/naming/file.rs new file mode 100644 index 0000000..a7c955c --- /dev/null +++ b/os/kernel/src/naming/file.rs @@ -0,0 +1,143 @@ +/* ╔═════════════════════════════════════════════════════════════════════════╗ + ║ Module: ns_file ║ + ╟─────────────────────────────────────────────────────────────────────────╢ + ║ Descr.: Implementation of files stored in the heap (). ║ + ║ Following structs are defined and implemented: ║ + ║ - NsFile ║ + ║ Following traits are implemented: ║ + ║ - NsNode ║ + ║ - NsNodeFile ║ + ║ - NsOpenFile ║ + ╟─────────────────────────────────────────────────────────────────────────╢ + ║ Author: Michael Schoettner, Univ. Duesseldorf, 15.9.2024 ║ + ╚═════════════════════════════════════════════════════════════════════════╝ +*/ +use alloc::boxed::Box; +use alloc::sync::Arc; +use alloc::vec::Vec; +use core::sync::atomic::AtomicUsize; +use core::sync::atomic::Ordering::SeqCst; +use spin::RwLock; + +use syscall::return_vals::{Errno, OpenOptions, SeekOrigin}; +use crate::naming::traits::*; + +/// NsFile is the actual file with its data +#[derive(Debug)] +pub(super) struct NsFile { + /// Position within the file + pos: AtomicUsize, + /// File content + data: Arc>>, +} + +impl Clone for NsFile { + fn clone(&self) -> Self { + NsFile { + pos: AtomicUsize::new(self.pos.load(core::sync::atomic::Ordering::SeqCst)), + data: self.data.clone(), + } + } +} + +impl NsFile { + pub fn new() -> Self { + NsFile { + pos: AtomicUsize::new(0), + data: Arc::new(RwLock::new(Vec::new())), + } + } +} + +/// Implement `NsNode` operations for `NsFile` +impl NsNode for NsFile { + fn get_type(&self) -> NsNodeType { + NsNodeType::File + } +} + +/// Implement `NsNodeFile` operations for `NsFile` +impl NsNodeFile for NsFile { + fn get_handle(&self, opt: OpenOptions) -> Result, Errno> { + Ok(Box::new(NsFile { + pos: AtomicUsize::new(0), + data: self.data.clone(), + })) + } +} + +/// Implement `FilePointer` operations for `NsFile` +impl NsOpenFile for NsFile { + + fn read(&self, buf: &mut [u8]) -> Result { + let guard = self.data.read(); + let vec: &[u8] = guard.as_ref(); + let pos: usize = self.pos.load(SeqCst); + + if pos >= vec.len() { + return Ok(0); + } + + let len; + if vec.len() - pos < buf.len() { + len = vec.len() - pos + } else { + len = buf.len() + } + + buf[0..len].clone_from_slice(&vec[pos..pos + len]); + self.pos.fetch_add(len, SeqCst); + Ok(len) + } + + fn write(&self, buf: &[u8]) -> Result { + let mut guard = self.data.write(); + let vec: &mut Vec = guard.as_mut(); + let pos = self.pos.load(SeqCst); + + if pos + buf.len() > vec.len() { + vec.resize(pos + buf.len(), 0); + } + + vec[pos..pos + buf.len()].clone_from_slice(buf); + + self.pos.fetch_add( buf.len(), SeqCst); + + Ok(buf.len()) + } + + fn size(&self) -> usize { + let guard = self.data.read(); + let vec: &[u8] = guard.as_ref(); + vec.len() as usize + } + + fn seek(&self, offset: usize, origin: SeekOrigin) -> Result { + match origin { + SeekOrigin::Start => { + let pos = self.pos.store(offset, SeqCst); + Ok(offset as usize) + } + SeekOrigin::End => { + let guard = self.data.read(); + let ref vec: &Vec = guard.as_ref(); + let data = vec.len() as usize + offset; + if data >= 0 { + let pos = self.pos.store(data, SeqCst); + Ok(data as usize) + } else { + Err(Errno::EINVAL) + } + } + SeekOrigin::Current => { + let pos: i64 = self.pos.load(SeqCst) as i64 + offset as i64; + if pos >= 0 { + self.pos.store(pos as usize, SeqCst); + Ok(pos as usize) + } else { + Err(Errno::EINVAL) + } + } + } + } +} diff --git a/os/kernel/src/naming/main.rs b/os/kernel/src/naming/main.rs new file mode 100644 index 0000000..a11b584 --- /dev/null +++ b/os/kernel/src/naming/main.rs @@ -0,0 +1,102 @@ +/* ╔═════════════════════════════════════════════════════════════════════════╗ + ║ Module: main ║ + ╟─────────────────────────────────────────────────────────────────────────╢ + ║ Descr.: Main module of the implementation of the naming service (ns). ║ + ║ - NS: global entry point ║ + ║ Following traits are implemented: ║ + ║ - NsInterface: all operations provided by the naming service║ + ╟─────────────────────────────────────────────────────────────────────────╢ + ║ Author: Michael Schoettner, Univ. Duesseldorf, 15.9.2024 ║ + ╚═════════════════════════════════════════════════════════════════════════╝ +*/ +use alloc::boxed::Box; +use alloc::string::String; +use alloc::sync::Arc; +use alloc::vec::Vec; +use core::fmt::Debug; +use spin::Once; + +use syscall::return_vals::{Errno, OpenOptions}; + +use crate::naming::traits::*; +use crate::naming::directory::{NsDirectoryWrapper,check_absolute_path}; +use crate::naming::open_objects::ns_open_object_table_init; + + +/// Entrypoint of the naming service +pub(super) static NS: Once> = Once::new(); + +/// Init `NS` once +pub(super) fn init() { + NS.call_once(|| Arc::new(Ns::new())); + ns_open_object_table_init(); +} + +/// Helper function returning safe access to the naming service +pub(super) fn ns_get() -> Arc { + let ns = NS.get(); + return ns.unwrap().clone(); +} + +/// Entrypoint of the naming service +#[derive(Debug)] +pub(super) struct Ns { + /// root directory + root_dir: Arc, +} + +impl Ns { + pub fn new() -> Ns { + Ns { + root_dir: Arc::new(NsDirectoryWrapper::new()), + } + } + + /// return root directory of the naming service + pub fn root_dir(&self) -> &Arc { + &self.root_dir + } +} + +impl NsInterface for Ns { + + /// Create a directory (including all sub directories) + fn mkdir(&self, path: &String) -> Result<(), Errno> { + if check_absolute_path(path) { + let mut components: Vec<&str> = path.split("/").collect(); + + components.reverse(); + components.pop(); + + // get root directory and create directories as needed + self.root_dir().clone().mkdir(&mut components) + } else { + Err(Errno::ENOENT) + } + } + + /// Dump all nodes in the naming service (for debugging) + fn dump(&self) { + println!("/"); + + // get root directory and create directories as needed + self.root_dir().clone().dump(String::from("")); + } + + fn open(&self, path: &String, flags: OpenOptions)-> Result, Errno> { + if check_absolute_path(path) { + let mut components: Vec<&str> = path.split("/").collect(); + + components.reverse(); + components.pop(); + + // get root directory and open the desired file + self + .root_dir() + .clone() + .open(&mut components, flags) + } else { + Err(Errno::ENOENT) + } + } +} diff --git a/os/kernel/src/naming/mod.rs b/os/kernel/src/naming/mod.rs index 888feed..242d218 100644 --- a/os/kernel/src/naming/mod.rs +++ b/os/kernel/src/naming/mod.rs @@ -1,5 +1,11 @@ + + +pub mod api; pub mod stat; -pub mod name_service; -mod name_service_internal; -pub mod name_service_tests; + +mod traits; +mod main; +mod file; +mod directory; +mod open_objects; diff --git a/os/kernel/src/naming/name_service.rs b/os/kernel/src/naming/name_service.rs deleted file mode 100644 index ac9f6b7..0000000 --- a/os/kernel/src/naming/name_service.rs +++ /dev/null @@ -1,128 +0,0 @@ -/* ╔═════════════════════════════════════════════════════════════════════════╗ - ║ Module: name_service ║ - ╟─────────────────────────────────────────────────────────────────────────╢ - ║ Descr.: API of name service. ║ - ╟─────────────────────────────────────────────────────────────────────────╢ - ║ Author: Michael Schoettner, 30.8.2024, HHU ║ - ╚═════════════════════════════════════════════════════════════════════════╝ -*/ -use alloc::sync::Arc; -use alloc::vec::Vec; -use syscall::return_vals::{SyscallResult,Errno}; -use ::log::info; - -use crate::naming::name_service_internal; -use crate::naming::name_service_internal::get_root_dir; -use crate::naming::stat::Stat; - -pub type Result = ::core::result::Result; - - - -// Wrapper function to convert Result<(), Errno> to SyscallResult -fn convert_result(result: core::result::Result<(), Errno>) -> SyscallResult { - match result { - Ok(()) => Ok(0), // Convert the success case to a meaningful u64, e.g., 0 - Err(e) => Err(e), // Forward the error directly - } -} - -/// -/// Description: -/// Add an entry (with or without data) -/// -/// Parameters: \ -/// `path` path (must exist) \ -/// `name` name for the new entry \ -/// `content` data bytes -/// -pub fn mkentry(path: &str, name: &str, content: Vec) -> SyscallResult { - convert_result(get_root_dir().mkentry(path, name, content)) -} - - -/// -/// Description: -/// Add a directory. Creates all sub directories for the given path (if they do not exist already) -/// -/// Parameters: \ -/// `path` path to be created -/// -pub fn mkdir(path: &str) -> SyscallResult { - convert_result(get_root_dir().mkdir(path)) -} - -/// -/// Description: -/// Get `stat` info for the given entry -/// -/// Parameters: \ -/// `path` path to entry -/// -pub fn stat(path: &str) -> Result { - get_root_dir().stat(path) -} - -/// -/// Description: -/// Get container contents for the given entry -/// -/// Parameters: \ -/// `path` path to entry -/// -pub fn cont(path: &str) -> Result> { - get_root_dir().cont(path) -} - -/// -/// Description: -/// Get directory content for the given directory -/// -/// Parameters: \ -/// `path` path to directory -/// -pub fn dir(path: &str) -> Result> { - get_root_dir().dir(path) -} - -/// -/// Description: -/// Rename a naming service entry. -/// -/// Parameters: \ -/// `path` path&entry name \ -/// `new_name` new name -/// -pub fn rename(path: &str, new_name: &str) -> SyscallResult { - convert_result(get_root_dir().rename(path, new_name)) -} - -/// -/// Description: -/// Rename a naming service entry. -/// -/// Parameters: \ -/// `path` path&entry name -/// -pub fn del(path: &str) -> SyscallResult { - convert_result(get_root_dir().del(path)) -} - -/// -/// Description: -/// Dump full name space -/// -pub fn dump() { - get_root_dir().dump(0); -} - -/// -/// Description: -/// Init naming service (called only once during booting) -/// -pub fn init() { - name_service_internal::NAME_SERVICE - .call_once(|| Arc::new(name_service_internal::NameService::new())); - info!("Initialized"); -} - diff --git a/os/kernel/src/naming/name_service_internal.rs b/os/kernel/src/naming/name_service_internal.rs deleted file mode 100644 index b6deb75..0000000 --- a/os/kernel/src/naming/name_service_internal.rs +++ /dev/null @@ -1,397 +0,0 @@ -/* ╔═════════════════════════════════════════════════════════════════════════╗ - ║ Module: name_service_interal ║ - ╟─────────────────────────────────────────────────────────────────────────╢ - ║ Descr.: Internal implementation of name service. ║ - ╟─────────────────────────────────────────────────────────────────────────╢ - ║ Author: Michael Schoettner, 29.8.2024, HHU ║ - ╚═════════════════════════════════════════════════════════════════════════╝ -*/ -use syscall::return_vals::Errno; -use crate::naming::stat; -use crate::naming::stat::Mode; -use crate::naming::stat::Stat; -use crate::naming::name_service::Result; - -use alloc::boxed::Box; -use alloc::string::ToString; -use alloc::sync::Arc; -use alloc::vec::Vec; -use core::fmt::Debug; -use core::mem; - -use spin::{Once, RwLock}; - -/// helper function returning `root_dir` -pub(super) fn get_root_dir() -> Arc { - let root = NAME_SERVICE.get(); - let root_dir = root.unwrap().root_dir(); - root_dir.clone() -} - -pub(super) static NAME_SERVICE: Once> = Once::new(); - -pub(super) struct NameService { - root_dir: Arc, -} - -impl NameService { - pub(super) fn new() -> NameService { - NameService { - root_dir: Arc::new(Directory::new()), - } - } - - fn root_dir(&self) -> &Arc { - &self.root_dir - } -} - -#[derive(Debug)] -pub(super) struct Directory(RwLock); - -#[derive(Debug, Clone)] -struct DirectoryInner { - entries: Vec, -} - -#[derive(Debug, Clone)] -pub struct DirEntry { - entry_type: EntryType, - stat: Stat, -} - -#[derive(Debug, Clone)] -enum EntryType { - Container(Container), - Directory(Box), -} - -#[derive(Debug, Clone)] -struct Container { - content: Vec, -} - -impl Directory { - fn new() -> Self { - Directory(RwLock::new(DirectoryInner { - entries: Vec::new(), - })) - } - - /// - /// Create directory (with all sub directories) - /// - pub(super) fn mkdir(&self, path: &str) -> Result<()> { - let parts: Vec<&str> = path.split('/').filter(|s| !s.is_empty()).collect(); - self.mkdir_in_dir(&parts) - } - - // Helper function to recursively add sub directories as needed - fn mkdir_in_dir(&self, parts: &[&str]) -> Result<()> { - let mut dir = self.0.write(); - - // If no more path parts, we did not find the file - if parts.is_empty() { - return Ok(()); - } - - // Find the directory matching the current part - let current_part = parts[0]; - let remaining_parts = &parts[1..]; - for entry in &dir.entries { - if entry.stat.name == current_part { - // entry found, continue recursively, if more to do - if let EntryType::Directory(ref dir) = entry.entry_type { - if remaining_parts.is_empty() { - return Err(Errno::EEXIST); // we are done, dir already exists - } else { - return dir.mkdir_in_dir(remaining_parts); // continue recursively - } - } else { - // found file with same name, abort - return Err(Errno::ENOTDIR); - } - } - } - - // directory not found -> create it and continue recursively - - let new_entry = DirEntry::new_directory(Stat::new( - current_part.to_string(), - Mode::new(stat::MODE_DIR), - 0, - )); - dir.entries.push(new_entry); - - // Retrieve the newly created directory - if let EntryType::Directory(ref mut new_dir) = dir.entries.last_mut().unwrap().entry_type { - return new_dir.mkdir_in_dir(remaining_parts); - } else { - return Err(Errno::EEXIST); // This should not happen - } - } - - /// - /// Register a new entry in the given `path` - /// - pub(super) fn mkentry(&self, path: &str, name: &str, content: Vec) -> Result<()> { - let element_size = mem::size_of::(); - let total_size = element_size * content.len(); - - let stat = Stat::new(name.to_string(), Mode::new(stat::MODE_CONT), total_size); - - let new_entry = DirEntry::new_file(stat, content); - let parts: Vec<&str> = path.split('/').filter(|s| !s.is_empty()).collect(); - self.mkentry_in_dir(&parts, new_entry) - } - - /// Recursive helper function for `mkentry` - fn mkentry_in_dir(&self, parts: &[&str], new_entry: DirEntry) -> Result<()> { - let mut dir = self.0.write(); - - // If no more path parts, add the entry to the current directory - if parts.is_empty() { - for entry in &dir.entries { - if entry.stat.name == new_entry.stat.name { - return Err(Errno::EEXIST); // file already exists - } - } - dir.entries.push(new_entry); - return Ok(()); - } - - // Recusively navigate to the right sub directory - let current_part = parts[0]; - let remaining_parts = &parts[1..]; - for entry in &dir.entries { - if entry.stat.name == current_part { - if let EntryType::Directory(ref directory) = entry.entry_type { - return directory.mkentry_in_dir(remaining_parts, new_entry); - } else { - return Err(Errno::ENOENT); // sub directory not found - } - } - } - return Err(Errno::ENOENT); - } - - /// - /// Retrieve `stat` info for a given entry - /// - pub(super) fn stat(&self, path: &str) -> Result { - let parts: Vec<&str> = path.split('/').filter(|s| !s.is_empty()).collect(); - match self.get_dentry(&parts) { - Ok(dentry) => Ok(dentry.stat), - Err(e) => Err(e), - } - } - - /// - /// Retrieve content for a given container - /// - pub(super) fn cont(&self, path: &str) -> Result> { - let parts: Vec<&str> = path.split('/').filter(|s| !s.is_empty()).collect(); - match self.get_dentry(&parts) { - Ok(dentry) => { - // check if this is a container - if let EntryType::Container(ref entry) = dentry.entry_type { - // yes, return the content - return Ok(entry.content.clone()); - } else { - // no, error - return Err(Errno::ENOENT); - } - } - Err(e) => Err(e), - } - } - - /// - /// Retrieve content for a given directory - /// - pub(super) fn dir(&self, path: &str) -> Result> { - let parts: Vec<&str> = path.split('/').filter(|s| !s.is_empty()).collect(); - match self.get_dentry(&parts) { - Ok(dentry) => { - // check if this is a directory - if let EntryType::Directory(ref dentry) = dentry.entry_type { - // yes, return the content - let mut ret: Vec = Vec::new(); - for entry in &dentry.0.read().entries { - ret.push(entry.stat.clone()); - } - return Ok(ret); - } else { - // no, error - return Err(Errno::ENOENT); - } - } - Err(e) => Err(e), - } - } - - /// Recursive helper function for looking up a dentry for read access (returns a clone) - fn get_dentry(&self, parts: &[&str]) -> Result { - let dir = self.0.read(); - - // If no more path parts, we did not find the file - if parts.is_empty() { - return Err(Errno::ENOENT); - } - - // Recusively navigate to the right sub directory - let current_part = parts[0]; - let remaining_parts = &parts[1..]; - for entry in &dir.entries { - if entry.stat.name == current_part { - if remaining_parts.is_empty() { - return Ok(entry.clone()); - } else if let EntryType::Directory(ref directory) = entry.entry_type { - return directory.get_dentry(remaining_parts); - } else { - return Err(Errno::ENOENT); - } - } - } - return Err(Errno::ENOENT); - } - - /// Rename given entry (any type) - pub fn rename(&self, path: &str, new_name: &str) -> Result<()> { - let parts: Vec<&str> = path.split('/').filter(|s| !s.is_empty()).collect(); - self.rename_internal(&parts, new_name) - } - - /// Recursive helper function for looking up an entry and rename it, if found - fn rename_internal(&self, parts: &[&str], new_name: &str) -> Result<()> { - let mut dir = self.0.write(); - - // If no more path parts, we did not find the file - if parts.is_empty() { - return Err(Errno::ENOENT); - } - - // Recusively navigate to the right sub directory - let current_part = parts[0]; - let remaining_parts = &parts[1..]; - for entry in &mut dir.entries { - if entry.stat.name == current_part { - if remaining_parts.is_empty() { - entry.stat.name = new_name.to_string(); - return Ok(()); - } else if let EntryType::Directory(ref directory) = entry.entry_type { - return directory.rename_internal(remaining_parts, new_name); - } else { - return Err(Errno::ENOENT); - } - } - } - return Err(Errno::ENOENT); - } - - /// Delete given entry (any type) - pub fn del(&self, path: &str) -> Result<()> { - // Check if we have a path to a directory which is empty - match self.dir(path) { - // Dir found? - Ok(s) => { - // Yes, is it empty? - if s.len() == 0 { - let parts: Vec<&str> = path.split('/').filter(|s| !s.is_empty()).collect(); - return self.del_internal(&parts); - } - // If we found a dire which is not empty, return an error - else { - return Err(Errno::ENOTEMPTY); - } - } - // No dir found?, we continue below - Err(_e) => { - // Check if we have a path to a container/symlink - match self.stat(path) { - // Entry found? - Ok(_s) => { - let parts: Vec<&str> = path.split('/').filter(|s| !s.is_empty()).collect(); - return self.del_internal(&parts); - } - // No dir found?, we continue below - Err(_e) => { - return Err(Errno::ENOENT); - } - } - } - } - } - - /// Recursive helper function for looking up an entry and delete it, if found - fn del_internal(&self, parts: &[&str]) -> Result<()> { - let current_part = parts[0]; - let remaining_parts = &parts[1..]; - let mut dir = self.0.write(); - - // Last part -> remove entry and return - if remaining_parts.is_empty() { - dir.entries.retain(|entry| entry.stat.name != current_part); - return Ok(()); - } - // Recusively navigate to the right sub directory - else { - for entry in &mut dir.entries { - if entry.stat.name == current_part { - if let EntryType::Directory(ref directory) = entry.entry_type { - return directory.del_internal(remaining_parts); - } else { - return Err(Errno::ENOENT); - } - } - } - } - - return Err(Errno::ENOENT); - } - - /// - /// Debug function dumping full naming service content - /// - pub(super) fn dump(&self, depth: usize) { - let indent = " ".repeat(depth); - for entry in &self.0.read().entries { - match &entry.entry_type { - EntryType::Container(_file) => { - println!("{}[F] {}, {:?}", indent, entry.stat.name, entry.stat); - //println!("{} [F]: {}, size: {}", indent, file.name, entry.stat.size) - } - EntryType::Directory(dir) => { - println!("{}[D] {}", indent, entry.stat.name); - dir.dump(depth + 1); - } - } - } - } -} - -// Implement Clone for Directory manually to handle the RwLock -impl Clone for Directory { - fn clone(&self) -> Self { - // Clone the inner DirectoryInner - let inner_clone = self.0.read().clone(); - Directory(RwLock::new(inner_clone)) - } -} - -impl DirEntry { - fn new_file(stat: Stat, content: Vec) -> Self { - let c = content.clone(); - DirEntry { - entry_type: EntryType::Container(Container { content: c }), - stat, - } - } - - fn new_directory(stat: Stat) -> Self { - DirEntry { - entry_type: EntryType::Directory(Box::new(Directory::new())), - stat, - } - } -} diff --git a/os/kernel/src/naming/name_service_tests.rs b/os/kernel/src/naming/name_service_tests.rs deleted file mode 100644 index 579f185..0000000 --- a/os/kernel/src/naming/name_service_tests.rs +++ /dev/null @@ -1,275 +0,0 @@ -/* ╔═════════════════════════════════════════════════════════════════════════╗ - ║ Module: name_service_tests ║ - ╟─────────────────────────────────────────────────────────────────────────╢ - ║ Descr.: Test all API functions of the naming service. ║ - ╟─────────────────────────────────────────────────────────────────────────╢ - ║ Author: Michael Schoettner, 1.8.2024, HHU ║ - ╚═════════════════════════════════════════════════════════════════════════╝ -*/ -use alloc::vec; -use ::log::info; - -use crate::naming::name_service::{cont, del, dir, mkdir, mkentry, rename, stat}; -use syscall::return_vals::Errno; - -/// -/// Description: -/// Init naming service (called only once during booting) -/// -pub fn run_tests() { - info!("name_service: running tests"); - - test_mkdir(); - test_mkentry(); - test_stat(); - test_cont(); - test_dir(); - test_del(); - test_rename(); - - info!("name_service: all tests passed."); -} - -/// -/// Description: -/// Should create following directories: \ -/// `/home/schoettner` \ -/// `/home/ruhland` -/// -fn test_mkdir() { - // Create directory & subdirectory -> should work - let path = "/home/schoettner"; - let r = mkdir(path); - assert!(r == Ok(0), "mkdir(\"{}\") -> {:?}", path, r); - - // Create directory & subdirectory -> should work - let path = "/home/ruhland"; - let r = mkdir("/home/ruhland"); - assert!(r == Ok(0), "mkdir(\"{}\") -> {:?}", path, r); - - // Create same directory & subdirectory -> should fail - let r = mkdir("/home/schoettner"); - assert!( - r == Err(Errno::EEXIST), - "mkdir(\"{}\") -> {:?}", - path, - r - ); - - // Create same parent directory -> should fail - let r = mkdir("/home"); - assert!( - r == Err(Errno::EEXIST), - "mkdir(\"{}\") -> {:?}", - path, - r - ); - - info!(" test 'mkdir': passed"); -} - -/// -/// Description: -/// Should create following containers: \ -/// `/home/schoettner/brief.txt` \ -/// `/home/ruhland/klausur.txt` -/// -fn test_mkentry() { - // Create container entry in existing directory -> should work - let path = "/home/schoettner"; - let name = "brief.txt"; - let r = mkentry(path, name, vec![1, 1, 1, 1, 1]); - assert!(r == Ok(0), "mkdir(\"{}\", \"{}\") -> {:?}", path, name, r); - - // Create container entry in existing directory -> should work - let path = "/home/ruhland"; - let name = "klausur.txt"; - let r = mkentry(path, name, vec![1, 1, 1, 1, 1]); - assert!(r == Ok(0), "mkdir(\"{}\", \"{}\") -> {:?}", path, name, r); - - // Create container in non-existing directory -> should fail - let path = "/home/krakowski"; - let name = "brief.txt"; - let r = mkentry(path, name, vec![1, 1, 1, 1, 1]); - assert!( - r == Err(Errno::ENOENT), - "mkdir(\"{}\", \"{}\") -> {:?}", - path, - name, - r - ); - - // Create container entry which already exists -> should fail - let path = "/home/schoettner"; - let name = "brief.txt"; - let r = mkentry(path, name, vec![1, 1, 1, 1, 1]); - assert!( - r == Err(Errno::EEXIST), - "mkdir(\"{}\", \"{}\") -> {:?}", - path, - name, - r - ); - - info!(" test 'mkentry': passed"); -} - -/// -/// Description: -/// Testing `stat` -/// -fn test_stat() { - // Get stat from existing container -> should work - let pathname = "/home/schoettner/brief.txt"; - let r = stat(pathname); - assert!(r.is_ok(), "stat(\"{}\") failed -> {:?}", pathname, r); - - // Get stat from existing directory -> should work - let pathname = "/home/schoettner"; - let r = stat(pathname); - assert!(r.is_ok(), "stat(\"{}\") failed -> {:?}", pathname, r); - - // Get stat from non-existing container -> should fail - let pathname = "/home/ruhland/brief.txt"; - let r = stat(pathname); - assert!(r.is_err(), "stat(\"{}\") did not fail -> {:?}", pathname, r); - - // Get stat from non-existing directory -> should fail - let pathname = "/home/krakowski"; - let r = stat(pathname); - assert!(r.is_err(), "stat(\"{}\") did not fail -> {:?}", pathname, r); - - info!(" test 'stat': passed"); -} - -/// -/// Description: -/// Testing `cont` -/// -fn test_cont() { - // Get existing container -> should work - let pathname = "/home/schoettner/brief.txt"; - let r = cont(pathname); - assert!(r.is_ok(), "cont(\"{}\") failed -> {:?}", pathname, r); - - // Get cont on existing directory -> should work - let pathname = "/home/schoettner"; - let r = cont(pathname); - assert!(r.is_err(), "cont(\"{}\") did not fail -> {:?}", pathname, r); - - // Get cont from non-existing container -> should fail - let pathname = "/home/ruhland/brief.txt"; - let r = cont(pathname); - assert!(r.is_err(), "stat(\"{}\") did not fail -> {:?}", pathname, r); - - // Get cont from non-existing directory -> should fail - let pathname = "/home/krakowski"; - let r = cont(pathname); - assert!(r.is_err(), "stat(\"{}\") did not fail -> {:?}", pathname, r); - - info!(" test 'cont': passed"); -} - -/// -/// Description: -/// Testing `dir` -/// -fn test_dir() { - // Get existing directory -> should work - let pathname = "/home/schoettner"; - let r = dir(pathname); - assert!(r.is_ok(), "dir(\"{}\") failed -> {:?}", pathname, r); - - // Try to get non-existing directory -> should fail - let pathname = "/home/krakowski"; - let r = cont(pathname); - assert!(r.is_err(), "dir(\"{}\") did not fail -> {:?}", pathname, r); - - // Get existing container -> should fail - let pathname = "/home/schoettner/brief.txt"; - let r = dir(pathname); - assert!(r.is_err(), "dir(\"{}\") did not fail -> {:?}", pathname, r); - - info!(" test 'dir': passed"); -} - -/// -/// Description: -/// Testing `del` -/// -fn test_del() { - // Delete non-existing entry -> should fail - let pathname = "/home/schoettner2"; - let r = del(pathname); - assert!(r.is_err(), "del(\"{}\") did not fail -> {:?}", pathname, r); - - // Delete existing but not empty directory -> should fail - let pathname = "/home/schoettner"; - let r = del(pathname); - assert!(r.is_err(), "del(\"{}\") did not fail -> {:?}", pathname, r); - - // Delete empty existing subdirectory -> should work - let pathname = "/home/krakowski"; - let r = mkdir(pathname); - assert!(r == Ok(0), "mkdir(\"{}\") -> {:?}", pathname, r); - let r = del(pathname); - assert!(r == Ok(0), "del(\"{}\") -> {:?}", pathname, r); - - // Delete existing container -> should work - let pathname = "/home/schoettner/brief.txt"; - let r = del(pathname); - assert!(r == Ok(0), "del(\"{}\") -> {:?}", pathname, r); - - info!(" test 'del': passed"); -} - -/// -/// Description: -/// Testing `rename` -/// -fn test_rename() { - // Create container entry in existing directory -> should work - let path = "/home/schoettner"; - let name = "brief.txt"; - let r = mkentry(path, name, vec![1, 1, 1, 1, 1]); - assert!(r == Ok(0), "mkdir(\"{}\", \"{}\") -> {:?}", path, name, r); - - // Rename existing container -> should work - let pathname = "/home/schoettner/brief.txt"; - let new_name = "email.txt"; - let r = rename(pathname, new_name); - assert!( - r == Ok(0), - "rename(\"{}\", \"{}\") -> {:?}", - pathname, - new_name, - r - ); - - // Rename existing directory -> should work - let pathname = "/home/schoettner"; - let new_name = "krakowski"; - let r = rename(pathname, new_name); - assert!( - r == Ok(0), - "rename(\"{}\", \"{}\") -> {:?}", - pathname, - new_name, - r - ); - - // Try to rename non-existing directory -> should fail - // Rename existing directory -> should work - let pathname = "/home/schoettner"; - let new_name = "krakowski"; - let r = rename(pathname, new_name); - assert!(r.is_err(), "rename(\"{}\") did not fail -> {:?}", pathname, r); - - // Try to rename non-existing container -> should fail - let pathname = "/home/krakowski/brief.txt"; - let new_name = "email.txt"; - let r = rename(pathname, new_name); - assert!(r.is_err(), "rename(\"{}\") did not fail -> {:?}", pathname, r); - - info!(" test 'rename': passed"); -} diff --git a/os/kernel/src/naming/open_objects.rs b/os/kernel/src/naming/open_objects.rs new file mode 100644 index 0000000..dc3ab5c --- /dev/null +++ b/os/kernel/src/naming/open_objects.rs @@ -0,0 +1,87 @@ +/* ╔═════════════════════════════════════════════════════════════════════════╗ + ║ Module: open_objects ║ + ╟─────────────────────────────────────────────────────────────────────────╢ + ║ Descr.: Managing all open objects in the open object table (oot). This ║ + ║ table stores tuples (usize, NsOpenFile). ║ + ║ The number of max. open objects is limited by MAX_OPEN_OBJECTS ║ + ╟─────────────────────────────────────────────────────────────────────────╢ + ║ Author: Michael Schoettner, Univ. Duesseldorf, 15.9.2024 ║ + ╚═════════════════════════════════════════════════════════════════════════╝ +*/ +use alloc::sync::Arc; +use alloc::boxed::Box; +use spin::{Mutex, Once}; +use alloc::vec::Vec; +use core::result::Result; + +use syscall::return_vals::{SyscallResult, Errno}; + +use crate::naming::traits::NsOpenFile; + + +/// Max. number of open objetcs +const MAX_OPEN_OBJECTS: usize = 0x100; + +/// Helper function returning safe access to the open object table (oot) +pub(super) fn ns_get_oot() -> Arc> { + let oot = NS_OPEN_OBJECTS.get(); + return oot.unwrap().clone(); +} + + +static NS_OPEN_OBJECTS: Once>> = Once::new(); + +pub fn ns_open_object_table_init() { + NS_OPEN_OBJECTS.call_once(|| Arc::new(Mutex::new(NsOpenObjectTable::new()))); +} + + +pub(super) struct NsOpenObjectTable { + open_handles: Vec< (usize, Option>>) >, + free_handles: [usize; MAX_OPEN_OBJECTS], +} + +impl NsOpenObjectTable { + + fn new() -> NsOpenObjectTable { + NsOpenObjectTable { + open_handles: Vec::new(), + free_handles: [0; MAX_OPEN_OBJECTS], + } + } + + /// Get `NsOpenFile` for a given handle, if possible + pub fn get(&self, file_handle: usize) -> Result<&Arc>, Errno> { + for (fh,fptr) in &self.open_handles { + if *fh == file_handle { + match fptr { + Some(v) => return Ok(v), + _ => return Err(Errno::EINVALH), + } + } + } + return Err(Errno::EINVALH); + } + + fn find_free_handle(&mut self) -> Option { + for (index, &value) in self.free_handles.iter().enumerate() { + if value == 0 { + self.free_handles[index] = 1; + return Some(index); + } + } + None + } + + pub(super) fn create_new_handle_for_filepointer(&mut self, fp: Box) -> SyscallResult { + let opt_new_handle = self.find_free_handle(); + if opt_new_handle.is_none() { + return Err(Errno::ENOHANDLES); + } + let new_handle = opt_new_handle.unwrap(); + self.open_handles.push( (new_handle, Some(Arc::new(fp)) )); + Ok(new_handle) + } + +} + diff --git a/os/kernel/src/naming/traits.rs b/os/kernel/src/naming/traits.rs new file mode 100644 index 0000000..dc3144f --- /dev/null +++ b/os/kernel/src/naming/traits.rs @@ -0,0 +1,116 @@ +/* ╔═════════════════════════════════════════════════════════════════════════╗ + ║ Module: traits ║ + ╟─────────────────────────────────────────────────────────────────────────╢ + ║ Descr.: All internal traits used within the naming service (ns). ║ + ║ - NsInterface: specifies all operations provided by the ns ║ + ║ - NsNode: trait defining all operations on a named object ║ + ║ - NsNodeDirectory: specifies all operations on a directory ║ + ║ - NsNodeFile: trait defining all operations on a file ║ + ║ - NsOpenFile: specifies all operations on an open file ║ + ╟─────────────────────────────────────────────────────────────────────────╢ + ║ Author: Michael Schoettner, Univ. Duesseldorf, 12.9.2024 ║ + ╚═════════════════════════════════════════════════════════════════════════╝ +*/ +use alloc::vec::Vec; +use alloc::boxed::Box; +use alloc::string::String; +use core::fmt::Debug; +use core::result::Result; + +use syscall::return_vals::{OpenOptions, Errno, SeekOrigin}; + + +/// Types of a node stored in the naming service +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum NsNodeType { + File, + Directory, +} + +/// `NsInterface` specifies all operations provided by the naming service +pub(super) trait NsInterface: Debug + Send + Sync { + /// Create a directory (including all sub directories) + fn mkdir(&self, path: &String) -> Result<(),Errno>; + + /// Open the file given in `path` (must be absolute) + /// Options for opening files + /// Returns a file handle on success + fn open(&self, path: &String, flags: OpenOptions) -> Result, Errno>; + + /// Dump all nodes in the naming service (for debugging) + fn dump(&self); +} + +/// `NsNode` defines all operations for a node in the the ns +pub(super) trait NsNode: Debug + Send + Sync { + /// Determines the current node type + fn get_type(&self) -> NsNodeType; +} + +/// `NsNodeFile` represents a file node of the naming service +pub trait NsNodeFile: NsNode + Debug + Send + Sync { + /// Create a file handle to the current file + fn get_handle(&self, _opt: OpenOptions) -> Result, Errno>; +} + + +/// `NsNodeDirectory` specifies all operations on a directory +pub(super) trait NsNodeDirectory : NsNode + Debug + Send + Sync +{ + /// Helper function to create a new dirctory node + fn mkdir(&self, _components: &mut Vec<&str>) -> Result<(),Errno>; + + /// Helper function to open a file + fn open( + &self, + path: &mut Vec<&str>, + _flags: OpenOptions, + ) -> Result, Errno>; + + /// Helper function to print the current state of the file system + fn dump(&self, _tabs: String); +} + +/// Description: This trait defines all functions that can be applied to an open file +pub(super) trait NsOpenFile: Debug + Send + Sync { + + /// + /// Description: \ + /// Read bytes from the file (from current position) into the given buffer. \ + /// The number of bytes to be read is determined by the buffer size + /// + /// Parameters: `buf` buffer to copy file bytes into + /// + /// Return: `Ok(#bytes read)` or `Err(errno)` + /// + fn read(&self, buf: &mut [u8]) -> Result; + + /// + /// Description: \ + /// Write bytes from the given buffer into the file (at the current position). \ + /// The number of bytes to be written is determined by the buffer size + /// + /// Parameters: `buf` buffer from which bytes are copied into the file + /// + /// Return: `Ok(#bytes written)` or `Err(errno)` + /// + fn write(&self, buf: &[u8]) -> Result; + + /// + /// Description: Get file size. + /// + /// Return: `Ok(size in bytes)` or `Err(errno)` + /// + fn size(&self) -> usize; + + /// + /// Description: Set file pointer. + /// + /// Parameters: \ + /// `offset` offset in bytes \ + /// `origin` point of origin + /// + /// Return: `Ok( in bytes)` or `Err(errno)` + /// + fn seek(&self, offset: usize, origin: SeekOrigin) -> Result; +} diff --git a/os/kernel/src/syscall/sys_naming.rs b/os/kernel/src/syscall/sys_naming.rs index c769186..c2aff89 100644 --- a/os/kernel/src/syscall/sys_naming.rs +++ b/os/kernel/src/syscall/sys_naming.rs @@ -3,37 +3,22 @@ ╟─────────────────────────────────────────────────────────────────────────╢ ║ Descr.: All system calls for the naming service. ║ ╟─────────────────────────────────────────────────────────────────────────╢ - ║ Author: Michael Schoettner, 30.8.2024, HHU ║ + ║ Author: Michael Schoettner, 15.9.2024, HHU ║ ╚═════════════════════════════════════════════════════════════════════════╝ */ -use alloc::vec; use core::ptr::slice_from_raw_parts; use core::str::from_utf8; -use syscall::return_vals::{convert_syscall_result_to_ret_code}; +use alloc::string::ToString; -use crate::naming::name_service; +use crate::naming::api; - - -pub fn sys_mkentry( - path_buff: *const u8, - path_buff_len: usize, - name_buff: *const u8, - name_buff_len: usize -) -> isize { +pub fn sys_mkdir(path_buff: *const u8, path_buff_len: usize) -> isize { let path = from_utf8(unsafe { slice_from_raw_parts(path_buff, path_buff_len) .as_ref() .unwrap() }) .unwrap(); - let name = from_utf8(unsafe { - slice_from_raw_parts(name_buff, name_buff_len) - .as_ref() - .unwrap() - }) - .unwrap(); - let r = name_service::mkentry(path, name, vec![1]); - convert_syscall_result_to_ret_code(r) + api::mkdir(&path.to_string()) } diff --git a/os/kernel/src/syscall/syscall_dispatcher.rs b/os/kernel/src/syscall/syscall_dispatcher.rs index 024cb8d..b898226 100644 --- a/os/kernel/src/syscall/syscall_dispatcher.rs +++ b/os/kernel/src/syscall/syscall_dispatcher.rs @@ -3,7 +3,7 @@ ╟─────────────────────────────────────────────────────────────────────────╢ ║ Descr.: Low-level dispatcher for system calls. ║ ╟─────────────────────────────────────────────────────────────────────────╢ - ║ Author: Fabian Ruhland, 30.8.2024, HHU ║ + ║ Author: Fabian Ruhland, 15.9.2024, HHU ║ ╚═════════════════════════════════════════════════════════════════════════╝ */ use core::arch::asm; @@ -20,7 +20,7 @@ use crate::syscall::sys_time::{sys_get_date, sys_get_system_time, sys_set_date, use crate::syscall::sys_concurrent::{sys_process_execute_binary, sys_process_exit, sys_process_id, sys_thread_create, sys_thread_exit, sys_thread_id, sys_thread_join, sys_thread_sleep, sys_thread_switch,}; use crate::syscall::sys_terminal::{sys_terminal_read, sys_terminal_write}; -use crate::syscall::sys_naming::sys_mkentry; +use crate::syscall::sys_naming::sys_mkdir; use crate::{core_local_storage, tss}; @@ -98,7 +98,7 @@ impl SyscallTable { sys_get_system_time as *const _, sys_get_date as *const _, sys_set_date as *const _, - sys_mkentry as *const _, + sys_mkdir as *const _, ], } } diff --git a/os/library/naming/src/lib.rs b/os/library/naming/src/lib.rs index 85fe59c..f556dce 100644 --- a/os/library/naming/src/lib.rs +++ b/os/library/naming/src/lib.rs @@ -3,27 +3,24 @@ ╟─────────────────────────────────────────────────────────────────────────╢ ║ Descr.: Syscalls for the naming service. ║ ╟─────────────────────────────────────────────────────────────────────────╢ - ║ Author: Michael Schoettner, 30.8.2024, HHU ║ + ║ Author: Michael Schoettner, 15.9.2024, HHU ║ ╚═════════════════════════════════════════════════════════════════════════╝ */ #![no_std] use syscall::{return_vals::Errno, syscall, SystemCall}; -pub fn mkentry(path: &str, name: &str, data: usize) -> Result { +pub fn mkdir(path: &str) -> Result { // Check if params are valid - if path.is_empty() || name.is_empty() { + if path.is_empty() { Err(Errno::EINVAL) // Abort, if not } else { // params OK, do the syscall syscall( - SystemCall::Mkentry, + SystemCall::MkDir, &[ path.as_bytes().as_ptr() as usize, path.len(), - name.as_bytes().as_ptr() as usize, - name.len(), - data, // place holder, to be replaced by pointer to container ], ) } diff --git a/os/library/syscall/Cargo.toml b/os/library/syscall/Cargo.toml index 2484821..d899ff4 100644 --- a/os/library/syscall/Cargo.toml +++ b/os/library/syscall/Cargo.toml @@ -9,3 +9,4 @@ authors = ["Michael Schöttner , Fabian Ruhland ; @@ -41,5 +60,3 @@ pub fn convert_syscall_result_to_ret_code(syscall_result: SyscallResult) -> isiz ret_val } - -