--- /dev/null
+/*-
+ * 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 <string.h>
+#include <err.h>
+#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 <Alloc.h>
+#include <7zFile.h>
+#include <7zVersion.h>
+#include <LzmaDec.h>
+#include <LzmaEnc.h>
+
+
+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;
+
+}
--- /dev/null
+/*
+ * 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 <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+
+#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]);
+ }
+}
--- /dev/null
+/*
+ * 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 <RamSize>0x4000000</RamSize> in xml.
+#else
+#define UA_RAM_SIZE 512*1024*1024 // it sould be same <RamSize>0x20000000</RamSize> 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);
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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 <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/vfs.h>
+#include <sys/types.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/wait.h>
+
+#include <ftw.h>
+#include <sys/xattr.h>
+#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.<p>
+ *
+ * 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;
+}
--- /dev/null
+/*
+ * 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.<p>
+ *
+ * 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.<p>
+ *
+ * \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.<p>
+ *
+ * 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.<p>
+ *
+ * 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.<p>
+ *
+ * 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.<p>
+ *
+ * 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.<p>
+ *
+ * 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.<p>
+ *
+ * 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.<p>
+ *
+ * Must return an error if the file does not exist or is not a symbolic link.<p>
+ *
+ * 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.<p>
+ *
+ * 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.<p>
+ *
+ * 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.<p>
+ *
+ * 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
--- /dev/null
+/*
+ * 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 <errno.h>
+#include <libgen.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#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 "<digest>:<anything>". 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 "<tgt-file>.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 "<tgt-file>.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;
+}
--- /dev/null
+/*
+ * 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 <stdint.h>
+#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
--- /dev/null
+/*
+ * 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<stdio.h>
+#include<ctype.h>
+#include<stdlib.h>
+#include<string.h>
+#include<inttypes.h>
+#include <stdbool.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/statfs.h>
+#include <mntent.h>
+#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 : <location of script> <location of log file to be created> <pid of the calling process>
+ 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 :
+<CHANGE-TYPE>:<FILE-TYPE>:<OTHER-DETAILS...>
+************************************************************************
+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();
+}
--- /dev/null
+/*
+ * 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 <stdbool.h>
+
+#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_
--- /dev/null
+/*
+ * 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 <stdio.h>
+#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__ */
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#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();
+}
+
+
--- /dev/null
+/*
+ * 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 <stdio.h>
+
+/*
+ * 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__ */
--- /dev/null
+/*
+ * 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 <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#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?
+}
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*-
+ * 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 <stdbool.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <Alloc.h>
+#include <7zFile.h>
+#include <7zVersion.h>
+#include <LzmaDec.h>
+#include <LzmaEnc.h>
+
+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;
+}
--- /dev/null
+#ifndef _SS_BSPATCH_COMMON_H
+#define _SS_BSPATCH_COMMON_H 1
+
+#include <Alloc.h>
+#include <7zFile.h>
+#include <7zVersion.h>
+#include <LzmaDec.h>
+#include <LzmaEnc.h>
+
+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 */
--- /dev/null
+/*
+ * 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 <stdio.h>
+
+#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
--- /dev/null
+/*
+ * 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 <string.h>
+
+#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);
+}
+
--- /dev/null
+/*
+ * 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__ */
+
+
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+#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);
+}
+
--- /dev/null
+/*
+ * 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_ */
+
--- /dev/null
+/*
+ * 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 <assert.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/reboot.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <time.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <blkid/blkid.h>
+
+#include <hal/device/hal-board.h>
+
+#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>
+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
+
+<Firmware Update Package-Device Mismatch>
+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
+
+<Failed Firmware Update Package Validation>
+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 Not Acceptable>
+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)
+
+<Firmware update fails due to device out of memory>
+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;
+}
--- /dev/null
+/*
+ * 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 <stdio.h>
+
+/*
+ * 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