use super::{VfsBackend, VfsDirEntry, VfsError, VfsFile, VfsStat, VfsRaidConfig, VfsRaidLevel}; use std::path::{Path, PathBuf}; pub struct VfsRaidBackend { config: VfsRaidConfig, backends: Vec>, stripe_size: usize, } impl VfsRaidBackend { pub fn new(config: VfsRaidConfig, backends: Vec>) -> Result { let min_disks = match config.level { VfsRaidLevel::Single => 1, VfsRaidLevel::RaidZ1 => 2, VfsRaidLevel::RaidZ2 => 3, VfsRaidLevel::RaidZ3 => 4, }; if backends.len() < min_disks { return Err(VfsError::Io(format!("RAID level {} requires at least {} disks", config.level, min_disks))); } let stripe_size = config.stripe_size; Ok(Self { config, backends, stripe_size, }) } pub fn data_disks(&self) -> usize { match self.config.level { VfsRaidLevel::Single => self.backends.len(), VfsRaidLevel::RaidZ1 => self.backends.len() - 1, VfsRaidLevel::RaidZ2 => self.backends.len() - 2, VfsRaidLevel::RaidZ3 => self.backends.len() - 3, } } pub fn parity_disks(&self) -> usize { match self.config.level { VfsRaidLevel::Single => 0, VfsRaidLevel::RaidZ1 => 1, VfsRaidLevel::RaidZ2 => 2, VfsRaidLevel::RaidZ3 => 3, } } fn calculate_parity_p(data: &[u8]) -> Vec { data.iter().fold(vec![0u8; data.len()], |mut p, byte| { for i in 0..p.len() { p[i] ^= byte; } p }) } fn calculate_parity_q(data: &[u8]) -> Vec { let mut q = vec![0u8; data.len()]; for (i, byte) in data.iter().enumerate() { let gf_exp = Self::gf_exp(i); for j in 0..q.len() { q[j] ^= Self::gf_mul(byte, gf_exp); } } q } fn calculate_parity_r(data: &[u8]) -> Vec { let mut r = vec![0u8; data.len()]; for (i, byte) in data.iter().enumerate() { let gf_exp = Self::gf_exp(i * i); for j in 0..r.len() { r[j] ^= Self::gf_mul(byte, gf_exp); } } r } fn gf_exp(n: usize) -> u8 { let mut result = 1; for _ in 0..n % 255 { result = Self::gf_mul(&result, 2); } result } fn gf_mul(a: &u8, b: u8) -> u8 { let mut p = 0u8; let mut a = *a; let mut b = b; for _ in 0..8 { if b & 1 != 0 { p ^= a; } let hi_bit = a & 0x80; a <<= 1; if hi_bit != 0 { a ^= 0x1b; } b >>= 1; } p } fn stripe_index(&self, offset: u64) -> usize { (offset / self.stripe_size as u64) as usize % self.backends.len() } fn rebuild_disk(&self, _failed_disk_index: usize) -> Result<(), VfsError> { if self.config.level == VfsRaidLevel::Single { return Err(VfsError::Io("Cannot rebuild single disk RAID".to_string())); } for backend in &self.backends { backend.create_dir_all(&PathBuf::from("/"), 0o755)?; } Ok(()) } } impl VfsBackend for VfsRaidBackend { fn clone_boxed(&self) -> Box { Box::new(Self { config: self.config.clone(), backends: self.backends.iter().map(|b| b.clone_boxed()).collect(), stripe_size: self.stripe_size, }) } fn read_dir(&self, path: &Path) -> Result, VfsError> { self.backends[0].read_dir(path) } fn open_file(&self, path: &Path, flags: &super::open_flags::OpenFlags) -> Result, VfsError> { self.backends[0].open_file(path, flags) } fn stat(&self, path: &Path) -> Result { self.backends[0].stat(path) } fn lstat(&self, path: &Path) -> Result { self.backends[0].lstat(path) } fn create_dir(&self, path: &Path, mode: u32) -> Result<(), VfsError> { for backend in &self.backends { backend.create_dir(path, mode)?; } Ok(()) } fn create_dir_all(&self, path: &Path, mode: u32) -> Result<(), VfsError> { for backend in &self.backends { backend.create_dir_all(path, mode)?; } Ok(()) } fn remove_dir(&self, path: &Path) -> Result<(), VfsError> { for backend in &self.backends { backend.remove_dir(path)?; } Ok(()) } fn remove_file(&self, path: &Path) -> Result<(), VfsError> { for backend in &self.backends { backend.remove_file(path)?; } Ok(()) } fn rename(&self, from: &Path, to: &Path) -> Result<(), VfsError> { for backend in &self.backends { backend.rename(from, to)?; } Ok(()) } fn set_stat(&self, path: &Path, stat: &VfsStat) -> Result<(), VfsError> { for backend in &self.backends { backend.set_stat(path, stat)?; } Ok(()) } fn read_link(&self, path: &Path) -> Result { self.backends[0].read_link(path) } fn create_symlink(&self, target: &Path, link: &Path) -> Result<(), VfsError> { self.backends[0].create_symlink(target, link) } fn real_path(&self, path: &Path) -> Result { self.backends[0].real_path(path) } fn exists(&self, path: &Path) -> bool { self.backends[0].exists(path) } fn hard_link(&self, original: &Path, link: &Path) -> Result<(), VfsError> { for backend in &self.backends { backend.hard_link(original, link)?; } Ok(()) } }