format sevices/pddb

wow the formatter hated this code.

hope i can recognize it later on when it needs work,
nobody else probably wants to touch it. :-/
This commit is contained in:
bunnie 2024-01-14 22:35:23 +08:00
parent 8d30c5bfc5
commit 679435c5f4
25 changed files with 4474 additions and 3043 deletions

View file

@ -1,9 +1,9 @@
mod rkyv_enum;
pub use rkyv_enum::*;
use core::ops::{Deref, DerefMut};
use std::num::NonZeroU32;
use bitfield::bitfield;
use std::num::NonZeroU32;
use core::ops::{Deref, DerefMut};
pub use rkyv_enum::*;
// on the "[allow(dead_code)]" directives: these constants are used to define the PDDB, and are
// sometimes used by both `bin` (main.rs) and `lib` (lib.rs) views, but also, sometimes used
@ -15,8 +15,8 @@ use core::ops::{Deref, DerefMut};
// here, because sometimes, clippy just can't see the big picture.
// note this name cannot be changed because it is baked into `libstd`
pub(crate) const SERVER_NAME_PDDB: &str = "_Plausibly Deniable Database_";
pub(crate) const SERVER_NAME_PDDB_POLLER: &str = "_PDDB Mount Poller_";
pub(crate) const SERVER_NAME_PDDB: &str = "_Plausibly Deniable Database_";
pub(crate) const SERVER_NAME_PDDB_POLLER: &str = "_PDDB Mount Poller_";
/// This is the registered name for a dedicated private API channel to the PDDB for doing the time reset
/// Even though nobody but the PDDB should connect to this, we have to share it publicly so the PDDB can
/// depend upon this constant.
@ -43,10 +43,10 @@ pub(crate) const PDDB_VERSION: u32 = 0x00_00_02_01;
#[allow(dead_code)]
// PDDB_A_LEN may be shorter than xous::PDDB_LEN, to speed up testing.
#[allow(dead_code)]
#[cfg(not(any(feature="pddbtest",feature="autobasis",feature="ci",feature="smalldb")))]
#[cfg(not(any(feature = "pddbtest", feature = "autobasis", feature = "ci", feature = "smalldb")))]
pub(crate) const PDDB_A_LEN: usize = xous::PDDB_LEN as usize;
#[allow(dead_code)]
#[cfg(any(feature="pddbtest",feature="autobasis",feature="ci",feature="smalldb"))]
#[cfg(any(feature = "pddbtest", feature = "autobasis", feature = "ci", feature = "smalldb"))]
pub const PDDB_A_LEN: usize = 4 * 1024 * 1024;
/// range for the starting point of a journal number, picked from a random seed
@ -108,7 +108,7 @@ pub(crate) const PDDB_FAST_SPACE_SYSTEM_BASIS: &'static str = ".FastSpace";
#[allow(dead_code)]
// TODO: add hardware acceleration for BCRYPT so we can hit the OWASP target without excessive UX delay
pub(crate) const BCRYPT_COST: u32 = 7; // 10 is the minimum recommended by OWASP; takes 5696 ms to verify @ 10 rounds; 804 ms to verify 7 rounds
pub(crate) const BCRYPT_COST: u32 = 7; // 10 is the minimum recommended by OWASP; takes 5696 ms to verify @ 10 rounds; 804 ms to verify 7 rounds
#[derive(num_derive::FromPrimitive, num_derive::ToPrimitive, Debug)]
pub(crate) enum Opcode {
@ -160,7 +160,7 @@ pub(crate) enum Opcode {
/// Write debug dump (only available in hosted mode)
#[cfg(not(target_os = "xous"))]
DangerousDebug = 25,
#[cfg(all(feature="pddbtest", feature="autobasis"))]
#[cfg(all(feature = "pddbtest", feature = "autobasis"))]
BasisTesting = 26,
ListBasisStd = 26,
@ -262,9 +262,11 @@ pub type ApiToken = [u32; 3];
#[derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
#[repr(C)]
pub struct PddbBasisList {
/// the first 63 that fit in the list -- generally we anticipate not more than a few being open at a time, so this should be enough.
pub list: [xous_ipc::String::<BASIS_NAME_LEN>; 63],
/// total number of basis open. Should be <= 63, but we allow it to be larger to indicate cases where this structure wasn't big enough.
/// the first 63 that fit in the list -- generally we anticipate not more than a few being open at a
/// time, so this should be enough.
pub list: [xous_ipc::String<BASIS_NAME_LEN>; 63],
/// total number of basis open. Should be <= 63, but we allow it to be larger to indicate cases where
/// this structure wasn't big enough.
pub num: u32,
}
@ -296,16 +298,16 @@ impl BasisRetentionPolicy {
}
#[derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
pub struct PddbBasisRequest {
pub name: xous_ipc::String::<BASIS_NAME_LEN>,
pub name: xous_ipc::String<BASIS_NAME_LEN>,
pub code: PddbRequestCode,
pub policy: Option<BasisRetentionPolicy>,
}
#[derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
pub struct PddbDictRequest {
pub basis_specified: bool,
pub basis: xous_ipc::String::<BASIS_NAME_LEN>,
pub dict: xous_ipc::String::<DICT_NAME_LEN>,
pub key: xous_ipc::String::<KEY_NAME_LEN>,
pub basis: xous_ipc::String<BASIS_NAME_LEN>,
pub dict: xous_ipc::String<DICT_NAME_LEN>,
pub key: xous_ipc::String<KEY_NAME_LEN>,
pub index: u32,
pub token: [u32; 4],
pub code: PddbRequestCode,
@ -321,13 +323,14 @@ pub struct PddbDictRequest {
#[derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
pub struct PddbKeyRequest {
pub basis_specified: bool,
pub basis: xous_ipc::String::<BASIS_NAME_LEN>,
pub dict: xous_ipc::String::<DICT_NAME_LEN>,
pub key: xous_ipc::String::<KEY_NAME_LEN>,
pub basis: xous_ipc::String<BASIS_NAME_LEN>,
pub dict: xous_ipc::String<DICT_NAME_LEN>,
pub key: xous_ipc::String<KEY_NAME_LEN>,
pub token: Option<ApiToken>,
pub create_dict: bool,
pub create_key: bool,
pub alloc_hint: Option<u64>, // this is a usize but for IPC we must have defined memory sizes, so we pick the big option.
pub alloc_hint: Option<u64>, /* this is a usize but for IPC we must have defined memory sizes, so we
* pick the big option. */
pub cb_sid: Option<[u32; 4]>,
pub result: PddbRequestCode,
}
@ -335,7 +338,7 @@ pub struct PddbKeyRequest {
pub(crate) const MAX_PDDBKLISTLEN: usize = 4064;
/// A structure for requesting a token to access a particular key/value pair
#[derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
pub (crate) struct PddbKeyList {
pub(crate) struct PddbKeyList {
pub token: [u32; 4],
pub data: [u8; MAX_PDDBKLISTLEN],
pub retcode: PddbRetcode,
@ -345,17 +348,26 @@ pub (crate) struct PddbKeyList {
/// A structure for bulk deletion of keys
pub(crate) const MAX_PDDB_DELETE_LEN: usize = 3800; // approximate limit, might be a little higher if we cared to calculate it out
#[derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
pub (crate) struct PddbDeleteList {
pub(crate) struct PddbDeleteList {
pub basis_specified: bool,
pub basis: xous_ipc::String::<BASIS_NAME_LEN>,
pub dict: xous_ipc::String::<DICT_NAME_LEN>,
pub basis: xous_ipc::String<BASIS_NAME_LEN>,
pub dict: xous_ipc::String<DICT_NAME_LEN>,
pub data: [u8; MAX_PDDB_DELETE_LEN],
pub retcode: PddbRetcode,
}
/// Return codes for Read/Write API calls to the main server
#[repr(u8)]
#[derive(num_derive::FromPrimitive, num_derive::ToPrimitive, Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize, Eq, PartialEq)]
#[derive(
num_derive::FromPrimitive,
num_derive::ToPrimitive,
Debug,
rkyv::Archive,
rkyv::Serialize,
rkyv::Deserialize,
Eq,
PartialEq,
)]
pub(crate) enum PddbRetcode {
Uninit = 0,
Ok = 1,
@ -380,7 +392,8 @@ pub(crate) struct PddbBuf {
reserved: u8,
/// length of the data field
pub(crate) len: u16,
/// point in the key stream. 64-bit for future-compatibility; but, can't be larger than 32 bits on a 32-bit target.
/// point in the key stream. 64-bit for future-compatibility; but, can't be larger than 32 bits on a
/// 32-bit target.
pub(crate) position: u64,
pub(crate) data: [u8; PDDB_BUF_DATA_LEN],
}
@ -401,12 +414,19 @@ pub struct PddbKeyRecord {
/// and the record must be explicitly re-read with a non-bulk call to fetch its data,
/// or the key has zero length. Check the `len` field to differentiate the two.
/// (Turns out that `rkyv` crashes when deserializing a zero-length Vec)
pub data: Option<Vec::<u8>>,
pub data: Option<Vec<u8>>,
}
/// Return codes for Read/Write API calls to the main server
#[repr(u32)]
#[derive(num_derive::FromPrimitive, num_derive::ToPrimitive, Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
#[derive(
num_derive::FromPrimitive,
num_derive::ToPrimitive,
Debug,
rkyv::Archive,
rkyv::Serialize,
rkyv::Deserialize,
)]
pub enum PddbBulkReadCode {
/// Uninitialized value
Uninit = 0,
@ -433,18 +453,23 @@ pub struct BulkReadHeader {
}
impl Deref for BulkReadHeader {
type Target = [u8];
fn deref(&self) -> &[u8] {
unsafe {
core::slice::from_raw_parts(self as *const BulkReadHeader as *const u8, core::mem::size_of::<BulkReadHeader>())
as &[u8]
core::slice::from_raw_parts(
self as *const BulkReadHeader as *const u8,
core::mem::size_of::<BulkReadHeader>(),
) as &[u8]
}
}
}
impl DerefMut for BulkReadHeader {
fn deref_mut(&mut self) -> &mut [u8] {
unsafe {
core::slice::from_raw_parts_mut(self as *mut BulkReadHeader as *mut u8, core::mem::size_of::<BulkReadHeader>())
as &mut [u8]
core::slice::from_raw_parts_mut(
self as *mut BulkReadHeader as *mut u8,
core::mem::size_of::<BulkReadHeader>(),
) as &mut [u8]
}
}
}
@ -452,13 +477,15 @@ impl DerefMut for BulkReadHeader {
#[allow(dead_code)]
/// Ensure that the `PddbBuf` struct is exactly one page big
const fn _assert_pddbbuf_is_4096_bytes() {
unsafe { core::mem::transmute::<_, PddbBuf>([0u8; 4096]); }
unsafe {
core::mem::transmute::<_, PddbBuf>([0u8; 4096]);
}
}
impl PddbBuf {
pub(crate) fn from_slice_mut(slice: &mut [u8]) -> &mut PddbBuf {
// this transforms the slice [u8] into a PddbBuf ref.
unsafe {core::mem::transmute::<*mut u8, &mut PddbBuf>(slice.as_mut_ptr()) }
unsafe { core::mem::transmute::<*mut u8, &mut PddbBuf>(slice.as_mut_ptr()) }
}
}
@ -497,8 +524,8 @@ pub struct PddbKeyAttrIpc {
pub len: u64,
pub reserved: u64,
pub age: u64,
pub dict: xous_ipc::String::<DICT_NAME_LEN>,
pub basis: xous_ipc::String::<BASIS_NAME_LEN>,
pub dict: xous_ipc::String<DICT_NAME_LEN>,
pub basis: xous_ipc::String<BASIS_NAME_LEN>,
pub flags: u32,
pub index: u32,
pub token: ApiToken,
@ -518,6 +545,7 @@ impl PddbKeyAttrIpc {
code: PddbRequestCode::Uninit,
}
}
#[allow(dead_code)]
pub fn to_attributes(&self) -> KeyAttributes {
KeyAttributes {
@ -530,6 +558,7 @@ impl PddbKeyAttrIpc {
index: NonZeroU32::new(self.index).unwrap(),
}
}
pub fn from_attributes(attr: KeyAttributes, token: ApiToken) -> PddbKeyAttrIpc {
PddbKeyAttrIpc {
len: attr.len as u64,
@ -550,7 +579,7 @@ impl PddbKeyAttrIpc {
#[derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
pub struct PddbDangerousDebug {
pub request: DebugRequest,
pub dump_name: xous_ipc::String::<128>,
pub dump_name: xous_ipc::String<128>,
}
#[cfg(not(target_os = "xous"))]
#[derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
@ -570,6 +599,9 @@ mod tests {
}
#[test]
fn test_pddb_len() {
assert!(PDDB_A_LEN <= xous::PDDB_LEN as usize, "PDDB_A_LEN is larger than the maximum extents available in the hardware");
assert!(
PDDB_A_LEN <= xous::PDDB_LEN as usize,
"PDDB_A_LEN is larger than the maximum extents available in the hardware"
);
}
}

View file

@ -12,8 +12,7 @@
// As of now, the current version is 0.7.x and there isn't a timeline yet for 0.8.
#![allow(dead_code)]
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
#[derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
#[derive(Copy, Clone, Eq, PartialEq, Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
pub enum BasisRetentionPolicy {
Persist,
ClearAfterSleeps(u32),
@ -51,11 +50,10 @@ pub enum PddbRekeyOp {
/// at this current time).
ChangePass(xous_ipc::String<BASIS_NAME_LEN>),
*/
/// Return codes
Success,
AuthFail,
UserAbort,
VerifyFail,
InternalError,
}
}

View file

@ -27,5 +27,5 @@ mod hosted;
#[cfg(not(target_os = "xous"))]
pub(crate) use hosted::*;
#[cfg(feature="migration1")]
#[cfg(feature = "migration1")]
mod migration1to2;

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,3 @@
// this code is based on https://github.com/Keats/rust-bcrypt
// the original crate is not used directly because the base64 wrappers cause the crate
// to be incompatible with a no-std environment. We are storing binary data directly
@ -30,7 +29,11 @@ pub fn bcrypt(cost: u32, salt: &[u8], pw: &str, output: &mut [u8]) {
assert!(output.len() == 24);
let pw_len = if pw.len() > crate::api::PASSWORD_LEN {
log::warn!("password of length {} is truncated to {} bytes [reason: bcrypt limitation]", pw.len(), crate::api::PASSWORD_LEN);
log::warn!(
"password of length {} is truncated to {} bytes [reason: bcrypt limitation]",
pw.len(),
crate::api::PASSWORD_LEN
);
crate::api::PASSWORD_LEN
} else {
pw.len() + 1
@ -47,19 +50,19 @@ pub fn bcrypt(cost: u32, salt: &[u8], pw: &str, output: &mut [u8]) {
let state = setup(cost, salt, &plaintext_copy[..pw_len]);
// erase the plaintext copy as soon as we're done with it
// an unsafe method is used because the compiler will correctly reason that plaintext_copy goes out of scope
// and these writes are never read, and therefore they may be optimized out.
// an unsafe method is used because the compiler will correctly reason that plaintext_copy goes out of
// scope and these writes are never read, and therefore they may be optimized out.
let pt_ptr = plaintext_copy.as_mut_ptr();
for i in 0..plaintext_copy.len() {
unsafe{pt_ptr.add(i).write_volatile(core::mem::zeroed());}
unsafe {
pt_ptr.add(i).write_volatile(core::mem::zeroed());
}
}
core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
// OrpheanBeholderScryDoubt
#[allow(clippy::unreadable_literal)]
let mut ctext = [
0x4f727068, 0x65616e42, 0x65686f6c, 0x64657253, 0x63727944, 0x6f756274,
];
let mut ctext = [0x4f727068, 0x65616e42, 0x65686f6c, 0x64657253, 0x63727944, 0x6f756274];
for i in 0..3 {
let i: usize = i * 2;
for _ in 0..64 {

File diff suppressed because it is too large Load diff

View file

@ -1,10 +1,11 @@
use core::ops::{Deref, DerefMut};
use core::convert::TryInto;
use core::mem::size_of;
use core::ops::{Deref, DerefMut};
use aes_gcm_siv::{Nonce, Tag};
use super::PAGE_SIZE;
use crate::*;
use core::mem::size_of;
use aes_gcm_siv::{Nonce, Tag};
/// Each free_pool entry takes about 4 bytes, so give-or-take we have about 1000 free_pool
/// entries per page of storage for the free_pool, or 4k * 1000 ~ 4MiB per page, when PhysAddr is a u32
@ -34,14 +35,12 @@ impl From<u8> for SpaceState {
}
}
impl From<SpaceState> for u8 {
fn from(arg: SpaceState) -> Self {
arg as u8
}
fn from(arg: SpaceState) -> Self { arg as u8 }
}
pub(crate) const FASTSPACE_FREE_POOL_LEN: usize =
((PAGE_SIZE * FASTSPACE_PAGES) - (size_of::<Nonce>() + size_of::<Tag>()))
/ core::mem::size_of::<PhysPage>();
pub(crate) const FASTSPACE_FREE_POOL_LEN: usize = ((PAGE_SIZE * FASTSPACE_PAGES)
- (size_of::<Nonce>() + size_of::<Tag>()))
/ core::mem::size_of::<PhysPage>();
/// FastSpace tracks a limited set of physical pages
/// An optimal implementation of this would fill whole pages with the free_pool array.
/// This record is meant to be updated rarely, and atomically, in a make-before-break fashion:
@ -60,17 +59,20 @@ pub(crate) const FASTSPACE_FREE_POOL_LEN: usize =
/// The "rare" property is important especially as the disk size scales up; if we wanted to keep
/// 100MiB of "fast space" on hand, this structure would span 25 pages.
#[repr(C)]
pub (crate) struct FastSpace {
pub(crate) struct FastSpace {
/// Not sure if there is a "better" way to compute things, but we want the number of entries in the
/// free_pool array to "round out" the FastSpace record to be equal to exactly one page
pub(crate) free_pool: [PhysPage; FASTSPACE_FREE_POOL_LEN],
}
impl Deref for FastSpace {
type Target = [u8];
fn deref(&self) -> &[u8] {
unsafe {
core::slice::from_raw_parts(self as *const FastSpace as *const u8, core::mem::size_of::<FastSpace>())
as &[u8]
core::slice::from_raw_parts(
self as *const FastSpace as *const u8,
core::mem::size_of::<FastSpace>(),
) as &[u8]
}
}
}
@ -84,10 +86,11 @@ pub(crate) struct FastSpaceInFlash {
p_tag: [u8; size_of::<Tag>()],
}
/// a 128-bit record that stores an encrypted update to the FastSpace pool, facilitating the "rarely" update property of the structure.
/// a 128-bit record that stores an encrypted update to the FastSpace pool, facilitating the "rarely" update
/// property of the structure.
#[repr(C, packed)]
#[cfg(not(feature = "u64_pa"))]
pub (crate) struct SpaceUpdate {
pub(crate) struct SpaceUpdate {
nonce: u64,
page_number: PhysPage,
// this checksum is "weak" but we are protecting against two scenarios:
@ -112,6 +115,7 @@ impl SpaceUpdate {
None
}
}
pub fn new(nonce: u64, page_number: PhysPage) -> Self {
let mut hashbuf: [u8; 12] = [0; 12];
for (&src, dst) in nonce.to_le_bytes().iter().zip(hashbuf[..8].iter_mut()) {
@ -121,16 +125,12 @@ impl SpaceUpdate {
*dst = src;
}
let computed_sum = murmur3_32(&hashbuf[..12], u32::from_be_bytes(hashbuf[4..8].try_into().unwrap()));
SpaceUpdate {
nonce,
page_number,
checksum: computed_sum.to_le_bytes(),
}
SpaceUpdate { nonce, page_number, checksum: computed_sum.to_le_bytes() }
}
}
#[cfg(feature = "u64_pa")]
pub (crate) struct SpaceUpdate {
pub(crate) struct SpaceUpdate {
nonce: u64,
page_number: PhysPage,
// consider: using the top 12 bits of the PhysAddr as a checksum
@ -138,18 +138,23 @@ pub (crate) struct SpaceUpdate {
impl Deref for SpaceUpdate {
type Target = [u8];
fn deref(&self) -> &[u8] {
unsafe {
core::slice::from_raw_parts(self as *const SpaceUpdate as *const u8, core::mem::size_of::<SpaceUpdate>())
as &[u8]
core::slice::from_raw_parts(
self as *const SpaceUpdate as *const u8,
core::mem::size_of::<SpaceUpdate>(),
) as &[u8]
}
}
}
impl DerefMut for SpaceUpdate {
fn deref_mut(&mut self) -> &mut [u8] {
unsafe {
core::slice::from_raw_parts_mut(self as *mut SpaceUpdate as *mut u8, core::mem::size_of::<SpaceUpdate>())
as &mut [u8]
core::slice::from_raw_parts_mut(
self as *mut SpaceUpdate as *mut u8,
core::mem::size_of::<SpaceUpdate>(),
) as &mut [u8]
}
}
}
@ -159,6 +164,9 @@ mod tests {
use super::*;
#[test]
fn test_fast_space_size() {
assert!(core::mem::size_of::<FastSpaceInFlash>() & (PAGE_SIZE - 1) == 0, "FastSpaceInFlash is not exactly a multiple of one page in size");
assert!(
core::mem::size_of::<FastSpaceInFlash>() & (PAGE_SIZE - 1) == 0,
"FastSpaceInFlash is not exactly a multiple of one page in size"
);
}
}

View file

@ -1,13 +1,12 @@
#![allow(dead_code)]
use crate::api::*;
use std::sync::Once;
use std::mem::MaybeUninit;
use std::fs::File;
use std::fs::OpenOptions;
use std::io::prelude::*;
use std::io::SeekFrom;
use std::mem::MaybeUninit;
use std::sync::Once;
use crate::api::*;
// This is considered bad practice for Rust to use a global singleton.
// However, this hack puts the burden of emulation on the emulator, while
@ -17,7 +16,7 @@ use std::io::SeekFrom;
//
// Note that this is a concurrently accessed, unsafe, unchecked vector.
struct FlashSingleton {
memory: Vec::<u8>,
memory: Vec<u8>,
disk: File,
}
@ -28,11 +27,11 @@ fn flashmem() -> &'static mut FlashSingleton {
unsafe {
ONCE.call_once(|| {
let mut disk = OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open("../tools/pddb-images/hosted.bin")
.expect("Can't open a PDDB image file for writing");
.read(true)
.write(true)
.create(true)
.open("../tools/pddb-images/hosted.bin")
.expect("Can't open a PDDB image file for writing");
let mut memory = Vec::<u8>::with_capacity(PDDB_A_LEN);
if disk.metadata().unwrap().len() == 0 {
@ -44,7 +43,11 @@ fn flashmem() -> &'static mut FlashSingleton {
match disk.read_to_end(&mut memory) {
Ok(bytes_read) => {
if bytes_read != PDDB_A_LEN {
log::warn!("PDDB disk image is of an incorrect size: got {}, expected {}", bytes_read, PDDB_A_LEN);
log::warn!(
"PDDB disk image is of an incorrect size: got {}, expected {}",
bytes_read,
PDDB_A_LEN
);
}
}
_ => {
@ -53,10 +56,7 @@ fn flashmem() -> &'static mut FlashSingleton {
}
}
let flashmem = FlashSingleton {
memory,
disk,
};
let flashmem = FlashSingleton { memory, disk };
SINGLETON.write(flashmem);
});
SINGLETON.assume_init_mut()
@ -71,28 +71,26 @@ pub struct KeyExport {
/// page table key
pub pt_key: [u8; 32],
}
pub struct EmuStorage {
}
pub struct EmuStorage {}
impl EmuStorage {
pub fn new() -> Self {
EmuStorage {
}
}
pub fn new() -> Self { EmuStorage {} }
pub unsafe fn as_slice<T>(&self) -> &[T] {
core::slice::from_raw_parts(
flashmem().memory.as_ptr() as *const T,
flashmem().memory.len() / core::mem::size_of::<T>(),
)
}
pub unsafe fn as_mut_slice(&mut self) -> &mut [u8] {
flashmem().memory.as_mut_slice()
core::slice::from_raw_parts(
flashmem().memory.as_ptr() as *const T,
flashmem().memory.len() / core::mem::size_of::<T>(),
)
}
pub unsafe fn as_mut_slice(&mut self) -> &mut [u8] { flashmem().memory.as_mut_slice() }
/// used to reset the storage for repeated test case generation
pub fn reset(&mut self) {
for b in flashmem().memory.as_mut_slice() {
*b = 0xFF;
}
}
pub fn dump_fs(&self, name: &Option<String>) {
let defaultname = String::from("pddb");
let rootname = name.as_ref().unwrap_or(&defaultname);
@ -100,6 +98,7 @@ impl EmuStorage {
f.write_all(flashmem().memory.as_slice()).unwrap();
f.flush().unwrap();
}
pub fn dump_keys(&self, known_keys: &[KeyExport], name: &Option<String>) {
let defaultname = String::from("pddb");
let rootname = name.as_ref().unwrap_or(&defaultname);
@ -114,26 +113,34 @@ impl EmuStorage {
}
}
pub struct HostedSpinor {
}
pub struct HostedSpinor {}
impl HostedSpinor {
pub fn new() -> Self {
HostedSpinor {
}
}
pub fn patch(&self, _region: &[u8], _region_base: u32, data: &[u8], offset: u32) -> Result<(), xous::Error> {
pub fn new() -> Self { HostedSpinor {} }
pub fn patch(
&self,
_region: &[u8],
_region_base: u32,
data: &[u8],
offset: u32,
) -> Result<(), xous::Error> {
// println!("patch at {:x}+{}", offset, data.len());
for (&src, dst) in data.iter().zip(
flashmem().memory.as_mut_slice()[offset as usize..offset as usize + data.len()].iter_mut()
) {
for (&src, dst) in data
.iter()
.zip(flashmem().memory.as_mut_slice()[offset as usize..offset as usize + data.len()].iter_mut())
{
*dst = src;
}
flashmem().disk.seek(SeekFrom::Start(offset as u64)).expect("couldn't seek PDDB");
flashmem().disk.write(data).expect("couldn't write PDDB");
Ok(())
}
pub fn bulk_erase(&self, start: u32, len: u32) -> Result<(), xous::Error> {
for b in flashmem().memory.as_mut_slice()[(start - xous::PDDB_LOC) as usize .. (start - xous::PDDB_LOC + len) as usize].iter_mut() {
for b in flashmem().memory.as_mut_slice()
[(start - xous::PDDB_LOC) as usize..(start - xous::PDDB_LOC + len) as usize]
.iter_mut()
{
*b = 0xFF;
}
flashmem().disk.seek(SeekFrom::Start(start as u64)).expect("couldn't seek PDDB");

File diff suppressed because it is too large Load diff

View file

@ -1,10 +1,10 @@
use crate::api::*;
use super::*;
use std::num::NonZeroU32;
use core::ops::{Deref, DerefMut};
use std::cmp::Ordering;
use std::io::{Result, Error, ErrorKind};
use std::io::{Error, ErrorKind, Result};
use std::num::NonZeroU32;
use super::*;
use crate::api::*;
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
#[repr(C, align(8))]
@ -30,12 +30,7 @@ impl KeyName {
}
}
impl Default for KeyName {
fn default() -> KeyName {
KeyName {
len: 0,
data: [0; KEY_NAME_LEN - 1]
}
}
fn default() -> KeyName { KeyName { len: 0, data: [0; KEY_NAME_LEN - 1] } }
}
/// On-disk representation of the Key. Note that the storage on disk is mis-aligned relative
@ -58,74 +53,79 @@ pub(crate) struct KeyDescriptor {
}
impl Default for KeyDescriptor {
fn default() -> Self {
KeyDescriptor {
start: 0,
len: 0,
reserved: 0,
flags: KeyFlags(0),
age: 0,
name: KeyName::default(),
}
KeyDescriptor { start: 0, len: 0, reserved: 0, flags: KeyFlags(0), age: 0, name: KeyName::default() }
}
}
impl Deref for KeyDescriptor {
type Target = [u8];
fn deref(&self) -> &[u8] {
unsafe {
core::slice::from_raw_parts(self as *const KeyDescriptor as *const u8, core::mem::size_of::<KeyDescriptor>())
as &[u8]
core::slice::from_raw_parts(
self as *const KeyDescriptor as *const u8,
core::mem::size_of::<KeyDescriptor>(),
) as &[u8]
}
}
}
impl DerefMut for KeyDescriptor {
fn deref_mut(&mut self) -> &mut [u8] {
unsafe {
core::slice::from_raw_parts_mut(self as *mut KeyDescriptor as *mut u8, core::mem::size_of::<KeyDescriptor>())
as &mut [u8]
core::slice::from_raw_parts_mut(
self as *mut KeyDescriptor as *mut u8,
core::mem::size_of::<KeyDescriptor>(),
) as &mut [u8]
}
}
}
/// In-RAM representation of a key. This file defines the storage for the KeyCacheEntry; most of the structure
/// manipulations happen inside `dictionary.rs`, in part because to locate a Key in absolute memory space you need
/// to know what Dictionary it comes from. This is a point to consider for a refactor: if we pull some info about
/// the containing Dictionary into the key, we could associate more methods with the data structure. However, this
/// means duplicating the dictionary index, a field that can then get out of sync.
/// manipulations happen inside `dictionary.rs`, in part because to locate a Key in absolute memory space you
/// need to know what Dictionary it comes from. This is a point to consider for a refactor: if we pull some
/// info about the containing Dictionary into the key, we could associate more methods with the data
/// structure. However, this means duplicating the dictionary index, a field that can then get out of sync.
pub(crate) struct KeyCacheEntry {
pub(crate) start: u64,
pub(crate) len: u64,
pub(crate) reserved: u64,
pub(crate) flags: KeyFlags,
pub(crate) age: u32,
/// this is an ephemeral time since boot, not commited to disk, used only for deciding which entries to evict
/// this is an ephemeral time since boot, not commited to disk, used only for deciding which entries to
/// evict
pub(crate) atime: u64,
/// the current on-disk index of the KeyCacheEntry item, enumerated as "0" being the Dict descriptor and
/// "1" being the first valid key. This is used to find the location of the key's metadata as stored on disk;
/// it has nothing to do with where the data itself is stored (that's derived from `start`).
/// "1" being the first valid key. This is used to find the location of the key's metadata as stored on
/// disk; it has nothing to do with where the data itself is stored (that's derived from `start`).
pub(crate) descriptor_index: NonZeroU32,
/// indicates if the descriptor cache entry is currently synchronized with what's on disk. Does not imply anything about the data,
/// but if the `data` field is None then there is nothing to in cache to be dirtied.
/// indicates if the descriptor cache entry is currently synchronized with what's on disk. Does not imply
/// anything about the data, but if the `data` field is None then there is nothing to in cache to be
/// dirtied.
pub(crate) clean: bool,
/// if Some, contains the keys data contents. if None, you must refer to the disk contents to retrieve it.
/// Current rule: "small" keys always have their data "hot"; large keys may often not keep their data around.
/// if Some, contains the keys data contents. if None, you must refer to the disk contents to retrieve
/// it. Current rule: "small" keys always have their data "hot"; large keys may often not keep their
/// data around.
pub(crate) data: Option<KeyCacheData>,
}
impl KeyCacheEntry {
/// Given a base offset of the dictionary containing the key, compute the starting VirtAddr of the key itself.
/// Given a base offset of the dictionary containing the key, compute the starting VirtAddr of the key
/// itself.
pub(crate) fn descriptor_vaddr(&self, dict_offset: VirtAddr) -> VirtAddr {
VirtAddr::new(dict_offset.get() + ((self.descriptor_index.get() as u64) * DK_STRIDE as u64)).unwrap()
}
/// Computes the modular position of the KeyDescriptor within a vpage.
#[allow(dead_code)] // I feel like we should have been calling this /somewhere/ at some point in time, but I probably just re-wrote the math long-hand.
pub(crate) fn descriptor_modulus(&self) -> usize {
(self.descriptor_index.get() as usize) % (VPAGE_SIZE / DK_STRIDE)
}
/// Computes the vpage offset as measured from the start of the dictionary storage region
pub(crate) fn descriptor_vpage_num(&self) -> usize {
(self.descriptor_index.get() as usize) / DK_PER_VPAGE
}
/// returns the list of large-pool virtual pages belonging to this entry, if any.
pub(crate) fn large_pool_vpages(&self) -> Vec::<VirtAddr> {
pub(crate) fn large_pool_vpages(&self) -> Vec<VirtAddr> {
let mut vpages = Vec::<VirtAddr>::new();
if self.start >= LARGE_POOL_START {
for vbase in (self.start..self.start + self.reserved).step_by(VPAGE_SIZE) {
@ -134,6 +134,7 @@ impl KeyCacheEntry {
}
vpages
}
/// returns a rough measure of the amount of data consumed by a given entry. It's not meant to
/// be absolutely accurate, but it should give an accurate impression of the relative size of
/// different cache entries. This metric is used to help decide which entries to discard.
@ -143,15 +144,17 @@ impl KeyCacheEntry {
Some(kcd) => match kcd {
KeyCacheData::Small(ksd) => ksd.data.len(),
KeyCacheData::Large(kld) => kld.data.len(),
}
},
};
core::mem::size_of::<KeyCacheEntry>() + data_size
}
pub(crate) fn atime(&self) -> u64 { self.atime }
pub(crate) fn set_atime(&mut self, atime: u64) { self.atime = atime; }
}
pub (crate) enum KeyCacheData {
pub(crate) enum KeyCacheData {
Small(KeySmallData),
// the "Medium" type has a region reserved for it, but we haven't coded a handler for it.
#[allow(dead_code)] // Large data caching isn't implemented, so of course, we don't ever create this type
@ -160,7 +163,7 @@ pub (crate) enum KeyCacheData {
/// Small data is optimized for low overhead, and always represent a complete copy of the data.
pub(crate) struct KeySmallData {
pub clean: bool,
pub(crate) data: Vec::<u8>,
pub(crate) data: Vec<u8>,
}
/// This can hold just a portion of a large key's data. For now, we now essentially manually
/// encode a sub-slice in parts, but, later on we could get more clever and start to cache
@ -169,17 +172,18 @@ pub(crate) struct KeySmallData {
pub(crate) struct KeyLargeData {
pub clean: bool,
pub(crate) start: u64,
pub(crate) data: Vec::<u8>,
pub(crate) data: Vec<u8>,
}
/// A storage pool for data that is strictly smaller than one VPAGE. These element are serialized
/// and stored inside the "small data pool" area.
pub(crate) struct KeySmallPool {
// location of data within the Small memory region. Index is in units of SMALL_CAPACITY. (this should be encoded in the vector position)
//pub(crate) index: u32,
// location of data within the Small memory region. Index is in units of SMALL_CAPACITY. (this should be
// encoded in the vector position) pub(crate) index: u32,
/// list of data actually stored within the pool - resolve against `keys` HashMap.
pub(crate) contents: Vec::<String>,
/// keeps track of the available space within the pool, avoiding an expensive lookup every time we want to query the available space
pub(crate) contents: Vec<String>,
/// keeps track of the available space within the pool, avoiding an expensive lookup every time we want
/// to query the available space
pub(crate) avail: u16,
/// if false, contents are modified and need syncing to disk
pub(crate) clean: bool,
@ -204,17 +208,11 @@ pub(crate) struct KeySmallPoolOrd {
}
// only compare based on the amount of data used
impl Ord for KeySmallPoolOrd {
fn cmp(&self, other: &Self) -> Ordering {
self.avail.cmp(&other.avail)
}
fn cmp(&self, other: &Self) -> Ordering { self.avail.cmp(&other.avail) }
}
impl PartialOrd for KeySmallPoolOrd {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }
}
impl PartialEq for KeySmallPoolOrd {
fn eq(&self, other: &Self) -> bool {
self.avail == other.avail
}
fn eq(&self, other: &Self) -> bool { self.avail == other.avail }
}

View file

@ -1,6 +1,7 @@
use crate::*;
use core::ops::Deref;
use core::mem::size_of;
use core::ops::Deref;
use crate::*;
pub(crate) const SCD_VERSION_MIGRATION1: u32 = 1;
@ -24,15 +25,18 @@ impl StaticCryptoDataV1 {
}
impl Deref for StaticCryptoDataV1 {
type Target = [u8];
fn deref(&self) -> &[u8] {
unsafe {
core::slice::from_raw_parts(self as *const StaticCryptoDataV1 as *const u8, size_of::<StaticCryptoDataV1>())
as &[u8]
core::slice::from_raw_parts(
self as *const StaticCryptoDataV1 as *const u8,
size_of::<StaticCryptoDataV1>(),
) as &[u8]
}
}
}
pub(crate) fn data_aad_v1(pddb_os: &PddbOs, name: &str) -> Vec::<u8> {
pub(crate) fn data_aad_v1(pddb_os: &PddbOs, name: &str) -> Vec<u8> {
let mut aad = Vec::<u8>::new();
aad.extend_from_slice(&name.as_bytes());
let (old_version, _new_version) = PDDB_MIGRATE_1;

View file

@ -7,7 +7,6 @@
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.
// This murmur3 code was vendored in on April 28, 2021. We choose to vendor the code for this simple
// non-cryptographic hash in to reduce the number of crate dependencies in the build system. See
// https://github.com/betrusted-io/xous-core/issues/54 for more details on why.
@ -55,7 +54,6 @@ fn calc_k(k: u32) -> u32 {
k.wrapping_mul(C1).rotate_left(R1).wrapping_mul(C2)
}
#[cfg(test)]
mod tests {
use super::*;
@ -75,18 +73,11 @@ mod tests {
slice: &[0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38], // "12345678",
hash_32: 0x91b313ce,
},
Result {
slice: &[],
hash_32: 0,
},
Result { slice: &[], hash_32: 0 },
];
for test in &tests {
assert_eq!(
murmur3_32(test.slice, 0),
test.hash_32,
"Failed on slice {:x?}", test.slice
);
assert_eq!(murmur3_32(test.slice, 0), test.hash_32, "Failed on slice {:x?}", test.slice);
}
}
}

View file

@ -1,13 +1,14 @@
use super::{PAGE_SIZE, TrngPool, VirtAddr, murmur3_32, VPAGE_SIZE};
use core::mem::size_of;
use aes_gcm_siv::{Nonce, Tag};
use std::rc::Rc;
use core::cell::RefCell;
use core::ops::{Deref, DerefMut};
use core::convert::TryInto;
use core::mem::size_of;
use core::ops::{Deref, DerefMut};
use std::rc::Rc;
use aes_gcm_siv::{Nonce, Tag};
use bitflags::bitflags;
use super::{murmur3_32, TrngPool, VirtAddr, PAGE_SIZE, VPAGE_SIZE};
bitflags! {
/// flags used by the page table
pub struct PtFlags: u8 {
@ -23,7 +24,7 @@ bitflags! {
}
}
impl Default for PtFlags {
fn default() -> PtFlags {PtFlags::INVALID}
fn default() -> PtFlags { PtFlags::INVALID }
}
/// A Page Table Entry. Must be equal in length to one AES block size (128 bits).
@ -51,8 +52,8 @@ pub(crate) struct Pte {
flags: PtFlags,
/// 32-bit strength of a nonce, but can be varied
nonce: [u8; 4],
/// 32-bit "weak" checksum, used only for quick scans of the PTE to determine a coarse "in" or "out" classifier
/// checksum is computed on all of the bits prior, so checksum(pddb_addr, flags, nonce)
/// 32-bit "weak" checksum, used only for quick scans of the PTE to determine a coarse "in" or "out"
/// classifier checksum is computed on all of the bits prior, so checksum(pddb_addr, flags, nonce)
checksum: [u8; 4],
}
impl Pte {
@ -70,22 +71,26 @@ impl Pte {
pte
}
pub fn vaddr(&self) -> VirtAddr {
let mut full_addr = [0u8; 8];
// LSB encoded, so this loop deposits the partial pddb_addr in the LSBs, and the MSBs are correctly 0 from above initializer
// LSB encoded, so this loop deposits the partial pddb_addr in the LSBs, and the MSBs are correctly 0
// from above initializer
for (&src, dst) in self.pddb_addr.iter().zip(full_addr.iter_mut()) {
*dst = src;
}
VirtAddr::new(u64::from_le_bytes(full_addr) * VPAGE_SIZE as u64).unwrap()
}
/// V1 databases stored the virtual address as a full address, instead of as a page number, which means
/// the overall size of our database was about 4000x smaller than we had thought. This was fixed in v2,
/// but this getter is required to migrate from v1.
/// This allows us to retrieve the old address format for the first phase of migration.
#[cfg(feature="migration1")]
#[cfg(feature = "migration1")]
pub fn vaddr_v1(&self) -> VirtAddr {
let mut full_addr = [0u8; 8];
// LSB encoded, so this loop deposits the partial pddb_addr in the LSBs, and the MSBs are correctly 0 from above initializer
// LSB encoded, so this loop deposits the partial pddb_addr in the LSBs, and the MSBs are correctly 0
// from above initializer
for (&src, dst) in self.pddb_addr.iter().zip(full_addr.iter_mut()) {
*dst = src;
}
@ -93,9 +98,8 @@ impl Pte {
}
#[allow(dead_code)]
pub fn flags(&self) -> PtFlags {
self.flags
}
pub fn flags(&self) -> PtFlags { self.flags }
pub fn try_from_slice(slice: &[u8]) -> Option<Self> {
if slice.len() == size_of::<Pte>() {
let mut maybe_pt = Pte::default();
@ -112,6 +116,7 @@ impl Pte {
None
}
}
/// Normally you should be using pt_patch_mapping(), which generates a new nonce every
/// time the entry is patched. However, this function is provided for "bulk" operations
/// such as migrations where we violate the abstractions to improve performance.
@ -125,6 +130,7 @@ impl Pte {
}
impl Deref for Pte {
type Target = [u8];
fn deref(&self) -> &[u8] {
unsafe {
core::slice::from_raw_parts(self as *const Pte as *const u8, core::mem::size_of::<Pte>())
@ -165,6 +171,7 @@ pub(crate) struct EncryptedPage {
journal_rev: [u8; 4],
/// data is encrypted and holds the good stuff
data: [u8; PAGE_SIZE - size_of::<Nonce>() - size_of::<Tag>() - size_of::<u32>()],
/// tag is the authentication tag. If the page decrypts & authenticates, we know it's a valid data block for us.
/// tag is the authentication tag. If the page decrypts & authenticates, we know it's a valid data block
/// for us.
p_tag: [u8; size_of::<Tag>()],
}
}

View file

@ -1,15 +1,16 @@
use core::mem::size_of;
use aes_gcm_siv::Nonce;
use std::convert::TryInto;
use core::cell::RefCell;
use core::mem::size_of;
use std::convert::TryInto;
use aes_gcm_siv::Nonce;
use rand_core::RngCore;
/// Crate-shared resource for TRNGs.
pub(crate) struct TrngPool {
trng: RefCell::<trng::Trng>,
trng: RefCell<trng::Trng>,
/// The PDDB eats a lot of entropy. Keep a local pool of entropy, so we're not wasting a lot of
/// overhead passing messages to the TRNG hardware server.
e_cache: RefCell::<Vec::<u8>>,
e_cache: RefCell<Vec<u8>>,
}
impl TrngPool {
pub fn new() -> Self {
@ -17,11 +18,9 @@ impl TrngPool {
let mut trng = trng::Trng::new(&xns).unwrap();
let mut cache: [u8; 8192] = [0; 8192];
trng.fill_bytes(&mut cache);
TrngPool {
trng: RefCell::new(trng),
e_cache: RefCell::new(cache.to_vec())
}
TrngPool { trng: RefCell::new(trng), e_cache: RefCell::new(cache.to_vec()) }
}
pub(crate) fn ensure_entropy(&self, amount: usize) {
if self.e_cache.borrow().len() < amount {
let mut cache: [u8; 8192] = [0; 8192];
@ -29,37 +28,42 @@ impl TrngPool {
self.e_cache.borrow_mut().extend_from_slice(&cache);
}
}
pub(crate) fn get_u8(&self) -> u8 {
self.ensure_entropy(1);
self.e_cache.borrow_mut().pop().unwrap()
}
pub(crate) fn get_u32(&self) -> u32 {
self.ensure_entropy(4);
let ret = u32::from_le_bytes(self.e_cache.borrow()[self.e_cache.borrow().len() - 4..].try_into().unwrap());
let ret =
u32::from_le_bytes(self.e_cache.borrow()[self.e_cache.borrow().len() - 4..].try_into().unwrap());
let ecache_len = self.e_cache.borrow().len();
self.e_cache.borrow_mut().truncate(ecache_len - 4);
ret
}
pub(crate) fn get_u64(&self) -> u64 {
self.ensure_entropy(8);
let ret = u64::from_le_bytes(self.e_cache.borrow()[self.e_cache.borrow().len() - 8..].try_into().unwrap());
let ret =
u64::from_le_bytes(self.e_cache.borrow()[self.e_cache.borrow().len() - 8..].try_into().unwrap());
let ecache_len = self.e_cache.borrow().len();
self.e_cache.borrow_mut().truncate(ecache_len - 8);
ret
}
pub(crate) fn get_slice(&self, bucket: &mut [u8]) {
self.ensure_entropy(bucket.len());
let drain_start = self.e_cache.borrow().len() - bucket.len();
for (src, dst) in self.e_cache.borrow_mut().drain(
drain_start..
).zip(bucket.iter_mut()) {
for (src, dst) in self.e_cache.borrow_mut().drain(drain_start..).zip(bucket.iter_mut()) {
*dst = src;
}
}
/// generates a 96-bit nonce using the TRNG
pub(crate) fn get_nonce(&self) -> [u8; size_of::<Nonce>()] {
let mut nonce: [u8; size_of::<Nonce>()] = [0; size_of::<Nonce>()];
self.get_slice(&mut nonce);
nonce
}
}
}

View file

@ -1,18 +1,20 @@
use core::num::NonZeroU64;
use core::ops::Add;
use std::cmp::Ordering;
use std::hash::{Hash, Hasher};
use bitfield::bitfield;
use super::{PAGE_SIZE, VPAGE_SIZE};
use crate::SpaceState;
use bitfield::bitfield;
use std::hash::{Hash, Hasher};
use std::cmp::Ordering;
/// for the life of me, I can't figure out how to query the AES crate to give me the length of a 256-bit key.
/// I mean, we know what it is, it's well-defined and never changes. But it'd just be nice to you know,
/// derive it from a const or something with symbolic meaning, but the KeySize Trait is buried in some sort
/// of a NewBlock trait and I can't figure out how to access it. Looking at the example code on the AES crate
/// on docs.rs, they just pull the number 16 out of their ass instead of referring to a trait.
/// So, maybe that's just what you're supposed to do. ¯\_(ツ)_/¯ Oddly enough, a BLOCK_SIZE constant /is/ defined,
/// but maybe that's because it's constant regardless of the key size so it's easy to do.
/// So, maybe that's just what you're supposed to do. ¯\_(ツ)_/¯ Oddly enough, a BLOCK_SIZE constant /is/
/// defined, but maybe that's because it's constant regardless of the key size so it's easy to do.
pub(crate) const AES_KEYSIZE: usize = 32;
/// This has to be manually synchronized with the bit range of the `journal` field below. It doesn't look like
@ -44,24 +46,16 @@ bitfield! {
}
// hashes should only key off of the page number, not the metadata
impl Hash for PhysPage {
fn hash<H: Hasher>(&self, state: &mut H) {
self.page_number().hash(state);
}
fn hash<H: Hasher>(&self, state: &mut H) { self.page_number().hash(state); }
}
impl PartialEq for PhysPage {
fn eq(&self, other: &Self) -> bool {
self.page_number() == other.page_number()
}
fn eq(&self, other: &Self) -> bool { self.page_number() == other.page_number() }
}
impl Ord for PhysPage {
fn cmp(&self, other: &Self) -> Ordering {
self.page_number().cmp(&other.page_number())
}
fn cmp(&self, other: &Self) -> Ordering { self.page_number().cmp(&other.page_number()) }
}
impl PartialOrd for PhysPage {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }
}
/// Storage for journal revisions.
@ -90,10 +84,13 @@ impl PageAlignedVa {
panic!("PageAlignedVa would not fit into a u32");
}
}
#[allow(dead_code)]
pub(crate) fn as_u64(&self) -> u64 {self.0.get()}
pub(crate) fn as_u64(&self) -> u64 { self.0.get() }
#[allow(dead_code)]
pub(crate) fn as_usize(&self) -> usize {self.0.get() as usize}
pub(crate) fn as_usize(&self) -> usize { self.0.get() as usize }
/// This will turn a PageAlignedVa into a page number
#[allow(dead_code)]
pub(crate) fn as_vpage_num(&self) -> usize {
@ -102,8 +99,9 @@ impl PageAlignedVa {
}
}
impl Default for PageAlignedVa {
// 0 is not a valid address; the offset at VPAGE_SIZE is the location of BasisRoot, and that is the default value.
fn default() -> Self {PageAlignedVa(VirtAddr::new(VPAGE_SIZE as u64).unwrap())}
// 0 is not a valid address; the offset at VPAGE_SIZE is the location of BasisRoot, and that is the
// default value.
fn default() -> Self { PageAlignedVa(VirtAddr::new(VPAGE_SIZE as u64).unwrap()) }
}
impl From<u64> for PageAlignedVa {
fn from(arg: u64) -> Self {
@ -138,6 +136,7 @@ impl From<usize> for PageAlignedVa {
}
impl Add for PageAlignedVa {
type Output = PageAlignedVa;
fn add(self, other: PageAlignedVa) -> PageAlignedVa {
let a = self.0.get();
let b = other.0.get();
@ -150,42 +149,42 @@ impl Add for PageAlignedVa {
pub(crate) struct PageAlignedPa(PhysAddr);
impl PageAlignedPa {
#[allow(dead_code)]
pub(crate) fn as_u32(&self) -> u32 {self.0 as u32}
pub(crate) fn as_u32(&self) -> u32 { self.0 as u32 }
#[allow(dead_code)]
pub(crate) fn as_u64(&self) -> u64 {self.0 as u64}
pub(crate) fn as_u64(&self) -> u64 { self.0 as u64 }
#[allow(dead_code)]
pub(crate) fn as_usize(&self) -> usize {self.0 as usize}
pub(crate) fn as_usize(&self) -> usize { self.0 as usize }
#[allow(dead_code)]
pub(crate) fn as_phys_addr(&self) -> PhysAddr {self.0}
pub(crate) fn as_phys_addr(&self) -> PhysAddr { self.0 }
}
impl From<u32> for PageAlignedPa {
fn from(arg: u32) -> Self {
if arg & (PAGE_SIZE as u32 - 1) == 0 {
PageAlignedPa( (arg & !(PAGE_SIZE as u32 - 1)) as PhysAddr )
PageAlignedPa((arg & !(PAGE_SIZE as u32 - 1)) as PhysAddr)
} else {
PageAlignedPa( ((arg & !(PAGE_SIZE as u32 - 1)) + PAGE_SIZE as u32) as PhysAddr )
PageAlignedPa(((arg & !(PAGE_SIZE as u32 - 1)) + PAGE_SIZE as u32) as PhysAddr)
}
}
}
impl From<usize> for PageAlignedPa {
fn from(arg: usize) -> Self {
if arg & (PAGE_SIZE as usize - 1) == 0 {
PageAlignedPa( (arg as u32 & !(PAGE_SIZE as u32 - 1)) as PhysAddr )
PageAlignedPa((arg as u32 & !(PAGE_SIZE as u32 - 1)) as PhysAddr)
} else {
PageAlignedPa( ((arg as u32 & !(PAGE_SIZE as u32 - 1)) + PAGE_SIZE as u32) as PhysAddr )
PageAlignedPa(((arg as u32 & !(PAGE_SIZE as u32 - 1)) + PAGE_SIZE as u32) as PhysAddr)
}
}
}
impl From<PageAlignedPa> for u32 {
fn from(arg: PageAlignedPa) -> Self {
arg.0 as u32
}
fn from(arg: PageAlignedPa) -> Self { arg.0 as u32 }
}
impl Add for PageAlignedPa {
type Output = PageAlignedPa;
fn add(self, other: PageAlignedPa) -> PageAlignedPa {
PageAlignedPa(self.0 + other.0 as PhysAddr)
}
fn add(self, other: PageAlignedPa) -> PageAlignedPa { PageAlignedPa(self.0 + other.0 as PhysAddr) }
}
#[cfg(test)]
@ -197,10 +196,10 @@ mod tests {
assert!(PAGE_SIZE & (PAGE_SIZE - 1) == 0, "PAGE_SIZE is not a power of two!");
}
/// This test exists because nothing in the bitfield spec explicitly requires that a true maps to a 1.
/// In fact a lot of code would work just fine if you mapped true to 0 and false to 1: if you're just using
/// the generated getter and setter, it woudln't matter.
/// However, in our application, we fully expect a true to be a 1. This test exists to ensure this seemingly
/// obvious but not explicitly stated fact always remains true.
/// In fact a lot of code would work just fine if you mapped true to 0 and false to 1: if you're just
/// using the generated getter and setter, it woudln't matter.
/// However, in our application, we fully expect a true to be a 1. This test exists to ensure this
/// seemingly obvious but not explicitly stated fact always remains true.
#[test]
fn test_bitfield_bool() {
bitfield! {

View file

@ -1,10 +1,11 @@
use crate::*;
use xous::{CID, send_message, Message};
use xous_ipc::Buffer;
use std::io::{Error, ErrorKind, Result};
use std::io::{Read, Seek, SeekFrom, Write};
use num_traits::*;
use std::io::{Result, Error, ErrorKind};
use std::io::{Read, Write, Seek, SeekFrom};
use xous::{send_message, Message, CID};
use xous_ipc::Buffer;
use crate::*;
pub struct PddbKey<'a> {
pub(crate) token: ApiToken,
@ -16,13 +17,13 @@ pub struct PddbKey<'a> {
/// PddbKeys are created by Pddb
impl<'a> PddbKey<'a> {
/// this will clear all residual values in the buffer. Should be called whenever the Basis set changes.
pub fn volatile_clear(&mut self) {
self.buf.volatile_clear();
}
pub fn volatile_clear(&mut self) { self.buf.volatile_clear(); }
pub fn attributes(&self) -> Result<KeyAttributes> {
let req = PddbKeyAttrIpc::new(self.token);
let mut buf = Buffer::into_buf(req).expect("Couldn't convert memory structure");
buf.lend_mut(self.conn, Opcode::KeyAttributes.to_u32().unwrap()).expect("couldn't execute KeyAttributes opcode");
buf.lend_mut(self.conn, Opcode::KeyAttributes.to_u32().unwrap())
.expect("couldn't execute KeyAttributes opcode");
let ret = buf.to_original::<PddbKeyAttrIpc, _>().expect("couldn't restore req structure");
match ret.code {
PddbRequestCode::NoErr => Ok(ret.to_attributes()),
@ -50,7 +51,8 @@ impl<'a> Seek for PddbKey<'a> {
SeekFrom::End(p) => {
let req = PddbKeyAttrIpc::new(self.token);
let mut buf = Buffer::into_buf(req).expect("Couldn't convert memory structure");
buf.lend_mut(self.conn, Opcode::KeyAttributes.to_u32().unwrap()).expect("couldn't execute KeyAttributes opcode");
buf.lend_mut(self.conn, Opcode::KeyAttributes.to_u32().unwrap())
.expect("couldn't execute KeyAttributes opcode");
let ret = buf.to_original::<PddbKeyAttrIpc, _>().expect("couldn't restore req structure");
match ret.code {
PddbRequestCode::NoErr => {
@ -61,7 +63,7 @@ impl<'a> Seek for PddbKey<'a> {
} else {
Err(Error::new(ErrorKind::InvalidInput, "Seek to negative offset"))
}
},
}
PddbRequestCode::NotFound => Err(Error::new(ErrorKind::NotFound, "Key not found")),
_ => Err(Error::new(ErrorKind::Other, "Internal error requesting key attributes")),
}
@ -78,26 +80,24 @@ impl<'a> Read for PddbKey<'a> {
// create pbuf from a pre-reserved chunk of memory, to save on allocator thrashing
// note that it does mean that un-erased data from previous reads and writes are passed back
// to the server, which is a kind of information leakage, but I think in practice we're
// leaking that data back to a server where the data had either originated from or was disclosed at
// one point.
// leaking that data back to a server where the data had either originated from or was disclosed
// at one point.
let readlen = {
let pbuf = PddbBuf::from_slice_mut(self.buf.as_mut());
// sure, we could make it a loop, but...unrolled seems better
pbuf.token[0] = self.token[0];
pbuf.token[1] = self.token[1];
pbuf.token[2] = self.token[2];
let readlen = if buf.len() <= pbuf.data.len() {
buf.len() as u16
} else {
pbuf.data.len() as u16
};
let readlen =
if buf.len() <= pbuf.data.len() { buf.len() as u16 } else { pbuf.data.len() as u16 };
pbuf.len = readlen;
pbuf.retcode = PddbRetcode::Uninit;
pbuf.position = self.pos;
readlen
};
// this takes the buffer and remaps it to the server, and on return the data is mapped back
self.buf.lend_mut(self.conn, Opcode::ReadKey.to_u32().unwrap())
self.buf
.lend_mut(self.conn, Opcode::ReadKey.to_u32().unwrap())
.or(Err(Error::new(ErrorKind::Other, "Xous internal error")))?;
{
// at this point, pbuf has been mutated by the server with a return code and the return data.
@ -112,12 +112,16 @@ impl<'a> Read for PddbKey<'a> {
Ok(pbuf.len as usize)
}
PddbRetcode::BasisLost => Err(Error::new(ErrorKind::BrokenPipe, "Basis lost")),
PddbRetcode::AccessDenied => Err(Error::new(ErrorKind::PermissionDenied, "Access denied")),
PddbRetcode::UnexpectedEof => Ok(0), // I believe this is the "expected" behavior for reads that want to read beyond the current end of file
PddbRetcode::AccessDenied => {
Err(Error::new(ErrorKind::PermissionDenied, "Access denied"))
}
PddbRetcode::UnexpectedEof => Ok(0), /* I believe this is the "expected" behavior for
* reads that want to read beyond the current end
* of file */
_ => {
log::error!("Unhandled error code: {:?}", pbuf.retcode);
Err(Error::new(ErrorKind::Other, "Unhandled error code in PddbKey Read"))
},
}
}
}
}
@ -135,11 +139,8 @@ impl<'a> Write for PddbKey<'a> {
pbuf.token[0] = self.token[0];
pbuf.token[1] = self.token[1];
pbuf.token[2] = self.token[2];
let writelen = if buf.len() <= pbuf.data.len() {
buf.len() as u16
} else {
pbuf.data.len() as u16
};
let writelen =
if buf.len() <= pbuf.data.len() { buf.len() as u16 } else { pbuf.data.len() as u16 };
pbuf.len = writelen;
pbuf.retcode = PddbRetcode::Uninit;
for (&src, dst) in buf.iter().zip(pbuf.data.iter_mut()) {
@ -149,7 +150,8 @@ impl<'a> Write for PddbKey<'a> {
writelen
};
// this takes the buffer and remaps it to the server, and on return the data is mapped back
self.buf.lend_mut(self.conn, Opcode::WriteKey.to_u32().unwrap())
self.buf
.lend_mut(self.conn, Opcode::WriteKey.to_u32().unwrap())
.or(Err(Error::new(ErrorKind::Other, "Xous internal error")))?;
{
// at this point, pbuf has been mutated by the server with a return code and the return data.
@ -161,22 +163,28 @@ impl<'a> Write for PddbKey<'a> {
Ok(pbuf.len as usize)
}
PddbRetcode::BasisLost => Err(Error::new(ErrorKind::BrokenPipe, "Basis lost")),
PddbRetcode::AccessDenied => Err(Error::new(ErrorKind::PermissionDenied, "Access denied")),
PddbRetcode::AccessDenied => {
Err(Error::new(ErrorKind::PermissionDenied, "Access denied"))
}
_ => Err(Error::new(ErrorKind::Other, "Unhandled error code in PddbKey Write")),
}
}
}
}
fn flush(&mut self) -> Result<()> {
let response = send_message(
self.conn,
Message::new_blocking_scalar(Opcode::WriteKeyFlush.to_usize().unwrap(), 0, 0, 0, 0)
).or(Err(Error::new(ErrorKind::Other, "Xous internal error")))?;
Message::new_blocking_scalar(Opcode::WriteKeyFlush.to_usize().unwrap(), 0, 0, 0, 0),
)
.or(Err(Error::new(ErrorKind::Other, "Xous internal error")))?;
if let xous::Result::Scalar1(rcode) = response {
match FromPrimitive::from_u8(rcode as u8) {
Some(PddbRetcode::Ok) => Ok(()),
Some(PddbRetcode::BasisLost) => Err(Error::new(ErrorKind::BrokenPipe, "Basis lost")),
Some(PddbRetcode::DiskFull) => Err(Error::new(ErrorKind::OutOfMemory, "Out of disk space, some data lost on sync")),
Some(PddbRetcode::DiskFull) => {
Err(Error::new(ErrorKind::OutOfMemory, "Out of disk space, some data lost on sync"))
}
_ => Err(Error::new(ErrorKind::Interrupted, "Flush failed for unspecified reasons")),
}
} else {
@ -191,12 +199,22 @@ impl<'a> Drop for PddbKey<'a> {
self.buf.volatile_clear(); // clears any confidential data in our memory buffer
// notify the server that we can drop the connection state when our object goes out of scope
send_message(self.conn, Message::new_blocking_scalar(Opcode::KeyDrop.to_usize().unwrap(),
self.token[0] as usize, self.token[1] as usize, self.token[2] as usize, 0)).expect("couldn't send KeyDrop message");
send_message(
self.conn,
Message::new_blocking_scalar(
Opcode::KeyDrop.to_usize().unwrap(),
self.token[0] as usize,
self.token[1] as usize,
self.token[2] as usize,
0,
),
)
.expect("couldn't send KeyDrop message");
if REFCOUNT.fetch_sub(1, Ordering::Relaxed) == 1 {
unsafe{xous::disconnect(self.conn).unwrap();}
unsafe {
xous::disconnect(self.conn).unwrap();
}
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,12 +1,12 @@
mod senres;
mod utils;
use senres::{Senres, SenresMut};
use crate::backend::BasisCache;
use crate::backend::PddbOs;
use crate::FileHandle;
use senres::{Senres, SenresMut};
#[repr(u8)]
enum FileType {
Basis = 0,
@ -48,13 +48,8 @@ pub(crate) fn stat_path(
let mut backing = unsafe { senres::Message::from_mut_slice(mem.buf.as_slice_mut()) }
.or(Err(crate::PddbRetcode::InternalError))?;
let reader = backing
.reader(*b"StaQ")
.ok_or(crate::PddbRetcode::InternalError)?;
let path = reader
.try_get_ref_from::<str>()
.or(Err(crate::PddbRetcode::InternalError))?
.to_owned();
let reader = backing.reader(*b"StaQ").ok_or(crate::PddbRetcode::InternalError)?;
let path = reader.try_get_ref_from::<str>().or(Err(crate::PddbRetcode::InternalError))?.to_owned();
// TODO: use the internal cache inside `basis_cache` to avoid cloning
let (basis, remainder) =
@ -62,18 +57,13 @@ pub(crate) fn stat_path(
.or(Err(crate::PddbRetcode::InternalError))?;
core::mem::drop(reader);
let mut writer = backing
.writer(*b"StaR")
.ok_or(crate::PddbRetcode::InternalError)?;
let mut writer = backing.writer(*b"StaR").ok_or(crate::PddbRetcode::InternalError)?;
// The only time these two are empty is when we want to list the default basis, which
// itself is not a valid path
if basis.is_none() && remainder.is_none() {
writer.append(4u8); // None
log::error!(
"path {} has no basis and no remainder, and therefore does not exist",
path
);
log::error!("path {} has no basis and no remainder, and therefore does not exist", path);
return Ok(());
}
@ -153,22 +143,16 @@ pub(crate) fn list_path(
let mut backing = unsafe { senres::Message::from_mut_slice(mem.buf.as_slice_mut()) }
.or(Err(crate::PddbRetcode::InternalError))?;
let reader = backing
.reader(*b"PthQ")
.ok_or(crate::PddbRetcode::InternalError)?;
let reader = backing.reader(*b"PthQ").ok_or(crate::PddbRetcode::InternalError)?;
let path = reader
.try_get_ref_from()
.or(Err(crate::PddbRetcode::InternalError))?;
let path = reader.try_get_ref_from().or(Err(crate::PddbRetcode::InternalError))?;
let (basis, dict) =
utils::split_basis_and_dict(path, || basis_cache.basis_latest().map(|m| m.to_owned()))
.or(Err(crate::PddbRetcode::InternalError))?;
core::mem::drop(reader);
let mut writer = backing
.writer(*b"PthR")
.ok_or(crate::PddbRetcode::InternalError)?;
let mut writer = backing.writer(*b"PthR").ok_or(crate::PddbRetcode::InternalError)?;
// The only time these two are empty is when we want to list the default basis.
if basis.is_none() && dict.is_none() {
@ -249,13 +233,9 @@ pub(crate) fn list_basis(
.or(Err(crate::PddbRetcode::InternalError))?;
{
backing
.reader(*b"basQ")
.ok_or(crate::PddbRetcode::InternalError)?;
backing.reader(*b"basQ").ok_or(crate::PddbRetcode::InternalError)?;
}
let mut writer = backing
.writer(*b"basR")
.ok_or(crate::PddbRetcode::InternalError)?;
let mut writer = backing.writer(*b"basR").ok_or(crate::PddbRetcode::InternalError)?;
// Add the count of bases
writer.append(basis_list.len() as u32);
@ -288,41 +268,22 @@ pub(crate) fn open_key(
let alloc_hint: usize;
let cb_sid: Option<xous::SID>;
let (requested_basis, requested_dict) = {
let reader = backing
.reader(*b"KyOQ")
.ok_or(crate::PddbRetcode::InternalError)?;
let reader = backing.reader(*b"KyOQ").ok_or(crate::PddbRetcode::InternalError)?;
let path = reader
.try_get_ref_from()
.or(Err(crate::PddbRetcode::InternalError))?;
create_file = reader
.try_get_from()
.or(Err(crate::PddbRetcode::InternalError))?;
let path = reader.try_get_ref_from().or(Err(crate::PddbRetcode::InternalError))?;
create_file = reader.try_get_from().or(Err(crate::PddbRetcode::InternalError))?;
create_path = reader
.try_get_from()
.or(Err(crate::PddbRetcode::InternalError))?;
create_path = reader.try_get_from().or(Err(crate::PddbRetcode::InternalError))?;
create_new = reader
.try_get_from()
.or(Err(crate::PddbRetcode::InternalError))?;
create_new = reader.try_get_from().or(Err(crate::PddbRetcode::InternalError))?;
append = reader
.try_get_from()
.or(Err(crate::PddbRetcode::InternalError))?;
append = reader.try_get_from().or(Err(crate::PddbRetcode::InternalError))?;
truncate = reader
.try_get_from()
.or(Err(crate::PddbRetcode::InternalError))?;
truncate = reader.try_get_from().or(Err(crate::PddbRetcode::InternalError))?;
alloc_hint = reader
.try_get_from::<u64>()
.or(Err(crate::PddbRetcode::InternalError))? as usize;
alloc_hint = reader.try_get_from::<u64>().or(Err(crate::PddbRetcode::InternalError))? as usize;
cb_sid = if let Some(sid) = reader
.try_get_from()
.or(Err(crate::PddbRetcode::InternalError))?
{
cb_sid = if let Some(sid) = reader.try_get_from().or(Err(crate::PddbRetcode::InternalError))? {
Some(xous::SID::from_array(sid))
} else {
None
@ -339,16 +300,13 @@ pub(crate) fn open_key(
// Split the final ":key" off from the dict. If there are no ":" then this will fail
// with the "no key was specified" error.
let (requested_dict, requested_key) = requested_dict
.rsplit_once(std::path::MAIN_SEPARATOR)
.ok_or_else(|| {
let (requested_dict, requested_key) =
requested_dict.rsplit_once(std::path::MAIN_SEPARATOR).ok_or_else(|| {
log::error!("no key was specified");
crate::PddbRetcode::AccessDenied
})?;
let mut writer = backing
.writer(*b"KyOR")
.ok_or(crate::PddbRetcode::InternalError)?;
let mut writer = backing.writer(*b"KyOR").ok_or(crate::PddbRetcode::InternalError)?;
// Behavior for opening files:
// 1. If `bname` is defined, then we only loop once.
@ -359,24 +317,19 @@ pub(crate) fn open_key(
let bname = Some(basis.as_str());
// If the dictionary wasn't found, either add it or move on
if basis_cache
.dict_attributes(pddb_os, requested_dict, bname)
.is_err()
{
if basis_cache.dict_attributes(pddb_os, requested_dict, bname).is_err() {
if !create_path {
continue;
}
basis_cache
.dict_add(pddb_os, requested_dict, bname)
.map_err(|e| {
log::error!(
"unable to add dict {} to basis {}: {:?}",
requested_dict,
bname.unwrap_or("internal_error"),
e
);
crate::PddbRetcode::InternalError
})?;
basis_cache.dict_add(pddb_os, requested_dict, bname).map_err(|e| {
log::error!(
"unable to add dict {} to basis {}: {:?}",
requested_dict,
bname.unwrap_or("internal_error"),
e
);
crate::PddbRetcode::InternalError
})?;
}
let mut len = 0;
@ -399,11 +352,7 @@ pub(crate) fn open_key(
requested_key,
&[],
None,
if alloc_hint > 0 {
Some(alloc_hint)
} else {
None
},
if alloc_hint > 0 { Some(alloc_hint) } else { None },
bname,
true,
)
@ -420,7 +369,9 @@ pub(crate) fn open_key(
} else if create_new {
log::error!(
"user requested to create {}{}{} with `create_new` set, but that file already exists",
requested_dict, std::path::MAIN_SEPARATOR, requested_key
requested_dict,
std::path::MAIN_SEPARATOR,
requested_key
);
return Err(crate::PddbRetcode::DiskFull);
} else if truncate {
@ -432,11 +383,7 @@ pub(crate) fn open_key(
requested_key,
&[],
None,
if alloc_hint > 0 {
Some(alloc_hint)
} else {
None
},
if alloc_hint > 0 { Some(alloc_hint) } else { None },
bname,
true,
)
@ -452,8 +399,7 @@ pub(crate) fn open_key(
}
// The basis exists for sure.
let conn =
cb_sid.map(|cb_sid| xous::connect(cb_sid).expect("couldn't connect for callback"));
let conn = cb_sid.map(|cb_sid| xous::connect(cb_sid).expect("couldn't connect for callback"));
let file_handle = crate::FileHandle {
dict: String::from(requested_dict),
key: String::from(requested_key),
@ -462,11 +408,7 @@ pub(crate) fn open_key(
length: len,
deleted: false,
conn,
alloc_hint: if alloc_hint > 0 {
Some(alloc_hint)
} else {
None
},
alloc_hint: if alloc_hint > 0 { Some(alloc_hint) } else { None },
};
// Look for the first `None` record in the file descriptor list. If there
@ -494,11 +436,7 @@ pub(crate) fn open_key(
return Ok(());
}
log::error!(
"unable to find key {} in dict {}",
requested_key,
requested_dict
);
log::error!("unable to find key {} in dict {}", requested_key, requested_dict);
// If we fall off the end, then the dict/key do not exist
Err(crate::PddbRetcode::BasisLost)
@ -557,45 +495,26 @@ pub(crate) fn delete_key(
let backing = unsafe { senres::Message::from_mut_slice(mem.buf.as_slice_mut()) }
.or(Err(crate::PddbRetcode::InternalError))?;
let reader = backing
.reader(*b"RmKQ")
.ok_or(crate::PddbRetcode::InternalError)?;
let reader = backing.reader(*b"RmKQ").ok_or(crate::PddbRetcode::InternalError)?;
let full_path = reader
.try_get_ref_from::<str>()
.or(Err(crate::PddbRetcode::BasisLost))?;
let full_path = reader.try_get_ref_from::<str>().or(Err(crate::PddbRetcode::BasisLost))?;
let (basis, path) = utils::split_basis_and_dict(full_path, || {
basis_cache.basis_latest().map(|m| m.to_owned())
})
.or(Err(crate::PddbRetcode::AccessDenied))?;
let (basis, path) =
utils::split_basis_and_dict(full_path, || basis_cache.basis_latest().map(|m| m.to_owned()))
.or(Err(crate::PddbRetcode::AccessDenied))?;
let path = path.ok_or(crate::PddbRetcode::AccessDenied)?;
let bname = basis.as_deref();
let (dict, key) = path
.rsplit_once(std::path::MAIN_SEPARATOR)
.ok_or(crate::PddbRetcode::AccessDenied)?;
let (dict, key) = path.rsplit_once(std::path::MAIN_SEPARATOR).ok_or(crate::PddbRetcode::AccessDenied)?;
// Perform the actual removal
basis_cache
.key_remove(pddb_os, dict, key, bname, false)
.or_else(|e| {
log::error!(
"unable to delete key {} in dict {} (basis {:?}): {:?}",
key,
dict,
bname,
e
);
Err(crate::PddbRetcode::UnexpectedEof)
})?;
basis_cache.key_remove(pddb_os, dict, key, bname, false).or_else(|e| {
log::error!("unable to delete key {} in dict {} (basis {:?}): {:?}", key, dict, bname, e);
Err(crate::PddbRetcode::UnexpectedEof)
})?;
// Mark the entry as deleted in all remaining file handles in the entire system
for fds in all_fds.values_mut() {
for fd in fds
.iter_mut()
.filter(|f| f.is_some())
.map(|f| f.as_mut().unwrap())
{
for fd in fds.iter_mut().filter(|f| f.is_some()).map(|f| f.as_mut().unwrap()) {
if fd.basis == basis && fd.key == key && fd.dict == dict {
fd.deleted = true;
}
@ -616,12 +535,7 @@ pub(crate) fn write_key(
let mut retcode = crate::PddbRetcode::InternalError;
for basis in basis_cache.access_list().iter() {
log::debug!(
"write (spec: {:?}){:?} {}",
file.basis,
file.basis.as_ref().unwrap_or(basis),
file.key
);
log::debug!("write (spec: {:?}){:?} {}", file.basis, file.basis.as_ref().unwrap_or(basis), file.key);
let length_to_write = mem.valid.map(|v| v.get()).unwrap_or_default();
// Safety: all `u8` values are valid
if basis_cache
@ -633,10 +547,11 @@ pub(crate) fn write_key(
// &mut pbuf.data[..pbuf.len as usize],
Some(file.offset as usize),
file.alloc_hint,
// this is a bit inefficient because if a specific basis is specified *and* the key does not exist,
// it'll retry the same basis for a number of times equal to the number of bases open.
// However, usually, there's only 1-2 bases open, and usually, if you specify a basis,
// the key will be a hit, so, we let it stand.
// this is a bit inefficient because if a specific basis is specified *and* the key does not
// exist, it'll retry the same basis for a number of times equal to the
// number of bases open. However, usually, there's only 1-2 bases open, and
// usually, if you specify a basis, the key will be a hit, so, we let it
// stand.
Some(file.basis.as_ref().unwrap_or(basis)),
false,
)
@ -665,11 +580,7 @@ pub(crate) fn seek_key(
) -> Result<u64, crate::PddbRetcode> {
let file = get_fd(fds, fd)?;
fn seek_from_point(
this: &mut FileHandle,
point: u64,
by: i64,
) -> Result<u64, crate::PddbRetcode> {
fn seek_from_point(this: &mut FileHandle, point: u64, by: i64) -> Result<u64, crate::PddbRetcode> {
let by64 = by as u64;
// Note that it's possible to seek past the end of a key, and in this case
// the `offset` will be greater than the `len`. This is fine, and `len` will
@ -712,12 +623,7 @@ pub(crate) fn read_key(
let mut retcode = crate::PddbRetcode::Ok;
for basis in basis_cache.access_list().iter() {
log::debug!(
"read (spec: {:?}){:?} {}",
file.basis,
file.basis.as_ref().unwrap_or(basis),
file.key
);
log::debug!("read (spec: {:?}){:?} {}", file.basis, file.basis.as_ref().unwrap_or(basis), file.key);
// Safety: all u8 values are valid
if let Ok(readlen) = basis_cache
.key_read(
@ -726,18 +632,17 @@ pub(crate) fn read_key(
&file.key,
unsafe { &mut mem.buf.as_slice_mut()[0..mem.valid.map(|v| v.get()).unwrap_or_default()] },
Some(file.offset as usize),
// this is a bit inefficient because if a specific basis is specified *and* the key does not exist,
// it'll retry the same basis for a number of times equal to the number of bases open.
// However, usually, there's only 1-2 bases open, and usually, if you specify a basis,
// the key will be a hit, so, we let it stand.
// this is a bit inefficient because if a specific basis is specified *and* the key does not
// exist, it'll retry the same basis for a number of times equal to the
// number of bases open. However, usually, there's only 1-2 bases open, and
// usually, if you specify a basis, the key will be a hit, so, we let it
// stand.
Some(file.basis.as_ref().unwrap_or(basis)),
)
.map_err(|e| {
match e.kind() {
std::io::ErrorKind::NotFound => retcode = crate::PddbRetcode::BasisLost,
std::io::ErrorKind::UnexpectedEof => {
retcode = crate::PddbRetcode::UnexpectedEof
}
std::io::ErrorKind::UnexpectedEof => retcode = crate::PddbRetcode::UnexpectedEof,
std::io::ErrorKind::OutOfMemory => retcode = crate::PddbRetcode::DiskFull,
_ => retcode = crate::PddbRetcode::InternalError,
};
@ -749,12 +654,7 @@ pub(crate) fn read_key(
return Ok(());
}
}
log::error!(
"couldn't find file {} in dict {} in basis {:?}",
file.key,
file.dict,
file.basis
);
log::error!("couldn't find file {} in dict {} in basis {:?}", file.key, file.dict, file.basis);
Err(retcode)
}
@ -768,17 +668,11 @@ pub(crate) fn list_dict(
.or(Err(crate::PddbRetcode::InternalError))?;
let bname;
{
let reader = backing
.reader(*b"LiDQ")
.ok_or(crate::PddbRetcode::InternalError)?;
bname = reader
.try_get_from::<Option<String>>()
.map_err(|_| crate::PddbRetcode::InternalError)?;
let reader = backing.reader(*b"LiDQ").ok_or(crate::PddbRetcode::InternalError)?;
bname = reader.try_get_from::<Option<String>>().map_err(|_| crate::PddbRetcode::InternalError)?;
}
let mut writer = backing
.writer(*b"LiDR")
.ok_or(crate::PddbRetcode::InternalError)?;
let mut writer = backing.writer(*b"LiDR").ok_or(crate::PddbRetcode::InternalError)?;
let dict_list = basis_cache.dict_list(pddb_os, bname.as_deref());
writer.append(dict_list.len() as u32);
@ -800,33 +694,17 @@ pub(crate) fn list_key(
let bname;
let key;
{
let reader = backing
.reader(*b"LiKQ")
.ok_or(crate::PddbRetcode::InternalError)?;
bname = reader
.try_get_from::<Option<String>>()
.map_err(|_| crate::PddbRetcode::InternalError)?;
key = reader
.try_get_ref_from::<str>()
.map_err(|_| crate::PddbRetcode::InternalError)?
.to_owned();
let reader = backing.reader(*b"LiKQ").ok_or(crate::PddbRetcode::InternalError)?;
bname = reader.try_get_from::<Option<String>>().map_err(|_| crate::PddbRetcode::InternalError)?;
key = reader.try_get_ref_from::<str>().map_err(|_| crate::PddbRetcode::InternalError)?.to_owned();
}
let mut writer = backing
.writer(*b"LiKR")
.ok_or(crate::PddbRetcode::InternalError)?;
let mut writer = backing.writer(*b"LiKR").ok_or(crate::PddbRetcode::InternalError)?;
let (key_list, _, _) = basis_cache
.key_list(pddb_os, &key, bname.as_deref())
.or_else(|e| {
log::error!(
"unable to get key list of dict {} in basis {:?}: {:?}",
key,
bname,
e
);
Err(crate::PddbRetcode::InternalError)
})?;
let (key_list, _, _) = basis_cache.key_list(pddb_os, &key, bname.as_deref()).or_else(|e| {
log::error!("unable to get key list of dict {} in basis {:?}: {:?}", key, bname, e);
Err(crate::PddbRetcode::InternalError)
})?;
writer.append(key_list.len() as u32);
for dict in key_list.iter() {
@ -844,13 +722,9 @@ pub(crate) fn delete_dict(
// Safety: the memory message must be aligned, and we test for validity here
let backing = unsafe { senres::Message::from_mut_slice(mem.buf.as_slice_mut()) }
.or(Err(crate::PddbRetcode::InternalError))?;
let reader = backing
.reader(*b"RmDQ")
.ok_or(crate::PddbRetcode::InternalError)?;
let reader = backing.reader(*b"RmDQ").ok_or(crate::PddbRetcode::InternalError)?;
let path = reader
.try_get_ref_from::<str>()
.or(Err(crate::PddbRetcode::InternalError))?;
let path = reader.try_get_ref_from::<str>().or(Err(crate::PddbRetcode::InternalError))?;
let (bname, dict) =
utils::split_basis_and_dict(path, || basis_cache.basis_latest().map(|m| m.to_owned()))
.or(Err(crate::PddbRetcode::InternalError))?;
@ -870,10 +744,7 @@ pub(crate) fn delete_dict(
}
}
if basis_cache
.dict_remove(pddb_os, &dict, bname.as_deref(), false)
.is_err()
{
if basis_cache.dict_remove(pddb_os, &dict, bname.as_deref(), false).is_err() {
log::error!("error removing dict {} in basis {:?}", dict, bname);
return Err(crate::PddbRetcode::InternalError);
}
@ -889,29 +760,23 @@ pub(crate) fn create_dict(
// Safety: the memory message must be aligned, and we test for validity here
let backing = unsafe { senres::Message::from_mut_slice(mem.buf.as_slice_mut()) }
.or(Err(crate::PddbRetcode::InternalError))?;
let reader = backing
.reader(*b"NuDQ")
.ok_or(crate::PddbRetcode::InternalError)?;
let reader = backing.reader(*b"NuDQ").ok_or(crate::PddbRetcode::InternalError)?;
let path = reader
.try_get_ref_from::<str>()
.or(Err(crate::PddbRetcode::InternalError))?;
let path = reader.try_get_ref_from::<str>().or(Err(crate::PddbRetcode::InternalError))?;
let (basis, dict) =
utils::split_basis_and_dict(path, || basis_cache.basis_latest().map(|m| m.to_owned()))
.or(Err(crate::PddbRetcode::InternalError))?;
let dict = dict.ok_or(crate::PddbRetcode::InternalError)?;
basis_cache
.dict_add(pddb_os, &dict, basis.as_deref())
.map_err(|e| {
log::error!(
"unable to add dict {} to basis {}: {:?}",
dict,
basis.as_deref().unwrap_or("internal_error"),
e
);
crate::PddbRetcode::InternalError
})?;
basis_cache.dict_add(pddb_os, &dict, basis.as_deref()).map_err(|e| {
log::error!(
"unable to add dict {} to basis {}: {:?}",
dict,
basis.as_deref().unwrap_or("internal_error"),
e
);
crate::PddbRetcode::InternalError
})?;
Ok(())
}

View file

@ -69,26 +69,18 @@ impl<'a> Message<'a> {
data: unsafe { core::slice::from_raw_parts_mut(data as *mut u8, len) },
})
}
// Need to figure out how to make the non-mutable version work, since `data`
// must be a mutable vec.
pub fn from_slice(data: &'a [u8]) -> Result<Self, ()> {
Ok(Message {
message_id: 0,
auto_return: false,
data,
})
Ok(Message { message_id: 0, auto_return: false, data })
}
pub fn from_mut_slice(data: &'a mut [u8]) -> Result<MutableMessage<'a>, ()> {
Ok(MutableMessage {
message_id: 0,
mutable: true,
auto_return: false,
data,
})
}
pub fn auto_return(&mut self, enable: bool) {
self.auto_return = enable;
Ok(MutableMessage { message_id: 0, mutable: true, auto_return: false, data })
}
pub fn auto_return(&mut self, enable: bool) { self.auto_return = enable; }
}
#[cfg(target_os = "xous")]
@ -123,52 +115,35 @@ impl<'a> Drop for Message<'a> {
fn drop(&mut self) {
if self.auto_return {
#[cfg(target_os = "xous")]
return_memory_message(
self.message_id,
self.data.as_ptr() as usize,
self.data.len(),
);
return_memory_message(self.message_id, self.data.as_ptr() as usize, self.data.len());
}
}
}
impl<'a> SenresMut for MutableMessage<'a> {
fn as_mut_slice(&mut self) -> &mut [u8] {
self.data
}
fn as_mut_ptr(&mut self) -> *mut u8 {
self as *mut _ as *mut u8
}
fn as_mut_slice(&mut self) -> &mut [u8] { self.data }
fn as_mut_ptr(&mut self) -> *mut u8 { self as *mut _ as *mut u8 }
}
impl<'a> Senres for MutableMessage<'a> {
fn as_slice(&self) -> &[u8] {
self.data
}
fn len(&self) -> usize {
self.data.len()
}
fn as_ptr(&self) -> *const u8 {
self as *const _ as *const u8
}
fn can_create_writer(&self) -> bool {
self.mutable
}
fn as_slice(&self) -> &[u8] { self.data }
fn len(&self) -> usize { self.data.len() }
fn as_ptr(&self) -> *const u8 { self as *const _ as *const u8 }
fn can_create_writer(&self) -> bool { self.mutable }
}
impl<'a> Senres for Message<'a> {
fn as_slice(&self) -> &[u8] {
self.data
}
fn len(&self) -> usize {
self.data.len()
}
fn as_ptr(&self) -> *const u8 {
self as *const _ as *const u8
}
fn can_create_writer(&self) -> bool {
false
}
fn as_slice(&self) -> &[u8] { self.data }
fn len(&self) -> usize { self.data.len() }
fn as_ptr(&self) -> *const u8 { self as *const _ as *const u8 }
fn can_create_writer(&self) -> bool { false }
}
pub trait Senres {
@ -176,18 +151,13 @@ pub trait Senres {
fn as_ptr(&self) -> *const u8;
fn len(&self) -> usize;
fn can_create_writer(&self) -> bool {
true
}
fn can_create_writer(&self) -> bool { true }
fn reader(&self, fourcc: [u8; 4]) -> Option<Reader<Self>>
where
Self: core::marker::Sized,
{
let reader = Reader {
backing: self,
offset: core::cell::Cell::new(0),
};
let reader = Reader { backing: self, offset: core::cell::Cell::new(0) };
if SENRES_V1_MAGIC != reader.try_get_from().ok()? {
return None;
}
@ -199,9 +169,7 @@ pub trait Senres {
}
#[cfg(not(target_os = "xous"))]
fn lend(&self, _connection: u32, _opcode: usize) -> Result<(), ()> {
Ok(())
}
fn lend(&self, _connection: u32, _opcode: usize) -> Result<(), ()> { Ok(()) }
#[cfg(target_os = "xous")]
fn lend(&self, connection: u32, opcode: usize) -> Result<(), ()> {
@ -246,18 +214,13 @@ pub trait SenresMut: Senres {
if !self.can_create_writer() {
return None;
}
let mut writer = Writer {
backing: self,
offset: 0,
};
let mut writer = Writer { backing: self, offset: 0 };
writer.append(SENRES_V1_MAGIC);
writer.append(fourcc);
Some(writer)
}
#[cfg(not(target_os = "xous"))]
fn lend_mut(&mut self, _connection: u32, _opcode: usize) -> Result<(), ()> {
Ok(())
}
fn lend_mut(&mut self, _connection: u32, _opcode: usize) -> Result<(), ()> { Ok(()) }
#[cfg(target_os = "xous")]
fn lend_mut(&mut self, connection: u32, opcode: usize) -> Result<(), ()> {
let mut a0 = Syscall::SendMessage as usize;
@ -294,7 +257,6 @@ pub trait SenresMut: Senres {
}
}
pub struct Writer<'a, Backing: SenresMut> {
backing: &'a mut Backing,
offset: usize,
@ -341,30 +303,21 @@ impl<const N: usize> Stack<N> {
}
impl<const N: usize> SenresMut for Stack<N> {
fn as_mut_slice(&mut self) -> &mut [u8] {
self.data.as_mut_slice()
}
fn as_mut_ptr(&mut self) -> *mut u8 {
&mut self.data as *mut _ as *mut u8
}
fn as_mut_slice(&mut self) -> &mut [u8] { self.data.as_mut_slice() }
fn as_mut_ptr(&mut self) -> *mut u8 { &mut self.data as *mut _ as *mut u8 }
}
impl<const N: usize> Senres for Stack<N> {
fn as_slice(&self) -> &[u8] {
self.data.as_slice()
}
fn len(&self) -> usize {
N
}
fn as_ptr(&self) -> *const u8 {
&self.data as *const _ as *const u8
}
fn as_slice(&self) -> &[u8] { self.data.as_slice() }
fn len(&self) -> usize { N }
fn as_ptr(&self) -> *const u8 { &self.data as *const _ as *const u8 }
}
impl<'a, Backing: SenresMut> Writer<'a, Backing> {
pub fn append<T: SenSer<Backing>>(&mut self, other: T) {
other.append_to(self);
}
pub fn append<T: SenSer<Backing>>(&mut self, other: T) { other.append_to(self); }
pub fn delayed_append<T: SenSer<Backing>>(&mut self) -> DelayedWriter<Backing, T> {
let delayed_writer = DelayedWriter {
@ -398,9 +351,7 @@ impl<'a, Backing: SenresMut> Writer<'a, Backing> {
}
impl<'a, Backing: Senres> Reader<'a, Backing> {
pub fn try_get_from<T: RecDes<Backing>>(&self) -> Result<T, ()> {
T::try_get_from(self)
}
pub fn try_get_from<T: RecDes<Backing>>(&self) -> Result<T, ()> { T::try_get_from(self) }
pub fn try_get_ref_from<T: RecDesRef<'a, Backing> + ?Sized>(&'a self) -> Result<&T, ()> {
T::try_get_ref_from(self)
@ -418,10 +369,8 @@ macro_rules! primitive_impl {
impl<Backing: SenresMut> SenSer<Backing> for $SelfT {
fn append_to(&self, senres: &mut Writer<Backing>) {
senres.align_to(core::mem::align_of::<Self>());
for (src, dest) in self
.to_le_bytes()
.iter()
.zip(senres.backing.as_mut_slice()[senres.offset..].iter_mut())
for (src, dest) in
self.to_le_bytes().iter().zip(senres.backing.as_mut_slice()[senres.offset..].iter_mut())
{
*dest = *src;
senres.offset += 1;
@ -438,9 +387,7 @@ macro_rules! primitive_impl {
return Err(());
}
let val = Self::from_le_bytes(
senres.backing.as_slice()[offset..offset + my_size]
.try_into()
.unwrap(),
senres.backing.as_slice()[offset..offset + my_size].try_into().unwrap(),
);
senres.offset.set(offset + my_size);
Ok(val)
@ -562,10 +509,8 @@ impl<T: RecDes<Backing>, Backing: Senres, const N: usize> RecDes<Backing> for [T
impl<Backing: SenresMut> SenSer<Backing> for str {
fn append_to(&self, senres: &mut Writer<Backing>) {
senres.append(self.len() as u32);
for (src, dest) in self
.as_bytes()
.iter()
.zip(senres.backing.as_mut_slice()[senres.offset..].iter_mut())
for (src, dest) in
self.as_bytes().iter().zip(senres.backing.as_mut_slice()[senres.offset..].iter_mut())
{
*dest = *src;
senres.offset += 1;
@ -576,10 +521,8 @@ impl<Backing: SenresMut> SenSer<Backing> for str {
impl<Backing: SenresMut> SenSer<Backing> for &str {
fn append_to(&self, senres: &mut Writer<Backing>) {
senres.append(self.len() as u32);
for (src, dest) in self
.as_bytes()
.iter()
.zip(senres.backing.as_mut_slice()[senres.offset..].iter_mut())
for (src, dest) in
self.as_bytes().iter().zip(senres.backing.as_mut_slice()[senres.offset..].iter_mut())
{
*dest = *src;
senres.offset += 1;
@ -594,12 +537,10 @@ impl<Backing: Senres> RecDes<Backing> for String {
if offset + len > senres.backing.as_slice().len() {
return Err(());
}
core::str::from_utf8(&senres.backing.as_slice()[offset..offset + len])
.or(Err(()))
.map(|e| {
senres.offset.set(offset + len);
e.to_owned()
})
core::str::from_utf8(&senres.backing.as_slice()[offset..offset + len]).or(Err(())).map(|e| {
senres.offset.set(offset + len);
e.to_owned()
})
}
}
@ -610,12 +551,10 @@ impl<'a, Backing: Senres> RecDesRef<'a, Backing> for str {
if offset + len > senres.backing.as_slice().len() {
return Err(());
}
core::str::from_utf8(&senres.backing.as_slice()[offset..offset + len])
.or(Err(()))
.map(|e| {
senres.offset.set(offset + len);
e
})
core::str::from_utf8(&senres.backing.as_slice()[offset..offset + len]).or(Err(())).map(|e| {
senres.offset.set(offset + len);
e
})
}
}
@ -627,10 +566,7 @@ impl<'a, Backing: Senres, T: RecDes<Backing>> RecDesRef<'a, Backing> for [T] {
return Err(());
}
let ret = unsafe {
core::slice::from_raw_parts(
senres.backing.as_slice().as_ptr().add(offset) as *const T,
len,
)
core::slice::from_raw_parts(senres.backing.as_slice().as_ptr().add(offset) as *const T, len)
};
senres.offset.set(offset + len * core::mem::size_of::<T>());
Ok(ret)
@ -638,9 +574,7 @@ impl<'a, Backing: Senres, T: RecDes<Backing>> RecDesRef<'a, Backing> for [T] {
}
impl<const N: usize> Default for Stack<N> {
fn default() -> Self {
Self::new()
}
fn default() -> Self { Self::new() }
}
fn do_stuff(_r: &Stack) {
@ -683,9 +617,7 @@ fn smoke_test() {
println!("u32 val: {}", val);
let val: u64 = reader.try_get_from().expect("couldn't get the u64 value");
println!("u64 val: {:x}", val);
let val: &str = reader
.try_get_ref_from()
.expect("couldn't get string value");
let val: &str = reader.try_get_ref_from().expect("couldn't get string value");
println!("String val: {}", val);
let val: String = reader.try_get_from().expect("couldn't get string2 value");
println!("String2 val: {}", val);
@ -694,9 +626,7 @@ fn smoke_test() {
let val: Option<u32> = reader.try_get_from().expect("couldn't get Option<u32>");
println!("Option<u32> val: {:?}", val);
let val: u8 = reader
.try_get_from()
.expect("couldn't get u8 weird padding");
let val: u8 = reader.try_get_from().expect("couldn't get u8 weird padding");
println!("u8 val: {}", val);
let val: &[i32] = reader.try_get_ref_from().expect("couldn't get &[i32]");

View file

@ -19,15 +19,14 @@ pub fn get_path<'a>(s: &'a str, prefix: &'a str) -> Option<&'a str> {
let without_prefix = s.strip_prefix(prefix)?.strip_prefix(':')?;
let mut path_split = without_prefix.split(':');
let parent = path_split.next();
if path_split.next().is_some() {
None
} else {
parent
}
if path_split.next().is_some() { None } else { parent }
}
/// Split a path into its constituant Basis and Dict, if the path is legal.
pub fn split_basis_and_dict<F: FnMut() -> Option<String>>(src: &str, mut default: F) -> io::Result<(Option<String>, Option<String>)> {
pub fn split_basis_and_dict<F: FnMut() -> Option<String>>(
src: &str,
mut default: F,
) -> io::Result<(Option<String>, Option<String>)> {
let mut basis = None;
let dict;
if let Some(src) = src.strip_prefix(MAIN_SEP) {
@ -70,9 +69,7 @@ pub fn split_basis_and_dict<F: FnMut() -> Option<String>>(src: &str, mut default
}
#[cfg(test)]
fn default_path() -> Option<String> {
Some("{DEFAULT}".to_owned())
}
fn default_path() -> Option<String> { Some("{DEFAULT}".to_owned()) }
#[test]
fn empty_string() {
@ -91,26 +88,23 @@ fn dict_with_colon() {
#[test]
fn dict_with_two_colons() {
assert_eq!(split_basis_and_dict("one:two:three", default_path).unwrap(), (None, Some("one:two:three".to_owned())));
assert_eq!(
split_basis_and_dict("one:two:three", default_path).unwrap(),
(None, Some("one:two:three".to_owned()))
);
}
#[test]
#[should_panic]
fn dict_with_trailing_colon() {
split_basis_and_dict("one:", default_path).unwrap();
}
fn dict_with_trailing_colon() { split_basis_and_dict("one:", default_path).unwrap(); }
#[test]
#[should_panic]
fn two_dicts_with_trailing_colon() {
split_basis_and_dict("one:two:", default_path).unwrap();
}
fn two_dicts_with_trailing_colon() { split_basis_and_dict("one:two:", default_path).unwrap(); }
#[test]
#[should_panic]
fn basis_with_dict_with_trailing_colon() {
split_basis_and_dict(":one:two:", default_path).unwrap();
}
fn basis_with_dict_with_trailing_colon() { split_basis_and_dict(":one:two:", default_path).unwrap(); }
#[test]
#[should_panic]
@ -125,12 +119,18 @@ fn basis_missing_colon() {
#[test]
fn basis_with_one_dict() {
assert_eq!(split_basis_and_dict(":one:two", default_path).unwrap(), (Some("one".to_owned()), Some("two".to_owned())));
assert_eq!(
split_basis_and_dict(":one:two", default_path).unwrap(),
(Some("one".to_owned()), Some("two".to_owned()))
);
}
#[test]
fn basis_with_two_dicts() {
assert_eq!(split_basis_and_dict(":one:two:three", default_path).unwrap(), (Some("one".to_owned()), Some("two:three".to_owned())));
assert_eq!(
split_basis_and_dict(":one:two:three", default_path).unwrap(),
(Some("one".to_owned()), Some("two:three".to_owned()))
);
}
#[test]
fn double_colon() {
@ -146,29 +146,29 @@ fn single_colon() {
#[test]
fn double_colon_two_keys() {
let default = default_path();
assert_eq!(split_basis_and_dict("::foo:bar", default_path).unwrap(), (default, Some("foo:bar".to_owned())));
assert_eq!(
split_basis_and_dict("::foo:bar", default_path).unwrap(),
(default, Some("foo:bar".to_owned()))
);
}
#[test]
fn double_colon_three_keys() {
let default = default_path();
assert_eq!(split_basis_and_dict("::foo:bar:baz", default_path).unwrap(), (default, Some("foo:bar:baz".to_owned())));
assert_eq!(
split_basis_and_dict("::foo:bar:baz", default_path).unwrap(),
(default, Some("foo:bar:baz".to_owned()))
);
}
#[test]
#[should_panic]
fn double_colon_three_keys_trailing_colon() {
split_basis_and_dict("::foo:bar:baz:", default_path).unwrap();
}
fn double_colon_three_keys_trailing_colon() { split_basis_and_dict("::foo:bar:baz:", default_path).unwrap(); }
#[test]
#[should_panic]
fn dict_with_two_keys_two_trailing_colons() {
split_basis_and_dict("foo:bar::", default_path).unwrap();
}
fn dict_with_two_keys_two_trailing_colons() { split_basis_and_dict("foo:bar::", default_path).unwrap(); }
#[test]
#[should_panic]
fn dict_with_two_keys_three_trailing_colons() {
split_basis_and_dict("foo:bar:::", default_path).unwrap();
}
fn dict_with_two_keys_three_trailing_colons() { split_basis_and_dict("foo:bar:::", default_path).unwrap(); }

File diff suppressed because it is too large Load diff

View file

@ -1,30 +1,27 @@
use gam::*;
use num_traits::*;
use locales::t;
use crate::api::*;
use num_traits::*;
use xous_ipc::String;
use crate::api::*;
pub(crate) fn pddb_menu(conn: xous::CID) {
let mut menu_items = Vec::<MenuItem>::new();
menu_items.push(
MenuItem {
name: String::from_str(t!("pddb.menu.listbasis", locales::LANG)),
action_conn: Some(conn),
action_opcode: Opcode::MenuListBasis.to_u32().unwrap(),
action_payload: MenuPayload::Scalar([0, 0, 0, 0]),
close_on_select: true,
}
);
menu_items.push(
MenuItem {
name: String::from_str(t!("pddb.menu.change_unlock_pin", locales::LANG)),
action_conn: Some(conn),
action_opcode: Opcode::MenuChangePin.to_u32().unwrap(),
action_payload: MenuPayload::Scalar([0, 0, 0, 0]),
close_on_select: true,
}
);
menu_items.push(MenuItem {
name: String::from_str(t!("pddb.menu.listbasis", locales::LANG)),
action_conn: Some(conn),
action_opcode: Opcode::MenuListBasis.to_u32().unwrap(),
action_payload: MenuPayload::Scalar([0, 0, 0, 0]),
close_on_select: true,
});
menu_items.push(MenuItem {
name: String::from_str(t!("pddb.menu.change_unlock_pin", locales::LANG)),
action_conn: Some(conn),
action_opcode: Opcode::MenuChangePin.to_u32().unwrap(),
action_payload: MenuPayload::Scalar([0, 0, 0, 0]),
close_on_select: true,
});
menu_items.push(MenuItem {
name: String::from_str(t!("mainmenu.closemenu", locales::LANG)),
action_conn: None,
@ -34,4 +31,4 @@ pub(crate) fn pddb_menu(conn: xous::CID) {
});
menu_matic(menu_items, PDDB_MENU_NAME, None);
}
}

View file

@ -1,6 +1,6 @@
use std::thread;
#[allow(unused_imports)]
use std::io::{Error, ErrorKind, Write, Read};
use std::io::{Error, ErrorKind, Read, Write};
use std::thread;
const PROFILING_DICT: &'static str = "pdict";
const NUMKEYS: usize = 200;
@ -21,9 +21,7 @@ pub fn do_query_work() {
let key_count = match pddb.list_keys(PROFILING_DICT, None) {
Ok(kl) => kl.len(),
Err(_e) => {
0
}
Err(_e) => 0,
};
// populate the dictionary if we're short the number of keys we want to have
@ -31,15 +29,7 @@ pub fn do_query_work() {
if key_count < NUMKEYS {
for _ in 0..NUMKEYS - key_count {
let guid = gen_guid(&mut trng);
match pddb.get(
PROFILING_DICT,
&guid,
None,
true,
true,
Some(256),
None::<fn()>
) {
match pddb.get(PROFILING_DICT, &guid, None, true, true, Some(256), None::<fn()>) {
Ok(mut key) => {
let mut rdata = [0u8; 192];
trng.fill_bytes(&mut rdata);
@ -63,4 +53,4 @@ pub fn do_query_work() {
log::info!("quitting");
});
}
}

View file

@ -1,18 +1,28 @@
use rand_chacha::ChaCha8Rng;
use rand_chacha::rand_core::RngCore;
use rand_chacha::rand_core::SeedableRng;
use crate::*;
use core::sync::atomic::{AtomicU64, Ordering};
use std::collections::{BTreeSet, HashSet};
use std::io::Result;
use rand_chacha::rand_core::RngCore;
use rand_chacha::rand_core::SeedableRng;
use rand_chacha::ChaCha8Rng;
use crate::*;
const UPPER_BOUND: usize = 9000;
const LOWER_BOUND: usize = 12; // needs to be big enough to compute murmur3 hash + hold checksum
static RNG_LOCAL_STATE: AtomicU64 = AtomicU64::new(3);
fn gen_key(dictname: &str, keynum: usize, lower_size_bound: usize, upper_size_bound: usize) -> (String, Vec::<u8>) {
let mut rng = ChaCha8Rng::seed_from_u64(RNG_LOCAL_STATE.load(Ordering::SeqCst) + xous::TESTING_RNG_SEED.load(core::sync::atomic::Ordering::SeqCst));
fn gen_key(
dictname: &str,
keynum: usize,
lower_size_bound: usize,
upper_size_bound: usize,
) -> (String, Vec<u8>) {
let mut rng = ChaCha8Rng::seed_from_u64(
RNG_LOCAL_STATE.load(Ordering::SeqCst)
+ xous::TESTING_RNG_SEED.load(core::sync::atomic::Ordering::SeqCst),
);
// we want roughly half our keys to be in the small bin, and half in the large bin
let keylen = if rng.next_u32() < (u32::MAX / 2) {
((rng.next_u64() as usize) % (VPAGE_SIZE - lower_size_bound)) + lower_size_bound
@ -25,12 +35,13 @@ fn gen_key(dictname: &str, keynum: usize, lower_size_bound: usize, upper_size_bo
// but it helps the test checking program check things.
let keyname = format!("sanitycheck|{}|key{}|len{}", dictname, keynum, keylen);
let mut keydata = Vec::<u8>::new();
for i in 0..keylen-4 {
for i in 0..keylen - 4 {
// the data starts with a number equal to the key number, and increments from there
keydata.push((keynum + i) as u8);
}
// a checksum is appended to each run of data
// copy the stored data, and pad it out to a multiple of word lengths with 0's so we can compute the checksum
// copy the stored data, and pad it out to a multiple of word lengths with 0's so we can compute the
// checksum
let mut checkdata = Vec::<u8>::new();
for &b in &keydata {
checkdata.push(b);
@ -44,14 +55,17 @@ fn gen_key(dictname: &str, keynum: usize, lower_size_bound: usize, upper_size_bo
(keyname, keydata)
}
pub(crate) fn create_basis_testcase(hw: &mut PddbOs, basis_cache: &mut BasisCache,
maybe_num_dicts: Option<usize>, maybe_num_keys: Option<usize>, maybe_key_sizes: Option<(usize, usize)>,
pub(crate) fn create_basis_testcase(
hw: &mut PddbOs,
basis_cache: &mut BasisCache,
maybe_num_dicts: Option<usize>,
maybe_num_keys: Option<usize>,
maybe_key_sizes: Option<(usize, usize)>,
maybe_extra_reserved: Option<usize>,
) -> Result<()> {
hw.pddb_format(false, None).unwrap();
let sys_basis = hw.pddb_mount().expect("couldn't mount system basis");
basis_cache.basis_add(sys_basis);
basis_cache.basis_add(sys_basis);
let num_dicts = maybe_num_dicts.unwrap_or(4);
let num_keys = maybe_num_keys.unwrap_or(34);
@ -72,14 +86,20 @@ pub(crate) fn create_basis_testcase(hw: &mut PddbOs, basis_cache: &mut BasisCach
let (keyname, keydata) = gen_key(&dictname, keynum, key_lower_bound, key_upper_bound);
// now we're ready to write it out
if maybe_extra_reserved.is_none() {
// we do this slightly funky way instead of just passing Some(0) because we want to test the "None" path explicitly
basis_cache.key_update(hw, &dictname, &keyname, &keydata, None,
None,
None, false)?;
// we do this slightly funky way instead of just passing Some(0) because we want to test the
// "None" path explicitly
basis_cache.key_update(hw, &dictname, &keyname, &keydata, None, None, None, false)?;
} else {
basis_cache.key_update(hw, &dictname, &keyname, &keydata, None,
basis_cache.key_update(
hw,
&dictname,
&keyname,
&keydata,
None,
Some(keydata.len() + extra_reserved),
None, false)?;
None,
false,
)?;
}
}
}
@ -87,9 +107,14 @@ pub(crate) fn create_basis_testcase(hw: &mut PddbOs, basis_cache: &mut BasisCach
}
/// Delete & add dictionary consistency check
pub(crate) fn delete_add_dict_consistency(hw: &mut PddbOs, basis_cache: &mut BasisCache,
maybe_num_dicts: Option<usize>, maybe_num_keys: Option<usize>, maybe_key_sizes: Option<(usize, usize)>,
maybe_extra_reserved: Option<usize>, basis_name: Option<&str>
pub(crate) fn delete_add_dict_consistency(
hw: &mut PddbOs,
basis_cache: &mut BasisCache,
maybe_num_dicts: Option<usize>,
maybe_num_keys: Option<usize>,
maybe_key_sizes: Option<(usize, usize)>,
maybe_extra_reserved: Option<usize>,
basis_name: Option<&str>,
) -> Result<()> {
let evict_count = maybe_num_dicts.unwrap_or(1);
let num_keys = maybe_num_keys.unwrap_or(36);
@ -113,7 +138,7 @@ pub(crate) fn delete_add_dict_consistency(hw: &mut PddbOs, basis_cache: &mut Bas
if evicted < evict_count {
log::debug!("evicting dict {}", evict_dict);
match basis_cache.dict_remove(hw, evict_dict, basis_name, false) {
Ok(_) => {},
Ok(_) => {}
Err(e) => log::error!("Error evicting dictionary {}: {:?}", evict_dict, e),
}
} else {
@ -128,14 +153,20 @@ pub(crate) fn delete_add_dict_consistency(hw: &mut PddbOs, basis_cache: &mut Bas
log::debug!("adding {}:{}", dictname, keyname);
// now we're ready to write it out
if maybe_extra_reserved.is_none() {
// we do this slightly funky way instead of just passing Some(0) because we want to test the "None" path explicitly
basis_cache.key_update(hw, &dictname, &keyname, &keydata, None,
None,
basis_name, false)?;
// we do this slightly funky way instead of just passing Some(0) because we want to test the
// "None" path explicitly
basis_cache.key_update(hw, &dictname, &keyname, &keydata, None, None, basis_name, false)?;
} else {
basis_cache.key_update(hw, &dictname, &keyname, &keydata, None,
basis_cache.key_update(
hw,
&dictname,
&keyname,
&keydata,
None,
Some(keydata.len() + extra_reserved),
basis_name, false)?;
basis_name,
false,
)?;
}
}
}
@ -143,9 +174,13 @@ pub(crate) fn delete_add_dict_consistency(hw: &mut PddbOs, basis_cache: &mut Bas
}
/// patch data check
pub(crate) fn patch_test(hw: &mut PddbOs, basis_cache: &mut BasisCache,
maybe_patch_offset: Option<usize>, maybe_patch_data: Option<String>, extend: bool) -> Result<()> {
pub(crate) fn patch_test(
hw: &mut PddbOs,
basis_cache: &mut BasisCache,
maybe_patch_offset: Option<usize>,
maybe_patch_data: Option<String>,
extend: bool,
) -> Result<()> {
let patch_offset = maybe_patch_offset.unwrap_or(5);
let patch_data = maybe_patch_data.unwrap_or("patched!".to_string());
@ -172,15 +207,33 @@ pub(crate) fn patch_test(hw: &mut PddbOs, basis_cache: &mut BasisCache,
let key_list = key_list_unord;
for key in key_list.iter() {
log::debug!("updating {}:{}", dict, key);
// this actually does something a bit more complicated on a multi-basis system than you'd think:
// it will get the union of all key names, and then patch the *latest open basis* only with new data.
// note: if the key didn't already exist in the latest open basis, it's added, with just that patch data in it.
// to override this behavior, you'd want to specify a _specific_ basis, but for testing purposes, we only have one
// so we're doing this way that would lead to surprising results if it were copied as template code elsewhere.
match basis_cache.key_update(hw, dict, key, patch_data.as_bytes(), Some(patch_offset), None, None, false) {
// this actually does something a bit more complicated on a multi-basis system than you'd
// think: it will get the union of all key names, and then patch the *latest
// open basis* only with new data. note: if the key didn't already exist in
// the latest open basis, it's added, with just that patch data in it.
// to override this behavior, you'd want to specify a _specific_ basis, but for testing
// purposes, we only have one so we're doing this way that would lead to
// surprising results if it were copied as template code elsewhere.
match basis_cache.key_update(
hw,
dict,
key,
patch_data.as_bytes(),
Some(patch_offset),
None,
None,
false,
) {
Ok(_) => (),
Err(e) => {
log::error!("couldn't update key {}:{} with {} bytes data offset {}: {:?}", dict, key, patch_data.as_bytes().len(), patch_offset, e);
log::error!(
"couldn't update key {}:{} with {} bytes data offset {}: {:?}",
dict,
key,
patch_data.as_bytes().len(),
patch_offset,
e
);
panic!("error updating patch key");
}
}
@ -192,7 +245,7 @@ pub(crate) fn patch_test(hw: &mut PddbOs, basis_cache: &mut BasisCache,
if !extend {
// now re-compute the checksum
let mut checkdata = Vec::<u8>::new();
for &b in &patchbuf[..readlen-4] {
for &b in &patchbuf[..readlen - 4] {
checkdata.push(b);
}
log::trace!("checkdata len: {}", checkdata.len());
@ -200,7 +253,16 @@ pub(crate) fn patch_test(hw: &mut PddbOs, basis_cache: &mut BasisCache,
checkdata.push(0);
}
let checksum = murmur3_32(&checkdata, 0);
basis_cache.key_update(hw, dict, key, &checksum.to_le_bytes(), Some(readlen-4), None, None, false)?;
basis_cache.key_update(
hw,
dict,
key,
&checksum.to_le_bytes(),
Some(readlen - 4),
None,
None,
false,
)?;
} else {
// this gloms a new checksum onto the existing record, adding 4 new bytes.
let mut checkdata = Vec::<u8>::new();
@ -212,7 +274,16 @@ pub(crate) fn patch_test(hw: &mut PddbOs, basis_cache: &mut BasisCache,
checkdata.push(0);
}
let checksum = murmur3_32(&checkdata, 0);
basis_cache.key_update(hw, dict, key, &checksum.to_le_bytes(), Some(readlen), None, None, false)?;
basis_cache.key_update(
hw,
dict,
key,
&checksum.to_le_bytes(),
Some(readlen),
None,
None,
false,
)?;
}
}
}
@ -220,8 +291,12 @@ pub(crate) fn patch_test(hw: &mut PddbOs, basis_cache: &mut BasisCache,
Ok(())
}
pub(crate) fn delete_pattern(hw: &mut PddbOs, basis_cache: &mut BasisCache,
maybe_num_dicts: Option<usize>, maybe_num_keys: Option<usize>, maybe_key_sizes: Option<(usize, usize)>,
pub(crate) fn delete_pattern(
hw: &mut PddbOs,
basis_cache: &mut BasisCache,
maybe_num_dicts: Option<usize>,
maybe_num_keys: Option<usize>,
maybe_key_sizes: Option<(usize, usize)>,
maybe_extra_reserved: Option<usize>,
) -> Result<()> {
let evict_count = maybe_num_dicts.unwrap_or(2);
@ -250,9 +325,10 @@ pub(crate) fn delete_pattern(hw: &mut PddbOs, basis_cache: &mut BasisCache,
key_list.insert(s);
}
for (index, key) in key_list.iter().enumerate() {
if index % 2 == (evict_iter % 2) { // exercise odd/even patterns
if index % 2 == (evict_iter % 2) {
// exercise odd/even patterns
log::info!("deleting {}:{}", evict_dict, key);
basis_cache.key_remove(hw, evict_dict, key,None, false).unwrap();
basis_cache.key_remove(hw, evict_dict, key, None, false).unwrap();
let da = basis_cache.dict_attributes(hw, evict_dict, None).unwrap();
log::info!("{:?}", da);
}
@ -288,18 +364,23 @@ pub(crate) fn delete_pattern(hw: &mut PddbOs, basis_cache: &mut BasisCache,
log::warn!("rng collision on keygen: {}, deleting key", keyname);
basis_cache.key_remove(hw, dictname, &keyname, None, false)?;
}
_ => {
}
_ => {}
}
if maybe_extra_reserved.is_none() {
// we do this slightly funky way instead of just passing Some(0) because we want to test the "None" path explicitly
basis_cache.key_update(hw, dictname, &keyname, &keydata, None,
None,
None, false)?;
// we do this slightly funky way instead of just passing Some(0) because we want to test the
// "None" path explicitly
basis_cache.key_update(hw, dictname, &keyname, &keydata, None, None, None, false)?;
} else {
basis_cache.key_update(hw, dictname, &keyname, &keydata, None,
basis_cache.key_update(
hw,
dictname,
&keyname,
&keydata,
None,
Some(keydata.len() + extra_reserved),
None, false)?;
None,
false,
)?;
}
}
}
@ -360,7 +441,11 @@ pub(crate) fn list_all(hw: &mut PddbOs, basis_cache: &mut BasisCache) {
let da = match basis_cache.dict_attributes(hw, &dict, None) {
Ok(da) => da,
Err(e) => {
log::warn!("dictionary {} not in sub-basis (this is normal for multi-basis systems, {:?}", dict, e);
log::warn!(
"dictionary {} not in sub-basis (this is normal for multi-basis systems, {:?}",
dict,
e
);
continue;
}
};
@ -370,7 +455,10 @@ pub(crate) fn list_all(hw: &mut PddbOs, basis_cache: &mut BasisCache) {
for key in key_list.iter() {
let attrs = match basis_cache.key_attributes(hw, dict, key, None) {
Ok(a) => a,
Err(e) => {log::debug!("key not in basis, searching another basis, {:?}", e); continue},
Err(e) => {
log::debug!("key not in basis, searching another basis, {:?}", e);
continue;
}
};
log::debug!("{}:{}=>{:?}", dict, key, attrs);
sanity_count += 1;
@ -398,14 +486,16 @@ pub(crate) fn ci_tests(pddb_os: &mut PddbOs) -> Result<()> {
const EXTRA_BASIS_PW: &'static str = "some password blah blah";
log::set_max_level(log::LevelFilter::Info);
log::info!("Seed for this run: {}", xous::TESTING_RNG_SEED.load(core::sync::atomic::Ordering::SeqCst));
log::info!(
"Seed for this run: {}",
xous::TESTING_RNG_SEED.load(core::sync::atomic::Ordering::SeqCst)
);
pddb_os.test_reset();
log::info!("Creating `basecase1e`");
log::set_max_level(log::LevelFilter::Info);
let mut basis_cache = BasisCache::new();
create_basis_testcase(pddb_os, &mut basis_cache, None,
None, None, Some(32))?;
create_basis_testcase(pddb_os, &mut basis_cache, None, None, None, Some(32))?;
log::info!("Saving `basecase1e` to local host");
pddb_os.dbg_dump(Some("basecase1e".to_string()), None);
let extra_basis_key = pddb_os.basis_derive_key(EXTRA_BASIS, EXTRA_BASIS_PW);
@ -413,23 +503,18 @@ pub(crate) fn ci_tests(pddb_os: &mut PddbOs) -> Result<()> {
for (&src, dst) in EXTRA_BASIS.as_bytes().iter().zip(name.iter_mut()) {
*dst = src;
}
let extra_export = KeyExport {
basis_name: name,
key: extra_basis_key.data,
pt_key: extra_basis_key.pt,
};
let mut export: Vec::<KeyExport> = Vec::new();
let extra_export =
KeyExport { basis_name: name, key: extra_basis_key.data, pt_key: extra_basis_key.pt };
let mut export: Vec<KeyExport> = Vec::new();
export.push(extra_export);
log::info!("Building a second basis");
basis_cache.basis_create(pddb_os,
EXTRA_BASIS, EXTRA_BASIS_PW).expect("couldn't build test basis");
basis_cache.basis_create(pddb_os, EXTRA_BASIS, EXTRA_BASIS_PW).expect("couldn't build test basis");
log::info!("heap usage: {}", heap_usage());
test_prune(pddb_os, &mut basis_cache);
log::info!("Doing delete/add consistency with data extension");
delete_add_dict_consistency(pddb_os, &mut basis_cache, None,
None, None, None, None)?;
delete_add_dict_consistency(pddb_os, &mut basis_cache, None, None, None, None, None)?;
test_prune(pddb_os, &mut basis_cache);
log::info!("Saving `dachecke` to local host");
pddb_os.dbg_dump(Some("dachecke".to_string()), None);
@ -454,22 +539,19 @@ pub(crate) fn ci_tests(pddb_os: &mut PddbOs) -> Result<()> {
pddb_os.dbg_dump(Some("patterne2".to_string()), None);
log::info!("Doing delete/add consistency with data extension 2");
delete_add_dict_consistency(pddb_os, &mut basis_cache, Some(3),
Some(50), None, None, None)?;
delete_add_dict_consistency(pddb_os, &mut basis_cache, Some(3), Some(50), None, None, None)?;
log::info!("Saving `dachecke2` to local host");
pddb_os.dbg_dump(Some("dachecke2".to_string()), None);
test_prune(pddb_os, &mut basis_cache);
log::info!("Doing delete/add consistency with data extension 3");
delete_add_dict_consistency(pddb_os, &mut basis_cache, Some(3),
Some(50), None, None, None)?;
delete_add_dict_consistency(pddb_os, &mut basis_cache, Some(3), Some(50), None, None, None)?;
log::info!("Saving `dachecke3` to local host");
pddb_os.dbg_dump(Some("dachecke3".to_string()), None);
test_prune(pddb_os, &mut basis_cache);
log::info!("Doing delete/add consistency with data extension 4");
delete_add_dict_consistency(pddb_os, &mut basis_cache, Some(6),
Some(50), None, None, None)?;
delete_add_dict_consistency(pddb_os, &mut basis_cache, Some(6), Some(50), None, None, None)?;
log::info!("Saving `dachecke4` to local host");
pddb_os.dbg_dump(Some("dachecke4".to_string()), None);
test_prune(pddb_os, &mut basis_cache);
@ -491,14 +573,22 @@ pub(crate) fn ci_tests(pddb_os: &mut PddbOs) -> Result<()> {
}
log::info!("Mounting the second basis");
if let Some(basis2) = basis_cache.basis_unlock(pddb_os,
EXTRA_BASIS, EXTRA_BASIS_PW, BasisRetentionPolicy::Persist) {
if let Some(basis2) =
basis_cache.basis_unlock(pddb_os, EXTRA_BASIS, EXTRA_BASIS_PW, BasisRetentionPolicy::Persist)
{
basis_cache.basis_add(basis2);
}
log::set_max_level(log::LevelFilter::Info);
log::info!("Adding keys to Basis2");
delete_add_dict_consistency(pddb_os, &mut basis_cache, Some(3),
Some(15), None, None, Some(EXTRA_BASIS))?;
delete_add_dict_consistency(
pddb_os,
&mut basis_cache,
Some(3),
Some(15),
None,
None,
Some(EXTRA_BASIS),
)?;
log::info!("Saving `basis2` to local host");
test_prune(pddb_os, &mut basis_cache);
pddb_os.dbg_dump(Some("basis2".to_string()), Some(&export));
@ -543,11 +633,15 @@ pub(crate) fn ci_tests(pddb_os: &mut PddbOs) -> Result<()> {
remount_list.insert(key.to_string());
}
}
assert!(remount_list.difference(&pre_list).count() == 0, "remounted list is not identical to the original list");
assert!(
remount_list.difference(&pre_list).count() == 0,
"remounted list is not identical to the original list"
);
log::info!("Mounting the second basis again");
if let Some(basis2) = basis_cache.basis_unlock(pddb_os,
EXTRA_BASIS, EXTRA_BASIS_PW, BasisRetentionPolicy::Persist) {
if let Some(basis2) =
basis_cache.basis_unlock(pddb_os, EXTRA_BASIS, EXTRA_BASIS_PW, BasisRetentionPolicy::Persist)
{
basis_cache.basis_add(basis2);
}
let mut merge2_list = HashSet::<String>::new();
@ -557,7 +651,10 @@ pub(crate) fn ci_tests(pddb_os: &mut PddbOs) -> Result<()> {
merge2_list.insert(key.to_string());
}
}
assert!(merge2_list.difference(&merge_list).count() == 0, "merged list is different from the original list after remount");
assert!(
merge2_list.difference(&merge_list).count() == 0,
"merged list is different from the original list after remount"
);
list_all(pddb_os, &mut basis_cache);
log::info!("CI done");
@ -567,11 +664,11 @@ pub(crate) fn ci_tests(pddb_os: &mut PddbOs) -> Result<()> {
}
fn test_prune(hw: &mut PddbOs, basis_cache: &mut BasisCache) {
const TARGET_SIZE: usize = 150*1024;
const TARGET_SIZE: usize = 150 * 1024;
let cache_size = basis_cache.cache_size();
if cache_size > TARGET_SIZE {
log::info!("size is {}, requesting prune of {}", cache_size, cache_size - TARGET_SIZE);
log::info!("pruned {}", basis_cache.cache_prune(hw, cache_size - TARGET_SIZE));
}
log::info!("size is now {}", basis_cache.cache_size());
}
}

View file

@ -1,13 +1,10 @@
use xous::{SID, CID};
use gam::modal::*;
use locales::t;
use num_traits::*;
use xous::msg_scalar_unpack;
use xous::{CID, SID};
use xous_ipc::Buffer;
use num_traits::*;
use gam::modal::*;
use locales::t;
use crate::BasisRequestPassword;
/*
Conclusions:
@ -59,8 +56,8 @@ pub(crate) fn password_ux_manager(
// the CID of the main loop, as a backchannel for async callbacks.
_main_cid: CID,
// the SID we're to use for our loop handler, for getting requests
ux_sid: SID) {
ux_sid: SID,
) {
let ux_cid = xous::connect(ux_sid).unwrap();
// create a thread that just handles the redrawing requests
// build the core data structure here
@ -74,16 +71,17 @@ pub(crate) fn password_ux_manager(
);
password_action.reset_action_payloads(1, None);
let mut pddb_modal =
Modal::new(
gam::PDDB_MODAL_NAME,
ActionType::TextEntry(password_action.clone()),
Some(t!("pddb.password", locales::LANG)),
None,
gam::SYSTEM_STYLE,
8
);
pddb_modal.spawn_helper(ux_sid, pddb_modal.sid,
let mut pddb_modal = Modal::new(
gam::PDDB_MODAL_NAME,
ActionType::TextEntry(password_action.clone()),
Some(t!("pddb.password", locales::LANG)),
None,
gam::SYSTEM_STYLE,
8,
);
pddb_modal.spawn_helper(
ux_sid,
pddb_modal.sid,
PwManagerOpcode::ModalRedraw.to_u32().unwrap(),
PwManagerOpcode::ModalKeypress.to_u32().unwrap(),
PwManagerOpcode::ModalDrop.to_u32().unwrap(),
@ -104,20 +102,32 @@ pub(crate) fn password_ux_manager(
};
pddb_modal.modify(
Some(ActionType::TextEntry(password_action.clone())),
Some(t!("pddb.password", locales::LANG)), false,
Some(format!("{}'{}'", t!("pddb.password_for", locales::LANG), db_name.as_str().unwrap()).as_str()), false, None
Some(t!("pddb.password", locales::LANG)),
false,
Some(
format!("{}'{}'", t!("pddb.password_for", locales::LANG), db_name.as_str().unwrap())
.as_str(),
),
false,
None,
);
log::info!(
"{}PDDB.REQPW,{},{}",
xous::BOOKEND_START,
db_name.as_str().unwrap(),
xous::BOOKEND_END
);
log::info!("{}PDDB.REQPW,{},{}", xous::BOOKEND_START, db_name.as_str().unwrap(), xous::BOOKEND_END);
pddb_modal.activate();
dr = Some(msg);
},
}
Some(PwManagerOpcode::PwReturn) => {
let mut buf = unsafe { Buffer::from_memory_message(msg.body.memory_message().unwrap()) };
let pw = buf.to_original::<gam::modal::TextEntryPayloads, _>().unwrap();
if let Some(mut response) = dr.take() {
let mut buffer = unsafe { Buffer::from_memory_message_mut(response.body.memory_message_mut().unwrap()) };
let mut buffer = unsafe {
Buffer::from_memory_message_mut(response.body.memory_message_mut().unwrap())
};
let mut request = buffer.to_original::<BasisRequestPassword, _>().unwrap();
request.plaintext_pw = Some(xous_ipc::String::from_str(pw.first().as_str()));
// return the password to the caller
@ -129,10 +139,10 @@ pub(crate) fn password_ux_manager(
pw.first().volatile_clear(); // ensure the data is destroyed after sending to the keys enclave
buf.volatile_clear();
},
}
Some(PwManagerOpcode::ModalRedraw) => {
pddb_modal.redraw();
},
}
Some(PwManagerOpcode::ModalKeypress) => msg_scalar_unpack!(msg, k1, k2, k3, k4, {
let keys = [
core::char::from_u32(k1 as u32).unwrap_or('\u{0000}'),
@ -142,14 +152,15 @@ pub(crate) fn password_ux_manager(
];
pddb_modal.key_event(keys);
}),
Some(PwManagerOpcode::ModalDrop) => { // this guy should never quit, it's a core OS service
Some(PwManagerOpcode::ModalDrop) => {
// this guy should never quit, it's a core OS service
panic!("Password modal for PDDB quit unexpectedly");
},
}
Some(PwManagerOpcode::Quit) => {
log::warn!("received quit on PDDB password UX renderer loop");
xous::return_scalar(msg.sender, 0).unwrap();
break;
},
}
None => {
log::error!("couldn't convert opcode");