merge and some fix
This commit is contained in:
commit
391359a54e
@ -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() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -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 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
|
/// decompose the name of the first directory
|
||||||
/// of the path given in argument, as well as the remainder of the path.
|
/// 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).
|
/// - **name** is the complete name (relatively to the root directory).
|
||||||
/// its content will be modified!
|
/// its content will be modified!
|
||||||
pub fn find_dir(name: &mut String) -> i32 {
|
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());
|
directory.fetch_from(filesys::get_dir_file());
|
||||||
|
|
||||||
let mut sector = DIRECTORY_SECTOR;
|
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
|
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() {
|
if file.get_file_header().is_dir() {
|
||||||
directory.fetch_from(&file);
|
directory.fetch_from(&file);
|
||||||
} else {
|
} else {
|
||||||
@ -79,25 +85,403 @@ pub fn find_dir(name: &mut String) -> i32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct Filesys {
|
pub struct Filesys {
|
||||||
pub free_map_file: Open_file, //Bit map of free disk blocks, represented as a file
|
pub free_map_file: OpenFile, //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 directory_file: OpenFile, //"Root" directory -- list of file names, represented as a file
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Filesys {
|
impl Filesys {
|
||||||
/// Initialize the file system.
|
/// Initialize the file system. If format = true, the disk has
|
||||||
/// If format = true, the disk has nothing on it,
|
/// nothing on it, and we need to initialize the disk to contain
|
||||||
/// and we need to initialize the disk to contain an empty directory,
|
/// an empty directory, and a bitmap of free sectors (with almost but
|
||||||
/// and a bitmap of free sectors (with almost but not all of the sectors marked as free).
|
/// not all of the sectors marked as free).
|
||||||
///
|
///
|
||||||
/// If format = false, we just have to open the files
|
/// If format = false, we just have to open the files
|
||||||
/// representing the bitmap and the directory.
|
/// 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
|
/// ### parameters
|
||||||
///
|
///
|
||||||
/// - **format** should we initialize the disk?
|
/// - **name** is the name of file to be created (NOT MODIFIED)
|
||||||
pub fn init_filesys(format: bool) -> Filesys {
|
/// - **initialSize** is the size of file to be created
|
||||||
if format {
|
pub fn create(self, name: String, initial_size: i32) -> Result<(), ErrorCode> {
|
||||||
let free_map = bitmap::init_bitmap();
|
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(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
pub mod directory;
|
pub mod directory;
|
||||||
|
pub mod filehdr;
|
||||||
pub mod filesys;
|
pub mod filesys;
|
||||||
pub mod fsmisc;
|
pub mod fsmisc;
|
||||||
|
pub mod oftable;
|
||||||
|
pub mod openfile;
|
||||||
|
@ -8,46 +8,42 @@ use std::os::unix::prelude::FileExt;
|
|||||||
pub const SECTORS_PER_TRACK: i32 = 32;
|
pub const SECTORS_PER_TRACK: i32 = 32;
|
||||||
pub const NUM_TRACKS: i32 = 64;
|
pub const NUM_TRACKS: i32 = 64;
|
||||||
pub const NUM_SECTORS: i32 = SECTORS_PER_TRACK * NUM_TRACKS;
|
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 DISK_PATH: &str = "disk_file";
|
||||||
|
|
||||||
pub const MAGIC_NUMBER : u32 = 0xABBACDDC;
|
pub const MAGIC_NUMBER: u32 = 0xABBACDDC;
|
||||||
//taille en octets, a confirmer
|
//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 struct Disk {
|
||||||
pub last_sector: i32,//Secteur accédé lors de la précédente requête de lecture/ecriture
|
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 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
|
pub disk_file: File, //On simule le disque sur un fichier
|
||||||
//Manque une ref a une fonction type handler, fournie via constructeur dans Nachos
|
//Manque une ref a une fonction type handler, fournie via constructeur dans Nachos
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Disk {
|
impl Disk {
|
||||||
pub fn init_disk() -> Disk {
|
pub fn init_disk() -> Disk {
|
||||||
|
|
||||||
//see Rust File impl FileExt for File For UNIX mode
|
//see Rust File impl FileExt for File For UNIX mode
|
||||||
let mut magic_buff : [u8 ; 4] = [0u8 ; 4];
|
let mut magic_buff: [u8; 4] = [0u8; 4];
|
||||||
let mut readed_magic_number : u32;
|
let mut readed_magic_number: u32;
|
||||||
let disk_file : File;
|
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 {
|
match result_open {
|
||||||
|
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
//On creer le fichier et on y écrit le magic number
|
//On creer le fichier et on y écrit le magic number
|
||||||
println!("Error opening file : {}", e);
|
println!("Error opening file : {}", e);
|
||||||
|
|
||||||
disk_file = File::options().
|
disk_file = File::options()
|
||||||
read(true).
|
.read(true)
|
||||||
write(true).
|
.write(true)
|
||||||
create_new(true).
|
.create_new(true)
|
||||||
open(DISK_PATH).unwrap();
|
.open(DISK_PATH)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
disk_file.set_len(DISK_SIZE as u64);
|
disk_file.set_len(DISK_SIZE as u64);
|
||||||
disk_file.write_at(&magic_to_write[..], 0);
|
disk_file.write_at(&magic_to_write[..], 0);
|
||||||
@ -58,24 +54,27 @@ impl Disk {
|
|||||||
disk_file.set_len(DISK_SIZE as u64);
|
disk_file.set_len(DISK_SIZE as u64);
|
||||||
disk_file.write_at(&magic_to_write[..], 0);
|
disk_file.write_at(&magic_to_write[..], 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
match disk_file.read_at(&mut magic_buff[..], 0) {
|
match disk_file.read_at(&mut magic_buff[..], 0) {
|
||||||
|
|
||||||
Ok(t) => {
|
Ok(t) => {
|
||||||
println!("init_disk :: on a lu {} octets", t);
|
println!("init_disk :: on a lu {} octets", t);
|
||||||
readed_magic_number = ((magic_buff[0] as u32) <<24)
|
readed_magic_number = ((magic_buff[0] as u32) << 24)
|
||||||
+ ((magic_buff[1] as u32) <<16)
|
+ ((magic_buff[1] as u32) << 16)
|
||||||
+ ((magic_buff[2] as u32) <<8)
|
+ ((magic_buff[2] as u32) << 8)
|
||||||
+ ((magic_buff[3] as u32) <<0);
|
+ ((magic_buff[3] as u32) << 0);
|
||||||
|
|
||||||
if readed_magic_number != MAGIC_NUMBER {
|
if readed_magic_number != MAGIC_NUMBER {
|
||||||
panic!("init_disk :: Did not recognize magic number at the beginning of disk_file,
|
panic!(
|
||||||
On a lu {:#08x}, Panic", readed_magic_number);
|
"init_disk :: Did not recognize magic number at the beginning of disk_file,
|
||||||
}
|
On a lu {:#08x}, Panic",
|
||||||
else {
|
readed_magic_number
|
||||||
println!("init_disk :: on a lu le magic_number {:#08x}", 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);
|
println!("init_disk :: Error reading file : {}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Disk {
|
Disk {
|
||||||
last_sector: 0,
|
last_sector: 0,
|
||||||
active: false,
|
active: false,
|
||||||
disk_file: disk_file
|
disk_file: disk_file,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,7 +109,8 @@ impl Disk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
disk.active = true;
|
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];
|
let mut buffer = [0; SECTOR_SIZE as usize];
|
||||||
disk.disk_file.read(&mut buffer)?;
|
disk.disk_file.read(&mut buffer)?;
|
||||||
for byte in buffer {
|
for byte in buffer {
|
||||||
@ -142,7 +142,8 @@ impl Disk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
disk.active = true;
|
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 i = 0;
|
||||||
let mut buff = Vec::new();
|
let mut buff = Vec::new();
|
||||||
for value in data {
|
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());
|
println!("Size of unknown sized parameter buffer : {}", buf.len());
|
||||||
for i in 0..buf.len() {
|
for i in 0..buf.len() {
|
||||||
println!("buf[{}] = {}", i, buf[i]);
|
println!("buf[{}] = {}", i, buf[i]);
|
||||||
@ -184,7 +183,7 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
#[serial]
|
#[serial]
|
||||||
fn test_init_stupid_fct() {
|
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);
|
stupid_fct(&buffy);
|
||||||
|
|
||||||
//EN passant par une ref , on s'abstrait du besoin de connaitre la taille au moment de la compilation
|
//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);
|
data1.push(1 as u8);
|
||||||
|
|
||||||
let mut data2: Vec<u8> = Vec::new();
|
let mut data2: Vec<u8> = Vec::new();
|
||||||
|
|
||||||
Disk::write_request(&mut disk, 0, &mut data);
|
Disk::write_request(&mut disk, 0, &mut data);
|
||||||
Disk::write_request(&mut disk, 1, &mut data1);
|
Disk::write_request(&mut disk, 1, &mut data1);
|
||||||
Disk::read_request(&mut disk, 1, &mut data2);
|
Disk::read_request(&mut disk, 1, &mut data2);
|
||||||
|
|
||||||
assert_eq!(data1, data2);
|
assert_eq!(data1, data2);
|
||||||
assert_ne!(data, data1);
|
assert_ne!(data, data1);
|
||||||
assert_ne!(data, data2);
|
assert_ne!(data, data2);
|
||||||
|
143
src/utility/bitmap.rs
Normal file
143
src/utility/bitmap.rs
Normal file
@ -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<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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<u32>;
|
||||||
|
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<u32>> {
|
||||||
|
// 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::<u32>()];
|
||||||
|
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::<u32>();
|
||||||
|
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::<u8>::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(())
|
||||||
|
}
|
||||||
|
}
|
@ -1 +1,2 @@
|
|||||||
pub mod list;
|
pub mod list;
|
||||||
|
pub mod bitmap;
|
Loading…
x
Reference in New Issue
Block a user