1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
// SPDX-License-Identifier: MIT
use std::{
    borrow::Cow,
    fmt::{Debug, Display, Formatter},
};

pub mod mtd;

pub mod v1v2;
pub mod v3;

fn chrp_checksum_add(lhs: u8, rhs: u8) -> u8 {
    let (out, carry) = lhs.overflowing_add(rhs);
    if carry {
        out + 1
    } else {
        out
    }
}

fn slice_rstrip<'a, T: PartialEq<T>>(mut ts: &'a [T], t: &T) -> &'a [T] {
    while let Some(last) = ts.last() {
        if last == t {
            ts = ts.split_last().unwrap().1;
        } else {
            break;
        }
    }
    ts
}

fn slice_find<T: PartialEq<T>>(ts: &[T], t: &T) -> Option<usize> {
    let mut ret = None;
    for (i, v) in ts.iter().enumerate() {
        if v == t {
            ret = Some(i);
            break;
        }
    }
    ret
}

#[derive(Debug)]
pub enum Error {
    ParseError,
    SectionTooBig,
    ApplyError(std::io::Error),
}

type Result<T> = std::result::Result<T, Error>;

#[derive(Clone, Copy, PartialEq)]
pub enum VarType {
    Common,
    System,
}

impl Display for VarType {
    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
        match self {
            &VarType::Common => write!(f, "common"),
            &VarType::System => write!(f, "system"),
        }
    }
}

pub fn nvram_parse<'a>(nvr: &'a [u8]) -> Result<Box<dyn Nvram<'a> + 'a>> {
    match (v3::Nvram::parse(nvr), v1v2::Nvram::parse(nvr)) {
        (Ok(nvram_v3), Err(_)) => Ok(Box::new(nvram_v3)),
        (Err(_), Ok(nvram_v1v2)) => Ok(Box::new(nvram_v1v2)),
        _ => Err(Error::ParseError),
    }
}

pub trait NvramWriter {
    fn erase_if_needed(&mut self, offset: u32, size: usize);
    fn write_all(&mut self, offset: u32, buf: &[u8]) -> std::io::Result<()>;
}

pub trait Nvram<'a> {
    fn prepare_for_write(&mut self);
    fn active_part_mut(&mut self) -> &mut dyn Partition<'a>;
    fn partitions(&self) -> Box<dyn Iterator<Item = &dyn Partition<'a>> + '_>;
    fn serialize(&self) -> Result<Vec<u8>>;
    fn apply(&mut self, w: &mut dyn NvramWriter) -> Result<()>;
}

pub trait Partition<'a>: Display {
    fn variables(&self) -> Box<dyn Iterator<Item = &dyn Variable<'a>> + '_>;
    fn get_variable(&self, key: &'a [u8], typ: VarType) -> Option<&dyn Variable<'a>>;
    fn insert_variable(&mut self, key: &'a [u8], value: Cow<'a, [u8]>, typ: VarType);
    fn remove_variable(&mut self, key: &'a [u8], typ: VarType);
}

pub trait Variable<'a>: Display {
    fn value(&self) -> Cow<'a, [u8]>;
}