--- /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 500
+#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 <sys/smack.h>
+#include <sys/wait.h>
+
+#include <ftw.h>
+#include <sys/xattr.h>
+#include "SS_Common.h"
+
+#include "fota_common.h"
+#include "ua.h"
+
+/************************************************************
+ * 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)
+{
+ if (src == NULL) {
+ return;
+ }
+
+ strcpy(dest, src);
+}
+
+void SS_char_to_unicode(const char *src, char *dest)
+{
+ if (src == NULL) {
+ return;
+ }
+
+ strcpy(dest, src);
+}
+
+long SS_recursive_folder_creater(const char *path, const mode_t mode)
+{
+ int ret = 0;
+ int offset = 0;
+ char temppath[MAX_PATH] = { '\0' };
+
+ LOGL(LOG_SSENGINE, "path: %s\n", path);
+
+ if ((offset = strlen(path)) == 0) // For counting back until the '/' delimiter
+ return -1; //if from some reason we got to the end return error!!!.
+
+ while (path[offset] != '/') // get to the next '/' place
+ offset--;
+
+ strncpy(temppath, path, offset); // copy one depth below till and without the char '/'
+ LOGL(LOG_SSENGINE, " temppath: %s\n", temppath);
+ ret = mkdir(temppath, mode);
+ LOGL(LOG_SSENGINE, " mkdir result: %d errno: %d\n", ret, errno);
+
+ if (ret == 0 || ((ret == -1) && (errno == EEXIST))) {
+ return 0; //meaning the depth creation is success.
+ } else if ((ret == -1) && (errno == ENOENT)) {
+ if ((ret = SS_recursive_folder_creater(temppath, mode)) == 0);
+ ret = mkdir(temppath, mode);
+ return ret;
+ } else {
+ return -1;
+ }
+}
+
+long
+SS_CopyFile(void *pbUserData,
+ 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);
+ SS_unicode_to_char((const char *)strToPath, (char *)path2);
+
+ //LOGL(LOG_SSENGINE, "%s -> %s \n", path1, path2);
+
+ fd1 = open(path1, O_RDONLY);
+ if (fd1 < 0)
+ return E_SS_OPENFILE_ONLYR;
+ ret = SS_OpenFile(pbUserData, 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(void *pbUserData, const char *strPath)
+{
+ char path[MAX_PATH] = { '\0' };
+ int ret = 0;
+
+ SS_unicode_to_char((const char *)strPath, (char *)path);
+ //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(void *pbUserData, 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(void *pbUserData, const char *strPath)
+{
+
+ int ret = 0;
+ char path[MAX_PATH] = { '\0' };
+
+ SS_unicode_to_char((const char *)strPath, (char *)path);
+ //LOGL(LOG_REDBEND, "%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(void *pbUserData, const char *strPath)
+{
+ mode_t mode = 0;
+ int ret = 0;
+ char path[MAX_PATH] = { '\0' };
+
+ SS_unicode_to_char((const char *)strPath, (char *)path);
+ 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(void *pbUserData,
+ 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);
+
+ 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);
+
+ if (SS_CreateFolder(pbUserData, 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(void *pbUserData, 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(void *pbUserData, 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(void *pbUserData,
+ 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(void *pbUserData, 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);
+ SS_unicode_to_char(strToPath, (char *)path2);
+
+ 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]",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(NULL, 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]",errno);
+ return E_SS_WRITE_ERROR;
+ }
+ }
+ LOGL(LOG_INFO, "leaved path1:%s | path2:%s\n", path1, path2);
+ return S_SS_SUCCESS;
+}
+long SS_SyncFile(void *pbUserData, long wHandle)
+{
+ return (-1 == fsync(wHandle)) ? E_SS_FAILURE : S_SS_SUCCESS;
+}
+
+long
+SS_ReadFile(void *pbUserData,
+ 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", 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", 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(pbUserData, wHandle)))
+ return E_SS_READ_ERROR;
+
+#if 0
+ LOGL(LOG_DEBUG, "Bytes Read: %d\n", ret);
+#endif
+ return S_SS_SUCCESS;
+}
+
+long SS_GetFileSize(void *pbUserData, 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(void *pbUserData, char *pLinkName)
+{
+ int ret = 0;
+ char path[MAX_PATH] = { '\0' };
+ //enumFileType fileType = FT_REGULAR_FILE;
+
+
+ SS_unicode_to_char((const char *)pLinkName, (char *)path);
+
+ 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(void *pbUserData,
+ 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);
+ SS_unicode_to_char((const char *)pReferenceFileName, (char *)refpath);
+
+ 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);
+ SS_unicode_to_char((const char *)pReferenceFileName, (char *)refpath);
+
+ 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(pbUserData,sympath);
+ SS_Link(pbUserData, pLinkName, pReferenceFileName);
+ }
+ }
+ if (SS_VerifyLinkReference(pbUserData, 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(void *pbUserData,
+ 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);
+
+ 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);
+ }
+}
+
+/*!
+ *******************************************************************************
+ * 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: _redbend_ro_ for R/O files, _redbend_rw_ for R/W files
+ * \li Linux: _redbend_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 *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;
+#if defined(FEATURE_SUPPORT_CAPABILITY)
+ int has_cap = 0;
+ char cap_raw[100];
+ int cap_len;
+ /*ACL */
+ int has_acl = 0;
+ char acl_raw[256];
+ int acl_len;
+
+#endif
+ 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);
+
+ 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(tmpAttribs, attrDelim);
+
+ // Get FileMode
+ if (tp != NULL) {
+ smack_attr_pos += strlen(tp);
+ smack_attr_pos++;
+ setFileMode = strtol(tp, &endstr, 8);
+ tp = strtok(NULL, attrDelim);
+ }
+ // Get UserID
+ if (tp != NULL) {
+ smack_attr_pos += strlen(tp);
+ smack_attr_pos++;
+ setUserID = (uid_t) strtol(tp, &endstr, 10);
+ tp = strtok(NULL, attrDelim);
+ }
+ // Get GroupID
+ if (tp != NULL) {
+ smack_attr_pos += strlen(tp);
+ smack_attr_pos++;
+ setGroupID = (gid_t) strtol(tp, &endstr, 10);
+ }
+#if defined(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;
+ }
+
+ }
+
+#endif
+ // Get Smack value -> Set Smack value
+ if (*smack_attr_pos != '\0') {
+ smack_lsetlabel(setFilePath, NULL, SMACK_LABEL_ACCESS);
+ smack_lsetlabel(setFilePath, NULL, SMACK_LABEL_EXEC);
+ smack_lsetlabel(setFilePath, NULL, SMACK_LABEL_MMAP);
+ smack_lsetlabel(setFilePath, NULL, SMACK_LABEL_TRANSMUTE);
+
+ psmack = strstr(smack_attr_pos, "access=\"");
+ if(psmack) {
+ memset(tmpSmackAttribs, 0x0, sizeof(tmpSmackAttribs));
+ memcpy(tmpSmackAttribs, psmack, strlen(psmack));
+ smack_value = strtok(tmpSmackAttribs, "\"");
+ if (smack_value) {
+ smack_value = strtok(NULL, "\"");
+ //LOGL(LOG_SSENGINE, "[SMACK_LABEL_ACCESS] smack_value=%s\n", smack_value);
+ if(smack_value) {
+ ret = smack_lsetlabel(setFilePath, smack_value, SMACK_LABEL_ACCESS);
+ if (ret < 0)
+ LOGL(LOG_SSENGINE, "smack_lsetlabel() failed\n");
+ }
+ }
+ }
+ psmack = strstr(smack_attr_pos, "execute=\"");
+ if(psmack) {
+ memset(tmpSmackAttribs, 0x0, sizeof(tmpSmackAttribs));
+ memcpy(tmpSmackAttribs, psmack, strlen(psmack));
+ smack_value = strtok(tmpSmackAttribs, "\"");
+ if (smack_value) {
+ smack_value = strtok(NULL, "\"");
+ //LOGL(LOG_SSENGINE, "[SMACK_LABEL_EXEC] smack_value=%s\n", smack_value);
+ if(smack_value) {
+ ret = smack_lsetlabel(setFilePath, smack_value, SMACK_LABEL_EXEC);
+ if (ret < 0)
+ LOGL(LOG_SSENGINE, "smack_lsetlabel() failed\n");
+ }
+ }
+ }
+ psmack = strstr(smack_attr_pos, "mmap=\"");
+ if(psmack) {
+ memset(tmpSmackAttribs, 0x0, sizeof(tmpSmackAttribs));
+ memcpy(tmpSmackAttribs, psmack, strlen(psmack));
+ smack_value = strtok(tmpSmackAttribs, "\"");
+ if (smack_value) {
+ smack_value = strtok(NULL, "\"");
+ //LOGL(LOG_SSENGINE, "[SMACK_LABEL_MMAP] smack_value=%s\n", smack_value);
+ if(smack_value) {
+ ret = smack_lsetlabel(setFilePath, smack_value, SMACK_LABEL_MMAP);
+ if (ret < 0)
+ LOGL(LOG_SSENGINE, "smack_lsetlabel() failed\n");
+ }
+ }
+ }
+ psmack = strstr(smack_attr_pos, "transmute=\"");
+ if(psmack) {
+ memset(tmpSmackAttribs, 0x0, sizeof(tmpSmackAttribs));
+ memcpy(tmpSmackAttribs, psmack, strlen(psmack));
+ smack_value = strtok(tmpSmackAttribs, "\"");
+ if (smack_value) {
+ smack_value = strtok(NULL, "\"");
+ //LOGL(LOG_SSENGINE, "[SMACK_LABEL_TRANSMUTE] smack_value=%s\n", smack_value);
+ if(smack_value) {
+ if (strcasecmp(smack_value, "TRUE")==0) {
+ ret = smack_lsetlabel(setFilePath, "1", SMACK_LABEL_TRANSMUTE);
+ } else {
+ ret = smack_lsetlabel(setFilePath, "0", SMACK_LABEL_TRANSMUTE);
+ }
+ if (ret < 0)
+ LOGL(LOG_SSENGINE, "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 defined(FEATURE_SUPPORT_CAPABILITY)
+ if (has_cap) {
+ if (setxattr(setFilePath, "security.capability", (void*)cap_raw, cap_len, 0) < 0) {
+ LOGL(LOG_SSENGINE, "cap setxattr() failed: %s\n", strerror(errno));
+ }
+ }
+
+ if (has_acl) {
+ if (setxattr(setFilePath, "system.posix_acl_access", (void*)acl_raw, acl_len, 0) < 0) {
+ LOGL(LOG_SSENGINE, "Acl setxattr() failed: %s\n", strerror(errno));
+ }
+ //LOG("Acl setxattr() :")asfd
+ }
+#endif
+
+ //LOGL(LOG_SSENGINE, "%s SUCCESS\n", __func__);
+
+ return S_SS_SUCCESS;
+}
+
+
+long SS_CompareFileAttributes(void *pbUserData,
+ char *pFilePath,
+ unsigned char *pAdditionalAttribs,
+ unsigned long iAddiInfoSize)
+{
+ return S_SS_SUCCESS;
+}
+
+
+
+#define MAX_INT 0xefffffff
+
+/* vrm functions */
+long
+SS_GetAvailableFreeSpace(void *pbUserData, 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);
+ //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 = 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 *user)
+{
+ 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 *user)
+{
+ return UA_RAM_SIZE;
+}
+
+void* SS_RunProcess(void *pbUserData, int argc, char* argv[])
+{
+ 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_REDBEND//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;
+ }
+}
+
+
+