handle directories

This commit is contained in:
husky 2025-09-09 09:17:42 -07:00
parent e004212c9c
commit 960de83bbc
8 changed files with 225 additions and 27 deletions

View file

@ -10,5 +10,12 @@ pub struct TaskSetup {
pub epc: usize,
pub ddi_first_addr: usize,
pub ddi_size: usize,
pub environment: usize,
pub wait_for_task_exit: bool,
}
#[repr(C)]
pub struct Environment {
pub current_directory_path: usize,
pub current_directory_path_len: usize,
}

View file

@ -65,6 +65,8 @@ pub enum SysCall {
/// waits for a sent notification to be received
/// (taskid) -> 0
WaitForNotifAck = 13,
/// returns the environment pointer for the given task
EnvironmentPointer = 14,
/// initializes kernel, ONLY CALL ONCE! IN FACT, YOU PROBABLY NEVER NEED TO CALL THIS
InitKernel = 666
@ -90,6 +92,7 @@ pub fn usize2sc(u: usize) -> SysCall {
11 => SysCall::WaitForNotification,
12 => SysCall::PendingNotifications,
13 => SysCall::WaitForNotifAck,
14 => SysCall::EnvironmentPointer,
666 => SysCall::InitKernel,
_ => SysCall::NoAction,
}
@ -159,6 +162,10 @@ pub fn wait_for_notif_ack(taskid: u8) {
syscall(SysCall::WaitForNotifAck, taskid as usize, 0, 0, 0, 0, 0);
}
pub fn environment_pointer() -> usize {
syscall(SysCall::EnvironmentPointer, 0, 0, 0, 0, 0, 0)
}
pub fn init_kernel() {
syscall(SysCall::InitKernel, 0, 0, 0, 0, 0, 0);
}

View file

@ -85,6 +85,7 @@ extern "C" fn _virt_init() -> ! {
epc: ktask as usize,
ddi_first_addr: 0,
ddi_size: 0,
environment: 0,
wait_for_task_exit: false,
});

View file

