use std::{mem, ptr};
use std::fs::File;
use std::io::{Read, Seek, SeekFrom, Write};
use super::avl;
use super::block_ptr::BlockPtr;
use super::dvaddr::DVAddr;
use super::from_bytes::FromBytes;
use super::lzjb;
use super::uberblock::Uberblock;
use super::zfs;
pub const NUM_TYPES: usize = 6;
pub const NUM_TASKQ_TYPES: usize = 4;
pub struct Reader {
pub disk: File,
}
impl Reader {
pub fn read(&mut self, start: usize, length: usize) -> Vec<u8> {
let mut ret: Vec<u8> = vec![0; length*512];
self.disk.seek(SeekFrom::Start(start as u64 * 512));
self.disk.read(&mut ret);
ret
}
pub fn write(&mut self, block: usize, data: &[u8; 512]) {
self.disk.seek(SeekFrom::Start(block as u64 * 512));
self.disk.write(data);
}
pub fn read_dva(&mut self, dva: &DVAddr) -> Vec<u8> {
self.read(dva.sector() as usize, dva.asize() as usize)
}
pub fn read_block(&mut self, block_ptr: &BlockPtr) -> Result<Vec<u8>, &'static str> {
let data = self.read_dva(&block_ptr.dvas[0]);
match block_ptr.compression() {
2 => {
Ok(data)
}
1 | 3 => {
let mut decompressed = vec![0; (block_ptr.lsize()*512) as usize];
lzjb::LzjbDecoder::new(&data).read(&mut decompressed);
Ok(decompressed)
}
_ => Err("Error: not enough bytes"),
}
}
pub fn read_type_array<T: FromBytes>(&mut self,
block_ptr: &BlockPtr,
offset: usize)
-> Result<T, String> {
self.read_block(block_ptr).map_err(|x| x.to_owned()).and_then(|data| T::from_bytes(&data[offset * mem::size_of::<T>()..]).map_err(|x| x.to_owned()))
}
pub fn uber(&mut self) -> Result<Uberblock, &'static str> {
let mut newest_uberblock: Option<Uberblock> = None;
for i in 0..128 {
if let Ok(uberblock) = Uberblock::from_bytes(&self.read(256 + i * 2, 2)) {
let newest = match newest_uberblock {
Some(previous) => {
if uberblock.txg > previous.txg {
true
} else {
false
}
}
None => true,
};
if newest {
newest_uberblock = Some(uberblock);
}
}
}
match newest_uberblock {
Some(uberblock) => Ok(uberblock),
None => Err("Failed to find valid uberblock"),
}
}
}
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum Priority {
Now,
SyncRead,
SyncWrite,
LogWrite,
CacheFill,
DTP,
Free,
AsyncRead,
AsyncWrite,
Resilver,
Scrub,
}
#[derive(Copy, Clone, PartialEq)]
pub enum Type {
Null,
Read,
Write,
Free,
Claim,
IoCtl,
}
enum Stage {
Open = 1 << 0,
ReadBpInit = 1 << 1,
FreeBpInit = 1 << 2,
IssueAsync = 1 << 3,
WriteBpInit = 1 << 4,
ChecksumGenerate = 1 << 5,
NopWrite = 1 << 6,
DdtReadStart = 1 << 7,
DdtReadDone = 1 << 8,
DdtWrite = 1 << 9,
DdtFree = 1 << 10,
GangAssemble = 1 << 11,
GangIssue = 1 << 12,
DvaAllocate = 1 << 13,
DvaFree = 1 << 14,
DvaClaim = 1 << 15,
Ready = 1 << 16,
VdevIoStart = 1 << 17,
VdevIoDone = 1 << 18,
VdevIoAssess = 1 << 19,
ChecksumVerify = 1 << 20,
Done = 1 << 21,
}
pub enum TaskqType {
Issue,
IssueHigh,
Interrupt,
InterruptHigh,
}
#[derive(Copy, Clone, PartialEq)]
enum PipelineFlow {
Continue = 0x100,
Stop = 0x101,
}
#[derive(Copy, Clone, PartialEq)]
enum Flag {
DontAggregate = 1 << 0,
IoRepair = 1 << 1,
SelfHeal = 1 << 2,
Resilver = 1 << 3,
Scrub = 1 << 4,
ScanThread = 1 << 5,
Physical = 1 << 6,
CanFail = 1 << 7,
Speculative = 1 << 8,
ConfigWriter = 1 << 9,
DontRetry = 1 << 10,
DontCache = 1 << 11,
NoData = 1 << 12,
InduceDamage = 1 << 13,
IoRetry = 1 << 14,
Probe = 1 << 15,
TryHard = 1 << 16,
Optional = 1 << 17,
DontQueue = 1 << 18,
DontPropagate = 1 << 19,
IoBypass = 1 << 20,
IoRewrite = 1 << 21,
Raw = 1 << 22,
GangChild = 1 << 23,
DdtChild = 1 << 24,
GodFather = 1 << 25,
NopWrite = 1 << 26,
ReExecuted = 1 << 27,
Delegated = 1 << 28,
FastWrite = 1 << 29,
}
#[derive(Copy, Clone, PartialEq)]
enum Child {
Vdev = 0,
Gang,
Ddt,
Logical,
}
#[repr(u8)]
enum WaitType {
Ready = 0,
Done,
}