delta_update.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. //hpatchz.c
  2. // patch tool
  3. //
  4. /*
  5. This is the HDiffPatch copyright.
  6. Copyright (c) 2012-2021 HouSisong All Rights Reserved.
  7. Permission is hereby granted, free of charge, to any person
  8. obtaining a copy of this software and associated documentation
  9. files (the "Software"), to deal in the Software without
  10. restriction, including without limitation the rights to use,
  11. copy, modify, merge, publish, distribute, sublicense, and/or sell
  12. copies of the Software, and to permit persons to whom the
  13. Software is furnished to do so, subject to the following
  14. conditions:
  15. The above copyright notice and this permission notice shall be
  16. included in all copies of the Software.
  17. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  18. EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  19. OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  20. NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  21. HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  22. WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  23. FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  24. OTHER DEALINGS IN THE SOFTWARE.
  25. */
  26. #include <string.h>
  27. #include <stdlib.h>
  28. #include <stdio.h> //fprintf
  29. #include "patch.h"
  30. #include "file_for_patch.h"
  31. #include "sysinfo.h"
  32. #include "mmcsd_core.h"
  33. #include "ota_update.h"
  34. #include "delta_update.h"
  35. #include "wdt.h"
  36. #ifdef DELTA_UPDATE_SUPPORT
  37. #ifndef _IS_NEED_PRINT_LOG
  38. # define _IS_NEED_PRINT_LOG 1
  39. #endif
  40. #if (_IS_NEED_PRINT_LOG)
  41. # define _log_info_utf8 hpatch_printPath_utf8
  42. #else
  43. # define printf(...)
  44. # define _log_info_utf8(...) do{}while(0)
  45. #endif
  46. #ifndef _IS_NEED_DEFAULT_CompressPlugin
  47. # define _IS_NEED_DEFAULT_CompressPlugin 1
  48. #endif
  49. #if (_IS_NEED_DEFAULT_CompressPlugin)
  50. //===== select needs decompress plugins or change to your plugin=====
  51. # define _CompressPlugin_zlib
  52. #endif
  53. #include "decompress_plugin_demo.h"
  54. typedef enum THPatchResult {
  55. HPATCH_SUCCESS=0,
  56. HPATCH_OPTIONS_ERROR=1,
  57. HPATCH_OPENREAD_ERROR,
  58. HPATCH_OPENWRITE_ERROR,
  59. HPATCH_FILEREAD_ERROR,
  60. HPATCH_FILEWRITE_ERROR, // 5 //see 24
  61. HPATCH_FILEDATA_ERROR,
  62. HPATCH_FILECLOSE_ERROR,
  63. HPATCH_MEM_ERROR, //see 22
  64. HPATCH_HDIFFINFO_ERROR,
  65. HPATCH_COMPRESSTYPE_ERROR, // 10
  66. HPATCH_HPATCH_ERROR,
  67. HPATCH_PATHTYPE_ERROR, //adding begin v3.0
  68. HPATCH_TEMPPATH_ERROR,
  69. HPATCH_DELETEPATH_ERROR,
  70. HPATCH_RENAMEPATH_ERROR, // 15
  71. HPATCH_SPATCH_ERROR,
  72. HPATCH_BSPATCH_ERROR,
  73. HPATCH_VCPATCH_ERROR,
  74. HPATCH_DECOMPRESSER_OPEN_ERROR=20,
  75. HPATCH_DECOMPRESSER_CLOSE_ERROR,
  76. HPATCH_DECOMPRESSER_MEM_ERROR,
  77. HPATCH_DECOMPRESSER_DECOMPRESS_ERROR,
  78. HPATCH_FILEWRITE_NO_SPACE_ERROR,
  79. } THPatchResult;
  80. #define _return_check(value,exitCode,errorInfo){ \
  81. if (!(value)) { LOG_ERR(errorInfo " ERROR!\n"); return exitCode; } }
  82. #define _options_check(value,errorInfo){ \
  83. if (!(value)) { LOG_ERR("options " errorInfo " ERROR!\n\n"); \
  84. printHelpInfo(); return HPATCH_OPTIONS_ERROR; } }
  85. #define kPatchCacheSize_min (hpatch_kStreamCacheSize*8)
  86. #define kPatchCacheSize_bestmin ((size_t)1<<21)
  87. #define kPatchCacheSize_default ((size_t)1<<18)
  88. #define _kNULL_VALUE (-1)
  89. #define _kNULL_SIZE (~(size_t)0)
  90. #define check_on_error(errorType) { \
  91. if (result==HPATCH_SUCCESS) result=errorType; if (!_isInClear){ goto clear; } }
  92. #define check(value,errorType,errorInfo) { \
  93. if (!(value)){ LOG_ERR(errorInfo " ERROR!\n"); check_on_error(errorType); } }
  94. #if (_HPATCH_IS_USED_errno)
  95. # define check_ferr(fileError,errorType,errorInfo){ \
  96. if (fileError){ \
  97. result=HPATCH_SUCCESS; \
  98. if (ENOSPC==(fileError)){ \
  99. check(hpatch_FALSE,HPATCH_FILEWRITE_NO_SPACE_ERROR,errorInfo); \
  100. }else{ \
  101. check(hpatch_FALSE,errorType,errorInfo); } } }
  102. #else
  103. # define check_ferr(fileError,errorType,errorInfo) { \
  104. if (fileError) { result=HPATCH_SUCCESS; check(hpatch_FALSE,errorType,errorInfo); } }
  105. #endif
  106. #define check_dec(decError) { \
  107. switch (decError){ \
  108. case hpatch_dec_ok: break; \
  109. case hpatch_dec_mem_error: check(0,HPATCH_DECOMPRESSER_MEM_ERROR,"decompressPlugin alloc memory"); \
  110. case hpatch_dec_open_error: check(0,HPATCH_DECOMPRESSER_OPEN_ERROR,"decompressPlugin open"); \
  111. case hpatch_dec_close_error: check(0,HPATCH_DECOMPRESSER_CLOSE_ERROR,"decompressPlugin close"); \
  112. default: { assert(decError==hpatch_dec_error); \
  113. check(0,HPATCH_DECOMPRESSER_DECOMPRESS_ERROR,"decompressPlugin decompress"); } break; \
  114. } }
  115. #define _try_rt_dec(dec) { if (dec.is_can_open(compressType)) return &dec; }
  116. static const hpatch_TDecompress* __find_decompressPlugin(const char* compressType){
  117. #ifdef _CompressPlugin_zlib
  118. _try_rt_dec(zlibDecompressPlugin);
  119. #endif
  120. return 0;
  121. }
  122. static hpatch_BOOL getDecompressPlugin(const hpatch_compressedDiffInfo* diffInfo,
  123. hpatch_TDecompress* out_decompressPlugin){
  124. const hpatch_TDecompress* decompressPlugin=0;
  125. memset(out_decompressPlugin,0,sizeof(*out_decompressPlugin));
  126. if (diffInfo->compressedCount>0){
  127. decompressPlugin=__find_decompressPlugin(diffInfo->compressType);
  128. if ((0==decompressPlugin)||(decompressPlugin->open==0)) return hpatch_FALSE; //error
  129. }
  130. if (decompressPlugin){
  131. *out_decompressPlugin=*decompressPlugin;
  132. out_decompressPlugin->decError=hpatch_dec_ok;
  133. }
  134. return hpatch_TRUE;
  135. }
  136. typedef struct _THDiffInfos{
  137. hpatch_BOOL isSingleCompressedDiff;
  138. hpatch_BOOL isBsDiff;
  139. hpatch_BOOL isVcDiff;
  140. hpatch_compressedDiffInfo diffInfo;
  141. hpatch_TDecompress _decompressPlugin;
  142. } _THDiffInfos;
  143. #define _kUnavailableSize hpatch_kNullStreamPos
  144. static int _getHDiffInfos(_THDiffInfos* out_diffInfos,const hpatch_TFileStreamInput* diffData){
  145. int result=HPATCH_SUCCESS;
  146. int _isInClear=hpatch_FALSE;
  147. hpatch_TDecompress* decompressPlugin=&out_diffInfos->_decompressPlugin;
  148. hpatch_compressedDiffInfo* diffInfo=&out_diffInfos->diffInfo;
  149. if (getCompressedDiffInfo(diffInfo,&diffData->base)){
  150. check(diffInfo->oldDataSize!=_kUnavailableSize,HPATCH_HDIFFINFO_ERROR,"saved oldDataSize");
  151. }else{
  152. check(hpatch_FALSE,HPATCH_HDIFFINFO_ERROR,"is hdiff file? get diffInfo");
  153. }
  154. if (decompressPlugin->open==0){
  155. if (getDecompressPlugin(diffInfo,decompressPlugin)){
  156. }else{
  157. LOG_ERR("can not decompress \"%s\" data ERROR!\n",out_diffInfos->diffInfo.compressType);
  158. check_on_error(HPATCH_COMPRESSTYPE_ERROR);
  159. }
  160. }
  161. clear:
  162. _isInClear=hpatch_TRUE;
  163. check(!diffData->fileError,HPATCH_FILEREAD_ERROR,"read file");
  164. return result;
  165. }
  166. static void _printHDiffInfos(const _THDiffInfos* diffInfos,hpatch_BOOL isInDirDiff){
  167. const hpatch_compressedDiffInfo* diffInfo=&diffInfos->diffInfo;
  168. {
  169. const char* typeTag="HDiff";
  170. printf(" diffDataType: %s %s\n",typeTag,isInDirDiff?"(in DirHDiff)":"");
  171. }
  172. if (diffInfo->oldDataSize==_kUnavailableSize)
  173. printf(" saved oldDataSize: unavailable\n");
  174. else
  175. printf(" saved oldDataSize: %" PRIu64 "\n",diffInfo->oldDataSize);
  176. printf(" saved newDataSize: %" PRIu64 "\n",diffInfo->newDataSize);
  177. printf(" compressType: \"%s\" (need decompress %d)\n",diffInfo->compressType,diffInfo->compressedCount);
  178. }
  179. #define _free_mem(p) { if (p) { vPortFree(p); p=0; } }
  180. static TByte* getPatchMemCache(hpatch_BOOL isLoadOldAll,size_t patchCacheSize,size_t mustAppendMemSize,
  181. hpatch_StreamPos_t oldDataSize,size_t* out_memCacheSize){
  182. TByte* temp_cache=0;
  183. size_t temp_cache_size;
  184. {
  185. hpatch_StreamPos_t limitCacheSize;
  186. const hpatch_StreamPos_t bestMaxCacheSize=oldDataSize+kPatchCacheSize_bestmin;
  187. if (isLoadOldAll){
  188. limitCacheSize=bestMaxCacheSize;
  189. }else{
  190. limitCacheSize=(patchCacheSize<kPatchCacheSize_min)?kPatchCacheSize_min:patchCacheSize;
  191. limitCacheSize=(limitCacheSize<bestMaxCacheSize)?limitCacheSize:bestMaxCacheSize;
  192. }
  193. if (limitCacheSize>(size_t)(_kNULL_SIZE-mustAppendMemSize))//too large
  194. limitCacheSize=(size_t)(_kNULL_SIZE-mustAppendMemSize);
  195. temp_cache_size=(size_t)limitCacheSize;
  196. }
  197. while (temp_cache_size>=kPatchCacheSize_min){
  198. temp_cache=(TByte*)pvPortMalloc(mustAppendMemSize+temp_cache_size);
  199. if (temp_cache) break;
  200. temp_cache_size>>=1;
  201. }
  202. *out_memCacheSize=(temp_cache)?(mustAppendMemSize+temp_cache_size):0;
  203. return temp_cache;
  204. }
  205. int delta_update(int filetype, size_t patchFileSize)
  206. {
  207. int result = HPATCH_SUCCESS;
  208. int _isInClear = hpatch_FALSE;
  209. uint32_t time0 = xTaskGetTickCount();
  210. _THDiffInfos diffInfos={0};
  211. hpatch_TDecompress* decompressPlugin=&diffInfos._decompressPlugin;
  212. hpatch_TFileStreamOutput newData;
  213. hpatch_TFileStreamInput diffData;
  214. hpatch_TFileStreamInput oldData;
  215. hpatch_TStreamInput* poldData=&oldData.base;
  216. TByte* temp_cache=0;
  217. size_t temp_cache_size;
  218. int patch_result = HPATCH_SUCCESS;
  219. char oldFileName[32];
  220. char diffFileName[32];
  221. char outNewFileName[32];
  222. SysInfo *sysinfo = GetSysInfo();
  223. SysInfo bak_sysinfo;
  224. memcpy(&bak_sysinfo, sysinfo, sizeof(SysInfo));
  225. //没有备份的程序不支持差分升级
  226. #ifndef IMAGE_RESOURCES_BACKUP
  227. if(filetype > UPFILE_TYPE_APP)
  228. #else
  229. if(filetype > UPFILE_TYPE_ROM)
  230. #endif
  231. {
  232. printf("%s, filetype not support delta update.\n", __func__);//no backup partition for the update file
  233. return -1;
  234. }
  235. hpatch_setPatchFileSize(patchFileSize);
  236. hpatch_TFileStreamInput_init(&oldData);
  237. hpatch_TFileStreamInput_init(&diffData);
  238. hpatch_TFileStreamOutput_init(&newData);
  239. #ifdef HPATCH_FILE_USE_FILESYSTEM
  240. strcpy(oldFileName, OTA_MOUNT_PATH);
  241. strcat(oldFileName, g_upfilename[filetype]);
  242. strcpy(diffData, oldFileName);
  243. strcpy(strrchr(diffData, '.'), "_patch.bin");
  244. strcpy(outNewFileName, oldFileName);
  245. strcpy(strrchr(outNewFileName, '.'), "_new.bin");
  246. #else
  247. strcpy(oldFileName, hpatch_NofsFileName[filetype]);
  248. strcpy(diffFileName, "patch");
  249. strcpy(outNewFileName, "new");
  250. strcat(outNewFileName, oldFileName);
  251. #endif
  252. {//open
  253. printf( "old : \""); if (oldFileName) _log_info_utf8(oldFileName);
  254. printf("\"\ndiff: \""); _log_info_utf8(diffFileName);
  255. printf("\"\nout : \""); _log_info_utf8(outNewFileName);
  256. printf("\"\n");
  257. if ((0==oldFileName)||(0==strlen(oldFileName))){
  258. mem_as_hStreamInput(&oldData.base,0,0);
  259. }else{
  260. check(hpatch_TFileStreamInput_open(&oldData,oldFileName),
  261. HPATCH_OPENREAD_ERROR,"open oldFile for read");
  262. }
  263. check(hpatch_TFileStreamInput_open(&diffData,diffFileName),
  264. HPATCH_OPENREAD_ERROR,"open diffFile for read");
  265. }
  266. printf(" input oldDataSize: %" PRIu64 "\n",poldData->streamSize);
  267. printf(" diffDataSize: %" PRIu64 "\n",diffData.base.streamSize);
  268. {//info
  269. int ret=_getHDiffInfos(&diffInfos,&diffData);
  270. #if (_IS_NEED_PRINT_LOG)
  271. if ((ret!=HPATCH_SUCCESS)&&(ret!=HPATCH_COMPRESSTYPE_ERROR))
  272. check_on_error(ret);
  273. _printHDiffInfos(&diffInfos,hpatch_FALSE);
  274. printf("\n");
  275. #endif
  276. if (ret!=HPATCH_SUCCESS)
  277. check_on_error(ret);
  278. if (diffInfos.diffInfo.newDataSize > get_upfile_maxsize(filetype)) {
  279. printf("The file is too large, not enough space to save.\n");
  280. check_on_error(HPATCH_FILEWRITE_NO_SPACE_ERROR);
  281. }
  282. }
  283. if (decompressPlugin->open==0) decompressPlugin=0;
  284. if ((poldData->streamSize!=diffInfos.diffInfo.oldDataSize)&&(diffInfos.diffInfo.oldDataSize!=_kUnavailableSize)){
  285. LOG_ERR("input oldFile oldDataSize %" PRIu64 " != diffFile saved oldDataSize %" PRIu64 " ERROR!\n",
  286. poldData->streamSize,diffInfos.diffInfo.oldDataSize);
  287. check_on_error(HPATCH_FILEDATA_ERROR);
  288. }
  289. check(hpatch_TFileStreamOutput_open(&newData, outNewFileName,diffInfos.diffInfo.newDataSize),
  290. HPATCH_OPENWRITE_ERROR,"open out newFile for write");
  291. #ifdef HPATCH_FILE_CHECK_DEBUG
  292. newData.m_file->filebuf = pvPortMalloc(diffInfos.diffInfo.newDataSize);
  293. #endif
  294. #ifndef HPATCH_FILE_USE_FILESYSTEM
  295. #if DEVICE_TYPE_SELECT != EMMC_FLASH
  296. sfud_erase(newData.m_file->sflash, newData.m_file->offset, diffInfos.diffInfo.newDataSize);
  297. #endif
  298. #endif
  299. {
  300. hpatch_StreamPos_t maxWindowSize=poldData->streamSize;
  301. hpatch_size_t mustAppendMemSize=0;
  302. temp_cache=getPatchMemCache(hpatch_FALSE,kPatchCacheSize_default,mustAppendMemSize,maxWindowSize, &temp_cache_size);
  303. }
  304. check(temp_cache,HPATCH_MEM_ERROR,"alloc cache memory");
  305. {
  306. if (!patch_decompress_with_cache(&newData.base,poldData,&diffData.base,decompressPlugin,
  307. temp_cache,temp_cache+temp_cache_size))
  308. patch_result=HPATCH_HPATCH_ERROR;
  309. }
  310. if (patch_result!=HPATCH_SUCCESS){
  311. check(!oldData.fileError,HPATCH_FILEREAD_ERROR,"oldFile read");
  312. check(!diffData.fileError,HPATCH_FILEREAD_ERROR,"diffFile read");
  313. check_ferr(newData.fileError,HPATCH_FILEWRITE_ERROR,"out newFile write");
  314. if (decompressPlugin) check_dec(decompressPlugin->decError);
  315. check(hpatch_FALSE,patch_result,"patch run");
  316. }
  317. if (newData.out_length!=newData.base.streamSize){
  318. LOG_ERR("out newFile dataSize %" PRIu64 " != diffFile saved newDataSize %" PRIu64 " ERROR!\n",
  319. newData.out_length,newData.base.streamSize);
  320. check_on_error(HPATCH_FILEDATA_ERROR);
  321. }
  322. printf(" patch ok!\n");
  323. printf("checksum after patch...\n");
  324. if(!check_upfile_and_save(filetype, diffInfos.diffInfo.newDataSize, newData.m_file->offset)) {
  325. printf("patch %s ok.\n", oldFileName);
  326. //wdt_cpu_reboot();
  327. } else {
  328. printf("checksum after patch fail.\n");
  329. result = HPATCH_HPATCH_ERROR;
  330. }
  331. clear:
  332. _isInClear=hpatch_TRUE;
  333. check(hpatch_TFileStreamOutput_close(&newData),HPATCH_FILECLOSE_ERROR,"out newFile close");
  334. check(hpatch_TFileStreamInput_close(&diffData),HPATCH_FILECLOSE_ERROR,"diffFile close");
  335. check(hpatch_TFileStreamInput_close(&oldData),HPATCH_FILECLOSE_ERROR,"oldFile close");
  336. _free_mem(temp_cache);
  337. printf("\nhpatchz time: %d ms\n",(xTaskGetTickCount()-time0));
  338. return result;
  339. }
  340. #endif