@ -176,6 +176,10 @@ pub fn reader_from_cluster(bpb: &BPBUseful, cluster: usize) -> Fat32FileReader {
}
}
pub fn root_target(bpb: &BPBUseful) -> u32 {
bpb.root_cluster as u32
}
pub fn root_reader(bpb: &BPBUseful) -> Fat32DirectoryReader {
let cluster = bpb.root_cluster as usize;
Fat32DirectoryReader {

View file

@ -38,6 +38,13 @@ pub fn open_fs(fs: &mut FileSystem) -> bool {
}
}
pub fn root_target(fs: &FileSystem) -> u32 {
#[cfg(feature = "fs_fat32")]
{
fat32::root_target(fs)
}
}
pub fn root_reader(fs: &FileSystem) -> DirectoryReader {
#[cfg(feature = "fs_fat32")]
{
@ -94,8 +101,8 @@ pub fn read_one_record(fs: &FileSystem, reader: &mut DirectoryReader, record: &m
}
}
pub fn open_directory(fs: &FileSystem, path: &mut [u8], reader: &mut DirectoryReader) -> usize {
path.make_ascii_uppercase();
pub fn open_directory(fs: &FileSystem, path: &[u8], reader: &mut DirectoryReader) -> usize {
//path.make_ascii_uppercase();
if path[0] != b'/' {
return 3;
}
@ -104,6 +111,10 @@ pub fn open_directory(fs: &FileSystem, path: &mut [u8], reader: &mut DirectoryRe
*reader = root_reader;
0
} else {
let mut target_stack = [0u32; 128]; // todo: make this actually dynamic
target_stack[0] = root_target(fs);
let mut target_stack_idx = 1;
let mut record = Record {
name: [0; 12],
record_type: 0,
@ -111,8 +122,43 @@ pub fn open_directory(fs: &FileSystem, path: &mut [u8], reader: &mut DirectoryRe
total_size_bytes: 0,
};
let mut current_reader = root_reader;
let mut next_path_start = path[1..].iter().position(|&x| x == b'/').unwrap_or(path.len());
let mut next_path_start = path[1..].iter().position(|&x| x == b'/').unwrap_or(path.len()) + 1;
let mut search_for = &path[1..next_path_start];
'into_next_dir: loop {
if search_for == b"." {
// do nothing and skip this part of the path
let new_path_start = next_path_start + 1;
if new_path_start >= path.len() {
// we're at the end of the path
*reader = current_reader;
return 0;
}
next_path_start = path[new_path_start..].iter().position(|&x| x == b'/').unwrap_or(path.len()) + new_path_start;
search_for = &path[new_path_start..next_path_start];
target_stack[target_stack_idx] = record.target;
target_stack_idx += 1;
continue 'into_next_dir;
} else if search_for == b".." {
// go back up
if target_stack_idx < 2 {
directory_reader(fs, &mut current_reader, target_stack[0]);
*reader = current_reader;
return 0;
}
target_stack_idx -= 2; // skip the current directory and the one before that
let prev_target = target_stack[target_stack_idx];
let new_path_start = next_path_start + 1;
if new_path_start >= path.len() {
// we're at the end of the path
directory_reader(fs, &mut current_reader, prev_target);
*reader = current_reader;
return 0;
}
next_path_start = path[new_path_start..].iter().position(|&x| x == b'/').unwrap_or(path.len()) + new_path_start;
search_for = &path[new_path_start..next_path_start];
directory_reader(fs, &mut current_reader, prev_target);
continue 'into_next_dir;
}
loop {
if !read_one_record(fs, &mut current_reader, &mut record) {
return 1;
@ -129,12 +175,16 @@ pub fn open_directory(fs: &FileSystem, path: &mut [u8], reader: &mut DirectoryRe
return 0;
}
next_path_start = path[new_path_start..].iter().position(|&x| x == b'/').unwrap_or(path.len()) + new_path_start;
search_for = &path[next_path_start..next_path_start];
search_for = &path[new_path_start..next_path_start];
directory_reader(fs, &mut current_reader, record.target);
target_stack[target_stack_idx] = record.target;
target_stack_idx += 1;
continue 'into_next_dir;
} else {
return 2;
}
}
}
}
}
}

View file

@ -110,6 +110,7 @@ pub extern "C" fn ktask() -> ! {
epc: entrypoint,
ddi_first_addr: first_addr,
ddi_size: size,
environment: 0,
wait_for_task_exit: false,
});
} else {

View file

@ -84,6 +84,7 @@ pub fn handle_syscall(
#[cfg(feature = "arch_virt")]
let t = Some(Task {
epc: unsafe { (*add).epc },
environment: unsafe { (*add).environment },
want_exit: false,
sp,
wait: 0,
@ -319,6 +320,14 @@ pub fn handle_syscall(
}
0
}
SysCall::EnvironmentPointer => {
let ci = tc.current;
if let Some(task) = tc.tasks[ci].as_ref() {
task.environment
} else {
0
}
}
},
suspend,
)
@ -413,6 +422,7 @@ pub struct TrafficControl {
pub struct Task {
#[cfg(feature = "arch_virt")]
pub epc: usize,
pub environment: usize,
pub want_exit: bool,
/// THE ORIGINAL STACK POINTER THAT THE TASK STARTED WITH
pub sp: usize,

View file

@ -1,11 +1,17 @@
#![no_std]
#![no_main]
use core::sync::atomic::{AtomicBool, Ordering};
use core::sync::atomic::{AtomicBool, AtomicPtr, AtomicUsize, Ordering};
use crate::terminal::{print, println};
use liblbos::fs::{DirectoryReader, FileSystem};
static NO_EXIT: AtomicBool = AtomicBool::new(false);
static CURRENT_DIR_PATH: AtomicPtr<u8> = AtomicPtr::new(0 as *mut _);
static CURRENT_DIR_PATH_LEN: AtomicUsize = AtomicUsize::new(0);
struct Environment<'a> {
pub current_directory_path: &'a [u8],
}
#[panic_handler]
fn panic(info: &core::panic::PanicInfo) -> ! {
@ -13,14 +19,83 @@ fn panic(info: &core::panic::PanicInfo) -> ! {
loop {}
}
fn lsdir() {
fn cd(new_path: &str, environment: &mut Environment<'_>) {
let old_path = environment.current_directory_path;
let abs_new_path = if new_path.starts_with('/') {
// absolute path, replaces old path
let new_path_buf = liblbos::syscalls::alloc_blocks(new_path.len().div_ceil(512));
let new_path_buf = unsafe { core::slice::from_raw_parts_mut(new_path_buf as *mut _, new_path.len()) };
// copy
{
for (i, &x) in new_path.as_bytes().iter().enumerate() {
new_path_buf[i] = x;
}
}
new_path_buf
} else {
// todo: ".." is currently handled on the ktask level, however...
// todo: we should evaluate this and instead modify the absolute path to remove the ".."
// todo: otherwise, we're bound to end up with a path like "/a/b/../../c" which is not nice
// relative path, append
let new_path_len = old_path.len() + new_path.len() + 1;
let new_path_buf = liblbos::syscalls::alloc_blocks(new_path_len.div_ceil(512));
let new_path_buf = unsafe { core::slice::from_raw_parts_mut(new_path_buf as *mut _, new_path_len) };
// copy old path
{
for (i, &x) in old_path.iter().enumerate() {
new_path_buf[i] = x;
}
}
// copy new path
{
for (i, &x) in new_path.as_bytes().iter().enumerate() {
new_path_buf[old_path.len() + i] = x;
}
}
// add separator
new_path_buf[old_path.len() + new_path.len()] = b'/';
new_path_buf
};
// check to make sure the new path is valid
{
let mut fs = FileSystem::empty();
if liblbos::ktask::ktask_fsopen(&mut fs) != 0 {
println("failed to open fs");
// free
liblbos::syscalls::free_blocks(abs_new_path.as_ptr() as usize, abs_new_path.len().div_ceil(512));
return;
}
let mut dir = DirectoryReader::empty();
if liblbos::ktask::ktask_fsopendir(&fs, &mut dir, abs_new_path) != 0 {
println("invalid dir");
// free
liblbos::syscalls::free_blocks(abs_new_path.as_ptr() as usize, abs_new_path.len().div_ceil(512));
return;
}
}
// it is valid, update everything
{
// free old path
liblbos::syscalls::free_blocks(CURRENT_DIR_PATH.load(Ordering::Relaxed) as usize, CURRENT_DIR_PATH_LEN.load(Ordering::Relaxed).div_ceil(512));
}
CURRENT_DIR_PATH.store(abs_new_path.as_ptr() as *mut _, Ordering::Relaxed);
CURRENT_DIR_PATH_LEN.store(abs_new_path.len(), Ordering::Relaxed);
environment.current_directory_path = unsafe {
core::slice::from_raw_parts_mut(CURRENT_DIR_PATH.load(Ordering::Relaxed) as *mut _, CURRENT_DIR_PATH_LEN.load(Ordering::Relaxed))
};
}
fn lsdir(env: &Environment<'_>) {
let mut fs = FileSystem::empty();
if liblbos::ktask::ktask_fsopen(&mut fs) != 0 {
println("failed to open fs");
return;
}
let mut dir = DirectoryReader::empty();
if liblbos::ktask::ktask_fsopendir(&fs, &mut dir, b"/") != 0 {
if liblbos::ktask::ktask_fsopendir(&fs, &mut dir, env.current_directory_path) != 0 {
println("failed to open dir");
return;
}
@ -107,6 +182,7 @@ fn attempt_run_file(name: &str) {
epc: 0,
ddi_first_addr: 0,
ddi_size: 0,
environment: 0,
wait_for_task_exit: true,
};
@ -118,19 +194,26 @@ fn attempt_run_file(name: &str) {
liblbos::syscalls::free_blocks(buf, size.div_ceil(512));
let task_id = liblbos::syscalls::create_task(task_setup);
liblbos::syscalls::create_task(task_setup);
println("\ntask exited\n");
}
fn execute(cmd: &str) {
fn execute(cmd: &str, environment: &mut Environment<'_>) {
print("\n");
let mut split = cmd.split_ascii_whitespace();
if let Some(cmd) = split.next() {
match cmd {
"ls" => {
lsdir();
lsdir(environment);
}
"cd" => {
if let Some(path) = split.next() {
cd(path, environment);
} else {
println("cd requires a path");
}
}
"exit" => {
if NO_EXIT.load(Ordering::Relaxed) {
@ -168,6 +251,40 @@ extern "C" fn main() {
let tid = liblbos::syscalls::current_task();
NO_EXIT.store(tid == 1, Ordering::Relaxed);
let environment = liblbos::syscalls::environment_pointer();
let mut environment = if environment == 0 {
// no environment, construct it ourself
static DEFAULT_CURRENT_DIRECTORY: &[u8] = b"/";
let environment = Environment {
current_directory_path: DEFAULT_CURRENT_DIRECTORY,
};
environment
} else {
let env = unsafe { &mut *(environment as *mut liblbos::Environment) };
let current_directory_path = unsafe { core::slice::from_raw_parts(env.current_directory_path as *const u8, env.current_directory_path_len) };
let environment = Environment {
current_directory_path,
};
environment
};
// replace the current path with one that we allocate ourself, so that we can modify it later
{
let path = environment.current_directory_path;
let len = environment.current_directory_path.len();
CURRENT_DIR_PATH.store(liblbos::syscalls::alloc_blocks(len.div_ceil(512)) as *mut u8, Ordering::Relaxed);
CURRENT_DIR_PATH_LEN.store(len, Ordering::Relaxed);
{
// copy
let dest = unsafe {
core::slice::from_raw_parts_mut(CURRENT_DIR_PATH.load(Ordering::Relaxed) as *mut _, len)
};
for (i, &x) in path.iter().enumerate() {
dest[i] = x;
}
}
environment.current_directory_path = unsafe { core::slice::from_raw_parts_mut(CURRENT_DIR_PATH.load(Ordering::Relaxed) as *mut u8, CURRENT_DIR_PATH_LEN.load(Ordering::Relaxed)) };
}
print("\n\n");
print("turntable v");
const VERSION: &str = env!("CARGO_PKG_VERSION");
@ -198,7 +315,8 @@ extern "C" fn main() {
if *c == b'\r' {
execute(unsafe {
core::str::from_utf8_unchecked(&cmdbuf[0..cmdbuf_len - 1])
});
},
&mut environment);
cmdbuf_len = 0;
print("> ");
break;