* Copyright (c) Huawei Technologies Co., Ltd. 2020-2023. All rights reserved.
* Licensed under the Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
* PURPOSE.
* See the Mulan PSL v2 for more details.
*/
#include "fs_work_agent.h"
#include <errno.h>
#include <sys/types.h>
#include <fcntl.h>
#include <limits.h>
#include <sys/ioctl.h>
#include <time.h>
#include <pthread.h>
#include <dirent.h>
#include <sys/statfs.h>
#include <sys/resource.h>
#include <securec.h>
#include <libgen.h>
#include <mntent.h>
#include "tc_ns_client.h"
#include "tee_log.h"
#include "tee_ca_daemon.h"
#include "tee_agent.h"
#ifdef LOG_TAG
#undef LOG_TAG
#endif
#define LOG_TAG "teecd_agent"
#define USEC_PER_SEC 1000000ULL
#define USEC_PER_MSEC 1000ULL
#define NSEC_PER_USEC 1000ULL
#define FSCMD_TIMEOUT_US (1 * USEC_PER_SEC)
static int32_t CopyFile(const char *fromPath, const char *toPath);
static uint32_t g_userId;
static uint32_t g_storageId;
static int g_fsAgentFd = -1;
static struct SecStorageType *g_fsAgentControl = NULL;
static pthread_t g_fsThread = ULONG_MAX;
int GetFsAgentFd(void)
{
return g_fsAgentFd;
}
void *GetFsAgentControl(void)
{
return g_fsAgentControl;
}
int FsAgentInit(void)
{
int ret;
uint32_t bufferSize = TRANS_BUFF_SIZE;
uint32_t check_ccos = 0;
#ifdef CONFIG_AGENTD
int fd = open(TC_NS_CVM_DEV_NAME, O_RDWR);
#else
int fd = open(TC_TEECD_PRIVATE_DEV_NAME, O_RDWR);
#endif
if (fd < 0) {
tloge("open tee client dev failed, fd is %d\n", fd);
return -1;
}
ret = ioctl(fd, TC_NS_CLIENT_IOCTL_CHECK_CCOS, &check_ccos);
if (ret == 0 && check_ccos != 0) {
bufferSize = FS_TRANS_BUFF_SIZE_CCOS;
}
(void)close(fd);
g_fsAgentFd = AgentInit(AGENT_FS_ID, bufferSize, (void **)(&g_fsAgentControl));
if (g_fsAgentFd < 0) {
tloge("fs agent init failed\n");
return -1;
}
return 0;
}
void FsAgentThreadCreate(void)
{
SetFileNumLimit();
(void)pthread_create(&g_fsThread, NULL, FsWorkThread, g_fsAgentControl);
}
void FsAgentThreadJoin(void)
{
(void)pthread_join(g_fsThread, NULL);
}
void FsAgentExit(void)
{
if (g_fsAgentFd >= 0) {
AgentExit(AGENT_FS_ID, g_fsAgentFd);
g_fsAgentFd = -1;
g_fsAgentControl = NULL;
}
}
static void SetCurrentUserId(uint32_t id)
{
g_userId = id;
}
static uint32_t GetCurrentUserId(void)
{
return g_userId;
}
static void SetCurrentStorageId(uint32_t id)
{
g_storageId = id;
}
static uint32_t GetCurrentStorageId(void)
{
return g_storageId;
}
static struct OpenedFile *g_firstFile = NULL;
static int32_t AddOpenFile(FILE *pFile)
{
struct OpenedFile *newFile = malloc(sizeof(struct OpenedFile));
if (newFile == NULL) {
tloge("malloc OpenedFile failed\n");
return -1;
}
newFile->file = pFile;
if (g_firstFile == NULL) {
g_firstFile = newFile;
newFile->next = newFile;
newFile->prev = newFile;
} else {
if (g_firstFile->prev == NULL) {
tloge("the tail is null\n");
free(newFile);
return -1;
}
g_firstFile->prev->next = newFile;
newFile->prev = g_firstFile->prev;
newFile->next = g_firstFile;
g_firstFile->prev = newFile;
}
return 0;
}
static void DelOpenFile(struct OpenedFile *file)
{
struct OpenedFile *next = NULL;
if (file == NULL) {
return;
}
next = file->next;
if (file == next) {
g_firstFile = NULL;
} else {
if (file->next == NULL || file->prev == NULL) {
tloge("the next or the prev is null\n");
return;
}
if (file == g_firstFile) {
g_firstFile = file->next;
}
next->prev = file->prev;
file->prev->next = next;
}
}
static int32_t FindOpenFile(int32_t fd, struct OpenedFile **file)
{
struct OpenedFile *p = g_firstFile;
int32_t findFlag = 0;
if (p == NULL) {
return findFlag;
}
do {
if (p->file != NULL) {
if (fileno(p->file) == fd) {
findFlag = 1;
break;
}
}
p = p->next;
} while (p != g_firstFile && p != NULL);
if (findFlag == 0) {
p = NULL;
}
if (file != NULL) {
*file = p;
}
return findFlag;
}
* path:file or dir to change own
* flag: 0(dir);1(file)
*/
static void ChownSecStorageDataToSystem(const char *path, bool flag)
{
if (path == NULL) {
return;
}
* check path is SEC_STORAGE_ROOT_DIR or SEC_STORAGE_DATA_DIR,
* we only need to change SEC_STORAGE_DATA_DIR from root to system
*/
if (strstr(path, "sec_storage_data") != NULL) {
int32_t ret;
if (flag) {
ret = chmod(path, S_IRUSR | S_IWUSR);
} else {
ret = chmod(path, S_IRUSR | S_IWUSR | S_IXUSR);
}
if (ret < 0) {
tloge("chmod error\n");
}
}
}
static int32_t CheckPathLen(const char *path, size_t pathLen)
{
uint32_t i = 0;
while (i < pathLen && path[i] != '\0') {
i++;
}
if (i >= pathLen) {
tloge("path is too long\n");
return -1;
}
return 0;
}
* path:file path name.
* e.g. sec_storage_data/app1/sub1/fileA.txt
* then CreateDir will make dir sec_storage_data, app1 and sub1.
*/
static int32_t CreateDir(const char *path, size_t pathLen)
{
int32_t ret;
ret = CheckPathLen(path, pathLen);
if (ret != 0) {
return -1;
}
char *pathTemp = strdup(path);
char *position = pathTemp;
if (pathTemp == NULL) {
tloge("strdup error\n");
return -1;
}
if (strncmp(pathTemp, "/", strlen("/")) == 0) {
position++;
} else if (strncmp(pathTemp, "./", strlen("./")) == 0) {
position += strlen("./");
}
for (; *position != '\0'; ++position) {
if (*position == '/') {
*position = '\0';
if (access(pathTemp, F_OK) == 0) {
*position = '/';
continue;
}
if (mkdir(pathTemp, ROOT_DIR_PERM) != 0) {
tloge("mkdir fail\n");
free(pathTemp);
return -1;
}
ChownSecStorageDataToSystem(pathTemp, false);
*position = '/';
}
}
free(pathTemp);
return 0;
}
static int32_t CheckFileNameAndPath(const char *name, const char *path)
{
if (name == NULL || path == NULL) {
return -1;
}
if (strstr(name, FILE_NAME_INVALID_STR) != NULL) {
tloge("Invalid file name\n");
return -1;
}
return 0;
}
static int32_t GetPathStorage(char *path, size_t pathLen, const char *env)
{
errno_t rc;
const char *defaultPath = NULL;
if (strncmp(env, "SFS_PARTITION_TRANSIENT", strlen("SFS_PARTITION_TRANSIENT")) == 0) {
defaultPath = USER_DATA_DIR;
} else if (strncmp(env, "SFS_PARTITION_PERSISTENT", strlen("SFS_PARTITION_PERSISTENT")) == 0) {
defaultPath = ROOT_DIR;
} else {
return -1;
}
rc = strncpy_s(path, pathLen, defaultPath, strlen(defaultPath) + 1);
if (rc != EOK) {
tloge("strncpy_s failed %d\n", rc);
return -1;
}
return 0;
}
static int32_t GetTransientDir(char* path, size_t pathLen)
{
return GetPathStorage(path, pathLen, "SFS_PARTITION_TRANSIENT");
}
static int32_t GetPersistentDir(char* path, size_t pathLen)
{
return GetPathStorage(path, pathLen, "SFS_PARTITION_PERSISTENT");
}
#define USER_PATH_SIZE 12
static int32_t JoinFileNameTransient(const char *name, char *path, size_t pathLen)
{
errno_t rc;
int32_t ret;
uint32_t userId = GetCurrentUserId();
ret = GetTransientDir(path, pathLen);
if (ret != 0) {
return ret;
}
if (userId != 0) {
char userPath[USER_PATH_SIZE] = { 0 };
rc = snprintf_s(userPath, sizeof(userPath), sizeof(userPath) - 1, "%u/", userId);
if (rc == -1) {
tloge("snprintf_s failed %d\n", rc);
return -1;
}
rc = strncat_s(path, pathLen, SFS_PARTITION_USER_SYMLINK, strlen(SFS_PARTITION_USER_SYMLINK));
if (rc != EOK) {
tloge("strncat_s failed %d\n", rc);
return -1;
}
rc = strncat_s(path, pathLen, userPath, strlen(userPath));
if (rc != EOK) {
tloge("strncat_s failed %d\n", rc);
return -1;
}
if (strlen(name) <= strlen(SFS_PARTITION_TRANSIENT)) {
tloge("name length is too small\n");
return -1;
}
rc = strncat_s(path, pathLen, name + strlen(SFS_PARTITION_TRANSIENT),
(strlen(name) - strlen(SFS_PARTITION_TRANSIENT)));
if (rc != EOK) {
tloge("strncat_s failed %d\n", rc);
return -1;
}
} else {
rc = strncat_s(path, pathLen, name, strlen(name));
if (rc != EOK) {
tloge("strncat_s failed %d\n", rc);
return -1;
}
}
return 0;
}
static int32_t GetDefaultDir(char *path, size_t pathLen)
{
errno_t rc;
int32_t ret;
ret = GetPersistentDir(path, pathLen);
if (ret != 0) {
return ret;
}
rc = strncat_s(path, pathLen, SFS_PARTITION_PERSISTENT, strlen(SFS_PARTITION_PERSISTENT));
if (rc != EOK) {
tloge("strncat_s failed %d\n", rc);
return -1;
}
return 0;
}
static int32_t DoJoinFileName(const char *name, char *path, size_t pathLen)
{
errno_t rc;
int32_t ret;
if (name == strstr(name, SFS_PARTITION_TRANSIENT_PERSO) || name == strstr(name, SFS_PARTITION_TRANSIENT_PRIVATE)) {
ret = GetTransientDir(path, pathLen);
} else if (name == strstr(name, SFS_PARTITION_PERSISTENT)) {
ret = GetPersistentDir(path, pathLen);
} else {
ret = GetDefaultDir(path, pathLen);
}
if (ret != 0) {
tloge("get dir failed %d\n", ret);
return -1;
}
rc = strncat_s(path, pathLen, name, strlen(name));
if (rc != EOK) {
tloge("strncat_s failed %d\n", rc);
return -1;
}
return 0;
}
static int32_t JoinFileNameForStorageCE(const char *name, char *path, size_t pathLen)
{
errno_t rc;
char temp[FILE_NAME_MAX_BUF] = { '\0' };
char *nameTemp = temp;
char *nameWithoutUserId = NULL;
char *idString = NULL;
rc = memcpy_s(nameTemp, FILE_NAME_MAX_BUF, name, strlen(name));
if (rc != EOK) {
tloge("copy failed");
return -1;
}
idString = strtok_r(nameTemp, ROOT_DIR, &nameWithoutUserId);
if (idString == NULL) {
tloge("the name %s does not match th rule as userid/xxx\n", name);
return -1;
}
rc = strncpy_s(path, pathLen, SEC_STORAGE_DATA_CE, sizeof(SEC_STORAGE_DATA_CE));
if (rc != EOK) {
tloge("strncpy_s failed %d\n", rc);
return -1;
}
rc = strncat_s(path, pathLen, idString, strlen(idString));
if (rc != EOK) {
tloge("strncat_s failed %d\n", rc);
return -1;
}
rc = strncat_s(path, pathLen, SEC_STORAGE_DATA_ROOT_DIR, sizeof(SEC_STORAGE_DATA_ROOT_DIR));
if (rc != EOK) {
tloge("strncat_s failed %d\n", rc);
return -1;
}
rc = strncat_s(path, pathLen, nameWithoutUserId, strlen(nameWithoutUserId));
if (rc != EOK) {
tloge("strncat_s failed %d\n", rc);
return -1;
}
return 0;
}
static int32_t JoinFileName(const char *name, bool isBackup, char *path, size_t pathLen)
{
int32_t ret = -1;
uint32_t storageId = GetCurrentStorageId();
if (CheckFileNameAndPath(name, path) != 0) {
return ret;
}
if (storageId == TEE_OBJECT_STORAGE_CE) {
ret = JoinFileNameForStorageCE(name, path, pathLen);
} else {
* If the path name does not start with sec_storage or sec_storage_data,
* add sec_storage str for the path
*/
if (name == strstr(name, SFS_PARTITION_TRANSIENT)) {
ret = JoinFileNameTransient(name, path, pathLen);
} else {
ret = DoJoinFileName(name, path, pathLen);
}
}
tlogv("joined path done\n");
(void)isBackup;
return ret;
}
static bool IsDataDir(const char *path, bool isUsers)
{
char secDataDir[FILE_NAME_MAX_BUF] = { 0 };
int32_t ret;
errno_t rc;
ret = GetTransientDir(secDataDir, FILE_NAME_MAX_BUF);
if (ret != 0) {
return false;
}
if (isUsers) {
rc = strncat_s(secDataDir, FILE_NAME_MAX_BUF, SFS_PARTITION_USER_SYMLINK, strlen(SFS_PARTITION_USER_SYMLINK));
} else {
rc = strncat_s(secDataDir, FILE_NAME_MAX_BUF, SFS_PARTITION_TRANSIENT, strlen(SFS_PARTITION_TRANSIENT));
}
if (rc != EOK) {
return false;
}
if (path == strstr(path, secDataDir)) {
return true;
}
return false;
}
static bool IsRootDir(const char *path)
{
char secRootDir[FILE_NAME_MAX_BUF] = { 0 };
int32_t ret;
errno_t rc;
ret = GetPersistentDir(secRootDir, FILE_NAME_MAX_BUF);
if (ret != 0) {
return false;
}
rc = strncat_s(secRootDir, FILE_NAME_MAX_BUF, SFS_PARTITION_PERSISTENT, strlen(SFS_PARTITION_PERSISTENT));
if (rc != EOK) {
return false;
}
if (path == strstr(path, secRootDir)) {
return true;
}
return false;
}
static bool IsValidFilePath(const char *path)
{
if (strstr(path, "..") != NULL) {
tloge("filename should not include .. dir\n");
return false;
}
if (IsDataDir(path, false) || IsDataDir(path, true) || IsRootDir(path) ||
(path == strstr(path, SEC_STORAGE_DATA_CE))) {
return true;
}
tloge("path is invalid\n");
return false;
}
static uint32_t GetRealFilePath(const char *originPath, char *trustPath, size_t tPathLen)
{
char *retPath = realpath(originPath, trustPath);
if (retPath == NULL) {
if ((errno != ENOENT) && (errno != EACCES)) {
tloge("get realpath failed: %d\n", errno);
return (uint32_t)errno;
}
if (!IsValidFilePath(originPath)) {
tloge("origin path is invalid\n");
return ENFILE;
}
errno_t rc = strncpy_s(trustPath, tPathLen, originPath, strlen(originPath));
if (rc != EOK) {
tloge("strncpy_s failed %d\n", rc);
return EPERM;
}
} else {
if (!IsValidFilePath(trustPath)) {
tloge("path is invalid\n");
return ENFILE;
}
}
return 0;
}
static int32_t UnlinkRecursive(const char *name);
static int32_t UnlinkRecursiveDir(const char *name)
{
bool fail = false;
char dn[PATH_MAX] = { 0 };
errno_t rc;
DIR *dir = opendir(name);
if (dir == NULL) {
tloge("dir open failed\n");
return -1;
}
errno = 0;
struct dirent *de = readdir(dir);
while (de != NULL) {
if (strncmp(de->d_name, "..", sizeof("..")) == 0 || strncmp(de->d_name, ".", sizeof(".")) == 0) {
de = readdir(dir);
continue;
}
rc = snprintf_s(dn, sizeof(dn), sizeof(dn) - 1, "%s/%s", name, de->d_name);
if (rc == -1) {
tloge("snprintf_s failed %d\n", rc);
fail = true;
break;
}
if (UnlinkRecursive(dn) < 0) {
tloge("loop UnlinkRecursive() failed, there are read-only file\n");
fail = true;
break;
}
errno = 0;
de = readdir(dir);
}
if (fail || errno < 0) {
int32_t save = errno;
closedir(dir);
errno = save;
tloge("fail is %d, errno is %d\n", fail, errno);
return -1;
}
if (closedir(dir) < 0) {
tloge("closedir failed, errno is %d\n", errno);
return -1;
}
if (rmdir(name) < 0) {
tloge("rmdir failed, errno is %d\n", errno);
return -1;
}
return 0;
}
static int32_t UnlinkRecursive(const char *name)
{
struct stat st;
if (lstat(name, &st) < 0) {
tloge("lstat failed, errno is %x\n", errno);
return -1;
}
if (!S_ISDIR(st.st_mode)) {
if (unlink(name) < 0) {
tloge("unlink failed, errno is %d\n", errno);
return -1;
}
return 0;
}
return UnlinkRecursiveDir(name);
}
static int32_t IsFileExist(const char *name)
{
struct stat statbuf;
if (name == NULL) {
tloge("Invalid file name\n");
return 0;
}
if (stat(name, &statbuf) != 0) {
if (errno == ENOENT) {
return 0;
}
}
return 1;
}
static uint32_t DoOpenFile(const char *path, struct SecStorageType *transControl)
{
char trustPath[PATH_MAX] = { 0 };
uint32_t rRet = GetRealFilePath(path, trustPath, sizeof(trustPath));
if (rRet != 0) {
tloge("get real path failed. err=%u\n", rRet);
return rRet;
}
FILE *pFile = fopen(trustPath, transControl->args.open.mode);
if (pFile == NULL) {
tloge("open file with flag %s failed: %d\n", transControl->args.open.mode, errno);
return (uint32_t)errno;
}
ChownSecStorageDataToSystem(trustPath, true);
int32_t ret = AddOpenFile(pFile);
if (ret != 0) {
tloge("add OpenedFile failed\n");
(void)fclose(pFile);
return ENOMEM;
}
transControl->ret = fileno(pFile);
return 0;
}
static int32_t CheckPartitionReady(const char *mntDir)
{
(void)mntDir;
return 1;
}
static inline uint64_t GetTimeStampUs(void)
{
struct timespec ts = { 0 };
(void)clock_gettime(CLOCK_MONOTONIC, &ts);
return ts.tv_sec * USEC_PER_SEC + ts.tv_nsec / NSEC_PER_USEC;
}
static int CheckOpenWorkValid(struct SecStorageType *transControl, bool isBackup, char *nameBuff, size_t nameLen)
{
int ret = 0;
if (transControl->cmd == SEC_CREATE) {
errno_t rc = strncpy_s(transControl->args.open.mode,
sizeof(transControl->args.open.mode), "w+", sizeof("w+"));
if (rc != EOK) {
tloge("strncpy_s failed %d\n", rc);
ret = ENOENT;
}
} else {
if (IsFileExist(nameBuff) == 0) {
ret = ENOENT;
}
}
(void)isBackup;
(void)nameLen;
return ret;
}
static void OpenWork(struct SecStorageType *transControl)
{
uint32_t error;
char nameBuff[FILE_NAME_MAX_BUF] = { 0 };
bool isBackup = false;
SetCurrentUserId(transControl->userId);
SetCurrentStorageId(transControl->storageId);
tlogv("sec storage : open\n");
if (strstr((char *)(transControl->args.open.name), SFS_PARTITION_PERSISTENT) != NULL) {
if (CheckPartitionReady("/sec_storage") <= 0) {
tloge("check /sec_storage partition_ready failed ----------->\n");
transControl->ret = -1;
return;
}
}
if (JoinFileName((char *)(transControl->args.open.name), isBackup, nameBuff, sizeof(nameBuff)) != 0) {
transControl->ret = -1;
return;
}
if (CheckOpenWorkValid(transControl, isBackup, nameBuff, sizeof(nameBuff)) != 0) {
error = ENOENT;
goto ERROR;
}
if (CreateDir(nameBuff, sizeof(nameBuff)) != 0) {
error = (uint32_t)errno;
goto ERROR;
}
error = DoOpenFile(nameBuff, transControl);
if (error != 0) {
goto ERROR;
}
return;
ERROR:
transControl->ret = -1;
transControl->error = error;
return;
}
static void CloseWork(struct SecStorageType *transControl)
{
int32_t ret;
struct OpenedFile *selFile = NULL;
tlogv("sec storage : close\n");
if (FindOpenFile(transControl->args.close.fd, &selFile) != 0) {
ret = fclose(selFile->file);
if (ret == 0) {
tlogv("close file %d success\n", transControl->args.close.fd);
DelOpenFile(selFile);
free(selFile);
selFile = NULL;
(void)selFile;
} else {
tloge("close file %d failed: %d\n", transControl->args.close.fd, errno);
transControl->error = (uint32_t)errno;
}
transControl->ret = ret;
} else {
tloge("can't find opened file(fileno = %d)\n", transControl->args.close.fd);
transControl->ret = -1;
transControl->error = EBADF;
}
}
static void ReadWork(struct SecStorageType *transControl)
{
struct OpenedFile *selFile = NULL;
size_t count;
tlogv("sec storage : read count = %u\n", transControl->args.read.count);
if (FindOpenFile(transControl->args.read.fd, &selFile) != 0) {
count = fread((void *)(transControl->args.read.buffer), 1, transControl->args.read.count, selFile->file);
transControl->ret = (int32_t)count;
if (count < transControl->args.read.count) {
if (feof(selFile->file) != 0) {
transControl->ret2 = 0;
tlogv("read end of file\n");
} else {
transControl->ret2 = -1;
transControl->error = (uint32_t)errno;
tloge("read file failed: %d\n", errno);
}
} else {
transControl->ret2 = 0;
tlogv("read file success, content len=%zu\n", count);
}
} else {
transControl->ret = 0;
transControl->ret2 = -1;
transControl->error = EBADF;
tloge("can't find opened file(fileno = %d)\n", transControl->args.read.fd);
}
}
static void WriteWork(struct SecStorageType *transControl)
{
struct OpenedFile *selFile = NULL;
size_t count;
tlogv("sec storage : write count = %u\n", transControl->args.write.count);
if (FindOpenFile(transControl->args.write.fd, &selFile) != 0) {
count = fwrite((void *)(transControl->args.write.buffer), 1, transControl->args.write.count, selFile->file);
if (count < transControl->args.write.count) {
tloge("write file failed: %d\n", errno);
transControl->ret = (int32_t)count;
transControl->error = (uint32_t)errno;
return;
}
if (transControl->ret2 == SEC_WRITE_SSA) {
if (fflush(selFile->file) != 0) {
tloge("fflush file failed: %d\n", errno);
transControl->ret = 0;
transControl->error = (uint32_t)errno;
} else {
transControl->ret = (int32_t)count;
}
} else {
transControl->ret = (int32_t)count;
transControl->error = 0;
}
} else {
tloge("can't find opened file(fileno = %d)\n", transControl->args.write.fd);
transControl->ret = 0;
transControl->error = EBADF;
}
}
static void SeekWork(struct SecStorageType *transControl)
{
int32_t ret;
struct OpenedFile *selFile = NULL;
tlogv("sec storage : seek offset=%d, whence=%u\n", transControl->args.seek.offset, transControl->args.seek.whence);
if (FindOpenFile(transControl->args.seek.fd, &selFile) != 0) {
ret = fseek(selFile->file, transControl->args.seek.offset, (int32_t)transControl->args.seek.whence);
if (ret != 0) {
tloge("seek file failed: %d\n", errno);
transControl->error = (uint32_t)errno;
} else {
tlogv("seek file success\n");
}
transControl->ret = ret;
} else {
tloge("can't find opened file(fileno = %d)\n", transControl->args.seek.fd);
transControl->ret = -1;
transControl->error = EBADF;
}
}
static void RemoveWork(struct SecStorageType *transControl)
{
int32_t ret;
char nameBuff[FILE_NAME_MAX_BUF] = { 0 };
bool isBackup = false;
tlogv("sec storage : remove\n");
SetCurrentUserId(transControl->userId);
SetCurrentStorageId(transControl->storageId);
if (JoinFileName((char *)(transControl->args.remove.name), isBackup, nameBuff, sizeof(nameBuff)) == 0) {
ret = UnlinkRecursive(nameBuff);
if (ret != 0) {
tloge("remove file failed: %d\n", errno);
transControl->error = (uint32_t)errno;
} else {
tlogv("remove file success\n");
}
transControl->ret = ret;
} else {
transControl->ret = -1;
}
}
static void TruncateWork(struct SecStorageType *transControl)
{
int32_t ret;
char nameBuff[FILE_NAME_MAX_BUF] = { 0 };
bool isBackup = false;
tlogv("sec storage : truncate, len=%u\n", transControl->args.truncate.len);
SetCurrentUserId(transControl->userId);
SetCurrentStorageId(transControl->storageId);
if (JoinFileName((char *)(transControl->args.truncate.name), isBackup, nameBuff, sizeof(nameBuff)) == 0) {
ret = truncate(nameBuff, (long)transControl->args.truncate.len);
if (ret != 0) {
tloge("truncate file failed: %d\n", errno);
transControl->error = (uint32_t)errno;
} else {
tlogv("truncate file success\n");
}
transControl->ret = ret;
} else {
transControl->ret = -1;
}
}
static void RenameWork(struct SecStorageType *transControl)
{
int32_t ret;
char nameBuff[FILE_NAME_MAX_BUF] = { 0 };
char nameBuff2[FILE_NAME_MAX_BUF] = { 0 };
bool oldIsBackup = false;
bool newIsBackup = false;
SetCurrentUserId(transControl->userId);
SetCurrentStorageId(transControl->storageId);
int32_t joinOldRet = JoinFileName((char *)(transControl->args.rename.buffer), oldIsBackup,
nameBuff, sizeof(nameBuff));
int32_t joinNewRet = JoinFileName((char *)(transControl->args.rename.buffer) + transControl->args.rename.oldNameLen,
newIsBackup, nameBuff2, sizeof(nameBuff2));
if (joinOldRet == 0 && joinNewRet == 0) {
ret = rename(nameBuff, nameBuff2);
if (ret != 0) {
tloge("rename file failed: %d\n", errno);
transControl->error = (uint32_t)errno;
} else {
tlogv("rename file success\n");
}
transControl->ret = ret;
} else {
transControl->ret = -1;
}
}
#define MAXBSIZE 65536
static int32_t DoCopy(int32_t fromFd, int32_t toFd)
{
int32_t ret;
ssize_t rcount;
ssize_t wcount;
char *buf = (char *)malloc(MAXBSIZE * sizeof(char));
if (buf == NULL) {
tloge("malloc buf failed\n");
return -1;
}
rcount = read(fromFd, buf, MAXBSIZE);
while (rcount > 0) {
wcount = write(toFd, buf, (size_t)rcount);
if (rcount != wcount || wcount == -1) {
tloge("write file failed: %d\n", errno);
ret = -1;
goto OUT;
}
rcount = read(fromFd, buf, MAXBSIZE);
}
if (rcount < 0) {
tloge("read file failed: %d\n", errno);
ret = -1;
goto OUT;
}
ret = fsync(toFd);
if (ret != 0) {
tloge("CopyFile:fsync file failed: %d\n", errno);
goto OUT;
}
OUT:
free(buf);
return ret;
}
static int32_t CopyFile(const char *fromPath, const char *toPath)
{
struct stat fromStat;
char realFromPath[PATH_MAX] = { 0 };
char realToPath[PATH_MAX] = { 0 };
uint32_t rRet = GetRealFilePath(fromPath, realFromPath, sizeof(realFromPath));
if (rRet != 0) {
tloge("get real from path failed. err=%u\n", rRet);
return -1;
}
rRet = GetRealFilePath(toPath, realToPath, sizeof(realToPath));
if (rRet != 0) {
tloge("get real to path failed. err=%u\n", rRet);
return -1;
}
int32_t fromFd = open(realFromPath, O_RDONLY, 0);
if (fromFd == -1) {
tloge("open from_file failed: %d\n", errno);
return -1;
}
int32_t ret = fstat(fromFd, &fromStat);
if (ret == -1) {
tloge("stat file failed: %d\n", errno);
close(fromFd);
return ret;
}
int32_t toFd = open(realToPath, O_WRONLY | O_TRUNC | O_CREAT, fromStat.st_mode);
if (toFd == -1) {
tloge("open to_file failed: %d\n", errno);
close(fromFd);
return -1;
}
ret = DoCopy(fromFd, toFd);
if (ret != 0) {
tloge("do copy failed\n");
} else {
ChownSecStorageDataToSystem((char *)realToPath, true);
}
close(fromFd);
close(toFd);
return ret;
}
static void CopyWork(struct SecStorageType *transControl)
{
int32_t ret;
char fromPath[FILE_NAME_MAX_BUF] = { 0 };
char toPath[FILE_NAME_MAX_BUF] = { 0 };
bool fromIsBackup = false;
bool toIsBackup = false;
SetCurrentUserId(transControl->userId);
SetCurrentStorageId(transControl->storageId);
char *fromName = (char *)(transControl->args.cp.buffer);
char *toName = (char *)transControl->args.cp.buffer + transControl->args.cp.fromPathLen;
int32_t joinFromRet = JoinFileName(fromName, fromIsBackup, fromPath, sizeof(fromPath));
int32_t joinToRet = JoinFileName(toName, toIsBackup, toPath, sizeof(toPath));
if (joinFromRet == 0 && joinToRet == 0) {
ret = CopyFile(fromPath, toPath);
if (ret != 0) {
tloge("copy file failed: %d\n", errno);
transControl->error = (uint32_t)errno;
} else {
tlogv("copy file success\n");
}
transControl->ret = ret;
} else {
transControl->ret = -1;
}
}
static void FileInfoWork(struct SecStorageType *transControl)
{
int32_t ret;
struct OpenedFile *selFile = NULL;
struct stat statBuff;
tlogv("sec storage : file info\n");
transControl->args.info.fileLen = transControl->args.info.curPos = 0;
if (FindOpenFile(transControl->args.info.fd, &selFile) != 0) {
ret = fstat(transControl->args.info.fd, &statBuff);
if (ret == 0) {
transControl->args.info.fileLen = (uint32_t)statBuff.st_size;
transControl->args.info.curPos = (uint32_t)ftell(selFile->file);
} else {
tloge("fstat file failed: %d\n", errno);
transControl->error = (uint32_t)errno;
}
transControl->ret = ret;
} else {
transControl->ret = -1;
transControl->error = EBADF;
}
}
static void FileAccessWork(struct SecStorageType *transControl)
{
int32_t ret;
char nameBuff[FILE_NAME_MAX_BUF] = { 0 };
bool isBackup = false;
tlogv("sec storage : file access\n");
if (transControl->cmd == SEC_ACCESS) {
SetCurrentUserId(transControl->userId);
SetCurrentStorageId(transControl->storageId);
if (JoinFileName((char *)(transControl->args.access.name), isBackup, nameBuff, sizeof(nameBuff)) == 0) {
ret = access(nameBuff, transControl->args.access.mode);
if (ret < 0) {
tlogw("access file mode %d failed: %d\n", transControl->args.access.mode, errno);
}
transControl->ret = ret;
transControl->error = (uint32_t)errno;
} else {
transControl->ret = -1;
}
} else {
ret = access((char *)(transControl->args.access.name), transControl->args.access.mode);
if (ret < 0) {
tlogw("access2 file mode %d failed: %d\n", transControl->args.access.mode, errno);
}
transControl->ret = ret;
transControl->error = (uint32_t)errno;
}
}
static void FsyncWork(struct SecStorageType *transControl)
{
int32_t ret;
int32_t fd = -1;
struct OpenedFile *selFile = NULL;
tlogv("sec storage : file fsync\n");
if (transControl->args.fsync.fd != 0 && FindOpenFile(transControl->args.fsync.fd, &selFile) != 0) {
ret = fflush(selFile->file);
if (ret != 0) {
tloge("fsync:fflush file failed: %d\n", errno);
transControl->ret = -1;
transControl->error = (uint32_t)errno;
return;
}
fd = fileno(selFile->file);
ret = fsync(fd);
if (ret != 0) {
tloge("fsync:fsync file failed: %d\n", errno);
transControl->ret = -1;
transControl->error = (uint32_t)errno;
return;
}
transControl->ret = 0;
tlogv("fsync file(%d) success\n", transControl->args.fsync.fd);
} else {
tloge("can't find opened file(fileno = %d)\n", transControl->args.fsync.fd);
transControl->ret = -1;
transControl->error = EBADF;
}
}
#define KBYTE 1024
static void DiskUsageWork(struct SecStorageType *transControl)
{
struct statfs st;
uint32_t dataRemain;
uint32_t secStorageRemain;
char nameBuff[FILE_NAME_MAX_BUF] = { 0 };
tlogv("sec storage : disk usage\n");
if (GetTransientDir(nameBuff, FILE_NAME_MAX_BUF) != 0) {
goto ERROR;
}
if (statfs((const char*)nameBuff, &st) < 0) {
tloge("statfs /secStorageData failed, err=%d\n", errno);
goto ERROR;
}
dataRemain = (uint32_t)st.f_bfree * (uint32_t)st.f_bsize / KBYTE;
if (GetPersistentDir(nameBuff, FILE_NAME_MAX_BUF) != 0) {
tloge("get persistent dir error.\n");
goto ERROR;
}
if (strncat_s(nameBuff, FILE_NAME_MAX_BUF, SFS_PARTITION_PERSISTENT, strlen(SFS_PARTITION_PERSISTENT)) != EOK) {
tloge("strncat_s error.\n");
goto ERROR;
}
if (statfs((const char*)nameBuff, &st) < 0) {
tloge("statfs /secStorage failed, err=%d\n", errno);
goto ERROR;
}
secStorageRemain = (uint32_t)st.f_bfree * (uint32_t)st.f_bsize / KBYTE;
transControl->ret = 0;
transControl->args.diskUsage.data = dataRemain;
transControl->args.diskUsage.secStorage = secStorageRemain;
return;
ERROR:
transControl->ret = -1;
transControl->error = (uint32_t)errno;
}
static void DeleteAllWork(struct SecStorageType *transControl)
{
int32_t ret;
char path[FILE_NAME_MAX_BUF] = { 0 };
char *pathIn = (char *)(transControl->args.deleteAll.path);
SetCurrentUserId(transControl->userId);
tlogv("sec storage : delete path, userid:%d\n", transControl->userId);
ret = DoJoinFileName(pathIn, path, sizeof(path));
if (ret != EOK) {
tloge("join name failed %d\n", ret);
transControl->ret = -1;
return;
}
tlogv("sec storage : joint delete path\n");
ret = UnlinkRecursive(path);
if (ret != 0) {
tloge("delete file failed: %d\n", errno);
transControl->error = (uint32_t)errno;
} else {
tloge("delete file success\n");
}
transControl->ret = ret;
}
typedef void (*FsWorkFunc)(struct SecStorageType *transControl);
struct FsWorkTbl {
enum FsCmdType cmd;
FsWorkFunc fn;
};
static const struct FsWorkTbl g_fsWorkTbl[] = {
{ SEC_OPEN, OpenWork }, { SEC_CLOSE, CloseWork },
{ SEC_READ, ReadWork }, { SEC_WRITE, WriteWork },
{ SEC_SEEK, SeekWork }, { SEC_REMOVE, RemoveWork },
{ SEC_TRUNCATE, TruncateWork }, { SEC_RENAME, RenameWork },
{ SEC_CREATE, OpenWork }, { SEC_INFO, FileInfoWork },
{ SEC_ACCESS, FileAccessWork }, { SEC_ACCESS2, FileAccessWork },
{ SEC_FSYNC, FsyncWork }, { SEC_CP, CopyWork },
{ SEC_DISKUSAGE, DiskUsageWork }, { SEC_DELETE_ALL, DeleteAllWork },
};
void *FsWorkThread(void *control)
{
struct SecStorageType *transControl = NULL;
int32_t ret;
int32_t fsFd;
if (control == NULL) {
return NULL;
}
transControl = control;
fsFd = g_fsAgentFd;
if (fsFd == -1) {
tloge("fs is not open\n");
return NULL;
}
uint64_t tsStart, tsEnd;
transControl->magic = AGENT_FS_ID;
while (1) {
ret = ioctl(fsFd, TC_NS_CLIENT_IOCTL_WAIT_EVENT, AGENT_FS_ID);
if (ret != 0) {
tloge("fs agent wait event failed\n");
break;
}
tsStart = GetTimeStampUs();
if ((transControl->cmd < SEC_MAX) && (g_fsWorkTbl[transControl->cmd].fn != NULL)) {
g_fsWorkTbl[transControl->cmd].fn(transControl);
} else {
tloge("fs agent error cmd:transControl->cmd=%x\n", transControl->cmd);
}
tsEnd = GetTimeStampUs();
if (tsEnd - tsStart > FSCMD_TIMEOUT_US) {
tlogw("fs agent timeout, cmd=0x%x, cost=%llums\n",
transControl->cmd, (tsEnd - tsStart) / USEC_PER_MSEC);
}
__asm__ volatile("isb");
__asm__ volatile("dsb sy");
transControl->magic = AGENT_FS_ID;
__asm__ volatile("isb");
__asm__ volatile("dsb sy");
ret = ioctl(fsFd, TC_NS_CLIENT_IOCTL_SEND_EVENT_RESPONSE, AGENT_FS_ID);
if (ret != 0) {
tloge("fs agent send response failed\n");
break;
}
tlogv("-- fs agent loop --\n");
}
return NULL;
}
void SetFileNumLimit(void)
{
struct rlimit rlim, rlimNew;
int32_t rRet = getrlimit(RLIMIT_NOFILE, &rlim);
if (rRet == 0) {
rlimNew.rlim_cur = rlimNew.rlim_max = FILE_NUM_LIMIT_MAX;
if (setrlimit(RLIMIT_NOFILE, &rlimNew) != 0) {
rlimNew.rlim_cur = rlimNew.rlim_max = rlim.rlim_max;
(void)setrlimit(RLIMIT_NOFILE, &rlimNew);
}
} else {
tloge("getrlimit error is 0x%x, errno is %x", rRet, errno);
}
}