• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024. 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 
16 #include "patch_shared.h"
17 
18 #include <string>
19 #include <unistd.h>
20 #include <cstdio>
21 #include <fcntl.h>
22 #include "log/log.h"
23 #include "applypatch/store.h"
24 #include "applypatch/transfer_manager.h"
25 #include "script_manager.h"
26 #include "applypatch/partition_record.h"
27 #include "utils.h"
28 #include "pkg_manager.h"
29 #include "updater_env.h"
30 #include <cstdarg>
31 #include <securec.h>
32 #include "hilog/log.h"
33 
34 constexpr int64_t MAX_BUF_SIZE = 1024;
35 
HiLogPrint(LogType type,LogLevel level,unsigned int domain,const char * tag,const char * fmt,...)36 int HiLogPrint(LogType type, LogLevel level, unsigned int domain, const char *tag, const char *fmt, ...)
37 {
38     va_list ap;
39     va_start(ap, fmt);
40     char buf[MAX_BUF_SIZE] = {0};
41     if (vsnprintf_s(buf, MAX_BUF_SIZE, MAX_BUF_SIZE - 1, fmt, ap) == -1) {
42         va_end(ap);
43         return 0;
44     }
45     va_end(ap);
46     /* save log to log partition */
47     printf("%s", buf);
48     return 0;
49 }
50 
51 using namespace Uscript;
52 using namespace Hpackage;
53 using namespace Updater;
54 
55 namespace Updater {
56 constexpr size_t WRITE_FILE_SIZE = 4096;
57 struct UpdateBlockInfo {
58     std::string partitionName;
59     std::string transferName;
60     std::string newDataName;
61     std::string patchDataName;
62     std::string devPath;
63 };
64 
UpdatePathCheck(const std::string & updatePath,size_t length)65 static bool UpdatePathCheck(const std::string &updatePath, size_t length)
66 {
67     if (updatePath.empty() || length == 0) {
68         LOG(ERROR) << "updatePath is nullptr.";
69         return false;
70     }
71 
72     char realPath[PATH_MAX + 1] = {0};
73     if (realpath(updatePath.c_str(), realPath) == nullptr) {
74         LOG(ERROR) << "realPath is NULL" << " : " << strerror(errno);
75         return false;
76     }
77 
78     if (access(realPath, F_OK) != 0) {
79         LOG(ERROR) << "package does not exist!";
80         return false;
81     }
82 
83     return true;
84 }
85 
GetUpdateBlockInfo(UpdateBlockInfo & infos,const std::string & packagePath,const std::string & srcImage,const std::string & targetPath)86 static int GetUpdateBlockInfo(UpdateBlockInfo &infos, const std::string &packagePath,
87     const std::string &srcImage, const std::string &targetPath)
88 {
89     if (!UpdatePathCheck(packagePath, packagePath.length())) {
90         LOG(ERROR) << packagePath << " is empty.";
91         return -1;
92     }
93 
94     if (!UpdatePathCheck(srcImage, srcImage.length())) {
95         LOG(ERROR) << srcImage << " is empty.";
96         return -1;
97     }
98 
99     if (!UpdatePathCheck(targetPath, targetPath.length())) {
100         LOG(INFO) << "need to make store";
101         if (Updater::Utils::MkdirRecursive(targetPath, S_IRWXU) != 0) {
102             LOG(ERROR) << "Failed to make store";
103             return -1;
104         }
105     }
106 
107     infos.newDataName = "anco_hmos.new.dat";
108     infos.patchDataName = "anco_hmos.patch.dat";
109 
110     infos.transferName = "anco_hmos.transfer.list";
111     infos.devPath = srcImage;
112     infos.partitionName = "/anco_hmos";
113 
114     return 0;
115 }
116 
ExtractFileByNameFunc(Uscript::UScriptEnv & env,const std::string & fileName,Hpackage::PkgManager::StreamPtr & outStream,uint8_t * & outBuf,size_t & buffSize)117 static int32_t ExtractFileByNameFunc(Uscript::UScriptEnv &env, const std::string &fileName,
118                                      Hpackage::PkgManager::StreamPtr &outStream, uint8_t *&outBuf, size_t &buffSize)
119 {
120     if (env.GetPkgManager() == nullptr) {
121         LOG(ERROR) << "Error to get pkg manager";
122         return USCRIPT_ERROR_EXECUTE;
123     }
124 
125     const FileInfo *info = env.GetPkgManager()->GetFileInfo(fileName);
126     if (info == nullptr) {
127         LOG(ERROR) << "GetFileInfo fail";
128         return USCRIPT_ERROR_EXECUTE;
129     }
130     auto ret = env.GetPkgManager()->CreatePkgStream(outStream,
131         fileName, info->unpackedSize, PkgStream::PkgStreamType_MemoryMap);
132     if (ret != USCRIPT_SUCCESS || outStream == nullptr) {
133         LOG(ERROR) << "Error to create output stream";
134         return USCRIPT_ERROR_EXECUTE;
135     }
136     ret = env.GetPkgManager()->ExtractFile(fileName, outStream);
137     if (ret != USCRIPT_SUCCESS) {
138         LOG(ERROR) << "Error to extract file";
139         env.GetPkgManager()->ClosePkgStream(outStream);
140         return USCRIPT_ERROR_EXECUTE;
141     }
142     ret = outStream->GetBuffer(outBuf, buffSize);
143     LOG(INFO) << "outBuf data size is: " << buffSize;
144     if (outBuf == nullptr) {
145         LOG(ERROR) << "Error to get outBuf";
146         return USCRIPT_ERROR_EXECUTE;
147     }
148 
149     return USCRIPT_SUCCESS;
150 }
151 
ExecuteTransferCommand(int fd,const std::vector<std::string> & lines,TransferManagerPtr tm,const std::string & partitionName,const std::string & targetPath)152 static int32_t ExecuteTransferCommand(int fd, const std::vector<std::string> &lines,
153     TransferManagerPtr tm, const std::string &partitionName, const std::string &targetPath)
154 {
155     auto transferParams = tm->GetTransferParams();
156     auto writerThreadInfo = transferParams->writerThreadInfo.get();
157 
158     transferParams->storeBase = targetPath + partitionName + "_tmp";
159     LOG(INFO) << "Store base path is " << transferParams->storeBase;
160     int32_t ret = Store::CreateNewSpace(transferParams->storeBase, true);
161     if (ret == -1) {
162         LOG(ERROR) << "Error to create new store space";
163         return -1;
164     }
165     transferParams->storeCreated = ret;
166 
167     if (!tm->CommandsParser(fd, lines)) {
168         return Uscript::USCRIPT_ERROR_EXECUTE;
169     }
170     pthread_mutex_lock(&writerThreadInfo->mutex);
171     if (writerThreadInfo->readyToWrite) {
172         LOG(WARNING) << "New data writer thread is still available...";
173     }
174 
175     writerThreadInfo->readyToWrite = false;
176     pthread_cond_broadcast(&writerThreadInfo->cond);
177     pthread_mutex_unlock(&writerThreadInfo->mutex);
178     ret = pthread_join(transferParams->thread, nullptr);
179     std::ostringstream logMessage;
180     logMessage << "pthread join returned with " << ret;
181     if (ret != 0) {
182         LOG(WARNING) << logMessage.str();
183     }
184     if (transferParams->storeCreated != -1) {
185         Store::DoFreeSpace(transferParams->storeBase);
186         (void)Utils::DeleteFile(transferParams->storeBase);
187     }
188     return Uscript::USCRIPT_SUCCESS;
189 }
190 
DoExecuteUpdateBlock(const UpdateBlockInfo & infos,TransferManagerPtr tm,const std::vector<std::string> & lines,const std::string & targetPath,const std::string & dstImage)191 static int32_t DoExecuteUpdateBlock(const UpdateBlockInfo &infos, TransferManagerPtr tm,
192     const std::vector<std::string> &lines, const std::string &targetPath, const std::string &dstImage)
193 {
194     int fd = open(dstImage.c_str(), O_RDWR | O_LARGEFILE);
195     if (fd == -1) {
196         LOG(ERROR) << "Failed to open block";
197         return Uscript::USCRIPT_ERROR_EXECUTE;
198     }
199     int32_t ret = ExecuteTransferCommand(fd, lines, tm, infos.partitionName, targetPath);
200 
201     fsync(fd);
202     close(fd);
203     fd = -1;
204     if (ret == Uscript::USCRIPT_SUCCESS) {
205         PartitionRecord::GetInstance().RecordPartitionUpdateStatus(infos.partitionName, true);
206     }
207 
208     return ret;
209 }
210 
ExtractNewDataFunc(const PkgBuffer & buffer,size_t size,size_t start,bool isFinish,const void * context)211 static int ExtractNewDataFunc(const PkgBuffer &buffer, size_t size, size_t start, bool isFinish, const void* context)
212 {
213     void *p = const_cast<void *>(context);
214     WriterThreadInfo *info = static_cast<WriterThreadInfo *>(p);
215     uint8_t *addr = buffer.buffer;
216     while (size > 0) {
217         pthread_mutex_lock(&info->mutex);
218         while (info->writer == nullptr) {
219             if (!info->readyToWrite) {
220                 LOG(WARNING) << "writer is not ready to write.";
221                 pthread_mutex_unlock(&info->mutex);
222                 return Hpackage::PKG_INVALID_STREAM;
223             }
224             pthread_cond_wait(&info->cond, &info->mutex);
225         }
226         pthread_mutex_unlock(&info->mutex);
227         size_t toWrite = std::min(size, info->writer->GetBlocksSize() - info->writer->GetTotalWritten());
228         // No more data to write.
229         if (toWrite == 0) {
230             break;
231         }
232         bool ret = info->writer->Write(addr, toWrite, nullptr);
233         std::ostringstream logMessage;
234         logMessage << "Write " << toWrite << " byte(s) failed";
235         if (!ret) {
236             LOG(ERROR) << logMessage.str();
237             return Hpackage::PKG_INVALID_STREAM;
238         }
239         size -= toWrite;
240         addr += toWrite;
241 
242         if (info->writer->IsWriteDone()) {
243             pthread_mutex_lock(&info->mutex);
244             info->writer.reset();
245             pthread_cond_broadcast(&info->cond);
246             pthread_mutex_unlock(&info->mutex);
247         }
248     }
249     return Hpackage::PKG_SUCCESS;
250 }
251 
CondBroadcast(WriterThreadInfo * info)252 static inline void CondBroadcast(WriterThreadInfo *info)
253 {
254     pthread_mutex_lock(&info->mutex);
255     info->readyToWrite = false;
256     if (info->writer != nullptr) {
257         pthread_cond_broadcast(&info->cond);
258     }
259     pthread_mutex_unlock(&info->mutex);
260 }
261 
UnpackNewDataFunc(void * arg)262 void* UnpackNewDataFunc(void *arg)
263 {
264     TransferManagerPtr tm = static_cast<TransferManagerPtr>(arg);
265     WriterThreadInfo *info = tm->GetTransferParams()->writerThreadInfo.get();
266     Hpackage::PkgManager::StreamPtr stream = nullptr;
267     if (info->newPatch.empty()) {
268         LOG(ERROR) << "new patch file name is empty. thread quit.";
269         CondBroadcast(info);
270         return nullptr;
271     }
272     LOG(DEBUG) << "new patch file name: " << info->newPatch;
273     auto env = tm->GetTransferParams()->env;
274     const FileInfo *file = env->GetPkgManager()->GetFileInfo(info->newPatch);
275     if (file == nullptr) {
276         LOG(ERROR) << "Cannot get file info of :" << info->newPatch;
277         CondBroadcast(info);
278         return nullptr;
279     }
280     LOG(DEBUG) << info->newPatch << " info: size " << file->packedSize << " unpacked size " <<
281         file->unpackedSize << " name " << file->identity;
282     int32_t ret = env->GetPkgManager()->CreatePkgStream(stream, info->newPatch, ExtractNewDataFunc, info);
283     if (ret != Hpackage::PKG_SUCCESS || stream == nullptr) {
284         LOG(ERROR) << "Cannot extract " << info->newPatch << " from package.";
285         CondBroadcast(info);
286         return nullptr;
287     }
288     ret = env->GetPkgManager()->ExtractFile(info->newPatch, stream);
289     env->GetPkgManager()->ClosePkgStream(stream);
290     LOG(DEBUG) << "new data writer ending...";
291     // extract new data done.
292     // tell command.
293     CondBroadcast(info);
294     return nullptr;
295 }
296 
InitThread(const struct UpdateBlockInfo & infos,TransferManagerPtr tm)297 static int InitThread(const struct UpdateBlockInfo &infos, TransferManagerPtr tm)
298 {
299     auto transferParams = tm->GetTransferParams();
300     auto writerThreadInfo = transferParams->writerThreadInfo.get();
301     writerThreadInfo->readyToWrite = true;
302     pthread_mutex_init(&writerThreadInfo->mutex, nullptr);
303     pthread_cond_init(&writerThreadInfo->cond, nullptr);
304     pthread_attr_t attr;
305     pthread_attr_init(&attr);
306     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
307     writerThreadInfo->newPatch = infos.newDataName;
308     int error = pthread_create(&transferParams->thread, &attr, UnpackNewDataFunc, tm);
309     return error;
310 }
311 
CreateFixedSizeEmptyFile(const UpdateBlockInfo & infos,const std::string & filename,int64_t size)312 static int CreateFixedSizeEmptyFile(const UpdateBlockInfo &infos, const std::string &filename, int64_t size)
313 {
314     if (size <= 0) {
315         LOG(ERROR) << "size is " << size;
316         return -1;
317     }
318     if (!Updater::Utils::CopyFile(infos.devPath, filename)) {
319         LOG(ERROR) << "copy " << infos.devPath << " to " << filename << " failed";
320         return -1;
321     }
322     size_t fileSize = Updater::Utils::GetFileSize(infos.devPath);
323     if (fileSize >= (static_cast<size_t>(size))) {
324         LOG(INFO) << "no need copy";
325         return 0;
326     }
327     std::ofstream file(filename, std::ios::binary | std::ios::ate);
328     if (!file.is_open()) {
329         LOG(ERROR) << "Failed to open file for writing.";
330         return -1;
331     }
332 
333     /* fill the remaining space with zero values */
334     size_t writeFileTmp = ((static_cast<size_t>(size)) - fileSize) / WRITE_FILE_SIZE;
335     char zerolist[WRITE_FILE_SIZE] = {0};
336     while (writeFileTmp > 0) {
337         file.write(zerolist, WRITE_FILE_SIZE);
338         writeFileTmp--;
339     }
340     writeFileTmp = ((static_cast<size_t>(size)) - fileSize) % WRITE_FILE_SIZE;
341     char zero = 0;
342     while (writeFileTmp > 0) {
343         file.write(&zero, 1);
344         writeFileTmp--;
345     }
346 
347     file.close();
348     return 0;
349 }
350 
GetFileName(const std::string & srcImage)351 static std::string GetFileName(const std::string &srcImage)
352 {
353     std::vector<std::string> lines =
354         Updater::Utils::SplitString(std::string(srcImage), "/");
355     LOG(INFO) << "lines.size is " << lines.size();
356     if (lines.size() == 0) {
357         return nullptr;
358     }
359     return lines[lines.size() - 1];
360 }
361 
ExecuteUpdateBlock(Uscript::UScriptEnv & env,const UpdateBlockInfo & infos,const std::string targetPath,std::string destImage)362 static int32_t ExecuteUpdateBlock(Uscript::UScriptEnv &env, const UpdateBlockInfo &infos,
363     const std::string targetPath, std::string destImage)
364 {
365     Hpackage::PkgManager::StreamPtr outStream = nullptr;
366     uint8_t *transferListBuffer = nullptr;
367     size_t transferListSize = 0;
368     uint8_t *fileSizeBuffer = nullptr;
369     size_t fileListSize = 0;
370     const std::string fileName = "anco_size";
371     if (ExtractFileByNameFunc(env, fileName, outStream, fileSizeBuffer,
372                               fileListSize) != USCRIPT_SUCCESS) {
373         return USCRIPT_ERROR_EXECUTE;
374     }
375     env.GetPkgManager()->ClosePkgStream(outStream);
376     std::string str(reinterpret_cast<char*>(fileSizeBuffer), fileListSize);
377     int64_t maxStashSize = 0;
378     if (!Utils::ConvertToLongLong(str, maxStashSize)) {
379         LOG(ERROR) << "ConvertToLongLong failed";
380         return USCRIPT_ERROR_EXECUTE;
381     }
382     if (CreateFixedSizeEmptyFile(infos, destImage, maxStashSize) != 0) {
383         LOG(ERROR) << "Failed to create empty file";
384         return USCRIPT_ERROR_EXECUTE;
385     }
386 
387     if (ExtractFileByNameFunc(env, infos.transferName,
388         outStream, transferListBuffer, transferListSize) != USCRIPT_SUCCESS) {
389         return USCRIPT_ERROR_EXECUTE;
390     }
391 
392     std::unique_ptr<TransferManager> tm = std::make_unique<TransferManager>();
393     auto transferParams = tm->GetTransferParams();
394     /* Save Script Env to transfer manager */
395     transferParams->env = &env;
396     std::vector<std::string> lines =
397         Updater::Utils::SplitString(std::string(reinterpret_cast<const char*>(transferListBuffer)), "\n");
398     env.GetPkgManager()->ClosePkgStream(outStream);
399 
400     if (ExtractFileByNameFunc(env, infos.patchDataName, outStream,
401         transferParams->dataBuffer, transferParams->dataBufferSize) != USCRIPT_SUCCESS) {
402         return USCRIPT_ERROR_EXECUTE;
403     }
404 
405     LOG(INFO) << "Ready to start a thread to handle new data processing";
406     if (InitThread(infos, tm.get()) != 0) {
407         LOG(ERROR) << "Failed to create pthread";
408         env.GetPkgManager()->ClosePkgStream(outStream);
409         return USCRIPT_ERROR_EXECUTE;
410     }
411     int32_t ret = DoExecuteUpdateBlock(infos, tm.get(), lines, targetPath, destImage);
412     env.GetPkgManager()->ClosePkgStream(outStream);
413     return ret;
414 }
415 
RestoreOriginalFile(const std::string & packagePath,const std::string & srcImage,const std::string & targetPath)416 int RestoreOriginalFile(const std::string &packagePath, const std::string &srcImage, const std::string &targetPath)
417 {
418     UpdateBlockInfo infos {};
419     if (GetUpdateBlockInfo(infos, packagePath, srcImage, targetPath) != 0) {
420         return USCRIPT_ERROR_EXECUTE;
421     }
422     std::string destName = GetFileName(srcImage);
423     std::string destImage = targetPath + "/" + destName;
424 
425     PkgManager::PkgManagerPtr pkgManager = PkgManager::CreatePackageInstance();
426     if (pkgManager == nullptr) {
427         LOG(ERROR) << "pkgManager is nullptr";
428         return USCRIPT_ERROR_EXECUTE;
429     }
430 
431     std::vector<std::string> components;
432     std::string pckPath = packagePath;
433     int32_t ret = pkgManager->LoadPackage(pckPath, components, PkgFile::PKG_TYPE_ZIP);
434     if (ret != PKG_SUCCESS) {
435         LOG(ERROR) << "Fail to load package";
436         PkgManager::ReleasePackageInstance(pkgManager);
437         return USCRIPT_ERROR_EXECUTE;
438     }
439     PostMessageFunction postMessage = nullptr;
440     UScriptEnv *env = new (std::nothrow) UpdaterEnv(pkgManager, postMessage, false);
441     if (env == nullptr) {
442         LOG(ERROR) << "Fail to creat env";
443         PkgManager::ReleasePackageInstance(pkgManager);
444         return USCRIPT_ERROR_EXECUTE;
445     }
446 
447     int result = ExecuteUpdateBlock(*env, infos, targetPath, destImage);
448     if (result != 0) {
449         (void)Utils::DeleteFile(destImage);
450         LOG(ERROR) << "restore original file fail.";
451     }
452     (void)Utils::DeleteFile(packagePath);
453     (void)Utils::DeleteFile(infos.devPath);
454     PkgManager::ReleasePackageInstance(pkgManager);
455     delete env;
456     env = nullptr;
457     return result;
458 }
459 }