1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #define LOG_TAG "UnifiedDataHelper"
16 #include "unified_data_helper.h"
17 
18 #include "common_func.h"
19 #include "directory_ex.h"
20 #include "file_ex.h"
21 #include "file_uri.h"
22 #include "logger.h"
23 #include "tlv_util.h"
24 #include "udmf_conversion.h"
25 #include "file.h"
26 
27 namespace OHOS {
28 namespace UDMF {
29 constexpr mode_t MODE = 0700;
30 static constexpr int64_t MAX_KV_RECORD_SIZE = 2 * 1024 * 1024;
31 static constexpr int64_t MAX_KV_DATA_SIZE = 4 * 1024 * 1024;
32 
33 constexpr const char *TEMP_UNIFIED_DATA_ROOT_PATH = "data/storage/el2/base/temp/udata";
34 constexpr const char *TEMP_UNIFIED_DATA_SUFFIX = ".ud";
35 constexpr const char *TEMP_UNIFIED_DATA_FLAG = "temp_udmf_file_flag";
36 
37 std::string UnifiedDataHelper::rootPath_ = "";
38 
SetRootPath(const std::string & rootPath)39 void UnifiedDataHelper::SetRootPath(const std::string &rootPath)
40 {
41     rootPath_ = rootPath;
42 }
43 
ExceedKVSizeLimit(UnifiedData & data)44 bool UnifiedDataHelper::ExceedKVSizeLimit(UnifiedData &data)
45 {
46     int64_t totalSize = data.GetSize();
47     if (data.GetSize() > MAX_KV_DATA_SIZE) {
48         LOG_DEBUG(UDMF_FRAMEWORK, "Exceeded KV data limit, totalSize:%{public}" PRId64 " !", totalSize);
49         return true;
50     }
51     for (const auto &record : data.GetRecords()) {
52         if (record->GetSize() > MAX_KV_RECORD_SIZE) {
53             LOG_DEBUG(UDMF_FRAMEWORK, "Exceeded KV record limit, recordSize:%{public}" PRId64 "!", record->GetSize());
54             return true;
55         }
56     }
57     return false;
58 }
59 
IsTempUData(UnifiedData & data)60 bool UnifiedDataHelper::IsTempUData(UnifiedData &data)
61 {
62     auto records = data.GetRecords();
63     if (records.size() != 1) {
64         return false;
65     }
66     if (records[0] == nullptr || records[0]->GetType() != UDType::FILE) {
67         return false;
68     }
69     auto file = static_cast<File*>(records[0].get());
70     if (file == nullptr) {
71         LOG_ERROR(UDMF_FRAMEWORK, "Invalid file record!");
72         return false;
73     }
74     auto details = file->GetDetails();
75     if (details.find(TEMP_UNIFIED_DATA_FLAG) == details.end()) {
76         return false;
77     }
78     LOG_DEBUG(UDMF_FRAMEWORK, "exist temp unified data flag!");
79     return true;
80 }
81 
CreateDirIfNotExist(const std::string & dirPath,const mode_t & mode)82 void UnifiedDataHelper::CreateDirIfNotExist(const std::string& dirPath, const mode_t& mode)
83 {
84     if (OHOS::FileExists(dirPath)) {
85         if (!OHOS::ForceRemoveDirectory(dirPath)) {
86             LOG_ERROR(UDMF_FRAMEWORK, "remove dir %{public}s failed, errno: %{public}d.", dirPath.c_str(), errno);
87         }
88     }
89     LOG_DEBUG(UDMF_FRAMEWORK, "ForceCreateDirectory, dir: %{public}s", dirPath.c_str());
90     bool success = OHOS::ForceCreateDirectory(dirPath);
91     if (!success) {
92         LOG_ERROR(UDMF_FRAMEWORK, "create dir %{public}s failed, errno: %{public}d.", dirPath.c_str(), errno);
93         return;
94     }
95     if (mode != 0) {
96         chmod(dirPath.c_str(), mode);
97     }
98 }
99 
GetSummary(const UnifiedData & data,Summary & summary)100 void UnifiedDataHelper::GetSummary(const UnifiedData &data, Summary &summary)
101 {
102     for (const auto &record : data.GetRecords()) {
103         int64_t recordSize = record->GetSize();
104         auto udType = UtdUtils::GetUtdIdFromUtdEnum(record->GetType());
105         auto it = summary.summary.find(udType);
106         if (it == summary.summary.end()) {
107             summary.summary[udType] = recordSize;
108         } else {
109             summary.summary[udType] += recordSize;
110         }
111         summary.totalSize += recordSize;
112     }
113 }
114 
Pack(UnifiedData & data)115 bool UnifiedDataHelper::Pack(UnifiedData &data)
116 {
117     Summary summary;
118     GetSummary(data, summary);
119 
120     int64_t now = std::chrono::duration_cast<std::chrono::milliseconds>
121                     (std::chrono::system_clock::now().time_since_epoch()).count();
122     CreateDirIfNotExist(GetRootPath(), MODE);
123     std::string filePath = GetRootPath() + std::to_string(now) + TEMP_UNIFIED_DATA_SUFFIX;
124     if (!SaveUDataToFile(filePath, data)) {
125         LOG_ERROR(UDMF_FRAMEWORK, "fail to save unified data to file");
126         return false;
127     }
128     std::string uri = AppFileService::CommonFunc::GetUriFromPath(filePath);
129     auto fileRecord = std::make_shared<File>(uri);
130     UDDetails details;
131     details.insert(std::make_pair(TEMP_UNIFIED_DATA_FLAG, true));
132     for (auto &item : summary.summary) {
133         details.insert(std::make_pair(item.first, item.second));
134     }
135     fileRecord->SetDetails(details);
136     std::vector<std::shared_ptr<UnifiedRecord>> records {};
137     records.emplace_back(fileRecord);
138     data.SetRecords(records);
139     return true;
140 }
141 
Unpack(UnifiedData & data)142 bool UnifiedDataHelper::Unpack(UnifiedData &data)
143 {
144     auto records = data.GetRecords();
145     if (records.size() != 1) {
146         return false;
147     }
148 
149     auto file = static_cast<File*>(records[0].get());
150     if (file == nullptr) {
151         LOG_ERROR(UDMF_FRAMEWORK, "Invalid file record!");
152         return false;
153     }
154     UnifiedData tempData;
155     if (!LoadUDataFromFile(file->GetUri(), tempData)) {
156         LOG_ERROR(UDMF_FRAMEWORK, "Fail to load udata from file!");
157         return false;
158     }
159     data.SetRecords(tempData.GetRecords());
160     return true;
161 }
162 
SaveUDataToFile(const std::string & dataFile,UnifiedData & data)163 bool UnifiedDataHelper::SaveUDataToFile(const std::string &dataFile, UnifiedData &data)
164 {
165     std::vector<uint8_t> dataBytes;
166     auto recordTlv = TLVObject(dataBytes);
167 
168     std::FILE *file = fopen(dataFile.c_str(), "w+");
169     if (file == nullptr) {
170         LOG_ERROR(UDMF_FRAMEWORK, "failed to open file: %{public}s, errno is %{public}d", dataFile.c_str(), errno);
171         return false;
172     }
173     recordTlv.SetFile(file);
174     UdmfConversion::InitValueObject(data);
175     if (!TLVUtil::Writing(data, recordTlv, TAG::TAG_UNIFIED_DATA)) {
176         LOG_ERROR(UDMF_FRAMEWORK, "TLV Writing failed!");
177         (void)fclose(file);
178         return false;
179     }
180     (void)fclose(file);
181     return true;
182 }
183 
LoadUDataFromFile(const std::string & dataFile,UnifiedData & data)184 bool UnifiedDataHelper::LoadUDataFromFile(const std::string &dataFile, UnifiedData &data)
185 {
186     std::vector<uint8_t> dataBytes;
187     auto recordTlv = TLVObject(dataBytes);
188     AppFileService::ModuleFileUri::FileUri fileUri(dataFile);
189     std::string path = fileUri.GetRealPath();
190     std::FILE *file = fopen(path.c_str(), "r");
191     if (file == nullptr) {
192         LOG_ERROR(UDMF_FRAMEWORK, "failed to open file, error:%{public}s, srcdir:%{public}s, relPath:%{public}s",
193                   std::strerror(errno),
194                   dataFile.c_str(),
195                   path.c_str());
196         return false;
197     }
198     recordTlv.SetFile(file);
199 
200     if (!TLVUtil::ReadTlv(data, recordTlv, TAG::TAG_UNIFIED_DATA)) {
201         LOG_ERROR(UDMF_FRAMEWORK, "TLV Reading failed!");
202         (void)fclose(file);
203         return false;
204     }
205     UdmfConversion::ConvertRecordToSubclass(data);
206     (void)fclose(file);
207     return true;
208 }
209 
GetRootPath()210 std::string UnifiedDataHelper::GetRootPath()
211 {
212     if (rootPath_ == "") {
213         return TEMP_UNIFIED_DATA_ROOT_PATH;
214     }
215     return rootPath_;
216 }
217 } // namespace UDMF
218 } // namespace OHOS