47 Commits
main ... disk

Author SHA1 Message Date
364723984e bit_map full 2023-04-26 11:45:16 +02:00
88d8d9cd58 openfile adapté aux slices 2023-04-19 12:04:13 +02:00
d6eef6fe08 nom var 2023-04-19 01:03:52 +02:00
8b19189689 possibilité d'écrire et de lire plusieurs secteurs d'un coup 2023-04-19 00:55:53 +02:00
153c3d6618 switching from vec to slice 2023-04-19 00:31:46 +02:00
d6ac7671dc changing impl 2023-04-18 23:48:57 +02:00
9a23b1bb37 bitmap presque entièrement testé 2023-04-18 04:17:17 +02:00
347cdd9cf3 corrected filesys 2023-04-13 13:23:05 +02:00
69a8a0d4ea modificiation of directory 2023-04-13 11:11:16 +02:00
85e999a7b0 no more errors in filesys & fsmisc... for now 2023-04-05 17:23:54 +02:00
dae609c6ed Merge branch 'disk' of gitlab.istic.univ-rennes1.fr:simpleos/burritos into disk 2023-04-05 16:50:05 +02:00
551c9079b9 adding filesys & drvdisk in params of filesys and fsmisc 2023-04-05 16:44:28 +02:00
d6ed2f1d75 modification of the bitmap::fetch_from et bitmap::write_back 2023-04-05 16:38:36 +02:00
4d2f27b3b2 removed drv_disk from init file header 2023-04-05 16:14:40 +02:00
1a884f2e98 FileHdr write_back 2023-04-05 13:34:37 +02:00
00b4ed0066 latest version of directory 2023-04-05 10:51:18 +02:00
6ad3b36201 impl oft to finish 2023-04-05 01:26:17 +02:00
3f3c79ec0c Merge branch 'disk' of https://gitlab.istic.univ-rennes1.fr/simpleos/burritos into disk 2023-04-04 21:52:20 +02:00
25140bda17 ajout de directory.rs 2023-04-04 21:51:45 +02:00
61b3643945 more impl open file 2023-04-04 20:37:10 +02:00
2549103636 open_file impl 2023-04-03 22:48:22 +02:00
856cbdfe01 adding getters in filesys.rs 2023-03-29 18:25:30 +02:00
391359a54e merge and some fix 2023-03-29 18:22:45 +02:00
f4420d9306 filesys.rs : decompname & find_dir 2023-03-29 18:04:55 +02:00
4633c512bd added num_dir_entries & directory_file_size in filesys.rs 2023-03-29 16:53:08 +02:00
d620822d97 end of filesys 2023-03-29 16:23:36 +02:00
58e866cb2f filesys : open & create 2023-03-29 15:10:11 +02:00
60410efd1a bug fix of bitmap constructor 2023-03-29 15:05:07 +02:00
1da8b8465f commented the bitmap + init_bitmap + init_file_hdr 2023-03-29 15:02:04 +02:00
6ac67efe2d merge 2023-03-29 13:26:09 +02:00
1c0f0765c0 init_filesys done 2023-03-29 13:24:12 +02:00
c1f436bcfb resolved merge conflict 2023-03-29 13:22:15 +02:00
99a69c7998 filehdr nearly done 2023-03-29 13:20:44 +02:00
52929cef24 added the bitmap, tests still need to be done 2023-03-29 13:17:21 +02:00
79bfcf6b57 fsmisc done 2023-03-23 12:59:33 +01:00
021aac6e6a new files 2023-03-22 16:11:03 +01:00
3be14e7f6a test with files are now sequentials 2023-03-22 16:01:53 +01:00
b07c675986 update disk 2023-03-22 15:43:10 +01:00
12c28f7681 read disk works 2023-03-22 15:33:33 +01:00
2413d4dec6 use a of file for disk 2023-03-22 11:50:56 +01:00
bc970a9603 disk test 2023-03-18 12:38:13 +01:00
274a8d2c0e disk doc 2023-03-17 17:39:14 +01:00
c5c82ac567 added tests for drv_disk 2023-03-16 23:35:13 +01:00
edf593cbf8 the driver and disk are working 2023-03-16 17:16:24 +01:00
4c81f0591a nouvelle version du driver et du disk 2023-03-16 15:59:58 +01:00
66eaa8a64f start of Disk 2023-03-15 17:53:10 +01:00
38004e0bc4 rename file 2023-03-15 16:19:29 +01:00
19 changed files with 2594 additions and 5 deletions

343
Cargo.lock generated
View File

