Compare commits
47 Commits
Author | SHA1 | Date | |
---|---|---|---|
364723984e | |||
88d8d9cd58 | |||
d6eef6fe08 | |||
8b19189689 | |||
153c3d6618 | |||
d6ac7671dc | |||
9a23b1bb37 | |||
347cdd9cf3 | |||
69a8a0d4ea | |||
85e999a7b0 | |||
dae609c6ed | |||
551c9079b9 | |||
d6ed2f1d75 | |||
4d2f27b3b2 | |||
1a884f2e98 | |||
00b4ed0066 | |||
6ad3b36201 | |||
3f3c79ec0c | |||
25140bda17 | |||
61b3643945 | |||
2549103636 | |||
856cbdfe01 | |||
391359a54e | |||
f4420d9306 | |||
4633c512bd | |||
d620822d97 | |||
58e866cb2f | |||
60410efd1a | |||
1da8b8465f | |||
6ac67efe2d | |||
1c0f0765c0 | |||
c1f436bcfb | |||
99a69c7998 | |||
52929cef24 | |||
79bfcf6b57 | |||
021aac6e6a | |||
3be14e7f6a | |||
b07c675986 | |||
12c28f7681 | |||
2413d4dec6 | |||
bc970a9603 | |||
274a8d2c0e | |||
c5c82ac567 | |||
edf593cbf8 | |||
4c81f0591a | |||
66eaa8a64f | |||
38004e0bc4 |
343
Cargo.lock
generated
343
Cargo.lock
generated
@ -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"
|
||||
|
@ -5,3 +5,4 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
libc = { version = "0.2.139", features = ["extra_traits"] }
|
||||
serial_test = "*"
|
113
src/drivers/drv_disk.rs
Normal file
113
src/drivers/drv_disk.rs
Normal 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
1
src/drivers/mod.rs
Normal file
@ -0,0 +1 @@
|
||||
pub mod drv_disk;
|
178
src/filesys/directory.rs
Normal file
178
src/filesys/directory.rs
Normal 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
262
src/filesys/filehdr.rs
Normal 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
508
src/filesys/filesys.rs
Normal 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
90
src/filesys/fsmisc.rs
Normal 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
6
src/filesys/mod.rs
Normal 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
153
src/filesys/oftable.rs
Normal 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
156
src/filesys/openfile.rs
Normal 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::*;
|
||||
|
||||
|
||||
}
|
32
src/main.rs
32
src/main.rs
@ -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", "là");
|
||||
/*
|
||||
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
283
src/simulator/disk.rs
Normal 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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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
465
src/utility/bitmap.rs
Normal 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]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1 +1,2 @@
|
||||
pub mod list;
|
||||
pub mod list;
|
||||
pub mod bitmap;
|
BIN
test/disk.txt
Normal file
BIN
test/disk.txt
Normal file
Binary file not shown.
Reference in New Issue
Block a user