This commit is contained in:
zhang-wenzhi821 2024-08-31 18:48:55 +08:00
commit 84e4590192
44 changed files with 1256 additions and 313 deletions

View File

@ -22,6 +22,7 @@ members = [
"services/core_service",
"services/crypto_manager",
"services/db_operator",
"services/db_key_operator",
"test/unittest/inner_api_rust",
"test/unittest/module_test"
]

View File

@ -2,7 +2,8 @@
"jobs" : [{
"name" : "post-fs-data",
"cmds" : [
"mkdir /data/service/el1/public/asset_service 0711 asset_service asset_service"
"mkdir /data/service/el1/public/asset_service 0711 asset_service asset_service",
"start asset_service"
]
}
],

View File

@ -139,8 +139,11 @@ impl_tag_trait! {
/// A tag whose value is a byte array indicating the update time of an Asset.
OperationType = DataType::Number as isize | 0x46,
/// A tag whose value is a bool indicating whether the attributes of an asset are required to be encrypted.
RequireAttrEncrypted = DataType::Bool as isize | 0x47,
/// A tag whose value is a 32-bit unsigned integer indicating the specific user id.
UserId = DataType::Number as isize | 0x47,
UserId = DataType::Number as isize | 0x100,
}
}

View File

@ -66,6 +66,7 @@ const std::vector<uint32_t> ACCESS_CONTROL_TAGS = {
SEC_ASSET_TAG_IS_PERSISTENT,
SEC_ASSET_TAG_SYNC_TYPE,
SEC_ASSET_TAG_REQUIRE_PASSWORD_SET,
SEC_ASSET_TAG_REQUIRE_ATTR_ENCRYPTED,
SEC_ASSET_TAG_USER_ID
};
@ -139,7 +140,8 @@ const std::unordered_map<uint32_t, const char *> TAG_MAP = {
{ SEC_ASSET_TAG_RETURN_ORDERED_BY, "RETURN_ORDERED_BY" },
{ SEC_ASSET_TAG_UPDATE_TIME, "UPDATE_TIME" },
{ SEC_ASSET_TAG_OPERATION_TYPE, "OPERATION_TYPE" },
{ SEC_ASSET_TAG_USER_ID, "USER_ID" }
{ SEC_ASSET_TAG_REQUIRE_ATTR_ENCRYPTED, "REQUIRE_ATTR_ENCRYPTED" },
{ SEC_ASSET_TAG_USER_ID, "USER_ID" },
};
bool CheckAssetRequiredTag(const napi_env env, const std::vector<AssetAttr> &attrs,

View File

@ -72,6 +72,7 @@ napi_value DeclareTag(const napi_env env)
AddUint32Property(env, tag, "RETURN_ORDERED_BY", SEC_ASSET_TAG_RETURN_ORDERED_BY);
AddUint32Property(env, tag, "UPDATE_TIME", SEC_ASSET_TAG_UPDATE_TIME);
AddUint32Property(env, tag, "OPERATION_TYPE", SEC_ASSET_TAG_OPERATION_TYPE);
AddUint32Property(env, tag, "REQUIRE_ATTR_ENCRYPTED", SEC_ASSET_TAG_REQUIRE_ATTR_ENCRYPTED);
return tag;
}

View File

@ -0,0 +1,91 @@
/*
* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//! This file implements ce file operations.
use asset_definition::{log_throw_error, ErrCode, Result};
use std::{fs, path::Path};
use crate::common::{get_user_dbs, DB_KEY, is_file_exist};
fn construct_ce_db_dir(user_id: i32) -> String {
format!("data/service/el2/{}/asset_service", user_id)
}
fn construct_db_key_cipher_path(user_id: i32) -> String {
format!("data/service/el2/{}/asset_service/{}", user_id, DB_KEY)
}
/// Check db key cipher file exists.
pub fn is_db_key_cipher_file_exist(user_id: i32) -> Result<bool> {
let path_str = construct_db_key_cipher_path(user_id);
is_file_exist(&path_str)
}
/// Read db key cipher.
pub fn read_db_key_cipher(user_id: i32) -> Result<Vec<u8>> {
let path_str = construct_db_key_cipher_path(user_id);
let path: &Path = Path::new(&path_str);
match fs::read(path) {
Ok(db_key_cipher) => Ok(db_key_cipher),
Err(e) => {
log_throw_error!(
ErrCode::FileOperationError,
"[FATAL][SA]Read database key ciphertext failed! error is [{}]",
e
)
},
}
}
/// Write db key cipher. If path does not exist, create it automatically.
pub fn write_db_key_cipher(user_id: i32, db_key_cipher: &Vec<u8>) -> Result<()> {
let path_str = construct_db_key_cipher_path(user_id);
let path: &Path = Path::new(&path_str);
match fs::write(path, db_key_cipher) {
Ok(_) => Ok(()),
Err(e) => {
log_throw_error!(
ErrCode::FileOperationError,
"[FATAL][SA]Write database key ciphertext failed! error is [{}]",
e
)
},
}
}
/// Remove all CE file in a specific user space.
pub fn remove_ce_files(user_id: i32) -> Result<()> {
let path_str = construct_ce_db_dir(user_id);
for file in fs::read_dir(path_str)? {
let file = &file?;
match fs::remove_file(file.path().to_string_lossy().to_string()) {
Ok(_) => (),
Err(e) => {
return log_throw_error!(
ErrCode::FileOperationError,
"[FATAL]Remove [{}] failed, error code:[{}]", file.path().to_string_lossy().to_string(),
e
)
}
}
}
Ok(())
}
/// Obtain ce user dbs
pub fn get_ce_user_dbs(user_id: i32) -> Result<Vec<String>> {
get_user_dbs(&construct_ce_db_dir(user_id))
}

View File

@ -0,0 +1,59 @@
/*
* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//! This file implements ce file operations.
use asset_definition::{log_throw_error, Result, ErrCode};
use std::{fs, path::Path};
/// Suffix for backup database files.
pub const BACKUP_SUFFIX: &str = ".backup";
/// Suffix for database files.
pub const DB_SUFFIX: &str = ".db";
/// Name for data base key ciphertext file.
pub const DB_KEY: &str = "db_key";
/// Root path to de user directories.
pub const DE_ROOT_PATH: &str = "data/service/el1/public/asset_service";
/// Root path to ce user directories.
pub const CE_ROOT_PATH: &str = "data/service/el2";
/// Get all db name in user directory.
pub(crate) fn get_user_dbs(path_str: &str) -> Result<Vec<String>> {
let mut dbs = vec![];
for db_path in fs::read_dir(path_str)? {
let db_path = db_path?;
let db_file_name = db_path.file_name().to_string_lossy().to_string();
if db_file_name.ends_with(DB_SUFFIX) {
dbs.push(db_file_name.strip_suffix(DB_SUFFIX).unwrap_or(&db_file_name).to_string())
}
}
Ok(dbs)
}
/// Check whether file exists.
pub fn is_file_exist(path_str: &str) -> Result<bool> {
let path: &Path = Path::new(&path_str);
match path.try_exists() {
Ok(true) => Ok(true),
Ok(false) => Ok(false),
Err(e) => {
log_throw_error!(
ErrCode::FileOperationError,
"[FATAL][SA]]Checking existence of database key ciphertext file failed! error is [{}]",
e
)
},
}
}

View File

@ -0,0 +1,79 @@
/*
* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//! This file implements de file operations.
use asset_definition::{log_throw_error, ErrCode, Result};
use asset_log::logi;
use std::{fs, path::Path};
use crate::common::{get_user_dbs, is_file_exist};
fn construct_user_de_path(user_id: i32) -> String {
format!("data/service/el1/public/asset_service/{}", user_id)
}
fn is_user_de_dir_exist(user_id: i32) -> Result<bool> {
let path_str = construct_user_de_path(user_id);
is_file_exist(&path_str)
}
/// Create user de directory.
pub fn create_user_de_dir(user_id: i32) -> Result<()> {
if is_user_de_dir_exist(user_id)? {
return Ok(());
}
logi!("[INFO]User DE directory does not exist, create it...");
let path_str = construct_user_de_path(user_id);
let path: &Path = Path::new(&path_str);
match fs::create_dir(path) {
Ok(_) => Ok(()),
Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => Ok(()),
Err(e) => {
log_throw_error!(
ErrCode::FileOperationError,
"[FATAL][SA]Create user DE directory failed! error is [{}]",
e
)
},
}
}
/// Delete user de directory.
pub fn delete_user_de_dir(user_id: i32) -> Result<()> {
if !is_user_de_dir_exist(user_id)? {
return Ok(());
}
let path_str = construct_user_de_path(user_id);
let path: &Path = Path::new(&path_str);
match fs::remove_dir_all(path) {
Ok(_) => Ok(()),
Err(e) if e.kind() != std::io::ErrorKind::NotFound => Ok(()),
Err(e) => {
log_throw_error!(
ErrCode::FileOperationError,
"[FATAL][SA]Delete user DE directory failed! error is [{}]",
e
)
},
}
}
/// Obtain de user dbs
pub fn get_de_user_dbs(user_id: i32) -> Result<Vec<String>> {
get_user_dbs(&construct_user_de_path(user_id))
}

View File

@ -13,57 +13,8 @@
* limitations under the License.
*/
//! This file implement the file operations.
//! This file implements file operations.
use std::{fs, path::Path};
use asset_definition::{log_throw_error, ErrCode, Result};
use asset_log::logi;
const ROOT_PATH: &str = "data/service/el1/public/asset_service";
fn construct_user_path(user_id: i32) -> String {
format!("{}/{}", ROOT_PATH, user_id)
}
/// Check user db dir exist.
pub fn is_user_db_dir_exist(user_id: i32) -> bool {
let path_str = construct_user_path(user_id);
let path: &Path = Path::new(&path_str);
path.exists()
}
/// Create user database directory.
pub fn create_user_db_dir(user_id: i32) -> Result<()> {
if is_user_db_dir_exist(user_id) {
return Ok(());
}
logi!("[INFO]Directory is not exist, create it...");
let path_str = construct_user_path(user_id);
let path: &Path = Path::new(&path_str);
match fs::create_dir(path) {
Ok(_) => Ok(()),
Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => Ok(()),
Err(e) => {
log_throw_error!(ErrCode::FileOperationError, "[FATAL][SA]Create dir failed! error is [{}]", e)
},
}
}
/// Delete user database directory.
pub fn delete_user_db_dir(user_id: i32) -> Result<()> {
if !is_user_db_dir_exist(user_id) {
return Ok(());
}
let path_str = construct_user_path(user_id);
let path: &Path = Path::new(&path_str);
match fs::remove_dir_all(path) {
Ok(_) => Ok(()),
Err(e) if e.kind() != std::io::ErrorKind::NotFound => Ok(()),
Err(e) => {
log_throw_error!(ErrCode::FileOperationError, "[FATAL][SA]Delete dir failed! error is [{}]", e)
},
}
}
pub mod ce_operator;
pub mod de_operator;
pub mod common;

View File