@ -2,15 +2,358 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "burritos"
version = "0.1.0"
dependencies = [
"libc",
"serial_test",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "dashmap"
version = "5.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc"
dependencies = [
"cfg-if",
"hashbrown",
"lock_api",
"once_cell",
"parking_lot_core",
]
[[package]]
name = "futures"
version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "531ac96c6ff5fd7c62263c5e3c67a603af4fcaee2e1a0ae5565ba3a11e69e549"
dependencies = [
"futures-channel",
"futures-core",
"futures-executor",
"futures-io",
"futures-sink",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-channel"
version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "164713a5a0dcc3e7b4b1ed7d3b433cabc18025386f9339346e8daf15963cf7ac"
dependencies = [
"futures-core",
"futures-sink",
]
[[package]]
name = "futures-core"
version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86d7a0c1aa76363dac491de0ee99faf6941128376f1cf96f07db7603b7de69dd"
[[package]]
name = "futures-executor"
version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1997dd9df74cdac935c76252744c1ed5794fac083242ea4fe77ef3ed60ba0f83"
dependencies = [
"futures-core",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-io"
version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89d422fa3cbe3b40dca574ab087abb5bc98258ea57eea3fd6f1fa7162c778b91"
[[package]]
name = "futures-sink"
version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec93083a4aecafb2a80a885c9de1f0ccae9dbd32c2bb54b0c3a65690e0b8d2f2"
[[package]]
name = "futures-task"
version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd65540d33b37b16542a0438c12e6aeead10d4ac5d05bd3f805b8f35ab592879"
[[package]]
name = "futures-util"
version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ef6b17e481503ec85211fed8f39d1970f128935ca1f814cd32ac4a6842e84ab"
dependencies = [
"futures-channel",
"futures-core",
"futures-io",
"futures-sink",
"futures-task",
"memchr",
"pin-project-lite",
"pin-utils",
"slab",
]
[[package]]
name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.139"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
[[package]]
name = "lock_api"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
dependencies = [
"autocfg",
"scopeguard",
]
[[package]]
name = "log"
version = "0.4.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
dependencies = [
"cfg-if",
]
[[package]]
name = "memchr"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "once_cell"
version = "1.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
[[package]]
name = "parking_lot"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
dependencies = [
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.9.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"windows-sys",
]
[[package]]
name = "pin-project-lite"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
[[package]]
name = "pin-utils"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "proc-macro2"
version = "1.0.53"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba466839c78239c09faf015484e5cc04860f88242cff4d03eb038f04b4699b73"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc"
dependencies = [
"proc-macro2",
]
[[package]]
name = "redox_syscall"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
dependencies = [
"bitflags",
]
[[package]]
name = "scopeguard"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "serial_test"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "538c30747ae860d6fb88330addbbd3e0ddbe46d662d032855596d8a8ca260611"
dependencies = [
"dashmap",
"futures",
"lazy_static",
"log",
"parking_lot",
"serial_test_derive",
]
[[package]]
name = "serial_test_derive"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "079a83df15f85d89a68d64ae1238f142f172b1fa915d0d76b26a7cba1b659a69"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "slab"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d"
dependencies = [
"autocfg",
]
[[package]]
name = "smallvec"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
[[package]]
name = "windows-sys"
version = "0.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
[[package]]
name = "windows_i686_gnu"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
[[package]]
name = "windows_i686_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"

View File

@ -5,3 +5,4 @@ edition = "2021"
[dependencies]
libc = { version = "0.2.139", features = ["extra_traits"] }
serial_test = "*"

BIN
disk_file Normal file

Binary file not shown.

113
src/drivers/drv_disk.rs Normal file
View File

@ -0,0 +1,113 @@
use crate::Disk;
/// driver disk
pub struct DrvDisk {
disk: Disk,
}
impl DrvDisk {
///initialize the disk ok the current driver
pub fn init_drv_disk(disk: Disk) -> DrvDisk {
DrvDisk { disk: disk }
}
/// read inside the disk
///
/// ### Parameters
///
/// - **self** driver disk
/// - **sector_number** sector where to read the data
/// - **data** where the readed data will be stored
pub fn read_sector(&mut self, sector_number: i32, data: &mut [u8]) {
match Disk::read_request(&mut self.disk, sector_number, data) {
Err(e) => println!("{:?}", e),
_ => (),
}
}
/// write inside the disk
///
/// ### Parameters
///
/// - **self** driver disk
/// - **sector_number** sector where to write the data
/// - **data** where the data to write is stored
pub fn write_sector(&mut self, sector_number: i32, data: &[u8]) {
match Disk::write_request(&mut self.disk, sector_number, data) {
Err(e) => println!("{:?}", e),
_ => (),
}
}
/// read inside the disk
///
/// ### Parameters
///
/// - **self** driver disk
/// - **sector_number** sector where to read the data
/// - **data** where the readed data will be stored
pub fn read_multiple_sector(&mut self, sector_number: i32, data: &mut [u8]) {
match Disk::read_multiple_request(&mut self.disk, sector_number, data) {
Err(e) => println!("{:?}", e),
_ => (),
}
}
/// write inside the disk
///
/// ### Parameters
///
/// - **self** driver disk
/// - **sector_number** sector where to write the data
/// - **data** where the data to write is stored
pub fn write_multiple_sector(&mut self, sector_number: i32, data: &[u8]) {
match Disk::write_multiple_request(&mut self.disk, sector_number, data) {
Err(e) => println!("{:?}", e),
_ => (),
}
}
}
#[cfg(test)]
mod test {
use serial_test::serial;
use super::DrvDisk;
use crate::Disk;
#[test]
#[serial]
fn test_init_driver() {
let disk = Disk::init_disk();
let _ = DrvDisk::init_drv_disk(disk);
}
#[test]
#[serial]
fn test_read_write_drv_disk() {
let disk = Disk::init_disk();
let mut drv_disk = DrvDisk::init_drv_disk(disk);
let mut data = Vec::new();
data.push(0 as u8);
data.push(0 as u8);
data.push(0 as u8);
data.push(0 as u8);
let mut data1 = Vec::new();
data1.push(1 as u8);
data1.push(1 as u8);
data1.push(1 as u8);
data1.push(1 as u8);
let mut data2: Vec<u8> = Vec::new();
drv_disk.write_sector(0, &mut data);
drv_disk.write_sector(1, &mut data1);
drv_disk.read_sector(1, &mut data2);
assert_eq!(data1, data2);
assert_ne!(data, data1);
assert_ne!(data, data2);
}
}

1
src/drivers/mod.rs Normal file
View File

@ -0,0 +1 @@
pub mod drv_disk;

178
src/filesys/directory.rs Normal file
View File

@ -0,0 +1,178 @@
const FILE_NAME_MAX_LEN: i32 = 80;
const NUM_DIR_ENTRIES: i32 = 30;
use crate::drivers::drv_disk::DrvDisk;
use crate::kernel::mgerror::ErrorCode;
use std::mem;
use super::openfile::OpenFile;
pub struct DirectoryEntry {
in_use: bool,
sector: i32,
name: [char; FILE_NAME_MAX_LEN as usize],
}
impl DirectoryEntry {
fn to_bytes(&self) -> Vec<u8> {
let mut bytes = Vec::new();
bytes.push(self.in_use as u8);
bytes.extend_from_slice(&self.sector.to_le_bytes());
for ch in &self.name {
bytes.extend_from_slice(&ch.encode_utf8(&mut [0; 4]).as_bytes());
}
bytes
}
}
fn entries_to_bytes(entries: &Vec<DirectoryEntry>) -> Vec<u8> {
let mut bytes = Vec::new();
for entry in entries {
bytes.extend_from_slice(&entry.to_bytes());
}
bytes
}
pub struct Directory {
table_size: i32,
table: Vec<DirectoryEntry>,
}
impl Directory {
/// Initialize a directory; initially, the directory is completely
/// empty. If the disk is being formatted, an empty directory
/// is all we need, but otherwise, we need to call FetchFrom in order
/// to initialize it from disk.
///
/// ### Parameters
/// - **size** is the number of entries in the directory
pub fn init_directory(size: i32) -> Directory {
let mut tmp:Vec<DirectoryEntry> = Vec::new();
for i in 0..size {
tmp[i as usize].in_use = false;
}
Directory {
table_size: size,
table: tmp,
}
}
pub fn fetch_from(&self,mut file: OpenFile, mut drv_disk: DrvDisk) {
OpenFile::read_at(&mut drv_disk, &mut file, &mut entries_to_bytes(&self.table), self.table_size * mem::size_of::<DirectoryEntry>() as i32, 0);
}
pub fn write_back(&self,mut file: OpenFile, mut drv_disk: DrvDisk) {
OpenFile::write_at(&mut drv_disk,&mut file,&mut entries_to_bytes(&self.table),self.table_size * mem::size_of::<DirectoryEntry>() as i32,0);
}
/// Look up file name in directory.
///
/// return its location in the table of directory entries,
/// ERROR if the name isn't in the directory.
///
/// ### Parameters
/// - **name** the file name to look up
pub fn find_index(&self, name: String) -> i32 {
for i in 0..self.table_size {
if self.table[i as usize].in_use && self.table[i as usize].name.starts_with(&self.table[i as usize].name) {
return i;
}
}
return -1;
}
/// Look up file name in directory, and return the disk sector number
/// where the file's header is stored. Return ERROR if the name isn't
/// in the directory.
///
/// return the disk sector number where the file's header is stored
/// or ERROR if the name isn't in the directory.
///
/// ### Parameters
///
/// - **name** the file name to look up
pub fn find(&self, name: String) -> i32 {
let i = self.find_index(name);
if i != -1 {
return self.table[i as usize].sector;
}
return -1;
}
///Add a file into the directory.
///
/// ### Parameters
/// - **name** the name of the file being added
/// - **new_sector** the disk sector containing the added file's header
///
/// return NO_ERROR, ALREADY_IN_DIRECTORY or NOSPACE_IN_DIRECTORY.
pub fn add(&mut self, name: String, new_sector: i32) -> Result<(), ErrorCode> {
if self.find_index(name) != -1 {
return Err(ErrorCode::AlreadyInDirectory);
}
for i in 0..self.table_size {
if !self.table[i as usize].in_use {
self.table[i as usize].in_use = true;
self.table[i as usize].name.starts_with(&self.table[i as usize].name);
self.table[i as usize].sector = new_sector;
return Ok(());
}
}
return Err(ErrorCode::NospaceInDirectory);
}
/// Remove a file name from the directory.
///
/// ### Parameters
/// - **name** the file name to be removed
/// return NO_ERROR, or INEXIST_DIRECTORY_ERROR
pub fn remove(&mut self, name: String) -> Result<(), ErrorCode> {
let i = self.find_index(name);
if i == -1 {
return Err(ErrorCode::InexistDirectoryError);
}
self.table[i as usize].in_use = false;
Ok(())
}
/// List all the file names in the directory.(recursive function)
///
/// ### Parameters
/// - **name** the name of the Dir to print
/// - **depth** the depth in the recursion (to print a nice hierarchy with spaces)
pub fn list(&self, name: char, depth: i32) {
let dir = Directory::init_directory(NUM_DIR_ENTRIES);
for i in 0..self.table_size {
if self.table[i as usize].in_use {
for j in 0..depth {
if j<depth-3 {
print!(" ");
}else if j==depth-3 {
print!("+");
}else if j>depth-3 {
print!("-");
}
}
print!("{:#?}",self.table[i as usize].name);
}
}
}
/// Return true if the directory is empty
pub fn is_empty(&mut self) -> bool {
let mut empty = true;
for i in 0..self.table_size {
if self.table[i as usize].in_use {
empty = false;
}
}
empty
}
}

262
src/filesys/filehdr.rs Normal file
View File

@ -0,0 +1,262 @@
use crate::drivers::drv_disk;
use crate::filesys::openfile;
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;
use std::mem;
use super::openfile::OpenFile;
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 init_file_hdr() -> FileHdr {
FileHdr {
is_dir: 0,
num_bytes: 0,
num_sectors: 0,
data_sectors: Vec::new(),
num_header_sectors: 0,
header_sectors: [0;MAX_HEADER_SECTORS as usize],
}
}
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 = openfile::div_round_up(file_size, SECTOR_SIZE);
self.num_header_sectors = openfile::div_round_up(self.num_sectors-DATAS_IN_FIRST_SECTOR, 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) as i32 {
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, free_map: &mut BitMap, old_file_size: i32, new_file_size: i32) -> bool {
let mut new_num_sectors = openfile::div_round_up(new_file_size, SECTOR_SIZE) - self.num_sectors;
self.num_bytes = new_file_size;
let mut new_num_header_sectors = openfile::div_round_up(self.num_sectors-DATAS_IN_FIRST_SECTOR, 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) as i32{
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);
}
}
///Fetch contents of file header from disk.
pub fn fetch_from(&mut self, sector: i32, drv_disk: &mut DrvDisk) {
//temporary buffer
let mut sector_img = vec![0; SECTOR_SIZE as usize / std::mem::size_of::<i32>() ];
let mut data_sectors = vec![0; MAX_DATA_SECTORS as usize];
// Fills the temporary buffer with zeros
sector_img.fill(0);
// Read the header from the disk
// and put it in the temporary buffer
DrvDisk::read_sector(&mut drv_disk, sector, &mut sector_img);
// Set up the memory image of the file header
// from the newly read buffer
self.is_dir = sector_img[0] as i32;
self.num_bytes = sector_img[1] as i32;
self.num_sectors = sector_img[2] as i32;
self.num_header_sectors = sector_img[3] as i32;
// Get the first header sector
self.header_sectors[0] = *FileHdr::next_header_sector(sector_img);
// Get the number of the data sectors stored into
// the header sector in disk
for i in 4..DATAS_IN_SECTOR as usize {
data_sectors[i - 4] = sector_img[i];
}
// Get the other numbers of header sectors and data sectors
for i in 0..self.num_header_sectors as usize {
// Fill the temporary buffer with zeroes
sector_img.fill(0);
DrvDisk::read_sector(&mut drv_disk, self.header_sectors[i], &mut sector_img);
for j in 0..DATAS_IN_SECTOR as usize {
data_sectors[DATAS_IN_FIRST_SECTOR as usize + i * DATAS_IN_SECTOR as usize + j] = sector_img[j];
}
// Make sure we don't go out of bounds
if i + 1 < self.num_header_sectors as usize {
self.header_sectors[i + 1] = *FileHdr::next_header_sector(&mut sector_img);
}
}
}
pub fn write_back(&self, sector: i32, drv_disk: &mut DrvDisk) {
let mut sector_img = vec![0; DATAS_IN_SECTOR as usize];
// Fills the temporary buffer with zeroes
sector_img.fill(0);
// Fills the header of the first header sector
sector_img[0] = self.is_dir;
sector_img[1] = self.num_bytes;
sector_img[2] = self.num_sectors;
sector_img[3] = self.num_header_sectors;
// Fills the number of the data sectors and the first header
// sector in the temporary buffer
for i in 4..DATAS_IN_SECTOR as usize {
sector_img[i] = self.data_sectors[(i - 4)];
}
// Write the first header sector into disk
*FileHdr::next_header_sector(&mut sector_img) = self.header_sectors[0];
let mut vec_u8: Vec<u8> = sector_img.iter().map(|&x| x as u8).collect();
DrvDisk::write_sector(&mut drv_disk, sector, &mut vec_u8);
// Write the following header sectors into disk
for i in 0..self.num_header_sectors {
sector_img.fill(0);
for j in 0..DATAS_IN_SECTOR {
sector_img[j as usize] = self.data_sectors[(j + DATAS_IN_FIRST_SECTOR + i * DATAS_IN_SECTOR) as usize];
}
if i + 1 < self.num_header_sectors {
*FileHdr::next_header_sector(&mut sector_img) = self.header_sectors[(i + 1) as usize];
} else {
*FileHdr::next_header_sector(&mut sector_img) = 0;
}
let mut vec_u8: Vec<u8> = sector_img.iter().map(|&x| x as u8).collect();
DrvDisk::write_sector(&mut drv_disk, self.header_sectors[i as usize], &mut vec_u8);
}
}
pub fn next_header_sector(hdr_sector: &mut [i32]) -> &mut i32 {
let sector_size = SECTOR_SIZE as usize / std::mem::size_of::<i32>();
&mut hdr_sector[sector_size - 1]
}
pub fn byte_to_sector(&self,offset: usize) -> 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, drv_disk: &mut DrvDisk) {
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 {
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() {
}
}

508
src/filesys/filesys.rs Normal file
View File

@ -0,0 +1,508 @@
use crate::{kernel::mgerror::ErrorCode, simulator::disk, utility::bitmap::BitMap, drivers::drv_disk::DrvDisk, filesys::openfile};
use super::{filehdr::FileHdr, openfile::OpenFile, directory::Directory};
pub const ERROR: i32 = -1;
pub const FREE_MAP_SECTOR: i32 = 0;
pub const DIRECTORY_SECTOR: i32 = 1;
pub const NUM_DIR_ENTRIES: i32 = 10;
pub const DIRECTORY_FILE_SIZE: i32 = 100; //std::mem::size_of<Directory>() * NUM_DIR_ENTRIES;
pub const FREE_MAP_FILE_PATH : &str = "free_map_file";
pub const DIRECTORY_FILE_PATH : &str = "directory_file";
/// decompose the name of the first directory
/// of the path given in argument, as well as the remainder of the path.
/// if we call decompname("/bin/new/halt", head, tail), we get "bin" in head and "/new/halt" in tail
/// returns true if everything goes ok, otherwise, return false.
/// head and tail MUST be large enough to contain the resulting strings
///
/// ### parameters
///
/// - **orig_path** the pathname we want to decompose
/// - **head** the first element in the path (for instance "bin")
/// - **tail** the remainder of the string (for instance "/new/halt")
pub fn decomp_name(origin_path: String, head: &mut String, tail: &mut String) -> bool {
let mut working_path = origin_path;
// remove the leading "/" if any
if working_path.get(0..1).unwrap_or_else(|| "").eq("/") {
working_path = (&working_path[1..]).to_string();
}
if working_path.contains("/") {
let index = working_path.find("/").expect("shouldn't happen");
*head = working_path[..index].to_string();
*tail = working_path[index..].to_string();
return true;
} else {
*head = "".to_string();
*tail = origin_path;
return false;
}
}
/// this function takes a complete pathname and returns
/// the disc sector of the fileheader of the directory.
/// return -1 in case of error
///
/// IMPORTANT WARNING : name is modified : after the execution, name
/// contains only the name of the file
/// (e.g. if we called find_dir("/bin/halt") then name is "halt" after the execution,
/// the function returns the sector number of the directory "/bin").
///
/// Actually, this function does not support complete pathnames
/// This is one of the objectives of the file system assignment
///
/// ### parameters
///
/// - **name** is the complete name (relatively to the root directory).
/// its content will be modified!
pub fn find_dir(name: &mut String, file_sys : Filesys, drv_disk : DrvDisk) -> i32 {
let directory = Directory::init_directory(NUM_DIR_ENTRIES);
directory.fetch_from(file_sys.get_dir_file(), drv_disk);
let mut sector = DIRECTORY_SECTOR;
let mut dirname = String::from("");
let mut reminder = String::from("");
while decomp_name(name.to_string(), &mut dirname, &mut reminder) {
*name = reminder;
// Get the sector of the file/directory corresponding to 'name'
sector = directory.find(dirname);
if sector < 0 {
return -1; // This file/directory does not exist
}
let file = OpenFile::open_file(sector);
if file.hdr.is_dir() {
directory.fetch_from(file, drv_disk);
} else {
return -1;
}
}
*name = reminder;
sector
}
pub struct Filesys {
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).
///
/// 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, mut drv_disk : DrvDisk) -> Filesys {
if format {
let mut free_map = BitMap::init_bitmap(disk::NUM_SECTORS as usize);
let mut directory = Directory::init_directory(NUM_DIR_ENTRIES);
free_map.mark(FREE_MAP_SECTOR as usize);
free_map.mark(DIRECTORY_SECTOR as usize);
let mut map_header: FileHdr;
let mut 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, &mut drv_disk);
dir_header.write_back(DIRECTORY_SECTOR, &mut drv_disk);
let mut free_map_file = OpenFile::open_file(FREE_MAP_SECTOR);
let directory_file = OpenFile::open_file(DIRECTORY_SECTOR);
free_map.write_back(&mut free_map_file, &mut drv_disk);
directory.write_back(directory_file, drv_disk);
Filesys {
free_map_file,
directory_file,
}
} else {
Filesys {
free_map_file: OpenFile::open_file(FREE_MAP_SECTOR),
directory_file: OpenFile::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
///
/// - **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, mut drv_disk : DrvDisk) -> Result<(), ErrorCode> {
//lock.acquire();
let mut dir_name = name.clone();
let dir_sector = find_dir(&mut dir_name, *self, drv_disk);
if dir_sector == ERROR {
//lock.release();
return Err(ErrorCode::InexistFileError);
}
let dir_file = OpenFile::open_file(dir_sector);
let mut directory = Directory::init_directory(NUM_DIR_ENTRIES);
directory.fetch_from(dir_file, drv_disk);
if directory.find(dir_name) != ERROR {
//lock.release();
return Err(ErrorCode::AlreadyInDirectory);
}
// Get the freemap from the disk
let mut free_map = BitMap::init_bitmap(disk::NUM_SECTORS as usize);
free_map.fetch_from(&mut self.free_map_file, &mut drv_disk);
// 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 mut 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, &mut drv_disk);
directory.write_back(dir_file, drv_disk);
free_map.write_back(&mut self.free_map_file, &mut drv_disk);
//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(self, name: String, file_sys : Filesys, drv_disk : DrvDisk) -> Option<OpenFile> {
let mut open_file: OpenFile;
let mut dir_name = name.clone();
// Find the directory containing the file
let dir_sector = find_dir(&mut dir_name, file_sys, drv_disk);
if dir_sector == ERROR {
return None;
}
// Read the directory from disk
let dir_file = OpenFile::open_file(dir_sector);
let directory = Directory::init_directory(NUM_DIR_ENTRIES);
directory.fetch_from(dir_file, drv_disk);
// Find the file in the directory
let sector = directory.find(dir_name);
if sector >= 0 {
open_file = OpenFile::open_file(sector);
open_file.name = name;
if open_file.hdr.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(&mut self, name: String, file_sys : Filesys, mut drv_disk : DrvDisk) -> Result<(), ErrorCode> {
let mut dir_name = name.clone();
// Get the sector number of the parent directory
let dir_sector = find_dir(&mut dir_name, file_sys, drv_disk);
// Check if the path is correct
if dir_sector == ERROR {
return Err(ErrorCode::InexistDirectoryError);
}
// Fetch the directory from the disk
let dir_file = OpenFile::open_file(dir_sector);
let mut directory = Directory::init_directory(NUM_DIR_ENTRIES);
directory.fetch_from(dir_file, drv_disk);
// 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 mut file_hdr: FileHdr;
file_hdr.fetch_from(sector, &mut drv_disk);
// Do nothing if it's a directory
if file_hdr.is_dir() {
return Err(ErrorCode::NotAFile);
}
// Get the freemap file from the disk
let mut free_map = BitMap::init_bitmap(disk::NUM_SECTORS as usize);
free_map.fetch_from(&mut self.free_map_file, &mut drv_disk);
// Indicate that sectors are deallocated in the freemap
file_hdr.deallocate(free_map);
free_map.clear(sector as usize);
// Remove the file from the directory
directory.remove(dir_name);
// Flush everything to disk
free_map.write_back(&mut self.free_map_file, &mut drv_disk);
directory.write_back(dir_file, drv_disk);
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
}
/*
Temporairement, et pour des raison de test,
Nous allons utiliser un fichier unix dans lequels
Donc pour le moment ces fonctions renvoient le nom fichier contenant ces infos
*/
/// return the free map file (used by the open file table).
///
pub fn get_free_map_file() -> String {
//return self.free_map_file.get_name();
return String::from(FREE_MAP_FILE_PATH);
}
/// return the base directory file (used by the open file table).
pub fn get_dir_file() -> String {
//return self.directory_file.get_name();
return String::from(DIRECTORY_FILE_PATH);
}
/// 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(&mut self, name: String, file_sys : Filesys, mut drv_disk : DrvDisk) -> 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, file_sys, drv_disk);
if parent_sector < 0 {
return Err(ErrorCode::InexistDirectoryError);
}
// Fetch it from disk
let parent_dir_file = OpenFile::open_file(parent_sector);
let mut parent_dir = Directory::init_directory(NUM_DIR_ENTRIES);
parent_dir.fetch_from(parent_dir_file, drv_disk);
// Check that the directory does not exit yet
if parent_dir.find(dir_name) >= 0 {
return Err(ErrorCode::AlreadyInDirectory);
}
// Get the freemap
let mut free_map = BitMap::init_bitmap(disk::NUM_SECTORS as usize);
free_map.fetch_from(&mut self.free_map_file, &mut drv_disk);
// 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 mut 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, &mut drv_disk);
// New directory (initially empty)
let new_dir_file = OpenFile::open_file(hdr_sector);
let new_dir = Directory::init_directory(NUM_DIR_ENTRIES);
new_dir.write_back(new_dir_file, drv_disk);
// Parent directory
parent_dir.write_back(parent_dir_file, drv_disk);
free_map.write_back(&mut self.free_map_file, &mut drv_disk);
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(&mut self, name: String, file_sys : Filesys, mut drv_disk : DrvDisk) -> Result<(), ErrorCode> {
let mut dir_name = name.clone();
// Get the sector number of the parent directory
let parent_sector = find_dir(&mut dir_name, file_sys, drv_disk);
if parent_sector < 0 {
return Err(ErrorCode::InexistDirectoryError);
}
// Fetch it from disk
let parent_dir_file = OpenFile::open_file(parent_sector);
let mut parent_dir = Directory::init_directory(NUM_DIR_ENTRIES);
parent_dir.fetch_from(parent_dir_file, drv_disk);
// 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 mut the_dir_header: FileHdr;
the_dir_header.fetch_from(the_dir_sector, &mut drv_disk);
// 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::open_file(the_dir_sector);
let mut the_dir = Directory::init_directory(NUM_DIR_ENTRIES);
the_dir.fetch_from(the_dir_file, drv_disk);
// Check that is is empty
if !the_dir.is_empty() {
return Err(ErrorCode::DirectoryNotEmpty);
}
// Get the freemap from disk
let mut free_map = BitMap::init_bitmap(disk::NUM_SECTORS as usize);
free_map.fetch_from(&mut self.free_map_file, &mut drv_disk);
// 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 as usize);
// We remove the directory from its parent directory
parent_dir.remove(dir_name);
// Flush everything to disk
free_map.write_back(&mut self.free_map_file, &mut drv_disk);
parent_dir.write_back(parent_dir_file, drv_disk);
Ok(())
}
}

90
src/filesys/fsmisc.rs Normal file
View File

@ -0,0 +1,90 @@
use std::{
fs::File,
io::{Read, Seek, SeekFrom},
};
use crate::drivers::drv_disk::DrvDisk;
use super::{filesys::Filesys, openfile::OpenFile};
pub const TRANSFER_SIZE: usize = 10;
/// copy the contents of the UNIX file "from" to the BurritOS file "to"
///
/// `panic!` when the file from doesn't exist
///
/// ### parameters
///
/// - **from** file UNIX
/// - **to** BurritOS file
pub fn copy(from: String, to: String, file_sys : Filesys, mut drv_disk : DrvDisk) {
let file_from_opt = File::options().read(true).open(from);
let mut file_from: File;
match file_from_opt {
Err(e) => {
panic!("Copy: couldn't open Unix file {}", from);
}
Ok(f) => {
file_from = f;
}
}
let mut file_length_buf = [0; 1];
file_from.seek(SeekFrom::End(2));
file_from.read(&mut file_length_buf);
file_from.seek(SeekFrom::Start(0));
let file_length = file_length_buf[0];
file_sys.create(to, file_length as i32, file_sys, drv_disk);
let mut open_file_opt = file_sys.open(to, file_sys, drv_disk);
let open_file : &mut OpenFile;
match open_file_opt {
Some(f) => {
open_file = &mut f;
},
None => return
}
let mut buffer = Vec::new();
loop {
let amount_read = file_from
.read(&mut buffer)
.expect("copy : couldn't read the UNIX file");
OpenFile::write(&mut drv_disk, open_file, &mut buffer, TRANSFER_SIZE as i32);
if amount_read != TRANSFER_SIZE {
break;
}
}
}
/// Print the contents of the BurritOS file "name".
///
/// `panic!` when the file name doesn't exist
///
/// ### parameters
///
/// - **name** of the BurritOS file
pub fn print(name: String, file_sys : Filesys, mut drv_disk : DrvDisk) {
let mut open_file_opt = file_sys.open(name, file_sys, drv_disk);
let open_file : &mut OpenFile;
match open_file_opt {
Some(mut f) => {
open_file = &mut f;
},
None => return
}
let mut buffer = Vec::new();
loop {
let amount_read = OpenFile::read(&mut drv_disk, open_file, &mut buffer, TRANSFER_SIZE as i32);
for i in 0..amount_read {
print!("{:1x} ", buffer[i as usize]);
}
if amount_read != TRANSFER_SIZE as i32 {
break;
}
}
}

6
src/filesys/mod.rs Normal file
View File

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

153
src/filesys/oftable.rs Normal file
View File

@ -0,0 +1,153 @@
use super::openfile::OpenFile;
pub const MAX_OF_TABLE_ENTRY : i32 = 500;
pub struct OpenFileTableEntry {
name : String,
pub file : Option<OpenFile>,
pub num_thread : i32,//number of threads havng that file open
//lock : Lock,
pub to_be_deleted : bool,//si mis a true, quand ce fichier n'est plus ouvert par aucun thread, il doit etre supprimé
pub sector : i32,//secteur disque ou se situe le header de ce fichier
}
pub struct OpenFileTable{
table : Vec<Option<OpenFileTableEntry>>,
nb_entry : i32//numero du prochain fichier ouvert/prochaine entrée
}
impl OpenFileTableEntry {
pub fn new() -> OpenFileTableEntry {
OpenFileTableEntry {
name : String::new(),
file : None,
num_thread : 1,
to_be_deleted : false,
sector : -1
}
}
}
impl OpenFileTable{
pub fn open(oft : &mut OpenFileTable, name : String)-> Option<OpenFile>{
let mut num : i32;
let mut sector : i32;
let mut dirsector : i32;
let mut file_name = String::new();
//Impl le trait copy sur open file
num = OpenFileTable::findl(oft, &name);
//no error
if num != -1 {
//the file is opened by another thread
match oft.table[num as usize] {
Some(e) => {
if !e.to_be_deleted{
e.num_thread += 1;
let new_file : OpenFile = OpenFile::open_file(e.sector);
new_file.name = name.clone();
return Some(new_file);
}
else {
return None;
}
}
None => {
println!("OpenFileTale :: open :: Error opening {}", name);
return None;
}
}
}
//file is not opened yet
else {
if(oft.nb_entry != -1){
//il reste de la place
let mut new_entry : OpenFileTableEntry = OpenFileTableEntry::new();
let mut open_file : OpenFile;
let mut new_file : OpenFile;
//on va creer, si fichier present sur disque, deux objet open_file,
//open_file ira dans la table
//new_file sera renvoyé
}
}
return None;
}
pub fn close(name : String){
}
pub fn file_lock(name : String){
}
pub fn file_release(name : String){
}
pub fn remove(name : String)-> i32{
0
}
pub fn next_entry(oft : &mut OpenFileTable)-> i32{
let mut i = 0;
for entry in oft.table.iter(){
match entry {
None => {
return i;
}
_ => {
i+=1;
}
}
}
0
}
pub fn findl(oft : &mut OpenFileTable, name : &String)-> i32{
let mut i = 0;
for entry in oft.table.iter(){
match entry {
Some(e) => {
if e.name.eq(name){
return i;
}
}
_ => {}
}
i+=1
}
-1
}
}

156
src/filesys/openfile.rs Normal file
View File

@ -0,0 +1,156 @@
use crate::{simulator::{self, disk}, drivers::drv_disk::{DrvDisk, self}, utility::bitmap::BitMap};
use super::{filehdr::FileHdr, filesys::{Filesys, self}};
pub const MAX_FILE_NAME_SIZE : i32 = 500;
pub struct OpenFile {
pub name : String, // the file's
pub hdr : FileHdr, // Header for this file
pub seekPosition : i32, // Current position in the file (in byte)
pub fSector : i32 // this file first sector on the disk (fichiers stockés de maniere contigue)
}
//division arrondie vers le bas
pub fn div_round_down(a : i32, b : i32) -> i32{
a/b
}
//division arrondie vers le haut
pub fn div_round_up(a : i32, b : i32) -> i32{
let mut result = a/b;
if a%b > 0 {
result + 1
}
else {
result
}
}
impl OpenFile {
/*
Creer un "fichier ouvert", charge le file_hdr depuis disk
*/
pub fn open_file(sector : i32) -> OpenFile{
let file_hdr : FileHdr = FileHdr::init_file_hdr();
let name : String = String::from("");
//ici appel a fetchFrom(sector) sur file_hdr
OpenFile { name: name,
hdr: file_hdr,
seekPosition: 0,
fSector: sector }
}
pub fn seek(file : &mut OpenFile, position : i32){
file.seekPosition = position;
}
/* params :
into : buffer de reception
num_bytes : nombre d'octets à lire
position : position du premier octet à lire dans le fichier (header compté??)
*/
pub fn read_at(driver_disk : &mut DrvDisk, file : &mut OpenFile, into : &mut Vec<u8>, num_bytes : i32, position : i32) -> i32 {
let mut nbr_octet_lu = num_bytes;
let file_length = file.hdr.file_length();
//on transforme position (position en octets) en un numéro de secteur
let sector_position = position/disk::SECTOR_SIZE;
if ( num_bytes <= 0)||( position < 0)||( position >= file_length) {
return 0;
}
if (position + num_bytes > file_length) {
nbr_octet_lu = file_length - position;
}
DrvDisk::read_multiple_sector(driver_disk, sector_position, &mut into[..]);
nbr_octet_lu
}
/* params :
from : données à écrire
num_bytes : nombre d'octets à écrire depuis from
position : position du premier octet à écrire dans le fichier(header compté??)
*/
pub fn write_at(driver_disk : &mut DrvDisk, file : &mut OpenFile, from : &Vec<u8>, num_bytes_to_write : i32, position : i32) -> i32 {
let mut file_length = file.hdr.file_length();
let mut max_file_length = file.hdr.max_file_length();
//on transforme position (position en octets) en un numéro de secteur
let sector_position = position/disk::SECTOR_SIZE;
let mut num_bytes = num_bytes_to_write; //le nombre d'octets que l'on va réellement écrire, on ne pourra pas forcément ecrire la taille demandée en paramètre
if (num_bytes <= 0)||(position < 0) ||(position > file_length){
return 0;
}
if num_bytes + file_length > max_file_length {
//bit_map represente les secteur du disque, pour savoir ou trouver de la place
let mut bit_map = BitMap::init_bitmap(disk::NUM_SECTORS as usize);
bit_map.fetch_from(filesys::FREE_MAP_FILE_PATH);
if !file.hdr.re_allocate(&mut bit_map, file_length, position + num_bytes){
//plus de place sur le disquen on se contente d'écrire ce que l'on peut
num_bytes = file_length - position;
}
else {
//write_back the header and freemap to disk
file.hdr.write_back(file.fSector, driver_disk);
bit_map.write_back(filesys::FREE_MAP_FILE_PATH);
}
}
else if position + num_bytes > file_length{
file.hdr.change_file_length(position + num_bytes);
}
DrvDisk::write_multiple_sector(driver_disk, sector_position, &from[..]);
num_bytes
}
pub fn read(driver_disk : &mut DrvDisk, file : &mut OpenFile, into : &mut Vec<u8>, num_bytes : i32) -> i32 {
let result = OpenFile::read_at(driver_disk, file, into, num_bytes, file.seekPosition);
file.seekPosition += result;
result
}
pub fn write(driver_disk : &mut DrvDisk, file : &mut OpenFile, from : & Vec<u8>, num_bytes : i32) -> i32 {
let result = OpenFile::write_at(driver_disk, file, from, num_bytes, file.seekPosition);
file.seekPosition += result;
result
}
pub fn get_name(&self) -> String {
return self.name.clone();
}
}
#[cfg(test)]
mod tests {
use super::*;
}

View File

@ -12,15 +12,45 @@ mod simulator;
mod kernel;
/// module containing useful tools which can be use in most part of the OS to ease the development of the OS
pub mod utility;
/// module containing drivers
pub mod drivers;
mod filesys;
use std::{rc::Rc, cell::RefCell};
use kernel::system::System;
use simulator::machine::Machine;
use simulator::{machine::Machine, print::print};
use drivers::drv_disk::DrvDisk;
use simulator::disk::Disk;
use filesys::fsmisc;
fn main() {
fsmisc::copy("ici", "");
/*
let machine = Machine::init_machine();
let system = Rc::new(RefCell::new(System::new(machine)));
let disk = Disk::init_disk();
let mut drv_disk = DrvDisk::init_drv_disk(disk);
let mut data = Vec::new();
data.push(0 as u8); data.push(0 as u8); data.push(0 as u8); data.push(0 as u8);
let mut data1 = Vec::new();
data1.push(1 as u8); data1.push(1 as u8); data1.push(1 as u8); data1.push(1 as u8);
let mut data2: Vec<u8> = Vec::new();
drv_disk.write_sector(0, &mut data);
drv_disk.write_sector(1, &mut data1);
drv_disk.read_sector(1, &mut data2);
for value in data2 {
println!("BYTE: {}", value);
}
System::freeze(system);
*/
}

283
src/simulator/disk.rs Normal file
View File

@ -0,0 +1,283 @@
use core::panic;
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::io::SeekFrom;
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 DISK_PATH: &str = "disk_file";
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 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
}
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 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.set_len(DISK_SIZE as u64);
disk_file.write_at(&magic_to_write[..], 0);
}
Ok(f) => {
disk_file = f;
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);
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
);
}
}
Err(e) => {
println!("init_disk :: Error reading file : {}", e);
}
}
Disk {
last_sector: 0,
active: false,
disk_file: disk_file,
}
}
/// read data from a disk, at a certain sector number
/// on lit un et un seul secteur
/// `panic!` when the disk is already active or the sector number is impossible
///
/// ### parameters
///
/// - **disk** to read from
/// - **sector_number** sector where to read the data
/// - **data** where the readed data will be stored
pub fn read_request(disk: &mut Disk, sector_number: i32, data: &mut [u8]) -> io::Result<()> {
if disk.active {
panic!("Only one request at time");
}
if sector_number < 0 || sector_number >= NUM_SECTORS {
panic!("sector_number isn't right");
}
if data.len() < (SECTOR_SIZE as usize){
panic!("disk::read_request, param slice too small, must be at least {} bytes", SECTOR_SIZE);
}
disk.active = true;
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 data[0..(SECTOR_SIZE as usize)]);
/*for byte in buffer {
data.push(byte);
}*/
disk.active = false;
Ok(())
}
/// write data into a disk, at a certain sector number
/// on écrit sur le disque un secteur, ni plus, ni moins
/// `panic!` when the disk is already active or the sector number is impossible
///
/// ### parameters
///
/// - **disk** to write data into
/// - **sector_number** sector where to write the data
/// - **data** where the data to write is stored
///
pub fn write_request(disk: &mut Disk,sector_number: i32,data: &[u8]) -> io::Result<()> {
if disk.active {
panic!("Only one request at time");
}
if sector_number < 0 || sector_number >= NUM_SECTORS {
panic!("sector_number isn't right");
}
if data.len() < (SECTOR_SIZE as usize) {
panic!("disk::write_request, param slice must contain at least enought to write a full sector")
}
disk.active = true;
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 {
buff.push(*value);
i = i + 1;
if i >= SECTOR_SIZE {
break;
}
}
*/
let res = disk.disk_file.write(&data[0..(SECTOR_SIZE as usize)]);
match res {
Ok(_) => println!("Data written successfully"),
Err(e) => println!("{:?}", e),
}
disk.active = false;
Ok(())
}
/// read data from a disk, at a certain sector number
/// on lit de un à plusieurs secteurs
/// `panic!` when the disk is already active or the sector number is impossible
///
/// ### parameters
///
/// - **disk** to read from
/// - **sector_number** sector where to read the data
/// - **data** where the readed data will be stored
pub fn read_multiple_request(disk: &mut Disk, sector_number: i32, data: &mut [u8]) -> io::Result<()> {
if data.len() < (SECTOR_SIZE as usize) {
panic!("disk::read_multiple_request, param slice smaller than one sector")
}
//ex SECTOR_SIZE = 4, data.len = 27, number_sector_to_read = 27 - (27%4) = 27 - 3 = 24 = 6*4, soit 6 secteurs
let number_sector_to_read = data.len() - (data.len()%(SECTOR_SIZE as usize));
//ex on lit 4 secteurs ce qui donne data[0..4],data[4..8],data[8..12],data[12..16]
for i in 0..number_sector_to_read {
Disk::read_request(disk, sector_number + (i as i32), &mut data[(i*(SECTOR_SIZE as usize))..((i+1)*(SECTOR_SIZE as usize))]);
}
Ok(())
}
/// write data into a disk, at a certain sector number
/// on écrit de un à plusieurs secteurs
/// `panic!` when the disk is already active or the sector number is impossible
///
/// ### parameters
///
/// - **disk** to write data into
/// - **sector_number** sector where to write the data
/// - **data** where the data to write is stored
///
pub fn write_multiple_request(disk: &mut Disk,sector_number: i32,data: &[u8]) -> io::Result<()> {
if data.len() < (SECTOR_SIZE as usize) {
panic!("disk::read_multiple_request, param slice smaller than one sector")
}
let number_sector_to_write = data.len() - (data.len()%(SECTOR_SIZE as usize));
//ex on ecrit 4 secteurs ce qui donne data[0..4],data[4..8],data[8..12],data[12..16]
for i in 0..number_sector_to_write {
Disk::write_request(disk, sector_number + (i as i32), &data[(i*(SECTOR_SIZE as usize))..((i+1)*(SECTOR_SIZE as usize))]);
}
Ok(())
}
}
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]);
}
}
#[cfg(test)]
mod test {
use serial_test::serial;
use crate::Disk;
use super::stupid_fct;
#[test]
#[serial]
fn test_init_stupid_fct() {
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
}
#[test]
#[serial]
fn test_init_disk() {
let disk = Disk::init_disk();
}
#[test]
#[serial]
fn test_read_write_disk() {
let mut disk = Disk::init_disk();
let mut data = Vec::new();
data.push(0 as u8);
data.push(0 as u8);
data.push(0 as u8);
data.push(0 as u8);
let mut data1 = Vec::new();
data1.push(1 as u8);
data1.push(1 as u8);
data1.push(1 as u8);
data1.push(1 as u8);
let mut data2: Vec<u8> = 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);
}
}

