diff --git a/src/filesys/filesys.rs b/src/filesys/filesys.rs index 350ac13..3d31522 100644 --- a/src/filesys/filesys.rs +++ b/src/filesys/filesys.rs @@ -1,12 +1,14 @@ -use crate::{simulator::disk, utility::bitmap, kernel::mgerror::ErrorCode}; +use crate::{simulator::disk, utility::bitmap::BitMap, kernel::mgerror::ErrorCode}; + +use super::filehdr::FileHdr; const ERROR : i32 = -1; const FREE_MAP_SECTOR : i32 = 0; const DIRECTORY_SECTOR : i32 = 1; 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 { @@ -24,22 +26,25 @@ impl Filesys { /// -**format** should we initialize the disk? pub fn init_filesys(format : bool) -> Filesys { if format { - let free_map = bitmap::init_bitmap(disk::NUM_SECTORS); - let directory = directory::init_directory(num_dir_entries); + 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); - free_map.mark(DIRECTORY_SECTOR); + free_map.mark(FREE_MAP_SECTOR as usize); + free_map.mark(DIRECTORY_SECTOR as usize); - let map_header = filehdr::allocate(&free_map, FREE_MAP_SECTOR); - let dir_header = filehdr::allocate(&free_map, directory_file_size); + 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); + 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); @@ -50,8 +55,8 @@ impl Filesys { } } else { Filesys { - free_map_file : openfile::init_open_file(FREE_MAP_SECTOR), - directory_file : openfile::init_open_file(DIRECTORY_SECTOR) + free_map_file : OpenFile::init_open_file(FREE_MAP_SECTOR), + directory_file : OpenFile::init_open_file(DIRECTORY_SECTOR) } } } @@ -81,7 +86,7 @@ impl Filesys { /// /// -**name** is the name of file to be created (NOT MODIFIED) /// -**initialSize** is the size of file to be created - pub fn create(&mut self, name : String, initial_size : i32) -> Result<(), ErrorCode> { + pub fn create(self, name : String, initial_size : i32) -> Result<(), ErrorCode> { lock.acquire(); @@ -91,8 +96,8 @@ impl Filesys { return Err(ErrorCode::InexistFileError); } - let dir_file = openfile::init_open_file(dir_sector); - let directory = directory::init_directory(num_dir_entries); + 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(name) != ERROR { @@ -101,7 +106,7 @@ impl Filesys { } // Get the freemap from the disk - let free_map = bitmap::init_bitmap(disk::NUM_SECTORS); + 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 @@ -122,10 +127,10 @@ impl Filesys { } // Indicate that this is a file, not a directory - let hdr = file_header::init_file_header(); + let hdr = FileHdr::init_file_hdr(); hdr.set_file(); - if !hdr.allocate(&free_map, initial_size) { + if !hdr.allocate(free_map, initial_size) { lock.release(); return Err(ErrorCode::OutOfDisk); } @@ -148,8 +153,8 @@ impl Filesys { /// ### parameters /// /// -**name** the text name of the file to be opened (NOT MODIFIED) - pub fn open(name : String) -> Option { - let open_file : Open_file; + pub fn open(name : String) -> Option { + let open_file : OpenFile; // Find the directory containing the file let dir_sector = find_dir(name); if dir_sector == ERROR { @@ -157,14 +162,14 @@ impl Filesys { } // Read the directory from disk - let dir_file = open_file::init_open_file(dir_sector); - let directory = directory::init_directory(num_dir_entries); + 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(name); if sector >= 0 { - open_file = openfile::init_open_file(sector); + open_file = OpenFile::init_open_file(sector); open_file.set_name(name); if open_file.is_dir() { return None; @@ -174,4 +179,226 @@ impl Filesys { 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> { + + // Get the sector number of the parent directory + let dir_sector = find_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(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(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> { + + // Lokk for the sector number of the parent directory + let parent_sector = find_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(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(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 + /// + /// -**namedir** the text name of the directory to be removed (NOT MODIFIED) + pub fn rmdir(self, namedir : String) -> Result<(), ErrorCode> { + + // Get the sector number of the parent directory + let parent_sector = find_dir(namedir); + 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(namedir); + 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(namedir); + + // Flush everything to disk + free_map.write_back(self.free_map_file); + parent_dir.write_back(parent_dir_file); + + Ok(()) + } } \ No newline at end of file diff --git a/src/utility/bitmap.rs b/src/utility/bitmap.rs index a34e5b4..4af76a1 100644 --- a/src/utility/bitmap.rs +++ b/src/utility/bitmap.rs @@ -4,6 +4,8 @@ pub const BITS_IN_WORD: usize = 32; use std::fs::File; use std::io::{Cursor, Write, Read}; +use crate::simulator::disk::SECTOR_SIZE; + pub struct BitMap { num_bits: usize, num_words: usize, @@ -12,16 +14,42 @@ pub struct BitMap { impl BitMap { + /// Initialize a bitmap with "nitems" bits, so that every bit is clear. + /// it can be added somewhere on a list. + /// + /// ### Parameters + /// - **nitems** is the number of bits in the bitmap. + ///---------------------------------------------------------------------- + pub fn init_bitmap(n_items: usize) -> BitMap { + let mut tmp: Vec; + BitMap{ + num_bits: n_items, + num_words: (n_items + SECTOR_SIZE as usize -1) / SECTOR_SIZE as usize, + map: tmp, + } + } + + /// Set the "nth" bit in a bitmap. + /// ### Parameters + /// - **which** is the number of the bit to be set. pub fn mark(&mut self, which: usize) { assert!(which >= 0 && which < self.num_bits); self.map[which / BITS_IN_WORD] |= 1 << (which % BITS_IN_WORD); } + /// return true if the "nth" bit is set. + /// + /// ### Paramenters + /// - **which** is the number of the bit to be tested. pub fn test(&self, which: usize) -> bool { assert!(which < self.num_bits); (self.map[which / BITS_IN_WORD] & (1 << (which % BITS_IN_WORD))) != 0 } + /// Return the number of the first bit which is clear. + /// As a side effect, set the bit (mark it as in use). + /// (In other words, find and allocate a bit.) + /// If no bits are clear, return ERROR pub fn find(&mut self) -> i32 { for i in 0..self.num_bits { if !self.test(i) { @@ -32,6 +60,9 @@ impl BitMap { -1 } + /// Clear the "nth" bit in a bitmap. + /// ### Parameters + /// - **which** is the number of the bit to be cleared. pub fn clear(&mut self, which: usize) { assert!(which < self.num_bits, "index out of range"); @@ -40,6 +71,8 @@ impl BitMap { self.map[word_idx] &= !(1 << bit_idx); } + /// Return the number of clear bits in the bitmap. + /// (In other words, how many bits are unallocated?) pub fn num_clear(&self) -> i32 { let mut count = 0; for i in 0..self.num_bits { @@ -50,6 +83,9 @@ impl BitMap { count } + /// Print the contents of the bitmap, for debugging. + /// Could be done in a number of ways, but we just print the #'s of + /// all the bits that are set in the bitmap. pub fn print(&self) { println!("Bitmap set:"); for i in 0..self.num_bits { @@ -60,8 +96,10 @@ impl BitMap { println!(); } - - + ///Initialize the contents of a bitmap from a Nachos file. + /// + /// ### Parameters + /// - **file** is the place to read the bitmap from pub fn fetch_from(&mut self, file_path: &str) -> std::io::Result<&Vec> { // Ouvre le fichier en mode lecture seule let mut file = File::open(file_path)?; @@ -83,6 +121,10 @@ impl BitMap { Ok(&self.map) } + /// Store the contents of a bitmap to a Nachos file. + /// + /// ### Paramenters + /// - **file** is the place to write the bitmap to pub fn write_back(&mut self, file_path: &str) -> std::io::Result<()> { // Encapsule le vecteur dans un std::io::Cursor pour l'utiliser comme un std::io::Write let mut cursor = Cursor::new(Vec::::new()); @@ -98,5 +140,4 @@ impl BitMap { Ok(()) } - } \ No newline at end of file