diff --git a/src/filesys/filehdr.rs b/src/filesys/filehdr.rs index e69de29..e6dcad9 100644 --- a/src/filesys/filehdr.rs +++ b/src/filesys/filehdr.rs @@ -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, + 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() { + + } +} \ No newline at end of file diff --git a/src/filesys/filesys.rs b/src/filesys/filesys.rs index fe53f35..a0961ee 100644 --- a/src/filesys/filesys.rs +++ b/src/filesys/filesys.rs @@ -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() * 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 { + 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(()) } } diff --git a/src/filesys/mod.rs b/src/filesys/mod.rs index e9cb30b..1436871 100644 --- a/src/filesys/mod.rs +++ b/src/filesys/mod.rs @@ -1,3 +1,6 @@ pub mod directory; +pub mod filehdr; pub mod filesys; pub mod fsmisc; +pub mod oftable; +pub mod openfile; diff --git a/src/simulator/disk.rs b/src/simulator/disk.rs index 957061d..8b69b17 100644 --- a/src/simulator/disk.rs +++ b/src/simulator/disk.rs @@ -8,46 +8,42 @@ use std::os::unix::prelude::FileExt; pub const SECTORS_PER_TRACK: i32 = 32; pub const NUM_TRACKS: i32 = 64; pub const NUM_SECTORS: i32 = SECTORS_PER_TRACK * NUM_TRACKS; -pub const SECTOR_SIZE: i32 = 4;//4 octects ? +pub const SECTOR_SIZE: i32 = 4; //4 octects ? pub const DISK_PATH: &str = "disk_file"; -pub const MAGIC_NUMBER : u32 = 0xABBACDDC; +pub const MAGIC_NUMBER: u32 = 0xABBACDDC; //taille en octets, a confirmer -pub const DISK_SIZE: i32 = 4 + NUM_SECTORS*SECTOR_SIZE;//4 <=> sizeof(u32) +pub const DISK_SIZE: i32 = 4 + NUM_SECTORS * SECTOR_SIZE; //4 <=> sizeof(u32) pub struct Disk { - pub last_sector: i32,//Secteur accédé lors de la précédente requête de lecture/ecriture - pub active: bool,//C'est notre lock -> Une seule requête de lecture/ecriture à la fois - pub disk_file : File //On simule le disque sur un fichier - //Manque une ref a une fonction type handler, fournie via constructeur dans Nachos + pub last_sector: i32, //Secteur accédé lors de la précédente requête de lecture/ecriture + pub active: bool, //C'est notre lock -> Une seule requête de lecture/ecriture à la fois + pub disk_file: File, //On simule le disque sur un fichier + //Manque une ref a une fonction type handler, fournie via constructeur dans Nachos } impl Disk { pub fn init_disk() -> Disk { - //see Rust File impl FileExt for File For UNIX mode - let mut magic_buff : [u8 ; 4] = [0u8 ; 4]; - let mut readed_magic_number : u32; - let disk_file : File; + let mut magic_buff: [u8; 4] = [0u8; 4]; + let mut readed_magic_number: u32; + let disk_file: File; + + let result_open = File::options().read(true).write(true).open(DISK_PATH); + + let magic_to_write: [u8; 4] = [0xAB, 0xBA, 0xCD, 0xDC]; - let result_open = File::options(). - read(true). - write(true). - open(DISK_PATH); - - let magic_to_write : [u8 ; 4] = [0xAB, 0xBA, 0xCD, 0xDC]; - match result_open { - Err(e) => { //On creer le fichier et on y écrit le magic number println!("Error opening file : {}", e); - disk_file = File::options(). - read(true). - write(true). - create_new(true). - open(DISK_PATH).unwrap(); + disk_file = File::options() + .read(true) + .write(true) + .create_new(true) + .open(DISK_PATH) + .unwrap(); disk_file.set_len(DISK_SIZE as u64); disk_file.write_at(&magic_to_write[..], 0); @@ -58,24 +54,27 @@ impl Disk { disk_file.set_len(DISK_SIZE as u64); disk_file.write_at(&magic_to_write[..], 0); } - } match disk_file.read_at(&mut magic_buff[..], 0) { - Ok(t) => { println!("init_disk :: on a lu {} octets", t); - readed_magic_number = ((magic_buff[0] as u32) <<24) - + ((magic_buff[1] as u32) <<16) - + ((magic_buff[2] as u32) <<8) - + ((magic_buff[3] as u32) <<0); + readed_magic_number = ((magic_buff[0] as u32) << 24) + + ((magic_buff[1] as u32) << 16) + + ((magic_buff[2] as u32) << 8) + + ((magic_buff[3] as u32) << 0); if readed_magic_number != MAGIC_NUMBER { - panic!("init_disk :: Did not recognize magic number at the beginning of disk_file, - On a lu {:#08x}, Panic", readed_magic_number); - } - else { - println!("init_disk :: on a lu le magic_number {:#08x}", readed_magic_number); + panic!( + "init_disk :: Did not recognize magic number at the beginning of disk_file, + On a lu {:#08x}, Panic", + readed_magic_number + ); + } else { + println!( + "init_disk :: on a lu le magic_number {:#08x}", + readed_magic_number + ); } } @@ -83,11 +82,11 @@ impl Disk { println!("init_disk :: Error reading file : {}", e); } } - + Disk { last_sector: 0, active: false, - disk_file: disk_file + disk_file: disk_file, } } @@ -110,7 +109,8 @@ impl Disk { } disk.active = true; - disk.disk_file.seek(SeekFrom::Start((sector_number * SECTOR_SIZE) as u64))?; + disk.disk_file + .seek(SeekFrom::Start((sector_number * SECTOR_SIZE) as u64))?; let mut buffer = [0; SECTOR_SIZE as usize]; disk.disk_file.read(&mut buffer)?; for byte in buffer { @@ -142,7 +142,8 @@ impl Disk { } disk.active = true; - disk.disk_file.seek(SeekFrom::Start((sector_number * SECTOR_SIZE) as u64))?; + disk.disk_file + .seek(SeekFrom::Start((sector_number * SECTOR_SIZE) as u64))?; let mut i = 0; let mut buff = Vec::new(); for value in data { @@ -163,9 +164,7 @@ impl Disk { } } - -pub fn stupid_fct(buf : &[u8]){ - +pub fn stupid_fct(buf: &[u8]) { println!("Size of unknown sized parameter buffer : {}", buf.len()); for i in 0..buf.len() { println!("buf[{}] = {}", i, buf[i]); @@ -184,7 +183,7 @@ mod test { #[test] #[serial] fn test_init_stupid_fct() { - let buffy: [u8 ; 6] = [1,2,3,4,5,6]; + let buffy: [u8; 6] = [1, 2, 3, 4, 5, 6]; stupid_fct(&buffy); //EN passant par une ref , on s'abstrait du besoin de connaitre la taille au moment de la compilation @@ -214,11 +213,11 @@ mod test { data1.push(1 as u8); let mut data2: Vec = Vec::new(); - + Disk::write_request(&mut disk, 0, &mut data); Disk::write_request(&mut disk, 1, &mut data1); Disk::read_request(&mut disk, 1, &mut data2); - + assert_eq!(data1, data2); assert_ne!(data, data1); assert_ne!(data, data2); diff --git a/src/utility/bitmap.rs b/src/utility/bitmap.rs new file mode 100644 index 0000000..4af76a1 --- /dev/null +++ b/src/utility/bitmap.rs @@ -0,0 +1,143 @@ +pub const BITS_IN_BYTE: usize = 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, + map: Vec, +} + +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) { + self.mark(i); + return i as i32; + } + } + -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"); + + let word_idx = which / BITS_IN_WORD; + let bit_idx = which % BITS_IN_WORD; + 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 { + if !self.test(i) { + count += 1; + } + } + 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 { + if self.test(i) { + print!("{}, ", i); + } + } + 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)?; + + // Lit les octets du fichier dans un buffer + let mut buffer = vec![0; self.num_words * std::mem::size_of::()]; + file.read_exact(&mut buffer)?; + + // Convertit les octets en vecteur de u32 + self.map = vec![0; self.num_words]; + for i in 0..self.num_words { + let j = i * std::mem::size_of::(); + let bytes = [ + buffer[j], buffer[j+1], buffer[j+2], buffer[j+3] + ]; + self.map[i] = u32::from_le_bytes(bytes); + } + + 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()); + for u32_val in self.map.as_mut_slice() { + cursor.write_all(&u32_val.to_le_bytes())?; + } + + // Ouvre le fichier en mode écriture + let mut file = File::create(file_path)?; + + // Écrit les données dans le fichier + file.write_all(&cursor.into_inner())?; + + Ok(()) + } +} \ No newline at end of file diff --git a/src/utility/mod.rs b/src/utility/mod.rs index 651aed7..6db23f2 100644 --- a/src/utility/mod.rs +++ b/src/utility/mod.rs @@ -1 +1,2 @@ -pub mod list; \ No newline at end of file +pub mod list; +pub mod bitmap; \ No newline at end of file