@ -175,13 +175,17 @@ typedef enum {
*/
SEC_ASSET_TAG_UPDATE_TIME = SEC_ASSET_TYPE_BYTES | 0x45,
/**
* Tag used to store specific user id. The value is of the uint32 type.
* A tag whose value is the uint32 type indicating the additional action.
*/
SEC_ASSET_TAG_OPERATION_TYPE = SEC_ASSET_TYPE_NUMBER | 0x46,
/**
* A tag whose value is a bool indicating whether the attributes of an asset are required to be encrypted.
*/
SEC_ASSET_TAG_REQUIRE_ATTR_ENCRYPTED = SEC_ASSET_TYPE_BOOL | 0x47,
/**
* Tag used to store specific user id. The value is of the uint32 type.
*/
SEC_ASSET_TAG_USER_ID = SEC_ASSET_TYPE_NUMBER | 0x47,
SEC_ASSET_TAG_USER_ID = SEC_ASSET_TYPE_NUMBER | 0x100,
} AssetTag;
/**

View File

@ -58,10 +58,10 @@ pub const PARAM_NAME_BUNDLE_NAME: &str = "BundleName";
/// param name for user id
pub const PARAM_NAME_USER_ID: &str = "UserId";
/// param name for user id
/// param name for app index
pub const PARAM_NAME_APP_INDEX: &str = "AppIndex";
/// param name for whether is hap
/// param name for owner type
pub const PARAM_NAME_IS_HAP: &str = "IsHap";
/// An enumeration representing different plugin types.
@ -78,36 +78,48 @@ pub trait IAssetPluginCtx: Any + Sync + Send + std::panic::RefUnwindSafe {
/// Initializes the plugin before usage.
fn init(&mut self, user_id: i32) -> Result<(), u32>;
/// Adds an asset to the database.
/// Adds an asset to de db.
fn add(&mut self, attributes: &ExtDbMap) -> Result<i32, u32>;
/// Add an asset with replace.
/// Adds an asset to ce cb.
fn ce_add(&mut self, attributes: &ExtDbMap) -> Result<i32, u32>;
/// Adds an asset with replace to de db.
fn replace(&mut self, condition: &ExtDbMap, attributes: &ExtDbMap) -> std::result::Result<(), u32>;
/// Queries the asset database.
/// Adds an asset with replace to ce db.
fn ce_replace(&mut self, condition: &ExtDbMap, attributes: &ExtDbMap) -> std::result::Result<(), u32>;
/// Queries de db.
fn query(&mut self, attributes: &ExtDbMap) -> Result<Vec<ExtDbMap>, u32>;
/// Removes an asset from the database.
/// Queries ce db.
fn ce_query(&mut self, attributes: &ExtDbMap) -> Result<Vec<ExtDbMap>, u32>;
/// Removes an asset from de db.
fn remove(&mut self, attributes: &ExtDbMap) -> Result<i32, u32>;
/// Removes assets from the database with specific condition.
/// Removes an asset from ce db.
fn ce_remove(&mut self, attributes: &ExtDbMap) -> Result<i32, u32>;
/// Removes assets from de db with specific condition.
fn remove_with_specific_cond(&mut self, specific_cond: &str, condition_value: &[Value]) -> Result<i32, u32>;
/// Updates the attributes of an asset in the database.
/// Removes assets from ce db with specific condition.
fn ce_remove_with_specific_cond(&mut self, specific_cond: &str, condition_value: &[Value]) -> Result<i32, u32>;
/// Updates the attributes of an asset in de db.
fn update(&mut self, attributes: &ExtDbMap, attrs_to_update: &ExtDbMap) -> Result<i32, u32>;
/// Begins a transaction for the asset database.
fn begin_transaction(&mut self) -> Result<(), u32>;
/// Updates the attributes of an asset in ce db.
fn ce_update(&mut self, attributes: &ExtDbMap, attrs_to_update: &ExtDbMap) -> Result<i32, u32>;
/// Commits a transaction for the asset database.
fn commit_transaction(&mut self) -> Result<(), u32>;
/// Rolls back a transaction for the asset database.
fn rollback_transaction(&mut self) -> Result<(), u32>;
/// Returns the storage path for the asset database.
/// Returns the storage path for de db.
fn get_storage_path(&self) -> String;
/// Returns the storage path for ce db.
fn ce_get_storage_path(&self) -> String;
/// Increase count
fn increase_count(&mut self);

View File

@ -34,6 +34,11 @@ impl CallingInfo {
Self::new(0, OwnerType::Native, "asset_service_8100".as_bytes().to_vec())
}
/// Build identity of part process info.
pub fn new_part_info(user_id: i32) -> Self {
Self::new(user_id, OwnerType::Native, "asset_service_8100".as_bytes().to_vec())
}
/// Build identity of the specified owner.
pub fn new(user_id: i32, owner_type: OwnerType, owner_info: Vec<u8>) -> Self {
Self { user_id, owner_type, owner_info }
@ -67,6 +72,11 @@ impl CallingInfo {
self.owner_type as u32
}
/// Get owner type enum of calling.
pub fn owner_type_enum(&self) -> OwnerType {
self.owner_type
}
/// Get owner info of calling.
pub fn owner_info(&self) -> &Vec<u8> {
&self.owner_info

View File

@ -25,6 +25,7 @@ ohos_rust_shared_library("asset_service") {
"../../interfaces/inner_api/rs:asset_sdk_rust",
"../common:asset_common",
"../crypto_manager:asset_crypto_manager",
"../db_key_operator:asset_db_key_operator",
"../db_operator:asset_db_operator",
"../os_dependency:asset_os_dependency",
"../plugin:asset_plugin",

View File

@ -24,10 +24,11 @@ samgr = { git = "https://gitee.com/openharmony/systemabilitymgr_samgr.git" }
system_ability_fwk = { git = "https://gitee.com/openharmony/systemabilitymgr_safwk" }
hisysevent = { git = "https://gitee.com/openharmony/hiviewdfx_hisysevent.git" }
ipc = { git = "https://gitee.com/openharmony/communication_ipc" }
ylong_runtime = { git = "https://gitee.com/openharmony/commonlibrary_rust_ylong_runtime.git", features = ["full"]}
ylong_runtime = { git = "https://gitee.com/openharmony/commonlibrary_rust_ylong_runtime.git", features = ["full"] }
asset_common = { path = "../common" }
asset_crypto_manager = { path = "../crypto_manager" }
asset_db_key_operator = { path = "../db_key_operator" }
asset_db_operator = { path = "../db_operator" }
asset_definition = { path = "../../frameworks/definition" }
asset_file_operator = { path = "../../frameworks/os_dependency/file" }

View File

@ -25,12 +25,13 @@ use std::{
use asset_common::{AutoCounter, CallingInfo, OwnerType};
use asset_crypto_manager::{crypto_manager::CryptoManager, secret_key::SecretKey};
use asset_db_operator::{
database::Database,
types::{column, DbMap},
database::Database, database_file_upgrade::construct_splited_db_name, types::{column, DbMap}
};
use asset_definition::{Result, SyncType, Value};
use asset_file_operator::delete_user_db_dir;
use asset_log::{loge, logi};
use asset_definition::{log_throw_error, ErrCode, Result, SyncType, Value};
use asset_file_operator::{
ce_operator::is_db_key_cipher_file_exist, common::{BACKUP_SUFFIX, CE_ROOT_PATH, DB_SUFFIX, DE_ROOT_PATH}, de_operator::delete_user_de_dir
};
use asset_log::{loge, logi, logw};
use asset_plugin::asset_plugin::AssetPlugin;
use asset_sdk::plugin_interface::{
EventType, ExtDbMap, PARAM_NAME_APP_INDEX, PARAM_NAME_BUNDLE_NAME, PARAM_NAME_IS_HAP, PARAM_NAME_USER_ID,
@ -38,22 +39,79 @@ use asset_sdk::plugin_interface::{
use crate::sys_event::upload_fault_system_event;
const ASSET_DB: &str = "asset.db";
const BACKUP_SUFFIX: &str = ".backup";
const ROOT_PATH: &str = "data/service/el1/public/asset_service";
/// success code.
const SUCCESS: i32 = 0;
const USER_ID_VEC_BUFFER: u32 = 5;
const MINIMUM_MAIN_USER_ID: i32 = 100;
fn delete_on_package_removed(user_id: i32, owner: Vec<u8>) -> Result<bool> {
let mut cond = DbMap::new();
cond.insert(column::OWNER_TYPE, Value::Number(OwnerType::Hap as u32));
cond.insert(column::OWNER, Value::Bytes(owner));
cond.insert(column::IS_PERSISTENT, Value::Bool(false));
fn remove_db(file_path: &str, calling_info: &CallingInfo, is_ce: bool) -> Result<()> {
let db_name = construct_splited_db_name(calling_info.owner_type_enum(), calling_info.owner_info(), is_ce)?;
for db_path in fs::read_dir(file_path)? {
let db_path = db_path?;
let db_file_name = db_path.file_name().to_string_lossy().to_string();
if db_file_name.contains(&db_name) {
match fs::remove_file(&db_path.path().to_string_lossy().to_string()) {
Ok(_) => (),
Err(e) => {
logw!("[WARNING]Remove db:[{}] failed, error code:[{}]", db_file_name, e);
}
}
}
}
Ok(())
}
fn delete_in_de_db_on_package_removed(
calling_info: &CallingInfo,
delete_cond: &DbMap,
reverse_condition: &DbMap,
check_cond: &DbMap
) -> Result<bool> {
// Delete non-persistent data in de db.
let mut de_db = Database::build(calling_info, false)?;
let _ = de_db.delete_datas(delete_cond, Some(reverse_condition), false)?;
let de_db_data_exists = de_db.is_data_exists(check_cond, false)?;
// remove db and backup db
if !de_db_data_exists {
remove_db(&format!("{}/{}", DE_ROOT_PATH,calling_info.user_id()), calling_info, false)?;
}
Ok(de_db_data_exists)
}
fn delete_in_ce_db_on_package_removed(
calling_info: &CallingInfo,
delete_cond: &DbMap,
reverse_condition: &DbMap,
check_cond: &DbMap,
) -> Result<bool> {
// Delete non-persistent data in ce db if ce db file exists.
let mut ce_db = Database::build(calling_info, true)?;
let _ = ce_db.delete_datas(delete_cond, Some(reverse_condition), false)?;
// Check whether there is still persistent data left in ce db.
let ce_db_data_exists = ce_db.is_data_exists(check_cond, false)?;
if !ce_db_data_exists {
remove_db(&format!("{}/{}/asset_service", CE_ROOT_PATH, calling_info.user_id()), calling_info, false)?;
}
Ok(ce_db_data_exists)
}
fn delete_on_package_removed(owner: Vec<u8>, calling_info: &CallingInfo) -> Result<bool> {
let mut delete_cond = DbMap::new();
delete_cond.insert(column::OWNER_TYPE, Value::Number(OwnerType::Hap as u32));
delete_cond.insert(column::OWNER, Value::Bytes(owner.clone()));
delete_cond.insert(column::IS_PERSISTENT, Value::Bool(false));
let mut reverse_condition = DbMap::new();
reverse_condition.insert(column::SYNC_TYPE, Value::Number(SyncType::TrustedAccount as u32));
let mut db = Database::build(user_id)?;
let _ = db.delete_datas(&cond, Some(&reverse_condition), false)?;
let mut check_cond = delete_cond.clone();
check_cond.remove(column::IS_PERSISTENT);
let de_db_data_exists = delete_in_de_db_on_package_removed(calling_info, &delete_cond, &reverse_condition, &check_cond)?;
cond.remove(column::IS_PERSISTENT);
db.is_data_exists(&cond, false)
if is_db_key_cipher_file_exist(calling_info.user_id())? {
let ce_db_data_exists = delete_in_ce_db_on_package_removed(calling_info, &delete_cond, &reverse_condition, &check_cond)?;
Ok(de_db_data_exists || ce_db_data_exists)
} else {
Ok(de_db_data_exists)
}
}
fn clear_cryptos(calling_info: &CallingInfo) {
@ -67,7 +125,7 @@ fn delete_data_by_owner(user_id: i32, owner: *const u8, owner_size: u32) {
let owner: Vec<u8> = unsafe { slice::from_raw_parts(owner, owner_size as usize).to_vec() };
let calling_info = CallingInfo::new(user_id, OwnerType::Hap, owner.clone());
clear_cryptos(&calling_info);
let res = match delete_on_package_removed(user_id, owner) {
let res = match delete_on_package_removed(owner, &calling_info) {
Ok(true) => {
logi!("The owner wants to retain data after uninstallation. Do not delete key in HUKS!");
Ok(())
@ -76,10 +134,9 @@ fn delete_data_by_owner(user_id: i32, owner: *const u8, owner_size: u32) {
Err(e) => {
// Report the database operation fault event.
upload_fault_system_event(&calling_info, start_time, "on_package_removed", &e);
SecretKey::delete_by_owner(&calling_info)
Ok(())
},
};
if let Err(e) = res {
// Report the key operation fault event.
let calling_info = CallingInfo::new_self();
@ -124,7 +181,7 @@ pub(crate) extern "C" fn on_package_removed(
extern "C" fn delete_dir_by_user(user_id: i32) {
let _counter_user = AutoCounter::new();
let _ = delete_user_db_dir(user_id);
let _ = delete_user_de_dir(user_id);
}
extern "C" fn delete_crypto_need_unlock() {
@ -197,24 +254,86 @@ pub(crate) extern "C" fn on_schedule_wakeup() {
}
}
fn backup_db_if_accessible(entry: &DirEntry, user_id: i32) -> Result<()> {
let from_path = entry.path().with_file_name(format!("{}/{}", user_id, ASSET_DB)).to_string_lossy().to_string();
Database::check_db_accessible(from_path.clone(), user_id)?;
let backup_path = format!("{}{}", from_path, BACKUP_SUFFIX);
fs::copy(from_path, backup_path)?;
fn backup_de_db_if_accessible(entry: &DirEntry, user_id: i32) -> Result<()> {
for db_path in fs::read_dir(format!("{}", entry.path().to_string_lossy()))? {
let db_path = db_path?;
let db_name = db_path.file_name().to_string_lossy().to_string();
if db_name.ends_with(DB_SUFFIX) {
let from_path = db_path.path().to_string_lossy().to_string();
Database::check_de_db_accessible(from_path.clone(), user_id, db_name.clone())?;
let backup_path = format!("{}{}", from_path, BACKUP_SUFFIX);
fs::copy(from_path, backup_path)?;
}
}
Ok(())
}
fn backup_ce_db(user_id: i32) -> Result<()> {
if user_id < MINIMUM_MAIN_USER_ID {
return Ok(());
}
let ce_path = format!("{}/{}/asset_service", CE_ROOT_PATH, user_id);
for db_path in fs::read_dir(ce_path)? {
let db_path = db_path?;
let db_name = db_path.file_name().to_string_lossy().to_string();
if db_name.ends_with(DB_SUFFIX) {
let from_path = db_path.path().to_string_lossy().to_string();
let backup_path = format!("{}{}", from_path, BACKUP_SUFFIX);
fs::copy(from_path, backup_path)?;
}
}
Ok(())
}
extern "C" {
fn GetUserIds(userIdsPtr: *mut i32, userIdsSize: *mut u32) -> i32;
fn GetUsersSize(userIdsSize: *mut u32) -> i32;
}
fn backup_all_db(start_time: &Instant) -> Result<()> {
for entry in fs::read_dir(ROOT_PATH)? {
// Backup all de db if accessible.
for entry in fs::read_dir(DE_ROOT_PATH)? {
let entry = entry?;
if let Ok(user_id) = entry.file_name().to_string_lossy().to_string().parse::<i32>() {
if let Err(e) = backup_db_if_accessible(&entry, user_id) {
if let Err(e) = backup_de_db_if_accessible(&entry, user_id) {
let calling_info = CallingInfo::new_self();
upload_fault_system_event(&calling_info, *start_time, &format!("backup_db_{}", user_id), &e);
upload_fault_system_event(&calling_info, *start_time, &format!("backup_de_db_{}", user_id), &e);
}
}
}
// Backup all ce db if db key cipher file exists.
let mut user_ids_size: u32 = 0;
let user_ids_size_ptr = &mut user_ids_size;
let mut ret: i32;
unsafe {
ret = GetUsersSize(user_ids_size_ptr);
}
if ret != SUCCESS {
return log_throw_error!(ErrCode::AccountError, "[FATAL][SA]Get users size failed.");
}
let mut user_ids: Vec<i32> = vec![0i32; (*user_ids_size_ptr + USER_ID_VEC_BUFFER).try_into().unwrap()];
let user_ids_ptr = user_ids.as_mut_ptr();
unsafe {
ret = GetUserIds(user_ids_ptr, user_ids_size_ptr);
}
if ret != SUCCESS {
return log_throw_error!(ErrCode::AccountError, "[FATAL][SA]Get user IDs failed.");
}
let user_ids_slice;
unsafe {
user_ids_slice = slice::from_raw_parts_mut(user_ids_ptr, (*user_ids_size_ptr).try_into().unwrap());
}
for user_id in user_ids_slice.iter() {
if let Err(e) = backup_ce_db(*user_id) {
let calling_info = CallingInfo::new_self();
upload_fault_system_event(&calling_info, *start_time, &format!("backup_ce_db_{}", *user_id), &e);
}
}
Ok(())
}

View File

@ -17,7 +17,7 @@
use std::collections::HashMap;
use asset_file_operator::delete_user_db_dir;
use asset_file_operator::de_operator::delete_user_de_dir;
use asset_log::{loge, logi};
use system_ability_fwk::cxx_share::SystemAbilityOnDemandReason;
@ -82,7 +82,7 @@ pub(crate) fn handle_common_event(reason: SystemAbilityOnDemandReason) {
handle_package_removed(&want, true);
} else if reason_name == "usual.event.USER_REMOVED" {
logi!("on_start by user remove");
let _ = delete_user_db_dir(reason.extra_data.code);
let _ = delete_user_de_dir(reason.extra_data.code);
} else if reason_name == "usual.event.CHARGING" {
listener::backup_db();
} else if reason_name == "COMMON_EVENT_RESTORE_START" {

View File

@ -15,8 +15,9 @@
//! This module implements the Asset service.
use std::time::{Duration, Instant};
use std::{fs, time::{Duration, Instant}};
use asset_db_operator::database_file_upgrade::check_and_split_db;
use samgr::manage::SystemAbilityManager;
use system_ability_fwk::{
ability::{Ability, Handler},
@ -24,9 +25,10 @@ use system_ability_fwk::{
};
use ylong_runtime::{builder::RuntimeBuilder, time::sleep};
use asset_common::{CallingInfo, Counter};
use asset_common::{AutoCounter, CallingInfo, Counter, OwnerType};
use asset_crypto_manager::crypto_manager::CryptoManager;
use asset_definition::{log_throw_error, AssetMap, ErrCode, Result};
use asset_file_operator::{common::DE_ROOT_PATH, de_operator::create_user_de_dir};
use asset_ipc::SA_ID;
use asset_log::{loge, logi};
use asset_plugin::asset_plugin::{AssetContext, AssetPlugin};
@ -102,11 +104,22 @@ impl Ability for AssetAbility {
}
}
async fn upgrade_process() -> Result<()> {
let _counter_user = AutoCounter::new();
for entry in fs::read_dir(DE_ROOT_PATH)? {
let entry = entry?;
if let Ok(user_id) = entry.file_name().to_string_lossy().parse::<i32>() {
check_and_split_db(user_id)?;
}
}
Ok(())
}
fn start_service(handler: Handler) -> Result<()> {
let asset_plugin = AssetPlugin::get_instance();
match asset_plugin.load_plugin() {
Ok(loader) => {
let _tr = loader.init(Box::new(AssetContext { data_base: None }));
let _tr = loader.init(Box::new(AssetContext { user_id: 0, calling_info: CallingInfo::new(0, OwnerType::Hap, vec![]) }));
logi!("load plugin success.");
},
Err(_) => loge!("load plugin failed."),
@ -116,6 +129,7 @@ fn start_service(handler: Handler) -> Result<()> {
if !handler.publish(AssetService::new(handler.clone())) {
return log_throw_error!(ErrCode::IpcError, "Asset publish stub object failed");
};
let _handle = ylong_runtime::spawn(upgrade_process());
Ok(())
}
@ -142,8 +156,8 @@ macro_rules! execute {
let func_name = hisysevent::function!();
let start = Instant::now();
let _trace = TraceScope::trace(func_name);
// Create database directory if not exists.
asset_file_operator::create_user_db_dir($calling_info.user_id())?;
// Create de database directory if not exists.
create_user_de_dir($calling_info.user_id())?;
upload_system_event($func($calling_info, $($args),+), $calling_info, start, func_name)
}};
}

View File

@ -29,7 +29,9 @@ use asset_definition::{
};
use asset_log::{loge, logi};
use asset_plugin::asset_plugin::AssetPlugin;
use asset_sdk::plugin_interface::{EventType, ExtDbMap, PARAM_NAME_BUNDLE_NAME, PARAM_NAME_USER_ID};
use asset_sdk::plugin_interface::{
EventType, ExtDbMap, PARAM_NAME_BUNDLE_NAME, PARAM_NAME_USER_ID,
};
const TAG_COLUMN_TABLE: [(Tag, &str); 20] = [
(Tag::Secret, column::SECRET),
@ -80,13 +82,14 @@ pub(crate) const NORMAL_LABEL_ATTRS: [Tag; 4] =
pub(crate) const NORMAL_LOCAL_LABEL_ATTRS: [Tag; 4] =
[Tag::DataLabelNormalLocal1, Tag::DataLabelNormalLocal2, Tag::DataLabelNormalLocal3, Tag::DataLabelNormalLocal4];
pub(crate) const ACCESS_CONTROL_ATTRS: [Tag; 7] = [
pub(crate) const ACCESS_CONTROL_ATTRS: [Tag; 8] = [
Tag::Alias,
Tag::Accessibility,
Tag::AuthType,
Tag::IsPersistent,
Tag::SyncType,
Tag::RequirePasswordSet,
Tag::RequireAttrEncrypted,
Tag::UserId,
];
@ -136,7 +139,7 @@ pub(crate) fn build_secret_key(calling: &CallingInfo, attrs: &DbMap) -> Result<S
let auth_type = attrs.get_enum_attr::<AuthType>(&column::AUTH_TYPE)?;
let access_type = attrs.get_enum_attr::<Accessibility>(&column::ACCESSIBILITY)?;
let require_password_set = attrs.get_bool_attr(&column::REQUIRE_PASSWORD_SET)?;
SecretKey::new(calling, auth_type, access_type, require_password_set)
SecretKey::new(calling, auth_type, access_type, require_password_set, None)
}
fn build_aad_v1(attrs: &DbMap) -> Vec<u8> {

View File

@ -146,7 +146,7 @@ fn check_data_value(tag: &Tag, value: &Value) -> Result<()> {
Tag::Secret => check_array_size(tag, value, MIN_ARRAY_SIZE, MAX_SECRET_SIZE),
Tag::Alias => check_array_size(tag, value, MIN_ARRAY_SIZE, MAX_ALIAS_SIZE),
Tag::Accessibility => check_enum_variant::<Accessibility>(tag, value),
Tag::RequirePasswordSet | Tag::IsPersistent => Ok(()),
Tag::RequirePasswordSet | Tag::IsPersistent | Tag::RequireAttrEncrypted => Ok(()),
Tag::AuthType => check_enum_variant::<AuthType>(tag, value),
Tag::AuthValidityPeriod => check_number_range(tag, value, MIN_NUMBER_VALUE, MAX_AUTH_VALID_PERIOD),
Tag::AuthChallenge => check_array_size(tag, value, CHALLENGE_SIZE - 1, CHALLENGE_SIZE),

View File

@ -15,46 +15,26 @@
//! This module is used to insert an Asset with a specified alias.
use std::{ffi::CString, os::raw::c_char, sync::Mutex};
use std::{ffi::CString, os::raw::c_char};
use asset_common::CallingInfo;
use asset_crypto_manager::{crypto::Crypto, secret_key::SecretKey};
use asset_crypto_manager::crypto::Crypto;
use asset_db_key_operator::generate_secret_key_if_needed;
use asset_db_operator::{
database::Database,
database::{create_db_instance, Database},
types::{column, DbMap, DB_DATA_VERSION},
};
use asset_definition::{
log_throw_error, Accessibility, AssetMap, AuthType, ConflictResolution, ErrCode, Extension, LocalStatus, Result,
SyncStatus, SyncType, Tag, Value,
};
use asset_log::logi;
use asset_utils::time;
use crate::operations::common;
static GEN_KEY_MUTEX: Mutex<()> = Mutex::new(());
fn generate_key_if_needed(secret_key: &SecretKey) -> Result<()> {
match secret_key.exists() {
Ok(true) => Ok(()),
Ok(false) => {
let _lock = GEN_KEY_MUTEX.lock().unwrap();
match secret_key.exists() {
Ok(true) => Ok(()),
Ok(false) => {
logi!("[INFO]The key does not exist, generate it.");
secret_key.generate()
},
Err(ret) => Err(ret),
}
},
Err(ret) => Err(ret),
}
}
fn encrypt(calling_info: &CallingInfo, db_data: &mut DbMap) -> Result<()> {
fn encrypt_secret(calling_info: &CallingInfo, db_data: &mut DbMap) -> Result<()> {
let secret_key = common::build_secret_key(calling_info, db_data)?;
generate_key_if_needed(&secret_key)?;
generate_secret_key_if_needed(&secret_key)?;
let secret = db_data.get_bytes_attr(&column::SECRET)?;
let cipher = Crypto::encrypt(&secret_key, secret, &common::build_aad(db_data)?)?;
@ -71,7 +51,7 @@ fn resolve_conflict(
) -> Result<()> {
match attrs.get(&Tag::ConflictResolution) {
Some(Value::Number(num)) if *num == ConflictResolution::Overwrite as u32 => {
encrypt(calling, db_data)?;
encrypt_secret(calling, db_data)?;
db.replace_datas(query, false, db_data)
},
_ => {
@ -79,7 +59,7 @@ fn resolve_conflict(
condition.insert(column::SYNC_TYPE, Value::Number(SyncType::TrustedAccount as u32));
condition.insert(column::SYNC_STATUS, Value::Number(SyncStatus::SyncDel as u32));
if db.is_data_exists(&condition, false)? {
encrypt(calling, db_data)?;
encrypt_secret(calling, db_data)?;
db.replace_datas(&condition, false, db_data)
} else {
log_throw_error!(ErrCode::Duplicated, "[FATAL][SA]The specified alias already exists.")
@ -175,14 +155,17 @@ fn local_add(attributes: &AssetMap, calling_info: &CallingInfo) -> Result<()> {
add_default_attrs(&mut db_data);
let query = get_query_condition(calling_info, attributes)?;
let mut db = Database::build(calling_info.user_id())?;
let mut db = create_db_instance(attributes, calling_info)?;
if db.is_data_exists(&query, false)? {
resolve_conflict(calling_info, &mut db, attributes, &query, &mut db_data)
resolve_conflict(calling_info, &mut db, attributes, &query, &mut db_data)?;
} else {
encrypt(calling_info, &mut db_data)?;
encrypt_secret(calling_info, &mut db_data)?;
let _ = db.insert_datas(&db_data)?;
Ok(())
}
Ok(())
}
pub(crate) fn add(calling_info: &CallingInfo, attributes: &AssetMap) -> Result<()> {

View File

@ -17,10 +17,7 @@
use asset_common::CallingInfo;
use asset_crypto_manager::{crypto::Crypto, crypto_manager::CryptoManager, secret_key::SecretKey};
use asset_db_operator::{
database::Database,
types::{column, DbMap},
};
use asset_db_operator::{database::create_db_instance, types::{column, DbMap}};
use asset_definition::{log_throw_error, Accessibility, AssetMap, AuthType, ErrCode, Extension, Result, Tag, Value};
use crate::operations::common;
@ -47,13 +44,9 @@ fn check_arguments(attributes: &AssetMap) -> Result<()> {
}
}
fn query_key_attrs(calling_info: &CallingInfo, db_data: &DbMap) -> Result<(Accessibility, bool)> {
let results = Database::build(calling_info.user_id())?.query_datas(
&vec![column::ACCESSIBILITY, column::REQUIRE_PASSWORD_SET],
db_data,
None,
true,
)?;
fn query_key_attrs(calling_info: &CallingInfo, db_data: &DbMap, attrs: &AssetMap) -> Result<(Accessibility, bool)> {
let mut db = create_db_instance(attrs, calling_info)?;
let results = db.query_datas(&vec![column::ACCESSIBILITY, column::REQUIRE_PASSWORD_SET], db_data, None, true)?;
match results.len() {
0 => log_throw_error!(ErrCode::NotFound, "[FATAL][SA]No data that meets the query conditions is found."),
1 => {
@ -75,12 +68,12 @@ pub(crate) fn pre_query(calling_info: &CallingInfo, query: &AssetMap) -> Result<
common::add_owner_info(calling_info, &mut db_data);
db_data.entry(column::AUTH_TYPE).or_insert(Value::Number(AuthType::Any as u32));
let (access_type, require_password_set) = query_key_attrs(calling_info, &db_data)?;
let (access_type, require_password_set) = query_key_attrs(calling_info, &db_data, query)?;
let valid_time = match query.get(&Tag::AuthValidityPeriod) {
Some(Value::Number(num)) => *num,
_ => DEFAULT_AUTH_VALIDITY_IN_SECS,
};
let secret_key = SecretKey::new(calling_info, AuthType::Any, access_type, require_password_set)?;
let secret_key = SecretKey::new(calling_info, AuthType::Any, access_type, require_password_set, None)?;
let mut crypto = Crypto::build(secret_key, valid_time)?;
let challenge = crypto.init_key()?.to_vec();
let crypto_manager = CryptoManager::get_instance();

View File

@ -20,7 +20,7 @@ use std::cmp::Ordering;
use asset_common::CallingInfo;
use asset_crypto_manager::{crypto::Crypto, crypto_manager::CryptoManager};
use asset_db_operator::{
database::Database,
database::{create_db_instance, Database},
types::{column, DbMap, QueryOptions, DB_DATA_VERSION},
};
use asset_definition::{
@ -59,7 +59,7 @@ fn upgrade_version(db: &mut Database, calling_info: &CallingInfo, db_data: &mut
Ok(())
}
fn decrypt(calling_info: &CallingInfo, db_data: &mut DbMap) -> Result<()> {
fn decrypt_secret(calling_info: &CallingInfo, db_data: &mut DbMap) -> Result<()> {
let secret = db_data.get_bytes_attr(&column::SECRET)?;
let secret_key = common::build_secret_key(calling_info, db_data)?;
let secret = Crypto::decrypt(&secret_key, secret, &common::build_aad(db_data)?)?;
@ -86,7 +86,7 @@ fn exec_crypto(calling_info: &CallingInfo, query: &AssetMap, db_data: &mut DbMap
}
fn query_all(calling_info: &CallingInfo, db_data: &mut DbMap, query: &AssetMap) -> Result<Vec<AssetMap>> {
let mut db = Database::build(calling_info.user_id())?;
let mut db = create_db_instance(query, calling_info)?;
let mut results = db.query_datas(&vec![], db_data, None, true)?;
match results.len() {
0 => throw_error!(ErrCode::NotFound, "[FATAL]The data to be queried does not exist."),
@ -95,7 +95,7 @@ fn query_all(calling_info: &CallingInfo, db_data: &mut DbMap, query: &AssetMap)
Some(Value::Number(auth_type)) if *auth_type == AuthType::Any as u32 => {
exec_crypto(calling_info, query, &mut results[0])?;
},
_ => decrypt(calling_info, &mut results[0])?,
_ => decrypt_secret(calling_info, &mut results[0])?,
};
if common::need_upgrade(&results[0])? {
upgrade_version(&mut db, calling_info, &mut results[0])?;
@ -140,12 +140,8 @@ fn get_query_options(attrs: &AssetMap) -> QueryOptions {
}
pub(crate) fn query_attrs(calling_info: &CallingInfo, db_data: &DbMap, attrs: &AssetMap) -> Result<Vec<AssetMap>> {
let mut results = Database::build(calling_info.user_id())?.query_datas(
&vec![],
db_data,
Some(&get_query_options(attrs)),
true,
)?;
let mut db = create_db_instance(attrs, calling_info)?;
let mut results = db.query_datas(&vec![], db_data, Some(&get_query_options(attrs)), true)?;
if results.is_empty() {
return throw_error!(ErrCode::NotFound, "[FATAL]The data to be queried does not exist.");
}

View File

@ -16,10 +16,7 @@
//! This module is used to delete the Asset, including single and batch deletion.
use asset_common::CallingInfo;
use asset_db_operator::{
database::Database,
types::{column, DbMap},
};
use asset_db_operator::{database::create_db_instance, types::{column, DbMap}};
use asset_definition::{log_throw_error, AssetMap, ErrCode, Result, SyncStatus, SyncType, Value};
use asset_log::logi;
use asset_utils::time;
@ -57,7 +54,7 @@ pub(crate) fn remove(calling_info: &CallingInfo, query: &AssetMap) -> Result<()>
add_system_attrs(&mut update_db_data)?;
add_normal_attrs(&mut update_db_data);
let mut db = Database::build(calling_info.user_id())?;
let mut db = create_db_instance(query, calling_info)?;
let results = db.query_datas(&vec![], &db_data, None, true)?;
if results.is_empty() {
return log_throw_error!(ErrCode::NotFound, "[FATAL]The data to be deleted does not exist.");

View File

@ -17,10 +17,7 @@
use asset_common::CallingInfo;
use asset_crypto_manager::crypto::Crypto;
use asset_db_operator::{
database::Database,
types::{column, DbMap, DB_DATA_VERSION},
};
use asset_db_operator::{database::create_db_instance, types::{column, DbMap, DB_DATA_VERSION}};
use asset_definition::{log_throw_error, AssetMap, ErrCode, Extension, LocalStatus, Result, SyncStatus, Tag, Value};
use asset_utils::time;
@ -97,7 +94,7 @@ pub(crate) fn update(calling_info: &CallingInfo, query: &AssetMap, update: &Asse
add_system_attrs(update, &mut update_db_data)?;
add_normal_attrs(&mut update_db_data);
let mut db = Database::build(calling_info.user_id())?;
let mut db = create_db_instance(query, calling_info)?;
let results = db.query_datas(&vec![], &query_db_data, None, true)?;
if results.is_empty() {
return log_throw_error!(ErrCode::NotFound, "[FATAL]The asset to update is not found.");

View File

@ -97,8 +97,7 @@ pub(crate) fn upload_fault_system_event(
.set_param(build_str_param!(SysEvent::EXTRA, e.msg.clone()))
.write();
loge!(
"[ERROR]Calling fun:[{}], user_id:[{}],
caller:[{}], start_time:[{:?}], error_code:[{}], error_msg:[{}]",
"[ERROR]Calling fun:[{}], user_id:[{}], caller:[{}], start_time:[{:?}], error_code:[{}], error_msg:[{}]",
func_name,
calling_info.user_id(),
owner_info,

View File

@ -47,6 +47,8 @@ static int32_t HuksErrorTransfer(int32_t ret)
case HKS_ERROR_KEY_AUTH_FAILED:
case HKS_ERROR_KEY_AUTH_VERIFY_FAILED:
return ASSET_ACCESS_DENIED;
case HKS_ERROR_CRYPTO_ENGINE_ERROR:
return ASSET_DATA_CORRUPTED;
default:
return ASSET_CRYPTO_ERROR;
}

View File

@ -79,7 +79,12 @@ impl SecretKey {
auth_type: AuthType,
access_type: Accessibility,
require_password_set: bool,
alias: Option<Vec<u8>>,
) -> Result<Self> {
if let Some(alias) = alias {
return Ok(Self { auth_type, access_type, require_password_set, alias, calling_info: calling_info.clone() })
}
// Check whether new key exists.
let alias = calculate_key_alias(calling_info, auth_type, access_type, require_password_set, true)?;
let new_key = Self { auth_type, access_type, require_password_set, alias, calling_info: calling_info.clone() };
@ -139,19 +144,19 @@ impl SecretKey {
let accessibilitys =
[Accessibility::DevicePowerOn, Accessibility::DeviceFirstUnlocked, Accessibility::DeviceUnlocked];
for accessibility in accessibilitys.into_iter() {
let secret_key = SecretKey::new(calling_info, AuthType::None, accessibility, true)?;
let secret_key = SecretKey::new(calling_info, AuthType::None, accessibility, true, None)?;
let tmp = secret_key.delete();
res = if tmp.is_err() { tmp } else { res };
let secret_key = SecretKey::new(calling_info, AuthType::Any, accessibility, true)?;
let secret_key = SecretKey::new(calling_info, AuthType::Any, accessibility, true, None)?;
let tmp = secret_key.delete();
res = if tmp.is_err() { tmp } else { res };
let secret_key = SecretKey::new(calling_info, AuthType::None, accessibility, false)?;
let secret_key = SecretKey::new(calling_info, AuthType::None, accessibility, false, None)?;
let tmp = secret_key.delete();
res = if tmp.is_err() { tmp } else { res };
let secret_key = SecretKey::new(calling_info, AuthType::Any, accessibility, false)?;
let secret_key = SecretKey::new(calling_info, AuthType::Any, accessibility, false, None)?;
let tmp = secret_key.delete();
res = if tmp.is_err() { tmp } else { res };
}

View File

@ -0,0 +1,31 @@
# Copyright (c) 2024 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import("//build/ohos.gni")
ohos_rust_static_library("asset_db_key_operator") {
sources = [ "src/lib.rs" ]
deps = [
"../../../../../third_party/rust/crates/rust-openssl/openssl:lib",
"../../frameworks/definition:asset_definition",
"../../frameworks/os_dependency/file:asset_file_operator",
"../../frameworks/os_dependency/log:asset_log",
"../common:asset_common",
"../crypto_manager:asset_crypto_manager",
]
crate_name = "asset_db_key_operator"
crate_type = "rlib"
subsystem_name = "security"
part_name = "asset"
}

View File

@ -0,0 +1,28 @@
# Copyright (c) 2024 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
[package]
name = "asset_db_key_operator"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
openssl = { git = "https://gitee.com/openharmony/third_party_rust_rust-openssl.git" }
asset_common = { path = "../common" }
asset_crypto_manager = { path = "../crypto_manager" }
asset_definition = { path = "../../frameworks/definition" }
asset_file_operator = { path = "../../frameworks/os_dependency/file" }
asset_log = { path = "../../frameworks/os_dependency/log" }

View File

@ -0,0 +1,125 @@
/*
* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//! This module implements functions related to Asset database key.
use asset_common::CallingInfo;
use asset_crypto_manager::{crypto::Crypto, secret_key::SecretKey};
use asset_definition::{Accessibility, AuthType, Result};
use asset_file_operator::ce_operator::{is_db_key_cipher_file_exist, read_db_key_cipher, write_db_key_cipher};
use asset_log::logi;
use openssl::rand::rand_bytes;
use std::sync::Mutex;
fn build_db_key_secret_key(calling_info: &CallingInfo) -> Result<SecretKey> {
let auth_type = AuthType::None;
let access_type = Accessibility::DeviceFirstUnlocked;
let require_password_set = false;
let alias = "db_key_secret_key".as_bytes().to_vec();
SecretKey::new(calling_info, auth_type, access_type, require_password_set, Some(alias))
}
static GEN_KEY_MUTEX: Mutex<()> = Mutex::new(());
static GET_DB_KEY_MUTEX: Mutex<()> = Mutex::new(());
/// Generate secret key if it does not exist.
pub fn generate_secret_key_if_needed(secret_key: &SecretKey) -> Result<()> {
match secret_key.exists() {
Ok(true) => Ok(()),
Ok(false) => {
let _lock = GEN_KEY_MUTEX.lock().unwrap();
match secret_key.exists() {
Ok(true) => Ok(()),
Ok(false) => {
logi!("[INFO]The key does not exist, generate it.");
secret_key.generate()
},
Err(ret) => Err(ret),
}
},
Err(ret) => Err(ret),
}
}
/// db key obj
pub struct DbKey {
/// db key
pub db_key: Vec<u8>,
}
impl DbKey {
/// Decrypt db key cipher.
pub fn decrypt_db_key_cipher(calling_info: &CallingInfo, db_key_cipher: &Vec<u8>) -> Result<DbKey> {
let secret_key = build_db_key_secret_key(calling_info)?;
let aad: Vec<u8> = "trivial_aad_for_db_key".as_bytes().to_vec();
let db_key = Crypto::decrypt(&secret_key, db_key_cipher, &aad)?;
Ok(Self { db_key })
}
fn generate_db_key() -> Result<DbKey> {
const KEY_LEN_IN_BYTES: usize = 32; // aes-256-gcm requires key length 256 bits = 32 bytes.
let mut db_key = [0; KEY_LEN_IN_BYTES];
rand_bytes(&mut db_key).unwrap();
Ok(Self { db_key: db_key.to_vec() })
}
fn encrypt_db_key(&self, calling_info: &CallingInfo) -> Result<Vec<u8>> {
let secret_key = build_db_key_secret_key(calling_info)?;
generate_secret_key_if_needed(&secret_key)?;
let aad: Vec<u8> = "trivial_aad_for_db_key".as_bytes().to_vec();
let db_key_cipher = Crypto::encrypt(&secret_key, &self.db_key, &aad)?;
Ok(db_key_cipher)
}
/// Check whether the database key exists.
pub fn check_existance(user_id: i32) -> Result<bool> {
is_db_key_cipher_file_exist(user_id)
}
/// Read db key cipher and decrypt if the db key cipher file exists, generate db_key if not.
pub fn get_db_key(calling_info: &CallingInfo) -> Result<DbKey> {
match is_db_key_cipher_file_exist(calling_info.user_id()) {
Ok(true) => {
let db_key_cipher = read_db_key_cipher(calling_info.user_id())?;
Self::decrypt_db_key_cipher(calling_info, &db_key_cipher)
},
Ok(false) => {
let _lock = GET_DB_KEY_MUTEX.lock().unwrap();
match is_db_key_cipher_file_exist(calling_info.user_id()) {
Ok(true) => {
let db_key_cipher = read_db_key_cipher(calling_info.user_id())?;
Self::decrypt_db_key_cipher(calling_info, &db_key_cipher)
},
Ok(false) => {
let db_key = Self::generate_db_key()?;
let db_key_cipher = db_key.encrypt_db_key(calling_info)?;
write_db_key_cipher(calling_info.user_id(), &db_key_cipher)?;
Ok(db_key)
},
Err(e) => Err(e)
}
},
Err(e) => Err(e),
}
}
}
impl Drop for DbKey {
fn drop(&mut self) {
self.db_key.fill(0);
}
}

View File

@ -21,8 +21,10 @@ ohos_rust_static_library("asset_db_operator") {
deps = [
":asset_sqlite3_wrapper",
"../../frameworks/definition:asset_definition",
"../../frameworks/os_dependency/file:asset_file_operator",
"../../frameworks/os_dependency/log:asset_log",
"../common:asset_common",
"../db_key_operator:asset_db_key_operator",
]
crate_name = "asset_db_operator"
@ -37,8 +39,10 @@ ohos_rust_unittest("asset_db_operator_test") {
deps = [
":asset_sqlite3_wrapper",
"../../frameworks/definition:asset_definition",
"../../frameworks/os_dependency/file:asset_file_operator",
"../../frameworks/os_dependency/log:asset_log",
"../common:asset_common",
"../db_key_operator:asset_db_key_operator",
]
subsystem_name = "security"
part_name = "asset"

View File

@ -21,4 +21,6 @@ edition = "2021"
[dependencies]
asset_common = { path = "../common" }
asset_definition = { path = "../../frameworks/definition" }
asset_log = { path = "../../frameworks/os_dependency/log" }
asset_log = { path = "../../frameworks/os_dependency/log" }
asset_db_key_operator = { path = "../db_key_operator" }
asset_file_operator = { path = "../../frameworks/os_dependency/file" }

View File

@ -19,9 +19,11 @@
use core::ffi::c_void;
use std::{ffi::CStr, fs, ptr::null_mut, sync::Mutex};
use asset_common::OwnerType;
use asset_definition::{log_throw_error, ErrCode, Extension, Result, Value};
use asset_common::{CallingInfo, OwnerType};
use asset_definition::{log_throw_error, AssetMap, ErrCode, Extension, Result, Tag, Value};
use asset_file_operator::{ce_operator::remove_ce_files, common::is_file_exist};
use asset_log::{loge, logi};
use asset_db_key_operator::DbKey;
use crate::{
statement::Statement,
@ -30,6 +32,7 @@ use crate::{
column, sqlite_err_handle, DbMap, QueryOptions, COLUMN_INFO, DB_UPGRADE_VERSION, DB_UPGRADE_VERSION_V1,
DB_UPGRADE_VERSION_V2, SQLITE_OK, TABLE_NAME, UPGRADE_COLUMN_INFO, UPGRADE_COLUMN_INFO_V2,
},
database_file_upgrade::{check_and_split_db, construct_splited_db_name, fmt_old_de_db_path},
};
extern "C" {
@ -38,26 +41,48 @@ extern "C" {
fn SqliteExec(db: *mut c_void, sql: *const u8, msg: *mut *mut u8) -> i32;
fn SqliteFree(data: *mut c_void);
fn SqliteErrMsg(db: *mut c_void) -> *const u8;
fn SqliteKey(db: *mut c_void, pKey: *const c_void, nKey: i32) -> i32;
}
/// each user have a Database file
pub(crate) struct UserDbLock {
pub(crate) user_id: i32,
pub(crate) mtx: Mutex<i32>,
#[allow(dead_code)]
pub(crate) db_file_name: String,
}
static USER_DB_LOCK_LIST: Mutex<Vec<&'static UserDbLock>> = Mutex::new(Vec::new());
static SPLIT_DB_LOCK_LIST: Mutex<Vec<&'static UserDbLock>> = Mutex::new(Vec::new());
pub(crate) static OLD_DB_NAME: &str = "asset";
/// If the user exists, the reference to the lock is returned.
/// Otherwise, a new lock is created and its reference is returned.
fn get_file_lock_by_user_id(user_id: i32) -> &'static UserDbLock {
let mut list = USER_DB_LOCK_LIST.lock().unwrap();
pub(crate) fn get_split_db_lock_by_user_id(user_id: i32) -> &'static UserDbLock {
let mut list = SPLIT_DB_LOCK_LIST.lock().unwrap();
for f in list.iter() {
if f.user_id == user_id {
return f;
}
}
let nf = Box::new(UserDbLock { user_id, mtx: Mutex::new(user_id) });
let nf = Box::new(
UserDbLock { user_id, mtx: Mutex::new(user_id), db_file_name: OLD_DB_NAME.clone().to_string() }
);
// SAFETY: We just push item into USER_DB_LOCK_LIST, never remove item or modify item,
// so return a reference of leak item is safe.
let nf: &'static UserDbLock = Box::leak(nf);
list.push(nf);
list[list.len() - 1]
}
/// If the user exists, the reference to the lock is returned.
/// Otherwise, a new lock is created and its reference is returned.
pub(crate) fn get_file_lock_by_user_id_db_file_name(user_id: i32, db_file_name: String) -> &'static UserDbLock {
let mut list = USER_DB_LOCK_LIST.lock().unwrap();
for f in list.iter() {
if f.user_id == user_id && f.db_file_name == db_file_name {
return f;
}
}
let nf = Box::new(UserDbLock { user_id, mtx: Mutex::new(user_id), db_file_name });
// SAFETY: We just push item into USER_DB_LOCK_LIST, never remove item or modify item,
// so return a reference of leak item is safe.
let nf: &'static UserDbLock = Box::leak(nf);
@ -72,23 +97,19 @@ pub struct Database {
pub(crate) backup_path: String,
pub(crate) handle: usize, // Pointer to the database connection.
pub(crate) db_lock: &'static UserDbLock,
pub(crate) db_name: String,
}
/// Callback for database upgrade.
pub type UpgradeDbCallback = fn(db: &Database, old_ver: u32, new_ver: u32) -> Result<()>;
#[cfg(not(test))]
const ROOT_PATH: &str = "/data/service/el1/public/asset_service";
pub(crate) const DE_ROOT_PATH: &str = "/data/service/el1/public/asset_service";
#[cfg(test)]
const ROOT_PATH: &str = "/data/asset_test";
pub(crate) const DE_ROOT_PATH: &str = "/data/asset_test";
#[inline(always)]
fn fmt_db_path(user_id: i32) -> String {
format!("{}/{}/asset.db", ROOT_PATH, user_id)
}
#[inline(always)]
fn fmt_backup_path(path: &str) -> String {
pub(crate) fn fmt_backup_path(path: &str) -> String {
let mut bp = path.to_string();
bp.push_str(".backup");
bp
@ -96,33 +117,106 @@ fn fmt_backup_path(path: &str) -> String {
/// Get asset storage path.
pub fn get_path() -> String {
ROOT_PATH.to_string()
DE_ROOT_PATH.to_string()
}
#[inline(always)]
pub(crate) fn fmt_ce_db_path_with_name(user_id: i32, db_name: &str) -> String {
format!("data/service/el2/{}/asset_service/{}.db", user_id, db_name)
}
#[inline(always)]
pub(crate) fn fmt_de_db_path_with_name(user_id: i32, db_name: &str) -> String {
format!("{}/{}/{}.db", DE_ROOT_PATH, user_id, db_name)
}
fn check_validity_of_db_key(path: &str, user_id: i32) -> Result<()> {
if is_file_exist(path)? && !DbKey::check_existance(user_id)? {
loge!("[FATAL]There is database bot no database key. Now all data should be cleared and restart over.");
remove_ce_files(user_id)?;
return log_throw_error!(ErrCode::DataCorrupted, "[FATAL]All data is cleared in {}.", user_id)
}
Ok(())
}
pub(crate) fn get_db(user_id: i32, db_name: &str, is_ce: bool) -> Result<Database> {
let path = if is_ce {
fmt_ce_db_path_with_name(user_id, db_name)
} else {
fmt_de_db_path_with_name(user_id, db_name)
};
let db_key = if is_ce {
check_validity_of_db_key(&path, user_id)?;
let calling_info = CallingInfo::new_part_info(user_id);
match DbKey::get_db_key(&calling_info) {
Ok(res) => Some(res),
Err(e) if e.code == ErrCode::NotFound || e.code == ErrCode::DataCorrupted => {
loge!("[FATAL]The key is corrupted. Now all data should be cleared and restart over, err is {}.",
e.code);
remove_ce_files(user_id)?;
return log_throw_error!(ErrCode::DataCorrupted, "[FATAL]All data is cleared in {}.", user_id)
}
Err(e) => return Err(e)
}
} else {
None
};
let backup_path = fmt_backup_path(path.as_str());
let lock = get_file_lock_by_user_id_db_file_name(user_id, db_name.to_string().clone());
let mut db = Database { path, backup_path, handle: 0, db_lock: lock, db_name: db_name.to_string() };
let _lock = db.db_lock.mtx.lock().unwrap();
db.open_and_restore(db_key.as_ref())?;
db.restore_if_exec_fail(|e: &Table| e.create(COLUMN_INFO))?;
db.upgrade(DB_UPGRADE_VERSION, |_, _, _| Ok(()))?;
Ok(db)
}
/// Create de db instance if the value of tag "RequireAttrEncrypted" is not specified or set to false.
/// Create ce db instance if true.
pub fn create_db_instance(attributes: &AssetMap, calling_info: &CallingInfo) -> Result<Database> {
match attributes.get(&Tag::RequireAttrEncrypted) {
Some(Value::Bool(true)) => {
let db = Database::build(calling_info, true)?;
Ok(db)
},
_ => {
let db = Database::build(calling_info, false)?;
Ok(db)
},
}
}
impl Database {
/// Create a database.
pub fn build(user_id: i32) -> Result<Database> {
let path = fmt_db_path(user_id);
let backup_path = fmt_backup_path(path.as_str());
let lock = get_file_lock_by_user_id(user_id);
let mut db = Database { path, backup_path, handle: 0, db_lock: lock };
let _lock = db.db_lock.mtx.lock().unwrap();
db.open_and_restore()?;
db.restore_if_exec_fail(|e: &Table| e.create(COLUMN_INFO))?;
db.upgrade(DB_UPGRADE_VERSION, |_, _, _| Ok(()))?;
Ok(db)
pub fn build(calling_info: &CallingInfo, is_ce: bool) -> Result<Database> {
if !is_ce {
// DE database needs trigger the upgrade action.
check_and_split_db(calling_info.user_id())?;
}
get_db(
calling_info.user_id(),
&construct_splited_db_name(calling_info.owner_type_enum(),
calling_info.owner_info(), is_ce)?, is_ce
)
}
/// check is db ok
pub fn check_db_accessible(path: String, user_id: i32) -> Result<()> {
let lock = get_file_lock_by_user_id(user_id);
let mut db = Database { path: path.clone(), backup_path: path, handle: 0, db_lock: lock };
/// Create a database from a file name.
pub fn build_with_file_name(user_id: i32, db_name: &str, is_ce: bool) -> Result<Database> {
check_and_split_db(user_id)?;
get_db(user_id, db_name, is_ce)
}
/// Check whether de db is ok
pub fn check_de_db_accessible(path: String, user_id: i32, db_name: String) -> Result<()> {
let lock = get_file_lock_by_user_id_db_file_name(user_id, db_name.clone());
let mut db = Database { path: path.clone(), backup_path: path, handle: 0, db_lock: lock, db_name };
db.open()?;
let table = Table::new(TABLE_NAME, &db);
table.create(COLUMN_INFO)
}
// Open database connection.
/// Open database connection.
pub(crate) fn open(&mut self) -> Result<()> {
let mut path_c = self.path.clone();
path_c.push('\0');
@ -137,8 +231,11 @@ impl Database {
}
/// Open the database connection and restore the database if the connection fails.
fn open_and_restore(&mut self) -> Result<()> {
pub(crate) fn open_and_restore(&mut self, db_key: Option<&DbKey>) -> Result<()> {
let result = self.open();
if let Some(db_key) = db_key {
self.set_db_key(db_key)?;
}
let result = match result {
Err(ret) if ret.code == ErrCode::DataCorrupted => self.restore(),
ret => ret,
@ -146,6 +243,11 @@ impl Database {
result
}
/// Get db name.
pub(crate) fn get_db_name(&mut self) -> &str {
&self.db_name
}
/// Close database connection.
fn close(&mut self) {
if self.handle != 0 {
@ -160,6 +262,16 @@ impl Database {
self.close()
}
/// Encrypt/Decrypt CE database.
pub fn set_db_key(&mut self, db_key: &DbKey) -> Result<()> {
let ret = unsafe { SqliteKey(self.handle as _, db_key.db_key.as_ptr() as *const c_void, db_key.db_key.len() as i32) };
if ret == SQLITE_OK {
Ok(())
} else {
log_throw_error!(sqlite_err_handle(ret), "[FATAL][DB]Set database key failed, err={}", ret)
}
}
// Recovery the corrupt database and reopen it.
pub(crate) fn restore(&mut self) -> Result<()> {
loge!("[WARNING]Database is corrupt, start to restore");
@ -213,7 +325,7 @@ impl Database {
/// Delete database file.
#[allow(dead_code)]
pub(crate) fn delete(user_id: i32) -> Result<()> {
let path = fmt_db_path(user_id);
let path = fmt_old_de_db_path(user_id);
let backup_path = fmt_backup_path(&path);
if let Err(e) = fs::remove_file(path) {
return log_throw_error!(ErrCode::FileOperationError, "[FATAL][DB]Delete database failed, err={}", e);
@ -437,6 +549,16 @@ impl Database {
self.restore_if_exec_fail(closure)
}
/// query how many data fit the query condition
pub fn query_data_count(
&mut self,
condition: &DbMap,
) -> Result<u32> {
let _lock = self.db_lock.mtx.lock().unwrap();
let closure = |e: &Table| e.count_datas(condition, false);
self.restore_if_exec_fail(closure)
}
/// Delete old data and insert new data.
pub fn replace_datas(&mut self, condition: &DbMap, is_filter_sync: bool, datas: &DbMap) -> Result<()> {
let _lock = self.db_lock.mtx.lock().unwrap();

View File

@ -0,0 +1,171 @@
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//! This module provides interfaces for database management.
//! Databases are isolated based on users and protected by locks.
use std::{fs, path::Path};
use asset_common::OwnerType;
use asset_definition::{log_throw_error, ErrCode, Extension, Result, Value};
use asset_log::logi;
use crate::{
database::{fmt_backup_path, fmt_de_db_path_with_name, get_db, get_split_db_lock_by_user_id, Database, OLD_DB_NAME, DE_ROOT_PATH}, types::{
column, DbMap, QueryOptions,
}
};
const MINIM_OWNER_INFO_LEN: usize = 3;
const REMOVE_INDEX: usize = 2;
static MAX_BATCH_NUM: u32 = 100;
#[inline(always)]
pub(crate) fn fmt_old_de_db_path(user_id: i32) -> String {
format!("{}/{}/asset.db", DE_ROOT_PATH, user_id)
}
fn check_old_db_exist(user_id: i32) -> bool {
let path_str = fmt_old_de_db_path(user_id);
let path = Path::new(&path_str);
path.exists()
}
/// Use owner_type and owner_info construct db name.
pub fn construct_splited_db_name(owner_type: OwnerType, owner_info: &[u8], is_ce: bool) -> Result<String> {
let mut res: String = match owner_type {
OwnerType::Hap => {
let owner_info_string = String::from_utf8_lossy(owner_info).to_string();
let split_owner_info: Vec<&str> = owner_info_string.split('_').collect();
if split_owner_info.len() < MINIM_OWNER_INFO_LEN || split_owner_info.last().is_none() {
return log_throw_error!(ErrCode::DatabaseError, "[FATAL]The queried owner info is not correct.");
}
let app_index = split_owner_info.last().unwrap();
let mut split_owner_info_mut = split_owner_info.clone();
for _ in 0..REMOVE_INDEX {
split_owner_info_mut.pop();
}
let owner_info = split_owner_info_mut.join("_").clone();
format!("Hap_{}_{}", owner_info, app_index)
},
OwnerType::Native => {
format!("Native_{}", String::from_utf8_lossy(owner_info))
}
};
if is_ce {
res = format!("enc_{}", res)
}
Ok(res)
}
fn get_db_before_split(user_id: i32) -> Result<Database> {
get_db(user_id, OLD_DB_NAME, false)
}
fn get_value_from_db_map(db_map: &DbMap, key: &str) -> Result<Value> {
match db_map.get(key) {
Some(value) => Ok(value.clone()),
_ => log_throw_error!(ErrCode::DatabaseError, "[FATAL]Get value from {} failed.", key)
}
}
fn remove_old_db(user_id: i32) -> Result<()> {
let mut remove_db_files = vec![];
let path = fmt_de_db_path_with_name(user_id, OLD_DB_NAME);
remove_db_files.push(path.clone());
remove_db_files.push(fmt_backup_path(path.as_str()));
for file_path in &remove_db_files {
fs::remove_file(file_path)?;
}
Ok(())
}
fn get_new_db(user_id: i32, info_map: &DbMap) -> Result<Database> {
// 1.1 construct db name
let owner_type = OwnerType::try_from(info_map.get_num_attr(&column::OWNER_TYPE)?.to_owned())?;
let owner_info = info_map.get_bytes_attr(&column::OWNER)?;
let new_db_name = construct_splited_db_name(owner_type, owner_info, false)?;
// 1.2 construct new db
get_db(user_id, &new_db_name, false)
}
fn construct_old_query_condition(info_map: &DbMap) -> Result<DbMap> {
let mut old_data_query_condition = DbMap::new();
let owner_info = info_map.get_bytes_attr(&column::OWNER)?;
old_data_query_condition.insert(column::OWNER, Value::Bytes(owner_info.clone()));
Ok(old_data_query_condition)
}
fn calculate_batch_split_times(old_data_query_condition: &DbMap, old_db: &mut Database) -> Result<u32> {
let query_times = (old_db.query_data_count(old_data_query_condition)? + MAX_BATCH_NUM - 1) / MAX_BATCH_NUM;
Ok(query_times)
}
fn migrate_data(old_db: &mut Database, new_db: &mut Database, split_time: u32, old_data_query_condition: &DbMap) -> Result<()> {
// 3.1 query data in old db
let query_options = QueryOptions {offset: None, limit: Some(MAX_BATCH_NUM), order_by: None, order: None};
let old_data_vec =
old_db.query_datas(&vec![], old_data_query_condition, Some(&query_options), false)?;
// 3.2 insert data in new db
for data in &old_data_vec {
let mut condition = DbMap::new();
condition.insert(column::ALIAS, get_value_from_db_map(data, column::ALIAS)?);
condition.insert(column::OWNER, get_value_from_db_map(data, column::OWNER)?);
condition.insert(column::OWNER_TYPE, get_value_from_db_map(data, column::OWNER_TYPE)?);
let mut data_clone = data.clone();
data_clone.remove(column::ID);
new_db.replace_datas(&condition, false, &data_clone)?;
// 3.3 remove data in old db
old_db.delete_datas(&condition, None, false)?;
}
logi!("[INFO]Upgrade [{}] [{}]times", new_db.get_db_name(), split_time);
Ok(())
}
fn split_db(user_id: i32) -> Result<()> {
// 1. open old db
let mut old_db = get_db_before_split(user_id)?;
// 2. get split db info
let empty_condition = DbMap::new();
let owner_info_db_list =
old_db.query_datas(&vec![column::OWNER_TYPE, column::OWNER], &empty_condition, None, false)?;
for info_map in &owner_info_db_list {
// 1. get new db
let mut new_db = get_new_db(user_id, info_map)?;
// 2. batch insert data from old db to new db.
let old_data_query_condition = construct_old_query_condition(info_map)?;
for split_time in 0..calculate_batch_split_times(&old_data_query_condition, &mut old_db)? {
migrate_data(&mut old_db, &mut new_db, split_time, &old_data_query_condition)?;
}
logi!("[INFO]Upgrade [{}] success!", new_db.get_db_name());
}
logi!("[INFO]Upgrade all db success!");
remove_old_db(user_id)?;
Ok(())
}
/// check db need split or not. If needed, split it by owner.
pub fn check_and_split_db(user_id: i32) -> Result<()> {
if check_old_db_exist(user_id) {
let _lock = get_split_db_lock_by_user_id(user_id).mtx.lock().unwrap();
if check_old_db_exist(user_id) {
logi!("[INFO]Start split db.");
split_db(user_id)?;
}
}
Ok(())
}

View File

@ -19,6 +19,7 @@ pub mod database;
mod statement;
mod table;
mod transaction;
pub mod database_file_upgrade;
pub mod types;
#[cfg(test)]

View File

@ -112,3 +112,8 @@ int SqliteReset(void *pStmt)
{
return sqlite3_reset((sqlite3_stmt *)pStmt);
}
int SqliteKey(void *db, const void *pKey, int nKey)
{
return sqlite3_key((sqlite3 *)db, pKey, nKey);
}

View File

@ -20,6 +20,7 @@ use std::{
path::Path,
};
use asset_common::CallingInfo;
use asset_definition::{ErrCode, Extension, Value};
use crate::{
@ -60,7 +61,8 @@ fn open_db_and_insert_data() -> Database {
create_dir();
let mut def = DbMap::from(DB_DATA);
add_bytes_column(&mut def);
let mut db = Database::build(0).unwrap();
let calling_info = CallingInfo::new_self();
let mut db = Database::build(&calling_info, false).unwrap();
let count = db.insert_datas(&def).unwrap();
assert_eq!(count, 1);
db
@ -81,7 +83,8 @@ fn backup_db(db: &Database) {
#[test]
fn create_and_drop_database() {
fs::create_dir_all("/data/asset_test/0").unwrap();
let mut db = Database::build(0).unwrap();
let calling_info = CallingInfo::new_self();
let mut db = Database::build(&calling_info, false).unwrap();
backup_db(&db);
db.close_db();
assert!(Database::delete(0).is_ok());
@ -90,7 +93,8 @@ fn create_and_drop_database() {
#[test]
fn database_version() {
fs::create_dir_all("/data/asset_test/0").unwrap();
let db = Database::build(0).unwrap();
let calling_info = CallingInfo::new_self();
let db = Database::build(&calling_info, false).unwrap();
assert_eq!(1, db.get_version().unwrap());
assert!(db.set_version(2).is_ok());
assert_eq!(2, db.get_version().unwrap());
@ -100,7 +104,8 @@ fn database_version() {
#[test]
fn error_sql() {
fs::create_dir_all("/data/asset_test/0").unwrap();
let db = Database::build(0).unwrap();
let calling_info = CallingInfo::new_self();
let db = Database::build(&calling_info, false).unwrap();
let sql = "pragma zzz user_version = {} mmm";
assert!(db.exec(sql).is_err());
let _ = Database::delete(0);
@ -109,7 +114,8 @@ fn error_sql() {
#[test]
fn create_delete_asset_table() {
fs::create_dir_all("/data/asset_test/0").unwrap();
let mut db = Database::build(0).unwrap();
let calling_info = CallingInfo::new_self();
let mut db = Database::build(&calling_info, false).unwrap();
let table = Table::new(TABLE_NAME, &db);
assert!(table.exist().unwrap());
assert!(table.delete().is_ok());
@ -124,7 +130,8 @@ fn insert_data_with_different_alias() {
let mut def = DbMap::from(DB_DATA);
add_bytes_column(&mut def);
let mut db = Database::build(0).unwrap();
let calling_info = CallingInfo::new_self();
let mut db = Database::build(&calling_info, false).unwrap();
let count = db.insert_datas(&def).unwrap();
assert_eq!(count, 1);
@ -195,7 +202,8 @@ fn query_ordered_data() {
let mut def = DbMap::from(DB_DATA);
add_bytes_column(&mut def);
let mut db = Database::build(0).unwrap();
let calling_info = CallingInfo::new_self();
let mut db = Database::build(&calling_info, false).unwrap();
let count = db.insert_datas(&def).unwrap();
assert_eq!(count, 1);
@ -229,7 +237,8 @@ fn insert_error_data() {
create_dir();
let mut datas = DbMap::new();
datas.insert(column::OWNER, Value::Bytes(column::OWNER.as_bytes().to_vec()));
let mut db = Database::build(0).unwrap();
let calling_info = CallingInfo::new_self();
let mut db = Database::build(&calling_info, false).unwrap();
assert!(db.insert_datas(&datas).is_err());
remove_dir();
}
@ -245,7 +254,8 @@ fn backup_and_restore() {
let _ = db_file.write(b"buffer buffer buffer").unwrap();
// Recovery the main database.
let mut db = Database::build(0).unwrap();
let calling_info = CallingInfo::new_self();
let mut db = Database::build(&calling_info, false).unwrap();
let mut def = DbMap::from(DB_DATA);
add_bytes_column(&mut def);
@ -272,7 +282,8 @@ fn query_mismatch_type_data() {
let mut data = DbMap::from(DB_DATA);
add_bytes_column(&mut data);
data.insert(column::CREATE_TIME, Value::Number(1));
let mut db = Database::build(0).unwrap();
let calling_info = CallingInfo::new_self();
let mut db = Database::build(&calling_info, false).unwrap();
db.insert_datas(&data).unwrap();
assert_eq!(ErrCode::FileOperationError, db.query_datas(&vec![], &data, None, false).unwrap_err().code);

View File

@ -15,6 +15,7 @@
use std::fs;
use asset_common::CallingInfo;
use asset_definition::{DataType, Extension, Value};
use crate::{
@ -31,7 +32,8 @@ fn create_delete_table() {
ColumnInfo { name: "id", is_primary_key: true, not_null: true, data_type: DataType::Number },
ColumnInfo { name: "alias", is_primary_key: false, not_null: true, data_type: DataType::Bytes },
];
let mut db = Database::build(0).unwrap();
let calling_info = CallingInfo::new_self();
let mut db = Database::build(&calling_info, false).unwrap();
let table = Table::new("table_name", &db);
assert!(!table.exist().unwrap());
assert!(table.create(columns).is_ok());
@ -44,7 +46,8 @@ fn create_delete_table() {
#[test]
fn table_restore() {
fs::create_dir_all("/data/asset_test/0").unwrap();
let mut db = Database::build(0).unwrap();
let calling_info = CallingInfo::new_self();
let mut db = Database::build(&calling_info, false).unwrap();
let table = Table::new("table_name", &db);
table
.create(&[ColumnInfo { name: "Id", data_type: DataType::Number, is_primary_key: true, not_null: true }])
@ -67,7 +70,8 @@ fn table_restore() {
#[cfg(test)]
fn insert_test_data() -> Database {
fs::create_dir_all("/data/asset_test/0").unwrap();
let db = Database::build(0).unwrap();
let calling_info = CallingInfo::new_self();
let db = Database::build(&calling_info, false).unwrap();
let columns = &[
ColumnInfo { name: "Id", is_primary_key: true, not_null: true, data_type: DataType::Number },
ColumnInfo { name: "Owner", is_primary_key: false, not_null: true, data_type: DataType::Bytes },
@ -135,7 +139,8 @@ fn data_life_circle() {
#[test]
fn single_data() {
fs::create_dir_all("/data/asset_test/0").unwrap();
let db = Database::build(0).unwrap();
let calling_info = CallingInfo::new_self();
let db = Database::build(&calling_info, false).unwrap();
let table = Table::new("table_name", &db);
let columns = &[
ColumnInfo { name: "id", is_primary_key: true, not_null: true, data_type: DataType::Number },
@ -166,7 +171,8 @@ fn single_data() {
#[test]
fn multiple_data() {
fs::create_dir_all("/data/asset_test/0").unwrap();
let db = Database::build(0).unwrap();
let calling_info = CallingInfo::new_self();
let db = Database::build(&calling_info, false).unwrap();
let table = Table::new("table_name", &db);
let columns = &[
ColumnInfo { name: "id", is_primary_key: true, not_null: true, data_type: DataType::Number },
@ -206,7 +212,8 @@ fn multiple_data() {
#[test]
fn insert_query_row() {
fs::create_dir_all("/data/asset_test/0").unwrap();
let db = Database::build(0).unwrap();
let calling_info = CallingInfo::new_self();
let db = Database::build(&calling_info, false).unwrap();
let table = Table::new("table_name", &db);
let columns = &[
@ -234,7 +241,8 @@ fn insert_query_row() {
#[test]
fn update_delete_row() {
fs::create_dir_all("/data/asset_test/0").unwrap();
let db = Database::build(0).unwrap();
let calling_info = CallingInfo::new_self();
let db = Database::build(&calling_info, false).unwrap();
let table = Table::new("table_name", &db);
let columns = &[
@ -260,7 +268,8 @@ fn update_delete_row() {
#[test]
fn upgrade_table() {
fs::create_dir_all("/data/asset_test/0").unwrap();
let db = Database::build(0).unwrap();
let calling_info = CallingInfo::new_self();
let db = Database::build(&calling_info, false).unwrap();
let table = Table::new("table_name", &db);
let columns = &[
@ -298,7 +307,8 @@ fn upgrade_table() {
#[test]
fn replace_datas() {
fs::create_dir_all("/data/asset_test/0").unwrap();
let db = Database::build(0).unwrap();
let calling_info = CallingInfo::new_self();
let db = Database::build(&calling_info, false).unwrap();
let table = Table::new("table_name", &db);
let columns = &[

View File

@ -24,6 +24,8 @@ extern "C" {
bool GetUserIdByUid(uint64_t uid, uint32_t *userId);
bool IsUserIdExist(int32_t userId, bool *exist);
int32_t GetUserIds(int32_t *userIdsPtr, uint32_t *userIdsSize);
int32_t GetUsersSize(uint32_t *userIdsSize);
#ifdef __cplusplus
}

View File

@ -17,6 +17,7 @@
#include "os_account_manager.h"
#include "asset_type.h"
#include "asset_log.h"
bool GetUserIdByUid(uint64_t uid, uint32_t *userId)
@ -42,3 +43,50 @@ bool IsUserIdExist(int32_t userId, bool *exist)
*exist = isUserIdExist;
return true;
}
int32_t GetUserIds(int32_t *userIdsPtr, uint32_t *userIdsSize)
{
std::vector<OHOS::AccountSA::OsAccountInfo> accountInfos = {};
int32_t ret = OHOS::AccountSA::OsAccountManager::QueryAllCreatedOsAccounts(accountInfos);
if (ret != OHOS::ERR_OK) {
LOGE("[FATAL]Query all account id failed! res is %{public}d", ret);
return ASSET_ACCOUNT_ERROR;
}
if (accountInfos.empty()) {
LOGE("[FATAL]accountInfos is empty");
return ASSET_ACCOUNT_ERROR;
}
std::vector<int32_t> userIdsVec = { 0 };
std::transform(accountInfos.begin(), accountInfos.end(), std::back_inserter(userIdsVec),
[](auto &iter) { return iter.GetLocalId(); });
if (userIdsVec.size() > *userIdsSize) {
LOGE("[FATAL]Users size increased after getting users size.");
return ASSET_ACCOUNT_ERROR;
}
for (uint32_t i = 0; i < *userIdsSize; i++) {
userIdsPtr[i] = userIdsVec[i];
}
*userIdsSize = static_cast<uint32_t>(userIdsVec.size());
return ASSET_SUCCESS;
}
int32_t GetUsersSize(uint32_t *userIdsSize)
{
std::vector<OHOS::AccountSA::OsAccountInfo> accountInfos = {};
int32_t ret = OHOS::AccountSA::OsAccountManager::QueryAllCreatedOsAccounts(accountInfos);
if (ret != OHOS::ERR_OK) {
LOGE("[FATAL]Query all account id failed! res is %{public}d", ret);
return ASSET_ACCOUNT_ERROR;
}
if (accountInfos.empty()) {
LOGE("[FATAL]accountInfos is empty");
return ASSET_ACCOUNT_ERROR;
}
std::vector<int32_t> userIdsVec = { 0 };
std::transform(accountInfos.begin(), accountInfos.end(), std::back_inserter(userIdsVec),
[](auto &iter) { return iter.GetLocalId(); });
*userIdsSize = static_cast<uint32_t>(userIdsVec.size());
return ASSET_SUCCESS;
}

View File

@ -22,6 +22,7 @@ ohos_rust_static_library("asset_plugin") {
"../../frameworks/utils:asset_utils",
"../../interfaces/inner_api/rs:asset_sdk_rust",
"../common:asset_common",
"../db_key_operator:asset_db_key_operator",
"../db_operator:asset_db_operator",
"//third_party/rust/crates/libloading:lib",
]

View File

@ -23,5 +23,6 @@ asset_common = { path = "../common" }
asset_definition = { path = "../../frameworks/definition" }
asset_log = { path = "../../frameworks/os_dependency/log" }
asset_sdk = { path = "../../interfaces/inner_api/rs" }
asset_db_key_operator = { path = "../db_key_operator" }
asset_db_operator = { path = "../db_operator" }
asset_file_operator = { path = "../../frameworks/os_dependency/file" }

View File

@ -13,18 +13,16 @@
* limitations under the License.
*/
use asset_common::Counter;
use asset_db_operator::database::{get_path, Database};
use asset_definition::{log_throw_error, ErrCode, Result};
use asset_common::{CallingInfo, Counter, OwnerType};
use asset_db_operator::{database::{get_path, Database}, database_file_upgrade::construct_splited_db_name, types::column};
use asset_definition::{log_throw_error, ErrCode, Extension, Result};
use asset_file_operator::de_operator::create_user_de_dir;
use asset_log::{loge, logi};
use asset_sdk::{
plugin_interface::{ExtDbMap, IAssetPlugin, IAssetPluginCtx},
Value,
};
use std::{
cell::RefCell,
sync::{Arc, Mutex},
};
use std::{cell::RefCell, sync::{Arc, Mutex}};
/// The asset_ext plugin.
#[derive(Default)]
@ -100,103 +98,162 @@ impl AssetPlugin {
/// The asset_ext plugin context.
#[repr(C)]
pub struct AssetContext {
/// The asset database instance.
pub data_base: Option<Database>,
/// The asset databse's user id.
pub user_id: i32,
/// The asset databse's user id.
pub calling_info: CallingInfo,
}
fn get_db_name(attributes: &ExtDbMap, is_ce: bool) -> std::result::Result<String, u32> {
let owner = attributes.get_bytes_attr(&column::OWNER).map_err(|e| e.code as u32)?;
let owner_type = attributes.get_enum_attr::<OwnerType>(&column::OWNER_TYPE).map_err(|e| e.code as u32)?;
// use owner and owner type calculate db file name
construct_splited_db_name(owner_type, owner, is_ce).map_err(|e| e.code as u32)
}
#[allow(dead_code)]
impl IAssetPluginCtx for AssetContext {
/// Initializes the plugin before usage.
fn init(&mut self, user_id: i32) -> std::result::Result<(), u32> {
// Create database directory if not exists.
asset_file_operator::create_user_db_dir(user_id).map_err(|e| e.code as u32)?;
let db = Database::build(user_id).map_err(|e| e.code as u32)?;
self.data_base = Some(db);
create_user_de_dir(user_id).map_err(|e| e.code as u32)?;
self.user_id = user_id;
Ok(())
}
/// Adds an asset to the database.
/// Adds an asset to de db.
fn add(&mut self, attributes: &ExtDbMap) -> std::result::Result<i32, u32> {
self.data_base
.as_mut()
.ok_or(ErrCode::InvalidArgument as u32)?
.insert_datas(attributes)
.map_err(|e| e.code as u32)
let db_name = get_db_name(attributes, false)?;
let mut db = Database::build_with_file_name(self.user_id, &db_name, false).map_err(|e| e.code as u32)?;
db.insert_datas(attributes).map_err(|e| e.code as u32)
}
/// Adds an asset to ce db.
fn ce_add(&mut self, attributes: &ExtDbMap) -> std::result::Result<i32, u32> {
let db_name = get_db_name(attributes, true)?;
let mut db = Database::build_with_file_name(self.user_id, &db_name, true).map_err(|e| e.code as u32)?;
db.insert_datas(attributes).map_err(|e| e.code as u32)
}
/// Adds an asset with replace to de db.
fn replace(&mut self, condition: &ExtDbMap, attributes: &ExtDbMap) -> std::result::Result<(), u32> {
self.data_base
.as_mut()
.ok_or(ErrCode::InvalidArgument as u32)?
.replace_datas(condition, false, attributes)
.map_err(|e| e.code as u32)
let db_name = get_db_name(attributes, false)?;
let mut db = Database::build_with_file_name(self.user_id, &db_name, false).map_err(|e| e.code as u32)?;
db.replace_datas(condition, false, attributes).map_err(|e| e.code as u32)
}
/// Queries the asset database.
/// Adds an asset with replace to ce db.
fn ce_replace(&mut self, condition: &ExtDbMap, attributes: &ExtDbMap) -> std::result::Result<(), u32> {
let db_name = get_db_name(attributes, true)?;
let mut db = Database::build_with_file_name(self.user_id, &db_name, true).map_err(|e| e.code as u32)?;
db.replace_datas(condition, false, attributes).map_err(|e| e.code as u32)
}
/// Queries de db.
fn query(&mut self, attributes: &ExtDbMap) -> std::result::Result<Vec<ExtDbMap>, u32> {
self.data_base
.as_mut()
.ok_or(ErrCode::InvalidArgument as u32)?
.query_datas(&vec![], attributes, None, false)
.map_err(|e| e.code as u32)
let de_dbs = asset_file_operator::de_operator::get_de_user_dbs(self.user_id).map_err(|e| e.code as u32)?;
let mut query_data = vec![];
for db_name in de_dbs {
let mut db = Database::build_with_file_name(self.user_id, &db_name, false).map_err(|e| e.code as u32)?;
query_data.extend(db.query_datas(&vec![], attributes, None, false).map_err(|e| e.code as u32)?);
}
Ok(query_data)
}
/// Removes an asset from the database.
/// Queries ce db.
fn ce_query(&mut self, attributes: &ExtDbMap) -> std::result::Result<Vec<ExtDbMap>, u32> {
let ce_dbs = asset_file_operator::ce_operator::get_ce_user_dbs(self.user_id).map_err(|e| e.code as u32)?;
let mut query_data = vec![];
for db_name in ce_dbs {
let mut db = Database::build_with_file_name(self.user_id, &db_name, true).map_err(|e| e.code as u32)?;
query_data.extend(db.query_datas(&vec![], attributes, None, false).map_err(|e| e.code as u32)?);
}
Ok(query_data)
}
/// Removes an asset from de db.
fn remove(&mut self, attributes: &ExtDbMap) -> std::result::Result<i32, u32> {
self.data_base
.as_mut()
.ok_or(ErrCode::InvalidArgument as u32)?
.delete_datas(attributes, None, false)
.map_err(|e| e.code as u32)
let de_dbs = asset_file_operator::de_operator::get_de_user_dbs(self.user_id).map_err(|e| e.code as u32)?;
let mut total_remove_count = 0;
for db_name in de_dbs {
let mut db = Database::build_with_file_name(self.user_id, &db_name, false).map_err(|e| e.code as u32)?;
total_remove_count += db.delete_datas(attributes, None, false).map_err(|e| e.code as u32)?;
}
Ok(total_remove_count)
}
/// Remove assets from the database with sepcific condition.
/// Removes an asset from ce db.
fn ce_remove(&mut self, attributes: &ExtDbMap) -> std::result::Result<i32, u32> {
let ce_dbs = asset_file_operator::ce_operator::get_ce_user_dbs(self.user_id).map_err(|e| e.code as u32)?;
let mut total_remove_count = 0;
for db_name in ce_dbs {
let mut db = Database::build_with_file_name(self.user_id, &db_name, true).map_err(|e| e.code as u32)?;
total_remove_count += db.delete_datas(attributes, None, false).map_err(|e| e.code as u32)?;
}
Ok(total_remove_count)
}
/// Removes assets from de db with sepcific condition.
fn remove_with_specific_cond(
&mut self,
specific_cond: &str,
condition_value: &[Value],
) -> std::result::Result<i32, u32> {
self.data_base
.as_mut()
.ok_or(ErrCode::InvalidArgument as u32)?
.delete_specific_condition_datas(specific_cond, condition_value)
.map_err(|e| e.code as u32)
let de_dbs = asset_file_operator::de_operator::get_de_user_dbs(self.user_id).map_err(|e| e.code as u32)?;
let mut total_remove_count = 0;
for db_name in de_dbs {
let mut db = Database::build_with_file_name(self.user_id, &db_name, false).map_err(|e| e.code as u32)?;
total_remove_count += db.delete_specific_condition_datas(specific_cond, condition_value).map_err(|e| e.code as u32)?;
}
Ok(total_remove_count)
}
/// Updates the attributes of an asset in the database.
/// Removes assets from ce db with sepcific condition.
fn ce_remove_with_specific_cond(
&mut self,
specific_cond: &str,
condition_value: &[Value],
) -> std::result::Result<i32, u32> {
let ce_dbs = asset_file_operator::ce_operator::get_ce_user_dbs(self.user_id).map_err(|e| e.code as u32)?;
let mut total_remove_count = 0;
for db_name in ce_dbs {
let mut db = Database::build_with_file_name(self.user_id, &db_name, true).map_err(|e| e.code as u32)?;
total_remove_count += db.delete_specific_condition_datas(specific_cond, condition_value).map_err(|e| e.code as u32)?;
}
Ok(total_remove_count)
}
/// Updates the attributes of an asset in de db.
fn update(&mut self, attributes: &ExtDbMap, attrs_to_update: &ExtDbMap) -> std::result::Result<i32, u32> {
self.data_base
.as_mut()
.ok_or(ErrCode::InvalidArgument as u32)?
.update_datas(attributes, false, attrs_to_update)
.map_err(|e| e.code as u32)
let de_dbs = asset_file_operator::de_operator::get_de_user_dbs(self.user_id).map_err(|e| e.code as u32)?;
let mut total_update_count = 0;
for db_name in de_dbs {
let mut db = Database::build_with_file_name(self.user_id, &db_name, false).map_err(|e| e.code as u32)?;
total_update_count += db.update_datas(attributes, false, attrs_to_update).map_err(|e| e.code as u32)?;
}
Ok(total_update_count)
}
/// Begins a transaction for the asset database.
fn begin_transaction(&mut self) -> std::result::Result<(), u32> {
self.data_base
.as_mut()
.ok_or(ErrCode::InvalidArgument as u32)?
.exec("begin immediate")
.map_err(|e| e.code as u32)
/// Updates the attributes of an asset in ce db.
fn ce_update(&mut self, attributes: &ExtDbMap, attrs_to_update: &ExtDbMap) -> std::result::Result<i32, u32> {
let ce_dbs = asset_file_operator::ce_operator::get_ce_user_dbs(self.user_id).map_err(|e| e.code as u32)?;
let mut total_update_count = 0;
for db_name in ce_dbs {
let mut db = Database::build_with_file_name(self.user_id, &db_name, true).map_err(|e| e.code as u32)?;
total_update_count += db.update_datas(attributes, false, attrs_to_update).map_err(|e| e.code as u32)?;
}
Ok(total_update_count)
}
/// Commits a transaction for the asset database.
fn commit_transaction(&mut self) -> std::result::Result<(), u32> {
self.data_base.as_mut().ok_or(ErrCode::InvalidArgument as u32)?.exec("commit").map_err(|e| e.code as u32)
}
/// Rolls back a transaction for the asset database.
fn rollback_transaction(&mut self) -> std::result::Result<(), u32> {
self.data_base.as_mut().ok_or(ErrCode::InvalidArgument as u32)?.exec("rollback").map_err(|e| e.code as u32)
}
/// Returns the storage path for the asset database.
/// Returns the storage path for de db.
fn get_storage_path(&self) -> String {
get_path()
}
/// Returns the storage path for ce db.
fn ce_get_storage_path(&self) -> String {
get_path()
}
/// Increase count
fn increase_count(&mut self) {
let counter = Counter::get_instance();

View File

@ -65,7 +65,7 @@ fn grant_self_permission() -> i32 {
fn generate_and_delete() {
assert_eq!(0, grant_self_permission());
let calling_info = CallingInfo::new(0, OwnerType::Native, vec![b'2']);
let secret_key = SecretKey::new(&calling_info, AuthType::None, Accessibility::DevicePowerOn, false).unwrap();
let secret_key = SecretKey::new(&calling_info, AuthType::None, Accessibility::DevicePowerOn, false, None).unwrap();
secret_key.generate().unwrap();
secret_key.exists().unwrap();
let _ = SecretKey::delete_by_owner(&calling_info);
@ -77,7 +77,7 @@ fn encrypt_and_decrypt() {
assert_eq!(0, grant_self_permission());
// generate key
let calling_info = CallingInfo::new(0, OwnerType::Native, vec![b'2']);
let secret_key = SecretKey::new(&calling_info, AuthType::None, Accessibility::DevicePowerOn, false).unwrap();
let secret_key = SecretKey::new(&calling_info, AuthType::None, Accessibility::DevicePowerOn, false, None).unwrap();
secret_key.generate().unwrap();
// encrypt data
@ -98,7 +98,7 @@ fn encrypt_and_decrypt() {
fn crypto_init() {
assert_eq!(0, grant_self_permission());
let calling_info = CallingInfo::new(0, OwnerType::Native, vec![b'2']);
let secret_key = SecretKey::new(&calling_info, AuthType::Any, Accessibility::DevicePowerOn, false).unwrap();
let secret_key = SecretKey::new(&calling_info, AuthType::Any, Accessibility::DevicePowerOn, false, None).unwrap();
secret_key.generate().unwrap();
let mut crypto = Crypto::build(secret_key.clone(), 600).unwrap();
@ -110,7 +110,7 @@ fn crypto_init() {
fn crypto_exec() {
assert_eq!(0, grant_self_permission());
let calling_info = CallingInfo::new(0, OwnerType::Native, vec![b'2']);
let secret_key = SecretKey::new(&calling_info, AuthType::Any, Accessibility::DevicePowerOn, false).unwrap();
let secret_key = SecretKey::new(&calling_info, AuthType::Any, Accessibility::DevicePowerOn, false, None).unwrap();
secret_key.generate().unwrap();
let msg = vec![1, 2, 3, 4, 5, 6];
@ -128,12 +128,12 @@ fn crypto_exec() {
fn crypto_manager() {
assert_eq!(0, grant_self_permission());
let calling_info = CallingInfo::new(0, OwnerType::Native, vec![b'2']);
let secret_key1 = SecretKey::new(&calling_info, AuthType::Any, Accessibility::DevicePowerOn, false).unwrap();
let secret_key1 = SecretKey::new(&calling_info, AuthType::Any, Accessibility::DevicePowerOn, false, None).unwrap();
secret_key1.generate().unwrap();
let mut crypto1 = Crypto::build(secret_key1.clone(), 600).unwrap();
let challenge1 = crypto1.init_key().unwrap().clone();
let secret_key2 = SecretKey::new(&calling_info, AuthType::Any, Accessibility::DevicePowerOn, false).unwrap();
let secret_key2 = SecretKey::new(&calling_info, AuthType::Any, Accessibility::DevicePowerOn, false, None).unwrap();
secret_key2.generate().unwrap();
let mut crypto2 = Crypto::build(secret_key2.clone(), 600).unwrap();
let challenge2 = crypto2.init_key().unwrap().clone();