View File

@ -91,9 +91,7 @@ impl <'a>MMU <'_>{
let vpn : u64 = virtAddr/PAGE_SIZE; //virtual page index
let offset : u64 = virtAddr%PAGE_SIZE; //adresse intra page
match &mut mmu.translationTable {
match &mut mmu.translationTable {
None => {
println!("Error from translate : MMU refers to None (No page Table)");
return ExceptionType::ADDRESSERROR_EXCEPTION;

View File

@ -6,6 +6,7 @@ pub mod loader;
pub mod interrupt;
pub mod translationtable;
pub mod mmu;
pub mod disk;
pub mod global {

465
src/utility/bitmap.rs Normal file
View File

@ -0,0 +1,465 @@
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 {
pub num_bits: usize,
pub num_words: usize,
pub map: Vec<u32>,
}
impl BitMap {
pub fn compute_map_size(n_item : usize, dst_n_item : &mut usize, dst_num_word : &mut usize){
//on effectue un calcul sur n_item pour avoir un nombre de bits multiple de 32
//On fait le choix d'arrondir vers le haut pour que la map puisse acceuillir la taille souhaitée
*dst_n_item = n_item - (n_item%32);
if n_item%32 > 0 {
*dst_n_item += 32;
}
*dst_num_word = *dst_n_item/32;
}
/// 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 rounded_num_bits = 0;
let mut rounded_num_words = 0;
BitMap::compute_map_size(n_items, &mut rounded_num_bits, &mut rounded_num_words);
BitMap{
num_bits: rounded_num_bits,
num_words: rounded_num_words,//(n_items + SECTOR_SIZE as usize -1) / SECTOR_SIZE as usize,
map: vec![0u32 ; rounded_num_words],
}
}
//values is not borrowed
pub fn init_bitmap_from(values: &mut Vec<u32>)-> BitMap {
let mut tmp: Vec<u32> = Vec::new();
for value in values.iter(){
tmp.push(*value)
}
BitMap{
num_bits: values.len()*std::mem::size_of::<u32>()*8,
num_words: values.len(),
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);
let position_modulo = which%BITS_IN_WORD;
let left_shift = BITS_IN_WORD-position_modulo-1;
self.map[which / BITS_IN_WORD] |= 1u32 << left_shift;
}
/// 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
let position_modulo = which%BITS_IN_WORD;
let left_shift = BITS_IN_WORD-position_modulo-1;
(self.map[which / BITS_IN_WORD] & (1u32 << left_shift)) != 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 position_modulo = which%BITS_IN_WORD;
let left_shift = BITS_IN_WORD-position_modulo-1;
let mask : u32 = 0xFFFFFFFF^(1u32 << left_shift);
self.map[which / BITS_IN_WORD] &= mask;
}
/// 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){
// Ouvre le fichier en mode lecture seule
let mut file = File::open(file_path).expect("BitMap::fetch_from , unable to open file in read only");
let mut buf_to_convert : Vec<u8> = Vec::new();
file.read_to_end(&mut buf_to_convert).expect("BitMap::fetch_from , unable to read from file");
let borne_max_exclue;
//si le fichier contient plus de mots que la map ne peut en acceuillir, on lit de quoi remplir la map
if buf_to_convert.len() > self.num_bits/8 {
borne_max_exclue = self.num_words*4;
}
//sinon on lit ce que le fichier contient, en respectant l'alignement sur 4 octects !
else {
borne_max_exclue = buf_to_convert.len() - (buf_to_convert.len()%4);
}
let mut i = 0;
// !! borne_max_exclue doit etre multiple de 4 !!
while i < borne_max_exclue {
let a : u32 = buf_to_convert[i] as u32;
let b : u32 = buf_to_convert[i+1] as u32;
let c : u32 = buf_to_convert[i+2] as u32;
let d : u32 = buf_to_convert[i+3] as u32;
self.map[i/4] = (a<<24) | (b<<16) | (c<<8) | (d);
i += 4;//on passe aux 4 octets suivants
}
}
/// 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<()> {
let mut buf : Vec<u8> = Vec::new();
for val in self.map.iter(){
let a : u32 = (*val>>24)&0x000000ff;
let b : u32 = (*val>>16)&0x000000ff;
let c : u32 = (*val>>8)&0x000000ff;
let d : u32 = *val&0x000000ff;
buf.push(a as u8);
buf.push(b as u8);
buf.push(c as u8);
buf.push(d as u8);
}
// Ouvre le fichier en mode écriture, si absent on le creer
let mut file = File::options()
.read(false)
.write(true)
.create(true)
.open(file_path)
.expect("bitmap::write_back, Unable to create or open File");
// Écrit les données dans le fichier
file.write_all(&buf);
file.flush();//histoire d'etre sur
Ok(())
}
pub fn add_word(&mut self, word : u32){
self.map.push(word);
self.num_words += 1;
self.num_bits += std::mem::size_of::<u32>()*8;
}
pub fn add_words(&mut self, words : Vec<u32>){
for word in words.iter(){
self.add_word(*word);
}
}
}
#[cfg(test)]
mod tests {
use std::io::{Seek, SeekFrom};
use super::*;
#[test]
fn test_num_clear() {
let mut bit_map : BitMap = BitMap::init_bitmap(128);
let index_to_set : [usize ; 16] = [0,5,10,15,18,25,28,31,45,70,74,88,99,101,102,127];
for val in index_to_set.iter(){
bit_map.mark(*val);
}
assert!(bit_map.num_bits == 128);
assert!(bit_map.num_words == 4);
assert!((bit_map.num_clear() as usize) == bit_map.num_bits - index_to_set.len());
}
#[test]
fn test_fetch_from_file_smaller_than_map() {
//On ecrit la séquence 0x AB CD EF 10 20 2E 3E 4F
let values : [u8 ; 8] = [0xAB, 0xCD, 0xEF, 0x10, 0x20, 0x2E, 0x3E, 0x4F];
let values_for_test : [u32 ; 2] = [0xABCDEF10, 0x202E3E4F];
let mut f = File::options()
.read(true)
.write(true)
.create(true)
.open("test_fetch_bitmap")
.expect("Unable to create File");
f.write_all(&values[..]).expect("Unable to write data");
//creating and loading the bitmap
let mut bit_map : BitMap = BitMap::init_bitmap(100);
bit_map.fetch_from("test_fetch_bitmap");
assert!(bit_map.num_bits == 128);
assert!(bit_map.num_words == 4);
for j in 0..bit_map.map.len(){
if j<2 {
assert!(values_for_test[j] == bit_map.map[j]);
}
else {
assert!(bit_map.map[j] == 0u32);
}
}
//print for debug
/*for val in bit_map.map.iter(){
println!("{:08X?}", *val)
}*/
}
#[test]
fn test_fetch_from_map_smaller_than_file() {
//println!("\n\n TEST FETCH FROM\n");
//On ecrit la séquence 0x AB CD EF 10 20 2E 3E 4F
let mut values : [u8 ; 8] = [0xFE, 0x59, 0xEF, 0x10, 0x20, 0x2E, 0x3E, 0x4F];
let mut f = File::options()
.read(true)
.write(true)
.create(true)
.open("test_fetch_bitmap_2")
.expect("Unable to create File");
f.write_all(&values[..]).expect("Unable to write data");
//creating and loading the bitmap
//1 bit donnera lieu via init_bit_map a une map de 32 bit soit 1 mot
let mut bit_map : BitMap = BitMap::init_bitmap(1);
bit_map.fetch_from("test_fetch_bitmap_2");
assert!(bit_map.num_bits == 32);
assert!(bit_map.num_words == 1);
assert!(bit_map.map[0] == 0xFE59EF10);
/*println!("\n\n data loaded into map \n");
//print for debug
for val in bit_map.map.iter(){
println!("{:08X?}", *val)
}*/
}
#[test]
fn test_mark() {
let mut bit_map : BitMap = BitMap::init_bitmap(128);
let index_to_set : [usize ; 16] = [0,5,10,15,18,25,28,31,45,70,74,88,99,101,102,127];
for val in index_to_set.iter(){
bit_map.mark(*val);
}
assert!(bit_map.num_bits == 128);
assert!(bit_map.num_words == 4);
/*for i in bit_map.map.iter(){
println!("\n{:#032b}", *i);
}*/
for i in 0..bit_map.num_bits {
let word_index = i/32;
let mask_to_shift : u32 = 0x80000000;//un 1 au debut puis full 0 <=> 0x100000000000000000000000000000000
let shift_value = i%32;
if index_to_set.contains(&i) {
assert!( (bit_map.map[word_index] & (mask_to_shift>>shift_value)) != 0);
}
else{
assert!( (bit_map.map[word_index] & (mask_to_shift>>shift_value)) == 0) ;
}
}
}
#[test]
fn test_test() {
let mut bit_map : BitMap = BitMap::init_bitmap(128);
let index_to_set : [usize ; 16] = [0,5,10,15,18,25,28,31,45,70,74,88,99,101,102,127];
for val in index_to_set.iter(){
bit_map.mark(*val);
}
assert!(bit_map.num_bits == 128);
assert!(bit_map.num_words == 4);
for i in 0..bit_map.num_bits {
if index_to_set.contains(&i) {
assert!( bit_map.test(i) == true);
}
else{
assert!( bit_map.test(i) == false) ;
}
}
}
#[test]
fn test_clear() {
let mut bit_map : BitMap = BitMap::init_bitmap(128);
let index_to_set : [usize ; 16] = [0,5,10,15,18,25,28,31,45,70,74,88,99,101,102,127];
//mise a 1
for val in index_to_set.iter(){
bit_map.mark(*val);
}
assert!(bit_map.num_bits == 128);
assert!(bit_map.num_words == 4);
for i in 0..bit_map.num_bits {
if index_to_set.contains(&i) {
assert!( bit_map.test(i) == true);
}
else{
assert!( bit_map.test(i) == false) ;
}
}
//on met a 0 partout dans bit_map pour tester que le clear ne transforme pas 0 en 1
for i in 0..bit_map.num_bits {
bit_map.clear(i);
assert!( bit_map.test(i) == false);
}
}
#[test]
fn test_find() {
let mut bit_map : BitMap = BitMap::init_bitmap(128);
assert!(bit_map.num_bits == 128);
assert!(bit_map.num_words == 4);
for i in 0..bit_map.num_bits {
let j = bit_map.find();
assert!(i == (j as usize));
}
for j in 0..bit_map.num_bits{
assert!(bit_map.test(j) == true);
}
}
#[test]
fn test_write_back() {
let mut bit_map : BitMap = BitMap::init_bitmap(128);
let mut bit_map_from_file : BitMap = BitMap::init_bitmap(128);
let index_to_set : [usize ; 16] = [1,5,10,15,18,25,28,31,45,70,74,88,99,101,102,127];
for val in index_to_set.iter(){
bit_map.mark(*val);
}
assert!(bit_map.num_bits == 128);
assert!(bit_map.num_words == 4);
assert!(bit_map_from_file.num_bits == 128);
assert!(bit_map_from_file.num_words == 4);
bit_map.write_back("test_bit_map_write_back");
bit_map_from_file.fetch_from("test_bit_map_write_back");
for i in 0..(bit_map.num_words){
assert!(bit_map_from_file.map[i] == bit_map.map[i]);
}
}
}

View File

@ -1 +1,2 @@
pub mod list;
pub mod list;
pub mod bitmap;

BIN
test/disk.txt Normal file

Binary file not shown.