From: Antoni Adaszkiewicz Date: Tue, 30 Aug 2022 15:21:01 +0000 (+0200) Subject: Add files from libtota and tota-ua, necessary for easier review of the next commit. X-Git-Tag: accepted/tizen/unified/20221220.041635~18 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=7a36ec4f606a6a41a976f82d91e96369a366bcc5;p=platform%2Fcore%2Fsystem%2Fupgrade.git Add files from libtota and tota-ua, necessary for easier review of the next commit. The code is imported from following: -> platform/core/system/libtota, SHA1: d36348f (ss_bsdiff: Change the search function) -> platform/core/system/tota-ua, SHA1: 681435d (Fix fprintf format warning) Change-Id: I783799ed335f03bc69c287f6d85092b6dbff9b21 --- diff --git a/src/delta-ua/engine/SS_ApplyPatch.c b/src/delta-ua/engine/SS_ApplyPatch.c new file mode 100755 index 0000000..bc9e86b --- /dev/null +++ b/src/delta-ua/engine/SS_ApplyPatch.c @@ -0,0 +1,115 @@ +/*- + * Copyright 2003-2005 Colin Percival + * Copyright 2012 Matthew Endsley + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted providing that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Modifications are made in reimplementing suffix sort array generation + * and how the data is read and written to.Iterative part replaced the + * recursive implementation to avoid buffer overflow problems + */ +#include +#include +#include "SS_PatchDelta.h" +#include "fota_common.h" +#include "sha1.h" +#include "SS_Engine_Errors.h" +#include "SS_FSUpdate.h" + +#include "ss_bspatch_common.h" +#include +#include <7zFile.h> +#include <7zVersion.h> +#include +#include + + +int SS_ApplyBsdiff(char *oldfile, char *newfile, char *patch, SinkFn sink, void *token, SHA1_CTX * ctx1) +{ + UInt64 unpackSize = 0; + CFileSeqInStream inStream; + ISeqOutStream outStream; + unsigned char *buf_res = NULL; + unsigned char *new_data = NULL; + char buf[256]; + ssize_t new_size = 0; + int result = E_SS_FAILURE; + + FileSeqInStream_CreateVTable(&inStream); + File_Construct(&inStream.file); + FileOutStream_CreateVTable((CFileOutStream *) & outStream); + + if (InFile_Open(&inStream.file, patch) != 0) + return E_SS_FAILURE; + + UInt64 i; + CLzmaDec state; + unsigned char header[LZMA_PROPS_SIZE + 8]; + + RINOK(SeqInStream_Read(&inStream.s, header, sizeof(header))); + + unpackSize = 0; + for (i = 0; i < 8; i++) + unpackSize += (UInt64) header[LZMA_PROPS_SIZE + i] << (i * 8); + + LzmaDec_Construct(&state); + RINOK(LzmaDec_Allocate(&state, header, LZMA_PROPS_SIZE, &g_Alloc)); + + //decompress the patch file into buf_res + buf_res = (unsigned char *)SS_Malloc(unpackSize); + if (!buf_res) { + LOGE("Bad memory allocation\n"); + goto Cleanup; + } + result = Decode2(&state, &outStream, &inStream.s, &unpackSize, buf_res); + + LzmaDec_Free(&state, &g_Alloc); + File_Close(&inStream.file); + + if (result != S_SS_SUCCESS) { + LOGE("Error decompression failed with code : [%d]\n", result); + goto Cleanup; + } + //apply patch using buffer decoded by Decode2 + result = apply_patch(oldfile, buf_res, &new_data, &new_size); + if (result != S_SS_SUCCESS) + goto Cleanup; + + result = (sink(new_data, new_size, token) < new_size) ? E_SS_FAILURE : S_SS_SUCCESS; + if (result != S_SS_SUCCESS) { + strerror_r(errno, buf, sizeof(buf)); + LOGE("short write of output: %d (%s)\n", errno, buf); + goto Cleanup; + } + + if (ctx1) + SHA1Update(ctx1, new_data, new_size); +Cleanup: + if (new_data) + SS_Free(new_data); + if (buf_res) + SS_Free(buf_res); + File_Close(&inStream.file);//wgid: 27007 + return result; + +} diff --git a/src/delta-ua/engine/SS_Common.c b/src/delta-ua/engine/SS_Common.c new file mode 100755 index 0000000..b0815ea --- /dev/null +++ b/src/delta-ua/engine/SS_Common.c @@ -0,0 +1,186 @@ +/* + * libtota + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "SS_ImageUpdate.h" +#include "SS_Engine_Errors.h" +#include "SS_Common.h" + +#include "ua_types.h" +#include "fota_tar.h" +#include "fota_common.h" +#include "sha1.h" + +void SS_Progress(void *pbUserData, SS_UINT32 uPercent) +{ + LOG("Progress before\n"); + LOGL(LOG_SSENGINE, "Progress.. (%u %%)\n", uPercent); + LOG("Progress after:\n"); + ((ua_data_t *) pbUserData)->ui_progress(pbUserData, uPercent); +} + +/* Prints a string like the C printf() function */ +SS_UINT32 SS_Trace(const char *aFormat, ...) +{ +#if 0 + LOGL(LOG_SSENGINE, aFormat); +#else + char temp[4096]; + va_list list; + + va_start(list, aFormat); + vsnprintf(temp, sizeof(temp), aFormat, list); + va_end(list); + + LOGL(LOG_SSENGINE, "%s\n", temp); +#endif + return S_SS_SUCCESS; +} + +long SS_FSTrace(const unsigned short *aFormat, ...) +{ + va_list list; + + va_start(list, aFormat); + vprintf((const char *)aFormat, list); + va_end(list); + + return S_SS_SUCCESS; +} + +long SS_ResetTimerA(void) +{ + //LOG("%s \n", __func__); + + return S_SS_SUCCESS; +} + +long SS_GetDelta(void *pbUserData, unsigned char *pbBuffer, SS_UINT32 dwStartAddressOffset, SS_UINT32 dwSize) +{ + int ret = S_SS_SUCCESS; + int readCount = 0; + FILE *fp; + long itemOffset = 0; + + ua_data_t *ua_data = (ua_data_t *) pbUserData; + ua_part_info_t *ua_partition = ua_data->parti_info; + ua_update_data_t *ua_update_data = ua_data->update_data; + + LOGL(LOG_SSENGINE, "SS_GetDelta offset 0x%x(%u), size 0x%x(%u)\n", + dwStartAddressOffset, dwStartAddressOffset, dwSize, dwSize); + + itemOffset = tar_get_item_offset(ua_update_data->ua_delta_path, ua_partition->ua_subject_name); + if (itemOffset < 0) + return E_SS_OPENFILE_ONLYR; + + fp = fopen(ua_update_data->ua_delta_path, "r"); + if (!fp) { + LOGL(LOG_SSENGINE, "open file %s failed.\n", ua_update_data->ua_delta_path); + return E_SS_OPENFILE_ONLYR; + } + + if (fseek(fp, itemOffset + dwStartAddressOffset, 0) == -1) + ret = E_SS_READ_ERROR; + else { + readCount = fread(pbBuffer, 1, dwSize, fp); + if (readCount != dwSize) { + LOGL(LOG_SSENGINE, "error in read size\n"); + ret = E_SS_READ_ERROR; + } + } + fclose(fp); + + return ret; +} + +int SS_CalculateFileSha(char *filename, long int filesize, unsigned char calculated_sha1[SHA_DIGEST_SIZE]) +{ + + FILE *fp = NULL; + int ulResult = S_SS_SUCCESS; + long int chunk = 20*1024*1024; + char buf[256]; + uint8_t *buffer = NULL; + + fp = fopen(filename, "rb"); + if (fp == NULL) { + strerror_r(errno, buf, sizeof(buf)); + LOGE("failed to open \"%s\": %s\n", filename, buf); + ulResult = E_SS_FAILURE; + goto Cleanup; + } + + buffer = SS_Malloc(chunk); + if (!buffer) { + strerror_r(errno, buf, sizeof(buf)); + LOGE("failed to allocate memory for \"%s\": %s\n", filename, buf); + ulResult = E_SS_FAILURE; + goto Cleanup; + } + + ssize_t bytes_read = 0; + SHA1_CTX sha_ctx; + SHA1Init(&sha_ctx); + + while (filesize > 0) { + if (filesize < chunk) { + bytes_read = fread(buffer, 1, filesize, fp); + if (bytes_read != filesize) { + LOGE("short read of \"%s\" (%ld bytes of %ld)\n", filename, (long)bytes_read, filesize); + ulResult = E_SS_FAILURE; + goto Cleanup; + } + SHA1Update(&sha_ctx, buffer, filesize); + break; + } else { + bytes_read = fread(buffer, 1, chunk, fp); + if (bytes_read != chunk) { + LOGE("short read of \"%s\" (%ld bytes of %ld)\n", filename, (long)bytes_read, filesize); + ulResult = E_SS_FAILURE; + goto Cleanup; + } + SHA1Update(&sha_ctx, buffer, chunk); + filesize -= chunk; + } + } + + SHA1Final(calculated_sha1, &sha_ctx); + +Cleanup: + if (fp) + fclose(fp); + if (buffer) + SS_Free(buffer); + return ulResult; +} + +void hex_digest(char * sha1, char *buffer, int size) +{ + for (int i = 0; i < size; i++) { + snprintf(&buffer[i * 2], (size * 2) - (i * 2) + 1, "%02x", sha1[i]); + } +} diff --git a/src/delta-ua/engine/SS_Common.h b/src/delta-ua/engine/SS_Common.h new file mode 100755 index 0000000..6e75a46 --- /dev/null +++ b/src/delta-ua/engine/SS_Common.h @@ -0,0 +1,71 @@ +/* + * libtota + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "SS_MultiProcessUpdate.h" +#include "SS_FSUpdate.h" +#include "SS_ImageUpdate.h" +#include "SS_Engine_Errors.h" +#include "SS_Engine_Update.h" + +#include "ua_types.h" + +#define MAX_PATH 256 + +#define NAND_BLOCK_BITS 18 // 0x40000 +#define NAND_PAGE_BITS 12 // 0x1000 + +#if defined(PART_W) || defined(PART_WB1) || defined(PART_W3G) || defined(PART_TINY) \ + || defined(PART_HIGGS) || defined(PART_KIRAN) || defined(PART_KIRANLTE) || defined(PART_ORBIS) +#define UA_RAM_SIZE 64*1024*1024 // it sould be same 0x4000000 in xml. +#else +#define UA_RAM_SIZE 512*1024*1024 // it sould be same 0x20000000 in xml. +#endif + +#define FS_ID_MAX_LEN 4 +#define DP_HEADER_SIZE 36 +#define DP_START_OFFSET 0 +#define BACKUPBUFFER_NUM 4 +#define SIZE_4GB (0Xffffffff) + +/*******[ Multiprocess API sample implementation ]******/ +#define _NOEXEC_ +#define SAMPLE_PROCS_NUM (0) +#define EXTRA_ARGS (3) +#define HANDLE_RUN_PROC "handle_run_process" + +struct status_header_page { + unsigned char preamble[5]; // state·Î »ç¿ëÇÒ ¼ö ÀÖÀ½, FOTA, SBLB, ZIMG, PLRM, MDEM, DONE, FAILµî + unsigned long format; //ÃÖÁ¾ return °ª, ¾Æ·¡ °¢ image¿¡ ´ëÇÑ engineÀÇ return°ªÀ» DM error table·Î º¯°æµÈ °ª + unsigned long reserved; // Not used + unsigned long flexStatus; // Not used + unsigned long apfwStatus; //zImage update¿¡ ´ëÇÑ engineÀÇ return °ª + unsigned long apffsStatus; //platform update¿¡ ´ëÇÑengineÀÇreturn °ª + unsigned long apuaStatus; //sbl update¿¡ ´ëÇÑengineÀÇreturn °ª + unsigned long bpfwStatus; //modem update¿¡ ´ëÇÑengineÀÇreturn °ª + unsigned long bpuaStatus; +}; + +void SS_unicode_to_char(const char *src, char *dest, int size); + +#ifndef SHA_DIGEST_SIZE +#define SHA_DIGEST_SIZE 20 // To avoid creating dependencies on sha1.h +#endif +int SS_CalculateFileSha(char *filename, long int filesize, unsigned char calculated_sha1[SHA_DIGEST_SIZE]); +void hex_digest(char * sha1, char *buffer, int size); diff --git a/src/delta-ua/engine/SS_Engine_Errors.h b/src/delta-ua/engine/SS_Engine_Errors.h new file mode 100755 index 0000000..c9e2daa --- /dev/null +++ b/src/delta-ua/engine/SS_Engine_Errors.h @@ -0,0 +1,116 @@ +/* + * libtota + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + SS_Engine Errors + + 0xAxx Series define INPUT/UA Errors + + 0xBxx Series define Delta Errors + + 0xCxx Series define System Errors + + 0xDxx Series define Engine Errors + + 0xExx Series define any Other Errors + +*/ + +#ifndef __SS_Engine_ERRORS__ +#define __SS_Engine_ERRORS__ + +#define S_SS_SUCCESS (0) /*! Success Code */ +#define E_SS_FAILURE (1) /*! Failure Code */ + +/* INPUT Processing errors */ + +/* invocation errors */ +#define E_SS_BAD_PARAMS (0xA00) /**< error in a run parameter */ +#define E_SS_FSINVALIDNODEPARAMS (0xA01) /* Failed to Parse the Params to verify NODE */ +#define E_SS_FSBADNODES (0xA02) /* Failed to verify NODE for FS */ +#define E_SS_FSBADDELTA (0xA03) /* Delta File does NOT contain required information on FS */ +#define E_SS_FSBADATTRIBUTES (0xA04) /* Failed to parse attribute data */ +#define E_SS_FSFAILEDTOOPENPATCHINFO (0xA05) /*Failed to open patch list file having details of PATCH info */ +#define E_SS_FSFAILEDTOPARSEDELTACNT (0xA06) /* Failed to parse the PATCH count information */ +#define E_SS_FSFAILEDTOPARSEDELTAINFO (0xA07) /* Failed to parse the Delta patch information */ + +/* update package errors */ +#define E_SS_PKG_TOO_LONG (0xA08) /**< expected length error */ +#define E_SS_PKG_CORRUPTED (0xA09) /**< structural error */ +#define E_SS_SOURCE_CORRUPTED (0xA10) /**< signature error */ + +/*Delta Errors*/ + +#define E_SS_FSBADPATCH (0xB00) /*File Patch Does NOT match the signature */ +#define E_SS_FSSHA_MISMATCH (0xB01) /*Could NOT produce expected Target SHA for file */ +#define E_SS_IMGBADDELTA (0xB02) /* Failed to parse attribute data */ +#define E_SS_IMGBADPATCH (0xB03) /*Image Patch Does NOT match the signature */ +#define E_SS_IMGSHA_MISMATCH (0xB04) /*Could NOT produce expected Target SHA for Image */ +#define E_SS_SHAPRASE_FAILED (0xB05) /*Could NOT Parse SHA */ + +/* SYSTEM errors */ + +/* Resources errors */ +#define E_SS_NOT_ENOUGH_RAM (0xC00) /**< given RAM is not enough */ +#define E_SS_BAD_RAM (0xC01) /**< does not behave as RAM */ +#define E_SS_MALLOC_ERROR (0xC02) /**< memory allocation failure */ + +/* Image update Error codes */ +#define E_SS_WRITE_ERROR (0xC03) /**< flash writing failure */ +#define E_SS_ERASE_ERROR (0xC04) /**< flash erasing failure */ +#define E_SS_READ_ERROR (0xC05) /**< flash reading failure */ + +/*File System Error codes */ +#define E_SS_OPENFILE_ONLYR (0xC06) /**< file does not exist */ +#define E_SS_OPENFILE_WRITE (0xC07) /**< RO or no access rights */ +#define E_SS_DELETEFILE_NOFILE (0xC08) /**< file does not exist */ +#define E_SS_DELETEFILE (0xC09) /**< no access rights */ +#define E_SS_RESIZEFILE (0xC10) /**< cannot resize file */ +#define E_SS_READFILE_SIZE (0xC11) /**< cannot read specified size*/ +#define E_SS_CLOSEFILE_ERROR (0xC12) /**< cannot close file handle */ +#define E_SS_FAILED_CREATING_SYMBOLIC_LINK (0xC13) /**< Failed creating symbolic link */ +#define E_SS_CANNOT_CREATE_DIRECTORY (0xC14) /**< Failed creating directory */ +#define E_SS_FSMEMORYERROR (0xC15) /* Failed to allocate Memory */ +#define E_SS_FILENAMELENERROR (0xC16) /* Failed to serve filename length */ + +/*Engine errors */ + +#define E_SS_NOT_ENOUGH_RAM_FOR_OPERATION2 (0xD00) /**< There is not enough RAM to run with operation=2 (Dry update) */ +#define E_SS_DELTA_FILE_TOO_LONG (0xD01) /**< Delta file too long - curropted */ +#define E_SS_ERROR_IN_DELETES_SIG (0xD02) /**< Mismatch between deletes sig and delta deletes buffers signature */ +#define E_SS_DELTA_IS_CORRUPT (0xD03) /**< Delta file is corrupt: signature mismatch between delta header signature and calculated signature */ +#define E_SS_SOURCE_FILE_SIG_MISMATCH (0xD04) /**< File signature does not match signature */ +#define E_SS_TARGET_SIG_MISMATCH (0xD05) /**< Signature for the target buffer does not match the one stored in the delta file */ +#define E_SS_INVALID_BACKUP (0xD06) /**< Too many dirty buffers */ +#define E_SS_UPI_VERSION_MISMATCH (0xD07) /**< UPI version mismatch between UPI and delta */ +#define E_SS_PARTITION_NAME_NOT_FOUND (0xD08) /**< Partition name is different in delta and in UPI data */ +#define E_SS_NO_SPACE_LEFT (0xD09) /**< There is not enough flash to update or install the files */ +#define E_SS_INVALID_DP_HEADER (0xD10) /**< Deployment Package header is invalid */ +#define E_SS_INVALID_DP_WRONG_SIGNATURE (0xD11) /**< Deployment Package signature is invalid */ +#define E_SS_FSFAILEDTOBACKUPPATCHINFO (0xD12) /* Failed to create backup file to write Delta patch info data */ +#define E_SS_FSUPDATEFAILED (0xD13) /*FS Failed during UPGRADE */ +#define E_SS_FSSRCBACKUPFAILED (0xD14) /*Failed to backup FS */ +#define E_SS_FSSRCCURRUPTED (0xD15) /*Could NOT update FS as SRC seems to be corrupted */ +#define E_SS_IMGUPDATEFAILED (0xD16) /*IMG Failed during UPGRADE */ +#define E_SS_IMGSRCBACKUPFAILED (0xD17) /*Failed to backup IMG */ +#define E_SS_IMGRECOVERYWRITEFAILED (0xD18) /*Failed to write patched Recovery IMG */ +#define E_SS_IMGSRCCURRUPTED (0xD19) /*Could NOT update IMG as SRC seems to be corrupted */ +#define E_SS_IMGFLASHWRITEFAIL (0xD20) /*Failed to write Patched IMG data to flash */ +#define E_SS_PATCHFILE_DEL_ERROR (0xD21) /*Failed to Clear/Del Patched SRC file */ + +#endif diff --git a/src/delta-ua/engine/SS_FSUpdate.c b/src/delta-ua/engine/SS_FSUpdate.c new file mode 100755 index 0000000..8f382fd --- /dev/null +++ b/src/delta-ua/engine/SS_FSUpdate.c @@ -0,0 +1,1314 @@ +/* + * tota-ua + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define _XOPEN_SOURCE 600 +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "SS_Common.h" + +#include "fota_common.h" +#include "ua_types.h" + +static int feature_support_capability; + +enum smack_label_type { + SMACK_LABEL_ACCESS, + SMACK_LABEL_EXEC, + SMACK_LABEL_MMAP, + SMACK_LABEL_TRANSMUTE, + SMACK_LABEL_IPIN, + SMACK_LABEL_IPOUT, +}; + +#define SMACK_LABEL_LEN 255 + +/************************************************************ + * common functions + ************************************************************/ +void SS_create_dir(char *pathname, int mode) +{ + char *p; + int r; + + /* Strip trailing '/' */ + if (pathname[strlen(pathname) - 1] == '/') + pathname[strlen(pathname) - 1] = '\0'; + + /* Try creating the directory. */ + r = mkdir(pathname, mode); + + if (r != 0) { + /* On failure, try creating parent directory. */ + p = strrchr(pathname, '/'); + if (p != NULL) { + *p = '\0'; + SS_create_dir(pathname, 0755); + *p = '/'; + r = mkdir(pathname, mode); + } + } + if (r != 0) { + if (r != EEXIST && r != -1) + LOG("Could not create directory [%s] Error[%d]\n", pathname, r); + } +} + + +void SS_unicode_to_char(const char *src, char *dest, int size) +{ + if (src == NULL) + return; + + strncpy(dest, src, size); +} + +void SS_char_to_unicode(const char *src, char *dest, int size) +{ + if (src == NULL) + return; + + strncpy(dest, src, size); +} + +long SS_recursive_folder_creater(const char *path, const mode_t mode) { + + if (path == 0) { + LOGL(LOG_SSENGINE, "Bad path param value \n"); + return -E_SS_BAD_PARAMS; + } + + if (path[0] == '\0') { + LOGL(LOG_SSENGINE, "Path empty \n"); + return -E_SS_FILENAMELENERROR; + } + + char input_path[MAX_PATH] = {'\0'}; + char temppath[MAX_PATH] = {'\0'}; + + strncpy(input_path, path, MAX_PATH - 1); + + if (input_path[0] == '/') { + temppath[0] = '/'; + } + + char *path_token; + char *path_pos = input_path; + + int temppath_current_len = (temppath[0] == '/'); + + while((path_token = strtok_r(path_pos, "/", &path_pos))) { + + int path_token_len = strnlen(path_token, MAX_PATH-temppath_current_len); + strncat(temppath, path_token, path_token_len); + temppath_current_len += path_token_len; + + int mkd_res = mkdir(temppath, mode); + + if(mkd_res != 0 && errno != EEXIST) { + LOGL(LOG_SSENGINE,"cannot create dir %s\n system error: %d error: %m\n", temppath, errno); + return -E_SS_CANNOT_CREATE_DIRECTORY; + } + + if(temppath_current_len < (MAX_PATH - 1)) { + strncat(temppath, "/", 1); + } + } + return 0; +} + +long +SS_CopyFile(const char *strFromPath, const char *strToPath) +{ + int fd1, fd2; + int readCount = 0, writeCount = 0; + char buf[1 << 15]; // copy 32KB wise + int ret = 0; + + char path1[MAX_PATH] = { '\0' }; + char path2[MAX_PATH] = { '\0' }; + + if (!strFromPath || !strToPath) { + LOGE("NULL file name find. Abort.\n"); + return -1; + } + + SS_unicode_to_char((const char *)strFromPath, (char *)path1, MAX_PATH - 1); + SS_unicode_to_char((const char *)strToPath, (char *)path2, MAX_PATH - 1); + + //LOGL(LOG_SSENGINE, "%s -> %s \n", path1, path2); + + fd1 = open(path1, O_RDONLY); + if (fd1 < 0) + return E_SS_OPENFILE_ONLYR; + ret = SS_OpenFile(strToPath, ONLY_W, (long *)&fd2); + if (ret != S_SS_SUCCESS || fd2 < 0) { + close(fd1); + LOGE(" SS_OpenFile fail leaved path1:%s | path2:%s\n", path1, path1); + return E_SS_WRITE_ERROR; + } + + while ((readCount = read(fd1, buf, sizeof(buf))) > 0) { + writeCount = write(fd2, buf, readCount); + if (writeCount != readCount) { + LOGE(" read %d, but write %d, abort.\n", readCount, + writeCount); + ret = E_SS_WRITE_ERROR; + break; + } + } + + close(fd1); + fsync(fd2); + close(fd2); + //LOGL(LOG_INFO, " leaved path1:%s | path2:%s\n", path1, path2); + + return ret; +} + +long SS_DeleteFile(const char *strPath) +{ + char path[MAX_PATH] = { '\0' }; + int ret = 0; + + SS_unicode_to_char((const char *)strPath, (char *)path, MAX_PATH - 1); + //LOGL(LOG_SSENGINE, "%s\n", path); + ret = unlink(path); + if (ret == 0) + return S_SS_SUCCESS; + + LOGE("failed to delete path [%s] unlink value: %d, errno: %d\n", path, ret, errno); + if (ret < 0 && errno == ENOENT) + return S_SS_SUCCESS; + return E_SS_DELETEFILE; +} + +int SS_unlink_cbf(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf) +{ + int rv = remove(fpath);//returns zero on success and -1 on failure + + if (rv) { + perror(fpath); + LOGE("path : %s, remove value: %d, errno: %d\n", fpath, rv, errno); + } + return rv; +} +long SS_DeleteFolder(const char *strPath) +{ + //runs till either tree is exhausted or when unlink_cbf returns non zero value. + return ((long)nftw(strPath, SS_unlink_cbf, 64, FTW_DEPTH | FTW_PHYS) == 0) ? S_SS_SUCCESS : E_SS_FAILURE; +} + +long SS_DeleteFolderEmpty(const char *strPath) +{ + + int ret = 0; + char path[MAX_PATH] = { '\0' }; + + SS_unicode_to_char((const char *)strPath, (char *)path, MAX_PATH - 1); + //LOGL(LOG_SSENGINE, "%s\n", path); + ret = rmdir(path); + if ((ret == 0) + || ((ret < 0) && ((errno == ENOENT) || (errno == ENOTEMPTY)))) { + LOGL(LOG_SSENGINE, "rmdir value: %d, errno: %d\n", ret, errno); + return S_SS_SUCCESS; + } + LOGE("rmdir value: %d, errno: %d\n", ret, errno); + return E_SS_FAILURE; +} + +long SS_CreateFolder(const char *strPath) +{ + mode_t mode = 0; + int ret = 0; + char path[MAX_PATH] = { '\0' }; + + SS_unicode_to_char((const char *)strPath, (char *)path, MAX_PATH - 1); + mode = S_IRUSR /*Read by owner */ | + S_IWUSR /*Write by owner */ | + S_IXUSR /*Execute by owner */ | + S_IRGRP /*Read by group */ | + S_IWGRP /*Write by group */ | + S_IXGRP /*Execute by group */ | + S_IROTH /*Read by others */ | + S_IWOTH /*Write by others */ | + S_IXOTH /*Execute by others */ ; + + LOGL(LOG_SSENGINE, "%s, mode:0x%x\n", path, mode); + + ret = mkdir(path, mode); + + if (ret == 0 || ((ret == -1) && (errno == EEXIST))) { + return S_SS_SUCCESS; + } else if ((ret == -1) && (errno == ENOENT)) { //maybe multi directory problem + //do//Recursive Function + //{ + ret = SS_recursive_folder_creater(path, mode); + if (ret == S_SS_SUCCESS) { + ret = mkdir(path, mode); //After creating all the depth Directories we try to create the Original one again. + if (ret == 0) + return S_SS_SUCCESS; + else + return E_SS_FAILURE; + } else { + return E_SS_FAILURE; + } + //} + //while(ret != 0); + + } else { + return E_SS_FAILURE; + } +} + +mode_t SS_get_mode(E_RW_TYPE wFlag) +{ + switch (wFlag) { + case ONLY_R: + //LOGL(LOG_SSENGINE, " RDONLY \n"); + return O_RDONLY; + case ONLY_W: + //LOGL(LOG_SSENGINE, " WRONLY \n"); + return O_WRONLY | O_CREAT; + case BOTH_RW: + //LOGL(LOG_SSENGINE, " RDWR \n"); + return O_RDWR | O_CREAT; + default: + //LOGL(LOG_SSENGINE, " Unknown \n"); + return 0; + } +} + +long +SS_OpenFile(const char *strPath, E_RW_TYPE wFlag, long *pwHandle) +{ + mode_t mode; + char path[MAX_PATH] = { '\0' }; + + SS_unicode_to_char((const char *)strPath, (char *)path, MAX_PATH - 1); + + mode = SS_get_mode(wFlag); + //LOGL(LOG_SSENGINE, "Path:%s wFlag:%d Mode:%d\n", path, wFlag, mode); + + if (mode & O_CREAT) { + //LOGL(LOG_SSENGINE, " open() S_IRWXU\n"); + *pwHandle = open(path, mode, S_IRWXU); + } else { + //LOGL(LOG_SSENGINE, " open() %d\n", mode); + *pwHandle = open(path, mode); + } + if (*pwHandle == -1) { + *pwHandle = 0; + LOGE(" First open() with error %d\n", errno); + if (wFlag == ONLY_R) { + LOGE(" error in ONLY_R return E_SS_OPENFILE_ONLYR\n"); + return E_SS_OPENFILE_ONLYR; + } + + //if we need to open the file for write or read/write then we need to create the folder (in case it does not exist) + if ((wFlag != ONLY_R) && (errno == ENOENT)) { + char dir[MAX_PATH] = { '\0' }; + char dirShort[MAX_PATH] = { '\0' }; + int i = 0; + //copy the full file path to directory path variable + while (path[i] != '\0') { + dir[i] = path[i]; + i++; + } + LOGL(LOG_SSENGINE, " copy dir[]=%s\n", dir); + //search for the last '/' char + while (dir[i--] != '/') ; + dir[i + 1] = '\0'; + + SS_char_to_unicode((const char *)dir, + (char *)dirShort, MAX_PATH - 1); + + if (SS_CreateFolder(dirShort)) { + LOGE(" Fail create folder, Leave SS_OpenFile\n"); + return E_SS_OPENFILE_WRITE; + } + + *pwHandle = open(path, mode); + if (*pwHandle == -1) { + *pwHandle = 0; + LOGE(" After successful creating folder, fail open() with error %d\n", errno); + return E_SS_OPENFILE_WRITE; + } + } else { + LOG(" fail open() *pwHandle:%ld\n", *pwHandle); + return E_SS_OPENFILE_WRITE; + } + } + + //LOGL(LOG_SSENGINE, " Successful open() *pwHandle:%ld\n", *pwHandle); + + return S_SS_SUCCESS; +} + +long SS_ResizeFile(long wHandle, SS_UINT32 dwSize) +{ + int ret = 0; + + LOGL(LOG_SSENGINE, "handle %ld, dwSize %d\n", wHandle, errno); + + if (wHandle) + ret = ftruncate(wHandle, dwSize); + else + ret = E_SS_RESIZEFILE; + + LOGL(LOG_SSENGINE, "ret %d handle %ld %d\n", ret, wHandle, errno); + + return ret; +} + +long SS_CloseFile(long wHandle) +{ + int ret = 0; + LOGL(LOG_SSENGINE, "wHandle = %ld\n", wHandle); + + if (wHandle) { + ret = fsync(wHandle); + if (ret < 0) { + LOG(" fsync Failed with return value: %d\n", ret); + return E_SS_WRITE_ERROR; + } + LOG(" fsync after write: %d\n", ret); + ret = close(wHandle); + } + + if (ret == 0) + return S_SS_SUCCESS; + + return E_SS_CLOSEFILE_ERROR; +} + +long +SS_WriteFile(long wHandle, + SS_UINT32 dwPosition, + unsigned char *pbBuffer, SS_UINT32 dwSize) +{ + int ret = 0; + + LOGL(LOG_SSENGINE, "Handle:%ld , Pos:%u , Size: %u\n", wHandle, + dwPosition, dwSize); + + ret = lseek(wHandle, dwPosition, SEEK_SET); + if (ret < 0) { + LOGE(" lseek failed with return value: %d\n", ret); + LOGL(LOG_SSENGINE, "lseek errno=%d\n", errno); + return E_SS_WRITE_ERROR; + } + + ret = write(wHandle, pbBuffer, dwSize); + if (ret < 0 || ret != dwSize) { + LOGE(" Failed with return value: %d\n", ret); + LOGL(LOG_SSENGINE, "ret=%d, dwSize=%u write errno=%d\n", + ret, (unsigned int)dwSize, errno); + return E_SS_WRITE_ERROR; + } + LOGL(LOG_SSENGINE, "leave Bytes Write: %d\n", ret); + + return S_SS_SUCCESS; +} + +long SS_MoveFile(const char *strFromPath, const char *strToPath) +{ + int ret = 0; + struct stat sbuf; + char path1[MAX_PATH] = { '\0' }; + char path2[MAX_PATH] = { '\0' }; + + if (!strFromPath || !strToPath) + return -1; //should never happen + + SS_unicode_to_char(strFromPath, (char *)path1, MAX_PATH - 1); + SS_unicode_to_char(strToPath, (char *)path2, MAX_PATH - 1); + + LOGL(LOG_INFO, "entered path1:%s | path2:%s\n", path1, path2); + ret = stat(path1, &sbuf); + if (ret < 0) { + LOGE("stat failed with return value: %d errno: %d\n", ret, errno); + return E_SS_FAILURE; + } + ret = rename(path1, path2); + if (ret < 0) { + LOGL(LOG_INFO, "rename fail with code [%d], try to create dir if errno is 2\n", errno); + if (errno == 2) { + char * file_name = strrchr(path2, '/'); + *file_name = '\0'; + SS_create_dir(path2, 0755); + *file_name = '/'; + ret = rename(path1, path2); + if (ret < 0) { + LOGE("Move failed, error code [%d]\n", errno); + return E_SS_WRITE_ERROR; + } + } else if (errno == 18) { //EXDEV 18 /* Cross-device link */ + //Moving file across partitions if mount point is different (Extremely rare) + ret = (int)SS_CopyFile(path1, path2); + if (ret != S_SS_SUCCESS) { + LOGE("failed to copy file [%s] result [%d]\n", path1, ret); + return E_SS_WRITE_ERROR; + } + ret = unlink(path1); + if (ret != 0) { + LOGE("failed to unlink [%s] code [%d]\n", path1, errno); + return E_SS_WRITE_ERROR; + } + } else { + LOGE("Move failed, error code [%d]\n", errno); + return E_SS_WRITE_ERROR; + } + } + LOGL(LOG_INFO, "leaved path1:%s | path2:%s\n", path1, path2); + return S_SS_SUCCESS; +} +long SS_SyncFile(long wHandle) +{ + return (-1 == fsync(wHandle)) ? E_SS_FAILURE : S_SS_SUCCESS; +} + +long +SS_ReadFile(long wHandle, + SS_UINT32 dwPosition, + unsigned char *pbBuffer, SS_UINT32 dwSize) +{ + int ret = 0; + +#if 0 + LOG(" %s: Handle:%ld , Pos:%u , Size: %u", __func__, wHandle, + dwPosition, dwSize); +#endif + ret = lseek(wHandle, dwPosition, SEEK_SET); + if (ret < 0) { + LOGE("Handle:%ld , Pos:%u , Size: %u\n", wHandle, dwPosition, + dwSize); + LOGE("lseek failed with return value: %d\n", ret); + return E_SS_READ_ERROR; + } + ret = read(wHandle, pbBuffer, dwSize); + if (ret < 0) { + LOGE("Handle:%ld , Pos:%u , Size: %u\n", wHandle, dwPosition, + dwSize); + LOGE("read failed with return value: %d\n", ret); + return E_SS_READ_ERROR; + } + + if (ret != dwSize && ((ret + dwPosition) != (unsigned long)SS_GetFileSize(wHandle))) + return E_SS_READ_ERROR; + + pbBuffer[ret] = '\0'; +#if 0 + LOGL(LOG_DEBUG, "Bytes Read: %d\n", ret); +#endif + return S_SS_SUCCESS; +} + +long SS_GetFileSize(long wHandle) +{ + int ret = 0; + + + ret = lseek(wHandle, 0, SEEK_END); + + if (ret == -1) { + LOGE(" lseek errno: %d\n", errno); + return E_SS_READFILE_SIZE; + } + LOGL(LOG_SSENGINE, "handle=%d Returning Size = %ld(0x%x)\n", + (int)wHandle, (long int)ret, ret); + + return ret; +} + +long SS_Unlink(char *pLinkName) +{ + int ret = 0; + char path[MAX_PATH] = { '\0' }; + //enumFileType fileType = FT_REGULAR_FILE; + + + SS_unicode_to_char((const char *)pLinkName, (char *)path, MAX_PATH - 1); + + ret = unlink(path); + if (ret < 0 && errno != ENOENT) { + LOGE("unlink failed with return value: %d\n", ret); + return E_SS_FAILURE; + } + LOGL(LOG_SSENGINE, "unlink with return value: %d\n", ret); + + return S_SS_SUCCESS; +} + +long +SS_VerifyLinkReference(char *pLinkName, char *pReferenceFileName) +{ + int ret = 0; + char path[MAX_PATH] = { '\0' }; + char linkedpath[MAX_PATH] = { '\0' }; + char refpath[MAX_PATH] = { '\0' }; + + + SS_unicode_to_char((const char *)pLinkName, (char *)path, MAX_PATH - 1); + SS_unicode_to_char((const char *)pReferenceFileName, (char *)refpath, MAX_PATH - 1); + + ret = readlink(path, linkedpath, MAX_PATH); + if (ret < 0) { + LOGE("readlink failed with return value: %d\n", ret); + return E_SS_FAILURE; + } + + if ((memcmp(&linkedpath, &refpath, ret)) != 0) { + LOGE("not same linked path\n"); + return E_SS_FAILURE; + } + LOGL(LOG_SSENGINE, "same linked path\n"); + + return S_SS_SUCCESS; +} + +long +SS_Link(void *pbUserData, char *pLinkName, char *pReferenceFileName) +{ + int ret = 0; + char sympath[MAX_PATH] = { '\0' }; + char refpath[MAX_PATH] = { '\0' }; + //enumFileType fileType = FT_SYMBOLIC_LINK; + struct stat sbuf; + + SS_unicode_to_char((const char *)pLinkName, (char *)sympath, MAX_PATH - 1); + SS_unicode_to_char((const char *)pReferenceFileName, (char *)refpath, MAX_PATH - 1); + + ret = symlink(refpath, sympath); + if (ret != 0) { + LOGE(" symlink failed with return value: %d, errno: %d\n", ret, errno); + + if (errno == EEXIST) { + ret = lstat(sympath, &sbuf); + LOGL(LOG_SSENGINE, "symlink LSTAT with return value: %d\n", ret); + if (ret >= 0) { + if (S_ISREG(sbuf.st_mode)) { + LOGL(LOG_SSENGINE, " stat->st_mode = regular file, To be deleted and create a LINK \n"); + SS_DeleteFile(sympath); + SS_Link(pbUserData, pLinkName, pReferenceFileName); + } + } + if (SS_VerifyLinkReference(pLinkName + , pReferenceFileName) == S_SS_SUCCESS) { + return S_SS_SUCCESS; + } else { + return E_SS_FAILURE; + } + } else if (errno == ENOENT) {//to handle cases where new symlink points to a new symlink yet to be created + return errno; + } else { + return E_SS_FAILURE; + } + } + //LOGL(LOG_SSENGINE, "symlink with return value: %d\n", ret); + + return S_SS_SUCCESS; +} + +long SS_GetFileType(char *pLinkName, enumFileType * fileType) +{ + int ret = 0; + char path[MAX_PATH] = { '\0' }; + struct stat sbuf; + + //LOGL(LOG_SSENGINE, "\n"); + SS_unicode_to_char((const char *)pLinkName, (char *)path, MAX_PATH - 1); + + ret = lstat(path, &sbuf); + if (ret < 0) { + ret = stat(path, &sbuf); + if (ret < 0) { + LOGE("stat failed with return value: %d errno: %d\n", + ret, errno); + *fileType = FT_MISSING; + return S_SS_SUCCESS; + } + } + //LOGL(LOG_SSENGINE, " sbuf.st_mode: %d\n", sbuf.st_mode); + //LOGL(LOG_SSENGINE, " S_ISREG(sbuf.st_mode): %d\n", S_ISREG(sbuf.st_mode)); + //LOGL(LOG_SSENGINE, " S_ISLNK(sbuf.st_mode): %d\n", S_ISLNK(sbuf.st_mode)); + + if (S_ISLNK(sbuf.st_mode)) { + //LOGL(LOG_SSENGINE, " stat->st_mode = symbolic link file\n"); + *fileType = FT_SYMBOLIC_LINK; + return S_SS_SUCCESS; + } + + if (S_ISREG(sbuf.st_mode)) { + //LOGL(LOG_SSENGINE, " stat->st_mode = regular file\n"); + *fileType = FT_REGULAR_FILE; + return S_SS_SUCCESS; + } + + if (S_ISDIR(sbuf.st_mode)) { + //LOGL(LOG_SSENGINE, " stat->st_mode = regular file\n"); + *fileType = FT_FOLDER; + return S_SS_SUCCESS; + } + LOGE("failed to lstat, err : %d\n", ret); + return E_SS_FAILURE; +} + +char SS_a2ch(int value) +{ + char set_value = 0; + + LOGL(LOG_SSENGINE, "%d\n", value); + + switch (value) { + case '1': + set_value = 0x01; + break; + case '2': + set_value = 0x02; + break; + case '3': + set_value = 0x03; + break; + case '4': + set_value = 0x04; + break; + case '5': + set_value = 0x05; + break; + case '6': + set_value = 0x06; + break; + case '7': + set_value = 0x07; + break; + case '8': + set_value = 0x08; + break; + case '9': + set_value = 0x09; + break; + case '0': + set_value = 0x00; + break; + default: + LOGL(LOG_SSENGINE, "Wrong attribute value: %d\n", value); + + } + LOGL(LOG_SSENGINE, "SS_a2ch : %c\n", set_value); + + return set_value; +} + +void SS_chtoa(int value, char *str) +{ + char *pStr = str; + + LOGL(LOG_SSENGINE, "%d\n", value); + + switch (value) { + case 1: + *pStr = '1'; + break; + case 2: + *pStr = '2'; + break; + case 3: + *pStr = '3'; + break; + case 4: + *pStr = '4'; + break; + case 5: + *pStr = '5'; + break; + case 6: + *pStr = '6'; + break; + case 7: + *pStr = '7'; + break; + case 8: + *pStr = '8'; + break; + case 9: + *pStr = '9'; + break; + case 0: + *pStr = '0'; + break; + default: + LOGL(LOG_SSENGINE, "Wrong attribute value: %d\n", value); + } +} + +static inline char *SS_get_xattr_name(enum smack_label_type type) +{ + switch (type) { + case SMACK_LABEL_ACCESS: + return "security.SMACK64"; + case SMACK_LABEL_EXEC: + return "security.SMACK64EXEC"; + case SMACK_LABEL_MMAP: + return "security.SMACK64MMAP"; + case SMACK_LABEL_TRANSMUTE: + return "security.SMACK64TRANSMUTE"; + case SMACK_LABEL_IPIN: + return "security.SMACK64IPIN"; + case SMACK_LABEL_IPOUT: + return "security.SMACK64IPOUT"; + default: + /* Should not reach this point */ + return NULL; + } +} + +int SS_smack_lsetlabel(const char *path, const char *label, enum smack_label_type type) +{ + if (path == NULL) { + LOGE("Path is NULL\n"); + return -1; + } + + char *xattr_name = SS_get_xattr_name(type); + if (xattr_name == NULL) { + LOGE("Failed get xattr name\n"); + return -1; + } + + /* Check validity of labels for LABEL_TRANSMUTE */ + if (type == SMACK_LABEL_TRANSMUTE && label != NULL) { + if (!strncmp(label, "0", strlen("0"))) { + label = NULL; + } else if (!strncmp(label, "1", strlen("0"))) { + label = "TRUE"; + } else { + return -1; + } + } + + if (label == NULL || label[0] == '\0') { + return lremovexattr(path, xattr_name); + } else { + int len = strnlen(label, SMACK_LABEL_LEN + 1); + if (len > SMACK_LABEL_LEN) { + return -1; + } + return lsetxattr(path, xattr_name, label, len, 0); + } +} + +/*! + ******************************************************************************* + * Set file attributes.

+ * + * The file attributes token (\a ui8pAttribs) is defined at generation time. + * If attributes are not defined explicitly, they are given the following, + * OS-dependent values: + * \li Windows: _foo_ro_ for R/O files, _foo_rw_ for R/W files + * \li Linux: _foo_oooooo:xxxx:yyyy indicating the file mode, uid, and gid + * (uid and gid use capitalized hex digits as required) + * + * \param pbUserData Optional opaque data-structure to pass to IPL + * functions + * \param ui16pFilePath File path + * \param ui32AttribSize Size of \a ui8pAttribs + * \param ui8pAttribs Attributes to set + * + * \return S_SS_SUCCESS on success or < 0 on error + ******************************************************************************* + */ + +long SS_SetFileAttributes(const char *ui16pFilePath, + const SS_UINT32 ui32AttribSize, + const unsigned char *ui8pAttribs) +{ + static char tmpAttribs[512]; + static char tmpSmackAttribs[512]; + char *tp; + char *endstr; + char *saveptr; + char *smack_value, *psmack; + uid_t setUserID = 0; + gid_t setGroupID = 0; + mode_t setFileMode = 0; + const char attrDelim[2] = ":"; + + char setFilePath[MAX_PATH] = { '\0' }; + struct stat sbuf; + int ret = 0; + char *smack_attr_pos = NULL; + int has_cap = 0; + char cap_raw[100]; + int cap_len; + /*ACL */ + int has_acl = 0; + char acl_raw[256]; + int acl_len; + + if (NULL == ui16pFilePath) { + LOGL(LOG_SSENGINE, "ui16pFilePath NULL [error]\n"); + return E_SS_BAD_PARAMS; + } else if (NULL == ui8pAttribs) { + LOGL(LOG_SSENGINE, "ui8pAttribs NULL [error]\n"); + return E_SS_BAD_PARAMS; + } else if (0 == ui32AttribSize) { + LOGL(LOG_SSENGINE, "ui32AttribSize 0\n"); + return S_SS_SUCCESS; + } + + SS_unicode_to_char((const char *)ui16pFilePath, (char *)setFilePath, MAX_PATH - 1); + + ret = lstat(setFilePath, &sbuf); + if (ret < 0) { + ret = stat(setFilePath, &sbuf); + if (ret < 0) { + LOGL(LOG_SSENGINE, " stat failed with return value: %d\n", ret); + return E_SS_FAILURE; + } else { + if (S_ISLNK(sbuf.st_mode)) { + LOGL(LOG_SSENGINE, " stat->st_mode = symbolic link file\n"); +// return S_RB_SUCCESS; // sybolic link should be set mode. + } + if (S_ISREG(sbuf.st_mode)) + LOGL(LOG_SSENGINE, " stat->st_mode = regular file\n"); + if (S_ISDIR(sbuf.st_mode)) + LOGL(LOG_SSENGINE, " stat->st_mode = directory\n"); + } + + LOGL(LOG_SSENGINE, "ui16pFilePath = %s\n", setFilePath); + LOGL(LOG_SSENGINE, "ui32AttribSize = %u\n", ui32AttribSize); + LOGL(LOG_SSENGINE, "ui8pAttribs = %s\n", ui8pAttribs); + + } + memset(tmpAttribs, 0x0, sizeof(tmpAttribs)); + memcpy(tmpAttribs, ui8pAttribs, (size_t) ui32AttribSize-1); + smack_attr_pos = tmpAttribs; + tp = strtok_r(tmpAttribs, attrDelim, &saveptr); + + // Get FileMode + if (tp != NULL) { + smack_attr_pos += strlen(tp); + smack_attr_pos++; + setFileMode = strtol(tp, &endstr, 8); + tp = strtok_r(NULL, attrDelim, &saveptr); + } + // Get UserID + if (tp != NULL) { + smack_attr_pos += strlen(tp); + smack_attr_pos++; + setUserID = (uid_t) strtol(tp, &endstr, 10); + tp = strtok_r(NULL, attrDelim, &saveptr); + } + // Get GroupID + if (tp != NULL) { + smack_attr_pos += strlen(tp); + smack_attr_pos++; + setGroupID = (gid_t) strtol(tp, &endstr, 10); + } + + if (feature_support_capability) { + // Get Capability + has_cap = 0; + if (*smack_attr_pos != '\0') { + char *cap_mark = "capability=0x"; + int cap_mark_len = strlen(cap_mark); + psmack = strstr(smack_attr_pos, cap_mark); + if (psmack) { + int cap_hex_len; + int i; + char ch1, ch2; + int raw1, raw2; + + tp = strstr(psmack, ":"); + smack_attr_pos = tp + 1; + memset(tmpSmackAttribs, 0x0, sizeof(tmpSmackAttribs)); + memcpy(tmpSmackAttribs, psmack+cap_mark_len, + (int)tp - (int)psmack - cap_mark_len); + + // convert hexadecimal into raw data + cap_hex_len = strlen(tmpSmackAttribs); + cap_len = cap_hex_len/2; + memset(cap_raw, 0x00, sizeof(cap_raw)); + for (i = 0; i < cap_len; i++) { + ch1 = tmpSmackAttribs[i*2]; + ch2 = tmpSmackAttribs[i*2+1]; + if ((ch1 >= '0') && (ch1 <= '9')) raw1 = ch1 - '0'; + else if ((ch1 >= 'a') && (ch1 <= 'f')) raw1 = ch1 - 'a' + 10; + else if ((ch1 >= 'A') && (ch1 <= 'F')) raw1 = ch1 - 'A' + 10; + else raw1 = 0; + if ((ch2 >= '0') && (ch2 <= '9')) raw2 = ch2 - '0'; + else if ((ch2 >= 'a') && (ch2 <= 'f')) raw2 = ch2 - 'a' + 10; + else if ((ch2 >= 'A') && (ch2 <= 'F')) raw2 = ch2 - 'A' + 10; + else raw2 = 0; + + cap_raw[i] = raw1*16 + raw2; + } + LOGL(LOG_SSENGINE, "[Cap] %s (cap_len=%d)\n", tmpSmackAttribs, cap_len); + has_cap = 1; + } + + } + // Get ACL + has_acl = 0; + if (*smack_attr_pos != '\0') { + char *acl_mark = "acl_access=0x"; + int acl_mark_len = strlen(acl_mark); + psmack = strstr(smack_attr_pos, acl_mark); + if (psmack) { + int acl_hex_len; + int i; + char ch1, ch2; + int raw1, raw2; + + tp = strstr(psmack, ":"); + smack_attr_pos = tp + 1; + memset(tmpSmackAttribs, 0x0, sizeof(tmpSmackAttribs)); + memcpy(tmpSmackAttribs, psmack+acl_mark_len, + (int)tp - (int)psmack - acl_mark_len); + + // convert hexadecimal into raw data + acl_hex_len = strlen(tmpSmackAttribs); + acl_len = acl_hex_len/2; + memset(acl_raw, 0x00, sizeof(acl_raw)); + for (i = 0; i < acl_len; i++) { + ch1 = tmpSmackAttribs[i*2]; + ch2 = tmpSmackAttribs[i*2+1]; + if ((ch1 >= '0') && (ch1 <= '9')) raw1 = ch1 - '0'; + else if ((ch1 >= 'a') && (ch1 <= 'f')) raw1 = ch1 - 'a' + 10; + else if ((ch1 >= 'A') && (ch1 <= 'F')) raw1 = ch1 - 'A' + 10; + else raw1 = 0; + if ((ch2 >= '0') && (ch2 <= '9')) raw2 = ch2 - '0'; + else if ((ch2 >= 'a') && (ch2 <= 'f')) raw2 = ch2 - 'a' + 10; + else if ((ch2 >= 'A') && (ch2 <= 'F')) raw2 = ch2 - 'A' + 10; + else raw2 = 0; + + acl_raw[i] = raw1*16 + raw2; + } + LOG("[ACL] %s (acl_len=%d)\n", tmpSmackAttribs, acl_len); + has_acl = 1; + } + + } + } + + // Get Smack value -> Set Smack value + if (*smack_attr_pos != '\0') { + SS_smack_lsetlabel(setFilePath, NULL, SMACK_LABEL_ACCESS); + SS_smack_lsetlabel(setFilePath, NULL, SMACK_LABEL_EXEC); + SS_smack_lsetlabel(setFilePath, NULL, SMACK_LABEL_MMAP); + SS_smack_lsetlabel(setFilePath, NULL, SMACK_LABEL_TRANSMUTE); + + psmack = strstr(smack_attr_pos, "access=\""); + if (psmack) { + memset(tmpSmackAttribs, 0x0, sizeof(tmpSmackAttribs)); + memcpy(tmpSmackAttribs, psmack, sizeof(tmpSmackAttribs) - 1); + smack_value = strtok_r(tmpSmackAttribs, "\"", &saveptr); + if (smack_value) { + smack_value = strtok_r(NULL, "\"", &saveptr); + //LOGL(LOG_SSENGINE, "[SMACK_LABEL_ACCESS] smack_value=%s\n", smack_value); + if (smack_value) { + ret = SS_smack_lsetlabel(setFilePath, smack_value, SMACK_LABEL_ACCESS); + if (ret < 0) + LOGL(LOG_SSENGINE, "SS_smack_lsetlabel() failed\n"); + } + } + } + psmack = strstr(smack_attr_pos, "execute=\""); + if (psmack) { + memset(tmpSmackAttribs, 0x0, sizeof(tmpSmackAttribs)); + memcpy(tmpSmackAttribs, psmack, sizeof(tmpSmackAttribs) - 1); + smack_value = strtok_r(tmpSmackAttribs, "\"", &saveptr); + if (smack_value) { + smack_value = strtok_r(NULL, "\"", &saveptr); + //LOGL(LOG_SSENGINE, "[SMACK_LABEL_EXEC] smack_value=%s\n", smack_value); + if (smack_value) { + ret = SS_smack_lsetlabel(setFilePath, smack_value, SMACK_LABEL_EXEC); + if (ret < 0) + LOGL(LOG_SSENGINE, "SS_smack_lsetlabel() failed\n"); + } + } + } + psmack = strstr(smack_attr_pos, "mmap=\""); + if (psmack) { + memset(tmpSmackAttribs, 0x0, sizeof(tmpSmackAttribs)); + memcpy(tmpSmackAttribs, psmack, sizeof(tmpSmackAttribs) - 1); + smack_value = strtok_r(tmpSmackAttribs, "\"", &saveptr); + if (smack_value) { + smack_value = strtok_r(NULL, "\"", &saveptr); + //LOGL(LOG_SSENGINE, "[SMACK_LABEL_MMAP] smack_value=%s\n", smack_value); + if (smack_value) { + ret = SS_smack_lsetlabel(setFilePath, smack_value, SMACK_LABEL_MMAP); + if (ret < 0) + LOGL(LOG_SSENGINE, "SS_smack_lsetlabel() failed\n"); + } + } + } + psmack = strstr(smack_attr_pos, "transmute=\""); + if (psmack) { + memset(tmpSmackAttribs, 0x0, sizeof(tmpSmackAttribs)); + memcpy(tmpSmackAttribs, psmack, sizeof(tmpSmackAttribs) - 1); + smack_value = strtok_r(tmpSmackAttribs, "\"", &saveptr); + if (smack_value) { + smack_value = strtok_r(NULL, "\"", &saveptr); + //LOGL(LOG_SSENGINE, "[SMACK_LABEL_TRANSMUTE] smack_value=%s\n", smack_value); + if (smack_value) { + if (strcasecmp(smack_value, "TRUE") == 0) + ret = SS_smack_lsetlabel(setFilePath, "1", SMACK_LABEL_TRANSMUTE); + else + ret = SS_smack_lsetlabel(setFilePath, "0", SMACK_LABEL_TRANSMUTE); + if (ret < 0) + LOGL(LOG_SSENGINE, "SS_smack_lsetlabel() failed\n"); + } + } + } + } + + // Set UserID,GroupID + if (lchown(setFilePath, setUserID, setGroupID)) { + // debug start + LOGL(LOG_SSENGINE, "%s chown error\n", __func__); + LOGL(LOG_SSENGINE, "%s setUserID = %d\n", __func__, setUserID); + LOGL(LOG_SSENGINE, "%s setGroupID = %d\n", __func__, setGroupID); + LOGL(LOG_SSENGINE, "%s chown errno = %d\n", __func__, errno); + // debug end + + return E_SS_FAILURE; + } + + // mode is always 0777 at symlink file. It doesn't need to call chmod(). + if (S_ISLNK(sbuf.st_mode)) { + LOGL(LOG_SSENGINE, " stat->st_mode = symbolic link file\n"); + return S_SS_SUCCESS; + } + + if (chmod(setFilePath, setFileMode)) { + LOGL(LOG_SSENGINE, "%s chmod error\n", __func__); + return E_SS_FAILURE; + } + + if (feature_support_capability) { + char buf[256]; + if (has_cap) { + if (setxattr(setFilePath, "security.capability", (void*)cap_raw, cap_len, 0) < 0) { + strerror_r(errno, buf, sizeof(buf)); + LOGL(LOG_SSENGINE, "cap setxattr() failed: %s\n", buf); + } + } + + if (has_acl) { + if (setxattr(setFilePath, "system.posix_acl_access", (void*)acl_raw, acl_len, 0) < 0) { + strerror_r(errno, buf, sizeof(buf)); + LOGL(LOG_SSENGINE, "Acl setxattr() failed: %s\n", buf); + } + //LOG("Acl setxattr() :")asfd + } + } + + //LOGL(LOG_SSENGINE, "%s SUCCESS\n", __func__); + + return S_SS_SUCCESS; +} + + +long SS_CompareFileAttributes(void) +{ + return S_SS_SUCCESS; +} + + + +#define MAX_INT 0xefffffff + +/* vrm functions */ +long +SS_GetAvailableFreeSpace(const char *partition_name, + SS_UINT32 *available_flash_size) +{ +// *available_flash_size = MAX_INT; +/* +#define IDENT_SBL "sbl" +#define IDENT_PLATFORM "platform" +#define IDENT_BOOT "boot" +*/ + int result = 0; + char path[MAX_PATH] = { '\0' }; + + SS_unicode_to_char(partition_name, (char *)path, MAX_PATH - 1); + //LOGL(LOG_SSENGINE, "Enter %s path=%s\n", __func__, path); + struct statfs vfs; + + //LOGL(LOG_SSENGINE, "path=%s\n", path); + result = statfs(path, &vfs); + if (result < 0) { + LOGE("failed to fstatfs, err : %d errno: %d\n", result, errno); + return -1; + } + + *available_flash_size = ((long long)vfs.f_bsize * (long long)vfs.f_bavail >= (long long)SIZE_4GB) ? SIZE_4GB : vfs.f_bsize * vfs.f_bavail; + if (*available_flash_size == 0) { + *available_flash_size = 0x80000; //Same as Legecy RB + LOGE("available_flash_size=%u(vfs.f_bsize=%d vfs.f_bavail=%d\n", + (unsigned int)*available_flash_size, (int)vfs.f_bsize, (int)vfs.f_bavail); + return 0; // Same as Legecy RB + } + return 0; +} + +#ifdef HEAP_PROFILING + int max_mem; + int cur_mem; +#endif +/*******[ Multiprocess API sample implementation ]******/ +void *SS_Malloc(SS_UINT32 size) +{ + void *p = malloc(size); + + if (p) + memset(p, 0, size); +#ifdef HEAP_PROFILING + cur_mem += size; + if (cur_mem > max_mem) { + max_mem = cur_mem; + LOGL(LOG_SSENGINE, "New chunk [%d] assigned making heap [%d]\n", size, cur_mem); + } +#endif + + return p; +} + +void SS_Free(void *pMemBlock) +{ +#ifdef HEAP_PROFILING + cur_mem -= malloc_usable_size(pMemBlock); + LOGL(LOG_SSENGINE, "Old chunk [%d] removed making heap [%d]\n", malloc_usable_size(pMemBlock), cur_mem); +#endif + if (pMemBlock) + free(pMemBlock); +} + +SS_UINT32 SS_GetMaxNumProcess(void) +{ + return SAMPLE_PROCS_NUM; +} + +void* SS_WaitForProcess(const void *handle, SS_UINT32* process_exit_code) +{ + pid_t pid; + *process_exit_code = 0; + + // processes + if (handle) + #ifdef _NOEXEC_ + pid = waitpid((pid_t)handle, (int *)process_exit_code, 0); + #else + pid = wait((int*)process_exit_code); + #endif + + else + pid = wait((int*)process_exit_code); + + if (pid < 0) + return NULL; + + if (!WIFEXITED(*process_exit_code)) { + *process_exit_code = (char)WTERMSIG(*process_exit_code); + LOG("Wait Error\n"); + } else { + *process_exit_code = (char)WEXITSTATUS(*process_exit_code); + } + + return (void*)pid; +} +unsigned long SS_GetMaxProcRamSize(void) +{ + return UA_RAM_SIZE; +} + +void* SS_RunProcess(void) +{ + pid_t child_pid; + + #ifdef _NOEXEC_ + child_pid = fork(); + #else + child_pid = vfork(); + #endif + + if (child_pid == -1) { + LOG("Fork failed.\n"); + return (void *)-1; + } + + // This is the child + if (child_pid == 0) { + #ifdef _NOEXEC_ + #ifdef _TIZEN_SSENGINE//bota + SS_HandleProcessRequest(pbUserData, argc, argv); + #endif + LOGL(LOG_SSENGINE, "SS_RunProcess was called - SS_HandleProcessRequest\n"); + exit(0); + #else + + char **params = NULL; + int i; + + params = (char **)SS_Malloc((argc+EXTRA_ARGS) *sizeof(char*)); + if (!params) { + LOG("params allocation failed\n"); + return NULL; + } + // prepare child data, as it's forbidden to change data after vfork + params[0] = strdup(((sample_userdata*)user)->exec_path); + params[1] = strdup("handle_run_process"); + params[2] = strdup(((sample_userdata*)user)->delta_path); + + for (i = 0; i < argc; i++) + params[i+EXTRA_ARGS] = strdup(argv[i]); + + // no need to free allocated memory - execv takes care of it + execv(params[0], (char**)params); + _exit(-1); // if we're here, execv has failed + #endif + } else { + return (void *)child_pid; + } +} + +int SS_get_feature_support_capability(void) +{ + return feature_support_capability; +} + +void SS_set_feature_support_capability(int val) +{ + feature_support_capability = val; +} diff --git a/src/delta-ua/engine/SS_FSUpdate.h b/src/delta-ua/engine/SS_FSUpdate.h new file mode 100755 index 0000000..0cc839b --- /dev/null +++ b/src/delta-ua/engine/SS_FSUpdate.h @@ -0,0 +1,356 @@ +/* + * libtota + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*! + ******************************************************************************* + * \file SS_FileSystemUpdate.h + * + * \brief UPI FS Update API + ******************************************************************************* + */ +#ifndef _SS_FILESYSTEM_UPDATE_H_ +#define _SS_FILESYSTEM_UPDATE_H_ + +#include "SS_Engine_Update.h" +#include "SS_Engine_Errors.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/*! + * File access modes + */ + typedef enum tag_RW_TYPE { + ONLY_R, //!< Read-only + ONLY_W, //!< Write-only + BOTH_RW //!< Read-write + } E_RW_TYPE; + +/*! + ******************************************************************************* + * Copy file.

+ * + * Must create the path to the new file as required. Must overwrite any contents + * in the old file, if any. Must check if the source file is a symbolic link. + * If it is, instead create a new symbolic link using \ref SS_Link. + * + * \param strFromPath Path to old file + * \param strToPath Path to new file + * + * \return S_SS_SUCCESS on success or an \ref SS_vRM_Errors.h error code + ******************************************************************************* + */ + + long SS_CopyFile(const char *strFromPath, const char *strToPath); + +/*! + ******************************************************************************* + * Move (rename) file.

+ * + * \param strFromPath Path to old file location + * \param strToPath Path to new file location + * + * \return S_SS_SUCCESS on success or an \ref SS_vRM_Errors.h error code + ******************************************************************************* + */ + + long SS_MoveFile(const char *strFromPath, const char *strToPath); + +/*! + ******************************************************************************* + * Delete file.

+ * + * Must return success if the file is deleted or didn't exist. + * + * \param strPath Path to file + * + * \return S_SS_SUCCESS on success, E_SS_DELETEFILE if the file cannot be + * deleted, or an \ref SS_vRM_Errors.h error code + ******************************************************************************* + */ + + long SS_DeleteFile(const char *strPath); + +/*! + ******************************************************************************* + * Delete folder.

+ * + * Must return success if the folder is now deleted or didn't exist. + * + * \param strPath Path to folder + * + * \return S_SS_SUCCESS on success or an \ref SS_vRM_Errors.h error code + ******************************************************************************* + */ + + long SS_DeleteFolder(const char *strPath); + +/*! + ******************************************************************************* + * Create folder.

+ * + * Must return success if the folder is created or already existsed. It is + * recommended that the new folder's attributes are a copy of its parent's + * attributes. + * + * \param strPath Path to folder + * + * \return S_SS_SUCCESS on success or an \ref SS_vRM_Errors.h error code + ******************************************************************************* + */ + + long SS_CreateFolder(const char *strPath); + +/*! + ******************************************************************************* + * Open file.

+ * + * Must create the the file (and the path to the file) if it doesn't exist. Must + * open in binary mode. + * + * \param strPath Path to file + * \param wFlag Read/write mode, an \ref E_RW_TYPE value + * \param pwHandle (out) File handle + * + * \return S_SS_SUCCESS on success, E_SS_OPENFILE_ONLYR if attempting to open a + * non-existant file in R/O mode, E_SS_OPENFILE_WRITE if there is an + * error opening a file for writing, or an \ref SS_vRM_Errors.h error code + ******************************************************************************* + */ + + long SS_OpenFile(const char *strPath, E_RW_TYPE wFlag, long *pwHandle); + +/*! + ******************************************************************************* + * Set file size. + * + * \param wHandle File handle + * \param dwSize New file size + * + * \return S_SS_SUCCESS on success or an \ref SS_vRM_Errors.h error code + ******************************************************************************* + */ + + long SS_ResizeFile(long wHandle, SS_UINT32 dwSize); + +/*! + ******************************************************************************* + * Close file. + * + * \param wHandle File handle + * + * \return S_SS_SUCCESS on success or an \ref SS_vRM_Errors.h error code + ******************************************************************************* + */ + + long SS_CloseFile(long wHandle); + +/*! + ******************************************************************************* + * Write data to a specified position within a file.

+ * + * Must return success if the block is written or at least resides in + * non-volatile memory. Use \ref SS_SyncFile to commit the file to storage. + * + * \param wHandle File handle + * \param dwPosition Position within the file to which to write + * \param pbBuffer Data to write + * \param dwSize Size of \a pbBuffer + * + * \return S_SS_SUCCESS on success, or an \ref SS_vRM_Errors.h error code + ******************************************************************************* + */ + + long SS_WriteFile(long wHandle, SS_UINT32 dwPosition, unsigned char *pbBuffer, SS_UINT32 dwSize); + +/*! + ******************************************************************************* + * Commit file to storage.

+ * + * Generally called after \ref SS_WriteFile. + * + * \param wHandle File handle + * + * \return S_SS_SUCCESS on success or an \ref SS_vRM_Errors.h error code + ******************************************************************************* + */ + long SS_SyncFile(long wHandle); + +/*! + ******************************************************************************* + * Read data from a specified position within a file. + * If fewer bytes than requested are available in the specified position, this + * function should read up to the end of file and return S_SS_SUCCESS. + * + * \param wHandle File handle + * \param dwPosition Position within the file from which to read + * \param pbBuffer Buffer to contain data + * \param dwSize Size of data to read + * + * \return S_SS_SUCCESS on success or an \ref SS_vRM_Errors.h error code + ******************************************************************************* + */ + + long SS_ReadFile(long wHandle, SS_UINT32 dwPosition, unsigned char *pbBuffer, SS_UINT32 dwSize); + +/*! + ******************************************************************************* + * Get file size. + * + * \param wHandle File handle + * + * \return File size, -1 if file not found, or < -1 on error + ******************************************************************************* + */ + long SS_GetFileSize(long wHandle); + +/*! + ******************************************************************************* + * Get free space of a mounted file system. + * + * \param path Name of any directory within the mounted + * file system + * \param available_flash_size (out) Available space + * + * \return S_SS_SUCCESS on success or an \ref SS_vRM_Errors.h error code + ******************************************************************************* + */ + long SS_GetAvailableFreeSpace(const char *path, SS_UINT32 * available_flash_size); + +/*! + ******************************************************************************* + * Remove symbolic link.

+ * + * Must return an error if the file does not exist or is not a symbolic link.

+ * + * If your platform does not support symbolic links, you do not need to + * implement this. + * + * \param pLinkName Link + * + * \return S_SS_SUCCESS on success or an \ref SS_vRM_Errors.h error code + ******************************************************************************* + */ + long SS_Unlink(char *pLinkName); + +/*! + ******************************************************************************* + * Create symbolic link.

+ * + * Must create the path to the link as required. If a file already exists at the + * named location, must return success if the file is a symbolic link or an + * error if the file is a regular file. The non-existance of the target of the + * link must NOT cause an error.

+ * + * If your platform does not support symbolic links, you do not need to + * implement this. + * + * \param pbUserData Optional opaque data-structure to pass to IPL + * functions + * \param pLinkName Path to the link file to create + * \param pReferenceFileName Path to which to point the link + * + * \return S_SS_SUCCESS on success or an \ref SS_vRM_Errors.h error code + ******************************************************************************* + */ + long SS_Link(void *pbUserData, char *pLinkName, char *pReferenceFileName); + +/*! + ******************************************************************************* + * Set file attributes.

+ * + * The file attributes token (\a ui8pAttribs) is defined at generation time. + * If attributes are not defined explicitly, they are given the following, + * OS-dependent values: + * \li Windows: _foo_ro_ for R/O files, _foo_rw_ for R/W files + * \li Linux: _foo_oooooo:xxxx:yyyy indicating the file mode, uid, and gid + * (uid and gid use capitalized hex digits as required) + * + * \param pbUserData Optional opaque data-structure to pass to IPL + * functions + * \param ui16pFilePath File path + * \param ui32AttribSize Size of \a ui8pAttribs + * \param ui8pAttribs Attributes to set + * + * \return S_SS_SUCCESS on success or < 0 on error + ******************************************************************************* + */ + + long SS_SetFileAttributes(const char *ui16pFilePath, + const SS_UINT32 ui32AttribSize, const unsigned char *ui8pAttribs); + +/*! + ******************************************************************************* + * Print status and debug information. + * + * \param aFormat A NULL-terminated printf-like string with support for + * the following tags: + * \li %x: Hex number + * \li %0x: Hex number with leading zeros + * \li %u: Unsigned decimal + * \li %s: NULL-terminated string + * \param ... Strings to insert in \a aFormat + * + * \return S_SS_SUCCESS on success or an \ref SS_vRM_Errors.h error code + ******************************************************************************* + */ + SS_UINT32 SS_Trace(const char *aFormat, ...); + +/** + ******************************************************************************* + * Allocate a memory block. + * + * \param size Memory block size, in blocks + * + * \return A pointer to the memory block on success, NULL on failure + ******************************************************************************* + */ + void *SS_Malloc(SS_UINT32 size); + +/** + ******************************************************************************* + * Free a memory block. + * + * \param pMemBlock Pointer to the memory block + ******************************************************************************* + */ + void SS_Free(void *pMemBlock); + +/** + ******************************************************************************* + * Get capability feature flag value + * + * \return The value of feature_support_capability + ******************************************************************************* + */ + int SS_get_feature_support_capability(void); + +/** + ******************************************************************************* + * Set capability feature flag + * + * \param val The value to set feature_support_capability + ******************************************************************************* + */ + void SS_set_feature_support_capability(int val); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif diff --git a/src/delta-ua/engine/SS_PatchDelta.c b/src/delta-ua/engine/SS_PatchDelta.c new file mode 100755 index 0000000..dd292ee --- /dev/null +++ b/src/delta-ua/engine/SS_PatchDelta.c @@ -0,0 +1,1041 @@ +/* + * libtota + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ua_types.h" +#include "sha1.h" +#include "SS_PatchDelta.h" +#include "fota_common.h" +#include "SS_Engine_Errors.h" +#include "ss_brotli_patch.h" +#include "SS_Common.h" + +extern void *SS_Malloc(unsigned int size); + +typedef struct { + unsigned char *buffer; + ssize_t size; + ssize_t pos; +} MemorySinkInfo; + +ssize_t ss_memorySink(unsigned char *data, ssize_t len, void *token) +{ + MemorySinkInfo *msi = (MemorySinkInfo *) token; + if (msi->size - msi->pos < len) + return -1; + memcpy(msi->buffer + msi->pos, data, len); + msi->pos += len; + return len; +} + +ssize_t ss_fileSink(unsigned char *data, ssize_t len, void *token) +{ + int ss_fd = *(int *)token; + char buf[256]; + ssize_t done = 0; + ssize_t wrote; + while (done < (ssize_t) len) { + wrote = write(ss_fd, data + done, len - done); + if (wrote <= 0) { + if (errno == EINTR || errno == EAGAIN) + continue; // try again + strerror_r(errno, buf, sizeof(buf)); + LOGE("error writing %d bytes: %s\n", (int)(len - done), buf); + return done; + } + done += wrote; + } + return done; +} + +// Take a string 'str' of 40 hex digits and parse it into the 20 +// byte array 'digest'. 'str' may contain only the digest or be of +// the form ":". Return 0 on success, -1 on any +// error. +int ParseSha1(const char *str, uint8_t * digest) +{ + int i; + const char *ps = str; + uint8_t *pd = digest; + for (i = 0; i < SHA_DIGEST_SIZE * 2; ++i, ++ps) { + int digit; + if (*ps >= '0' && *ps <= '9') + digit = *ps - '0'; + else if (*ps >= 'a' && *ps <= 'f') + digit = *ps - 'a' + 10; + else if (*ps >= 'A' && *ps <= 'F') + digit = *ps - 'A' + 10; + else + return -1; + if (i % 2 == 0) { + *pd = digit << 4; + } else { + *pd |= digit; + ++pd; + } + } + if (*ps != '\0') + return -1; + return 0; +} + +//Function to find the start of gzipped part in compressed kernel +//This function will be removed during further optimization of kernel delta +int getOffset(char *zimage_path) +{ + char gzip_header[] = { 31, -117, 8 }; //header value for gzip which needs to be checked + char buf[4] = { 0, }; + int offset = -1;//wgid:14074 + + FILE *f = fopen(zimage_path, "r"); + if (!f) { + LOGE("Fopen failed for path %s\n", zimage_path); + SS_SetUpgradeState(E_SS_OPENFILE_ONLYR); + return -1; + } + fseek(f, 0, SEEK_SET); + while (fread(buf, 1, 3, f) > 0) { + if (gzip_header[0] == buf[0] && gzip_header[1] == buf[1] && gzip_header[2] == buf[2]) { + LOGL(LOG_SSENGINE, "match for %d %d %d found at %d\n", buf[0], buf[1], buf[2], ftell(f) - 3); + offset = ftell(f) - 3;//145599 + break; + } else { + if (fseek(f, -2, SEEK_CUR) < 0) + LOGE("Failed to fseek\n"); + } + } + fclose(f); + return offset; +} + +int SS_LoadPartition(const char *filename, FileInfo * file) +{ + size_t read = 0; + FILE *dev = NULL; + int i; + char buf[256]; + + dev = fopen(filename, "rb"); + if (dev == NULL) { + strerror_r(errno, buf, sizeof(buf)); + LOGE("failed to open partition \"%s\": %s\n", filename, buf); + return -1; + } + + SHA1_CTX sha_ctx; + SHA1Init(&sha_ctx); + + file->data = SS_Malloc(file->size); + if (file->data) { + read = fread(file->data, 1, file->size, dev); + LOGL(LOG_SSENGINE, "Partition size read %d\n", read); + SHA1Update(&sha_ctx, file->data, read); + file->size = read; + } + + unsigned char sha_final[SHA_DIGEST_SIZE] = { 0, }; + SHA1Final(sha_final, &sha_ctx); + for (i = 0; i < SHA_DIGEST_SIZE; ++i) + file->sha1[i] = sha_final[i]; + //LOGL(LOG_SSENGINE, "Final SHA of Source (%s)\n", sha_final); + + file->st.st_mode = 0644; + file->st.st_uid = 0; + file->st.st_gid = 0; + fclose(dev); + return 0; +} + +//extern int write_data_to_blkdev(char* dev_name, int blk_start, int blk_cnt, char* data); + +int SS_LoadFile(const char *filename, FileInfo * file) +{ + char buf[256]; + + file->data = NULL; + //LOGL(LOG_SSENGINE,"SS_LoadFile --- [File name %s]\n",filename); + + if (stat(filename, &file->st) != 0) { + strerror_r(errno, buf, sizeof(buf)); + LOGE("failed to stat \"%s\": %s\n", filename, buf); + return -1; + } + + file->size = file->st.st_size; + file->data = SS_Malloc(file->size); + if (!file->data) { + strerror_r(errno, buf, sizeof(buf)); + LOGE("failed to allocate memory for \"%s\": %s\n", filename, buf); + return -1; + } + + FILE *f = fopen(filename, "rb"); + if (f == NULL) { + strerror_r(errno, buf, sizeof(buf)); + LOGE("failed to open \"%s\": %s\n", filename, buf); + SS_Free(file->data); + file->data = NULL; + return -1; + } + + ssize_t bytes_read = fread(file->data, 1, file->size, f); + if (bytes_read != file->size) { + LOGE("short read of \"%s\" (%ld bytes of %ld)\n", filename, (long)bytes_read, (long)file->size); + SS_Free(file->data); + file->data = NULL; + fclose(f); + return -1; + } + fclose(f); + //LOGL(LOG_SSENGINE,"SS_LoadFile --- [bytes_read %d]\n",bytes_read); + SHA1(file->sha1, file->data, file->size); + return 0; +} + +extern int gvalid_session; +extern void create_dir(char *pathname, int mode); + +/*! + ********************************************************************************* + * SS_UpdateDeltaFS + ********************************************************************************* + * + * @brief + * This is used to apply patch for a file during delta FS upgrade + * + * + * @param + * + * @return 0 - in case of success + * 1 - in case of error during patch application + * + ********************************************************************************* + */ + +int SS_UpdateDeltaFS(const char *source_filename, const char *target_filename, + const char *source_sha1_str, const char *target_sha1_str, int patch_data_size) +{ + uint8_t target_sha1[SHA_DIGEST_SIZE] = { 0, }; + uint8_t source_sha1[SHA_DIGEST_SIZE] = { 0, }; + SHA1_CTX ctx1; + int output; + int retry = 1; + int use_backup = 0; + char *outname = NULL; + int backupsrc = -1; + int result = 0; + char buf[256]; + FileInfo source_file; + FileInfo target_file; + + if (ParseSha1(target_sha1_str, target_sha1) != 0) { + LOGE("failed to parse tgt-sha1 \"%s\"\n", target_sha1_str); + return E_SS_FAILURE; + } + + /* + if battery removed in between update gvalid_session becomes 0 + need to check file integrity in that case + */ + if (0 == gvalid_session) { + if (ParseSha1(source_sha1_str, source_sha1) != 0) { + LOGE("failed to parse tgt-sha1 \"%s\"\n", source_sha1_str); + return E_SS_FAILURE; + } + if (SS_LoadFile(source_filename, &source_file) == 0) { + SS_Free(source_file.data); + + if (memcmp(source_file.sha1, source_sha1, SHA_DIGEST_SIZE) == 0) { + LOGL(LOG_SSENGINE, "Patch Can be applied\n"); + } else if (memcmp(source_file.sha1, target_sha1, SHA_DIGEST_SIZE) == 0) { + LOGL(LOG_SSENGINE, "Patch Already applied\n"); + return S_SS_SUCCESS; + } else { + //Check for backup file SHA + LOGL(LOG_SSENGINE, "Source was currupted, Try loading from backup source\n"); + + if (SS_LoadFile(target_filename, &target_file) == 0) { + SS_Free(target_file.data); + + if (memcmp(target_file.sha1, target_sha1, SHA_DIGEST_SIZE) == 0) { + LOGL(LOG_SSENGINE, "Patch Already applied\n"); + return S_SS_SUCCESS; + } + } + + if (SS_LoadFile(SS_BACKUP_SOURCE, &source_file) == 0) { + SS_Free(source_file.data); + + if (memcmp(source_file.sha1, source_sha1, SHA_DIGEST_SIZE) == 0) { + if (SS_CopyFile(SS_BACKUP_SOURCE, source_filename) != S_SS_SUCCESS) { + strerror_r(errno, buf, sizeof(buf)); + LOGE("copy of backup to \"%s\" failed: %s\n", source_filename, buf); + SS_SetUpgradeState(E_SS_FSUPDATEFAILED); + return E_SS_FAILURE; + } + LOGL(LOG_SSENGINE, + "Patch Can be applied from using backup file as source\n"); + } else { + SS_SetUpgradeState(E_SS_FSSRCCURRUPTED); + return E_SS_FAILURE; + } + } else { + SS_SetUpgradeState(E_SS_FSSRCCURRUPTED); + return E_SS_FAILURE; + } + } + } else { + LOGL(LOG_SSENGINE, "Source was deleted!!\n"); + if (SS_LoadFile(target_filename, &target_file) == 0) { + SS_Free(target_file.data); + + if (memcmp(target_file.sha1, target_sha1, SHA_DIGEST_SIZE) == 0) { + LOGL(LOG_SSENGINE, "Patch Already applied\n"); + return S_SS_SUCCESS; + } + } + + LOGL(LOG_SSENGINE, "Try loading from backup source\n"); + if (SS_LoadFile(SS_BACKUP_SOURCE, &source_file) == 0) { + SS_Free(source_file.data); + + if (memcmp(source_file.sha1, source_sha1, SHA_DIGEST_SIZE) == 0) { + use_backup = 1; + LOGL(LOG_SSENGINE, "Patch Can be applied from using backup file as source\n"); + } else { + SS_SetUpgradeState(E_SS_FSSRCCURRUPTED); + return E_SS_FAILURE; + } + } else { + LOGE(" SS_LoadFile from backup source failed!!\n"); + SS_SetUpgradeState(E_SS_FSSRCCURRUPTED); + return E_SS_FAILURE; + } + } + } + //Now proceed wit patch application since patch can be applied + do { + int enough_space = 0; + size_t free_space = 0; + char *tok; + + if (retry > 0) { + if (use_backup) { + tok = strrchr(source_filename, '/'); + *tok = '\0'; + } + SS_GetAvailableFreeSpace(source_filename, &free_space); + enough_space = (free_space > (256 << 10)) && // 256k (two-block) minimum + (free_space > (patch_data_size * 3 / 2)); // 50% margin of error + if (use_backup) + *tok = '/'; + } + + if (!use_backup) { +#ifndef ENHANCED_BSDIFF + backupsrc = SS_BackupSource(source_filename); + if (backupsrc != 0) { + LOGE("failed to Backup source File:[%s] \n", source_filename); + SS_SetUpgradeState(E_SS_FSSRCBACKUPFAILED); + return E_SS_FAILURE; + } +#endif + } + if (!enough_space) { + LOGL(LOG_SSENGINE, "For %s: free space %ld bytes; enough %d\n", source_filename, (long)free_space, + enough_space); + retry = 0; + use_backup = 1; + unlink(source_filename); + } + //LOGL(LOG_SSENGINE, "For %s: target %ld bytes; free space %ld bytes; enough %d\n", + // source_filename, (long)patch_data_size, (long)free_space, enough_space); + //LOGL(LOG_SSENGINE,"Generate Target Space availabitiy [%d]\n", enough_space); + + SinkFn sink = NULL; + void *token = NULL; + output = -1; + outname = NULL; + + { + // We write the decoded output to ".patch". + //allocate some extra space to allow for concatinating ".patch" with the name + outname = (char *)SS_Malloc(strlen(target_filename) + 10); + if (outname == NULL) { + LOGE("SS_Malloc failed!!\n"); + return E_SS_FAILURE; + } + snprintf(outname, strlen(target_filename) + 10, + "%s.patch", target_filename); + + output = open(outname, O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU); + if (output < 0) { + if (errno == 2) { + char *dir_path = strrchr(outname, '/'); + *dir_path = '\0'; + // need to create directory as the target may be different from source + LOGL(LOG_SSENGINE, "need to create directory [%s]\n", outname); + create_dir(outname, 0755); + *dir_path = '/'; + output = open(outname, O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU); + if (output < 0) { + strerror_r(errno, buf, sizeof(buf)); + LOGE("failed to open output file %s: %s\n", outname, buf); + SS_Free(outname); + return E_SS_FAILURE; + } + } + } + sink = ss_fileSink; + token = &output; + } + SHA1Init(&ctx1); + if (use_backup) + result = SS_ApplyBsdiff(SS_BACKUP_SOURCE, outname, SS_PATCHFILE_SOURCE, sink, token, &ctx1); + else + result = SS_ApplyBsdiff((char *)source_filename, outname, SS_PATCHFILE_SOURCE, sink, token, &ctx1); + if (output >= 0) { + fsync(output); + close(output); + } + + if (result != S_SS_SUCCESS) { + if (retry == 0) { + LOGE("applying patch failed result : [%d]\n", result); + SS_Free(outname);//wgid: 20739 + SS_SetUpgradeState(E_SS_FSUPDATEFAILED); + return E_SS_FAILURE; + } else { + LOGE("applying patch failed; retrying\n"); + SS_Free(outname);//wgid: 20739 + } + } else { + // succeeded; no need to retry + break; + } + } while (retry-- > 0); + + unsigned char current_target_sha1[SHA_DIGEST_SIZE] = { 0, }; + SHA1Final(current_target_sha1, &ctx1); + if (memcmp(current_target_sha1, target_sha1, SHA_DIGEST_SIZE) != 0) { + LOGE("patch did not produce expected sha1\n"); + SS_SetUpgradeState(E_SS_FSSHA_MISMATCH); + if (outname != NULL) + SS_Free(outname); + return E_SS_FAILURE; + } + + // Finally, rename the .patch file to replace the target file. +#ifdef ENHANCED_BSDIFF + if (SS_rename1(outname, target_filename) != 0) { + strerror_r(errno, buf, sizeof(buf)); + LOGE("rename of .patch to \"%s\" failed: %s\n", target_filename, buf); + SS_SetUpgradeState(E_SS_FSUPDATEFAILED); + if (outname != NULL) + SS_Free(outname); + return E_SS_FAILURE; + } +#else + if (rename(outname, target_filename) != 0) { + strerror_r(errno, buf, sizeof(buf)); + LOGE("rename of .patch to \"%s\" failed: %s\n", target_filename, buf); + SS_SetUpgradeState(E_SS_FSUPDATEFAILED); + if (outname != NULL) + SS_Free(outname); + return E_SS_FAILURE; + } + //remove source file if target is not same + if (strcmp(source_filename, target_filename) != 0) + unlink(source_filename); + SS_BackupSourceClear(); +#endif + SS_PatchSourceClear(); + SS_Free(outname); + + return result; +} + +/*! + ********************************************************************************* + * SS_UpdateDeltaKernel + ********************************************************************************* + * + * @brief + * This is used to apply patch for kernel delta during delta Image upgrade + * + * + * @param + * + * @return 0 - in case of success + * 1 - in case of error during patch application + * + ********************************************************************************* + */ + +int SS_UpdateDeltaKernel(ua_dataSS_t * ua_dataSS, int (*write_to_blkdev) (char *, int, int, char *)) +{ + uint8_t target_sha1[SHA_DIGEST_SIZE]; + uint8_t source_sha1[SHA_DIGEST_SIZE]; + FileInfo source_file; + int result = S_SS_SUCCESS; + int blk_cnt, read_count = 0; + int blk_start = 0; + int backupsrc = -1; + int use_backup_img = -1; + FILE *fp = NULL, *wp = NULL, *kp = NULL; + int i = 0, j = 0, file_len = 0; + char *magic = NULL, *file_name = NULL, *tok_buf = NULL, *buf = NULL, a = '0'; + char *saveptr; + char err_buf[256]; + char cmd[1024] = { 0, }; + char source_filename[MAX_FILE_PATH] = { 0, }; + char part_filename[MAX_FILE_PATH] = { 0, }; + int file_num = 0; + SinkFn sink = NULL; + void *tok = NULL; + int output = -1; + char *outname = NULL; + //Kernel Parts are created on unpacking kernel which is then used to apply delta + char *kernel_parts[] = { "decompression_code", + "piggy.gz", + "padding_piggy", + "piggy_trailer" + }; + + if (ParseSha1(ua_dataSS->update_cfg->target_sha1, target_sha1) != 0) { + LOGE("failed to parse tgt-sha1 \"%s\"\n", ua_dataSS->update_cfg->target_sha1); + return E_SS_FAILURE; + } + + source_file.size = ua_dataSS->update_cfg->soure_img_size; + source_file.data = NULL; + if (0 == gvalid_session) { + + if (ParseSha1(ua_dataSS->update_cfg->soure_sha1, source_sha1) != 0) { + LOGE("failed to parse Src-sha1 \"%s\"\n", ua_dataSS->update_cfg->soure_sha1); + return E_SS_FAILURE; + } + + if (SS_LoadPartition(ua_dataSS->parti_info->ua_blk_name, &source_file) == 0) { + if (memcmp(source_file.sha1, source_sha1, SHA_DIGEST_SIZE) == 0) { + LOGL(LOG_SSENGINE, "SS_UpdateDeltaIMG - Patch Can be applied\n"); + + } else if (memcmp(source_file.sha1, target_sha1, SHA_DIGEST_SIZE) == 0) { + LOGL(LOG_SSENGINE, "SS_UpdateDeltaIMG - Patch Already applied\n"); + SS_Free(source_file.data); + return S_SS_SUCCESS; + } else { + SS_Free(source_file.data); + source_file.data = NULL; + LOGL(LOG_SSENGINE, "SS_UpdateDeltaIMG - Source was currupted, Try loading from backup source\n"); + if (SS_LoadPartition(SS_BACKUP_SOURCE, &source_file) == 0) { + if (memcmp(source_file.sha1, source_sha1, SHA_DIGEST_SIZE) == 0) { + use_backup_img = 1; + + LOGL(LOG_SSENGINE, + "SS_UpdateDeltaIMG - Patch Can be applied from using backup file as source\n"); + } else { + SS_SetUpgradeState(E_SS_IMGSRCCURRUPTED); + SS_Free(source_file.data); + return E_SS_FAILURE; + } + } + } + } + } else { //in case of kernel delta need to copy kernel data from blk to buffer + if (SS_LoadPartition(ua_dataSS->parti_info->ua_blk_name, &source_file) != 0) { + SS_SetUpgradeState(E_SS_IMGSRCCURRUPTED); + LOGE("Fatal Error : Kernel block is corrupted\n"); + return E_SS_FAILURE; + } + } + if (use_backup_img == -1) { + backupsrc = SS_BackupSource(ua_dataSS->parti_info->ua_blk_name); + if (backupsrc != 0) { + LOGE("failed to Backup source File:[%s] \n", ua_dataSS->parti_info->ua_blk_name); + SS_Free(source_file.data); + SS_SetUpgradeState(E_SS_IMGSRCBACKUPFAILED); + return E_SS_FAILURE; + } + } + //Cleanup workspace and copy helper executables to it before proceeding + SS_DeleteFolder(SS_KERNEL_WORKSPACE); + create_dir(SS_KERNEL_WORKSPACE, 0755); + SS_CopyFile(SS_GZIP_SOURCE, SS_GZIP_TARGET); + SS_CopyFile(SS_STAT_SOURCE, SS_STAT_TARGET); + SS_CopyFile(SS_DD_SOURCE, SS_DD_TARGET); + + if (tar_get_item_size(ua_dataSS->update_data->ua_delta_path, SS_KERNEL_UNPACK_SCRIPT) > 0) + if (tar_extract_file(ua_dataSS->update_data->ua_delta_path, SS_KERNEL_UNPACK_SCRIPT, SS_KERN_UNPK_SCRIPT_PATH) > 0) + LOGL(LOG_SSENGINE, "Extracted %s successfully\n", SS_KERNEL_UNPACK_SCRIPT); + else { + LOGE("Error in fn tar_extract_file for item %s\n", SS_KERNEL_UNPACK_SCRIPT); + SS_SetUpgradeState(E_SS_DELTA_IS_CORRUPT); + result = E_SS_FAILURE; + goto Cleanup; + } else { + LOGE("Error size is not positive for item %s\n", SS_KERNEL_UNPACK_SCRIPT); + SS_SetUpgradeState(E_SS_DELTA_IS_CORRUPT); + result = E_SS_FAILURE; + goto Cleanup; + } + //Now write the kernel data to the workplace and start applying patch + snprintf(source_filename, sizeof(source_filename) - 1, "%s/%s", SS_KERNEL_WORKSPACE, SS_KERNEL_NAME); + fp = fopen(source_filename, "w"); + if (!fp) { + LOGE("file open error [%s] code [%d]\n", source_filename, errno); + result = E_SS_FAILURE; + goto Cleanup; + } + //write source kernel data to workspace + if (!source_file.data) { + LOGE("source_file.data is null before fwrite"); + result = E_SS_FAILURE; + goto Cleanup; + } + + read_count = fwrite(source_file.data, 1, source_file.size, fp); + if (read_count != source_file.size) { + LOGE("file write error read_count = %d for [%s]\n", read_count, source_filename); + result = E_SS_FAILURE; + goto Cleanup; + } + fclose(fp); + fp = NULL;//wgid: 59313 + + //Unpack source kernel + int offset = getOffset(source_filename); + if (offset < 0) { + LOGE("Failed to get offset\n"); + result = E_SS_FAILURE; + goto Cleanup; + } + snprintf(cmd, sizeof(cmd) - 1, "%s -u %s %s %d", SS_KERN_UNPK_SCRIPT_PATH, SS_KERNEL_WORKSPACE, SS_KERNEL_NAME, + offset); + int ret = _system_cmd_wait(cmd); + LOGL(LOG_SSENGINE, "ret for %s is %d\n", cmd, ret); + + //open delta file, extract kernel delta parts and apply patch to previously unpacked kernel + fp = fopen(SS_PATCHFILE_SOURCE, "r"); + if (fp == NULL) { + LOGE("Failed to open kernel delta patch\n"); + result = E_SS_FAILURE; + goto Cleanup; + } + //read kernel delta header for delta names and size + buf = SS_Malloc(SS_KERNEL_DELTA_HEADER + 1); + if (!buf) {//wgid: 13099 + LOGE("Failed to allocate memory\n"); + result = E_SS_MALLOC_ERROR; + goto Cleanup; + } + ssize_t bytes_read = fread(buf, 1, SS_KERNEL_DELTA_HEADER, fp); + if (bytes_read != SS_KERNEL_DELTA_HEADER) + LOGL(LOG_SSENGINE, "short read of \"%s\" (%ld bytes of %ld)\n", SS_PATCHFILE_SOURCE, (long)bytes_read, (long)SS_KERNEL_DELTA_HEADER); + buf[bytes_read] = '\0'; + + magic = strtok_r(buf, ":", &saveptr); + LOGL(LOG_SSENGINE, "magic: %s\n", magic); + tok_buf = strtok_r(NULL, ":", &saveptr); + if (tok_buf) + file_num = atoi(tok_buf); + + //adjust offset to start of data section before proceeding + ret = fseek(fp, SS_KERNEL_DELTA_HEADER, SEEK_SET); + if (ret != 0) { + LOGE("fseek is failed : errno[%d]\n", ret); + result = E_SS_FAILURE; + goto Cleanup; + } + + while (file_num-- > 0) { + file_name = strtok_r(NULL, ":", &saveptr); + tok_buf = strtok_r(NULL, ":", &saveptr); + if (tok_buf) + file_len = atoi(tok_buf); + j = file_len; + snprintf(source_filename, sizeof(source_filename) - 1, "%s/%s_unpacked/%s", SS_KERNEL_WORKSPACE, SS_KERNEL_NAME, + file_name); + snprintf(part_filename, sizeof(part_filename) - 1, "%s/%s", SS_KERNEL_WORKSPACE, file_name); + wp = fopen(part_filename, "w"); + if (wp == NULL) { + LOGE("Failed to open %s\n", part_filename); + result = E_SS_FAILURE; + goto Cleanup; + } + while (j-- > 0) { + a = fgetc(fp); + fputc(a, wp); + } + fclose(wp); + + //apply bspatch to the unpacked kernel parts + + { + // We write the decoded output to ".patch". + //allocate some extra space to allow for concatinating ".patch" with the name + outname = (char *)SS_Malloc(strlen(source_filename) + 10); + if (outname == NULL) { + SS_SetUpgradeState(E_SS_MALLOC_ERROR); + result = E_SS_FAILURE; + goto Cleanup; + } + snprintf(outname, strlen(source_filename) + 10, "%s.patch", + source_filename); + + output = open(outname, O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU); + if (output < 0) { + strerror_r(errno, err_buf, sizeof(err_buf)); + LOGE("failed to open output file %s: %s\n", outname, err_buf); + result = E_SS_FAILURE; + goto Cleanup; + } + sink = ss_fileSink; + tok = &output; + } + result = SS_ApplyBsdiff(source_filename, outname, part_filename, sink, tok, NULL); + LOGL(LOG_SSENGINE, "GenerateTarget Output is %d and result is %d\n", output, result); + if (output >= 0) { + fsync(output); + close(output); + } + + if (result != S_SS_SUCCESS) { + LOGE("applying patch failed %s\n", source_filename); + if (outname != NULL) + unlink(outname); + goto Cleanup; + } + result = rename(outname, source_filename); + if (result != S_SS_SUCCESS) { + LOGE("fatal error %s\n", source_filename); + goto Cleanup; + } + if (file_name && strcmp(file_name, "piggy") == 0) { + snprintf(cmd, sizeof(cmd) - 1, + "%s/gzip -n -9 -c %s/%s/%s > %s/%s/%s.gz", + SS_KERNEL_WORKSPACE, SS_KERNEL_WORKSPACE, SS_KERNEL_UNPACK_DIR, file_name, + SS_KERNEL_WORKSPACE, SS_KERNEL_UNPACK_DIR, file_name); + result = _system_cmd_wait(cmd); + LOGL(LOG_SSENGINE, "ret for %s = %d\n", cmd, result); + unlink(source_filename); + } + unlink(part_filename); + SS_Free(outname);//wgid :144116 + outname = NULL; + } + //open new kernel file and append kernel parts to it in + snprintf(source_filename, sizeof(source_filename) - 1, "%s/%s", SS_KERNEL_WORKSPACE, SS_KERNEL_TARGET_NAME); + kp = fopen(source_filename, "w"); + if (kp == NULL) { + LOGE("Failed to open %s\n", source_filename); + result = E_SS_FAILURE; + goto Cleanup; + } + for (i = 0; i < 4; i++) { + snprintf(part_filename, sizeof(part_filename) - 1, "%s/%s/%s", SS_KERNEL_WORKSPACE, SS_KERNEL_UNPACK_DIR, + kernel_parts[i]); + wp = fopen(part_filename, "r"); + if (wp == NULL) { + LOGE("Failed to open %s\n", part_filename); + result = E_SS_FAILURE; + fclose(kp); + goto Cleanup; + } + fseek(wp, SEEK_SET, SEEK_END); + j = ftell(wp); + fseek(wp, SEEK_SET, SEEK_SET); + while (j-- > 0) { + a = fgetc(wp); + if (a != EOF) + fputc(a, kp); + else + break; + } + fclose(wp); + unlink(part_filename); + } + fclose(fp); + fp = NULL; + fclose(kp); + + SS_Free(source_file.data); + source_file.data = NULL; + if (SS_LoadFile(source_filename, &source_file) == 0) + result = memcmp(source_file.sha1, target_sha1, SHA_DIGEST_SIZE); + if (result != S_SS_SUCCESS) { + LOGE("patch did not produce expected sha1 \n"); + SS_SetUpgradeState(E_SS_IMGSHA_MISMATCH); + goto Cleanup; + } + //Considering EMMC partition by default + + blk_cnt = ((ua_dataSS->update_cfg->target_img_size - 1) / SECTOR_SIZE) + 1; + result = write_to_blkdev((char *)ua_dataSS->parti_info->ua_blk_name, blk_start, blk_cnt, (char *)source_file.data); + if (result != S_SS_SUCCESS) { + LOGE("write of patched data to %s failed\n", ua_dataSS->parti_info->ua_blk_name); // All returns should go to CLEAN UP. + SS_SetUpgradeState(E_SS_IMGFLASHWRITEFAIL); + goto Cleanup; + } + + Cleanup: + SS_BackupSourceClear(); + SS_PatchSourceClear(); + SS_DeleteFile(SS_KERN_UNPK_SCRIPT_PATH); + SS_DeleteFolder(SS_KERNEL_WORKSPACE); + SS_Free(source_file.data); + SS_Free(buf); + SS_Free(outname);//wgid: 20740 + if (result == S_SS_SUCCESS) + LOGL(LOG_SSENGINE, "************* SS_UpdateDeltaKernel SUCCESS *****************\n"); + else{ + LOGL(LOG_SSENGINE, "************* SS_UpdateDeltaKernel FAILED *****************\n"); + if (fp) + fclose(fp);//wgid:14711 + } + return result; + +} + +/*! + ********************************************************************************* + * SS_UpdateDeltaIMG + ********************************************************************************* + * + * @brief + * This is used to apply patch for an image during delta Image upgrade + * + * + * @param + * + * @return 0 - in case of success + * 1 - in case of error during patch application + * + ********************************************************************************* + */ + +int SS_UpdateDeltaIMG(ua_dataSS_t * ua_dataSS, int (*write_to_blkdev) (char *, int, int, char *)) +{ + uint8_t target_sha1[SHA_DIGEST_SIZE]; + uint8_t source_sha1[SHA_DIGEST_SIZE]; + unsigned char current_target_sha1[SHA_DIGEST_SIZE]; + FileInfo source_file; + SHA1_CTX ctx1; + MemorySinkInfo msi; + int result = S_SS_SUCCESS; + int blk_cnt; + int blk_start = 0; + int backupsrc = -1; + int use_backup_img = -1; + int fd = -1; + char buf[256]; + if (ParseSha1(ua_dataSS->update_cfg->target_sha1, target_sha1) != 0) { + LOGE("failed to parse tgt-sha1 \"%s\"\n", ua_dataSS->update_cfg->target_sha1); + return E_SS_FAILURE; + } + + source_file.size = ua_dataSS->update_cfg->soure_img_size; + source_file.data = NULL; + if (0 == gvalid_session) { + + if (ParseSha1(ua_dataSS->update_cfg->soure_sha1, source_sha1) != 0) { + LOGE("failed to parse Src-sha1 \"%s\"\n", ua_dataSS->update_cfg->soure_sha1); + return E_SS_FAILURE; + } + + if (SS_LoadPartition(ua_dataSS->parti_info->ua_blk_name, &source_file) == 0) { + if (memcmp(source_file.sha1, source_sha1, SHA_DIGEST_SIZE) == 0) { + LOGL(LOG_SSENGINE, "SS_UpdateDeltaIMG - Patch Can be applied\n"); + SS_Free(source_file.data); + } else if (memcmp(source_file.sha1, target_sha1, SHA_DIGEST_SIZE) == 0) { + LOGL(LOG_SSENGINE, "SS_UpdateDeltaIMG - Patch Already applied\n"); + SS_Free(source_file.data); + return S_SS_SUCCESS; + } else { + SS_Free(source_file.data); + source_file.data = NULL; + LOGL(LOG_SSENGINE, "SS_UpdateDeltaIMG - Source was currupted, Try loading from backup source\n"); + if (SS_LoadPartition(SS_BACKUP_SOURCE, &source_file) == 0) { + if (memcmp(source_file.sha1, source_sha1, SHA_DIGEST_SIZE) == 0) { + use_backup_img = 1; + SS_Free(source_file.data); + LOGL(LOG_SSENGINE, + "SS_UpdateDeltaIMG - Patch Can be applied from using backup file as source\n"); + } else { + SS_SetUpgradeState(E_SS_IMGSRCCURRUPTED); + SS_Free(source_file.data); + return E_SS_FAILURE; + } + } + } + } + } + if (use_backup_img == -1) { + backupsrc = SS_BackupSource(ua_dataSS->parti_info->ua_blk_name); + if (backupsrc != 0) { + LOGE("failed to Backup source File:[%s] \n", ua_dataSS->parti_info->ua_blk_name); + SS_SetUpgradeState(E_SS_IMGSRCBACKUPFAILED); + return E_SS_FAILURE; + } + } + SinkFn sink = NULL; + void *token = NULL; + + blk_cnt = ((ua_dataSS->update_cfg->target_img_size - 1) / SECTOR_SIZE) + 1; + + msi.buffer = SS_Malloc(blk_cnt * SECTOR_SIZE); + if (msi.buffer == NULL) { + LOGE("failed to alloc %ld bytes for output\n", (long)ua_dataSS->update_cfg->target_img_size); + SS_SetUpgradeState(E_SS_MALLOC_ERROR); + return E_SS_FAILURE; + } + msi.pos = 0; + msi.size = ua_dataSS->update_cfg->target_img_size; + sink = ss_memorySink; + token = &msi; + + SHA1Init(&ctx1); + //if souce was corrupted, use backup to apply diff + if (use_backup_img == -1) + result = + SS_ApplyBsdiff((char *)ua_dataSS->parti_info->ua_blk_name, NULL, SS_PATCHFILE_SOURCE, sink, token, &ctx1); + else + result = SS_ApplyBsdiff(SS_BACKUP_SOURCE, NULL, SS_PATCHFILE_SOURCE, sink, token, &ctx1); + if (result != S_SS_SUCCESS) { + LOGE("failed to SS_ApplyBsdiff\n"); + SS_SetUpgradeState(E_SS_IMGRECOVERYWRITEFAILED); + goto Cleanup; + } + + SHA1Final(current_target_sha1, &ctx1); + result = memcmp(current_target_sha1, target_sha1, SHA_DIGEST_SIZE); + if (result != S_SS_SUCCESS) { + LOGE("patch did not produce expected sha1 \n"); + SS_SetUpgradeState(E_SS_IMGSHA_MISMATCH); + goto Cleanup; + } + //Considering EMMC partition by default + + if (ua_dataSS->update_cfg->update_type == EXTRA && ua_dataSS->update_data->ua_temp_path) { + fd = open(ua_dataSS->update_data->ua_temp_path, O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU); + if (fd < 0) { + strerror_r(errno, buf, sizeof(buf)); + LOGE("failed to open %s for write: %s\n", ua_dataSS->update_data->ua_temp_path, buf); + SS_SetUpgradeState(E_SS_IMGRECOVERYWRITEFAILED); + result = E_SS_FAILURE; + goto Cleanup; + } + result = SS_WriteFile(fd, 0, msi.buffer, msi.size); + if (result != S_SS_SUCCESS) { + LOGE("failed to write\n"); + SS_SetUpgradeState(E_SS_IMGRECOVERYWRITEFAILED); + goto Cleanup; + } + fsync(fd); + } else { + SS_SetUpgradeState(E_SS_IMGUPDATEFAILED); + result = E_SS_FAILURE; + LOGE("failed to apply patch - Invalid Update type params \n"); + } + +Cleanup: + SS_BackupSourceClear(); + SS_PatchSourceClear(); + if (msi.buffer) + SS_Free(msi.buffer); + if (fd >= 0) + close(fd); + if (result == S_SS_SUCCESS) + LOGL(LOG_SSENGINE, "************* SS_UpdateDeltaIMG SUCCESS *****************\n"); + return result; + +} + + +int SS_UpdateDeltaIMGAB(ua_dataSS_t * ua_dataSS, int (*write_to_blkdev) (char *, int, int, char *)) +{ + int result = S_SS_SUCCESS; + uint8_t target_sha1[SHA_DIGEST_SIZE]; + uint8_t source_sha1[SHA_DIGEST_SIZE]; + uint8_t current_target_sha1[SHA_DIGEST_SIZE]; + + if (ParseSha1(ua_dataSS->update_cfg->target_sha1, target_sha1) != 0) { + LOGE("failed to parse tgt-sha1 \"%s\"\n", ua_dataSS->update_cfg->target_sha1); + return E_SS_FAILURE; + } + + if (ParseSha1(ua_dataSS->update_cfg->soure_sha1, source_sha1) != 0) { + LOGE("failed to parse Src-sha1 \"%s\"\n", ua_dataSS->update_cfg->soure_sha1); + return E_SS_FAILURE; + } + + SS_CalculateFileSha(ua_dataSS->parti_info->ua_blk_name, + ua_dataSS->update_cfg->target_img_size, + current_target_sha1); + + /* source_file.size = ua_dataSS->update_cfg->soure_img_size; */ + /* source_file.data = NULL; */ + if (memcmp(target_sha1, current_target_sha1, SHA_DIGEST_SIZE) == 0) { + LOGL(LOG_SSENGINE, "SS_UpdateDeltaIMGAB - Patch already applied\n"); + return S_SS_SUCCESS; + } + + LOGL(LOG_SSENGINE, "SS_UpdateDeltaIMGAB - Checksum calculation of the source partition\n"); + SS_CalculateFileSha(ua_dataSS->parti_info->ua_blk_name_previous, + ua_dataSS->update_cfg->soure_img_size, + current_target_sha1); + + if (memcmp(source_sha1, current_target_sha1, SHA_DIGEST_SIZE) != 0) { + unsigned char actualShaBuffer[41] = { 0, }; + hex_digest(current_target_sha1, actualShaBuffer, SHA_DIGEST_SIZE); + LOGL(LOG_SSENGINE, "SS_UpdateDeltaIMGAB - Source partition was corrupted. SRC: [%s] Expected [%s] Actual [%s]\n", + ua_dataSS->parti_info->ua_blk_name_previous, ua_dataSS->update_cfg->soure_sha1, actualShaBuffer); + return E_SS_FAILURE; + } + + LOGL(LOG_SSENGINE, "SS_UpdateDeltaIMGAB - Applying the patch\n"); + apply_patch_brotli(ua_dataSS->parti_info->ua_blk_name_previous, + ua_dataSS->update_cfg->soure_img_size, + ua_dataSS->parti_info->ua_blk_name, + ua_dataSS->update_cfg->target_img_size, + SS_PATCHFILE_SOURCE); + + LOGL(LOG_SSENGINE, "SS_UpdateDeltaIMGAB - Checksum calculation of the target partition\n"); + SS_CalculateFileSha(ua_dataSS->parti_info->ua_blk_name, + ua_dataSS->update_cfg->target_img_size, + current_target_sha1); + + if (memcmp(target_sha1, current_target_sha1, SHA_DIGEST_SIZE) != 0) { + unsigned char actualShaBuffer[41] = { 0, }; + hex_digest(current_target_sha1, actualShaBuffer, SHA_DIGEST_SIZE); + LOGL(LOG_SSENGINE, "SS_UpdateDeltaIMGAB - Target partition was corrupted. SRC: [%s] Expected [%s] Actual [%s]\n", + ua_dataSS->parti_info->ua_blk_name, ua_dataSS->update_cfg->target_sha1, actualShaBuffer); + return E_SS_FAILURE; + } + + return result; +} diff --git a/src/delta-ua/engine/SS_PatchDelta.h b/src/delta-ua/engine/SS_PatchDelta.h new file mode 100755 index 0000000..edbe182 --- /dev/null +++ b/src/delta-ua/engine/SS_PatchDelta.h @@ -0,0 +1,78 @@ +/* + * libtota + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SS_PATCHDELTA_H +#define _SS_PATCHDELTA_H + +#include +#include "sha1.h" +#include "unistd.h" +#include "fcntl.h" +#include "errno.h" +#include "SS_Engine_Update.h" + +//#define ENHANCED_BSDIFF +#define SS_UPDATE_FS 0 +#define SS_UPDATE_IMG 1 +#define SHA_DIGEST_SIZE 20 +typedef struct { + int type; + ssize_t size; + char *data; +} Value; +typedef struct _Patch { + uint8_t sha1[SHA_DIGEST_SIZE]; + const char *patch_filename; +} Patch; + +typedef struct _FileInfo { + unsigned char sha1[20]; //SHA_DIGEST_SIZE 20 + unsigned char *data; + int size; + struct stat st; +} FileInfo; + +typedef ssize_t(*SinkFn) (unsigned char *, ssize_t, void *); + +int ParseSha1(const char *str, uint8_t * digest); + +void ShowBSDiffLicense(); +int ApplyBSDiffPatch(const unsigned char *old_data, ssize_t old_size, + const Value * patch, ssize_t patch_offset, SinkFn sink, void *token, SHA1_CTX * ctx1); +int ApplyBSDiffPatchMem(const unsigned char *old_data, ssize_t old_size, + const Value * patch, ssize_t patch_offset, unsigned char **new_data, ssize_t * new_size); +//int ApplyOptimizedBSDiffPatch(const unsigned char* old_data,void* token, +// const Value* patch, SinkFn sink,sha1_ctx_t* ctx1); + +int SS_LoadPartition(const char *filename, FileInfo * file); +int SS_LoadFile(const char *filename, FileInfo * file); +extern void SS_SetUpgradeState(int Val); +extern long SS_GetAvailableFreeSpace(const char *partition_name, SS_UINT32 * available_flash_size); +extern int SS_BackupSource(const char *source_filename); +extern int SS_ApplyBsdiff(char *oldfile, char *newfile, char *patch, SinkFn sink, void *token, SHA1_CTX * ctx1); +extern int SS_BackupSourceClear(); +extern int SS_PatchSourceClear(); +extern long SS_WriteFile(long wHandle, SS_UINT32 dwPosition, unsigned char *pbBuffer, SS_UINT32 dwSize); +extern void SS_Free(void * pMemBlock); +extern long SS_CopyFile(const char * strFromPath, const char * strToPath); +extern long SS_DeleteFolder(const char * strPath); +extern long SS_DeleteFile(const char * strPath); +extern int tar_get_item_size(char * tar, char * item); +extern int tar_extract_file(char * tar, char * item, char * pathname); +extern int _system_cmd_wait(const char * command); +#endif diff --git a/src/delta-ua/engine/SS_UPI.c b/src/delta-ua/engine/SS_UPI.c new file mode 100755 index 0000000..a7a4cac --- /dev/null +++ b/src/delta-ua/engine/SS_UPI.c @@ -0,0 +1,2351 @@ +/* + * libtota + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*HEADER */ + +/* + +Function Prototypes Mandatory + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ua_types.h" +#include "SS_Common.h" +#include "fota_common.h" +#include "SS_UPI.h" +#include "SS_PatchDelta.h" +#include "SS_Engine_Errors.h" +#include "SS_FSUpdate.h" +#include "ss_bspatch_common.h" + +int gtotalFSCnt = 0; +int FS_UpgradeState = E_SS_FAILURE; +int gvalid_session = 0; //used as fail-safe in case device is turmed off or battery removed during update +fs_list *fs_headptr_main = NULL; +fs_list *headptr_list[UA_PARTI_MAX]; +tar_Data_t *tar_cfg_data = NULL; + +#ifdef MEM_PROFILING +/* + Description: + Create script file , set it executable, execute script in child process + Only works if valid delta.tar is present for upgrade + Summary: + If MEM_PROFILING is activated, + we can see the result of memory profiling after delta upgrade + in file defined by macro - SS_MEMORY_PROFILING_SCRIPT +*/ +int mem_profiling_start = 0; +int SS_Do_Memory_Profiling() +{ + int ret = -1; + pid_t pid; + char memory_usage_script[1024] = "#!/bin/bash\nlog_file=$1\npid=$2\nmaxmem=0\nwhile [[ -d \"/proc/${pid}\" ]]; do\n\ + mem=`cat /proc/${pid}/smaps | grep Pss | grep -v Swap|awk '{print $2}'|awk '{s+=$1} END {print s}'`\n\ + if [[ ${mem} -gt ${maxmem} ]]; then\nmaxmem=${mem}\n\ + echo -e \"Memory usage till now is: ${maxmem} KB.\" >> $log_file\n fi\n sleep 0.01\ndone\n\ + echo -e \"Max was : ${maxmem} KB.\" >> $log_file\n"; + char cmd[1024] = { 0, }; + + //Open a file and write the script contents in it + FILE *fp = fopen(SS_MEMORY_PROFILING_SCRIPT, "w+"); + fwrite(memory_usage_script, strlen(memory_usage_script), 1, fp); + fclose(fp); + //make the file executable - Octal 495 is 757 decimal + if (chmod(SS_MEMORY_PROFILING_SCRIPT, 495) < 0) { + LOGE("Error in chmod(%s, 495) - %d (%s)\n", SS_MEMORY_PROFILING_SCRIPT, errno, strerror(errno)); + return E_SS_FAILURE; + } + //calling mem_use.sh + //Usage : + pid = getpid(); + snprintf(cmd, sizeof(cmd) - 1, "%s %s %d", SS_MEMORY_PROFILING_SCRIPT, SS_MEMORY_USAGE_LOG, pid); + ret = _system_cmd_nowait(cmd); + sleep(1); + LOG("ret for memory profiling cmd is %d\n", ret); + if (ret == 0) { + mem_profiling_start = 1; + return S_SS_SUCCESS; + } else { + LOGE("Could not start Memory Profiling\n"); + return E_SS_FAILURE; + } +} +#endif +#ifdef TIME_PROFILING +static char ts1[256]; +static double ts2; +double t1; +double t2; +double fast_tar_get_item_size_time = 0.0; +double SS_LoadFile_time = 0.0; +double SS_FSBuildNodes_time = 0.0; + +static void get_time_stamp1(void) +{ + struct timeval tv; + int sec, msec; + + gettimeofday(&tv, NULL); + sec = (int)tv.tv_sec; + msec = (int)(tv.tv_usec / 1000); + snprintf(ts1, 256, "%06d.%03d", sec % 100000, msec); +} + +static double get_time_stamp2(void) +{ + struct timeval tv; + + gettimeofday(&tv, NULL); + ts2 = (double)tv.tv_sec + (double)(tv.tv_usec / 1000000.0); + return ts2; +} +#endif + +//Check SS function if available +int file_exist(char *filename) +{ + struct stat buf; + int ret = 0; + + ret = lstat(filename, &buf); + if (ret < 0) + ret = stat(filename, &buf); + return (ret >= 0) ? (1) : (0); +} + +#ifdef POWER_FAIL_TEST + +static int SS_Get_power_fail_flag(void) +{ + int fd; + char buf[256]; + char *ptr = NULL; + int result = 0; + int ret_val = 0; + + if (file_exist(SS_POWER_FAIL_TEST_FLAG) == 0) { + LOGE("No exist file!!\n"); + return -1; + } + + fd = open(SS_POWER_FAIL_TEST_FLAG, O_RDWR, S_IRWXU); + if (fd == -1) { + LOGE("Could not open status file!!\n"); + return -1; + } + + result = SS_ReadFile(fd, 0, buf, sizeof(buf)); + if (result != 0) { + LOGE("SS_ReadFile failed!!\n"); + return -1; + } + + ret_val = atoi(buf); + + result = SS_CloseFile(fd); + if (result != 0) + LOGE("SS_CloseFile failed!!\n"); + + return ret_val; +} + +static void SS_Set_power_fail_flag(int del_type) +{ + int fd; + int result = 0; + char num_str[16]; + LOG("del_type:[%d]\n", del_type); + + fd = open(SS_POWER_FAIL_TEST_FLAG, O_RDWR | O_CREAT, S_IRWXU); + if (fd == -1) { + LOGE("Could not open status file!!\n"); + return; + } + + sprintf(num_str, "%d", del_type); + result = SS_WriteFile(fd, 0, num_str, strlen(num_str)); + if (result != 0) + LOGE("SS_WriteFile failed!!\n"); + + result = SS_CloseFile(fd); + if (result != 0) + LOGE("SS_CloseFile failed!!\n"); + + sync(); + +} + +int SS_Do_Power_fail_test(int del_type) +{ + int ret = -1; + char cmd[1024] = { 0, }; + + SS_Set_power_fail_flag(del_type); + + snprintf(cmd, sizeof(cmd) - 1, "%s", "/usr/sbin/reboot fota"); + ret = _system_cmd_nowait(cmd); + sleep(1); + LOG("ret for SS_Do_Power_fail_test cmd is %d\n", ret); + if (ret == 0) { + return S_SS_SUCCESS; + } else { + LOGE("Could not start Memory Profiling\n"); + return E_SS_FAILURE; + } +} +#endif + +long SS_GetUPIVersion(unsigned char *ver_str) +{ + if (ver_str) { + strncpy((char *)ver_str, SS_TOTA_VERSION, MAX_PATH); +#ifdef MEM_PROFILING + if (!mem_profiling_start) + if (!(S_SS_SUCCESS == SS_Do_Memory_Profiling())) + LOGE("Unable to start Memory_Profiling\n"); +#endif + return S_SS_SUCCESS;//wgid: 2456 + } else + return E_SS_FAILURE; +} + +int SS_verify_DELTA_image(char *filename) +{ + + FileInfo file; + FILE *fp = NULL; + char line[SS_TOKEN_MAXLINE_LEN] = { '\0' }; + char *delta_size = NULL; + char *signature = NULL; + char *sha1trg = NULL; + char *saveptr = NULL; + uint8_t target_sha1[SHA_DIGEST_SIZE] = { 0, }; + char cmd[512] = { 0, }; + char buf[256]; + long int udelta_size = 0; + int ulResult = S_SS_SUCCESS; + + file.data = NULL; + if (stat(filename, &file.st) != 0) { + strerror_r(errno, buf, sizeof(buf)); + LOGE("failed to stat \"%s\": %s\n", filename, buf); + return -1; + } + + snprintf(cmd, sizeof(cmd) - 1, "grep -o -P '%s' --binary-files=text system/%s > %s", + SS_IMAGE_MAGIC_KEY, filename, SS_IMAGE_MAGIC_KEY_VAL); + + ulResult = _system_cmd_wait(cmd); + if (ulResult != S_SS_SUCCESS) { + LOGE("Grep extraction for [%s] failed, code [%d]\n", cmd, ulResult); + ulResult = E_SS_FAILURE; + goto Cleanup; + } + + fp = fopen(SS_IMAGE_MAGIC_KEY_VAL, "r"); + if (!fp) { + LOGE("Grep extraction for [%s] failed, code [%d]\n", cmd, ulResult); + ulResult = E_SS_FAILURE; + goto Cleanup; + } + + if (fgets(line, SS_TOKEN_MAXLINE_LEN, fp) == NULL) { + ulResult = E_SS_FAILURE; + goto Cleanup; + } + fclose(fp); + fp = NULL; + + signature = strtok_r(line, SS_TOEKN_COLON, &saveptr); + delta_size = strtok_r(NULL, SS_TOEKN_COLON, &saveptr); + sha1trg = strtok_r(NULL, SS_TOEKN_COLON, &saveptr); + + if (signature && sha1trg && delta_size) { + udelta_size = strtol(delta_size, NULL, 10); + + if (udelta_size <= 0) { + LOGE("Invalid udelta_size %ld (%s)\n", udelta_size, delta_size); + ulResult = E_SS_FAILURE; + goto Cleanup; + } + else if (udelta_size >= __INT_MAX__) { + LOGE("Too big udelta_size %ld (%s)\n", udelta_size, delta_size); + ulResult = E_SS_FAILURE; + goto Cleanup; + } + + LOGL(LOG_SSENGINE, "delta_size %ld sha1trg %s\n", udelta_size, sha1trg); + } else { + LOGE("Could not parse signature [%s]\n", line); + ulResult = E_SS_FAILURE; + goto Cleanup; + } + + if (ParseSha1(sha1trg, target_sha1) != 0) { + LOGE("failed to parse tgt-sha1 \"%s\"\n", sha1trg); + ulResult = E_SS_FAILURE; + goto Cleanup; + } + + unsigned char calcualted_sha1[SHA_DIGEST_SIZE]; + ulResult = SS_CalculateFileSha(filename, udelta_size, calcualted_sha1); + if (ulResult != S_SS_SUCCESS) + goto Cleanup; + + if (memcmp(file.sha1, target_sha1, SHA_DIGEST_SIZE) != 0) { + unsigned char actualShaBuffer[41] = { 0, }; + hex_digest(file.sha1, actualShaBuffer, SHA_DIGEST_SIZE); + LOGE("SHA mismatch -[%s] actual [%s] target [%s]\n", filename, actualShaBuffer, sha1trg); + SS_SetUpgradeState(E_SS_FSBADDELTA); + ulResult = E_SS_FAILURE; + goto Cleanup; + } else { + LOGL(LOG_SSENGINE, "DELTA verified %s \n", sha1trg); + } + +Cleanup: + if (fp) + fclose(fp); + if (file_exist(SS_IMAGE_MAGIC_KEY_VAL)) + SS_DeleteFile(SS_IMAGE_MAGIC_KEY_VAL); + return ulResult; +} + + +int SS_GetProgressResolution(int ultotalFSCnt) +{ + if (ultotalFSCnt < DISPLAYRESOLUTION_SIZE) + return 1; + else + return (ultotalFSCnt / DISPLAYRESOLUTION_SIZE); +} + +void SS_SetUpgradeState(int Val) +{ + LOGE("FAILED to upgrade Cause:[0x%x]\n", Val); + FS_UpgradeState = Val; + return; +} + +int SS_GetUpgradeState() +{ + return FS_UpgradeState; +} + +int SS_Get_last_update_status(int* last_update_status, int* del_type) +{ + int fd; + unsigned char buf[257]; + char *ptr = NULL; + char *saveptr = NULL; + int result = 0; + + if (file_exist(SS_UPDATE_STATUR_PATH) == 0) { + LOG("No exist file!! - File_path:[%s]\n", SS_UPDATE_STATUR_PATH); + return -1; + } + + fd = open(SS_UPDATE_STATUR_PATH, O_RDWR, S_IRWXU); + if (fd == -1) { + LOGE("Could not open status file!!, File_path:[%s]\n", SS_UPDATE_STATUR_PATH); + return -1; + } + + result = SS_ReadFile(fd, 0, buf, sizeof(buf)-1); + if (result != 0) { + LOGE("SS_ReadFile failed!!\n"); + result = SS_CloseFile(fd); + if (result != 0) + LOGE("SS_CloseFile failed!!\n"); + return -1; + } + + ptr = strtok_r((char *)buf, " ", &saveptr); + + if (ptr != NULL) { + *last_update_status = atoi(ptr); + ptr = strtok_r(NULL, " ", &saveptr); + } + + if (ptr != NULL) { + *del_type = atoi(ptr); + } + + result = SS_CloseFile(fd); + if (result != 0) + LOGE("SS_CloseFile failed!!\n"); + + return 0; +} + +void SS_Set_last_update_status(int last_update_status, int del_type) +{ + int fd; + int result = 0; + char num_str[16]; + LOG("last_update_status:[%d], del_type:[%d]\n", last_update_status, del_type); + + fd = open(SS_UPDATE_STATUR_PATH, O_RDWR | O_CREAT, S_IRWXU); + if (fd == -1) { + LOGE("Could not open status file!!, File_path:[%s]\n", SS_UPDATE_STATUR_PATH); + return; + } + + snprintf(num_str, sizeof(num_str), "%d %d", last_update_status, del_type); + result = SS_WriteFile(fd, 0, (unsigned char *)num_str, strlen(num_str)); + if (result != 0) + LOGE("SS_WriteFile failed!!\n"); + + result = SS_CloseFile(fd); + if (result != 0) + LOGE("SS_CloseFile failed!!\n"); + + sync(); + +} + +int SS_rename(const char *old_file_name, const char *new_file_name) +{ + if (link(old_file_name, new_file_name) < 0) { + if (errno == EEXIST) { + if (unlink(new_file_name) < 0 || link(old_file_name, new_file_name) < 0) + return -1; + } else + return -1; + } + if (unlink(old_file_name) < 0) { + if (unlink(new_file_name) == 0) + return -1; + } + return 0; +} + +int SS_rename1(const char *old_file_name, const char *new_file_name) +{ + + int result = E_SS_FAILURE; + char *temp_name = NULL; + temp_name = (char *)SS_Malloc(strlen(new_file_name) + 10); + if (temp_name == NULL) + return E_SS_FAILURE; + snprintf(temp_name, strlen(new_file_name) + 10, "%s.temp", new_file_name); + result = rename(new_file_name, temp_name); + if (result != 0) + goto Cleanup; + result = rename(old_file_name, new_file_name); + if (result != 0) + goto Cleanup; + result = unlink(temp_name); + Cleanup: + if (temp_name) + SS_Free(temp_name); + return result; +} + +/*! + ********************************************************************************* + * SS_FSVerifyNode + ********************************************************************************* + * + * @brief + * This is to verify nodes being added to global control structure for diff and delete cases. + * gvalid_session global is used to check if nodes are already verified. + * + * + * @param + * + * @return returns S_SS_SUCCESS and + * returns E_SS_FAILURE in case any error occurs + * + ********************************************************************************* + */ +int SS_FSVerifyNode(const char *path, const char *patchname, const char *sha1src, int type, + char *patchpath_name, int *data_size, int *data_offset) +{ + char patch[MAX_FILE_PATH] = { 0 }; + FileInfo source_file; + uint8_t source_sha1[SHA_DIGEST_SIZE]; + + if (gvalid_session) { + if ((type == DIFFS || type == DELETES || type == MOVES) && !file_exist((char *)path)) { + LOGE("failed to verifyNodes [does not exist], Path : [%s] Type[%d]\n", path, type); + SS_SetUpgradeState(E_SS_FSBADNODES); + return E_SS_FAILURE; + } + snprintf(patch, MAX_FILE_PATH, "%s%s%s", patchpath_name, "/", patchname); + if ((type == DIFFS/*||type == NEWFILES */)) { // allowing size 0 also for folders + if (tar_get_item_size_from_struct(&tar_cfg_data, patchname, data_size, data_offset) + != S_SS_SUCCESS) { + LOGE("failed to get item size from struct, Patch : [%s]\n", patchname); + SS_SetUpgradeState(E_SS_FSBADNODES); + return E_SS_FAILURE; + } + if (*data_size < 0) { + LOGE("failed to verifyNodes [delta absent], Patch : [%s] Type[%d]\n", patch, type); + SS_SetUpgradeState(E_SS_FSBADNODES); + return E_SS_FAILURE; + } + } + //For other types (NEWs, SYMs, Folders), SHA check not required + if ((type == DIFFS || type == MOVES/* ||type == DELETES */) && + (strcmp(sha1src, SS_NULLENTRY) != 0)) { + if (ParseSha1(sha1src, source_sha1) != 0) { + LOGE("Failed to parse Src-sha1 \"%s\"\n", sha1src); + return E_SS_FAILURE; + } + if (SS_LoadFile(path, &source_file) == 0) { + if (memcmp(source_file.sha1, source_sha1, SHA_DIGEST_SIZE) != 0) { + SS_Free(source_file.data); + unsigned char actualShaBuffer[41] = { 0, }; + hex_digest(source_file.sha1, actualShaBuffer, SHA_DIGEST_SIZE); + LOGE("SS_FSVerifyNode - SHA mismatch with SRC - PATH [%s] Expected [%s] Actual [%s]\n", + path, sha1src, actualShaBuffer); + SS_SetUpgradeState(E_SS_FSSRCCURRUPTED); // Define other error + return E_SS_FAILURE; + } + } + SS_Free(source_file.data); + } + } else { + LOGL(LOG_SSENGINE, "FS partition Already verified - Filling only size and offset \n"); + snprintf(patch, MAX_FILE_PATH, "%s%s%s", patchpath_name, "/", patchname); + if ((type == DIFFS/* ||type == NEWFILES */)) { // allowing size 0 also for folders + if (tar_get_item_size_from_struct(&tar_cfg_data, patchname, data_size, data_offset) + != S_SS_SUCCESS) { + LOGE("failed to get item size from struct, Patch : [%s] \n", patchname); + SS_SetUpgradeState(E_SS_FSBADNODES); + return E_SS_FAILURE; + } + if (*data_size < 0) { + LOGE("failed to verifyNodes [delta absent], Patch : [%s] Type[%d]\n", patch, type); + SS_SetUpgradeState(E_SS_FSBADNODES); + return E_SS_FAILURE; + } + } + } + return S_SS_SUCCESS; +} + +/*! + ********************************************************************************* + * SS_AppendNode + ********************************************************************************* + * + * @brief + * This is to append node to the global control structure for delta files. + * + * + * @param + * + * @return returns S_SS_SUCCESS and + * returns E_SS_FAILURE in case any error occurs + * + ********************************************************************************* + */ +int SS_AppendNode(const char *ubDeltaPath, fs_params ** headparam, fs_params ** tailparam, const char *old_path, + const char *new_path, const char *patchname, const char *sha1src, const char *sha1trg, int type, + char *patchpath_name) +{ + fs_params *newnode = NULL; + int data_size = 0; + int data_offset = 0; + + if (!ubDeltaPath || !old_path || !new_path || !patchname || !sha1src || !sha1trg || !patchpath_name) { + LOGE("Bad Nodes, NULL params passed for Appending Nodes \n"); + SS_SetUpgradeState(E_SS_FSINVALIDNODEPARAMS); + return E_SS_FAILURE; + } + if ((E_SS_FAILURE == + SS_FSVerifyNode(old_path, patchname, sha1src, type, patchpath_name, &data_size, &data_offset))) { + LOGE("Bad Nodes, Failed to pass verification - [Delta Path - %s][OldPath - %s] [NewPath - %s] \n", ubDeltaPath, + old_path, new_path); + return E_SS_FAILURE; + } + newnode = (fs_params *) SS_Malloc(sizeof(fs_params)); + if (!newnode) + return E_SS_FAILURE; + strncpy(newnode->file_old_path, old_path, SS_MAX_NAMELENSUPPORTED);//wgid: 29483 + strncpy(newnode->file_new_path, new_path, SS_MAX_NAMELENSUPPORTED);//wgid: 29482 + strncpy(newnode->patch_name, patchname, SS_MAX_NAMELENSUPPORTED);//wgid: 28033 + strncpy(newnode->sha1src, sha1src, sizeof(newnode->sha1src) -1);//wgid: 25282 + strncpy(newnode->sha1trg, sha1trg, sizeof(newnode->sha1trg) - 1);//wgid: 25283 + newnode->type = type; + newnode->data_size = data_size; + newnode->data_offset = data_offset; + newnode->nextnode = NULL; + + //LOG("%s %s %d %s %s \n",newnode->file_path,newnode->patch_name,newnode->type, newnode->sha1src, newnode->sha1trg); + + if (*headparam == NULL) { + *headparam = newnode; + *tailparam = newnode; + } else { + (*tailparam)->nextnode = newnode; + (*tailparam) = (*tailparam)->nextnode; + } + return S_SS_SUCCESS; + +} + +void SS_UpdateUIProgress(ua_dataSS_t * ua_dataSS, int ulTotalFsCnt, int ulDone) +{ + static int ss_count = 1; + int res_val = SS_GetProgressResolution(ulTotalFsCnt); + if (!ua_dataSS) { + LOGE("Error ua_dataSS\n"); + return; + } +//LOG("\nvalues are ss_count[%d] total_file_cnt[%d]",ss_count,ulTotalFsCnt); + if (ulDone == 1) { + if (ua_dataSS->ui_progress) + ua_dataSS->ui_progress(ua_dataSS, 100); + ss_count = 1; + } else if (ss_count < ulTotalFsCnt) { + if (ss_count % res_val == 0) { //Max 50 times display + double data = (double)ss_count / (double)ulTotalFsCnt; + if (ua_dataSS->ui_progress) + ua_dataSS->ui_progress(ua_dataSS, data * 100); + } + ss_count++; + } else { + if (ua_dataSS->ui_progress) + ua_dataSS->ui_progress(ua_dataSS, 100); + ss_count = 1; + } + +} + +/*! + ********************************************************************************* + * SS_FSClearNodes + ********************************************************************************* + * + * @brief + * This is to clear the global control structure for delta files. + * + * + * @param + * + * @return + * + ********************************************************************************* + */ +void SS_FSClearNodes(int idx) +{ + fs_params *local_temp = NULL; + fs_params *local_next = NULL; + LOGL(LOG_SSENGINE, "Free Nodes idx=%d \n", idx); + if (headptr_list[idx]) { + if (headptr_list[idx]->del_ref) { + local_temp = headptr_list[idx]->del_ref; + while (local_temp) { + local_next = local_temp->nextnode; + SS_Free(local_temp); + local_temp = local_next; + } + } + if (headptr_list[idx]->dif_ref) { + local_temp = headptr_list[idx]->dif_ref; + while (local_temp) { + local_next = local_temp->nextnode; + SS_Free(local_temp); + local_temp = local_next; + } + } + if (headptr_list[idx]->move_ref) { + local_temp = headptr_list[idx]->move_ref; + while (local_temp) { + local_next = local_temp->nextnode; + SS_Free(local_temp); + local_temp = local_next; + } + } + if (headptr_list[idx]->new_ref) { + local_temp = headptr_list[idx]->new_ref; + while (local_temp) { + local_next = local_temp->nextnode; + SS_Free(local_temp); + local_temp = local_next; + } + } + if (headptr_list[idx]->sym_difref) { + local_temp = headptr_list[idx]->sym_difref; + while (local_temp) { + local_next = local_temp->nextnode; + SS_Free(local_temp); + local_temp = local_next; + } + } + if (headptr_list[idx]->sym_newref) { + local_temp = headptr_list[idx]->sym_newref; + while (local_temp) { + local_next = local_temp->nextnode; + SS_Free(local_temp); + local_temp = local_next; + } + } + SS_Free(headptr_list[idx]); + headptr_list[idx] = NULL; + } +} + +/*! + ********************************************************************************* + * SS_FSGetDeltaCount + ********************************************************************************* + * + * @brief + * This is to get the delta count for diffs , deletes etc. + * + * + * @param + * + * @return returns structure with delta count info + * NULL in case of error + * + ********************************************************************************* + */ + +struct details *SS_FSGetDeltaCount(char *ubDeltaPath, char *ubDeltaInfoFile) +{ + int size = 0, bckupsize = 0, ret = 1; + char *token = NULL; + char *FileData = NULL; + int data_size = -1; + char *line = NULL; + char *saveptr = NULL; + char buf[256]; + struct details *refer_copy = NULL; + FILE *filename_bkup = NULL; + + if (!(ubDeltaPath && ubDeltaInfoFile)) { + LOGE("failed to Parse DELTA count information: \n"); + SS_SetUpgradeState(E_SS_BAD_PARAMS); + return NULL; + } + refer_copy = (struct details *)SS_Malloc(sizeof(struct details)); + + if (refer_copy == NULL) { + LOGE("failed to allocate memory\n"); + return NULL; + } + + LOGL(LOG_SSENGINE, "Delta File Info =%s\n", ubDeltaInfoFile); + + size = tar_get_item_size(ubDeltaPath, ubDeltaInfoFile); + if (size < 0) { + LOGE("failed to Access DELTA info file DPath:[%s] File: [%s]\n", ubDeltaPath, ubDeltaInfoFile); + SS_SetUpgradeState(E_SS_FSBADDELTA); + ret = 0; + goto cleanup; + } + + FileData = SS_Malloc(size + 1); + if (FileData == NULL) { + LOGE("Failed to Allocate Memory\n"); + SS_SetUpgradeState(E_SS_MALLOC_ERROR); + ret = 0; + goto cleanup; + } + + memset(FileData, 0, size + 1); + data_size = tar_get_cfg_data(ubDeltaPath, ubDeltaInfoFile, FileData, size); + if (data_size <= 0) { // == 0 is NOT okay?? + LOGE("Failed to read cfg data from Delta\n"); + SS_SetUpgradeState(E_SS_FSBADDELTA); + ret = 0; + goto cleanup; + } + filename_bkup = fopen(SS_PATCHLIST_BKUPLOC, "wb+"); + if (filename_bkup == NULL) { + strerror_r(errno, buf, sizeof(buf)); + LOGE("Failed to create BACKUP file Error:[%s]\n", buf); + SS_SetUpgradeState(E_SS_FSFAILEDTOBACKUPPATCHINFO); + ret = 0; + goto cleanup; + } + + bckupsize = fwrite(FileData, 1, data_size, filename_bkup); //RECHECK SIZE 1 + if (bckupsize <= 0) { + SS_SetUpgradeState(E_SS_FSFAILEDTOBACKUPPATCHINFO); + ret = 0; + goto cleanup; + } + LOGL(LOG_SSENGINE, " Size [%d] DataSize [%d] BakUpSize [%d]\n", size, data_size, bckupsize); + + line = strstr(FileData, SS_FSCOUNT_MAGIC_KEY); + if (line) { + LOGL(LOG_SSENGINE, "SS_FSGetDeltaCount() last line %s \n", line); + + token = strtok_r(&line[SS_FSCOUNT_MAGIG_KEYLEN], SS_TOKEN_SPACE, &saveptr); + if (token) + refer_copy->diffs = atoi(token); + else { + SS_SetUpgradeState(E_SS_FSFAILEDTOPARSEDELTACNT); + ret = 0; + goto cleanup; + } + token = strtok_r(NULL, SS_TOKEN_SPACE, &saveptr); + if (token) + refer_copy->moves = atoi(token); + else { + SS_SetUpgradeState(E_SS_FSFAILEDTOPARSEDELTACNT); + ret = 0; + goto cleanup; + } + + token = strtok_r(NULL, SS_TOKEN_SPACE, &saveptr); + if (token) + refer_copy->news = atoi(token); + else { + SS_SetUpgradeState(E_SS_FSFAILEDTOPARSEDELTACNT); + ret = 0; + goto cleanup; + } + + token = strtok_r(NULL, SS_TOKEN_SPACE, &saveptr); + if (token) + refer_copy->deletes = atoi(token); + else { + SS_SetUpgradeState(E_SS_FSFAILEDTOPARSEDELTACNT); + ret = 0; + goto cleanup; + } + + token = strtok_r(NULL, SS_TOKEN_SPACE, &saveptr); + if (token) + refer_copy->symdiffs = atoi(token); + else { + SS_SetUpgradeState(E_SS_FSFAILEDTOPARSEDELTACNT); + ret = 0; + goto cleanup; + } + + token = strtok_r(NULL, SS_TOKEN_SPACE, &saveptr); + if (token) + refer_copy->symnews = atoi(token); + else { + SS_SetUpgradeState(E_SS_FSFAILEDTOPARSEDELTACNT); + ret = 0; + goto cleanup; + } + + gtotalFSCnt = + refer_copy->diffs + refer_copy->moves + refer_copy->news + refer_copy->deletes + refer_copy->symdiffs + + refer_copy->symnews; + LOG("SS_FSGetDeltaCount() total no of file %d\n", gtotalFSCnt); + + } else { + SS_SetUpgradeState(E_SS_FSFAILEDTOPARSEDELTACNT); + LOG("SS_FSGetDeltaCount() Failed to read last line\n"); + } + if (gtotalFSCnt < 0) { + ret = 0; + goto cleanup; + } + + cleanup: + if (ret) { + SS_Free(FileData); + if (filename_bkup) + fclose(filename_bkup); + return refer_copy; + } else { + SS_Free(FileData); + SS_Free(refer_copy); + if (filename_bkup) + fclose(filename_bkup); + return NULL; + } + +} + +/*! + ********************************************************************************* + * SS_FSBuildNodes + ********************************************************************************* + * + * @brief + * This is used to build the gobal control structure for diffs, deletes etc. + * For all the entries in config file (which has info) the information is parsed to the global control struct + * + * + * @param + * + * @return returns fs_list structure filled with details of all the files to be diff-ed ,deleted etc. + * NULL in case of error + * + ********************************************************************************* + */ +fs_list *SS_FSBuildNodes(ua_dataSS_t * ua_dataSS) +{ + FILE *fp = NULL; + char line[SS_TOKEN_MAXLINE_LEN] = { '\0' }; + char string_na[] = "NA"; + char *patch_name = NULL; + char *source_name = NULL; + char *target_name = NULL; + char *sha1src = NULL; + char *sha1trg = NULL; + char *change_type = NULL; + char *file_type = NULL; + char *saveptr = NULL; + uint32_t ulPatchCount = 0, del_type = DELETES; + fs_params *fs_diffhead = NULL; + fs_params *fs_difftail = NULL; + fs_params *fs_movehead = NULL; + fs_params *fs_movetail = NULL; + fs_params *fs_newhead = NULL; + fs_params *fs_delhead = NULL; + fs_params *fs_deltail = NULL; + fs_params *fs_symlinkdiffhead = NULL; + fs_params *fs_symlinkdifftail = NULL; + fs_params *fs_symlinknewhead = NULL; + fs_params *fs_symlinknewtail = NULL; + + struct details *local = NULL; + fs_list *fs_head_node = NULL; + int i = 0, retval = 0; + if (!ua_dataSS) { + LOGE("Bad structure ua_dataSS\n"); + SS_SetUpgradeState(E_SS_BAD_PARAMS); + return NULL; + } + LOGL(LOG_SSENGINE, " Build Nodes Entry \n"); + if (tar_cfg_data == NULL) + tar_cfg_data = tar_build_cfg_table(ua_dataSS->update_data->ua_delta_path); + if (!tar_cfg_data) { + LOGE(" tar_build_cfg_table Failed \n"); + SS_SetUpgradeState(E_SS_BAD_PARAMS); + return NULL; + } + local = SS_FSGetDeltaCount(ua_dataSS->update_data->ua_delta_path, ua_dataSS->update_delta->ua_patch_info); + if (local == NULL) { + LOGE(" Build Nodes Failed \n"); + if (tar_cfg_data) + tar_free_cfg_table(&tar_cfg_data); + SS_SetUpgradeState(E_SS_BAD_PARAMS); + return NULL; + } + + fp = fopen(SS_PATCHLIST_BKUPLOC, "r"); + if (!fp) { + SS_SetUpgradeState(E_SS_FSFAILEDTOOPENPATCHINFO); + if (tar_cfg_data) + tar_free_cfg_table(&tar_cfg_data); + SS_Free(local); + return NULL; + } + + ulPatchCount = local->diffs + local->deletes + local->news + local->moves + local->symdiffs + local->symnews; + LOG("Total FS count [%d].\n", ulPatchCount); +/* +************************************************************************ +Parsing logic implemented for patchlist +************************************************************************ +Sample entries in patchlist as below : +:: +************************************************************************ +DIFF:REG:system/bin/vi:system/bin/vi:2f2f3dc6d3ee06af0080ac7975f22941660f2480:78b2d44af32d854c70f1cb7431a60c2682a320cc:diff1_vi.delta +DIFF:TPK:system/usr/packages/removable/com.samsung.calculator.tpk:system/usr/packages/removable/com.samsung.calculator.tpk: + 96fc1bcde30d501ba65ef0038e05da46d255a7b3:fa1d5d9daa4097ac302b69244297f508577c3a01:diff1598_com.samsung.calculator.tpk.delta/ +MOVE:REG:system/etc/smack/accesses.d/heremaps-engine-devel:system/usr/apps/com.samsung.contacts/res/temp:da39a3ee5e6b4b0d3255bfef95601890afd80709 +DEL:REG:system/usr/ug/res/images/ug-phone/contacts/favorites_icon_remove.PNG:38ad8be378506d19b1c769d46be262cf100f6c59 +DEL:SYM:system/usr/apps/com.samsung.message-lite/lib/libmsg-common.so +SYM:DIFF:system/usr/lib/sync-agent/kies-private/libplugin-na-mobex.so.0:system/usr/lib/sync-agent/kies-private/libplugin-na-mobex.so.0: + libplugin-na-mobex.so.0.3.57 +SYM:NEW:system/lib/firmware/vbc_eq:/opt/system/vbc_eq +*********************************************************************** +*/ + if (local && ((local->diffs) > 0 || (local->moves > 0))) { + LOGL(LOG_SSENGINE, "%ss [%d] %ss [%d]\n", SS_STRING_DIFF, local->diffs, SS_STRING_MOVE, local->moves); + for (i = 0; i < (local->diffs + local->moves); i++) { + if (fgets(line, SS_TOKEN_MAXLINE_LEN, fp) == NULL) { + SS_SetUpgradeState(E_SS_FSFAILEDTOPARSEDELTAINFO); + break; + } + //LOGL(LOG_SSENGINE, "DIFF LINE:[%d] [%s] \n",i+1,line); + + change_type = strtok_r(line, SS_TOEKN_COLON, &saveptr); + file_type = strtok_r(NULL, SS_TOEKN_COLON, &saveptr); + if (!file_type) { + LOGE("Unexpected null in strtok_r"); + goto CleanUp; + } + + if (change_type && strcmp(change_type, SS_STRING_MOVE) == 0) { // && strcmp(file_type,"TPK") == 0){ + source_name = strtok_r(NULL, SS_TOEKN_COLON, &saveptr); + target_name = strtok_r(NULL, SS_TOEKN_COLON, &saveptr); + sha1src = strtok_r(NULL, SS_TOKEN_NEWLINE, &saveptr); + //LOGL(LOG_SSENGINE, "%s Index [%d]\n", SS_STRING_MOVE, i); + + if (!source_name || !target_name || !sha1src) { + SS_SetUpgradeState(E_SS_FSFAILEDTOPARSEDELTAINFO); + //LOGE("Failed to extract Patch Info Type:DELETES \n"); + LOGE("Failed to parse DIFFS - LINE:[%d] [%s] \n", i + 1, line); + goto CleanUp; + } + retval = + SS_AppendNode(ua_dataSS->update_data->ua_delta_path, &fs_movehead, &fs_movetail, source_name, + target_name, string_na, sha1src, string_na, MOVES, + ua_dataSS->update_delta->ua_patch_path); + if (retval == E_SS_FAILURE) // ONLY test purpose, should enable this + goto CleanUp; + + if (ua_dataSS->ua_operation == UI_OP_SCOUT) { + SS_UpdateUIProgress(ua_dataSS, ulPatchCount, 0); + } + } else if (change_type && strcmp(change_type, SS_STRING_DIFF) == 0) { // && strcmp(file_type,"TPK") == 0){ + source_name = strtok_r(NULL, SS_TOEKN_COLON, &saveptr); + target_name = strtok_r(NULL, SS_TOEKN_COLON, &saveptr); + sha1src = strtok_r(NULL, SS_TOEKN_COLON, &saveptr); + sha1trg = strtok_r(NULL, SS_TOEKN_COLON, &saveptr); + patch_name = strtok_r(NULL, SS_TOKEN_NEWLINE, &saveptr); + //LOGL(LOG_SSENGINE, "%s Index [%d]\n", SS_STRING_DIFF, i); + + if (patch_name && (strlen(patch_name) <= SS_MAX_NAMELENSUPPORTED)) { + retval = + SS_AppendNode(ua_dataSS->update_data->ua_delta_path, &fs_diffhead, &fs_difftail, + source_name, target_name, patch_name, sha1src, sha1trg, DIFFS, + ua_dataSS->update_delta->ua_patch_path); + if (retval == E_SS_FAILURE) // ONLY test purpose, should enable this + goto CleanUp; + } else { + SS_SetUpgradeState(E_SS_FILENAMELENERROR); + LOGE("File Name length Limitation Error File:[%s]\n", patch_name); + goto CleanUp; + } + + if (ua_dataSS->ua_operation == UI_OP_SCOUT) { + SS_UpdateUIProgress(ua_dataSS, ulPatchCount, 0); + } + } else { + SS_SetUpgradeState(E_SS_FSFAILEDTOPARSEDELTAINFO); + LOGE("Patch Name format Error File\n"); + goto CleanUp; + } + } + } + if (local && (local->news) > 0) { //check if new files archive is present in the delta + char new_patch_path[MAX_FILE_PATH] = { 0, }; + snprintf(new_patch_path, MAX_FILE_PATH, "%s%s", ua_dataSS->parti_info->ua_subject_name, SS_COMPRESSED_FILE); + if (tar_get_item_size(ua_dataSS->update_data->ua_delta_path, new_patch_path) <= 0) { + SS_SetUpgradeState(E_SS_FSFAILEDTOPARSEDELTAINFO); + LOGE("New files not present in Patch\n"); + goto CleanUp; + } + } + if (local && (local->deletes) > 0) { //this is to group to delete list + LOGL(LOG_SSENGINE, "%ss [%d]\n", SS_STRING_DEL, local->deletes); + for (i = 0; i < (local->deletes); i++) { + if (fgets(line, SS_TOKEN_MAXLINE_LEN, fp) == NULL) { + SS_SetUpgradeState(E_SS_FSFAILEDTOPARSEDELTAINFO); + break; + } + + change_type = strtok_r(line, SS_TOEKN_COLON, &saveptr); + if (!change_type) { + LOGE("Unexpected null in strtok_r"); + goto CleanUp; + } + file_type = strtok_r(NULL, SS_TOEKN_COLON, &saveptr); + + if (file_type && strcmp(file_type, SS_STRING_REG) == 0) { + source_name = strtok_r(NULL, SS_TOEKN_COLON, &saveptr); + sha1src = strtok_r(NULL, SS_TOKEN_NEWLINE, &saveptr); + del_type = DELETES; + } else if (file_type && strcmp(file_type, SS_STRING_SYM) == 0) { + source_name = strtok_r(NULL, SS_TOKEN_NEWLINE, &saveptr); + sha1src = string_na; + del_type = DELETES; + } else if (file_type && strcmp(file_type, SS_STRING_END) == 0) { + source_name = strtok_r(NULL, SS_TOKEN_NEWLINE, &saveptr); + sha1src = string_na; + del_type = DELETE_END; + } else { + LOGE("Failed to parse DELETES - LINE:[%d] [%s] \n", i + 1, line); + goto CleanUp; + } + + if (!source_name || !sha1src) { + SS_SetUpgradeState(E_SS_FSFAILEDTOPARSEDELTAINFO); + //LOGE("Failed to extract Patch Info Type:DELETES \n"); + LOGE("Failed to parse DELETES - LINE:[%d] [%s] \n", i + 1, line); + goto CleanUp; + } + //LOGL(LOG_SSENGINE, "%s Index [%d]\n", SS_STRING_DEL, i); + retval = + SS_AppendNode(ua_dataSS->update_data->ua_delta_path, &fs_delhead, &fs_deltail, source_name, + string_na, string_na, sha1src, string_na, del_type, + ua_dataSS->update_delta->ua_patch_path); + if (retval == E_SS_FAILURE) // ONLY test purpose, should enable this + goto CleanUp; + if (ua_dataSS->ua_operation == UI_OP_SCOUT) { + SS_UpdateUIProgress(ua_dataSS, ulPatchCount, 0); + } + + } + } //For symlink files + + if (local && (local->symdiffs) > 0) { + LOGL(LOG_SSENGINE, "%s %ss [%d]\n", SS_STRING_SYM, SS_STRING_DIFF, local->symdiffs); + for (i = 0; i < (local->symdiffs); i++) { //get the count from below function + if (fgets(line, SS_TOKEN_MAXLINE_LEN, fp) == NULL) { + SS_SetUpgradeState(E_SS_FSFAILEDTOPARSEDELTAINFO); + break; + } + //LOGL(LOG_SSENGINE, "SYMDIFF LINE:[%d] [%s] \n",i+1,line); + + change_type = strtok_r(line, SS_TOEKN_COLON, &saveptr); + file_type = strtok_r(NULL, SS_TOEKN_COLON, &saveptr); + + if ((change_type && file_type) && + strcmp(change_type, SS_STRING_SYM) == 0 && strcmp(file_type, SS_STRING_DIFF) == 0) { // && strcmp(file_type,"TPK") == 0){ + source_name = strtok_r(NULL, SS_TOEKN_COLON, &saveptr); + target_name = strtok_r(NULL, SS_TOEKN_COLON, &saveptr); + patch_name = strtok_r(NULL, SS_TOKEN_NEWLINE, &saveptr); + //LOGL(LOG_SSENGINE, "%s %s Index [%d]\n", SS_STRING_SYM, SS_STRING_DIFF, i); + + if (!source_name || !target_name || !patch_name) { + SS_SetUpgradeState(E_SS_FSFAILEDTOPARSEDELTAINFO); + //LOGE("Failed to extract Patch Info Type:DELETES \n"); + LOGE("Failed to parse SymDiffs - LINE:[%d] [%s] \n", i + 1, line); + goto CleanUp; + } + retval = + SS_AppendNode(ua_dataSS->update_data->ua_delta_path, &fs_symlinkdiffhead, &fs_symlinkdifftail, + source_name, target_name, patch_name, string_na, string_na, SYMDIFFS, + ua_dataSS->update_delta->ua_patch_path); + if (retval == E_SS_FAILURE) // ONLY test purpose, should enable this + goto CleanUp; + if (ua_dataSS->ua_operation == UI_OP_SCOUT) { + SS_UpdateUIProgress(ua_dataSS, ulPatchCount, 0); + } + } + } + } + if (local && (local->symnews) > 0) { + LOGL(LOG_SSENGINE, "%s %ss [%d]n", SS_STRING_SYM, SS_STRING_NEW, local->symnews); + for (i = 0; i < (local->symnews); i++) { + if (fgets(line, SS_TOKEN_MAXLINE_LEN, fp) == NULL) { + SS_SetUpgradeState(E_SS_FSFAILEDTOPARSEDELTAINFO); + break; + } + //LOGL(LOG_SSENGINE, "SYMNEWS LINE:[%d] [%s] \n",i+1,line); + + change_type = strtok_r(line, SS_TOEKN_COLON, &saveptr); + file_type = strtok_r(NULL, SS_TOEKN_COLON, &saveptr); + + if ((change_type && file_type) && + (strcmp(change_type, SS_STRING_SYM) == 0 && strcmp(file_type, SS_STRING_NEW) == 0)) { + source_name = strtok_r(NULL, SS_TOEKN_COLON, &saveptr); + patch_name = strtok_r(NULL, SS_TOKEN_NEWLINE, &saveptr); + //LOGL(LOG_SSENGINE, "%s %s Index [%d]\n", SS_STRING_SYM, SS_STRING_NEW, i); + + if (!source_name || !patch_name) { + SS_SetUpgradeState(E_SS_FSFAILEDTOPARSEDELTAINFO); + //LOGE("Failed to extract Patch Info Type:DELETES \n"); + LOGE("Failed to parse SymNews - LINE:[%d] [%s] \n", i + 1, line); + goto CleanUp; + } + retval = + SS_AppendNode(ua_dataSS->update_data->ua_delta_path, &fs_symlinknewhead, &fs_symlinknewtail, + source_name, string_na, patch_name, string_na, string_na, SYMNEWFILES, + ua_dataSS->update_delta->ua_patch_path); + if (retval == E_SS_FAILURE) // ONLY test purpose, should enable this + goto CleanUp; + if (ua_dataSS->ua_operation == UI_OP_SCOUT) { + SS_UpdateUIProgress(ua_dataSS, ulPatchCount, 0); + } + } + } + } + + fs_head_node = (fs_list *) SS_Malloc(sizeof(fs_list)); + if (!fs_head_node) { + SS_SetUpgradeState(E_SS_MALLOC_ERROR); + goto CleanUp; + } + fs_head_node->dif_ref = fs_diffhead; + fs_head_node->move_ref = fs_movehead; + fs_head_node->new_ref = fs_newhead; + fs_head_node->del_ref = fs_delhead; + fs_head_node->sym_difref = fs_symlinkdiffhead; + fs_head_node->sym_newref = fs_symlinknewhead; + fs_head_node->ulPatchCount = ulPatchCount; + + if (ua_dataSS->ua_operation == UI_OP_SCOUT) { + SS_UpdateUIProgress(ua_dataSS, ulPatchCount, 1); + } + + CleanUp: + fclose(fp); + SS_Free(local); + unlink(SS_PATCHLIST_BKUPLOC); + if (retval == E_SS_FAILURE) + if (tar_cfg_data) + tar_free_cfg_table(&tar_cfg_data); + return fs_head_node; +} + +void SS_GetPartition_LocDetails(ua_dataSS_t * ua_dataSS) +{ + LOGL(LOG_SSENGINE, "PART NAME: [%s] \n", ua_dataSS->parti_info->ua_parti_name); + snprintf(ua_dataSS->update_delta->ua_patch_path, MAX_FILE_PATH, "%s", ua_dataSS->parti_info->ua_subject_name); + snprintf(ua_dataSS->update_delta->ua_patch_info, MAX_FILE_PATH, "%s%s%s", ua_dataSS->parti_info->ua_subject_name, + ua_dataSS->parti_info->ua_parti_name, SS_PATCHLISTFORMAT); + snprintf(ua_dataSS->update_delta->ua_attrib_path, MAX_FILE_PATH, "%s%s%s", ua_dataSS->parti_info->ua_subject_name, + ua_dataSS->parti_info->ua_parti_name, SS_PATCH_ATTR_FORMAT); + LOGL(LOG_SSENGINE, "PatchPath[%s] PatchInfo [%s] Attributes [%s]\n", ua_dataSS->update_delta->ua_patch_path, + ua_dataSS->update_delta->ua_patch_info, ua_dataSS->update_delta->ua_attrib_path); + + return; +} + +//Support functions//Change Struct format details (Can include total file count also???)/*! +/* +******************************************************************************** * +SS_FSSetAttributes + ********************************************************************************* + * *@brief + * This is used to set the file attributes at the end of application of patches in FS + * + * *@param + * + *@return returns S_SS_SUCCESS + * E_SS_FAILURE in case of error + * + ********************************************************************************* + */ +int SS_FSSetAttributes(ua_dataSS_t * ua_dataSS) +{ + char *pline = NULL; + char *psaveptr = NULL; + char *pfilePath = NULL; + char *pfiletype = NULL; + char *attributSize = NULL; + char *pattribs = NULL; + int ulAttribSize = 0; + int result = S_SS_SUCCESS; + int fail_cnt = 0; + + if (!(ua_dataSS && ua_dataSS->update_delta && ua_dataSS->update_data->ua_delta_path)) { + LOGE("Bad params for SS_FSSetAttributes\n"); + SS_SetUpgradeState(E_SS_BAD_PARAMS); + return E_SS_FAILURE; + } + LOGL(LOG_SSENGINE, "ATTRIB PATH: [%s] \n", ua_dataSS->update_delta->ua_attrib_path); + + int item_size = tar_get_item_size(ua_dataSS->update_data->ua_delta_path, ua_dataSS->update_delta->ua_attrib_path); + + if (item_size <= 0) { + LOGL(LOG_SSENGINE, "No Attributes to SET\n"); + return S_SS_SUCCESS; // Delta with ONLY deletes + } + char *item_data = SS_Malloc(item_size + 1); + if (item_data == NULL) { + LOGE("SS_Malloc failed!! - item_data\n"); + SS_SetUpgradeState(E_SS_MALLOC_ERROR); + return E_SS_FAILURE; + } + int read_data = + tar_get_cfg_data(ua_dataSS->update_data->ua_delta_path, ua_dataSS->update_delta->ua_attrib_path, item_data, + item_size); + if (read_data <= 0) { + LOGE("read_data failed!!\n"); + SS_SetUpgradeState(E_SS_FSBADDELTA); + if (item_data != NULL) { + SS_Free(item_data); + item_data = NULL; + } + return E_SS_FAILURE; + } + item_data[read_data] = '\0'; + + pline = strtok_r(item_data, "\n", &psaveptr); + if (pline == NULL) { + LOGL(LOG_SSENGINE, "No Attributes to SET as no lines in file\n"); + if (item_data != NULL) { + SS_Free(item_data); + item_data = NULL; + } + return E_SS_FAILURE; + } + + while (pline) { + char *saveptr_pline = NULL; + pfilePath = strtok_r(pline, "\"", &saveptr_pline); + + if (pfilePath && strcmp(pfilePath, SS_FWSLASH) == 0) { + LOGE("skip root: it is RO\n"); + pline = strtok_r(NULL, SS_TOKEN_NEWLINE, &psaveptr); + continue; + } + + pfiletype = strtok_r(NULL, SS_TOKEN_SPACE, &saveptr_pline); + attributSize = strtok_r(NULL, SS_TOKEN_SPACE, &saveptr_pline); + pattribs = strtok_r(NULL, SS_TOKEN_NEWLINE, &saveptr_pline); + //LOG("\nSS_FSSetAttributes [%s][%s][%s]", pfiletype, attributSize, pattribs); + if (pattribs && pfilePath && pfiletype && attributSize) { + ulAttribSize = strlen(pattribs); + //LOG("\nSS_SetFileAttributes [%s][%s][%d][%s]",pfilePath,pfiletype,ulAttribSize, pattribs ); + //LOG("SS_SetFileAttributes [%s]\n", pfilePath); + + result = SS_SetFileAttributes(pfilePath, ulAttribSize, (const unsigned char *)pattribs); + if (result != S_SS_SUCCESS) { + LOGE("Failed to set Attributes %s\n", pfilePath); + SS_SetUpgradeState(E_SS_FSBADATTRIBUTES); + if (item_data) { + SS_Free(item_data); + item_data = NULL; + } + fail_cnt++; + } + } else { + LOGE("Failed to Parse Attributes - LINE %s\n", pline); + SS_SetUpgradeState(E_SS_FSBADATTRIBUTES); + if (item_data) { + SS_Free(item_data); + item_data = NULL; + } + fail_cnt++; + } + pline = strtok_r(NULL, SS_TOKEN_NEWLINE, &psaveptr); + } + + if (item_data != NULL) { + SS_Free(item_data); + item_data = NULL; + } + + if (fail_cnt > 0) + result = E_SS_FAILURE; + else + result = S_SS_SUCCESS; + + return result; +} + +/*! + ********************************************************************************* + * SS_FSUpdateFile + ********************************************************************************* + * + * @brief + * This is used to update individual files on case basis + * + * + * @param + * + * @return returns S_SS_SUCCESS + * E_SS_FAILURE in case of error + * + ********************************************************************************* + */ +int SS_FSUpdateFile(int ubFileType, ua_dataSS_t * ua_dataSS, int ulPatchCount, fs_params * pFsNode, + const char *patch_path) +{ + int ulFileIndex = 1; + char ubPatch[SS_MAX_FILE_PATH] = { 0, }; + int ulReadCnt = 0; + int ulResult = S_SS_SUCCESS; + FileInfo source_file; + FileInfo target_file; + uint8_t target_sha1[SHA_DIGEST_SIZE] = { 0, }; + + if (!patch_path) { + LOGE("Bad patch_path name\n"); + return E_SS_FAILURE; + } + switch (ubFileType) { + case DIFFS: + { + LOGL(LOG_SSENGINE, "DIFFS mode start\n"); +#ifdef TIME_PROFILING + get_time_stamp1(); //total time capturing + t1 = atof(ts1); + LOGL(LOG_SSENGINE, "DIFFS mode start time = [%lf]\n", + t1); +#endif + tar_open(ua_dataSS->update_data->ua_delta_path); + while (pFsNode) { + //LOGL(LOG_SSENGINE, "DIFFS update Index: [%d] \n", ulFileIndex++); + snprintf(ubPatch, SS_MAX_FILE_PATH, "%s%s", patch_path, pFsNode->patch_name); + //LOGL(LOG_SSENGINE, "DIFF list --- [File Name %s]\n [Patch Name %s]",pFsNode->file_path, ubPatch); + if (pFsNode->data_size > 0) { + ulReadCnt = + fast_tar_extract_file(ua_dataSS->update_data->ua_delta_path, ubPatch, SS_PATCHFILE_SOURCE, + pFsNode->data_size, pFsNode->data_offset); + if (ulReadCnt < 0) { + ulResult = E_SS_FAILURE; + tar_close(); + SS_SetUpgradeState(E_SS_FSUPDATEFAILED); + LOGE("Delta Read Failed\n"); + break; + } + //LOGL(LOG_SSENGINE,"Updating [Item - %s]and size is[%d] Read Count[%d]\n",ubPatch, pFsNode->data_size, ulReadCnt); + + if (ulReadCnt > 0) + ulResult = + SS_UpdateDeltaFS(pFsNode->file_old_path, pFsNode->file_new_path, pFsNode->sha1src, + pFsNode->sha1trg, pFsNode->data_size); + if (ulResult != S_SS_SUCCESS) { + LOGE("FS update Failed Result : [%d], [Item - %s]and size is[%d] Read Count[%d], index = [%d]\n", ulResult, + ubPatch, pFsNode->data_size, ulReadCnt, ulFileIndex); + tar_close(); + SS_SetUpgradeState(E_SS_FSUPDATEFAILED); + break; + } + SS_UpdateUIProgress(ua_dataSS, ulPatchCount, 0); + pFsNode = pFsNode->nextnode; + } + else { + ulResult = E_SS_FAILURE; + tar_close(); + LOGE("size is invalid, index = [%d]\n", + ulFileIndex); + SS_SetUpgradeState(E_SS_FSUPDATEFAILED); + break; + } + ulFileIndex++; + } + LOGL(LOG_SSENGINE, "DIFFS : Total index = [%d]\n", + ulFileIndex - 1); +#ifdef TIME_PROFILING + get_time_stamp1(); //total time capturing + t2 = atof(ts1); + LOGL(LOG_SSENGINE, + "DIFFS mode end time = [%lf], diff = [%lf]\n", t2, + (t2 - t1)); +#endif + tar_close(); + LOGL(LOG_SSENGINE, "DIFFS mode end\n"); + } + break; + case MOVES: + { + LOGL(LOG_SSENGINE, "MOVES mode start\n"); + +#ifdef TIME_PROFILING + get_time_stamp1(); //total time capturing + t1 = atof(ts1); + LOGL(LOG_SSENGINE, "MOVES mode start time = [%lf]\n", + t1); +#endif + while (pFsNode) { + //LOGL(LOG_SSENGINE, "MOVES update Index: [%d] \n", ulFileIndex++); + int skip_flag = 0; + if (SS_LoadFile(pFsNode->file_old_path, &source_file) == 0) { + LOGL(LOG_SSENGINE, "Patch Can be applied\n"); + if (source_file.data) + SS_Free(source_file.data); + } else if (SS_LoadFile(pFsNode->file_new_path, &target_file) == 0) { + LOGL(LOG_SSENGINE, "source deleted!!, file_old_path: [%s]\n", pFsNode->file_old_path); + if (ParseSha1(pFsNode->sha1src, target_sha1) != 0) { + LOGE("failed to parse sha1 \"%s\"\n", pFsNode->sha1src); + ulResult = E_SS_FAILURE; + SS_SetUpgradeState(E_SS_FSUPDATEFAILED); + if (target_file.data) + SS_Free(target_file.data); + break; + } + if (memcmp(target_file.sha1, target_sha1, SHA_DIGEST_SIZE) == 0) { + LOGL(LOG_SSENGINE, "Patch already applied\n"); + skip_flag = 1; + if (target_file.data) + SS_Free(target_file.data); + } else { + LOGL(LOG_SSENGINE, "target_sha1 diff!!: [%s]\n", target_sha1); + ulResult = E_SS_FAILURE; + SS_SetUpgradeState(E_SS_FSUPDATEFAILED); + if (target_file.data) + SS_Free(target_file.data); + break; + } + } else { + LOGE("No exist files. - file_old_path: [%s] file_new_path: [%s]\n", pFsNode->file_old_path, pFsNode->file_new_path); + ulResult = E_SS_FAILURE; + SS_SetUpgradeState(E_SS_FSUPDATEFAILED); + break; + } + + if (skip_flag == 0) { + ulResult = SS_MoveFile(pFsNode->file_old_path, pFsNode->file_new_path); + if (ulResult != S_SS_SUCCESS) { + LOGE("Move Failed for [%s] to [%s], result = [%d], index = [%d]\n", pFsNode->file_old_path, pFsNode->file_new_path, ulResult, ulFileIndex); + SS_SetUpgradeState(ulResult); + break; + } else { + // Verification + if (SS_LoadFile(pFsNode->file_new_path, &target_file) == 0) { + if (ParseSha1(pFsNode->sha1src, target_sha1) != 0) { + LOGE("failed to parse sha1 \"%s\"\n", pFsNode->sha1src); + ulResult = E_SS_FAILURE; + SS_SetUpgradeState(E_SS_FSUPDATEFAILED); + if (target_file.data) + SS_Free(target_file.data); + break; + } + if (memcmp(target_file.sha1, target_sha1, SHA_DIGEST_SIZE) == 0) { + LOGL(LOG_SSENGINE, "Patch success!!\n"); + if (target_file.data) + SS_Free(target_file.data); + } else { + LOGL(LOG_SSENGINE, "target_sha1 diff!!: [%s]\n", target_sha1); + ulResult = E_SS_FAILURE; + SS_SetUpgradeState(E_SS_FSUPDATEFAILED); + if (target_file.data) + SS_Free(target_file.data); + break; + } + } + } + } + SS_UpdateUIProgress(ua_dataSS, ulPatchCount, 0); + pFsNode = pFsNode->nextnode; + ulFileIndex++; + } + LOGL(LOG_SSENGINE, "MOVES : Total index = [%d]\n", + ulFileIndex - 1); +#ifdef TIME_PROFILING + get_time_stamp1(); //total time capturing + t2 = atof(ts1); + LOGL(LOG_SSENGINE, + "MOVES mode end time = [%lf], diff = [%lf]\n", t2, + (t2 - t1)); +#endif + LOGL(LOG_SSENGINE, "MOVES mode end\n"); + } + break; + case DELETES: + { + LOGL(LOG_SSENGINE, "DELETES mode start\n"); + + int ulFiletype = 0; +#ifdef TIME_PROFILING + get_time_stamp1(); //total time capturing + t1 = atof(ts1); + LOGL(LOG_SSENGINE, "DELETES mode start time = [%lf]\n", + t1); +#endif + while (pFsNode) { + if (pFsNode->type == DELETES) { + //LOGL(LOG_SSENGINE, "DELETES update Index: [%d] \n", ulFileIndex++); + SS_GetFileType(pFsNode->file_old_path, (enumFileType *) & ulFiletype); + if (ulFiletype == 2) //FT_FOLDER + ulResult = SS_DeleteFolder(pFsNode->file_old_path); + else + ulResult = SS_DeleteFile(pFsNode->file_old_path); + if (ulResult != S_SS_SUCCESS) { + LOGE("Delete Failed, result = [%d], index = [%d]\n", ulResult, ulFileIndex); + SS_SetUpgradeState(ulResult); + break; + } + ulFileIndex++; + } + SS_UpdateUIProgress(ua_dataSS, ulPatchCount, 0); + pFsNode = pFsNode->nextnode; + } + LOGL(LOG_SSENGINE, "DELETES : Total index = [%d]\n", + ulFileIndex - 1); +#ifdef TIME_PROFILING + get_time_stamp1(); //total time capturing + t2 = atof(ts1); + LOGL(LOG_SSENGINE, + "DELETES mode end time = [%lf], diff = [%lf]\n", + t2, (t2 - t1)); +#endif + LOGL(LOG_SSENGINE, "DELETES mode end\n"); + } + break; + case DELETE_END: + { + LOGL(LOG_SSENGINE, "DELETE_END mode start\n"); + + int ulFiletype = 0; +#ifdef TIME_PROFILING + get_time_stamp1(); //total time capturing + t1 = atof(ts1); + LOGL(LOG_SSENGINE, + "DELETE_END mode start time = [%lf]\n", t1); +#endif + while (pFsNode) { + if (pFsNode->type == DELETE_END) { + LOGL(LOG_SSENGINE, "DELETE_END update Index: [%d] \n", ulFileIndex++); + SS_GetFileType(pFsNode->file_old_path, (enumFileType *) & ulFiletype); + if (ulFiletype == 2) //FT_FOLDER + ulResult = SS_DeleteFolder(pFsNode->file_old_path); + else + ulResult = SS_DeleteFile(pFsNode->file_old_path); + if (ulResult != S_SS_SUCCESS) { + LOGE("Delete Failed, result = [%d], index = [%d]\n", ulResult, ulFileIndex); + SS_SetUpgradeState(ulResult); + break; + } + ulFileIndex++; + } + pFsNode = pFsNode->nextnode; + } + LOGL(LOG_SSENGINE, "DELETE_END : Total index = [%d]\n", + ulFileIndex - 1); +#ifdef TIME_PROFILING + get_time_stamp1(); //total time capturing + t2 = atof(ts1); + LOGL(LOG_SSENGINE, + "DELETE_END mode start time = [%lf], diff = [%lf]\n", + t2, (t2 - t1)); +#endif + LOGL(LOG_SSENGINE, "DELETE_END mode end\n"); + } + break; + + case NEWFILES: + { + LOGL(LOG_SSENGINE, "NEWFILES mode start\n"); + +#ifdef TIME_PROFILING + get_time_stamp1(); //total time capturing + t1 = atof(ts1); + LOGL(LOG_SSENGINE, "NEWFILES mode start time = [%lf]\n", + t1); +#endif + LOGL(LOG_SSENGINE, "Starting New file upgrade for [%s]\n", patch_path); + if (tar_extract_file(ua_dataSS->update_data->ua_delta_path, (char *)patch_path, SS_NEW_COMPRESSED_FILE) >= + 0) + if (_7zdecompress(SS_NEW_COMPRESSED_FILE) == 0) + LOGL(LOG_SSENGINE, "7zip extracted successfully %s\n", ua_dataSS->parti_info->ua_parti_name); + else + LOGL(LOG_SSENGINE, "7zip extraction error for %s\n", ua_dataSS->parti_info->ua_parti_name); + else + LOGL(LOG_SSENGINE, "tar extraction error for %s\n", ua_dataSS->parti_info->ua_parti_name); + SS_DeleteFile(SS_NEW_COMPRESSED_FILE); +#ifdef TIME_PROFILING + get_time_stamp1(); //total time capturing + t2 = atof(ts1); + LOGL(LOG_SSENGINE, + "NEWFILES mode end time = [%lf], diff = [%lf]\n", + t2, (t2 - t1)); +#endif + LOGL(LOG_SSENGINE, "NEWFILES mode end\n"); + } + break; + case SYMDIFFS: + { + LOGL(LOG_SSENGINE, "SYMDIFFS mode start\n"); + +#ifdef TIME_PROFILING + get_time_stamp1(); //total time capturing + t1 = atof(ts1); + LOGL(LOG_SSENGINE, "SYMDIFFS mode start time = [%lf]\n", + t1); +#endif + while (pFsNode) { + //LOGL(LOG_SSENGINE, "SYMDIFFS update Index: [%d] \n", ulFileIndex++); + //LOG("Sym Diff file paths: [Linkname - %s] [reference file name- %s][]\n", pFsNode->file_path,pFsNode->patch_name); + ulResult = SS_Unlink(pFsNode->file_old_path); + if (ulResult == S_SS_SUCCESS) { + ulResult = SS_Link(NULL, pFsNode->file_new_path, pFsNode->patch_name); + if (ulResult != S_SS_SUCCESS) { + LOGE("SS_Link Failed, Linkname:[%s], reference file name, index = [%d]:[%s]\n", + pFsNode->file_new_path, ulFileIndex, pFsNode->patch_name); + } + } else { + LOGE("Unlink Failed, result = [%d], index = [%d]\n", ulResult, ulFileIndex); + SS_SetUpgradeState(E_SS_FSUPDATEFAILED); + break; + } + SS_UpdateUIProgress(ua_dataSS, ulPatchCount, 0); + pFsNode = pFsNode->nextnode; + ulFileIndex++; + } + LOGL(LOG_SSENGINE, "SYMDIFFS : Total index = [%d]\n", + ulFileIndex - 1); +#ifdef TIME_PROFILING + get_time_stamp1(); //total time capturing + t2 = atof(ts1); + LOGL(LOG_SSENGINE, + "SYMDIFFS mode end time = [%lf], diff = [%lf]\n", + t2, (t2 - t1)); +#endif + LOGL(LOG_SSENGINE, "SYMDIFFS mode end\n"); + } + break; + case SYMNEWFILES: + { + LOGL(LOG_SSENGINE, "SYMNEWFILES mode start\n"); + + fs_params *head_node; + int retry_count = 0, do_retry = 0; +#ifdef TIME_PROFILING + get_time_stamp1(); //total time capturing + t1 = atof(ts1); + LOGL(LOG_SSENGINE, + "SYMNEWFILES mode start time = [%lf]\n", t1); +#endif + SYMLINK_CREATE: + head_node = pFsNode; + while (head_node) { + //LOGL(LOG_SSENGINE, "SYMNEWS update Index: [%d] \n", ulFileIndex++); + snprintf(ubPatch, SS_MAX_FILE_PATH, "%s%s%s", patch_path, "/", head_node->patch_name); + LOGL(LOG_SSENGINE, "Sym New file paths: [Linkname - %s] [reference file name- %s][]\n", + head_node->file_old_path, head_node->patch_name); + ulResult = SS_Link(NULL, head_node->file_old_path, head_node->patch_name); + if (ulResult == E_SS_FAILURE) { + LOGE("Link Failed, result = [%d], index = [%d]\n", ulResult, ulFileIndex); + SS_SetUpgradeState(E_SS_FSUPDATEFAILED); + break; + } else if (ulResult == ENOENT) { //to handle cases where new symlink points to a new symlink yet to be created + do_retry = 1; //we will retry the failed symlinks with error 2 (no file or dir) again after this cycle + //SS_UpdateUIProgress(ua_dataSS,ulPatchCount); + head_node = head_node->nextnode; + continue; + } + SS_UpdateUIProgress(ua_dataSS, ulPatchCount, 0); + head_node = head_node->nextnode; + ulFileIndex++; + } + LOGL(LOG_SSENGINE, "SYMNEWFILES : Total index = [%d]\n", + ulFileIndex - 1); + if (do_retry && (retry_count < 4)) { + retry_count++; + ulFileIndex = 0; + do_retry = 0; + goto SYMLINK_CREATE; + } else if (do_retry && (retry_count >= 4)) { //retry to be done maximum 4 times + LOGE("Link Failed after %d retrys\n", retry_count); + //SS_SetUpgradeState(E_SS_FSUPDATEFAILED); + break; + } +#ifdef TIME_PROFILING + get_time_stamp1(); //total time capturing + t2 = atof(ts1); + LOGL(LOG_SSENGINE, + "SYMNEWFILES mode end time = [%lf], diff = [%lf]\n", + t2, (t2 - t1)); +#endif + LOGL(LOG_SSENGINE, "SYMNEWFILES mode end\n"); + } + break; + default: + break; + } + return ulResult; +} + +#ifdef MEM_PROFILING +extern int max_mem; +extern int cur_mem; +#endif +/*! + ********************************************************************************* + * SS_FSUpdatemain + ********************************************************************************* + * + * @brief + * This is the API exposed from the engine to update FS. + * + * + * @param + * + * @return returns S_SS_SUCCESS + * E_SS_FAILURE in case of error + * + ********************************************************************************* + */ + +int SS_FSUpdatemain(ua_dataSS_t * ua_dataSS, int part_idx) +{ + int ulResult = S_SS_SUCCESS; + int last_update_status = 0; + int del_type = 0; + fs_list *head_ptr_node = NULL; + char new_patch_path[SS_MAX_FILE_PATH] = { + 0 + }; + + if (!ua_dataSS) + return E_SS_BAD_PARAMS; // Set error ?? + head_ptr_node = headptr_list[part_idx]; + + if (!head_ptr_node) { //in case of power failure, try rebilding nodes again + SS_FSVerifyPartition(ua_dataSS, part_idx); + head_ptr_node = headptr_list[part_idx]; + } + + if (!head_ptr_node) + return E_SS_FSBADNODES; + + SS_GetPartition_LocDetails(ua_dataSS); + + LOGL(LOG_SSENGINE, "FS Update Entry PartIndex: [%d]\n", part_idx); + +#ifdef POWER_FAIL_TEST + int fail_test_flag = 0; + fail_test_flag = SS_Get_power_fail_flag(); + LOGL(LOG_SSENGINE, "fail_test_flag: [%d]\n", fail_test_flag); +#endif + + if(SS_Get_last_update_status(&last_update_status, &del_type) == -1) + LOGE("SS_Get_last_update_status failed!!\n"); + + LOGL(LOG_SSENGINE, "last_update_status: [%d], del_type: [%d]\n", last_update_status, del_type); + + if (head_ptr_node->del_ref == NULL) { + LOGL(LOG_SSENGINE, "No DEL header\n"); + } else if (ulResult == S_SS_SUCCESS) { + if (del_type < DELETES) { + ulResult = SS_FSUpdateFile(DELETES, ua_dataSS, head_ptr_node->ulPatchCount, head_ptr_node->del_ref, + ua_dataSS->update_delta->ua_patch_path); + if (ulResult == S_SS_SUCCESS) { + LOGL(LOG_SSENGINE, "SS_FSUpdateFile - DELETES success!!\n"); + +#ifdef POWER_FAIL_TEST + if (fail_test_flag < DELETES) { + if (SS_Do_Power_fail_test(DELETES) == E_SS_FAILURE) { + LOGE("SS_Do_Power_fail_test failed!!\n"); + } + } +#endif + SS_Set_last_update_status(part_idx, DELETES); + } + } else { + LOGL(LOG_SSENGINE, "SS_FSUpdateFile - DELETES already applied!!\n"); + } + } + + if (head_ptr_node->dif_ref == NULL) { + LOGL(LOG_SSENGINE, "No DIFF header\n"); + } else if (ulResult == S_SS_SUCCESS) { + ulResult = + SS_FSUpdateFile(DIFFS, ua_dataSS, head_ptr_node->ulPatchCount, head_ptr_node->dif_ref, + ua_dataSS->update_delta->ua_patch_path); + if (ulResult == S_SS_SUCCESS) { + LOGL(LOG_SSENGINE, "SS_FSUpdateFile - DIFFS success!!\n"); +#ifdef POWER_FAIL_TEST + if (fail_test_flag < DIFFS) { + if (SS_Do_Power_fail_test(DIFFS) == E_SS_FAILURE) { + LOGE("SS_Do_Power_fail_test failed!!\n"); + } + } +#endif + } + } + + if (head_ptr_node->move_ref == NULL) { + LOGL(LOG_SSENGINE, "No MOVE header\n"); + } else if (ulResult == S_SS_SUCCESS) { + if (del_type < MOVES) { + ulResult = + SS_FSUpdateFile(MOVES, ua_dataSS, head_ptr_node->ulPatchCount, head_ptr_node->move_ref, + ua_dataSS->update_delta->ua_patch_path); + if (ulResult == S_SS_SUCCESS) { + LOGL(LOG_SSENGINE, "SS_FSUpdateFile - MOVES success!!\n"); +#ifdef POWER_FAIL_TEST + if (fail_test_flag < MOVES) { + if (SS_Do_Power_fail_test(MOVES) == E_SS_FAILURE) { + LOGE("SS_Do_Power_fail_test failed!!\n"); + } + } +#endif + SS_Set_last_update_status(part_idx, MOVES); + } + } else { + LOGL(LOG_SSENGINE, "SS_FSUpdateFile - MOVES already applied!!\n"); + } + } + + if (head_ptr_node->del_ref == NULL) { + LOGL(LOG_SSENGINE, "No DEL header\n"); + } else if (ulResult == S_SS_SUCCESS) { + if (del_type < DELETE_END) { + ulResult = SS_FSUpdateFile(DELETE_END, ua_dataSS, head_ptr_node->ulPatchCount, head_ptr_node->del_ref, + ua_dataSS->update_delta->ua_patch_path); + if (ulResult == S_SS_SUCCESS) { + LOGL(LOG_SSENGINE, "SS_FSUpdateFile - DELETE_END success!!\n"); +#ifdef POWER_FAIL_TEST + if (fail_test_flag < DELETE_END) { + if (SS_Do_Power_fail_test(DELETE_END) == E_SS_FAILURE) { + LOGE("SS_Do_Power_fail_test failed!!\n"); + } + } +#endif + SS_Set_last_update_status(part_idx, DELETE_END); + } + } else { + LOGL(LOG_SSENGINE, "SS_FSUpdateFile - DELETE_END already applied!!\n"); + } + } + + if (ulResult == S_SS_SUCCESS) { + //new file extraction start + snprintf(new_patch_path, SS_MAX_FILE_PATH, "%s%s", ua_dataSS->parti_info->ua_subject_name, SS_COMPRESSED_FILE); // subject name wil have fw slash as part of cfg file + LOGL(LOG_SSENGINE, "File path created to extract new files : [%s]\n", new_patch_path); + ulResult = + SS_FSUpdateFile(NEWFILES, ua_dataSS, head_ptr_node->ulPatchCount, head_ptr_node->new_ref, new_patch_path); + //new file extraction end + if (ulResult == S_SS_SUCCESS) { + LOGL(LOG_SSENGINE, "SS_FSUpdateFile - NEWFILES success!!\n"); + } + } + + if (head_ptr_node->sym_difref == NULL) { + LOGL(LOG_SSENGINE, "No SYMDIFF header\n"); + } else if (ulResult == S_SS_SUCCESS) { + ulResult = + SS_FSUpdateFile(SYMDIFFS, ua_dataSS, head_ptr_node->ulPatchCount, head_ptr_node->sym_difref, + ua_dataSS->update_delta->ua_patch_path); + if (ulResult == S_SS_SUCCESS) { + LOGL(LOG_SSENGINE, "SS_FSUpdateFile - SYMDIFFS success!!\n"); +#ifdef POWER_FAIL_TEST + if (fail_test_flag < SYMDIFFS) { + if (SS_Do_Power_fail_test(SYMDIFFS) == E_SS_FAILURE) { + LOGE("SS_Do_Power_fail_test failed!!\n"); + } + } +#endif + } + } + + if (head_ptr_node->sym_newref == NULL) { + LOGL(LOG_SSENGINE, "No SYMNEW header\n"); + } else if (ulResult == S_SS_SUCCESS) { + ulResult = + SS_FSUpdateFile(SYMNEWFILES, ua_dataSS, head_ptr_node->ulPatchCount, head_ptr_node->sym_newref, + ua_dataSS->update_delta->ua_patch_path); + if (ulResult == S_SS_SUCCESS) { + LOGL(LOG_SSENGINE, "SS_FSUpdateFile - SYMNEWFILES success!!\n"); +#ifdef POWER_FAIL_TEST + if (fail_test_flag < SYMNEWFILES) { + if (SS_Do_Power_fail_test(SYMNEWFILES) == E_SS_FAILURE) { + LOGE("SS_Do_Power_fail_test failed!!\n"); + } + } +#endif + } + } + + + if (ulResult == S_SS_SUCCESS) { + ulResult = SS_FSSetAttributes(ua_dataSS); + } else { + SS_FSSetAttributes(ua_dataSS); // To prevent boot failures by smack. + } + + sync(); + sleep(1); + SS_FSClearNodes(part_idx); + + if (ulResult == S_SS_SUCCESS) { + SS_UpdateUIProgress(ua_dataSS, 0, 1); //fix WGID : 51963, When all updates are done to FS , patchcount is not needed, passing 1 to 3rd arg is enough + SS_Set_last_update_status(part_idx, DEL_TYPE_MAX); + } + + LOGL(LOG_SSENGINE, "FS update Complete PartIndex: [%d]\n", part_idx); +#ifdef MEM_PROFILING + LOGL(LOG_SSENGINE, "Stats are : Cur Max : [%d] Global Max : [%d]\n", cur_mem, max_mem); +#endif +#ifdef POWER_FAIL_TEST + unlink(SS_POWER_FAIL_TEST_FLAG); +#endif + if (ulResult == S_SS_SUCCESS) + return ulResult; + else + return SS_GetUpgradeState(); +} + +/*! + ********************************************************************************* + * SS_FSUpdatemain + ********************************************************************************* + * + * @brief + * This is the API exposed from the engine to update FS. + * FS entry function for updating FS partition. Should be invoked only after verification of the partition + * + * + * @param Requires common data structure having all details & Partition Index. + * (Used for getting right NODES information that built during verification) + * (Configuration, Delta info, Partition Info, UI link , Kind of operation.(Verify or Updates)) + * + * @return returns S_SS_SUCCESS + * E_SS_FAILURE in case of error + * + ********************************************************************************* + */ +size_t SS_FSAvailiableFreeSpace(char *block_name) +{ + + struct mntent *ent; + FILE *aFile; + struct statfs sb; + aFile = setmntent("/proc/mounts", "r"); + if (aFile == NULL) { + LOGE("setmntent error\n"); + return E_SS_FAILURE; + } + while (NULL != (ent = getmntent(aFile))) { + if (strcmp(ent->mnt_fsname, block_name) == 0) { + if (statfs(ent->mnt_dir, &sb) == 0) + LOGL(LOG_SSENGINE, "Total free space = %" PRIu64 ", blocks free = %" PRIu64 "\n", sb.f_bsize * sb.f_bavail, sb.f_bfree); + } + } + endmntent(aFile); + return ((long long)sb.f_bsize * (long long)sb.f_bavail >= (long long)SIZE_4GB) ? SIZE_4GB : sb.f_bsize * sb.f_bavail ; +} + +int SS_FSVerifyPartition(ua_dataSS_t * ua_dataSS, int part_idx) +{ + int ulResult = S_SS_SUCCESS; + size_t free_space = 0; + if (!ua_dataSS) { + LOGE("Wrong Param for fs verification\n"); + SS_SetUpgradeState(E_SS_BAD_PARAMS); + return E_SS_FAILURE; + } + + LOGL(LOG_SSENGINE, "FS max free mem reqired : [%d]\n", ua_dataSS->update_cfg->soure_img_size); + free_space = SS_FSAvailiableFreeSpace(ua_dataSS->parti_info->ua_blk_name); + if (free_space != E_SS_FAILURE) { + //Source img size is max single file size for a file system under upgrade, which is updated in CFG file by UPG + if ((free_space) < (ua_dataSS->update_cfg->soure_img_size + ua_dataSS->update_cfg->soure_img_size / 10)) { + LOGE("Not enough free space [%d] for max size [%d]\n", free_space, + (ua_dataSS->update_cfg->soure_img_size + ua_dataSS->update_cfg->soure_img_size / 10)); + //SS_SetUpgradeState(E_SS_FSMEMORYERROR); + //return E_SS_FAILURE; + } else + LOGL(LOG_SSENGINE, "Enough space for Partition [%s]\n", ua_dataSS->parti_info->ua_parti_name); + } + + SS_GetAvailableFreeSpace(SS_COMMON_WORKSPACE, &free_space); + //Checking for 2 times the file size free space , as delta can be worst case size of file. + if ((free_space) < (2 * ua_dataSS->update_cfg->soure_img_size)) { + LOGE("Not enough free space [%d] for max size [%d]\n", free_space, (2 * ua_dataSS->update_cfg->soure_img_size)); + SS_SetUpgradeState(E_SS_FSMEMORYERROR); + return E_SS_FAILURE; + } +#ifdef MEM_PROFILING + if (!mem_profiling_start) + if (!(S_SS_SUCCESS == SS_Do_Memory_Profiling())) + return E_SS_FAILURE; +#endif + SS_GetPartition_LocDetails(ua_dataSS); + LOGL(LOG_SSENGINE, "FS Verification Start PartIndex:[%d]\n", part_idx); + if (ua_dataSS->ua_operation == UI_OP_SCOUT) + gvalid_session = 1; // (shd b true if called during verification) + headptr_list[part_idx] = SS_FSBuildNodes(ua_dataSS); +#ifdef TIME_PROFILING + LOGL(LOG_SSENGINE, "fast_tar_get_item_size_time :[%lf]\n", fast_tar_get_item_size_time); + LOGL(LOG_SSENGINE, "SS_LoadFile_time :[%lf]\n", SS_LoadFile_time); + LOGL(LOG_SSENGINE, "SS_FSBuildNodes_time :[%lf]\n", SS_FSBuildNodes_time); +#endif + if (!headptr_list[part_idx]) { + LOGE("FS Verification Failed PartIndex: [%d]\n", part_idx); + SS_FSClearNodes(part_idx); + ulResult = E_SS_FAILURE; + } + + if (ulResult == S_SS_SUCCESS) + return ulResult; + else + return SS_GetUpgradeState(); +} + +//Should check if space is available???? +int SS_BackupSource(const char *source_filename) +{ + int ret = E_SS_FAILURE; + + if (source_filename) { + ret = (int)SS_CopyFile(source_filename, SS_BACKUP_SOURCE); + if (ret != S_SS_SUCCESS) { + LOGE("failed to back up source file Error [%d]\n", ret); + SS_SetUpgradeState(E_SS_FSSRCBACKUPFAILED); + } + } + return ret; +} + +int SS_BackupSourceClear(void) +{ + int ret = E_SS_FAILURE; + ret = (int)SS_DeleteFile(SS_BACKUP_SOURCE); + if (ret != S_SS_SUCCESS) { + LOGE("failed to delete BACKUP file\n"); + SS_SetUpgradeState(E_SS_FSSRCBACKUPFAILED); + } + return ret; +} + +int SS_PatchSourceClear(void) +{ + int ret = E_SS_FAILURE; + ret = (int)SS_DeleteFile(SS_PATCHFILE_SOURCE); + if (ret != S_SS_SUCCESS) { + LOGE("failed to delete PATCHFILE file\n"); + SS_SetUpgradeState(E_SS_PATCHFILE_DEL_ERROR); + } + return ret; +} +int SS_IMGVerifyFullImage(ua_dataSS_t * ua_dataSS) +{ + int read_cnt = 0, patch_size = 0; + FileInfo source_file; + uint8_t target_sha1[SHA_DIGEST_SIZE]; + int ulResult = S_SS_SUCCESS; + + if (!(ua_dataSS && ua_dataSS->update_cfg && ua_dataSS->parti_info && + ua_dataSS->parti_info->ua_blk_name && + !(ua_dataSS->update_cfg->skip_verify == 1))) { + LOGE("Bad structure or members\n"); + SS_SetUpgradeState(E_SS_BAD_PARAMS); + return E_SS_FAILURE; + } + + LOGL(LOG_SSENGINE, "FULL IMG Verification Entry BlkName:[%s]\n", ua_dataSS->parti_info->ua_blk_name); + + if (ua_dataSS->update_data && ua_dataSS->parti_info && ua_dataSS->update_data->ua_delta_path + && ua_dataSS->parti_info->ua_subject_name) { + patch_size = tar_get_item_size(ua_dataSS->update_data->ua_delta_path, ua_dataSS->parti_info->ua_subject_name); + } else { + LOGE("Bad structure members in ua_dataSS\n"); + SS_SetUpgradeState(E_SS_BAD_PARAMS); + ulResult = E_SS_FAILURE; + goto Cleanup; + } + + if (ua_dataSS->update_cfg && ua_dataSS->update_cfg->soure_img_size && ua_dataSS->update_cfg->target_sha1) { + LOGL(LOG_SSENGINE, "\nParams -image size [%d] sha1 [%s]\n", + ua_dataSS->update_cfg->soure_img_size, ua_dataSS->update_cfg->target_sha1); + } else { + LOGE("Bad structure member update_cfg in ua_dataSS\n"); + SS_SetUpgradeState(E_SS_BAD_PARAMS); + ulResult = E_SS_FAILURE; + goto Cleanup; + } + + if (ParseSha1(ua_dataSS->update_cfg->target_sha1, target_sha1) != 0) { + LOGE("failed to parse tgt-sha1 \"%s\"\n", ua_dataSS->update_cfg->target_sha1); + SS_SetUpgradeState(E_SS_IMGBADDELTA); + ulResult = E_SS_FAILURE; + goto Cleanup; + } + + if ((patch_size) > 0) + read_cnt = tar_extract_file(ua_dataSS->update_data->ua_delta_path, + ua_dataSS->parti_info->ua_subject_name, SS_PATCHFILE_SOURCE); + + if (read_cnt <= 0) { + LOGL(LOG_SSENGINE, "Failed to read delta\n"); + SS_SetUpgradeState(E_SS_IMGBADDELTA); + ulResult = E_SS_FAILURE; + goto Cleanup; + } + if (SS_LoadFile(SS_PATCHFILE_SOURCE, &source_file) == 0) { + if (memcmp(source_file.sha1, target_sha1, SHA_DIGEST_SIZE) == 0) { + LOGL(LOG_SSENGINE, "Patch Can be applied\n"); + SS_Free(source_file.data); + ulResult = S_SS_SUCCESS; + } else{ + LOGL(LOG_SSENGINE, "Patch Cannot be applied\n"); + SS_Free(source_file.data); + SS_SetUpgradeState(E_SS_IMGBADDELTA); + ulResult = E_SS_FAILURE; + goto Cleanup; + } + } else { + LOGL(LOG_SSENGINE, "Failed to LoadFile\n"); + SS_SetUpgradeState(E_SS_IMGBADDELTA); + ulResult = E_SS_FAILURE; + } + +Cleanup: + if (file_exist(SS_PATCHFILE_SOURCE)) + SS_DeleteFile(SS_PATCHFILE_SOURCE); + return ulResult; +} + +int SS_IMGVerfiyPartition(ua_dataSS_t * ua_dataSS, const char *src_blk_name, bool check_free_space) +{ + int ulResult = S_SS_SUCCESS; + uint8_t source_sha1[SHA_DIGEST_SIZE]; + uint8_t target_sha1[SHA_DIGEST_SIZE]; + uint8_t calculated_sha1[SHA_DIGEST_SIZE]; + size_t free_space = 0; + + if (!(ua_dataSS && ua_dataSS->update_cfg && ua_dataSS->parti_info && src_blk_name)) { + LOGE("Bad structure or members\n"); + SS_SetUpgradeState(E_SS_BAD_PARAMS); + return E_SS_FAILURE; + } + + if (check_free_space) { + //We verify twice the image size for BACKUP source, not on Partition. As Patch will be created on RAM + SS_GetAvailableFreeSpace(SS_COMMON_WORKSPACE, &free_space); + if ((free_space) < (2 * ua_dataSS->update_cfg->target_img_size)) { + LOGE("Not enough free space [%d] for twice max size [%d]\n", free_space, + (2 * ua_dataSS->update_cfg->target_img_size)); + SS_SetUpgradeState(E_SS_FSMEMORYERROR); + return E_SS_FAILURE; + } + } + + if (ParseSha1(ua_dataSS->update_cfg->soure_sha1, source_sha1) != 0) { + LOGE("failed to parse Src-sha1 \"%s\"\n", ua_dataSS->update_cfg->soure_sha1); + SS_SetUpgradeState(E_SS_SHAPRASE_FAILED); + return E_SS_FAILURE; + } + // corner case, Parsing sha can fail if update.cfg is wrong/manually edited + if (ParseSha1(ua_dataSS->update_cfg->target_sha1, target_sha1) != 0) { + LOGE("failed to parse Target-sha1 \"%s\"\n", ua_dataSS->update_cfg->target_sha1); + SS_SetUpgradeState(E_SS_SHAPRASE_FAILED); + return E_SS_FAILURE; + } + + /* + * If ab_update is set it means it is a DELTA_IMAGE update, where the patch + * is applied to data directly read from a partition in the previous slot + */ + SS_CalculateFileSha(src_blk_name, ua_dataSS->update_cfg->soure_img_size, calculated_sha1); + if (memcmp(calculated_sha1, source_sha1, SHA_DIGEST_SIZE) == 0) { + LOGL(LOG_SSENGINE, "SS_IMGVerfiyPartition - SHA matches with source [%s] \n", src_blk_name); + } else { // Need not compare with Target sha as once upgraded, it should NOT verify same partition again. + unsigned char actualShaBuffer[41] = { 0, }; + hex_digest(calculated_sha1, actualShaBuffer, SHA_DIGEST_SIZE); + LOGE("SS_IMGVerfiyPartition - SHA mismatch with SRC [%s] Expected [%s] Actual [%s]\n", + src_blk_name, ua_dataSS->update_cfg->soure_sha1, actualShaBuffer); + SS_SetUpgradeState(E_SS_IMGSRCCURRUPTED); + ulResult = E_SS_FAILURE; + } + if (ulResult == S_SS_SUCCESS) { + if (ua_dataSS->ui_progress) + ua_dataSS->ui_progress(ua_dataSS, 100); + return ulResult; + } else + return SS_GetUpgradeState(); +} + +/*! + ********************************************************************************* + * SS_IMGUpdatemain + ********************************************************************************* + * + * @brief + * This is the API exposed from the engine to update Images(FULL and DELTA images) + * + * + * @param + * + * @return returns S_SS_SUCCESS + * E_SS_FAILURE in case of error + * + ********************************************************************************* + */ + +int SS_IMGUpdatemain(ua_dataSS_t * ua_dataSS, int update_type) //SS_FSUpdatePartition +{ + int read_cnt = 0, patch_size; + int ulResult = S_SS_SUCCESS; + + //sprintf(Blk_name, "%s%s%s","EMMC",":", ua_dataSS->parti_info->ua_blk_name); + //LOGL(LOG_SSENGINE, "IMG Upgrade Entry BlkName:[%s]\n",Blk_name); + if (!ua_dataSS) { + LOGE("Bad structure ua_dataSS\n"); + SS_SetUpgradeState(E_SS_BAD_PARAMS); + return E_SS_FAILURE; + } + LOGL(LOG_SSENGINE, "IMG Upgrade Entry BlkName:[%s]\n", ua_dataSS->parti_info->ua_blk_name); + + if (ua_dataSS->update_data && ua_dataSS->parti_info && ua_dataSS->update_data->ua_delta_path + && ua_dataSS->parti_info->ua_subject_name) + patch_size = tar_get_item_size(ua_dataSS->update_data->ua_delta_path, ua_dataSS->parti_info->ua_subject_name); + else { + LOGE("Bad structure members in ua_dataSS\n"); + SS_SetUpgradeState(E_SS_BAD_PARAMS); + return E_SS_FAILURE; + } + if (ua_dataSS->update_cfg && ua_dataSS->update_cfg->soure_img_size && ua_dataSS->update_cfg->target_sha1) + LOGL(LOG_SSENGINE, "SS_IMGUpdatemain Params -source size [%d] sha1 [%s]\n", + ua_dataSS->update_cfg->soure_img_size, ua_dataSS->update_cfg->target_sha1); + else { + LOGE("Bad structure member update_cfg in ua_dataSS\n"); + SS_SetUpgradeState(E_SS_BAD_PARAMS); + return E_SS_FAILURE; + } + + if ((patch_size) > 0) + read_cnt = + tar_extract_file(ua_dataSS->update_data->ua_delta_path, ua_dataSS->parti_info->ua_subject_name, + SS_PATCHFILE_SOURCE); + + if (read_cnt <= 0) { + ulResult = E_SS_FAILURE; + SS_SetUpgradeState(E_SS_IMGBADDELTA); + return E_SS_FAILURE; //ulResult; + } + if (ua_dataSS->ui_progress) + ua_dataSS->ui_progress(ua_dataSS, 40); + + if (update_type == FULL_IMAGE && ua_dataSS->update_data->ua_temp_path) + ulResult = SS_MoveFile(SS_PATCHFILE_SOURCE, ua_dataSS->update_data->ua_temp_path); + else if (ua_dataSS->update_cfg->update_type == EXTRA || ua_dataSS->update_cfg->update_type == DELTA_IMAGE) { + + FILE *fp = NULL; + char buf[14] = { 0, }; //to store zImage-delta magic keyword + char err_buf[256]; + ssize_t bytes_read; + fp = fopen(SS_PATCHFILE_SOURCE, "r"); + if (fp == NULL) { + strerror_r(errno, err_buf, sizeof(err_buf)); + LOGE("Failed to open patch file Error:[%s]\n", err_buf); + SS_SetUpgradeState(E_SS_FSFAILEDTOOPENPATCHINFO); + return E_SS_FAILURE; + } + bytes_read = fread(buf, 1, 13, fp); //error check not required as any delta corruption will be caught in SS_UpdateDeltaIMG + if (bytes_read != 13) + LOGL(LOG_SSENGINE, "short read of \"%s\" (%ld bytes of %ld)\n", SS_PATCHFILE_SOURCE, (long)bytes_read, (long)13); + fclose(fp); + + if (update_type == DELTA_IMAGE) + ulResult = SS_UpdateDeltaIMGAB(ua_dataSS); + else if (strncmp(buf, SS_KERNEL_MAGIC, sizeof(buf) / sizeof(char)) == 0) + ulResult = SS_UpdateDeltaKernel(ua_dataSS, ua_dataSS->write_data_to_blkdev); + } else { + LOGE("Update type is INVALID - Exit \n"); + ulResult = E_SS_FAILURE; + SS_SetUpgradeState(E_SS_BAD_PARAMS); + return E_SS_FAILURE; + } + + if (ulResult == S_SS_SUCCESS) { + if (ua_dataSS->ui_progress) + ua_dataSS->ui_progress(ua_dataSS, 100); + return ulResult; + } else + return SS_GetUpgradeState(); +} diff --git a/src/delta-ua/engine/SS_UPI.h b/src/delta-ua/engine/SS_UPI.h new file mode 100755 index 0000000..9e6fa1d --- /dev/null +++ b/src/delta-ua/engine/SS_UPI.h @@ -0,0 +1,91 @@ +/* + * libtota + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SS_UPI_H_ +#define _SS_UPI_H_ +#include + +#define DISPLAYRESOLUTION_SIZE 50 + +struct details { + int diffs; + int moves; + int news; + int deletes; + int symdiffs; + int symnews; +}; + +enum DEL_TYPE { DELETES = 1, DIFFS, MOVES, DELETE_END, NEWFILES, SYMDIFFS, SYMNEWFILES, DEL_TYPE_MAX }; +struct fs_params { // Use Macros + char file_old_path[512]; + char file_new_path[512]; + char patch_name[256]; + char sha1src[64]; + char sha1trg[64]; + int data_size; + int data_offset; + int type; //0 is for diff and 1 is for verbatim + struct fs_params *nextnode; +}; +typedef struct fs_params fs_params; + +struct fs_list { + fs_params *dif_ref; + fs_params *move_ref; + fs_params *new_ref; + fs_params *del_ref; + fs_params *sym_difref; + fs_params *sym_newref; + int ulPatchCount; +}; +typedef struct fs_list fs_list; +struct details *get_fs_details(char *filename); + +int SS_AppendNode(const char *ubDeltaPath, fs_params ** headparam, fs_params ** tailparam, const char *old_path, + const char *new_path, const char *patchname, const char *sha1src, const char *sha1trg, int type, + char *patchpath_name); +extern int SS_IMGUpdatemain(ua_dataSS_t * ua_dataSS, int update_type); +extern int SS_IMGVerfiyPartition(ua_dataSS_t * ua_dataSS, const char *src_blk_name, bool check_free_space); +extern int SS_FSUpdatemain(ua_dataSS_t * ua_dataSS, int part_idx); +extern int SS_FSVerifyPartition(ua_dataSS_t * ua_dataSS, int part_idx); +extern int SS_UpdateDeltaIMG(ua_dataSS_t * ua_dataSS, int (*write_to_blkdev) (char *, int, int, char *)); +extern int SS_UpdateDeltaKernel(ua_dataSS_t * ua_dataSS, int (*write_to_blkdev) (char *, int, int, char *)); +extern int SS_UpdateDeltaIMGAB(ua_dataSS_t * ua_dataSS); + +//extra functions +extern void *SS_Malloc(unsigned int size); +extern int tar_get_item_size_from_struct(tar_Data_t **, const char *, int *, int *); +extern void SS_Free(void *pMemBlock); +extern int tar_get_item_size(char *tar, char *item); +extern int tar_get_cfg_data(char *tar, char *item, char *buf, int buflen); +extern tar_Data_t *tar_build_cfg_table(char *tar); +extern int tar_open(char *tar); +extern int fast_tar_extract_file(char *tar, char *item, char *pathname, int size, int offset); +extern int tar_close(); +extern int SS_UpdateDeltaFS(const char *source_filename, const char *target_filename, + const char *source_sha1_str, const char *target_sha1_str, int patch_data_size); +extern int tar_extract_file(char *tar, char *item, char *pathname); +extern int _7zdecompress(char *path); +extern void tar_free_cfg_table(tar_Data_t ** delta_tar); +extern long SS_GetFileType(char *pLinkName, enumFileType * fileType); + +extern int SS_Get_last_update_status(int* last_update_status, int* del_type); +extern void SS_Set_last_update_status(int last_update_status, int del_type); + +#endif //_SS_UPI_H_ diff --git a/src/delta-ua/engine/fota_common.h b/src/delta-ua/engine/fota_common.h new file mode 100755 index 0000000..93d28fa --- /dev/null +++ b/src/delta-ua/engine/fota_common.h @@ -0,0 +1,136 @@ +/* + * libtota + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __FOTA_COMMON_H__ +#define __FOTA_COMMON_H__ + +#include +#include "fota_log.h" + +typedef signed char s8; +typedef unsigned char u8; + +typedef signed short s16; +typedef unsigned short u16; + +typedef signed int s32; +typedef unsigned int u32; +#ifndef __size_t /* typedef check for x86 env: stddef.h */ +#define __size_t +typedef u32 size_t; +#endif /* __size_t */ + +typedef signed long sl32; +typedef unsigned long ul32; + +typedef signed long long s64; +typedef unsigned long long u64; + +#define MAX_FILE_PATH 512 + +#ifndef TIME_PROFILING + //#define TIME_PROFILING +#endif +#ifndef HEAP_PROFILING + //#define HEAP_PROFILING; +#endif +#ifndef MEM_PROFILING + //#define MEM_PROFILING +#endif +#ifndef POWER_FAIL_TEST + //#define POWER_FAIL_TEST +#endif + +#define UNUSED(x) (void)(x) + +#define SS_TOTA_VERSION "1.0.19" +#define BSDIFF "BSDIFF40" +#define IMGDIFF "IMGDIFF2" +#define SECTOR_SIZE 512 +#define SS_KERNEL_DELTA_HEADER 128 + +#define SS_COMMON_WORKSPACE "/run/upgrade-sysroot/opt/usr/data/fota" +#define SS_KERNEL_UNPACK_SCRIPT "unpack.sh" +#define SS_KERN_UNPK_SCRIPT_PATH SS_COMMON_WORKSPACE "/" SS_KERNEL_UNPACK_SCRIPT +#define SS_BACKUP_SOURCE SS_COMMON_WORKSPACE "/saved.file" //How to make sure there is SPACE +#define SS_PATCHFILE_SOURCE SS_COMMON_WORKSPACE "/patchfile.file" //define in common place +#define SS_PATCHLIST_BKUPLOC SS_COMMON_WORKSPACE "/patchlist.txt" +#define SS_NEW_COMPRESSED_FILE SS_COMMON_WORKSPACE "/system.7z" +#define SS_KERNEL_WORKSPACE SS_COMMON_WORKSPACE "/kernel-work" +#define SS_GZIP_TARGET SS_KERNEL_WORKSPACE "/gzip" +#define SS_STAT_TARGET SS_KERNEL_WORKSPACE "/stat" +#define SS_DD_TARGET SS_KERNEL_WORKSPACE "/dd" +//#define SS_UPDATE_STATUR_PATH SS_COMMON_WORKSPACE "/UP.STATUS" +#define SS_UPDATE_STATUR_PATH "/run/upgrade-sysroot/opt/data/recovery/UP.STATUS" + +#define SS_GZIP_SOURCE "run/upgrade-sysroot/bin/gzip" +#define SS_STAT_SOURCE "run/upgrade-sysroot/usr/bin/stat" +#define SS_DD_SOURCE "run/upgrade-sysroot/bin/dd" + +#define SS_KERNEL_MAGIC "UnpackdzImage" +#define SS_KERNEL_NAME "zImage" +#define SS_KERNEL_TARGET_NAME "dzImage_final" +#define SS_KERNEL_UNPACK_DIR SS_KERNEL_NAME "_unpacked" +#define SS_PATCHLISTFOLDER "/p" +#define SS_NEWPATCHFOLDER "/n" +#define SS_PATCHLISTFORMAT ".txt" +#define SS_PATCH_ATTR_FORMAT "_attr.txt" +#define SS_FSCOUNT_MAGIC_KEY "PaTcHCoUnT:" +#define SS_FSCOUNT_MAGIG_KEYLEN (11) //length of SS_FSCOUNT_MAGIC_KEY +#define SS_IMAGE_MAGIC_KEY "TiZSiG@tOtA_00_:.{0,64}" +#define SS_IMAGE_MAGIC_KEY_VAL SS_COMMON_WORKSPACE "/delta_sha.txt" + +#define SS_TOKEN_SPACE " " +#define SS_TOKEN_NEWLINE "\n" +#define SS_TOEKN_COLON ":" +#define SS_CHAR_FWSLASH '/' +#define SS_FWSLASH "/" +#define SS_NULLENTRY "0" +#define SS_MAX_NAMELENSUPPORTED (200) //(Tar supports 256, But extra space is used for PartitionName, .delta, /p, so restricting filename max to 200) +#define SS_MAX_FILE_PATH (512) +#define SS_TOKEN_MAXLINE_LEN (1024) +#define SS_COMPRESSED_FILE "system.7z" + +#define SS_STRING_DIFF "DIFF" +#define SS_STRING_MOVE "MOVE" +#define SS_STRING_DEL "DEL" +#define SS_STRING_SYM "SYM" +#define SS_STRING_NEW "NEW" +#define SS_STRING_REG "REG" +#define SS_STRING_TPK "TPK" +#define SS_STRING_ZIP "ZIP" +#define SS_STRING_END "END" + +#ifdef MEM_PROFILING +#define SS_MEMORY_USAGE_LOG SS_COMMON_WORKSPACE "/log_memory" +#define SS_MEMORY_PROFILING_SCRIPT SS_COMMON_WORKSPACE "/mem_use.sh" +#endif + +#ifdef POWER_FAIL_TEST +#define SS_POWER_FAIL_TEST_FLAG SS_COMMON_WORKSPACE "/power_fail_test_flag" +#endif + +struct tar_Data { + int itemSize; + int itemOffset; + int itemName[256]; + struct tar_Data *nextnode; +}; +typedef struct tar_Data tar_Data_t; + +#endif /* __FOTA_COMMON_H__ */ diff --git a/src/delta-ua/engine/fota_log.c b/src/delta-ua/engine/fota_log.c new file mode 100755 index 0000000..348dba0 --- /dev/null +++ b/src/delta-ua/engine/fota_log.c @@ -0,0 +1,193 @@ +/* + * libtota + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOG_SIZE_OPT_PATH "/opt/data/recovery/.ua_log_size" +#define DEF_MAX_LOG_SIZE (2*1024*1024) +#define MAX_FILE_PATH 512 + +long curr_offset = 0; +long next_offset = 0; +long backup_offset = 0; +long max_logfile_size = DEF_MAX_LOG_SIZE; + +/*----------------------------------------------------------------------------- + __check_existence + ----------------------------------------------------------------------------*/ +static long __check_existence(const char *file_path) +{ + struct stat statbuf; + char filename[MAX_FILE_PATH]; + + if (strncpy(filename, file_path, strlen(file_path) + 1) == NULL) + return 0; + if (stat(filename, &statbuf)) { + if (ENOENT == errno) + return 0; + } + return statbuf.st_size; +} + +/*----------------------------------------------------------------------------- + __read_from_file + ----------------------------------------------------------------------------*/ +static int __read_from_file(const char *path, char *buf, size_t size) +{ + int fd; + ssize_t count; + + if (!path) + return -1; + + if (size == 0) + return 0; + + fd = open(path, O_RDONLY, 0); + if (fd == -1) + return -1; + + count = read(fd, buf, size); + if (count > 0) { + count = (count < (ssize_t)size) ? count : ((ssize_t)size - 1); + while (count > 0 && buf[count - 1] == '\n') + count--; + buf[count] = '\0'; + } else { + buf[0] = '\0'; + } + + close(fd); + + return (int)count; +} + +/*----------------------------------------------------------------------------- + get_opt_logfile_size + ----------------------------------------------------------------------------*/ +static int get_opt_logfile_size(void) +{ + /* + if status file does not exist, status = UP_START_NONE. + if status file exist, read status from file. + */ + char buf[256]; + + if (__check_existence(LOG_SIZE_OPT_PATH) == 0) + return -1; + + if (__read_from_file(LOG_SIZE_OPT_PATH, buf, sizeof(buf)) < 0) + return -1; + + return atoi(buf); +} + +/*----------------------------------------------------------------------------- + set_max_logfile_size + ----------------------------------------------------------------------------*/ +void set_max_logfile_size(void) +{ + int size = get_opt_logfile_size(); + + if (size <= 0) + size = DEF_MAX_LOG_SIZE; + + max_logfile_size = size; +} + +/*----------------------------------------------------------------------------- + log_printf + ----------------------------------------------------------------------------*/ +int log_printf(FILE* log_fp, char* format_str, ...) +{ + int ret = 0; + char log_str[4096]; + char backup_ch; + int len; + va_list list; + + va_start(list, format_str); + vsnprintf(log_str, sizeof(log_str), format_str, list); + va_end(list); + + len = strlen(log_str); + next_offset = curr_offset + len; + + if (next_offset <= max_logfile_size) { + if (fprintf(log_fp, "%s", log_str) < 0) { + ret = -1; + goto exit; + } + curr_offset = next_offset; + if (curr_offset == max_logfile_size) { + rewind(log_fp); + curr_offset = 0; + } + } else { + backup_offset = max_logfile_size - curr_offset; + backup_ch = log_str[backup_offset]; + log_str[backup_offset] = 0x00; + if (fprintf(log_fp, "%s", log_str) < 0) { + ret = -1; + goto exit; + } + rewind(log_fp); + log_str[backup_offset] = backup_ch; + if (fprintf(log_fp, "%s", log_str+backup_offset) < 0) { + ret = -1; + goto exit; + } + curr_offset = next_offset - max_logfile_size; + } + +exit: + return ret; +} + +/*----------------------------------------------------------------------------- + truncate_log_file + ----------------------------------------------------------------------------*/ +void truncate_log_file(char *log_path, int size_kb) +{ + FILE *log_fp; + + if (max_logfile_size != DEF_MAX_LOG_SIZE) { + /* This means someone wants to see log file, so not truncate. */ + return; + } + + if (size_kb == 0) { + log_fp = fopen(log_path, "w"); + if (log_fp == NULL) + perror("file open error\n"); + else + fclose(log_fp); + } + + sync(); +} + + diff --git a/src/delta-ua/engine/fota_log.h b/src/delta-ua/engine/fota_log.h new file mode 100755 index 0000000..231af30 --- /dev/null +++ b/src/delta-ua/engine/fota_log.h @@ -0,0 +1,76 @@ +/* + * libtota + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __FOTA_LOG_H__ +#define __FOTA_LOG_H__ + +#include + +/* + * DEBUGGING FEATURE + */ + +extern unsigned int __log_level__; +extern FILE *__log_out_file__; +extern int log_printf(FILE* log_fp, char* format_str, ...); +extern void truncate_log_file(char *log_path, int size_kb); +extern void set_max_logfile_size(void); + +#define LOG_INFO (1<<8) +#define LOG_ENGINE (1<<7) +#define LOG_FUNCS (1<<6) +#define LOG_GUI (1<<5) +#define LOG_DEBUG (1<<4) +#define LOG_FILE (1<<3) +#define LOG_FLASH (1<<2) +#define LOG_SSENGINE LOG_ENGINE + +//#define DEBUG_STDOUT +#define DEBUG_FILE + +#ifdef DEBUG_STDOUT +#define LOGE(s, args...) printf("UA/ERROR(%s) " s, __func__, ##args) // Error log +#define LOGL(mask, s, args...) do { if ((mask) & __log_level__) printf("UA/(%s): " s, __func__, ##args); } while (0) +#define LOG(s, args...) LOGL(LOG_DEBUG, s, ##args) + +#elif defined(DEBUG_FILE) +#define LOGE(s, args...) (void)log_printf(__log_out_file__, "UA/ERROR(%s) " s, __func__, ##args) +#define LOGL(mask, s, args...) do { if ((mask) & __log_level__) (void)log_printf(__log_out_file__, "UA/(%s): " s , __func__, ##args); } while (0) +#define LOG(s, args...) LOGL(LOG_DEBUG, s, ##args) + +#elif defined(DEBUG_STDOUT_FILE) // debug printf +#define LOGE(s, args...) do {\ + printf("UA/ERROR(%s) " s, __func__, ##args);\ + (void)log_printf(__log_out_file__, "UA/ERROR(%s) " s, __func__, ##args);\ + } while (0) +#define LOGL(mask, s, args...) do { \ + if ((mask) & __log_level__) {\ + printf("UA/(%s): " s , __func__, ##args);\ + (void)log_printf(__log_out_file__, "UA/(%s): " s, __func__, ##args);\ + } \ + } while (0) +#define LOG(s, args...) LOGL(LOG_DEBUG, s, ##args) + +#else +#define LOGE(s, args...) +#define LOGL(mask, s, args...) +#define LOG(s, args...) + +#endif + +#endif /* __FOTA_LOG_H__ */ diff --git a/src/delta-ua/engine/fota_tar.c b/src/delta-ua/engine/fota_tar.c new file mode 100755 index 0000000..af32bb2 --- /dev/null +++ b/src/delta-ua/engine/fota_tar.c @@ -0,0 +1,1199 @@ +/* + * libtota + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "SS_Engine_Update.h" +#include "SS_Engine_Errors.h" +#include "SS_FSUpdate.h" +#include "fota_common.h" +#include "fota_tar.h" +#include "ua_types.h" + +/* tar Header Block, from POSIX 1003.1-1990. for reference */ +#if 0 + /* POSIX header. */ + +struct posix_header { /* byte offset */ + char name[100]; /* 0 */ + char mode[8]; /* 100 */ + char uid[8]; /* 108 */ + char gid[8]; /* 116 */ + char size[12]; /* 124 */ + char mtime[12]; /* 136 */ + char chksum[8]; /* 148 */ + char typeflag; /* 156 */ + char linkname[100]; /* 157 */ + char magic[6]; /* 257 */ + char version[2]; /* 263 */ + char uname[32]; /* 265 */ + char gname[32]; /* 297 */ + char devmajor[8]; /* 329 */ + char devminor[8]; /* 337 */ + char prefix[155]; /* 345 */ + /* 500 */ +}; +#endif + +#define MAX_ITEM_SIZE 0x7FFFFFFF +#define TAR_ITEM_SIZE_POSITION 124 +#define TAR_SIZE_OF_ITEM_SIZE 8 +#define TAR_SIZE_OF_HEADER 12 +#define TAR_BLOCK_SIZE 512 +#define TAR_ITEM_NAME_SIZE 100 +#define TAR_LONG_NAME_SIZE 256 +#define TAR_ITEM_TYPE_FLAG_POS 156 + +/*** The byte that indicates whether the prefix is present or not */ +#define PREFIX_INDICATOR_BYTE 345 +#define PREFIX_LEN 155 + +/** the rest heavily based on (ie mostly) untgz.c from zlib **/ + +/* Values used in typeflag field. */ + +#define REGTYPE '0' /* regular file */ +#define AREGTYPE '\0' /* regular file */ +#define LNKTYPE '1' /* link */ +#define SYMTYPE '2' /* reserved */ +#define CHRTYPE '3' /* character special */ +#define BLKTYPE '4' /* block special */ +#define DIRTYPE '5' /* directory */ +#define FIFOTYPE '6' /* FIFO special */ +#define CONTTYPE '7' /* reserved, for compatibility with gnu tar, + treat as regular file, where it represents + a regular file, but saved contiguously on disk */ + +/* GNU tar extensions */ + +#define GNUTYPE_DUMPDIR 'D' /* file names from dumped directory */ +#define GNUTYPE_LONGLINK 'K' /* long link name */ +#define GNUTYPE_LONGNAME 'L' /* long file name */ +#define GNUTYPE_MULTIVOL 'M' /* continuation of file from another volume */ +#define GNUTYPE_NAMES 'N' /* file name that does not fit into main hdr */ +#define GNUTYPE_SPARSE 'S' /* sparse file */ +#define GNUTYPE_VOLHDR 'V' /* tape/volume header */ + +extern void *SS_Malloc(SS_UINT32 size); + +int gTarFd = -1; // Currenlty this logic supports only one tar file + +/* Parse an octal number, ignoring leading and trailing nonsense. */ +static int parseoct(const char *p, size_t n) +{ + int i = 0; + + while (*p < '0' || *p > '7') { + ++p; + --n; + } + while (*p >= '0' && *p <= '7' && n > 0) { + i *= 8; + i += *p - '0'; + ++p; + --n; + } + return (i); +} + +/* Verify the tar checksum. */ +static int verify_checksum(const char *p) +{ + int n, u = 0; + for (n = 0; n < 512; ++n) { + if (n < 148 || n > 155) + /* Standard tar checksum adds unsigned bytes. */ + u += ((unsigned char *)p)[n]; + else + u += 0x20; + + } + return (u == parseoct(p + 148, 8)); +} + +static int is_end_of_archive(const char *p) +{ + int n; + for (n = 511; n >= 0; --n) + if (p[n] != '\0') + return (0); + return (1); +} + +void create_dir(char *pathname, int mode) +{ + char *p; + int r; + + /* Strip trailing '/' */ + if (pathname[strlen(pathname) - 1] == '/') + pathname[strlen(pathname) - 1] = '\0'; + + /* Try creating the directory. */ + r = mkdir(pathname, mode); + + if (r != 0) { + /* On failure, try creating parent directory. */ + p = strrchr(pathname, '/'); + if (p != NULL) { + *p = '\0'; + create_dir(pathname, 0755); + *p = '/'; + r = mkdir(pathname, mode); + } + } + if (r != 0) { + if (r != EEXIST && r != -1) + LOG("Could not create directory [%s] Error[%d]\n", pathname, r); + } +} + +/* Create a file, including parent directory as necessary. */ +static FILE *create_file(char *pathname) +{ + FILE *f; + f = fopen(pathname, "w+"); + if (f == NULL) { + /* Try creating parent dir and then creating file. */ + char *p = strrchr(pathname, '/'); + if (p != NULL) { + *p = '\0'; + create_dir(pathname, 0755); + *p = '/'; + f = fopen(pathname, "w+"); + } + } + return (f); +} + +/*----------------------------------------------------------------------------- + tar_get_item_offset + ----------------------------------------------------------------------------*/ +int tar_get_item_offset(char *tar, char *item) +{ + int ret = -1; + int fd = -1; + char header[TAR_BLOCK_SIZE] = { 0, }; + char uExtendedName[MAX_FILE_PATH + 1] = { 0, }; + char size_oct[TAR_SIZE_OF_HEADER] = { 0, }; + unsigned long size_dec = 0; + int blknum = 0; + off_t pos = 0; + off_t tar_len = 0; + ssize_t rdcnt = 0; + + if (!item || !tar){ + LOG("Invalid params\n"); + return -1; + }; + //check if gTarFd was opened by tar_open during SS_FSUpdateFile then use it + if (gTarFd >= 0) + fd = gTarFd; + else { + fd = open(tar, O_RDONLY); + if (fd < 0) { + LOGE("can't open file(%s).\n", tar); + return -1; + } + } + + tar_len = lseek(fd, 0, SEEK_END); + if (tar_len < 0) { + LOGL(LOG_SSENGINE, "can't read tar_len (%s).\n", tar); + goto Cleanup; + } + pos = lseek(fd, 0, SEEK_SET); + if (pos < 0) { + LOGL(LOG_SSENGINE, "can't read pos (%s).\n", tar); + goto Cleanup; + } + while (pos < tar_len) { + /* read file header */ + rdcnt = read(fd, header, sizeof(header)); + if (rdcnt <= 0) { + LOG("read failed. (rdcnt=%d)\n", rdcnt); + break; + } + + /* get file name and file size */ + if (header[TAR_ITEM_TYPE_FLAG_POS] == GNUTYPE_LONGNAME || header[TAR_ITEM_TYPE_FLAG_POS] == GNUTYPE_LONGLINK) { + //rdcnt = read(fd, header, sizeof(header)); + memset(uExtendedName, 0, sizeof(uExtendedName)); + rdcnt = read(fd, uExtendedName, sizeof(uExtendedName) - 1); + if (rdcnt <= 0) { + LOG("read failed. (rdcnt=%d)\n", rdcnt); + break; + } + rdcnt = read(fd, header, sizeof(header)); + if (rdcnt <= 0) { + LOG("read failed. (rdcnt=%d)\n", rdcnt); + break; + } + } else { + memset(uExtendedName, 0, sizeof(uExtendedName)); + memcpy(uExtendedName, header, TAR_ITEM_NAME_SIZE); + } + memcpy(size_oct, header + TAR_ITEM_SIZE_POSITION, sizeof(size_oct)); + size_dec = strtoul(size_oct, NULL, TAR_SIZE_OF_ITEM_SIZE); + if (size_dec > MAX_ITEM_SIZE) { + LOG("ITEM : [%s]\n", item); + LOG("size too big. (size_dec=0x%08X)\n", size_dec); + break; + } + + /* check if the file is what we are looking for */ + if (strncmp(uExtendedName, item, sizeof(uExtendedName) - 1) == 0) { + ret = (int)lseek(fd, 0, SEEK_CUR); + break; + } + + /* move file pointer to next file header */ + blknum = size_dec / TAR_BLOCK_SIZE; + if (size_dec % TAR_BLOCK_SIZE) + blknum++; + + pos = lseek(fd, (off_t) (blknum * TAR_BLOCK_SIZE), SEEK_CUR); + if (pos < 0) { + LOGE("can't read next block (%s).\n", tar); + close(fd); + return -1; + } + } + + Cleanup: + if (gTarFd < 0) + close(fd); + + return ret; +} + +/*----------------------------------------------------------------------------- + tar_get_item_size + ----------------------------------------------------------------------------*/ +int tar_get_item_size(char *tar, char *item) +{ + int ret = -1; + int fd = -1; + char header[TAR_BLOCK_SIZE] = { 0, }; + char uExtendedName[MAX_FILE_PATH + 1] = { 0, }; + char size_oct[TAR_SIZE_OF_HEADER] = { 0, }; + unsigned long size_dec = 0; + int blknum = 0; + off_t pos = 0; + off_t tar_len = 0; + ssize_t rdcnt = 0; + + if (!item || !tar){ + LOG("Invalid params\n"); + return -1; + } + LOGL(LOG_SSENGINE, "Tar file Looking for (%s)\n", item); + fd = open(tar, O_RDONLY); + if (fd < 0) { + LOG("can't open file(%s).\n", tar); + return -1; + } + + tar_len = lseek(fd, 0, SEEK_END); + if (tar_len < 0) { + LOGL(LOG_SSENGINE, "can't read tar_len (%s).\n", tar); + goto Cleanup; + } + pos = lseek(fd, 0, SEEK_SET); + if (pos < 0) { + LOGL(LOG_SSENGINE, "can't read pos (%s).\n", tar); + goto Cleanup; + } + + while (pos < tar_len) { + /* read file header */ + rdcnt = read(fd, header, sizeof(header)); + if (rdcnt <= 0) { + LOG("read failed. (rdcnt=%d)\n", rdcnt); + break; + } + + /* get file name and file size */ + if (header[TAR_ITEM_TYPE_FLAG_POS] == GNUTYPE_LONGNAME || header[TAR_ITEM_TYPE_FLAG_POS] == GNUTYPE_LONGLINK) { + //rdcnt = read(fd, header, sizeof(header)); + memset(uExtendedName, 0, sizeof(uExtendedName)); + rdcnt = read(fd, uExtendedName, sizeof(uExtendedName) - 1); + if (rdcnt <= 0) { + LOG("read failed. (rdcnt=%d)\n", rdcnt); + break; + } + rdcnt = read(fd, header, sizeof(header)); + if (rdcnt <= 0) { + LOG("read failed. (rdcnt=%d)\n", rdcnt); + break; + } + } else { + memset(uExtendedName, 0, sizeof(uExtendedName)); + memcpy(uExtendedName, header, TAR_ITEM_NAME_SIZE); + } + memcpy(size_oct, header + TAR_ITEM_SIZE_POSITION, sizeof(size_oct)); + size_dec = strtoul(size_oct, NULL, TAR_SIZE_OF_ITEM_SIZE); + if (size_dec > MAX_ITEM_SIZE) { + LOG("ITEM : [%s]\n", item); + LOG("size too big. (size_dec=0x%08X)\n", (unsigned int)size_dec); + break; + } + + /* check if the file is what we are looking for */ + if (strncmp(uExtendedName, item, sizeof(uExtendedName) - 1) == 0) { + ret = (int)size_dec; + if ((ret == 0) && (header[TAR_ITEM_TYPE_FLAG_POS] == DIRTYPE)) + ret = tar_get_folder_size(tar, item); + break; + } + /* move file pointer to next file header */ + //LOGL(LOG_SSENGINE,"Item in Tar (%s)\n", uExtendedName); + blknum = size_dec / TAR_BLOCK_SIZE; + if (size_dec % TAR_BLOCK_SIZE) + blknum++; + + pos = lseek(fd, (off_t) (blknum * TAR_BLOCK_SIZE), SEEK_CUR); + if (pos < 0) { + LOGL(LOG_SSENGINE, "can't read next block (%s).\n", tar); + close(fd); + return -1; + } + } + + Cleanup: + close(fd); + + return ret; +} + +/*----------------------------------------------------------------------------- + tar_get_item_tye. (Dir/file/link etc) + ----------------------------------------------------------------------------*/ + +char tar_get_item_type(char *tar, char *item) +{ + char ret = '0'; + int fd = -1; + char header[TAR_BLOCK_SIZE] = { 0, }; + char uExtendedName[MAX_FILE_PATH + 1] = { 0, }; + char size_oct[TAR_SIZE_OF_HEADER] = { 0, }; + unsigned long size_dec = 0; + int blknum = 0; + off_t pos = 0; + off_t tar_len = 0; + ssize_t rdcnt = 0; + + if (!item || !tar){ + LOG("Invalid params\n"); + return -1; + } + //LOG("Tar file Looking for (%s)\n", item); + fd = open(tar, O_RDONLY); + if (fd < 0) { + LOG("can't open file(%s).\n", tar); + return -1; + } + + tar_len = lseek(fd, 0, SEEK_END); + if (tar_len < 0) { + LOGL(LOG_SSENGINE, "can't read tar_len (%s).\n", tar); + goto Cleanup; + } + pos = lseek(fd, 0, SEEK_SET); + if (pos < 0) { + LOGL(LOG_SSENGINE, "can't read pos (%s).\n", tar); + goto Cleanup; + } + + while (pos < tar_len) { + /* read file header */ + rdcnt = read(fd, header, sizeof(header)); + if (rdcnt <= 0) { + LOG("read failed. (rdcnt=%d)\n", rdcnt); + ret = -1; + break; + } + + /* get file name and file size */ + if (header[TAR_ITEM_TYPE_FLAG_POS] == GNUTYPE_LONGNAME || header[TAR_ITEM_TYPE_FLAG_POS] == GNUTYPE_LONGLINK) { + //rdcnt = read(fd, header, sizeof(header)); + memset(uExtendedName, 0, sizeof(uExtendedName)); + rdcnt = read(fd, uExtendedName, sizeof(uExtendedName) - 1); + if (rdcnt <= 0) { + LOG("read failed. (rdcnt=%d)\n", rdcnt); + break; + } + rdcnt = read(fd, header, sizeof(header)); + if (rdcnt <= 0) { + LOG("read failed. (rdcnt=%d)\n", rdcnt); + break; + } + } else { + memset(uExtendedName, 0, sizeof(uExtendedName)); + memcpy(uExtendedName, header, TAR_ITEM_NAME_SIZE); + } + memcpy(size_oct, header + TAR_ITEM_SIZE_POSITION, sizeof(size_oct)); + size_dec = strtoul(size_oct, NULL, TAR_SIZE_OF_ITEM_SIZE); + if (size_dec > MAX_ITEM_SIZE) { + LOG("ITEM : [%s]\n", item); + LOG("size too big. (size_dec=0x%08X)\n", (unsigned int)size_dec); + ret = -1; + break; + } + + /* check if the file is what we are looking for */ + if (strncmp(uExtendedName, item, sizeof(uExtendedName) - 1) == 0) { + ret = header[TAR_ITEM_TYPE_FLAG_POS]; + break; + } + + /* move file pointer to next file header */ + blknum = size_dec / TAR_BLOCK_SIZE; + if (size_dec % TAR_BLOCK_SIZE) + blknum++; + + pos = lseek(fd, (off_t) (blknum * TAR_BLOCK_SIZE), SEEK_CUR); + if (pos < 0) { + LOGL(LOG_SSENGINE, "can't read next block (%s).\n", tar); + close(fd); + return -1; + } + } + + Cleanup: + close(fd); + + return ret; +} + +/*----------------------------------------------------------------------------- + tar_get_cfg_data + ----------------------------------------------------------------------------*/ +int tar_get_cfg_data(char *tar, char *item, char *buf, int buflen) +{ + int fd = -1; + int data_size = -1; + int data_offset = -1; + off_t pos = 0; + ssize_t rdcnt = 0; + + if (!buf){ + LOG("Invalid params\n"); + return -1; + } + data_size = tar_get_item_size(tar, item); + if (data_size <= 0) + return -1; + + if (data_size > buflen) + data_size = buflen; + + data_offset = tar_get_item_offset(tar, item); + if (data_offset < 0) + return -1; + + fd = open(tar, O_RDONLY); + if (fd < 0) { + LOG("can't open file(%s).\n", tar); + return -1; + } + + pos = lseek(fd, data_offset, SEEK_SET); + if (pos < 0) { + LOG("lseek fail (%s offset %d).\n", tar, data_offset); + close(fd); + return -1; + } + + rdcnt = read(fd, buf, data_size); + if (rdcnt != (ssize_t) data_size) { + LOG("read fail(%s from %s).\n", item, tar); + close(fd); + return -1; + } + + close(fd); + + return rdcnt; +} + +tar_Data_t *tar_build_cfg_table(char *tar) +{ + + int fd = -1; + int ret = 0; + char header[TAR_BLOCK_SIZE] = { 0, }; + char uExtendedName[MAX_FILE_PATH + 1] = { 0, }; + char size_oct[TAR_SIZE_OF_HEADER] = { 0, }; + unsigned long size_dec = 0; + int blknum = 0; + off_t pos = 0; + off_t tar_len = 0; + ssize_t rdcnt = 0; + + int itemSize; + int itemOffset; + tar_Data_t *headparam = NULL, *tailparam = NULL, *newnode = NULL; + tar_Data_t *local_temp = NULL; + tar_Data_t *local_next = NULL; + if (!tar) { + LOGE("Bad param tar\n"); + return NULL; + } + //check if gTarFd was opened by tar_open during SS_FSUpdateFile then use it + if (gTarFd >= 0) + fd = gTarFd; + else { + fd = open(tar, O_RDONLY); + if (fd < 0) { + LOG("can't open file(%s).\n", tar); + return NULL; + } + } + + tar_len = lseek(fd, 0, SEEK_END); + if (tar_len < 0) { + LOGL(LOG_SSENGINE, "can't read tar_len (%s).\n", tar); + goto Cleanup; + } + pos = lseek(fd, 0, SEEK_SET); + if (pos < 0) { + LOGL(LOG_SSENGINE, "can't read pos (%s).\n", tar); + goto Cleanup; + } + while (pos < tar_len) { + /* read file header */ + rdcnt = read(fd, header, sizeof(header)); + if (rdcnt <= 0) { + LOG("read failed. (rdcnt=%d)\n", rdcnt); + ret = -1; + break; + } + /* get file name and file size */ + if (header[TAR_ITEM_TYPE_FLAG_POS] == GNUTYPE_LONGNAME || header[TAR_ITEM_TYPE_FLAG_POS] == GNUTYPE_LONGLINK) { + //rdcnt = read(fd, header, sizeof(header)); + memset(uExtendedName, 0, sizeof(uExtendedName)); + rdcnt = read(fd, uExtendedName, sizeof(uExtendedName) - 1); + if (rdcnt <= 0) { + LOG("read failed. (rdcnt=%d)\n", rdcnt); + ret = -1; + break; + } + rdcnt = read(fd, header, sizeof(header)); + if (rdcnt <= 0) { + LOG("read failed. (rdcnt=%d)\n", rdcnt); + ret = -1; + break; + } + } else { + memset(uExtendedName, 0, sizeof(uExtendedName)); + memcpy(uExtendedName, header, TAR_ITEM_NAME_SIZE); + } + memcpy(size_oct, header + TAR_ITEM_SIZE_POSITION, sizeof(size_oct)); + size_dec = strtoul(size_oct, NULL, TAR_SIZE_OF_ITEM_SIZE); + if (size_dec > MAX_ITEM_SIZE) { + LOG("uExtendedName is : [%s]\n", uExtendedName); + LOG("size too big. (size_dec=0x%08X)\n", (unsigned int)size_dec); + ret = -1; + break; + } + //fix WGID : 51254 , size_dec comparison is not required + if ((strstr(uExtendedName, "/diff") != NULL)) { //add only delta files from rootfs and csc, hardcoding shd b removed.. + + /* check if the file is what we are looking for */ + //strncpy(itemName, name,100); + itemSize = (int)size_dec; + itemOffset = (int)lseek(fd, 0, SEEK_CUR); + newnode = (tar_Data_t *) SS_Malloc(sizeof(tar_Data_t)); + if (!newnode) { + ret = -1; + break; + } + memset(newnode->itemName, 0, sizeof(newnode->itemName)); + strncpy((char *)newnode->itemName, uExtendedName, sizeof(newnode->itemName) - 1); + newnode->itemOffset = itemOffset; + newnode->itemSize = itemSize; + newnode->nextnode = NULL; + if (headparam == NULL) { + headparam = newnode; + tailparam = newnode; + } else { + (tailparam)->nextnode = newnode; + (tailparam) = (tailparam)->nextnode; + } + } + + /* move file pointer to next file header */ + blknum = size_dec / TAR_BLOCK_SIZE; + if (size_dec % TAR_BLOCK_SIZE) + blknum++; + + pos = lseek(fd, (off_t) (blknum * TAR_BLOCK_SIZE), SEEK_CUR); + if (pos < 0) { + LOGL(LOG_SSENGINE, "can't read next block (%s).\n", tar); + ret = -1; + break; + } + } + Cleanup: + //if gTarFd was opened by tar_open during SS_FSUpdateFile we do not close it + if (gTarFd < 0) + close(fd); + if (ret != -1) + return headparam; + else { + if (headparam != newnode && newnode) + SS_Free(newnode); + if (headparam) { + local_temp = headparam; + while (local_temp) { + local_next = local_temp->nextnode; + SS_Free(local_temp); + local_temp = local_next; + } + } + return NULL; + } +} + +void tar_free_cfg_table(tar_Data_t ** delta_tar) +{ + tar_Data_t *local_temp = NULL; + tar_Data_t *local_next = NULL; + LOGL(LOG_SSENGINE, "Free TAR CFG TABLE\n"); + if (*delta_tar) { + local_temp = *delta_tar; + while (local_temp) { + local_next = local_temp->nextnode; + //LOGL(LOG_SSENGINE,"freeing [%s]\n",local_temp->itemName); + SS_Free(local_temp); + local_temp = local_next; + } + } +} + +void deleteNode(tar_Data_t * head, tar_Data_t * n) +{ + tar_Data_t *prev = head; + if (head == n) { + if (head->nextnode == NULL) { + LOG("There is only one node. The list can't be made empty\n"); + return; + } + strncpy((char *)head->itemName, (const char *)head->nextnode->itemName, TAR_ITEM_NAME_SIZE); //head->itemName = head->nextnode->itemName; + head->itemSize = head->nextnode->itemSize; + head->itemOffset = head->nextnode->itemOffset; + n = head->nextnode; + head->nextnode = head->nextnode->nextnode; + SS_Free(n); + return; + } + while (prev->nextnode != NULL && prev->nextnode != n) + prev = prev->nextnode; + if (prev->nextnode == NULL) { + LOG("Given node is not present in Linked List\n"); + return; + } + prev->nextnode = prev->nextnode->nextnode; + SS_Free(n); + return; +} + +int tar_get_item_size_from_struct(tar_Data_t ** delta_tar, const char *patchname, int *data_size, int *data_offset) +{ + tar_Data_t *head = *delta_tar; + tar_Data_t *base = *delta_tar; + if (head == NULL) + return 1; + else { + //LOG("fast_tar_get_item_size- looking for [%s] [%s]\n",patchname,head->itemName); + while (1) { + if (strstr((const char *)head->itemName, patchname) != 0) { + //LOG("fast_tar_get_item_size found [%s] in [%s]\n",patchname, head->itemName); + *data_size = head->itemSize; + *data_offset = head->itemOffset; + deleteNode(base, head); + return 0; + + } else if (head->nextnode != NULL) { + head = head->nextnode; + //LOG("fast_tar_get_item_size current node [%s] \n",head->itemName); + } else { + LOGE("fast_tar_get_item_size FAILED TO GET [%s] in [%s]\n", patchname, (char *)head->itemName); + break; + } + } + return 1; + } +} + +tar_Data_t *tar_cfg_clear_nodes(tar_Data_t * head) +{ + tar_Data_t *local_temp = NULL; + while (head) { + LOGL(LOG_SSENGINE, "tar_cfg_delete_node [%s]\n", (char *)head->itemName); + local_temp = head->nextnode; + SS_Free(head); + head = local_temp; + } + return 0; +} + +int tar_open(char *tar) +{ + if (gTarFd >= 0) + close(gTarFd); + gTarFd = open(tar, O_RDONLY); + if (gTarFd < 0) { + LOG("can't open TAR file(%s).\n", tar); + return -1; + } + return 0; +} + +int tar_close() +{ + if (gTarFd >= 0) + close(gTarFd); + gTarFd = -1; + return 0; +} + +int tar_get_folder_size(char *tar, char *item) +{ + int ret = -1; + int fd = -1; + char header[TAR_BLOCK_SIZE] = { 0, }; + char name[TAR_LONG_NAME_SIZE + 1] = { 0, }; + char *lastfolder = NULL; + int folderpathlen = 0; + char size_oct[TAR_SIZE_OF_HEADER] = { 0, }; + unsigned long size_dec = 0; + int blknum = 0; + off_t pos = 0; + off_t tar_len = 0; + ssize_t rdcnt = 0; + + if (!item || !tar){ + LOG("Invalid params\n"); + return -1; + } + LOG("Tar folder Looking for (%s)\n", item); + fd = open(tar, O_RDONLY); + if (fd < 0) { + LOG("can't open file(%s).\n", tar); + return -1; + } + + tar_len = lseek(fd, 0, SEEK_END); + if (tar_len < 0) { + LOGL(LOG_SSENGINE, "can't read tar_len (%s).\n", tar); + goto Cleanup; + } + pos = lseek(fd, 0, SEEK_SET); + if (pos < 0) { + LOGL(LOG_SSENGINE, "can't read pos (%s).\n", tar); + goto Cleanup; + } + + while (pos < tar_len) { + /* read file header */ + rdcnt = read(fd, header, sizeof(header)); + if (rdcnt <= 0) { + LOG("read failed. (rdcnt=%d)\n", rdcnt); + ret = -1; + break; + } + + /* get file name and file size */ + memcpy(name, header, sizeof(name) - 1); + memcpy(size_oct, header + TAR_ITEM_SIZE_POSITION, sizeof(size_oct)); + errno = 0; + size_dec = strtoul(size_oct, NULL, TAR_SIZE_OF_ITEM_SIZE); + if (errno != 0) { + LOG("strtoul failed. (errno=%d)\n", errno); + ret = -1; + break; + } else if (size_dec > MAX_ITEM_SIZE) { + LOG("size too big. (size_dec=0x%08X)\n", (unsigned int)size_dec); + ret = -1; + break; + } + + /* check if the file is what we are looking for */ + //Get until folder name + + lastfolder = strrchr(name, '/'); + if (lastfolder) + folderpathlen = strlen(name) - strlen(lastfolder); + + if (strncmp(name, item, folderpathlen) == 0) { + ret += (int)size_dec; + //LOG("Tar Files under folder [%s]\n", name); + //break; + } + + /* move file pointer to next file header */ + blknum = size_dec / TAR_BLOCK_SIZE; + if (size_dec % TAR_BLOCK_SIZE) + blknum++; + + pos = lseek(fd, (off_t) (blknum * TAR_BLOCK_SIZE), SEEK_CUR); + if (pos < 0) { + LOGL(LOG_SSENGINE, "can't read next block (%s).\n", tar); + close(fd); + return -1; + } + } + + Cleanup: + close(fd); + LOG("ret=%d\n", ret); + + return ret; //Should return +1?? or Ignore?? +} + +/*Extract Specific Folder from tar, Taken from Untar.c */ +int tar_extract_folder(char *tar, char *item, char *path) +{ + char buff[MAX_FILE_PATH]; + FILE *f = NULL; + size_t bytes_read; + int filesize; + int data_offset = -1; + int fd = -1; + char name[512] = { 0, }; + int folderpathlen = 0; + char dirPath[512] = { 0 }; + int getheader = 1; // Asuming initial header is TAR header + char fullname[512] = { 0 }; + int ret; + + if (!item || !tar || !path){ + LOG("Invalid params\n"); + return -1; + } + LOG("Extracting Folder from %s %s to %s\n", tar, item, path); + + data_offset = tar_get_item_offset(tar, item); + if (data_offset < 0) { + LOGE("data offset for [%s] is [%d]\n", item, data_offset); + return -1; + } + + fd = open(tar, O_RDONLY); + if (fd < 0) { + LOGE("can't open file(%s).\n", tar); + return -1; + } + + folderpathlen = strlen(item); + + for (;;) { + bytes_read = read(fd, buff, sizeof(buff)); + if (bytes_read < 512) { + LOGE("Short read on %s: expected 512, got %d\n", tar, bytes_read); + close(fd); + return -1; + } + if (is_end_of_archive(buff)) { + close(fd); + LOG("End of %s\n", tar); //Can stop at end of folder. + return S_SS_SUCCESS; + } + if (!verify_checksum(buff)) { + close(fd); + LOGE("Checksum failure\n"); + return -1; + } + filesize = parseoct(buff + 124, 12); + if (getheader == 2) { + getheader = 1; + //LOG(" Working on LONG FILE NAME CASE [%s]\n", fullname); + } else { + memset(fullname, 0, sizeof(fullname)); + strncpy(fullname, buff, 100); + //LOG(" Working on Normal FILE NAME CASE [%s]\n", fullname); + } + + switch (buff[156]) { + case '1': + LOG(" Ignoring hardlink %s\n", fullname); + break; + case '2': + + //LOG(" Creating symlink %s\n", buff); + if (strncmp(fullname, item, folderpathlen) == 0) { + //LOG("Printing Buffer \n"); + //for(i=157; buff[i] !='\0' ;i++) + //{ + //LOG("%c", buff[i]) ; + //} + //LOG("\nEnd buffer\n"); + memset(name, 0, sizeof(name)); + strncpy(name, buff + 157, 100); //157, target link name will be present + memset(dirPath, 0, sizeof(dirPath)); + snprintf(dirPath, sizeof(dirPath), "%s/%s", path, fullname + folderpathlen); + LOG(" Creating Symlink [%s][%s]\n", name, dirPath); + ret = symlink(name, dirPath); // use ss_link + if (ret < 0) + LOG("Error with symlink: %d\n", errno); + } + break; + case '3': + LOG(" Ignoring character device %s\n", fullname); + break; + case '4': + LOG(" Ignoring block device %s\n", fullname); + break; + case '5': + //break;//delete + //LOG(" Dir [%s] Item [%s] Length [%d]\n", fullname, item, folderpathlen); + if (strncmp(fullname, item, folderpathlen) == 0) { + //LOG(" Extracting dir %s\n", fullname); + memset(dirPath, 0, sizeof(dirPath)); + snprintf(dirPath, sizeof(dirPath), "%s/%s", path, fullname + folderpathlen); + create_dir(dirPath, parseoct(fullname + 100, 8)); + } + + filesize = 0; + break; + case '6': + LOG(" Ignoring FIFO %s\n", fullname); + break; + case GNUTYPE_LONGLINK: + case GNUTYPE_LONGNAME: + { + getheader = 2; + memset(fullname, 0, sizeof(fullname)); + bytes_read = read(fd, fullname, sizeof(fullname)); + if (bytes_read < 512) { + LOGE("Short read on %s: expected 512, got %d\n", tar, bytes_read); + close(fd); + return -1; + } + filesize = 0; + //LOG("Entered LONG FILE NAME CASE new NAME is [%s]\n", fullname); + break; + } + + default: + //break; + //LOG(" File [%s] Item [%s] Length [%d]\n", fullname, item, folderpathlen); + if (strncmp(fullname, item, folderpathlen) == 0) { + if (buff[PREFIX_INDICATOR_BYTE] != 0) { + memset(name, 0, sizeof(name)); + memset(dirPath, 0, sizeof(dirPath)); + strncpy(name, buff, 100); + snprintf(name + strlen(name), sizeof(name) - strlen(name), + "%s", buff + PREFIX_INDICATOR_BYTE); + snprintf(dirPath, sizeof(dirPath), "%s/%s", path, name + folderpathlen); + LOG(" File Name is longer than 100 bytes -Remaining Str [%s]\n Full Str[%s]\n", dirPath, fullname); + } else { + //LOG(" Extracting file %s\n", fullname); + memset(dirPath, 0, sizeof(dirPath)); + snprintf(dirPath, sizeof(dirPath), "%s/%s", path, fullname + folderpathlen); + f = create_file(dirPath); + } + } + + break; + } + + while (filesize > 0) { + bytes_read = read(fd, buff, sizeof(buff)); + if (bytes_read < 512) { + LOGE("Short read on %s: Expected 512, got %d\n", tar, bytes_read); + close(fd); + if (f) { + fclose(f);//wgid: 16892 + f = NULL; + } + return -1; + } + if (filesize < 512) + bytes_read = filesize; + if (f != NULL) { + if (fwrite(buff, 1, bytes_read, f) + != bytes_read) { + LOG("Failed write\n"); + fclose(f); + f = NULL; + close(fd);//wgid: 59268 + return -1;//wgid: 16892 + } + } + filesize -= bytes_read; + } + if (f != NULL) { + fclose(f); + f = NULL; + } + + } + close(fd); + return S_SS_SUCCESS; +} + +int fast_tar_extract_file(char *tar, char *item, char *pathname, int size, int offset) +{ + int fd = -1; + int data_size = size; + int data_offset = offset; + off_t pos = 0; + ssize_t rdcnt = 0; + ssize_t writeCount = 0; + char *buf = NULL; + char err_buf[256]; + int fd2; + + if (!item || !tar || !pathname){ + LOG("Invalid params\n"); + return -1; + } + if (gTarFd >= 0) + fd = gTarFd; + else { + fd = open(tar, O_RDONLY); + if (fd < 0) { + LOG("can't open file(%s).\n", tar); + return -1; + } + } + + pos = lseek(fd, data_offset, SEEK_SET); + if (pos < 0) { + LOG("lseek fail (%s offset %d).\n", tar, data_offset); + close(fd); + return -1; + } + buf = SS_Malloc(data_size + 1); + if (buf == NULL) { + close(fd); + LOGE("Failed to Allocate Memory\n"); + return -1; + } + rdcnt = read(fd, buf, data_size); + if (rdcnt != (ssize_t) data_size) { + LOG(" rdcnt read fail(%s from %s).\n", item, tar); + SS_Free(buf); + close(fd); + return -1; + } + fd2 = open(pathname, O_CREAT | O_WRONLY, S_IRWXU); // Directory where file is required should be created already. + if (fd2 < 0) { + LOG("can't open file(%s).\n", pathname); + SS_Free(buf); + close(fd); + return -1; + } + writeCount = write(fd2, buf, rdcnt); + if (writeCount != rdcnt) { + LOG("writeCount write fail(%s from %s).\n", item, tar); + strerror_r(errno, err_buf, sizeof(err_buf)); + LOG("Oh dear, something went wrong with read()! %s\n", err_buf); + close(fd); + close(fd2); + SS_Free(buf); + return -1; + } + SS_Free(buf); + if (gTarFd < 0) + close(fd); + fsync(fd2); + close(fd2); + return rdcnt; // or jus return success? +} + +int tar_extract_file(char *tar, char *item, char *pathname) +{ + int fd = -1; + int data_size = -1; + int data_offset = -1; + off_t pos = 0; + ssize_t rdcnt = 0; + ssize_t writeCount = 0; + char *buf = NULL; + char err_buf[256]; + int fd2; + + if (!item || !tar || !pathname){ + LOG("Invalid params\n"); + return -1; + } + data_size = tar_get_item_size(tar, item); + data_offset = tar_get_item_offset(tar, item); + + if (data_size <= 0 || data_offset < 0) { + LOGE("Error Not a file , size is [%d], offset [%d] for item [%s]\n", data_size, data_offset, item); + return -1; + } else + LOGL(LOG_SSENGINE, "extracting file [%s] size [%d]\n", item, data_size); + fd = open(tar, O_RDONLY); + if (fd < 0) { + LOG("can't open file(%s).\n", tar); + return -1; + } + pos = lseek(fd, data_offset, SEEK_SET); + if (pos < 0) { + LOG("lseek fail (%s offset %d).\n", tar, data_offset); + close(fd); + return -1; + } + buf = SS_Malloc(data_size + 1); + if (buf == NULL) { + close(fd); + LOGE("Failed to Allocate Memory\n"); + return -1; + } + rdcnt = read(fd, buf, data_size); + if (rdcnt != (ssize_t) data_size) { + LOG(" rdcnt read fail(%s from %s).\n", item, tar); + SS_Free(buf); + close(fd); + return -1; + } + fd2 = open(pathname, O_CREAT | O_WRONLY, S_IRWXU); // Directory where file is required should be created already. + if (fd2 < 0) { + LOG("can't open file(%s).\n", pathname); + SS_Free(buf); + close(fd); + return -1; + } + writeCount = write(fd2, buf, rdcnt); + if (writeCount != rdcnt) { + LOG("writeCount write fail(%s from %s).\n", item, tar); + strerror_r(errno, err_buf, sizeof(err_buf)); + LOG("Oh dear, something went wrong with read()! %s\n", err_buf); + close(fd); + close(fd2); + SS_Free(buf); + return -1; + } + SS_Free(buf); + close(fd); + fsync(fd2); + close(fd2); + return rdcnt; // or jus return success? +} diff --git a/src/delta-ua/engine/fota_tar.h b/src/delta-ua/engine/fota_tar.h new file mode 100755 index 0000000..6d141ef --- /dev/null +++ b/src/delta-ua/engine/fota_tar.h @@ -0,0 +1,30 @@ +/* + * libtota + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _FOTA_TAR_H_ +#define _FOTA_TAR_H_ + +int tar_get_item_offset(char *tar, char *item); + +int tar_get_item_size(char *tar, char *item); + +int tar_get_cfg_data(char *tar, char *item, char *buf, int buflen); + +int tar_get_folder_size(char *tar, char *item); + +#endif /* _FOTA_TAR_H_ */ diff --git a/src/delta-ua/engine/ss_bspatch_common.c b/src/delta-ua/engine/ss_bspatch_common.c new file mode 100755 index 0000000..e7bd45e --- /dev/null +++ b/src/delta-ua/engine/ss_bspatch_common.c @@ -0,0 +1,291 @@ +/*- + * Copyright 2003-2005 Colin Percival + * Copyright 2012 Matthew Endsley + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted providing that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Modifications are made in reimplementing suffix sort array generation + * and how the data is read and written to.Iterative part replaced the + * recursive implementation to avoid buffer overflow problems + */ +//#define ZLIB_MOD //not stable yet. +//#define MAX_MATCH_SIZE // define ( MAX_MATCH_SIZE or CONST_MEMORY_USAGE ) or ( none of them ) +#define CONST_MEMORY_USAGE (64*1024) //tests show smallest time when using 64 kb +#define PATCH_FILE_FORMAT_MOD +#define BSDIFF_HEADER "BSDIFF40" +#define SSDIFF_HEADER "SSDIFF40" +//#define MULTI_THREADING +#include +#include +#include + +#include +#include +#include + +#include +#include <7zFile.h> +#include <7zVersion.h> +#include +#include + +static void *SzAlloc(void *p, size_t size) +{ + p = p; + return MyAlloc(size); +} + +static void SzFree(void *p, void *address) +{ + p = p; + MyFree(address); +} +ISzAlloc g_Alloc = { SzAlloc, SzFree }; + +static off_t offtin(u_char *buf) +{ + off_t y; + + y = buf[7] & 0x7F; + y = y * 256; + y += buf[6]; + y = y * 256; + y += buf[5]; + y = y * 256; + y += buf[4]; + y = y * 256; + y += buf[3]; + y = y * 256; + y += buf[2]; + y = y * 256; + y += buf[1]; + y = y * 256; + y += buf[0]; + + if (buf[7] & 0x80) + y = -y; + + return y; +} + +#define IN_BUF_SIZE (1 << 16) +#define OUT_BUF_SIZE (1 << 16) + +SRes Decode2(CLzmaDec *state, ISeqOutStream *outStream, ISeqInStream *inStream, + UInt64 *unpackSize, unsigned char *dec_data) +{ + int thereIsSize = (*unpackSize != (UInt64)(Int64) - 1); + UInt64 offset = 0; + Byte inBuf[IN_BUF_SIZE]; + Byte outBuf[OUT_BUF_SIZE]; + size_t inPos = 0, inSize = 0, outPos = 0; + + LzmaDec_Init(state); + + offset = 0; + + for (;;) { + if (inPos == inSize) { + inSize = IN_BUF_SIZE; + RINOK(inStream->Read(inStream, inBuf, &inSize)); + inPos = 0; + } + + SRes res; + SizeT inProcessed = inSize - inPos; + SizeT outProcessed = OUT_BUF_SIZE - outPos; + ELzmaFinishMode finishMode = LZMA_FINISH_ANY; + ELzmaStatus status; + + if (thereIsSize && outProcessed > *unpackSize) { + outProcessed = (SizeT) * unpackSize; + finishMode = LZMA_FINISH_END; + } + + res = LzmaDec_DecodeToBuf(state, outBuf + outPos, &outProcessed, + inBuf + inPos, &inProcessed, finishMode, &status); + inPos += inProcessed; + outPos += outProcessed; + *unpackSize -= outProcessed; + memcpy(dec_data + offset, outBuf, outProcessed); + offset += outProcessed; + + outPos = 0; + + if ((res != SZ_OK) || (thereIsSize && *unpackSize == 0)) + return res; + + if (inProcessed == 0 && outProcessed == 0) { + if (thereIsSize || status != LZMA_STATUS_FINISHED_WITH_MARK) + return SZ_ERROR_DATA; + return res; + } + } +} + +int apply_patch(const char *oldfile, unsigned char *patch_buffer, unsigned char **dest_buf, ssize_t *dest_size) +{ + int fd = -1, result = 0; + off_t oldsize, newsize; + u_char header[16], buf[8]; + u_char *old = NULL; + off_t oldpos, newpos; + off_t ctrl[4]; /////////////////////////////////////THREAD + off_t total_write; /////////////////////////////////////////THREAD + off_t j; + off_t memory_usage = CONST_MEMORY_USAGE; + off_t match_size; + off_t patch_buffer_offset = 0; + bool flag; + + /* + File format: + 0 8 "BSDIFF40" + 8 8 X + 16 8 Y + 24 8 sizeof(newfile) + 32 X bzip2(control block) + 32+X Y bzip2(diff block) + 32+X+Y ??? bzip2(extra block) + with control block a set of triples (x,y,z) meaning "add x bytes + from oldfile to x bytes from the diff block; copy y bytes from the + extra block; seek forwards in oldfile by z bytes". + */ + // Read header + if (patch_buffer) + memcpy(header, patch_buffer, 16); + else { + printf("%s().%d Corrupt decoded patch buffer\n", __FUNCTION__, __LINE__); + return 1; + } + + /* Check for appropriate magic */ + if (memcmp(header, BSDIFF_HEADER, 8) != 0 && memcmp(header, SSDIFF_HEADER, 8) != 0) { + printf("%s().%d Patch buffer header corrupt\n", __FUNCTION__, __LINE__); + return 1; + } + + /* Read lengths from header */ + newsize = offtin(header + 8); + + if ((newsize < 0)) { + printf("%s().%d Patch buffer corrupt\n", __FUNCTION__, __LINE__); + return 1; + } + + /* Cset patch_buffer_offset at the right place */ + patch_buffer_offset += 16; + + if (((fd = open(oldfile, O_RDONLY, 0)) < 0) || + ((oldsize = lseek(fd, 0, SEEK_END)) == -1) || + ((old = malloc(memory_usage + 1)) == NULL) || + (lseek(fd, 0, SEEK_SET) != 0)) { + printf("Corruption in old file %s\n", oldfile); + result = 1; + goto Cleanup; + } + + if ((*dest_buf = malloc(newsize + 1)) == NULL) { + printf("Corruption in old file %s\n", oldfile); + result = 1; + goto Cleanup; + } + oldpos = 0; + newpos = 0; + + total_write = 0; + + while (total_write != newsize) { + /* Read control data */ + for (j = 0; j <= 3; j++) { + memcpy(buf, patch_buffer + patch_buffer_offset, 8); + patch_buffer_offset += 8; + ctrl[j] = offtin(buf); + }; + + total_write += (ctrl[0] + ctrl[1]); + newpos = ctrl[3]; + oldpos = ctrl[2]; + + ////////////////////////////////////////////////////////////////////////////////// + flag = true; + match_size = ctrl[0]; + while (flag == true) { + if (match_size <= memory_usage) { + if (pread(fd, old, match_size, oldpos) != match_size) { + printf("Corruption in old file %s\n", oldfile); + result = 1; + goto Cleanup; + } + if (newpos + match_size > newsize) { + printf("%s().%d Corrupt patch\n", __FUNCTION__, __LINE__); + result = 1; + goto Cleanup; + } + memcpy((*dest_buf) + newpos, patch_buffer + patch_buffer_offset, match_size); + patch_buffer_offset += match_size; + for (j = 0; j < match_size; j++) + (*dest_buf)[newpos + j] += old[j]; + newpos += match_size; + flag = false; + } else { + if (pread(fd, old, memory_usage, oldpos) != memory_usage) { + printf("%s().%d Corruption in old file %s\n", __FUNCTION__, __LINE__ , oldfile); + result = 1; + goto Cleanup; + } + if (newpos + memory_usage > newsize) { + printf("%s().%d Corrupt patch\n", __FUNCTION__, __LINE__); + result = 1; + goto Cleanup; + } + memcpy((*dest_buf) + newpos, patch_buffer + patch_buffer_offset, memory_usage); + patch_buffer_offset += memory_usage; + for (j = 0; j < memory_usage; j++) + (*dest_buf)[newpos + j] += old[j]; + match_size -= memory_usage; + oldpos += memory_usage; + newpos += memory_usage; + } + } + + //////////////////////////////////////////////////////////////////////////////////////// + /* Sanity-check */ + if (newpos + ctrl[1] > newsize) { + printf("%s().%d Corrupt patch\n", __FUNCTION__, __LINE__); + result = 1; + goto Cleanup; + } + /* Read extra string */ + memcpy((*dest_buf) + newpos, patch_buffer + patch_buffer_offset, ctrl[1]); + patch_buffer_offset += ctrl[1]; + }; + *dest_size = newsize; +Cleanup: + //close old file + if (fd >= 0) + close(fd); + if (old) + free(old); + return result; +} diff --git a/src/delta-ua/engine/ss_bspatch_common.h b/src/delta-ua/engine/ss_bspatch_common.h new file mode 100644 index 0000000..3075ea2 --- /dev/null +++ b/src/delta-ua/engine/ss_bspatch_common.h @@ -0,0 +1,17 @@ +#ifndef _SS_BSPATCH_COMMON_H +#define _SS_BSPATCH_COMMON_H 1 + +#include +#include <7zFile.h> +#include <7zVersion.h> +#include +#include + +extern ISzAlloc g_Alloc; + +SRes Decode2(CLzmaDec *state, ISeqOutStream *outStream, ISeqInStream *inStream, + UInt64 *unpackSize, unsigned char *dec_data); + +int apply_patch(const char *oldfile, unsigned char *patch_buffer, unsigned char **dest_buf, ssize_t *dest_size); + +#endif /* _SS_BSPATCH_COMMON_H */ diff --git a/src/delta-ua/engine/ua_types.h b/src/delta-ua/engine/ua_types.h new file mode 100755 index 0000000..cb53ca7 --- /dev/null +++ b/src/delta-ua/engine/ua_types.h @@ -0,0 +1,115 @@ +/* + * libtota + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __UA_TYPES_H__ +#define __UA_TYPES_H__ + +#include + +#define MAX_FILE_PATH 512 + +/* + * FOTA Adaptaion header + */ + +#define UA_PARTI_MAX 20 //currently supporting max 20 partitions + +#define UI_OP_SCOUT_UPDATE 0 +#define UI_OP_SCOUT 1 +#define UI_OP_UPDATE 3 + +typedef enum { + FULL_IMAGE, + DELTA_IMAGE, + DELTA_FS, + EXTRA +} UA_DATA_FORMAT; + +typedef enum { + BEFORE_BOOT_FOTA, + AT_BOOT_FOTA +} UPDATE_WHEN; + +typedef enum { + UA_MODE_SCOUT_UPDATE, + UA_MODE_SCOUT, + UA_MODE_VERIFYTARGET, + UA_MODE_UPDATE, + UA_MODE_SUPPLYIMFOM = 200 +} UA_OPERATION_MODE; + +typedef struct _ua_update_data_t { + unsigned int exist_check; + unsigned int verify_check; + unsigned int update_check; + unsigned int weight; // the sum of weight should be 100 + unsigned int weight_offset; // start offset + unsigned int data_size; // byte + char *ua_delta_path; // it will be allocated to copy delta file path, need to free memory + char *ua_temp_path; // it will be allocated to copy delta file path, need to free memory +} ua_update_data_t; + +typedef struct _ua_update_cfg_t { + unsigned int update_type; + unsigned int update_when; + int skip_verify; + int skip_update; + int soure_img_size; //TOTA + int target_img_size; + char *soure_sha1; + char *target_sha1; +} ua_update_cfg_t; + +typedef struct _ua_part_info_t { + char *ua_parti_name; + char *ua_subject_name; + char *ua_blk_name; + char *ua_blk_name_previous; + int ua_blk_offset; +} ua_part_info_t; + +// User data structure +typedef struct _ua_data_t { // partition operations + ua_part_info_t *parti_info; + ua_update_cfg_t *update_cfg; + ua_update_data_t *update_data; + unsigned long ua_operation; + + int (*ua_op_read_block)(void *, unsigned char *, unsigned long, unsigned long); + int (*ua_op_write_block)(void *, unsigned char *, unsigned long); + void (*ui_progress)(void *, unsigned long); +} ua_data_t; + +typedef struct _ua_delta_info_t { + char ua_patch_path[MAX_FILE_PATH]; + char ua_patch_info[MAX_FILE_PATH]; + char ua_delta_path[MAX_FILE_PATH]; + char ua_attrib_path[MAX_FILE_PATH]; +} ua_delta_info_t; + +typedef struct _ua_dataSS_t { // partition operations + ua_part_info_t *parti_info; + ua_update_cfg_t *update_cfg; + ua_update_data_t *update_data; + ua_delta_info_t *update_delta; + unsigned long ua_operation; + void (*ui_progress)(void *, unsigned long); + int (*write_data_to_blkdev)(char *, int, int, char *); +} ua_dataSS_t; + +#endif diff --git a/src/delta-ua/fota_cfg.c b/src/delta-ua/fota_cfg.c new file mode 100755 index 0000000..23747e2 --- /dev/null +++ b/src/delta-ua/fota_cfg.c @@ -0,0 +1,32 @@ +/* + * tota-ua + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "fota_cfg.h" + +char fota_cfg_str[EN_CFG_MAX][CFG_MAX_LEN]; + +void fota_cfg_str_load(void) +{ + strncpy(fota_cfg_str[EN_CFG_SUPPORT_FB], "1", CFG_MAX_LEN-1); + strncpy(fota_cfg_str[EN_CFG_SUPPORT_DRM], "0", CFG_MAX_LEN-1); + strncpy(fota_cfg_str[EN_CFG_DEV_FB], "/dev/fb0", CFG_MAX_LEN-1); + strncpy(fota_cfg_str[EN_CFG_DEV_DRM_NAME], "exynos", CFG_MAX_LEN-1); +} + diff --git a/src/delta-ua/fota_cfg.h b/src/delta-ua/fota_cfg.h new file mode 100755 index 0000000..0afd301 --- /dev/null +++ b/src/delta-ua/fota_cfg.h @@ -0,0 +1,41 @@ +/* + * tota-ua + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __FOTA_CFG_H__ +#define __FOTA_CFG_H__ + +#define CFG_MAX_LEN 1024 + +enum { + EN_CFG_SUPPORT_FB, + EN_CFG_SUPPORT_DRM, + EN_CFG_DEV_FB, + EN_CFG_DEV_DRM_NAME, + EN_CFG_MAX +}; + +extern char fota_cfg_str[EN_CFG_MAX][CFG_MAX_LEN]; + + +extern void fota_cfg_str_load(void); + + + +#endif /* __FOTA_FB_H__ */ + + diff --git a/src/delta-ua/fota_util.c b/src/delta-ua/fota_util.c new file mode 100755 index 0000000..4e0b46b --- /dev/null +++ b/src/delta-ua/fota_util.c @@ -0,0 +1,194 @@ +/* + * tota-ua + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fota_common.h" + +int s_fd_stdin = -1; +int s_fd_stdout = -1; +int s_fd_stderr = -1; + +/*----------------------------------------------------------------------------- + set_default_stdio + ----------------------------------------------------------------------------*/ +static int set_default_stdio(int flags, int nfd) +{ + int fd, r; + + fd = open("/dev/null", flags|O_NOCTTY); + if (fd < 0) + return -errno; + + if (fd == nfd) { + return fd; + } else { + r = dup2(fd, nfd) < 0 ? -errno : nfd; + close(fd); + return r; + } +} + +/*----------------------------------------------------------------------------- + _init_stdio + ----------------------------------------------------------------------------*/ +void _init_stdio(void) +{ + s_fd_stdin = set_default_stdio(O_RDONLY, STDIN_FILENO); + + s_fd_stdout = set_default_stdio(O_WRONLY, STDOUT_FILENO); + + s_fd_stderr = set_default_stdio(O_WRONLY, STDERR_FILENO); +} + +/*----------------------------------------------------------------------------- + _exit_stdio + ----------------------------------------------------------------------------*/ +void _exit_stdio(void) +{ + if (s_fd_stdin >= 0) + close(s_fd_stdin); + + if (s_fd_stdout >= 0) + close(s_fd_stdout); + + if (s_fd_stderr >= 0) + close(s_fd_stderr); +} + +/*----------------------------------------------------------------------------- + _system_cmd_wait + ----------------------------------------------------------------------------*/ +int _system_cmd_wait(const char *command) +{ + + int pid = 0; + int status = 0; + char* const environ[2] = {"DISPLAY=:0", NULL }; + + if (command == NULL) + return -1; + + pid = fork(); + + if (pid == -1) + return -1; + + if (pid == 0) { + char *argv[4]; + argv[0] = "sh"; + argv[1] = "-c"; + argv[2] = (char*)command; + argv[3] = 0; + execve("/bin/sh", argv, environ); + exit(127); + } + + do { + if (waitpid(pid, &status, 0) == -1) { + if (errno != EINTR) + return -1; + } else { + return status; + } + } while (1); +} + +/*----------------------------------------------------------------------------- + _system_cmd_nowait + ----------------------------------------------------------------------------*/ +int _system_cmd_nowait(const char *command) +{ + + int pid = 0; + char* const environ[2] = {"DISPLAY=:0", NULL }; + + if (command == NULL) + return -1; + + pid = fork(); + + if (pid == -1) + return -1; + + if (pid == 0) { + char *argv[4]; + argv[0] = "sh"; + argv[1] = "-c"; + argv[2] = (char*)command; + argv[3] = 0; + execve("/bin/sh", argv, environ); + exit(127); + } + + return 0; +} + +/*----------------------------------------------------------------------------- + check_existence + ----------------------------------------------------------------------------*/ +long check_existence(const char *file_path) +{ + struct stat statbuf; + char filename[MAX_FILE_PATH]; + char buf[256]; + + LOG("%s: %s\n", __func__ , file_path); + if (strncpy(filename, file_path, sizeof(filename) - 1) == NULL) { + LOG("strncpy error=%s\n", filename); + return 0; + } + if (stat(filename, &statbuf)) { + if (ENOENT == errno) { + strerror_r(errno, buf, sizeof(buf)); + LOG("stat %s: %s\n", filename, buf); + return 0; + } + } + LOG("%s: statbuf.st_size = %d\n", __func__ , (int)statbuf.st_size); + return statbuf.st_size; +} + +/*----------------------------------------------------------------------------- + make_temp_file + ----------------------------------------------------------------------------*/ +void make_temp_file(char *temp_file, int file_size) +{ + FILE *fp; + int i = 0, temp = 0; + + LOG("Make %s file\n", temp_file); + + fp = fopen(temp_file, "wb"); + if (!fp) { + LOGE("failed to fopen\n"); + return; + } + for (i = 0; i < file_size; i++) + fwrite(&temp, sizeof(int), 1, fp); + fclose(fp); +} + diff --git a/src/delta-ua/fota_util.h b/src/delta-ua/fota_util.h new file mode 100755 index 0000000..184ef65 --- /dev/null +++ b/src/delta-ua/fota_util.h @@ -0,0 +1,31 @@ +/* + * tota-ua + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _FOTA_UTIL_H_ +#define _FOTA_UTIL_H_ + +extern void _init_stdio(void); +extern void _exit_stdio(void); +extern int _system_cmd_wait(const char *command); +extern int _system_cmd_nowait(const char *command); +extern long check_existence(const char *file_path); +extern void make_temp_file(char *temp_file, int file_size); + + +#endif /* _FOTA_UTIL_H_ */ + diff --git a/src/delta-ua/ua.c b/src/delta-ua/ua.c new file mode 100755 index 0000000..ac6652e --- /dev/null +++ b/src/delta-ua/ua.c @@ -0,0 +1,1538 @@ +/* + * tota-ua + * + * Copyright (c) 2017 - 2021 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "SS_Common.h" +#include "fota_common.h" +#include "ua.h" +#include "ua_types.h" +#include "mmc_io.h" +#include "fota_cfg.h" +#include "fota_tar.h" +#include "fota_util.h" +#include "SS_UPI.h" +#include "blkid-api.h" + +#define MAX_CFG_LEN 4096 + +#define RAMDISK_PATH "/opt/usr/data/fota" +#define SYSTEM_LOG_DIR "/opt/var/log" + +int ua_op_mode = UA_OP_MODE_FG; +char ua_slot_mode = 0; +int dm_verity_status = DM_VERITY_DISABLED; + +// TODO: Consider changing all to PATH_MAX +static char fota_result[MAX_FILE_PATH]; +static char fota_cause[MAX_FILE_PATH]; +static char fota_status_path[MAX_FILE_PATH]; +static char delta_folder[MAX_FOLDER_PATH]; +static char delta_path[MAX_FILE_PATH]; +static char log_folder[MAX_FOLDER_PATH]; +static char result_folder[MAX_FOLDER_PATH]; +static char temp_folder[MAX_FOLDER_PATH]; +static char log_path[MAX_FILE_PATH]; +static char blk_dev_arg[PATH_MAX] = "/dev/mmcblk0"; + +static ua_part_info_t s_part_info[UA_PARTI_MAX]; + +static ua_update_cfg_t s_update_cfg[UA_PARTI_MAX]; + +static ua_update_data_t s_update_data[UA_PARTI_MAX]; + +static int s_part_num = 0; +static ua_delta_info_t s_delta_info; + +unsigned int __log_level__ = + (LOG_DEBUG | LOG_FLASH | LOG_FILE | LOG_FUNCS | LOG_GUI | LOG_ENGINE | LOG_INFO); +FILE *__log_out_file__; + +static void save_result(int result); +static void save_cause(int cause); + +/*----------------------------------------------------------------------------- + fota_gui_update_progress + ----------------------------------------------------------------------------*/ +#define TMP_DIR "/tmp/upgrade" +#define PROGRESS_FILE TMP_DIR "/ro_progress" + +#define HAL_PROGRESS_MIN 40 +#define HAL_PROGRESS_MAX 80 + +void print_usage(const char *msg) +{ + if (msg) { + printf("%s\n", msg); + } + printf("USAGE: delta.ua delta_dir output_dir [operation_mode] [upgrade_slot block_device]\n" + "delta_dir: directory path where delta.tar file is located\n" + "output_dir: directory path for log file, result file, temporary file\n" + "operation_mode: run program in Background Mode: 0 or Foreground Mode: 1\n" + "upgrade_slot: upgrade slot number \"a\" or \"b\" It is used for A|B upgrade mode.\n" + " When it is set delta.ua will not read hardcoded partitions from config file.\n" + " Program will use libblkid to determine it based on GPT partition label.\n" + " e.g. delta.ua will try to update rootfs from a slot, so it will search for rootfs_a label\n" + " NOTE: if this argument is set block_device have to be specified.\n" + "block_device: block device that partitions for upgrade are on. e.g. /dev/mmcblk0\n" + " NOTE: if this argument is set upgrade_slot have to be specified.\n" + ); +} + +void print_error_code(int err) +{ + char msg[]="delta.ua error:"; + switch (err) { + case UPI_CONFIG_ERROR: + printf("%s config error.\n", msg); + break; + case UPI_DELTA_PATH_ERROR: + printf("%s delta path error.\n", msg); + break; + case UPI_DELTA_PATH_LENGTH_ERROR: + printf("%s delta path lenght error.\n", msg); + break; + case UPI_VERSION_ERROR: + printf("%s version error.\n", msg); + break; + case UPI_VERIFY_ERROR: + printf("%s verify error.\n", msg); + break; + case UPI_UPDATE_ERROR: + printf("%s update error.\n", msg); + break; + case UPI_INVALID_PARAM_ERROR: + printf("%s invalid parameter error.\n", msg); + break; + case UPI_DELTACOUNT_ERROR: + printf("%s delta count error.\n", msg); + break; + case UPI_PARTINFO_ERROR: + printf("%s partition information error.\n", msg); + break; + default: + printf("delta.ua unable to determine error code: %d\n", err); + } +} + +void fota_gui_update_progress(int percent) +{ + int ret; + int fd; + struct stat s; + + // Check directory + ret = stat(TMP_DIR, &s); + if (ret == 0) { + // TMP_DIR exists but it is not directory + if (!S_ISDIR(s.st_mode)) + goto remove_file; + else + goto update_progress; + } else if (errno == ENOENT) // TMP_DIR not exists + goto make_directory; + else { + LOG("stat failed : %m\n"); + return; + } + +remove_file: + ret = remove(TMP_DIR); + if (ret != 0) { + LOG("remove failed : %m\n"); + return; + } + +make_directory: + ret = mkdir(TMP_DIR, 0755); + if (ret != 0) { + LOG("mkdir failed : %m\n"); + return; + } + +update_progress: + fd = creat(PROGRESS_FILE, 0644); + if (fd < 0) { + LOG("creat failed : %m\n"); + return; + } + + ret = dprintf(fd, "%d\n", percent); + if (close(fd) != 0) { + LOG("close failed : %m\n"); + return; + } + if (ret < 2) { + LOG("write failed (%d) : %m\n", ret); + return; + } + + LOG("Succeed to write\n"); +} + +static void set_upgrade_progress(int percent) +{ + int relative_precent = HAL_PROGRESS_MIN + ((HAL_PROGRESS_MAX - HAL_PROGRESS_MIN) * percent)/100; + if (hal_device_board_set_upgrade_status(relative_precent) < 0) { + LOG("set_upgrade_status failed: %d\n", relative_precent); + return; + } + + LOG("set_upgrade_status success: %d\n", relative_precent); +} + +/*----------------------------------------------------------------------------- + fota_gui_progress + ----------------------------------------------------------------------------*/ +void fota_gui_progress(void * pbUserData, unsigned long uPercent) +{ + int percent; + int from, to; + ua_dataSS_t *ua_data = (ua_dataSS_t *)pbUserData; + ua_update_data_t *ua_update_data = ua_data->update_data; + + LOGL(LOG_FUNCS|LOG_GUI, "%s: ++ uPercent(%lu%%), config->weight=%lu\n", __func__, + uPercent, (long unsigned int)ua_update_data->weight); + + if (uPercent == 100) + percent = ua_update_data->weight_offset + ua_update_data->weight; + else + percent = ua_update_data->weight_offset + (ua_update_data->weight * uPercent / 100); + + set_upgrade_progress(percent); + /** + * re-arrange progress percentage between scout & update + * + * 0 ~ 100 -> from ~ to + */ + switch (ua_data->ua_operation) { + case UI_OP_SCOUT: + from = 0; + to = 20; + break; + case UI_OP_SCOUT_UPDATE: + case UI_OP_UPDATE: + from = 20; + to = (dm_verity_status == DM_VERITY_ENABLED) ? 80 : 100; + break; + default: + from = 0; + to = 100; + break; + } + + percent = from + ((to - from) * percent / 100); + + fota_gui_update_progress(percent); /* update progress bar and text */ + + LOGL(LOG_FUNCS|LOG_GUI, "-- uPercent=%lu, Print Percent(%d%%)\n", uPercent, percent); +} + +/*----------------------------------------------------------------------------- + write_data_to_blkdev + - blk_start : start sector number + - blk_cnt : number of sectors to write + - data length should be blk_cnt x SECTOR_SIZE + ----------------------------------------------------------------------------*/ +static int write_data_to_blkdev(char* dev_name, int blk_start, int blk_cnt, char* data) +{ + int fd_mmc; + + LOG("%s: entered start offset=%d sectos, size=%d sectos\n", dev_name, blk_start, blk_cnt); + /* destination MMC device open */ + fd_mmc = mmc_dev_open(dev_name, O_RDWR); + if (fd_mmc < 0) { + LOG("mmc_dev_open() fail ...\n"); + return FAIL; + } + + if (mmc_dev_sector_write(fd_mmc, blk_start, blk_cnt, data) < 0) { + LOG("mmc_dev_sector_write() fail ...\n"); + mmc_dev_close(fd_mmc); + return FAIL; + } + + mmc_dev_close(fd_mmc); + LOG("%s: leaved\n", __func__); + + return SUCCESS; +} + +/*----------------------------------------------------------------------------- + write_full_image + ----------------------------------------------------------------------------*/ +static int write_full_image(ua_dataSS_t* ua_data, int part_idx) +{ + int ret = SUCCESS; + int blk_start = 0; + int blk_cnt = 0; + int read_count = 0, data_length = 0; + char* data = NULL; + int bin_size = 0, offset = 0; + ua_part_info_t *ua_part_info = ua_data->parti_info; + ua_update_data_t *ua_update_data = ua_data->update_data; + + FILE *fp; + + LOG("ua_delta_path=%s, ua_subject_name=%s\n", ua_update_data->ua_delta_path, ua_part_info->ua_subject_name); + + fp = fopen(ua_update_data->ua_delta_path, "r"); + if (!fp) { + LOGE("open file %s failed.\n", ua_update_data->ua_delta_path); + return FAIL; + } + + bin_size = tar_get_item_size(ua_update_data->ua_delta_path, ua_part_info->ua_subject_name); + if (bin_size <= 0) { + LOGE("bin_size=%d\n", bin_size); + fclose(fp); + return FAIL; + } + offset = tar_get_item_offset(ua_update_data->ua_delta_path, ua_part_info->ua_subject_name); + if (offset < 0) { + LOGE("offset=%d\n", offset); + fclose(fp); + return FAIL; + } + + blk_cnt = ((bin_size-1)/SECTOR_SIZE)+1; + data_length = blk_cnt * SECTOR_SIZE; + LOG("bin_size=%d, data_length=%d\n", bin_size, data_length); + + if (fseek(fp, offset, SEEK_SET) < 0) { + LOGE("fseek() fail\n"); + fclose(fp); + return FAIL; + } + + data = malloc(data_length); + if (data) { + read_count = fread(data, 1, bin_size, fp); + LOG("read file read_count=%d byte, blk_cnt=%d\n", read_count, blk_cnt); + if (read_count != bin_size) { + LOGE("error in read size\n"); + if (data) + free(data); + if (fp) + fclose(fp); + return FAIL; + } + + if (write_data_to_blkdev(ua_part_info->ua_blk_name, + blk_start, blk_cnt, data) != SUCCESS) { + LOGE("error in write_data_to_blkdev()\n"); + ret = FAIL; + } + + if (data) + free(data); + } + + if (fp) + fclose(fp); + + LOG("%s leaved\n", __func__); + + return ret; +} + +/*----------------------------------------------------------------------------- + verify_Full_Image + ----------------------------------------------------------------------------*/ +int verify_Full_Image(int part_idx) +{ + int ret = SUCCESS; + ua_dataSS_t ua_dataSS; + ua_part_info_t *ua_part_info = &s_part_info[part_idx]; + ua_update_cfg_t *ua_update_cfg = &s_update_cfg[part_idx]; + ua_update_data_t *ua_update_data = &s_update_data[part_idx]; + ua_delta_info_t *ua_delta_info = &s_delta_info; + ua_dataSS.parti_info = ua_part_info; + ua_dataSS.update_cfg = ua_update_cfg; + ua_dataSS.update_data = ua_update_data; + ua_dataSS.update_delta = ua_delta_info; + ua_dataSS.ua_operation = UI_OP_SCOUT; + ua_dataSS.ui_progress = fota_gui_progress; + + if (ua_update_data->ua_delta_path != NULL) { + ret = SUCCESS;//SS_IMGVerfiyPartition(&ua_dataSS); + fota_gui_progress(&ua_dataSS, 100); + } + return ret; +} + +/*----------------------------------------------------------------------------- + update_Full_Image + ----------------------------------------------------------------------------*/ +int update_Full_Image(int part_idx) +{ + int ret = FAIL; + ua_dataSS_t ua_data; + ua_part_info_t *ua_part_info = &s_part_info[part_idx]; + ua_update_cfg_t *ua_update_cfg = &s_update_cfg[part_idx]; + ua_update_data_t *ua_update_data = &s_update_data[part_idx]; + + ua_data.parti_info = ua_part_info; + ua_data.update_cfg = ua_update_cfg; + ua_data.update_data = ua_update_data; + ua_data.ui_progress = fota_gui_progress; + ua_data.ua_operation = UI_OP_UPDATE; + + LOG("%s entered\n", __func__); + + ret = write_full_image(&ua_data, part_idx); + if (ret != SUCCESS) { + LOGE("%s entered\n", __func__); + goto CleanUp; + } + + fota_gui_progress(&ua_data, 100); /* display completion of update_Sbl */ + + CleanUp: + + LOG("%s leaved ret=%d\n", __func__, ret); + return ret; +} + +/*----------------------------------------------------------------------------- + verify_Delta_FS + ----------------------------------------------------------------------------*/ +int verify_Delta_FS(int part_idx) +{ + int ret = SUCCESS; + ua_dataSS_t ua_dataSS; + ua_part_info_t *ua_part_info = &s_part_info[part_idx]; + ua_update_cfg_t *ua_update_cfg = &s_update_cfg[part_idx]; + ua_update_data_t *ua_update_data = &s_update_data[part_idx]; + ua_delta_info_t *ua_delta_info = &s_delta_info; + ua_dataSS.parti_info = ua_part_info; + ua_dataSS.update_cfg = ua_update_cfg; + ua_dataSS.update_data = ua_update_data; + ua_dataSS.update_delta = ua_delta_info; + ua_dataSS.ua_operation = UI_OP_SCOUT; + ua_dataSS.ui_progress = fota_gui_progress; + + if (ua_update_data->ua_delta_path != NULL) { + LOG("Verifying %s \n", ua_dataSS.parti_info->ua_parti_name); + ret = SS_FSVerifyPartition(&ua_dataSS, part_idx); + } + + return ret; +} + +/*----------------------------------------------------------------------------- + update_Delta_FS + ----------------------------------------------------------------------------*/ +int update_Delta_FS(int part_idx, unsigned long ui32Operation) +{ + int ret = SUCCESS; + ua_dataSS_t ua_dataSS; + ua_part_info_t *ua_part_info = &s_part_info[part_idx]; + ua_update_cfg_t *ua_update_cfg = &s_update_cfg[part_idx]; + ua_update_data_t *ua_update_data = &s_update_data[part_idx]; + ua_delta_info_t *ua_delta_info = &s_delta_info; + ua_dataSS.parti_info = ua_part_info; + ua_dataSS.update_cfg = ua_update_cfg; + ua_dataSS.update_data = ua_update_data; + ua_dataSS.update_delta = ua_delta_info; + ua_dataSS.ua_operation = ui32Operation; + ua_dataSS.ui_progress = fota_gui_progress; + + if (ua_update_data->ua_delta_path != NULL) + ret = SS_FSUpdatemain(&ua_dataSS, part_idx); + + return ret; +} + +/*----------------------------------------------------------------------------- + verify_Delta_IMAGE + ----------------------------------------------------------------------------*/ +int verify_Delta_IMAGE(int part_idx) +{ + int ret = SUCCESS; + ua_dataSS_t ua_dataSS; + ua_part_info_t *ua_part_info = &s_part_info[part_idx]; + ua_update_cfg_t *ua_update_cfg = &s_update_cfg[part_idx]; + ua_update_data_t *ua_update_data = &s_update_data[part_idx]; + ua_delta_info_t *ua_delta_info = &s_delta_info; + + ua_dataSS.parti_info = ua_part_info; + ua_dataSS.update_cfg = ua_update_cfg; + ua_dataSS.update_data = ua_update_data; + ua_dataSS.update_delta = ua_delta_info; + ua_dataSS.ua_operation = UI_OP_SCOUT; + ua_dataSS.ui_progress = fota_gui_progress; + + if (ua_update_data->ua_delta_path != NULL) + ret = SS_IMGVerfiyPartition(&ua_dataSS, ua_dataSS.parti_info->ua_blk_name_previous, false); + + return ret; +} + +/*----------------------------------------------------------------------------- + update_Delta_IMAGE + ----------------------------------------------------------------------------*/ +int update_Delta_IMAGE(int part_idx, unsigned long ui32Operation) +{ + int ret = SUCCESS; + ua_dataSS_t ua_dataSS; + ua_part_info_t *ua_part_info = &s_part_info[part_idx]; + ua_update_cfg_t *ua_update_cfg = &s_update_cfg[part_idx]; + ua_update_data_t *ua_update_data = &s_update_data[part_idx]; + + ua_delta_info_t *ua_delta_info = &s_delta_info; + ua_dataSS.parti_info = ua_part_info; + ua_dataSS.update_cfg = ua_update_cfg; + ua_dataSS.update_data = ua_update_data; + ua_dataSS.update_delta = ua_delta_info; + ua_dataSS.ua_operation = ui32Operation; + ua_dataSS.ui_progress = fota_gui_progress; + ua_dataSS.write_data_to_blkdev = write_data_to_blkdev; + if (ua_update_data->ua_delta_path != NULL) + ret = SS_IMGUpdatemain(&ua_dataSS, DELTA_IMAGE); + return ret; +} + +int verify_RecoveryDelta_IMAGE(int part_idx, int update_type) +{ + int ret = SUCCESS; + ua_dataSS_t ua_dataSS; + ua_part_info_t *ua_part_info = &s_part_info[part_idx]; + ua_update_cfg_t *ua_update_cfg = &s_update_cfg[part_idx]; + ua_update_data_t *ua_update_data = &s_update_data[part_idx]; + ua_delta_info_t *ua_delta_info = &s_delta_info; + ua_dataSS.parti_info = ua_part_info; + ua_dataSS.update_cfg = ua_update_cfg; + ua_dataSS.update_data = ua_update_data; + ua_dataSS.update_delta = ua_delta_info; + ua_dataSS.ua_operation = UI_OP_SCOUT; + ua_dataSS.ui_progress = fota_gui_progress; + if (update_type == FULL_IMAGE) { + if (ua_update_data->ua_delta_path != NULL) { + ret = SUCCESS; + fota_gui_progress(&ua_dataSS, 100); + } + } else if (update_type == DELTA_IMAGE) { + if (ua_update_data->ua_delta_path != NULL) + ret = SS_IMGVerfiyPartition(&ua_dataSS, ua_dataSS.parti_info->ua_blk_name, true); + } + return ret; +} + + +int update_RecoveryDelta_IMAGE(int part_idx, int update_type) +{ + int ret = SUCCESS; + ua_dataSS_t ua_dataSS; + ua_part_info_t *ua_part_info = &s_part_info[part_idx]; + ua_update_cfg_t *ua_update_cfg = &s_update_cfg[part_idx]; + ua_update_data_t *ua_update_data = &s_update_data[part_idx]; + ua_delta_info_t *ua_delta_info = &s_delta_info; + ua_dataSS.parti_info = ua_part_info; + ua_dataSS.update_cfg = ua_update_cfg; + ua_dataSS.update_data = ua_update_data; + ua_dataSS.update_delta = ua_delta_info; + ua_dataSS.update_data->ua_temp_path = malloc(MAX_FILE_PATH); + ua_dataSS.ua_operation = UI_OP_SCOUT_UPDATE; + ua_dataSS.ui_progress = fota_gui_progress; + if (ua_update_data->ua_delta_path != NULL && ua_dataSS.update_data->ua_temp_path) { + snprintf(ua_dataSS.update_data->ua_temp_path, MAX_FILE_PATH, "%s/%s", RAMDISK_PATH, ua_dataSS.parti_info->ua_parti_name); + LOG("update_RecoveryDelta_IMAGE() [%s] temp path [%s]\n", ua_dataSS.parti_info->ua_parti_name, ua_dataSS.update_data->ua_temp_path); + ret = SS_IMGUpdatemain(&ua_dataSS, update_type); //PASS temp path whr file has to be written, Once written it should be UNLINKED after upgrade. + } + return ret; +} + + +/*----------------------------------------------------------------------------- + set_data_weight + ----------------------------------------------------------------------------*/ +/* set data weight using data size minimum:1 total: 100 */ +static void set_data_weight(unsigned int total_data_size) +{ + int i = 0, big = 0, weight = 0, total_weight = 0; + + LOG("%s entered, total_data_size=%u\n", __func__, total_data_size); + + for (i = 0; i < s_part_num; i++) { + if (s_update_data[i].exist_check) { + s_update_data[i].weight = 100 * (unsigned long long)s_update_data[i].data_size / total_data_size; + + if (s_update_data[i].weight == 0) + s_update_data[i].weight = 1; + + if (weight < s_update_data[i].weight) { + weight = s_update_data[i].weight; + big = i; + } + + total_weight += s_update_data[i].weight; + } + + LOG("[%d] exist_check=%d, weight=%u total_weight=%u\n", + i, s_update_data[i].exist_check, s_update_data[i].weight, total_weight); + } + + if (total_weight < 100) + s_update_data[big].weight += (100 - total_weight); + else + s_update_data[big].weight -= (total_weight - 100); + + LOG("[big: %d] weight=%u\n", big, s_update_data[big].weight); + + LOG("%s leaved\n", __func__); +} + +/*----------------------------------------------------------------------------- + set_data_weight_offset + ----------------------------------------------------------------------------*/ +static void set_data_weight_offset(void) +{ + int i = 0, k = 0; + + LOG("%s entered\n", __func__); + + for (i = 0; i < s_part_num; i++) { + for (k = 0; k < i; k++) + s_update_data[i].weight_offset += s_update_data[k].weight; + + LOG("s_update_data[%d].weight_offset=%u\n", i, s_update_data[i].weight_offset); + } + + LOG("%s leaved\n", __func__); +} + +/*----------------------------------------------------------------------------- + get_time_stamp + ----------------------------------------------------------------------------*/ +static char ts[256]; +static void get_time_stamp(void) +{ + struct timeval tv; + int sec, msec; + + gettimeofday(&tv, NULL); + sec = (int) tv.tv_sec; + msec = (int) (tv.tv_usec / 1000); + snprintf(ts, sizeof(ts), "%06d.%03d", sec % 100000, msec); +} + +/*----------------------------------------------------------------------------- + update_all + ----------------------------------------------------------------------------*/ +int update_all() +{ + int i, data_count = 0, ret = OK; + unsigned long total_data_size = 0; + int cause = 0; + int item_size = 0; + int last_update_status = UP_START_NONE; + int update_status = UP_START_NONE; + int del_type = 0; // delta type + int part_idx = UA_PARTI_MAX; + unsigned int update_type = 0; + unsigned long ui32Operation = UI_OP_SCOUT; + + LOG("%s entered\n", __func__); + + data_count = 0; + + for (i = 0; i < s_part_num; i++) { + item_size = tar_get_item_size(s_update_data[i].ua_delta_path, s_part_info[i].ua_subject_name); + if (item_size > 0) + s_update_data[i].data_size = (unsigned int)item_size; + else + s_update_data[i].data_size = 0; + + LOGL(LOG_DEBUG, "s_update_data[%d].data_size=%lu, ua_delta_path=%s, " + "ua_blk_name = %s, ua_subject_name=%s\n", + i, + (long unsigned int)s_update_data[i].data_size, + s_update_data[i].ua_delta_path, + s_part_info[i].ua_blk_name, + s_part_info[i].ua_subject_name); + + if (s_update_data[i].data_size) { + data_count++; + + s_update_data[i].exist_check = 1; + total_data_size += s_update_data[i].data_size; + + LOGL(LOG_DEBUG, + "Check Delta : part_idx(%d), file_path(%s), total data cnt(%lu)\n", + i, s_update_data[i].ua_delta_path, + (long unsigned int)data_count); + } + } + + LOG("data_count=%lu, total_data_size=%lu\n", + (long unsigned int)data_count, (long unsigned int)total_data_size); + if (data_count == 0) { + ret = UPI_DELTACOUNT_ERROR; + sleep(3); + + goto CleanUp; + } + LOG(" set weight to draw progressive bar.....\n"); + set_data_weight(total_data_size); + set_data_weight_offset(); + + for (i = 0; i < s_part_num; i++) { + LOG("s_part_info[%s].ua_delta_path = %s ua_subject_name=%s\n", + s_part_info[i].ua_parti_name, + s_update_data[i].ua_delta_path, + s_part_info[i].ua_subject_name); + } + + if (SS_Get_last_update_status(&last_update_status, &del_type) == -1) + LOG("No last_update_status. Go normal update scenario.\n"); + else + LOG("Get last_update_status. Go Power safe update scenario.\n"); + + LOG("last_update_status: [%d], del_type: [%d] \n", last_update_status, del_type); + /* Verify */ + if (last_update_status == UP_START_NONE) { + for (part_idx = 0; part_idx < s_part_num; part_idx++) { + if (s_update_data[part_idx].data_size > 0) { + get_time_stamp(); + LOG("[%s] Verify %s ..............................................................\n", ts, + s_part_info[part_idx].ua_parti_name); + update_type = s_update_cfg[part_idx].update_type; + if (s_update_cfg[part_idx].update_when != AT_BOOT_FOTA) { + LOG("ignore %s - should be modified BEFORE_BOOT_FOTA", s_part_info[part_idx].ua_parti_name); + continue; + } + if (update_type == FULL_IMAGE) + ret = verify_Full_Image(part_idx); + else if (update_type == DELTA_IMAGE) + ret = verify_Delta_IMAGE(part_idx); + else if (update_type == DELTA_FS) + ret = verify_Delta_FS(part_idx); + else if (update_type == EXTRA) + ret = verify_RecoveryDelta_IMAGE(part_idx, FULL_IMAGE); + else + ret = -1; + + if (ret != OK) { + cause = ret; + ret = UPI_VERIFY_ERROR; + LOG("%s verify fail\n", s_part_info[part_idx].ua_parti_name); + goto CleanUp; + } + s_update_data[part_idx].verify_check = 1; + } + } + + } + + get_time_stamp(); + LOG("[%s] Verify End ..............................................................\n", ts); + + /* Update */ + for (part_idx = 0; part_idx < s_part_num; part_idx++) { + update_status = part_idx; + if (last_update_status <= update_status) { + if (last_update_status == update_status) + ui32Operation = UI_OP_SCOUT_UPDATE; + else + ui32Operation = UI_OP_UPDATE; + + if (s_update_data[part_idx].data_size > 0) { + get_time_stamp(); + LOG("[%s] Update %s ..............................................................\n", ts, + s_part_info[part_idx].ua_parti_name); + + SS_Set_last_update_status(update_status, del_type); + + if (s_update_cfg[part_idx].update_when != AT_BOOT_FOTA) { + LOG("ignore %s - should be modified BEFORE_BOOT_FOTA", s_part_info[part_idx].ua_parti_name); + continue; + } + update_type = s_update_cfg[part_idx].update_type; + if (update_type == FULL_IMAGE) + ret = update_Full_Image(part_idx); + else if (update_type == DELTA_IMAGE) + ret = update_Delta_IMAGE(part_idx, ui32Operation); + else if (update_type == DELTA_FS) + ret = update_Delta_FS(part_idx, ui32Operation); + else if (update_type == EXTRA) //TOTA + ret = update_RecoveryDelta_IMAGE(part_idx, FULL_IMAGE); + else + ret = -1; + + if (ret != OK) { + cause = ret; + ret = UPI_UPDATE_ERROR; + LOG("%s update fail\n", s_part_info[part_idx].ua_parti_name); + goto CleanUp; + } + s_update_data[part_idx].update_check = 1; + del_type = 0; + } + } + } + + if (part_idx == s_part_num) + SS_Set_last_update_status(s_part_num, 0); + + get_time_stamp(); + LOG("[%s] Update End ..............................................................\n", ts); + + CleanUp: + if (ret != OK) + save_cause(cause); + + return ret; +} + +/*----------------------------------------------------------------------------- + log_init + ----------------------------------------------------------------------------*/ +void log_init(void) +{ + memset(log_path, 0x00, sizeof(log_path)); + snprintf(log_path, sizeof(log_path), "%s%s", log_folder, LOG_FILE_PATH); + + __log_out_file__ = fopen(log_path, "w"); + if (__log_out_file__ == NULL) { + perror("file open error\n"); + return; + } + + get_time_stamp(); + LOG("===== log start [%s] =====\n", ts); +} + +/*----------------------------------------------------------------------------- + log_deinit + ----------------------------------------------------------------------------*/ +void log_deinit(void) +{ + get_time_stamp(); + LOG("===== log end [%s] =====\n", ts); + + if (__log_out_file__) { + fclose(__log_out_file__); + __log_out_file__ = NULL; + } + + sync(); +} + +/*----------------------------------------------------------------------------- + print_error_cause + ----------------------------------------------------------------------------*/ +static void print_error_cause(int error) +{ + switch (error) { + case E_SS_PKG_CORRUPTED: + case E_SS_SOURCE_CORRUPTED: /* not used */ + case E_SS_IMGBADDELTA: + case E_SS_FSBADDELTA: + LOG("Corrupted firmware update package, did not store correctly. Detected, for example, by mismatched CRCs between actual and expected.\n"); + break; + case E_SS_BAD_PARAMS: + LOG("Wrong Firmware Update Package delivered to device based on current device characteristics\n"); + break; + case E_SS_INVALID_DP_HEADER: + case E_SS_INVALID_DP_WRONG_SIGNATURE: + LOG("Failure to positively validate digital signature of firmware update package\n"); + break; + case E_SS_PKG_TOO_LONG: /* not used */ + LOG("Firmware Update Package is Not Acceptable\n"); + break; + case E_SS_NOT_ENOUGH_RAM: + case E_SS_MALLOC_ERROR: + LOG("The update fails because there isn't sufficient memory to update the device.\n"); + break; + case E_SS_FSSRCBACKUPFAILED: + case E_SS_IMGSRCBACKUPFAILED: + case E_SS_IMGRECOVERYWRITEFAILED: + case E_SS_IMGFLASHWRITEFAIL: + case E_SS_WRITE_ERROR: + case E_SS_FSFAILEDTOBACKUPPATCHINFO: + case E_SS_FSBADATTRIBUTES: + LOG("The update failed because writing data to the device was unsuccessful.\n"); + break; + case E_SS_FSSRCCURRUPTED: + case E_SS_IMGSRCCURRUPTED: + case E_SS_IMGSHA_MISMATCH: + case E_SS_FSSHA_MISMATCH: + case E_SS_FSFAILEDTOPARSEDELTACNT: + case E_SS_FSFAILEDTOOPENPATCHINFO: + case E_SS_FSFAILEDTOPARSEDELTAINFO: + LOG("The update failed because data was corrupted during update of device.\n"); + break; + default: + LOG("another error\n"); + break; + } +} + +/* + +Corrupted firmware update package, did not store correctly. Detected, for example, by mismatched CRCs between actual and expected. +E_RB_PKG_CORRUPTED(0x8000000D) +E_RB_PKG_NOT_AUTHORIZED(0x8000000E): not used + + +Wrong Firmware Update Package delivered to device based on current device characteristics +E_RB_BAD_PARAMS(0x800000002) +E_RB_WRONG_UPI_VER(0x80000011):not used +E_RB_WRONG_UPI_UPDATE(0x80000012): not used +E_RB_UPDATE_SECTOR_SIG(0x80000013): not used + + +Failure to positively validate digital signature of firmware update package +E_RB_NON_DP_FORMAT_NOT_SUPPORTED(0x8001001A) +E_RB_INVALID_DP_HEADER(0x80010025) +E_RB_INVALID_DP_WRONG_SIGNATURE(0x80010026) +E_RB_INVALID_DP(0x80010027) + + +Firmware Update Package is Not Acceptable +E_RB_PKG_TOO_SHORT(0x8000000B) not used +E_RB_PKG_TOO_LONG(0x8000000C) not used +E_RB_PKG_NOT_AUTHORIZED(0x8000000F) + + +The update fails because there isn\A1\AFt sufficient memory to update the device. +E_RB_NOT_ENOUGH_RAM(0x8000001E) +*/ +/*----------------------------------------------------------------------------- + save_cause + ----------------------------------------------------------------------------*/ +void save_cause(int cause) +{ + char return_char[20]; + FILE *result_fp; + + LOG("%s entered, 0x%x\n", __func__, cause); + + print_error_cause(cause); + + if ((result_fp = fopen(fota_cause, "w")) == NULL) { + LOG("cause file open fail\n"); + return; + } + + snprintf(return_char, sizeof(return_char), "%x", cause); + fwrite(return_char, strlen(return_char), 1, result_fp); + fclose(result_fp); + + LOG("%s leaved!\n", __func__); +} + +/*----------------------------------------------------------------------------- + save_result + ----------------------------------------------------------------------------*/ +void save_result(int result) +{ + char return_char[20]; + FILE *result_fp; + + LOG("%s entered, result=0x%x\n", __func__, result); + + if ((result_fp = fopen(fota_result, "w")) == NULL) { + LOG("result file open fail\n"); + return; + } + + snprintf(return_char, sizeof(return_char), "%x", result); + fwrite(return_char, strlen(return_char), 1, result_fp); + fclose(result_fp); + + LOG("%s leaved!\n", __func__); + + return; +} + +/*----------------------------------------------------------------------------- + fota_path_init + ----------------------------------------------------------------------------*/ +int fota_path_init(void) +{ + int i; + + if (strlen(delta_folder) > MAX_FILE_PATH - 15) { + LOG("FOTA path is too long\n"); + return FAIL; + } + + for (i = 0; i < s_part_num; i++) { + s_update_data[i].ua_delta_path = malloc(MAX_FILE_PATH); + if (s_update_data[i].ua_delta_path == NULL) { + LOG("Memory allocation fail\n"); + return FAIL; + } + snprintf(s_update_data[i].ua_delta_path, MAX_FILE_PATH, "%s/%s", delta_folder, DEFAULT_DELTA_NAME); + //will be filled by UA if required (eg : RAMDISK case in TOTA) + //s_update_data[i].ua_temp_path = malloc(MAX_FILE_PATH); + //sprintf(s_update_data[i].ua_temp_path, "%s/fota_temp_%s", delta_folder, s_part_info[i].ua_parti_name); + } + + snprintf(fota_cause, sizeof(fota_cause), "%s/%s", result_folder, "cause"); + snprintf(fota_status_path, sizeof(fota_status_path), "%s/%s", result_folder, UP_STATUS_FILE); + + for (i = 0; i < s_part_num; i++) { + LOG("s_part_info[UA_%s].ua_delta_path=%s\n", + s_part_info[i].ua_parti_name, + s_update_data[i].ua_delta_path); + } + + return SUCCESS; +} + +/*----------------------------------------------------------------------------- + fota_path_deinit + ----------------------------------------------------------------------------*/ +void fota_path_deinit(void) +{ + int i; + for (i = 0; i < s_part_num; i++) { + if (s_update_data[i].ua_delta_path) { + free(s_update_data[i].ua_delta_path); + s_update_data[i].ua_delta_path = NULL; + } + if (s_update_data[i].ua_temp_path) { + free(s_update_data[i].ua_temp_path); + s_update_data[i].ua_temp_path = NULL; + } + } +} + +/*----------------------------------------------------------------------------- + check_ua_op_mode + ----------------------------------------------------------------------------*/ +int check_ua_op_mode(int argc, char **argv) +{ + ua_op_mode = -1; + ua_slot_mode = 0; + if (argc == 3) { + ua_op_mode = UA_OP_MODE_FG; + } else if (argc >= 4 && argc <= 6) { + if (argv[3][0] == '0') { + ua_op_mode = UA_OP_MODE_FG; + } else if (argv[3][0] == '1') { + ua_op_mode = UA_OP_MODE_BG; + } + if (argc == 6) { + if (argv[4][0] == 'a') { + ua_slot_mode = 'a'; + } else if (argv[4][0] == 'b') { + ua_slot_mode = 'b'; + } else { + ua_slot_mode = -1; + } + // TODO: realpath is fundamentally broken, see man. Not that we care :) + char *block_device = realpath(argv[5], blk_dev_arg); + if (!block_device) { + int max_err_len = strlen(argv[5]) + 100; + char err[max_err_len]; + snprintf(err, max_err_len, "Unable to get realpath for: %s\n", argv[5]); + print_usage(err); + return -1; + } + // Thanks to realpath call, blk_dev_arg now contains the path. + } + else if (argc == 5) { + print_usage("Unable to parse arguments, please specify upgrade_slot and block_device or none of them.\n"); + return -1; + } + } + if (ua_op_mode != -1 || ua_slot_mode == -1) + return 0; + + print_usage("Unable to parse arguments.\n"); + return -1; +} + +/*----------------------------------------------------------------------------- + check_dm_verity_status + ----------------------------------------------------------------------------*/ +int check_dm_verity_status(void) +{ + int ret = 0; + + ret = access("/usr/bin/verityctl", F_OK); + if (ret == -1) { + if (errno == ENOENT) { + LOG("dm-verity status : disabled\n"); + dm_verity_status = DM_VERITY_DISABLED; + return 0; + } else { + LOG("access failed with errno: %d\n", errno); + return -errno; + } + } + + LOG("dm-verity status : enabled\n"); + dm_verity_status = DM_VERITY_ENABLED; + return 0; +} + +/*----------------------------------------------------------------------------- + remove_temp_files + ----------------------------------------------------------------------------*/ +void remove_temp_files(void) +{ + int ret = 0; + int i; + char *ua_temp_path; + struct stat sbuf; + + for (i = 0; i < s_part_num; i++) { + ua_temp_path = s_update_data[i].ua_temp_path; + if (NULL == ua_temp_path) + continue; + + ret = lstat(ua_temp_path, &sbuf); + if (ret < 0) { + ret = stat(ua_temp_path, &sbuf); + if (ret < 0) { + LOG("stat failed with return value: %d errno: %d\n", ret, errno); + continue; + } + } + + if (S_ISDIR(sbuf.st_mode)) { + ret = rmdir(ua_temp_path); + if (ret < 0) + LOG("rmdir(%s) failed with return value: %d errno: %d\n", ua_temp_path, ret, errno); + } else { + ret = unlink(ua_temp_path); + if (ret < 0) + LOG("unlink(%s) failed with return value: %d errno: %d\n", ua_temp_path, ret, errno); + } + } +} + +/*----------------------------------------------------------------------------- + get_update_type + ----------------------------------------------------------------------------*/ +int get_update_type(char* part_name) +{ + char *ctx; + char *part = strtok_r(part_name, ":", &ctx); + if (part) { + if (strcmp(part, "FULL_IMAGE") == 0) + return FULL_IMAGE; + if (strcmp(part, "DELTA_IMAGE") == 0) + return DELTA_IMAGE; + if (strcmp(part, "DELTA_FS") == 0) + return DELTA_FS; + } + + return EXTRA; +} + +/*----------------------------------------------------------------------------- + get_update_when + ----------------------------------------------------------------------------*/ +int get_update_when(char* part_name) +{ + char *ctx; + char *part = strtok_r(part_name, ":", &ctx); + + if (part) // ignore the first element + part = strtok_r(NULL, ":", &ctx); + + if (part) { + if (strcmp(part, "BEFORE_BOOT_FOTA") == 0) + return BEFORE_BOOT_FOTA; + if (strcmp(part, "AT_BOOT_FOTA") == 0) + return AT_BOOT_FOTA; + } + return -1; +} + + +/*----------------------------------------------------------------------------- + fota_blkid_update + ----------------------------------------------------------------------------*/ +int fota_blkid_update(void) +{ + char part_tbl_path[MAX_FILE_PATH]; + FILE *fp; + int num_part; + int i, j; + int id, id_previous; + char part_name[256]; + char blk_name[PATH_MAX + 32]; + char blk_name_previous[PATH_MAX + 32]; + blkid_partlist pr = NULL; + blkid_probe bp = NULL; + + // new mode: use libblkid rather than reading partitions from + // part_table configuration file. + if (ua_slot_mode == 'a' || ua_slot_mode == 'b') { + char ua_slot_mode_previous = ua_slot_mode == 'a' ? 'b' : 'a'; + pr = get_part_list(blk_dev_arg, &bp); + if (!pr) { + return -1; + } + for (j = 0; j < s_part_num; ++j) { + memset((void*)blk_name, 0x00, sizeof(blk_name)); + memset((void*)blk_name_previous, 0x00, sizeof(blk_name_previous)); + id = get_part_number_by_name(pr, s_part_info[j].ua_parti_name, &ua_slot_mode); + id_previous = get_part_number_by_name(pr, s_part_info[j].ua_parti_name, &ua_slot_mode_previous); + if (id == -1 || id_previous == -1) { + LOG("failed to get_part_number_by_name for: %s, slot: %c, %c (%d %d)", + s_part_info[j].ua_parti_name, ua_slot_mode, ua_slot_mode_previous, + id, id_previous); + blkid_free_probe(bp); + return -1; + } + if (s_part_info[j].ua_blk_name) free(s_part_info[j].ua_blk_name); + if (s_part_info[j].ua_blk_name_previous) free(s_part_info[j].ua_blk_name_previous); + if (strncmp("/dev/sd", blk_dev_arg, strlen(blk_dev_arg) + 1) == 0) { + snprintf(blk_name, sizeof(blk_name)-1, "%s%d", blk_dev_arg, id); + snprintf(blk_name_previous, sizeof(blk_name_previous)-1, "%s%d", blk_dev_arg, id_previous); + } else { + snprintf(blk_name, sizeof(blk_name)-1, "%sp%d", blk_dev_arg, id); + snprintf(blk_name_previous, sizeof(blk_name_previous)-1, "%sp%d", blk_dev_arg, id_previous); + } + s_part_info[j].ua_blk_name = strdup(blk_name); + s_part_info[j].ua_blk_name_previous = strdup(blk_name_previous); + if (s_part_info[j].ua_blk_name == NULL || + s_part_info[j].ua_blk_name_previous == NULL) { + LOG("failed to allocate memory for device name: %m (%d)", errno); + return -1; + } + } + blkid_free_probe(bp); + } else { + // legacy mode: get part numbers from file + memset((void*)part_tbl_path, 0x00, sizeof(part_tbl_path)); + snprintf(part_tbl_path, sizeof(part_tbl_path)-1, "%s/%s", temp_folder, + PART_TBL_FILE); + + fp = fopen(part_tbl_path, "r"); + if (fp == NULL) { + LOG("fail to open partition table\n"); + return -1; + } + + if ((fscanf(fp, "%d", &num_part) < 0) || (num_part <= 0) || + (num_part >= MAX_PART_TBL_ITEM)) { + LOG("fail to fscanf() or num_part is 0\n"); + fclose(fp); + return -1; + } + for (i = 0; i < num_part; i++) { + if (fscanf(fp, "%d %32s", &id, part_name) < 0) { + LOG("fail to fscanf()\n"); + break; + } + LOG("%s [%d]\n", part_name, id); + for (j = 0; j < s_part_num; j++) { + memset((void*)blk_name, 0x00, sizeof(blk_name)); + if (strncmp("/dev/sd", blk_dev_arg, strlen(blk_dev_arg) + 1) == 0) + snprintf(blk_name, sizeof(blk_name)-1, "%s%d", blk_dev_arg, id); + else + snprintf(blk_name, sizeof(blk_name)-1, "%sp%d", blk_dev_arg, id); + s_part_info[j].ua_blk_name = strdup(blk_name); + } + } + fclose(fp); + } + + return 0; +} + +/*----------------------------------------------------------------------------- + fota_configure_update + ----------------------------------------------------------------------------*/ +int fota_configure_update(void) +{ + char cfg_data[MAX_CFG_LEN+1]; + int data_size = -1; + char* line = NULL; + char* field = NULL; + char* ctx1 = NULL; + char* ctx2 = NULL; + int line_num = 0; + int field_num = 0; + char* part_name = NULL; + char* subj_name = NULL; + int update_type = EXTRA; + int update_when = -1; + char *blk_name = NULL; + int blk_offset = 0; + int src_img_size = 0; + int trg_img_size = 0; + char *src_img_sha1 = NULL; + char *trg_img_sha1 = NULL; + memset((void*)cfg_data, 0x00, sizeof(cfg_data)); + + data_size = tar_get_cfg_data(delta_path, UPDATTE_CFG_FILE, cfg_data, MAX_CFG_LEN); + if (data_size <= 0) { + LOG("tar_get_cfg_data() fail\n"); + return -1; + } + cfg_data[data_size] = '\0'; + + line_num = 0; + line = strtok_r(cfg_data, "\n", &ctx1); + while (line) { + part_name = NULL; + subj_name = NULL; + update_type = EXTRA; + blk_name = NULL; + blk_offset = 0; + src_img_size = 0; + trg_img_size = 0; + src_img_sha1 = NULL; + trg_img_sha1 = NULL; + + field_num = 0; + field = strtok_r(line, "\t", &ctx2); + while (field) { + switch (field_num) { + case 0: + part_name = strdup(field); + break; + case 1: + subj_name = strdup(field); + break; + case 2: + update_type = get_update_type(field); + update_when = get_update_when(field); + if (update_when < 0) { + LOG("unknown update type: %s", field); + return -1; + } + break; + case 3: + blk_name = strdup(field); + break; + case 4: + blk_offset = atoi(field); + break; + case 5: + src_img_size = atoi(field); + break; + case 6: + trg_img_size = atoi(field); + break; + case 7: + src_img_sha1 = strdup(field); + break; + case 8: + trg_img_sha1 = strdup(field); + break; + } + field_num++; + LOG("%s,", field); + field = strtok_r(NULL, "\t", &ctx2); + } + LOG("\n"); + + if (!part_name) + return -1; + + if ((update_type != EXTRA) || (0 == strcmp(part_name, "RAMDISK2"))) { + s_part_info[line_num].ua_parti_name = part_name; + s_part_info[line_num].ua_subject_name = subj_name; + s_part_info[line_num].ua_blk_name = blk_name; + s_part_info[line_num].ua_blk_offset = blk_offset; + + s_update_cfg[line_num].update_type = update_type; + s_update_cfg[line_num].update_when = update_when; + s_update_cfg[line_num].soure_img_size = src_img_size; + s_update_cfg[line_num].target_img_size = trg_img_size; + s_update_cfg[line_num].soure_sha1 = src_img_sha1; + s_update_cfg[line_num].target_sha1 = trg_img_sha1; + + line_num++; + } else { + if (part_name) free(part_name); + if (subj_name) free(subj_name); + if (blk_name) free(blk_name); + if (src_img_sha1) free(src_img_sha1); + if (trg_img_sha1) free(trg_img_sha1); + } + line = strtok_r(NULL, "\n", &ctx1); + } + + LOG("Effective cfg line num = %d\n", line_num); + + return line_num; +} + +/*----------------------------------------------------------------------------- + main + + argv[1] : directory path for delta file + argv[2] : directory path for log file, result file, temp file + argv[3] : operation mode ("0" or none : Foreground Mode, "1" : Background Mode) + argv[4] : "a" or "b" upgrade slot number. This is optional parameter. + When it's set ua will not read hardcoded partitions numbers from config file. + Ua will use libblkid to determine it based on partition label e.g. rootfs_a which is rootfs from a slot. + argv[5]: path for blkid device e.g. /dev/mmcblk0 + + ----------------------------------------------------------------------------*/ +int main(int argc, char **argv) +{ + char ver_str[MAX_PATH]; + int ret = FAIL; + int i = 0; + + log_init(); + +#if defined(FEATURE_SUPPORT_CAPABILITY) + SS_set_feature_support_capability(1); +#endif + + /* check whether FG mode or BG mode */ + if (check_ua_op_mode(argc, argv) < 0) { + ret = UPI_INVALID_PARAM_ERROR; + goto Results; + } + + memset(delta_folder, 0x00, sizeof(delta_folder)); + snprintf(delta_folder, sizeof(delta_folder)-1, "%s", argv[1]); + snprintf(delta_path, sizeof(delta_path)-1, "%s/%s", delta_folder, DEFAULT_DELTA_NAME); + + memset(temp_folder, 0x00, sizeof(temp_folder)); + snprintf(temp_folder, sizeof(temp_folder)-1, "%s", argv[2]); + + memset(log_folder, 0x00, sizeof(log_folder)); + snprintf(log_folder, sizeof(log_folder)-1, "%s", SYSTEM_LOG_DIR); + + memcpy(result_folder, temp_folder, sizeof(result_folder)); + + snprintf(fota_result, sizeof(fota_result), "%s/%s", result_folder, "result"); + + fota_cfg_str_load(); + + if (check_dm_verity_status() < 0) { + LOG("check_dm_verity_status fail\n"); + ret = UPI_CONFIG_ERROR; + goto Results; + } + + /* Check fota folder path */ + if (check_existence(delta_folder) == 0) { + ret = UPI_DELTA_PATH_ERROR; + goto Results; + } + + /* load update configuration */ + ret = fota_configure_update(); + if (ret > 0) { + s_part_num = ret; + } else { + LOG("Update Configuration fail.\n"); + ret = UPI_CONFIG_ERROR; + goto Results; + } + + /* load block device number at run-time */ + ret = fota_blkid_update(); + if (ret < 0) { + LOG("fota_blkid_update() fail\n"); + ret = UPI_PARTINFO_ERROR; + goto Results; + } + + ret = fota_path_init(); + if (ret == FAIL) { + ret = UPI_DELTA_PATH_LENGTH_ERROR; + goto Results; + } + + LOG("<<<<<<<<<<< log_init >>>>>>>>>>>>\n"); + + /* UPI version check */ + if (S_SS_SUCCESS == SS_GetUPIVersion((unsigned char*)ver_str)) { + LOG("<<<<<<<<< TOTA Update Agent %s >>>>>>>>>>>>\n", ver_str); + } else { + LOG("[SS_GetUPIVersion fail] \n"); + ret = UPI_VERSION_ERROR; + goto Results; + } + /* Main Update Routine : Scout & Update */ + ret = update_all(); + LOG("[update_all ret=%d]\n", ret); + + Results: + LOG("Result=%d\n", ret); + save_result(ret); + //remove_temp_files(); // TOTA + if (ret != SUCCESS) + print_error_code(ret); + + switch (ret) { + /* Before initialize fota path */ + case UPI_INVALID_PARAM_ERROR: + case UPI_DELTA_PATH_ERROR: + case UPI_CONFIG_ERROR: + case UPI_PARTINFO_ERROR: + case UPI_DELTA_PATH_LENGTH_ERROR: + log_deinit(); + _exit_stdio(); + return -1; + /* After initialize fota path */ + case UPI_VERSION_ERROR: + case UPI_DELTACOUNT_ERROR: + case UPI_VERIFY_ERROR: + case UPI_UPDATE_ERROR: + fota_path_deinit(); + log_deinit(); + _exit_stdio(); + return -1; + case SUCCESS: + fota_path_deinit(); + log_deinit(); + /* Preserve log file for debugging */ + //truncate_log_file(log_path, 0); + _exit_stdio(); + return 0; + default: + LOG("!!! Not expected ret (= %d)\n", ret); + } + + for(i = 0; i < s_part_num; i++) { + if(s_part_info[i].ua_parti_name) free(s_part_info[i].ua_parti_name); + if(s_part_info[i].ua_subject_name) free(s_part_info[i].ua_subject_name); + if(s_part_info[i].ua_blk_name) free(s_part_info[i].ua_blk_name); + if(s_update_cfg[i].soure_sha1) free(s_update_cfg[i].soure_sha1); + if(s_update_cfg[i].target_sha1) free(s_update_cfg[i].target_sha1); + } + + _exit_stdio(); + return -1; +} diff --git a/src/delta-ua/ua.h b/src/delta-ua/ua.h new file mode 100755 index 0000000..a9cc34b --- /dev/null +++ b/src/delta-ua/ua.h @@ -0,0 +1,90 @@ +/* + * tota-ua + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __UA_H__ +#define __UA_H__ + +#include + +/* + * FEATURE + */ + +//#define USE_POST_UPDATE +//#define USE_DELTA_DOWNLOAD +//#define USE_DUALSBL + +#define LOG_FILE_PATH "/opt/data/update/last_update.log" +#define MAX_FILE_PATH 512 +#define MAX_FOLDER_PATH 384 + +#define PART_TBL_FILE "part_tbl.txt" +#define MAX_PART_TBL_ITEM 50 + +/* + * FOTA Adaptaion header + */ + +#define ERROR -1 // 0XFFFFFFFF + +#define INVALID 0 +#define VALID 1 +#define TRUE 1 +#define FALSE 0 +#define OK 0 +#define SUCCESS 0 +#define FAIL 1 +#define RESTORING 2 + +#define UPI_ERROR(code) 0xFD##code + +#define UPI_CONFIG_ERROR UPI_ERROR(9A) + +#define UPI_DELTA_PATH_ERROR UPI_ERROR(AA) +#define UPI_DELTA_PATH_LENGTH_ERROR UPI_ERROR(AB) + +#define UPI_VERSION_ERROR UPI_ERROR(BB) + +#define UPI_VERIFY_ERROR UPI_ERROR(C0) +#define UPI_UPDATE_ERROR UPI_ERROR(D0) + +#define UPI_INVALID_PARAM_ERROR UPI_ERROR(EA) +#define UPI_DELTACOUNT_ERROR UPI_ERROR(EC) +#define UPI_PARTINFO_ERROR UPI_ERROR(ED) + +#define TEMP_SIZE 0x40000 + +#define DEFAULT_DELTA_NAME "delta.tar" +#define UPDATTE_CFG_FILE "update.cfg" + +#define UP_STATUS_FILE "UP.STATUS" +#define UP_START_NONE 0 + +enum { + UA_OP_MODE_FG = 0, + UA_OP_MODE_BG +}; + +enum { + DM_VERITY_DISABLED = 0, + DM_VERITY_ENABLED = 1 +}; + +void log_deinit(void); + +#endif