blob: 23d46276045087732e1037f0cc3e0bfc1792ff52 [file] [log] [blame]
use android_hardware_security_see_storage::aidl::android::hardware::security::see::storage::{
CreationMode::CreationMode, FileMode::FileMode, ISecureStorage as SecureStorage,
IStorageSession::IStorageSession, OpenOptions::OpenOptions, ReadIntegrity::ReadIntegrity,
};
use binder::ExceptionCode;
use test::{assert_ok, expect, fail};
mod helpers;
use helpers::{ensure_deleted, Exists};
const CREATE_EXCLUSIVE: &'static OpenOptions = &OpenOptions {
createMode: CreationMode::CREATE_EXCLUSIVE,
accessMode: FileMode::READ_WRITE,
readIntegrity: ReadIntegrity::NO_TAMPER,
truncateOnOpen: true,
allowWritesDuringAbUpdate: false,
};
const NO_CREATE: &'static OpenOptions = &OpenOptions {
createMode: CreationMode::NO_CREATE,
accessMode: FileMode::READ_WRITE,
readIntegrity: ReadIntegrity::NO_TAMPER,
truncateOnOpen: false,
allowWritesDuringAbUpdate: false,
};
pub(crate) fn create_delete(ss: &(impl IStorageSession + ?Sized)) {
let fname = "test_create_delete_file";
assert_ok!(ensure_deleted(ss, fname, Exists::Unknown));
{
// Create file
let _file = assert_ok!(ss.openFile(fname, CREATE_EXCLUSIVE));
assert_ok!(ss.commitChanges());
// Try to create file again
match ss.openFile(fname, CREATE_EXCLUSIVE) {
Ok(_) => fail!("openFile (on existing file) unexpectedly succeeded"),
Err(e)
if e.exception_code() == ExceptionCode::SERVICE_SPECIFIC
&& e.service_specific_error() == SecureStorage::ERR_ALREADY_EXISTS =>
{
()
}
Err(e) => fail!("openFile (on existing file) failed with: {}", e),
};
assert_ok!(ss.commitChanges());
// File closes
}
assert_ok!(ensure_deleted(ss, fname, Exists::Must));
}
pub(crate) fn create_move_delete(ss: &(impl IStorageSession + ?Sized)) {
let fname1 = "test_create_move_delete_1_file";
let fname2 = "test_create_move_delete_2_file";
assert_ok!(ensure_deleted(ss, fname1, Exists::Unknown));
assert_ok!(ensure_deleted(ss, fname2, Exists::Unknown));
{
// Create file
let file = assert_ok!(ss.openFile(fname1, CREATE_EXCLUSIVE));
assert_ok!(ss.commitChanges());
// Move fname1 -> fname2
assert_ok!(file.rename(fname2, CreationMode::CREATE_EXCLUSIVE));
assert_ok!(ss.commitChanges());
// Try to create fname2, with file still alive
match ss.openFile(fname2, CREATE_EXCLUSIVE) {
Ok(_) => fail!("openFile unexpectedly succeeded"),
Err(e)
if e.exception_code() == ExceptionCode::SERVICE_SPECIFIC
&& e.service_specific_error() == SecureStorage::ERR_ALREADY_EXISTS =>
{
()
}
Err(e) => fail!("openFile failed with unexpected error: {}", e),
};
assert_ok!(ss.commitChanges());
// file closes
}
// Try to create fname2, now that file is closed
match ss.openFile(fname2, CREATE_EXCLUSIVE) {
Ok(_) => fail!("openFile unexpectedly succeeded"),
Err(e)
if e.exception_code() == ExceptionCode::SERVICE_SPECIFIC
&& e.service_specific_error() == SecureStorage::ERR_ALREADY_EXISTS =>
{
()
}
Err(e) => fail!("openFile failed with unexpected error: {}", e),
};
assert_ok!(ss.commitChanges());
{
// Recreate fname1
let file = assert_ok!(ss.openFile(fname1, CREATE_EXCLUSIVE));
assert_ok!(ss.commitChanges());
// Move doesn't work now that fname2 exists
match file.rename(fname2, CreationMode::CREATE_EXCLUSIVE) {
Ok(_) => panic!("rename unexpectedly succeeded"),
Err(e)
if e.exception_code() == ExceptionCode::SERVICE_SPECIFIC
&& e.service_specific_error() == SecureStorage::ERR_ALREADY_EXISTS =>
{
()
}
Err(e) => panic!("rename failed with unexpected error: {}", e),
};
// file closes
}
assert_ok!(ensure_deleted(ss, fname1, Exists::Must));
assert_ok!(ensure_deleted(ss, fname2, Exists::Must));
}
pub(crate) fn file_list(ss: &(impl IStorageSession + ?Sized)) {
use core::array::from_fn;
use std::collections::HashSet;
let fnames: [String; 100] = from_fn(|i| format!("test_file_list_{:02}_file", i));
for fname in &fnames {
assert_ok!(ensure_deleted(ss, fname, Exists::Unknown), "file: {}", fname);
}
{
let dir = assert_ok!(ss.openDir("", ReadIntegrity::NO_TAMPER));
let filenames = assert_ok!(dir.readNextFilenames(0));
expect!(filenames.is_empty(), "Found unexpected files: {:?}", filenames);
}
// Create, commit, and close file #0
{
let _file = assert_ok!(ss.openFile(&fnames[0], CREATE_EXCLUSIVE));
assert_ok!(ss.commitChanges());
}
// Create and close (don't commit) other files
for fname in &fnames[1..] {
let _file = assert_ok!(ss.openFile(fname, CREATE_EXCLUSIVE), "for fname {}", fname);
}
let mut read_file_names = HashSet::new();
{
let dir = assert_ok!(ss.openDir("", ReadIntegrity::NO_TAMPER));
let mut filenames = assert_ok!(dir.readNextFilenames(0));
while !filenames.is_empty() {
for filename in filenames {
let existed = read_file_names.replace(filename);
if let Some(previous) = existed {
fail!("NextFilenameResult returned file more than once: {}", previous);
}
}
filenames = assert_ok!(dir.readNextFilenames(0));
}
}
assert_ok!(ss.commitChanges());
// Clean up
for fname in &fnames {
assert_ok!(ensure_deleted(ss, fname, Exists::Must), "file: {}", fname);
}
let expected = fnames.into_iter().collect::<HashSet<_>>();
let missing = expected.difference(&read_file_names).collect::<Vec<_>>();
let extra = read_file_names.difference(&expected).collect::<Vec<_>>();
expect!(missing.is_empty(), "Did not find the following expected files: {:?}", missing);
expect!(extra.is_empty(), "Found the following unexpected files: {:?}", extra);
}
pub(crate) fn write_read_sequential(ss: &(impl IStorageSession + ?Sized)) {
use helpers::{read_pattern, write_pattern};
let fname = "test_write_read_sequential";
let chunks = 32;
let chunk_len = 2048;
assert_ok!(ensure_deleted(ss, fname, Exists::Unknown));
{
let file = assert_ok!(ss.openFile(fname, CREATE_EXCLUSIVE));
assert_ok!(ss.commitChanges());
assert_ok!(write_pattern(&*file, 0, chunks, chunk_len));
assert_ok!(ss.commitChanges());
assert_ok!(read_pattern(&*file, 0, chunks, chunk_len));
} // file closes
{
let file = assert_ok!(ss.openFile(fname, NO_CREATE));
assert_ok!(read_pattern(&*file, 0, chunks, chunk_len));
} // file closes
assert_ok!(ensure_deleted(ss, fname, Exists::Must));
}