1
0
forked from Rativel/BurritOS

merge and some fix

This commit is contained in:
Baptiste
2023-03-29 18:22:45 +02:00
6 changed files with 745 additions and 61 deletions

View File

@@ -0,0 +1,154 @@
use crate::simulator::disk;
use crate::{simulator::disk::SECTOR_SIZE, utility::bitmap::BitMap};
pub const MAX_HEADER_SECTORS: i32 = 32;
pub const DATAS_IN_FIRST_SECTOR: i32 = (SECTOR_SIZE - 5 * 8) /8;
pub const DATAS_IN_SECTOR: i32 = (SECTOR_SIZE - 1 * 8) /8;
pub const MAX_DATA_SECTORS: i32 = ((MAX_HEADER_SECTORS-1) * DATAS_IN_SECTOR + DATAS_IN_FIRST_SECTOR);
pub const MAX_FILE_LENGTH: i32 = ((MAX_DATA_SECTORS) * SECTOR_SIZE);
use crate::DrvDisk;
use crate::Disk;
pub struct FileHdr {
is_dir: i32,
num_bytes: i32,
num_sectors: i32,
data_sectors: Vec<i32>,
num_header_sectors: i32,
header_sectors: [i32; MAX_HEADER_SECTORS as usize],
}
impl FileHdr {
pub fn allocate(&mut self, mut free_map: BitMap, file_size: i32) -> bool {
self.num_bytes = file_size;
if file_size > MAX_FILE_LENGTH {
panic!("file size is too long");
}
self.num_sectors = (file_size + SECTOR_SIZE -1) / SECTOR_SIZE;
self.num_header_sectors = ((self.num_sectors - DATAS_IN_FIRST_SECTOR)+DATAS_IN_SECTOR-1) / DATAS_IN_SECTOR;
// Check if there is enough free sectors for both of them
if free_map.num_clear() < self.num_sectors + self.num_header_sectors {
return false;
}
for i in 0..self.num_header_sectors {
self.header_sectors[i as usize] = free_map.find();
}
self.data_sectors = vec![0; MAX_DATA_SECTORS as usize];
for i in 0..self.num_sectors {
self.data_sectors[i as usize] = free_map.find();
}
return true;
}
pub fn re_allocate(&mut self, mut free_map: BitMap, old_file_size: i32, new_file_size: i32) -> bool {
let mut new_num_sectors = ((new_file_size + SECTOR_SIZE -1) / SECTOR_SIZE) - self.num_sectors;
self.num_bytes = new_file_size;
let mut new_num_header_sectors = (((self.num_sectors - DATAS_IN_FIRST_SECTOR)+DATAS_IN_SECTOR-1) / DATAS_IN_SECTOR) - self.num_header_sectors;
assert!(new_file_size <= MAX_FILE_LENGTH);
if free_map.num_clear() < new_num_sectors + new_num_header_sectors {
return false;
}
for i in 0..new_num_header_sectors {
self.header_sectors[(i + self.num_header_sectors)as usize] = free_map.find();
}
for i in 0..new_num_sectors {
self.data_sectors[(i + self.num_sectors) as usize] = free_map.find();
}
return true;
}
pub fn deallocate(&mut self, mut free_map: BitMap) {
for i in 0..self.num_sectors {
assert!(free_map.test(self.data_sectors[i as usize] as usize));
free_map.clear(self.data_sectors[i as usize]as usize);
}
for i in 0..self.num_header_sectors {
assert!(free_map.test(self.header_sectors[i as usize] as usize));
free_map.clear(self.header_sectors[i as usize]as usize);
}
}
//TODO: fetchFrom WriteBack
pub fn byte_to_sector(&self,offset: i32) -> i32 {
return self.data_sectors[ (offset / SECTOR_SIZE) as usize];
}
pub fn file_length(&self) -> i32 {
return self.num_bytes;
}
pub fn change_file_length(&mut self, new_size: i32) {
self.num_bytes = new_size;
assert!(new_size <= MAX_FILE_LENGTH);
}
pub fn max_file_length(&self) -> i32 {
return self.num_sectors * SECTOR_SIZE;
}
pub fn print(&self) {
let mut data = Vec::new();
println!("FileHeader contents. File size: {}. File blocks:", self.num_bytes);
for i in 0..self.num_sectors {
print!("{} ", self.data_sectors[i as usize]);
}
println!("\nFile contents:");
let mut k = 0;
for i in 0..self.num_sectors {
let disk = Disk::init_disk();
let mut drv_disk = DrvDisk::init_drv_disk(disk);
drv_disk.read_sector(self.data_sectors[i as usize], &mut data);
for j in 0..SECTOR_SIZE.min(self.num_bytes - k) {
let c = data[j as usize];
if c >= 0x20 && c <= 0x7E {
print!("{}", c as char);
} else {
print!("\\{:x}", c);
}
k += 1;
}
println!("");
}
}
pub fn is_dir(&self) -> bool{
return self.is_dir == 1;
}
pub fn set_file(&mut self) {
self.is_dir = 0;
}
pub fn set_dir(&mut self) {
self.is_dir = 1;
}
}
#[cfg(test)]
mod test {
#[test]
fn test_allocate() {
}
}

