tail_core 0.1.1

Core library for the Tail operating system
Documentation
// Copyright 2025, TAIL OS. All Rights Reserved.
//
// You must obtain a written license from and pay applicable license fees to TAIL OS
// before you may reproduce, modify, or distribute this software, or any work that
// includes all or part of this software.
//
// Free development licenses are available for evaluation, research, and non-commercial
// purposes, which may include access to the source code under these terms. Redistribution
// or commercial use without a license is strictly prohibited.
//
// This file may contain contributions from others. Please review this entire file for
// other proprietary rights or license notices, as well as the TAIL OS License Guide at
// https://tail-os.com/license-guide/ for more information.
//
// For licensing inquiries, visit https://tail-os.com or email license@tail-os.com.


use crate::error_kind::ErrorKind;
use crate::service::fat_file_system_server;
use crate::service::client;
use crate::service::service_request::ServiceRequestData;
use crate::service::service_reply::ServiceReplyData;
use alloc::vec::Vec;


pub mod open_file;

pub enum OpenMode {
    Read,
    Write,
    Append,
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct File {
    file_name: [u8; 8],
    fd: u64, // file descriptor
    starting_block_number: u64, // starting block number in the file system
    number_of_blocks: usize, // number of blocks in the file
    size: u64, // size of the file in bytes
}

impl File {
    pub fn new() -> Self {
        File {
            file_name: [0; 8],
            fd: 0,
            starting_block_number: 0,
            number_of_blocks: 0,
            size: 0,
        }
    }

    pub fn is_valid(&self) -> bool {
        self.fd != 0
    }

    pub fn as_ptr(&self) -> *const u8 {
        self as *const File as *const u8
    }

    pub fn get_fd(&self) -> u64 {
        self.fd
    }

    pub fn get_file_name(&self) -> &[u8; 8] {
        &self.file_name
    }

    pub fn get_starting_block_number(&self) -> u64 {
        self.starting_block_number
    }

    pub fn get_number_of_blocks(&self) -> usize {
        self.number_of_blocks
    }

    pub fn get_file_size(&self) -> u64 {
        self.size
    }

    pub fn set_file_name(&mut self, file_name: &[u8]) {
        let len = core::cmp::min(self.file_name.len(), file_name.len());

        unsafe {
            core::ptr::copy_nonoverlapping(
                file_name.as_ptr(),
                self.file_name.as_mut_ptr(),
                len,
            );
        }

        // Pad the rest with spaces if file_name is shorter
        if file_name.len() < self.file_name.len() {
            for i in file_name.len()..self.file_name.len() {
                self.file_name[i] = b' ';
            }
        }
    }

    pub fn set_fd(&mut self, fd: u64) {
        self.fd = fd;
    }

    pub fn set_file_size(&mut self, size: u64) {
        self.size = size;
    }

    pub fn set_starting_block_number(&mut self, starting_block_number: u64) {
        self.starting_block_number = starting_block_number;
    }

    pub fn set_number_of_blocks(&mut self, number_of_blocks: usize) {
        self.number_of_blocks = number_of_blocks;
    }

    pub fn read_to_end(&mut self) -> Result<Vec<u8>, ErrorKind>
    {
        let request_data = ServiceRequestData::new(self, core::mem::size_of_val(self));
        let result = client::send_service_request_and_wait_for_reply("fat_file_system_server", fat_file_system_server::FAT_FILE_SYSTEM_SERVER_READ_FILE, &request_data);
        if result.is_err() {
            return Err(crate::error_kind::ErrorKind::NotFound.into());
        } else {
            let reply: ServiceReplyData<u8> = result.unwrap();
            let reply_data_ptr = reply.get_reply_message_ptr();
            let reply_data_size = reply.get_reply_message_size();
            let vec = unsafe {
                Vec::from_raw_parts(reply_data_ptr as *mut u8, reply_data_size, reply_data_size)
            };
            return Ok(vec);
        }
    }

    pub fn from_u8_ref(file_u8_ref: &u8) -> Option<File> {
        /*
        let file = unsafe { &*(u8_ref as *const u8 as *const File) };
        if file.is_valid() {
            Ok(file.clone())
        } else {
            Err(ErrorKind::InvalidData)
        }
        */
        let file = file_u8_ref as *const u8 as *const File;
        if file.is_null() {
            return None;
        }
        return unsafe { Some(*file) }
    }

    pub fn from_u8_ptr(file_u8_ptr: *const u8) -> Option<File> {
        let file_ptr = file_u8_ptr as *const File;
        if file_ptr.is_null() {
            return None;
        }
        
        let file = unsafe { *file_ptr };
        Some(file)
    }
}