end of filesys
This commit is contained in:
commit
d620822d97
@ -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<Open_file> {
|
||||
let open_file : Open_file;
|
||||
pub fn open(name : String) -> Option<OpenFile> {
|
||||
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(())
|
||||
}
|
||||
}
|
@ -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<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) {
|
||||
@ -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<u32>> {
|
||||
// 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::<u8>::new());
|
||||
@ -98,5 +140,4 @@ impl BitMap {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user