114cf0368Sopenharmony_ci/*
214cf0368Sopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd.
314cf0368Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
414cf0368Sopenharmony_ci * you may not use this file except in compliance with the License.
514cf0368Sopenharmony_ci * You may obtain a copy of the License at
614cf0368Sopenharmony_ci *
714cf0368Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
814cf0368Sopenharmony_ci *
914cf0368Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
1014cf0368Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
1114cf0368Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1214cf0368Sopenharmony_ci * See the License for the specific language governing permissions and
1314cf0368Sopenharmony_ci * limitations under the License.
1414cf0368Sopenharmony_ci */
1514cf0368Sopenharmony_ci#define LOG_TAG "UnifiedDataHelper"
1614cf0368Sopenharmony_ci#include "unified_data_helper.h"
1714cf0368Sopenharmony_ci
1814cf0368Sopenharmony_ci#include "common_func.h"
1914cf0368Sopenharmony_ci#include "directory_ex.h"
2014cf0368Sopenharmony_ci#include "file_ex.h"
2114cf0368Sopenharmony_ci#include "file_uri.h"
2214cf0368Sopenharmony_ci#include "logger.h"
2314cf0368Sopenharmony_ci#include "tlv_util.h"
2414cf0368Sopenharmony_ci#include "udmf_conversion.h"
2514cf0368Sopenharmony_ci#include "file.h"
2614cf0368Sopenharmony_ci
2714cf0368Sopenharmony_cinamespace OHOS {
2814cf0368Sopenharmony_cinamespace UDMF {
2914cf0368Sopenharmony_ciconstexpr mode_t MODE = 0700;
3014cf0368Sopenharmony_cistatic constexpr int64_t MAX_KV_RECORD_SIZE = 2 * 1024 * 1024;
3114cf0368Sopenharmony_cistatic constexpr int64_t MAX_KV_DATA_SIZE = 4 * 1024 * 1024;
3214cf0368Sopenharmony_ci
3314cf0368Sopenharmony_ciconstexpr const char *TEMP_UNIFIED_DATA_ROOT_PATH = "data/storage/el2/base/temp/udata";
3414cf0368Sopenharmony_ciconstexpr const char *TEMP_UNIFIED_DATA_SUFFIX = ".ud";
3514cf0368Sopenharmony_ciconstexpr const char *TEMP_UNIFIED_DATA_FLAG = "temp_udmf_file_flag";
3614cf0368Sopenharmony_ci
3714cf0368Sopenharmony_cistd::string UnifiedDataHelper::rootPath_ = "";
3814cf0368Sopenharmony_ci
3914cf0368Sopenharmony_civoid UnifiedDataHelper::SetRootPath(const std::string &rootPath)
4014cf0368Sopenharmony_ci{
4114cf0368Sopenharmony_ci    rootPath_ = rootPath;
4214cf0368Sopenharmony_ci}
4314cf0368Sopenharmony_ci
4414cf0368Sopenharmony_cibool UnifiedDataHelper::ExceedKVSizeLimit(UnifiedData &data)
4514cf0368Sopenharmony_ci{
4614cf0368Sopenharmony_ci    int64_t totalSize = data.GetSize();
4714cf0368Sopenharmony_ci    if (data.GetSize() > MAX_KV_DATA_SIZE) {
4814cf0368Sopenharmony_ci        LOG_DEBUG(UDMF_FRAMEWORK, "Exceeded KV data limit, totalSize:%{public}" PRId64 " !", totalSize);
4914cf0368Sopenharmony_ci        return true;
5014cf0368Sopenharmony_ci    }
5114cf0368Sopenharmony_ci    for (const auto &record : data.GetRecords()) {
5214cf0368Sopenharmony_ci        if (record->GetSize() > MAX_KV_RECORD_SIZE) {
5314cf0368Sopenharmony_ci            LOG_DEBUG(UDMF_FRAMEWORK, "Exceeded KV record limit, recordSize:%{public}" PRId64 "!", record->GetSize());
5414cf0368Sopenharmony_ci            return true;
5514cf0368Sopenharmony_ci        }
5614cf0368Sopenharmony_ci    }
5714cf0368Sopenharmony_ci    return false;
5814cf0368Sopenharmony_ci}
5914cf0368Sopenharmony_ci
6014cf0368Sopenharmony_cibool UnifiedDataHelper::IsTempUData(UnifiedData &data)
6114cf0368Sopenharmony_ci{
6214cf0368Sopenharmony_ci    auto records = data.GetRecords();
6314cf0368Sopenharmony_ci    if (records.size() != 1) {
6414cf0368Sopenharmony_ci        return false;
6514cf0368Sopenharmony_ci    }
6614cf0368Sopenharmony_ci    if (records[0] == nullptr || records[0]->GetType() != UDType::FILE) {
6714cf0368Sopenharmony_ci        return false;
6814cf0368Sopenharmony_ci    }
6914cf0368Sopenharmony_ci    auto file = static_cast<File*>(records[0].get());
7014cf0368Sopenharmony_ci    if (file == nullptr) {
7114cf0368Sopenharmony_ci        LOG_ERROR(UDMF_FRAMEWORK, "Invalid file record!");
7214cf0368Sopenharmony_ci        return false;
7314cf0368Sopenharmony_ci    }
7414cf0368Sopenharmony_ci    auto details = file->GetDetails();
7514cf0368Sopenharmony_ci    if (details.find(TEMP_UNIFIED_DATA_FLAG) == details.end()) {
7614cf0368Sopenharmony_ci        return false;
7714cf0368Sopenharmony_ci    }
7814cf0368Sopenharmony_ci    LOG_DEBUG(UDMF_FRAMEWORK, "exist temp unified data flag!");
7914cf0368Sopenharmony_ci    return true;
8014cf0368Sopenharmony_ci}
8114cf0368Sopenharmony_ci
8214cf0368Sopenharmony_civoid UnifiedDataHelper::CreateDirIfNotExist(const std::string& dirPath, const mode_t& mode)
8314cf0368Sopenharmony_ci{
8414cf0368Sopenharmony_ci    if (OHOS::FileExists(dirPath)) {
8514cf0368Sopenharmony_ci        if (!OHOS::ForceRemoveDirectory(dirPath)) {
8614cf0368Sopenharmony_ci            LOG_ERROR(UDMF_FRAMEWORK, "remove dir %{public}s failed, errno: %{public}d.", dirPath.c_str(), errno);
8714cf0368Sopenharmony_ci        }
8814cf0368Sopenharmony_ci    }
8914cf0368Sopenharmony_ci    LOG_DEBUG(UDMF_FRAMEWORK, "ForceCreateDirectory, dir: %{public}s", dirPath.c_str());
9014cf0368Sopenharmony_ci    bool success = OHOS::ForceCreateDirectory(dirPath);
9114cf0368Sopenharmony_ci    if (!success) {
9214cf0368Sopenharmony_ci        LOG_ERROR(UDMF_FRAMEWORK, "create dir %{public}s failed, errno: %{public}d.", dirPath.c_str(), errno);
9314cf0368Sopenharmony_ci        return;
9414cf0368Sopenharmony_ci    }
9514cf0368Sopenharmony_ci    if (mode != 0) {
9614cf0368Sopenharmony_ci        chmod(dirPath.c_str(), mode);
9714cf0368Sopenharmony_ci    }
9814cf0368Sopenharmony_ci}
9914cf0368Sopenharmony_ci
10014cf0368Sopenharmony_civoid UnifiedDataHelper::GetSummary(const UnifiedData &data, Summary &summary)
10114cf0368Sopenharmony_ci{
10214cf0368Sopenharmony_ci    for (const auto &record : data.GetRecords()) {
10314cf0368Sopenharmony_ci        int64_t recordSize = record->GetSize();
10414cf0368Sopenharmony_ci        auto udType = UtdUtils::GetUtdIdFromUtdEnum(record->GetType());
10514cf0368Sopenharmony_ci        auto it = summary.summary.find(udType);
10614cf0368Sopenharmony_ci        if (it == summary.summary.end()) {
10714cf0368Sopenharmony_ci            summary.summary[udType] = recordSize;
10814cf0368Sopenharmony_ci        } else {
10914cf0368Sopenharmony_ci            summary.summary[udType] += recordSize;
11014cf0368Sopenharmony_ci        }
11114cf0368Sopenharmony_ci        summary.totalSize += recordSize;
11214cf0368Sopenharmony_ci    }
11314cf0368Sopenharmony_ci}
11414cf0368Sopenharmony_ci
11514cf0368Sopenharmony_cibool UnifiedDataHelper::Pack(UnifiedData &data)
11614cf0368Sopenharmony_ci{
11714cf0368Sopenharmony_ci    Summary summary;
11814cf0368Sopenharmony_ci    GetSummary(data, summary);
11914cf0368Sopenharmony_ci
12014cf0368Sopenharmony_ci    int64_t now = std::chrono::duration_cast<std::chrono::milliseconds>
12114cf0368Sopenharmony_ci                    (std::chrono::system_clock::now().time_since_epoch()).count();
12214cf0368Sopenharmony_ci    CreateDirIfNotExist(GetRootPath(), MODE);
12314cf0368Sopenharmony_ci    std::string filePath = GetRootPath() + std::to_string(now) + TEMP_UNIFIED_DATA_SUFFIX;
12414cf0368Sopenharmony_ci    if (!SaveUDataToFile(filePath, data)) {
12514cf0368Sopenharmony_ci        LOG_ERROR(UDMF_FRAMEWORK, "fail to save unified data to file");
12614cf0368Sopenharmony_ci        return false;
12714cf0368Sopenharmony_ci    }
12814cf0368Sopenharmony_ci    std::string uri = AppFileService::CommonFunc::GetUriFromPath(filePath);
12914cf0368Sopenharmony_ci    auto fileRecord = std::make_shared<File>(uri);
13014cf0368Sopenharmony_ci    UDDetails details;
13114cf0368Sopenharmony_ci    details.insert(std::make_pair(TEMP_UNIFIED_DATA_FLAG, true));
13214cf0368Sopenharmony_ci    for (auto &item : summary.summary) {
13314cf0368Sopenharmony_ci        details.insert(std::make_pair(item.first, item.second));
13414cf0368Sopenharmony_ci    }
13514cf0368Sopenharmony_ci    fileRecord->SetDetails(details);
13614cf0368Sopenharmony_ci    std::vector<std::shared_ptr<UnifiedRecord>> records {};
13714cf0368Sopenharmony_ci    records.emplace_back(fileRecord);
13814cf0368Sopenharmony_ci    data.SetRecords(records);
13914cf0368Sopenharmony_ci    return true;
14014cf0368Sopenharmony_ci}
14114cf0368Sopenharmony_ci
14214cf0368Sopenharmony_cibool UnifiedDataHelper::Unpack(UnifiedData &data)
14314cf0368Sopenharmony_ci{
14414cf0368Sopenharmony_ci    auto records = data.GetRecords();
14514cf0368Sopenharmony_ci    if (records.size() != 1) {
14614cf0368Sopenharmony_ci        return false;
14714cf0368Sopenharmony_ci    }
14814cf0368Sopenharmony_ci
14914cf0368Sopenharmony_ci    auto file = static_cast<File*>(records[0].get());
15014cf0368Sopenharmony_ci    if (file == nullptr) {
15114cf0368Sopenharmony_ci        LOG_ERROR(UDMF_FRAMEWORK, "Invalid file record!");
15214cf0368Sopenharmony_ci        return false;
15314cf0368Sopenharmony_ci    }
15414cf0368Sopenharmony_ci    UnifiedData tempData;
15514cf0368Sopenharmony_ci    if (!LoadUDataFromFile(file->GetUri(), tempData)) {
15614cf0368Sopenharmony_ci        LOG_ERROR(UDMF_FRAMEWORK, "Fail to load udata from file!");
15714cf0368Sopenharmony_ci        return false;
15814cf0368Sopenharmony_ci    }
15914cf0368Sopenharmony_ci    data.SetRecords(tempData.GetRecords());
16014cf0368Sopenharmony_ci    return true;
16114cf0368Sopenharmony_ci}
16214cf0368Sopenharmony_ci
16314cf0368Sopenharmony_cibool UnifiedDataHelper::SaveUDataToFile(const std::string &dataFile, UnifiedData &data)
16414cf0368Sopenharmony_ci{
16514cf0368Sopenharmony_ci    std::vector<uint8_t> dataBytes;
16614cf0368Sopenharmony_ci    auto recordTlv = TLVObject(dataBytes);
16714cf0368Sopenharmony_ci
16814cf0368Sopenharmony_ci    std::FILE *file = fopen(dataFile.c_str(), "w+");
16914cf0368Sopenharmony_ci    if (file == nullptr) {
17014cf0368Sopenharmony_ci        LOG_ERROR(UDMF_FRAMEWORK, "failed to open file: %{public}s, errno is %{public}d", dataFile.c_str(), errno);
17114cf0368Sopenharmony_ci        return false;
17214cf0368Sopenharmony_ci    }
17314cf0368Sopenharmony_ci    recordTlv.SetFile(file);
17414cf0368Sopenharmony_ci    UdmfConversion::InitValueObject(data);
17514cf0368Sopenharmony_ci    if (!TLVUtil::Writing(data, recordTlv, TAG::TAG_UNIFIED_DATA)) {
17614cf0368Sopenharmony_ci        LOG_ERROR(UDMF_FRAMEWORK, "TLV Writing failed!");
17714cf0368Sopenharmony_ci        (void)fclose(file);
17814cf0368Sopenharmony_ci        return false;
17914cf0368Sopenharmony_ci    }
18014cf0368Sopenharmony_ci    (void)fclose(file);
18114cf0368Sopenharmony_ci    return true;
18214cf0368Sopenharmony_ci}
18314cf0368Sopenharmony_ci
18414cf0368Sopenharmony_cibool UnifiedDataHelper::LoadUDataFromFile(const std::string &dataFile, UnifiedData &data)
18514cf0368Sopenharmony_ci{
18614cf0368Sopenharmony_ci    std::vector<uint8_t> dataBytes;
18714cf0368Sopenharmony_ci    auto recordTlv = TLVObject(dataBytes);
18814cf0368Sopenharmony_ci    AppFileService::ModuleFileUri::FileUri fileUri(dataFile);
18914cf0368Sopenharmony_ci    std::string path = fileUri.GetRealPath();
19014cf0368Sopenharmony_ci    std::FILE *file = fopen(path.c_str(), "r");
19114cf0368Sopenharmony_ci    if (file == nullptr) {
19214cf0368Sopenharmony_ci        LOG_ERROR(UDMF_FRAMEWORK, "failed to open file, error:%{public}s, srcdir:%{public}s, relPath:%{public}s",
19314cf0368Sopenharmony_ci                  std::strerror(errno),
19414cf0368Sopenharmony_ci                  dataFile.c_str(),
19514cf0368Sopenharmony_ci                  path.c_str());
19614cf0368Sopenharmony_ci        return false;
19714cf0368Sopenharmony_ci    }
19814cf0368Sopenharmony_ci    recordTlv.SetFile(file);
19914cf0368Sopenharmony_ci
20014cf0368Sopenharmony_ci    if (!TLVUtil::ReadTlv(data, recordTlv, TAG::TAG_UNIFIED_DATA)) {
20114cf0368Sopenharmony_ci        LOG_ERROR(UDMF_FRAMEWORK, "TLV Reading failed!");
20214cf0368Sopenharmony_ci        (void)fclose(file);
20314cf0368Sopenharmony_ci        return false;
20414cf0368Sopenharmony_ci    }
20514cf0368Sopenharmony_ci    UdmfConversion::ConvertRecordToSubclass(data);
20614cf0368Sopenharmony_ci    (void)fclose(file);
20714cf0368Sopenharmony_ci    return true;
20814cf0368Sopenharmony_ci}
20914cf0368Sopenharmony_ci
21014cf0368Sopenharmony_cistd::string UnifiedDataHelper::GetRootPath()
21114cf0368Sopenharmony_ci{
21214cf0368Sopenharmony_ci    if (rootPath_ == "") {
21314cf0368Sopenharmony_ci        return TEMP_UNIFIED_DATA_ROOT_PATH;
21414cf0368Sopenharmony_ci    }
21514cf0368Sopenharmony_ci    return rootPath_;
21614cf0368Sopenharmony_ci}
21714cf0368Sopenharmony_ci} // namespace UDMF
21814cf0368Sopenharmony_ci} // namespace OHOS