use std::assert_eq;
use littlefs2_core::path;
use trussed_core::{
syscall, try_syscall,
types::{Bytes, Location, Mechanism, PathBuf, StorageAttributes},
CryptoClient, Error, FilesystemClient,
};
mod client;
#[test]
fn escape_namespace_parent() {
client::get(|client| {
let key = syscall!(client.generate_key(Mechanism::P256, StorageAttributes::new())).key;
let mut path = PathBuf::from(path!(".."));
path.push(path!("sec"));
path.push(&key.legacy_hex_path());
assert_eq!(
try_syscall!(client.read_file(Location::Volatile, path)),
Err(Error::InvalidPath),
);
let mut path = PathBuf::from(path!("foobar/../.."));
path.push(path!("sec"));
path.push(&key.legacy_hex_path());
assert_eq!(
try_syscall!(client.read_file(Location::Volatile, path)),
Err(Error::InvalidPath),
);
let mut path = PathBuf::from(path!("foobar/.."));
path.push(path!("sec"));
path.push(&key.legacy_hex_path());
assert_eq!(
try_syscall!(client.read_file(Location::Volatile, path)),
Err(Error::InvalidPath),
);
})
}
#[test]
fn escape_namespace_root() {
client::get(|client| {
let key = syscall!(client.generate_key(Mechanism::P256, StorageAttributes::new())).key;
let mut path = PathBuf::from(path!("/test"));
path.push(path!("sec"));
path.push(&key.legacy_hex_path());
assert!(try_syscall!(client.read_file(Location::Volatile, path)).is_err());
})
}
#[test]
fn escape_namespace_root_only() {
client::get(|client| {
let key = syscall!(client.generate_key(Mechanism::P256, StorageAttributes::new())).key;
let mut path = PathBuf::from(path!("/"));
path.push(path!("sec"));
path.push(&key.legacy_hex_path());
assert!(try_syscall!(client.read_file(Location::Volatile, path)).is_err());
})
}
fn iterating(location: Location) {
client::get(|client| {
syscall!(client.write_file(
location,
PathBuf::from(path!("foo")),
Bytes::from(b"foo"),
None
));
syscall!(client.write_file(
location,
PathBuf::from(path!("bar")),
Bytes::from(b"bar"),
None
));
let first_entry = syscall!(client.read_dir_first(location, PathBuf::new(), None))
.entry
.unwrap();
assert_eq!(first_entry.file_name(), "bar");
let next_entry = syscall!(client.read_dir_next()).entry.unwrap();
assert_eq!(next_entry.file_name(), "foo");
let first_data = syscall!(client.read_dir_files_first(location, PathBuf::new(), None))
.data
.unwrap();
assert_eq!(first_data, b"bar");
let next_data = syscall!(client.read_dir_files_next()).data.unwrap();
assert_eq!(next_data, b"foo");
});
}
fn iterating_first(location: Location) {
use littlefs2_core::path;
client::get(|client| {
let files = [
path!("foo"),
path!("bar"),
path!("baz"),
path!("foobar"),
path!("foobaz"),
];
let files_sorted_lfs = {
let mut files = files;
files.sort_by(|a, b| a.cmp_lfs(b));
files
};
assert_eq!(
files_sorted_lfs,
[
path!("bar"),
path!("baz"),
path!("foobar"),
path!("foobaz"),
path!("foo"),
]
);
let files_sorted_str = {
let mut files = files;
files.sort_by(|a, b| a.cmp_str(b));
files
};
assert_eq!(
files_sorted_str,
[
path!("bar"),
path!("baz"),
path!("foo"),
path!("foobar"),
path!("foobaz"),
]
);
for f in files {
syscall!(client.write_file(
location,
PathBuf::from(f),
Bytes::try_from(f.as_ref().as_bytes()).unwrap(),
None
));
}
let first_entry =
syscall!(client.read_dir_first_alphabetical(location, PathBuf::from(path!("")), None))
.entry
.unwrap();
assert_eq!(first_entry.path(), files_sorted_lfs[0]);
for f in &files_sorted_lfs[1..] {
let entry = syscall!(client.read_dir_next()).entry.unwrap();
assert_eq!(&entry.path(), f);
}
assert!(syscall!(client.read_dir_next()).entry.is_none());
let first_entry = syscall!(client.read_dir_first_alphabetical(
location,
PathBuf::from(path!("")),
Some(PathBuf::from(path!("fo")))
))
.entry
.unwrap();
assert_eq!(first_entry.path(), path!("foobar"));
for f in &(files_sorted_lfs[3..]) {
let entry = syscall!(client.read_dir_next()).entry.unwrap();
assert_eq!(&entry.path(), f);
}
assert!(syscall!(client.read_dir_next()).entry.is_none());
});
}
fn iterating_files_and_dirs(location: Location) {
use littlefs2_core::path;
client::get(|client| {
let files = [
path!("foo"),
path!("bar"),
path!("baz"),
path!("foobar"),
path!("foobaz"),
];
for f in files {
syscall!(client.write_file(
location,
PathBuf::from(f),
Bytes::try_from(f.as_ref().as_bytes()).unwrap(),
None
));
}
let directories = [
path!("dir"),
path!("foodir"),
path!("bardir"),
path!("bazdir"),
path!("foobardir"),
path!("foobazdir"),
];
for d in directories {
let mut file_path = PathBuf::from(d);
file_path.push(path!("file"));
syscall!(client.write_file(
location,
file_path.clone(),
Bytes::try_from(file_path.as_ref().as_bytes()).unwrap(),
None
));
}
let all_entries: Vec<_> = files.into_iter().chain(directories).collect();
let all_entries_sorted_str = {
let mut all_entries = all_entries.clone();
all_entries.sort_by(|a, b| a.cmp_str(b));
all_entries
};
assert_eq!(
all_entries_sorted_str,
[
path!("bar"),
path!("bardir"),
path!("baz"),
path!("bazdir"),
path!("dir"),
path!("foo"),
path!("foobar"),
path!("foobardir"),
path!("foobaz"),
path!("foobazdir"),
path!("foodir"),
]
);
let all_entries_sorted_lfs = {
let mut all_entries = all_entries.clone();
all_entries.sort_by(|a, b| a.cmp_lfs(b));
all_entries
};
assert_eq!(
all_entries_sorted_lfs,
[
path!("bardir"),
path!("bar"),
path!("bazdir"),
path!("baz"),
path!("dir"),
path!("foobardir"),
path!("foobar"),
path!("foobazdir"),
path!("foobaz"),
path!("foodir"),
path!("foo"),
]
);
let first_entry =
syscall!(client.read_dir_first_alphabetical(location, PathBuf::from(path!("")), None))
.entry
.unwrap();
assert_eq!(first_entry.path(), all_entries_sorted_lfs[0]);
for f in &all_entries_sorted_lfs[1..] {
let entry = syscall!(client.read_dir_next()).entry.unwrap();
assert_eq!(&entry.path(), f);
}
assert!(syscall!(client.read_dir_next()).entry.is_none());
let first_entry = syscall!(client.read_dir_first_alphabetical(
location,
PathBuf::from(path!("")),
Some(PathBuf::from(path!("dir")))
))
.entry
.unwrap();
assert_eq!(first_entry.path(), all_entries_sorted_lfs[4]);
for f in &all_entries_sorted_lfs[5..] {
let entry = syscall!(client.read_dir_next()).entry.unwrap();
assert_eq!(&entry.path(), f);
}
assert!(syscall!(client.read_dir_next()).entry.is_none());
});
}
#[test]
fn iterating_internal() {
iterating(Location::Internal);
iterating_first(Location::Internal);
iterating_files_and_dirs(Location::Internal);
}
#[test]
fn iterating_external() {
iterating(Location::External);
iterating_first(Location::External);
iterating_files_and_dirs(Location::External);
}
#[test]
fn iterating_volatile() {
iterating(Location::Volatile);
iterating_first(Location::Volatile);
iterating_files_and_dirs(Location::Volatile);
}