• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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 #include "update_image_patch.h"
16 #include <cerrno>
17 #include <fcntl.h>
18 #include <pthread.h>
19 #include <sstream>
20 #include <sys/mman.h>
21 #include <sys/stat.h>
22 #include <sys/types.h>
23 #include <unistd.h>
24 #include <memory>
25 #include <vector>
26 #include "applypatch/block_set.h"
27 #include "applypatch/store.h"
28 #include "applypatch/transfer_manager.h"
29 #include "applypatch/partition_record.h"
30 #include "diffpatch/diffpatch.h"
31 #include "dump.h"
32 #include "fs_manager/mount.h"
33 #include "log/log.h"
34 #include "patch/update_patch.h"
35 #include "updater/updater_const.h"
36 #include "utils.h"
37 
38 using namespace Uscript;
39 using namespace Hpackage;
40 using namespace Updater;
41 
42 namespace Updater {
43 constexpr uint32_t IMAGE_PATCH_CMD_LEN = 6;
44 constexpr uint32_t IMAGE_PATCH_CHECK_CMD_LEN = 5;
45 
Execute(Uscript::UScriptEnv & env,Uscript::UScriptContext & context)46 int32_t USInstrImagePatch::Execute(Uscript::UScriptEnv &env, Uscript::UScriptContext &context)
47 {
48     int32_t result = ExecuteImagePatch(env, context);
49     context.PushParam(result);
50     return result;
51 }
52 
GetParam(Uscript::UScriptContext & context,ImagePatchPara & para)53 int32_t USInstrImagePatch::GetParam(Uscript::UScriptContext &context, ImagePatchPara &para)
54 {
55     if (context.GetParamCount() != IMAGE_PATCH_CMD_LEN) {
56         LOG(ERROR) << "para count error " << context.GetParamCount();
57         return USCRIPT_INVALID_PARAM;
58     }
59 
60     int index = 0;
61     uint32_t ret = static_cast<uint32_t>(context.GetParam(index++, para.partName));
62     ret |= static_cast<uint32_t>(context.GetParam(index++, para.srcSize));
63     ret |= static_cast<uint32_t>(context.GetParam(index++, para.srcHash));
64     ret |= static_cast<uint32_t>(context.GetParam(index++, para.destSize));
65     ret |= static_cast<uint32_t>(context.GetParam(index++, para.destHash));
66     ret |= static_cast<uint32_t>(context.GetParam(index++, para.patchFile));
67     if (ret != USCRIPT_SUCCESS) {
68         LOG(ERROR) << "para get error";
69         return USCRIPT_INVALID_PARAM;
70     }
71     para.devPath = GetBlockDeviceByMountPoint(para.partName);
72     if (para.devPath.empty()) {
73         LOG(ERROR) << "get " << para.partName << " dev path error";
74         return USCRIPT_ERROR_EXECUTE;
75     }
76     return USCRIPT_SUCCESS;
77 }
78 
GetFileHash(const std::string & file)79 std::string USInstrImagePatch::GetFileHash(const std::string &file)
80 {
81     UpdatePatch::MemMapInfo mapBuffer {};
82     if (PatchMapFile(file, mapBuffer) != UpdatePatch::PATCH_SUCCESS) {
83         LOG(ERROR) << "PatchMapFile error";
84         return "";
85     }
86     UpdatePatch::BlockBuffer data = { mapBuffer.memory, mapBuffer.length };
87     std::string resultSha = UpdatePatch::GeneraterBufferHash(data);
88     std::transform(resultSha.begin(), resultSha.end(), resultSha.begin(), ::toupper);
89     return resultSha;
90 }
91 
ApplyPatch(const ImagePatchPara & para,const UpdatePatch::MemMapInfo & srcData,const PkgBuffer & patchData)92 int32_t USInstrImagePatch::ApplyPatch(const ImagePatchPara &para, const UpdatePatch::MemMapInfo &srcData,
93     const PkgBuffer &patchData)
94 {
95     std::vector<uint8_t> empty;
96     UpdatePatch::PatchParam patchParam = {
97         srcData.memory, srcData.length, patchData.buffer, patchData.length
98     };
99     std::unique_ptr<DataWriter> writer = DataWriter::CreateDataWriter(WRITE_RAW, para.devPath);
100     if (writer.get() == nullptr) {
101         LOG(ERROR) << "Cannot create block writer, pkgdiff patch abort!";
102         return -1;
103     }
104     std::string resultSha = para.destHash;
105     std::transform(resultSha.begin(), resultSha.end(), resultSha.begin(), ::tolower);
106     int32_t ret = UpdatePatch::UpdateApplyPatch::ApplyImagePatch(patchParam, empty,
107         [&](size_t start, const UpdatePatch::BlockBuffer &data, size_t size) -> int {
108             return (writer->Write(data.buffer, size, nullptr)) ? 0 : -1;
109         }, resultSha);
110     writer.reset();
111     if (ret != 0) {
112         LOG(ERROR) << "Fail to ApplyImagePatch";
113         return -1;
114     }
115     return USCRIPT_SUCCESS;
116 }
117 
CreatePatchStream(Uscript::UScriptEnv & env,const ImagePatchPara & para,PkgManager::StreamPtr & patchStream)118 int32_t USInstrImagePatch::CreatePatchStream(Uscript::UScriptEnv &env, const ImagePatchPara &para,
119     PkgManager::StreamPtr &patchStream)
120 {
121     if (env.GetPkgManager() == nullptr) {
122         LOG(ERROR) << "Error to get pkg manager";
123         return -1;
124     }
125 
126     std::string patchName = para.patchFile;
127     const FileInfo *info = env.GetPkgManager()->GetFileInfo(patchName);
128     if (info == nullptr) {
129         LOG(WARNING) << "Error to get file info " << para.patchFile; // 兼容旧升级包
130         patchName = para.partName;
131         info = env.GetPkgManager()->GetFileInfo(patchName);
132         if (info == nullptr) {
133             return -1;
134         }
135     }
136 
137     std::string patchFile = UPDATER_PATH + para.patchFile;
138     int32_t ret = env.GetPkgManager()->CreatePkgStream(patchStream,
139         patchFile, info->unpackedSize, PkgStream::PkgStreamType_MemoryMap);
140     if (ret != PKG_SUCCESS || patchStream == nullptr) {
141         LOG(ERROR) << "Error to create output stream";
142         return -1;
143     }
144 
145     ret = env.GetPkgManager()->ExtractFile(patchName, patchStream);
146     if (ret != PKG_SUCCESS) {
147         env.GetPkgManager()->ClosePkgStream(patchStream);
148         LOG(ERROR) << "Error to extract file " << para.patchFile;
149         return -1;
150     }
151 
152     LOG(INFO) << "USInstrImagePatch::CreatePatchStream " << para.partName;
153     return USCRIPT_SUCCESS;
154 }
155 
GetSourceFile(const ImagePatchPara & para)156 std::string USInstrImagePatch::GetSourceFile(const ImagePatchPara &para)
157 {
158     // Back up partitions to prevent power failures during the upgrade.
159     std::string srcFile = UPDATER_PATH + para.partName + ".backup";
160 
161     if (access(srcFile.c_str(), F_OK) == 0 && GetFileHash(srcFile) != para.srcHash) {
162         LOG(INFO) << "using backup file:" << srcFile;
163         return srcFile;
164     }
165 
166     if (!Utils::CopyFile(para.devPath, srcFile)) {
167         LOG(ERROR) << "copy " << para.devPath << " to " << srcFile << " failed";
168         return "";
169     }
170     return srcFile;
171 }
172 
ExecuteImagePatch(Uscript::UScriptEnv & env,Uscript::UScriptContext & context)173 int32_t USInstrImagePatch::ExecuteImagePatch(Uscript::UScriptEnv &env, Uscript::UScriptContext &context)
174 {
175     ImagePatchPara para {};
176     int32_t ret = GetParam(context, para);
177     if (ret != USCRIPT_SUCCESS) {
178         UPDATER_LAST_WORD(ret);
179         LOG(ERROR) << "GetParam error";
180         return ret;
181     }
182 
183     if (env.IsRetry()) {
184         LOG(DEBUG) << "Retry updater, check if current partition updatered already during last time";
185         if (PartitionRecord::GetInstance().IsPartitionUpdated(para.partName)) {
186             LOG(INFO) << para.partName << " already updated, skip";
187             return USCRIPT_SUCCESS;
188         }
189     }
190 
191     std::string srcFile = GetSourceFile(para);
192     if (srcFile.empty()) {
193         UPDATER_LAST_WORD(USCRIPT_ERROR_EXECUTE);
194         LOG(ERROR) << "get source file error";
195         return USCRIPT_ERROR_EXECUTE;
196     }
197     UpdatePatch::MemMapInfo srcData {};
198     ret = UpdatePatch::PatchMapFile(srcFile, srcData);
199     if (ret != 0) {
200         UPDATER_LAST_WORD(ret);
201         LOG(ERROR) << "Failed to mmap src file error:" << ret;
202         return -1;
203     }
204 
205     PkgManager::StreamPtr patchStream = nullptr;
206     ret = CreatePatchStream(env, para, patchStream);
207     if (ret != USCRIPT_SUCCESS) {
208         UPDATER_LAST_WORD(USCRIPT_ERROR_EXECUTE);
209         LOG(ERROR) << "CreatePatchStream error";
210         return USCRIPT_ERROR_EXECUTE;
211     }
212     PkgBuffer patchData = {};
213     patchStream->GetBuffer(patchData);
214 
215     ret = ApplyPatch(para, srcData, patchData);
216     if (ret != USCRIPT_SUCCESS) {
217         env.GetPkgManager()->ClosePkgStream(patchStream);
218         return ret;
219     }
220 
221     PartitionRecord::GetInstance().RecordPartitionUpdateStatus(para.partName, true);
222     env.GetPkgManager()->ClosePkgStream(patchStream);
223     unlink(srcFile.c_str());
224     LOG(INFO) << "USInstrImageCheck::Execute ret:" << ret;
225     return ret;
226 }
227 
Execute(Uscript::UScriptEnv & env,Uscript::UScriptContext & context)228 int32_t USInstrImageShaCheck::Execute(Uscript::UScriptEnv &env, Uscript::UScriptContext &context)
229 {
230     int32_t result = ExecuteShaCheck(env, context);
231     context.PushParam(result);
232     return result;
233 }
234 
GetParam(Uscript::UScriptContext & context,CheckPara & para)235 int32_t USInstrImageShaCheck::GetParam(Uscript::UScriptContext &context, CheckPara &para)
236 {
237     if (context.GetParamCount() != IMAGE_PATCH_CHECK_CMD_LEN) {
238         LOG(ERROR) << "para count error " << context.GetParamCount();
239         return USCRIPT_INVALID_PARAM;
240     }
241     int index = 0;
242     uint32_t ret = static_cast<uint32_t>(context.GetParam(index++, para.partName));
243     ret |= static_cast<uint32_t>(context.GetParam(index++, para.srcSize));
244     ret |= static_cast<uint32_t>(context.GetParam(index++, para.srcHash));
245     ret |= static_cast<uint32_t>(context.GetParam(index++, para.destSize));
246     ret |= static_cast<uint32_t>(context.GetParam(index++, para.destHash));
247     if (ret != USCRIPT_SUCCESS) {
248         LOG(ERROR) << "para get error";
249         return USCRIPT_INVALID_PARAM;
250     }
251 
252     para.devPath = GetBlockDeviceByMountPoint(para.partName);
253     if (para.devPath.empty()) {
254         LOG(ERROR) << "cannot get block device of partition" << para.partName;
255         return USCRIPT_ERROR_EXECUTE;
256     }
257     LOG(INFO) << "dev path: " << para.devPath;
258     return USCRIPT_SUCCESS;
259 }
260 
CheckHash(const CheckPara & para)261 int32_t USInstrImageShaCheck::CheckHash(const CheckPara &para)
262 {
263     UpdatePatch::MemMapInfo mapBuffer {};
264     if (PatchMapFile(para.devPath, mapBuffer) != UpdatePatch::PATCH_SUCCESS) {
265         LOG(ERROR) << "PatchMapFile error";
266         return USCRIPT_ERROR_EXECUTE;
267     }
268     size_t length = std::stoul(para.srcSize);
269     UpdatePatch::BlockBuffer data = { mapBuffer.memory, length };
270     std::string resultSha = UpdatePatch::GeneraterBufferHash(data);
271     std::transform(resultSha.begin(), resultSha.end(), resultSha.begin(), ::toupper);
272     if (resultSha != para.srcHash) {
273         LOG(ERROR) << "resultSha:" << resultSha << " srcHash:" << para.srcHash;
274         return USCRIPT_INVALID_PARAM;
275     }
276     return USCRIPT_SUCCESS;
277 }
278 
ExecuteShaCheck(Uscript::UScriptEnv & env,Uscript::UScriptContext & context)279 int32_t USInstrImageShaCheck::ExecuteShaCheck(Uscript::UScriptEnv &env, Uscript::UScriptContext &context)
280 {
281     UPDATER_INIT_RECORD;
282     if (env.IsRetry()) {
283         return USCRIPT_SUCCESS;
284     }
285 
286     CheckPara para {};
287     int32_t ret = GetParam(context, para);
288     if (ret != USCRIPT_SUCCESS) {
289         UPDATER_LAST_WORD(ret);
290         LOG(ERROR) << "GetParam error";
291         return ret;
292     }
293 
294     ret = CheckHash(para);
295     if (ret != USCRIPT_SUCCESS) {
296         UPDATER_LAST_WORD(ret);
297         LOG(ERROR) << "CheckHash error";
298         return ret;
299     }
300 
301     LOG(INFO) << "USInstrImageCheck::Execute Success";
302     return USCRIPT_SUCCESS;
303 }
304 }
305 
306