View File

@@ -1,6 +1,12 @@
use super::directory;
use crate::{kernel::mgerror::ErrorCode, simulator::disk, utility::bitmap::BitMap};
use super::filehdr::FileHdr;
pub const ERROR: i32 = -1;
pub const FREE_MAP_SECTOR: i32 = 0;
pub const DIRECTORY_SECTOR: i32 = 1;
pub const NUM_DIR_ENTRIES: i32 = 10;
pub const DIRECTORY_FILE_SIZE: i32 = 100; //std::mem::size_of<Directory>() * NUM_DIR_ENTRIES;
/// decompose the name of the first directory
/// of the path given in argument, as well as the remainder of the path.
@@ -50,7 +56,7 @@ pub fn decomp_name(origin_path: String, head: &mut String, tail: &mut String) ->
/// - **name** is the complete name (relatively to the root directory).
/// its content will be modified!
pub fn find_dir(name: &mut String) -> i32 {
let directory = directory::init_directory(config.num_dir_entries);
let directory = Directory::init_directory(config.num_dir_entries);
directory.fetch_from(filesys::get_dir_file());
let mut sector = DIRECTORY_SECTOR;
@@ -66,7 +72,7 @@ pub fn find_dir(name: &mut String) -> i32 {
return -1; // This file/directory does not exist
}
let file = openfile::init_open_file(sector);
let file = OpenFile::init_open_file(sector);
if file.get_file_header().is_dir() {
directory.fetch_from(&file);
} else {
@@ -79,25 +85,403 @@ pub fn find_dir(name: &mut String) -> i32 {
}
pub struct Filesys {
pub free_map_file: Open_file, //Bit map of free disk blocks, represented as a file
pub directory_file: Open_file, //"Root" directory -- list of file names, represented as a file
pub free_map_file: OpenFile, //Bit map of free disk blocks, represented as a file
pub directory_file: OpenFile, //"Root" directory -- list of file names, represented as a file
}
impl Filesys {
/// Initialize the file system.
/// If format = true, the disk has nothing on it,
/// and we need to initialize the disk to contain an empty directory,
/// and a bitmap of free sectors (with almost but not all of the sectors marked as free).
/// Initialize the file system. If format = true, the disk has
/// nothing on it, and we need to initialize the disk to contain
/// an empty directory, and a bitmap of free sectors (with almost but
/// not all of the sectors marked as free).
///
/// If format = false, we just have to open the files
/// representing the bitmap and the directory.
/// If format = false, we just have to open the files
/// representing the bitmap and the directory.
///
/// ### parameters
///
/// - **format** should we initialize the disk?
pub fn init_filesys(format: bool) -> Filesys {
if format {
let free_map = BitMap::init_bitmap(disk::NUM_SECTORS as usize);
let directory = Directory::init_directory(NUM_DIR_ENTRIES);
free_map.mark(FREE_MAP_SECTOR as usize);
free_map.mark(DIRECTORY_SECTOR as usize);
let map_header: FileHdr;
let dir_header: FileHdr;
map_header.allocate(free_map, FREE_MAP_SECTOR);
dir_header.allocate(free_map, DIRECTORY_FILE_SIZE);
dir_header.set_dir();
map_header.write_back(FREE_MAP_SECTOR);
dir_header.write_back(DIRECTORY_SECTOR);
let free_map_file = OpenFile::init_open_file(FREE_MAP_SECTOR);
let directory_file = OpenFile::init_open_file(DIRECTORY_SECTOR);
free_map.write_back(free_map_file);
directory.write_back(directory_file);
Filesys {
free_map_file,
directory_file,
}
} else {
Filesys {
free_map_file: OpenFile::init_open_file(FREE_MAP_SECTOR),
directory_file: OpenFile::init_open_file(DIRECTORY_SECTOR),
}
}
}
/// Create a file in the BurritOS file system (similar to UNIX create).
/// Since we can't increase the size of files dynamically, we have
/// to give Create the initial size of the file.
//
/// The steps to create a file are:
/// Make sure the file doesn't already exist
/// Allocate a sector for the file header
/// Allocate space on disk for the data blocks for the file
/// Add the name to the directory
/// Store the new file header on disk
/// Flush the changes to the bitmap and the directory back to disk
///
/// Create fails if:
/// file is already in directory
/// no free space for file header
/// no free entry for file in directory
/// no free space for data blocks for the file
///
/// Note that this implementation assumes there is no concurrent access
/// to the file system!
///
/// ### parameters
///
/// - **format** should we initialize the disk?
pub fn init_filesys(format: bool) -> Filesys {
if format {
let free_map = bitmap::init_bitmap();
/// - **name** is the name of file to be created (NOT MODIFIED)
/// - **initialSize** is the size of file to be created
pub fn create(self, name: String, initial_size: i32) -> Result<(), ErrorCode> {
lock.acquire();
let mut dir_name = name.clone();
let dir_sector = find_dir(&mut dir_name);
if dir_sector == ERROR {
lock.release();
return Err(ErrorCode::InexistFileError);
}
let dir_file = OpenFile::init_open_file(dir_sector);
let directory = Directory::init_directory(NUM_DIR_ENTRIES);
directory.fetch_from(&dir_file);
if directory.find(dir_name) != ERROR {
lock.release();
return Err(ErrorCode::AlreadyInDirectory);
}
// Get the freemap from the disk
let free_map = BitMap::init_bitmap(disk::NUM_SECTORS as usize);
free_map.fetch_from(self.free_map_file);
// Find a sector to hold the file header
let sector = free_map.find();
if sector == ERROR {
lock.release();
return Err(ErrorCode::OutOfDisk);
}
// Add the file in the directory
let add_result = directory.add(dir_name, sector);
match add_result {
Err(e) => {
lock.release();
return Err(e);
}
_ => {}
}
// Indicate that this is a file, not a directory
let hdr = FileHdr::init_file_hdr();
hdr.set_file();
if !hdr.allocate(free_map, initial_size) {
lock.release();
return Err(ErrorCode::OutOfDisk);
}
// everthing worked, flush all changes back to disk
hdr.write_back(sector);
directory.write_back(&dir_file);
free_map.write_back(self.free_map_file);
lock.release();
Ok(())
}
/// Open a file for reading and writing.
/// To open a file:
/// Find the location of the file's header, using the directory
/// Bring the header into memory
///
/// ### parameters
///
/// - **name** the text name of the file to be opened (NOT MODIFIED)
pub fn open(name: String) -> Option<OpenFile> {
let open_file: OpenFile;
let mut dir_name = name.clone();
// Find the directory containing the file
let dir_sector = find_dir(&mut dir_name);
if dir_sector == ERROR {
return None;
}
// Read the directory from disk
let dir_file = OpenFile::init_open_file(dir_sector);
let directory = Directory::init_directory(NUM_DIR_ENTRIES);
directory.fetch_from(&directory);
// Find the file in the directory
let sector = directory.find(dir_name);
if sector >= 0 {
open_file = OpenFile::init_open_file(sector);
open_file.set_name(name);
if open_file.is_dir() {
return None;
}
}
Some(open_file)
}
/// Delete a file from the file system.
/// This requires:
/// Remove it from the directory
/// Delete the space for its header
/// Delete the space for its data blocks
/// Write changes to directory, bitmap back to disk
///
/// ### parameters
///
/// - **name** the text name of the file to be removed (NOT MODIFIED)
pub fn remove(self, name: String) -> Result<(), ErrorCode> {
let mut dir_name = name.clone();
// Get the sector number of the parent directory
let dir_sector = find_dir(&mut dir_name);
// Check if the path is correct
if dir_sector == ERROR {
return Err(ErrorCode::InexistDirectoryError);
}
// Fetch the directory from the disk
let dir_file = OpenFile::init_open_file(dir_sector);
let directory = Directory::init_directory(NUM_DIR_ENTRIES);
directory.fetch_from(&dir_file);
// Look for the file in the directory
let sector = directory.find(dir_name);
// Look if we find the file in the directory
if sector as i32 == ERROR {
return Err(ErrorCode::InexistFileError);
}
// Fetch the file header from disk
let file_hdr: FileHdr;
file_hdr.fetch_from(self.free_map_file);
// Do nothing if it's a directory
if file_hdr.is_dir() {
return Err(ErrorCode::NotAFile);
}
// Get the freemap file from the disk
let free_map = BitMap::init_bitmap(disk::NUM_SECTORS as usize);
free_map.fetch_from(self.free_map_file);
// Indicate that sectors are deallocated in the freemap
file_hdr.deallocate(free_map);
free_map.clear(sector);
// Remove the file from the directory
directory.remove(dir_name);
// Flush everything to disk
free_map.write_back(self.free_map_file);
directory.write_back(dir_file);
Ok(())
}
/// List all the files in the file system directory.
pub fn list() {
//TODO
}
/// Print everything about the file system:
/// the contents of the bitmap
/// the contents of the directory
/// for each file in the directory,
/// the contents of the file header
/// the data in the file
pub fn print() {
//TODO
}
/// Create a directory in the Nachos file system (similar to UNIX create).
/// A directory is a file containing a table of directory entries.
///
/// The steps to create a dirctory are:
/// Make sure the name is valid and does not exist
/// Create a file containing the directory entries
///
/// mkdir fails if:
/// dir already exists
/// no free space for file header
/// no free entry for dir in directory
/// no free space for data blocks for the file
///
/// Note that this implementation assumes there is no concurrent access
/// to the file system!
///
/// ### parameters
///
/// - **name** is the name of directory to be created (NOT MODIFIED)
pub fn mkdir(self, name: String) -> Result<(), ErrorCode> {
let mut dir_name = name.clone();
// Lokk for the sector number of the parent directory
let parent_sector = find_dir(&mut dir_name);
if parent_sector < 0 {
return Err(ErrorCode::InexistDirectoryError);
}
// Fetch it from disk
let parent_dir_file = OpenFile::init_open_file(parent_sector);
let parent_dir = Directory::init_directory(NUM_DIR_ENTRIES);
parent_dir.fetch_from(parent_dir_file);
// Check that the directory does not exit yet
if parent_dir.find(dir_name) >= 0 {
return Err(ErrorCode::AlreadyInDirectory);
}
// Get the freemap
let free_map = BitMap::init_bitmap(disk::NUM_SECTORS as usize);
free_map.fetch_from(self.free_map_file);
// Get a free sector for the file header
let hdr_sector = free_map.find();
if hdr_sector < 0 {
return Err(ErrorCode::OutOfDisk);
}
// Allocate free sectors for the directory contents
let hdr: FileHdr;
if !hdr.allocate(free_map, DIRECTORY_FILE_SIZE) {
return Err(ErrorCode::OutOfDisk);
}
// Add the directory in the parent directory
let add_result = parent_dir.add(dir_name, hdr_sector);
match add_result {
Err(e) => {
return Err(e);
}
_ => {}
}
// File header
hdr.set_dir();
hdr.write_back(hdr_sector);
// New directory (initially empty)
let new_dir_file = OpenFile::init_open_file(hdr_sector as usize);
let new_dir = Directory::init_directory(NUM_DIR_ENTRIES);
new_dir.write_back(new_dir_file);
// Parent directory
parent_dir.write_back(parent_dir_file);
free_map.write_back(self.free_map_file);
Ok(())
}
/// Delete a directory from the file system.
/// This requires:
/// check the name is valid
/// check the directory is empty
/// Remove it from its directory
/// Delete the space for its header
/// Delete the space for its data blocks
/// Write changes to directory, bitmap back to disk
///
/// ### parameters
///
/// - **name** the text name of the directory to be removed (NOT MODIFIED)
pub fn rmdir(self, name: String) -> Result<(), ErrorCode> {
let mut dir_name = name.clone();
// Get the sector number of the parent directory
let parent_sector = find_dir(&mut dir_name);
if parent_sector < 0 {
return Err(ErrorCode::InexistDirectoryError);
}
// Fetch it from disk
let parent_dir_file = OpenFile::init_open_file(parent_sector);
let parent_dir = Directory::init_directory(NUM_DIR_ENTRIES);
parent_dir.fetch_from(parent_dir_file);
// Check that the directory to be removed exist
let the_dir_sector = parent_dir.find(dir_name);
if the_dir_sector < 0 {
return Err(ErrorCode::InexistDirectoryError);
}
// Get its header
let the_dir_header: FileHdr;
the_dir_header.fetch_from(the_dir_sector);
// Check that is is a directory
if !the_dir_header.is_dir() {
return Err(ErrorCode::NotADirectory);
}
// Fetch its contents from the disk
let the_dir_file = OpenFile::init_open_file(the_dir_sector);
let the_dir = Directory::init_directory(NUM_DIR_ENTRIES);
the_dir.fetch_from(the_dir_file);
// Check that is is empty
if !the_dir.empty() {
return Err(ErrorCode::DirectoryNotEmpty);
}
// Get the freemap from disk
let free_map = BitMap::init_bitmap(disk::NUM_SECTORS as usize);
free_map.fetch_from(self.free_map_file);
// Deallocate the data sectors of the directory
the_dir_header.deallocate(free_map);
// Deallocate the sector containing the directory header
free_map.clear(the_dir_sector);
// We remove the directory from its parent directory
parent_dir.remove(dir_name);
// Flush everything to disk
free_map.write_back(self.free_map_file);
parent_dir.write_back(parent_dir_file);
Ok(())
}
}

View File

@@ -1,3 +1,6 @@
pub mod directory;
pub mod filehdr;
pub mod filesys;
pub mod fsmisc;
pub mod oftable;
pub mod openfile;