diff --git a/service/hnp/base/hnp_base.h b/service/hnp/base/hnp_base.h index f296384ba5e88dda58cd4f1b5bbd0b63213856f8..37fc3ad91b0776a9ed2079c99bb67375cdade106 100644 --- a/service/hnp/base/hnp_base.h +++ b/service/hnp/base/hnp_base.h @@ -55,6 +55,10 @@ extern "C" { #define HNP_PACKAGE_INFO_JSON_FILE_PATH "/data/service/el1/startup/hnp_info.json" #define HNP_ELF_FILE_CHECK_HEAD_LEN 4 +#define HAP_PACKAGE_INFO_HAP_PREFIX "hap" +#define HAP_PACKAGE_INFO_HNP_PREFIX "hnp" +#define HAP_PACKAGE_INFO_NAME_PREFIX "name" + #ifdef _WIN32 #define DIR_SPLIT_SYMBOL '\\' #else @@ -262,6 +266,9 @@ enum { // 0x801120 二进制文件过多 #define HNP_ERRNO_BASE_FILE_COUNT_OVER HNP_ERRNO_COMMON(HNP_MID_BASE, 0x20) +// 0x801121 软连接覆盖校验失败 +#define HNP_ERRNO_SYMLINK_CHECK_FAILED HNP_ERRNO_COMMON(HNP_MID_BASE, 0x21) + int GetFileSizeByHandle(FILE *file, int *size); int ReadFileToStream(const char *filePath, char **stream, int *streamLen); @@ -279,7 +286,9 @@ void HnpLogPrintf(int logLevel, char *module, const char *format, ...); int HnpCfgGetFromZip(const char *inputFile, HnpCfgInfo *hnpCfg); -int HnpSymlink(const char *srcFile, const char *dstFile); +bool CanRecovery(const char *hnpPackageName, HnpCfgInfo *hnpcfgInfo); + +int HnpSymlink(const char *srcFile, const char *dstFile, HnpCfgInfo *hnpCfg, bool canRecovery, bool isPublic); int HnpProcessRunCheck(const char *runPath); @@ -343,6 +352,11 @@ char *HnpCurrentVersionGet(const char *name); } \ } while (0) +#define HNP_ONLY_EXPER(ret, exper) \ + if ((ret)) { \ + exper; \ + } + #ifdef __cplusplus } #endif diff --git a/service/hnp/base/hnp_json.c b/service/hnp/base/hnp_json.c index 6ce5bef22e60db5b2119864a77358f3d89ab35e9..dc9b04f3ebb52696d75f6a2442718ed6dfab6a5f 100644 --- a/service/hnp/base/hnp_json.c +++ b/service/hnp/base/hnp_json.c @@ -451,6 +451,52 @@ static int HnpPackageJsonGet(cJSON **pJson) return 0; } +/** + * 读取配置文件 仅当未安装过对应hnp或者当前hap与之前安装者一致 方可覆盖 + */ +bool CanRecovery(const char *hnpPackageName, HnpCfgInfo *hnpCfg) +{ + cJSON *json = NULL; + + int ret = HnpPackageJsonGet(&json); + HNP_ERROR_CHECK(ret == 0, return false, "Get Package Json failed"); + HNP_INFO_CHECK(json != NULL, return true, "No Config, ingore"); + HNP_INFO_CHECK(cJSON_IsArray(json), cJSON_Delete(json); + return false, "Config file structed damaged"); + + // 默认可以覆盖 + bool canRecovery = true; + cJSON *hapItem = NULL; + cJSON *hapJson = NULL; + + for (int i = 0; i < cJSON_GetArraySize(json); i++) { + hapItem = cJSON_GetArrayItem(json, i); + hapJson = cJSON_GetObjectItem(hapItem, HAP_PACKAGE_INFO_HAP_PREFIX); + HNP_ERROR_CHECK(hapJson != NULL && cJSON_IsString(hapJson), continue, + "invalid hap info"); + cJSON *hnpItemArr = cJSON_GetObjectItem(hapItem, HAP_PACKAGE_INFO_HNP_PREFIX); + HNP_ERROR_CHECK(hnpItemArr != NULL && cJSON_IsArray(hnpItemArr), continue, + "invalid hnp info"); + for (int j = 0; j < cJSON_GetArraySize(hnpItemArr); j++) { + cJSON *hnpItem = cJSON_GetArrayItem(hnpItemArr, j); + cJSON *name = cJSON_GetObjectItem(hnpItem, HAP_PACKAGE_INFO_NAME_PREFIX); + HNP_ERROR_CHECK(name != NULL && cJSON_IsString(name), continue, + "invalid name info"); + + HNP_ONLY_EXPER(strcmp(name->valuestring, hnpCfg->name) != 0, continue); + // 找到对应hnp的安装信息时 要求当前hap与安装hap包名一致 + canRecovery = false; + HNP_LOGI("Found hnp Info %{public}s %{public}s", hapJson->valuestring, hnpPackageName); + if (strcmp(hapJson->valuestring, hnpPackageName) == 0) { + cJSON_Delete(json); + return true; + } + } + } + cJSON_Delete(json); + return canRecovery; +} + int HnpPackageInfoGet(const char *packageName, HnpPackageInfo **packageInfoOut, int *count) { bool hnpExist = false; diff --git a/service/hnp/base/hnp_sal.c b/service/hnp/base/hnp_sal.c index ab0291750422a4c9698fb1ab023625cd56afd42a..e56474a2d58143c1648f0213816428a67e72dc93 100644 --- a/service/hnp/base/hnp_sal.c +++ b/service/hnp/base/hnp_sal.c @@ -53,6 +53,56 @@ int HnpProcessRunCheck(const char *runPath) return 0; } +static int CheckSymlink(HnpCfgInfo *hnpCfg, const char *linkPath) +{ + HNP_ERROR_CHECK(linkPath != NULL && hnpCfg != NULL && hnpCfg->name != NULL, + return HNP_ERRNO_SYMLINK_CHECK_FAILED, "invalid param"); + + // 软链不存在 允许覆盖 + struct stat statBuf; + HNP_INFO_CHECK(lstat(linkPath, &statBuf) == 0, return 0, + "softLink not exist, ignore check"); + + // 获取软链信息 + char targetPath[MAX_FILE_PATH_LEN] = {0}; + size_t bytes = readlink(linkPath, targetPath, MAX_FILE_PATH_LEN); + HNP_ERROR_CHECK(bytes > 0, return HNP_ERRNO_SYMLINK_CHECK_FAILED, + "readlink failed %{public}d %{public}zu %{public}s", errno, bytes, linkPath); + + // 获取软连接所在目录 + char linkCopy[MAX_FILE_PATH_LEN] = {0}; + bytes = snprintf_s(linkCopy, MAX_FILE_PATH_LEN, MAX_FILE_PATH_LEN - 1, + "%s", linkPath); + HNP_ERROR_CHECK(bytes > 0, return HNP_ERRNO_SYMLINK_CHECK_FAILED, + "copy link path failed %{public}d", errno); + const char *pos = strrchr(linkCopy, DIR_SPLIT_SYMBOL); + HNP_ERROR_CHECK(pos != NULL && pos - linkCopy < MAX_FILE_PATH_LEN - 1, + return HNP_ERRNO_SYMLINK_CHECK_FAILED, "invalid link"); + linkCopy[pos - linkCopy + 1] = '\0'; + + // 拼接源文件路径 + char sourcePath[MAX_FILE_PATH_LEN] = {0} ; + bytes = snprintf_s(sourcePath, MAX_FILE_PATH_LEN, MAX_FILE_PATH_LEN - 1, + "%s/%s", linkCopy, targetPath); + HNP_ERROR_CHECK(bytes > 0, return HNP_ERRNO_SYMLINK_CHECK_FAILED, + "Get Source file path failed"); + // 源文件不存在 允许覆盖 + HNP_ONLY_EXPER(access(sourcePath, F_OK) != 0, return 0); + + // 判断源文件所属hnp + char *target = targetPath; + while (strncmp(target, "../", strlen("../")) == 0) { + target += strlen("../"); + } + char *split = strstr(target, ".org/"); + HNP_ERROR_CHECK(split != NULL, return HNP_ERRNO_SYMLINK_CHECK_FAILED, + "invalid source file %{public}s", targetPath); + *split = '\0'; + + HNP_LOGI("CheckSymlink with oldHnp %{public}s now %{public}s", target, hnpCfg->name); + return strcmp(hnpCfg->name, target); +} + APPSPAWN_STATIC void HnpRelPath(const char *fromPath, const char *toPath, char *relPath) { char *from = strdup(fromPath); @@ -111,11 +161,17 @@ APPSPAWN_STATIC void HnpRelPath(const char *fromPath, const char *toPath, char * return; } -int HnpSymlink(const char *srcFile, const char *dstFile) +int HnpSymlink(const char *srcFile, const char *dstFile, HnpCfgInfo *hnpCfg, bool canRecovery, bool isPublic) { int ret; char relpath[MAX_FILE_PATH_LEN]; + if (isPublic) { + HNP_ERROR_CHECK(canRecovery, return HNP_ERRNO_SYMLINK_CHECK_FAILED, + "can't recovery this hnp: %{public}s softlink", dstFile); + HNP_ERROR_CHECK(CheckSymlink(hnpCfg, dstFile) == 0, return HNP_ERRNO_SYMLINK_CHECK_FAILED, + "checkSymlink failed"); + } (void)unlink(dstFile); HnpRelPath(dstFile, srcFile, relpath); diff --git a/service/hnp/installer/src/hnp_installer.c b/service/hnp/installer/src/hnp_installer.c index c9658e8aae680d445b27531447aa7d53a919e335..ac99483d543f2e4a429e955f7e6734f9b6b3c958 100644 --- a/service/hnp/installer/src/hnp_installer.c +++ b/service/hnp/installer/src/hnp_installer.c @@ -47,7 +47,8 @@ static int HnpInstallerUidGet(const char *uidIn, int *uidOut) return 0; } -static int HnpGenerateSoftLinkAllByJson(const char *installPath, const char *dstPath, HnpCfgInfo *hnpCfg) +static int HnpGenerateSoftLinkAllByJson(const char *installPath, const char *dstPath, HnpCfgInfo *hnpCfg, + bool canRecovery, bool isPublic) { char srcFile[MAX_FILE_PATH_LEN]; char dstFile[MAX_FILE_PATH_LEN]; @@ -87,15 +88,12 @@ static int HnpGenerateSoftLinkAllByJson(const char *installPath, const char *dst fileName++; } ret = sprintf_s(dstFile, MAX_FILE_PATH_LEN, "%s/%s", dstPath, fileName); - if (ret < 0) { - HNP_LOGE("sprintf install bin dst file unsuccess."); - return HNP_ERRNO_BASE_SPRINTF_FAILED; - } + HNP_ERROR_CHECK(ret > 0, return HNP_ERRNO_BASE_SPRINTF_FAILED, + "sprintf install bin dst file unsuccess."); + /* 生成软链接 */ - ret = HnpSymlink(srcFile, dstFile); - if (ret != 0) { - return ret; - } + ret = HnpSymlink(srcFile, dstFile, hnpCfg, canRecovery, isPublic); + HNP_ERROR_CHECK(ret == 0, return ret, "hnpSymlink failed"); currentLink++; } @@ -103,7 +101,8 @@ static int HnpGenerateSoftLinkAllByJson(const char *installPath, const char *dst return 0; } -static int HnpGenerateSoftLinkAll(const char *installPath, const char *dstPath) +static int HnpGenerateSoftLinkAll(const char *installPath, const char *dstPath, HnpCfgInfo *hnpCfg, + bool canRecovery, bool isPublic) { char srcPath[MAX_FILE_PATH_LEN]; char srcFile[MAX_FILE_PATH_LEN]; @@ -113,10 +112,8 @@ static int HnpGenerateSoftLinkAll(const char *installPath, const char *dstPath) struct dirent *entry; ret = sprintf_s(srcPath, MAX_FILE_PATH_LEN, "%s/bin", installPath); - if (ret < 0) { - HNP_LOGE("sprintf install bin path unsuccess."); - return HNP_ERRNO_BASE_SPRINTF_FAILED; - } + HNP_ERROR_CHECK(ret > 0, return HNP_ERRNO_BASE_SPRINTF_FAILED, + "sprintf install bin path unsuccess."); if ((dir = opendir(srcPath)) == NULL) { HNP_LOGI("soft link bin file:%{public}s not exist", srcPath); @@ -151,7 +148,7 @@ static int HnpGenerateSoftLinkAll(const char *installPath, const char *dstPath) return HNP_ERRNO_BASE_SPRINTF_FAILED; } /* 生成软链接 */ - ret = HnpSymlink(srcFile, dstFile); + ret = HnpSymlink(srcFile, dstFile, hnpCfg, canRecovery, isPublic); if (ret != 0) { closedir(dir); return ret; @@ -162,21 +159,24 @@ static int HnpGenerateSoftLinkAll(const char *installPath, const char *dstPath) return 0; } -static int HnpGenerateSoftLink(const char *installPath, const char *hnpBasePath, HnpCfgInfo *hnpCfg) +static int HnpGenerateSoftLink(HnpInstallInfo *hnpInfo, HnpCfgInfo *hnpCfg) { + HNP_ERROR_CHECK(hnpInfo != NULL, return HNP_ERRNO_BASE_PARAMS_INVALID, + "invalid hnpInfp"); + bool canRecovery = CanRecovery(hnpInfo->hapInstallInfo->hapPackageName, hnpCfg); int ret = 0; char binPath[MAX_FILE_PATH_LEN]; - ret = sprintf_s(binPath, MAX_FILE_PATH_LEN, "%s/bin", hnpBasePath); - if (ret < 0) { - HNP_LOGE("sprintf install bin path unsuccess."); - return HNP_ERRNO_BASE_SPRINTF_FAILED; - } + ret = sprintf_s(binPath, MAX_FILE_PATH_LEN, "%s/bin", hnpInfo->hnpBasePath); + HNP_ERROR_CHECK(ret > 0, return HNP_ERRNO_BASE_SPRINTF_FAILED, + "sprintf install bin path unsuccess."); if (hnpCfg->linkNum == 0) { - ret = HnpGenerateSoftLinkAll(installPath, binPath); + ret = HnpGenerateSoftLinkAll(hnpInfo->hnpVersionPath, binPath, hnpCfg, + canRecovery, hnpInfo->isPublic); } else { - ret = HnpGenerateSoftLinkAllByJson(installPath, binPath, hnpCfg); + ret = HnpGenerateSoftLinkAllByJson(hnpInfo->hnpVersionPath, binPath, hnpCfg, + canRecovery, hnpInfo->isPublic); } return ret; @@ -194,7 +194,7 @@ static int HnpInstall(const char *hnpFile, HnpInstallInfo *hnpInfo, HnpCfgInfo * } /* 生成软链 */ - return HnpGenerateSoftLink(hnpInfo->hnpVersionPath, hnpInfo->hnpBasePath, hnpCfg); + return HnpGenerateSoftLink(hnpInfo, hnpCfg); } /** @@ -476,14 +476,12 @@ static int HnpReadAndInstall(char *srcFile, HnpInstallInfo *hnpInfo, HnpSignMapI /* 存在对应版本的公有hnp包跳过安装 */ if (access(hnpInfo->hnpVersionPath, F_OK) == 0 && hnpInfo->isPublic) { /* 刷新软链 */ - ret = HnpGenerateSoftLink(hnpInfo->hnpVersionPath, hnpInfo->hnpBasePath, &hnpCfg); - if (ret != 0) { - return ret; - } + ret = HnpGenerateSoftLink(hnpInfo, &hnpCfg); + // 释放软链接占用的内存 - if (hnpCfg.links != NULL) { - free(hnpCfg.links); - } + HNP_ONLY_EXPER(hnpCfg.links != NULL, free(hnpCfg.links)); + HNP_ONLY_EXPER(ret != 0, return ret); + return HnpPublicDealAfterInstall(hnpInfo, &hnpCfg); } diff --git a/test/unittest/hnp_test/hnp_installer_test.cpp b/test/unittest/hnp_test/hnp_installer_test.cpp index d5c2a31140488d12d0531e2c1af9401bd0f9be21..7e5c0e3043e11aaa6249c949548be221e451cd34 100644 --- a/test/unittest/hnp_test/hnp_installer_test.cpp +++ b/test/unittest/hnp_test/hnp_installer_test.cpp @@ -840,7 +840,7 @@ static void HnpVersionV2Install() char* argv[] = {arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13}; int argc = sizeof(argv) / sizeof(argv[0]); // install v1 - EXPECT_EQ(HnpCmdInstall(argc, argv), 0); + EXPECT_EQ(HnpCmdInstall(argc, argv), HNP_ERRNO_SYMLINK_CHECK_FAILED); } static void HnpVersionV3Install() @@ -862,7 +862,7 @@ static void HnpVersionV3Install() char* argv[] = {arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13}; int argc = sizeof(argv) / sizeof(argv[0]); // install v1 - EXPECT_EQ(HnpCmdInstall(argc, argv), 0); + EXPECT_EQ(HnpCmdInstall(argc, argv), HNP_ERRNO_SYMLINK_CHECK_FAILED); } static void HnpVersionV4Install() @@ -884,7 +884,7 @@ static void HnpVersionV4Install() char* argv[] = {arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13}; int argc = sizeof(argv) / sizeof(argv[0]); // install v1 - EXPECT_EQ(HnpCmdInstall(argc, argv), 0); + EXPECT_EQ(HnpCmdInstall(argc, argv), HNP_ERRNO_SYMLINK_CHECK_FAILED); } static void HnpVersionV1Uninstall() @@ -991,43 +991,47 @@ HWTEST_F(HnpInstallerTest, Hnp_Install_010, TestSize.Level0) HnpVersionV3Install(); // check v1 v2 v3 exist EXPECT_EQ(access(HNP_BASE_PATH"/hnppublic/sample_public.org/sample_public_1", F_OK), 0); - EXPECT_EQ(access(HNP_BASE_PATH"/hnppublic/sample_public.org/sample_public_2", F_OK), 0); - EXPECT_EQ(access(HNP_BASE_PATH"/hnppublic/sample_public.org/sample_public_3", F_OK), 0); - EXPECT_EQ(HnpSymlinkCheck(HNP_BASE_PATH"/hnppublic/bin/out", "../sample_public.org/sample_public_3/bin/out"), true); + EXPECT_EQ(access(HNP_BASE_PATH"/hnppublic/sample_public.org/sample_public_2", F_OK), -1); + EXPECT_EQ(access(HNP_BASE_PATH"/hnppublic/sample_public.org/sample_public_3", F_OK), -1); + EXPECT_EQ(HnpSymlinkCheck(HNP_BASE_PATH"/hnppublic/bin/out", "../sample_public.org/sample_public_1/bin/out"), true); // uninstall v3 HnpVersionV3Uninstall(); // check v1 v2 v3 exist EXPECT_EQ(access(HNP_BASE_PATH"/hnppublic/sample_public.org/sample_public_1", F_OK), 0); - EXPECT_EQ(access(HNP_BASE_PATH"/hnppublic/sample_public.org/sample_public_2", F_OK), 0); - EXPECT_EQ(access(HNP_BASE_PATH"/hnppublic/sample_public.org/sample_public_3", F_OK), 0); - EXPECT_EQ(HnpSymlinkCheck(HNP_BASE_PATH"/hnppublic/bin/out", "../sample_public.org/sample_public_3/bin/out"), true); + EXPECT_EQ(access(HNP_BASE_PATH"/hnppublic/sample_public.org/sample_public_2", F_OK), -1); + EXPECT_EQ(access(HNP_BASE_PATH"/hnppublic/sample_public.org/sample_public_3", F_OK), -1); + EXPECT_EQ(HnpSymlinkCheck(HNP_BASE_PATH"/hnppublic/bin/out", + "../sample_public.org/sample_public_3/bin/out"), false); HnpVersionV4Install(); // check v1 v2 v4 exist v3 is uninstall EXPECT_EQ(access(HNP_BASE_PATH"/hnppublic/sample_public.org/sample_public_1", F_OK), 0); - EXPECT_EQ(access(HNP_BASE_PATH"/hnppublic/sample_public.org/sample_public_2", F_OK), 0); + EXPECT_EQ(access(HNP_BASE_PATH"/hnppublic/sample_public.org/sample_public_2", F_OK), -1); EXPECT_EQ(access(HNP_BASE_PATH"/hnppublic/sample_public.org/sample_public_3", F_OK), -1); - EXPECT_EQ(access(HNP_BASE_PATH"/hnppublic/sample_public.org/sample_public_4", F_OK), 0); - EXPECT_EQ(HnpSymlinkCheck(HNP_BASE_PATH"/hnppublic/bin/out", "../sample_public.org/sample_public_4/bin/out"), true); + EXPECT_EQ(access(HNP_BASE_PATH"/hnppublic/sample_public.org/sample_public_4", F_OK), -1); + EXPECT_EQ(HnpSymlinkCheck(HNP_BASE_PATH"/hnppublic/bin/out", + "../sample_public.org/sample_public_4/bin/out"), false); // uninstall v1 HnpVersionV1Uninstall(); // check v2 v4 exist v1 v3 is uninstall EXPECT_EQ(access(HNP_BASE_PATH"/hnppublic/sample_public.org/sample_public_1", F_OK), -1); - EXPECT_EQ(access(HNP_BASE_PATH"/hnppublic/sample_public.org/sample_public_2", F_OK), 0); + EXPECT_EQ(access(HNP_BASE_PATH"/hnppublic/sample_public.org/sample_public_2", F_OK), -1); EXPECT_EQ(access(HNP_BASE_PATH"/hnppublic/sample_public.org/sample_public_3", F_OK), -1); - EXPECT_EQ(access(HNP_BASE_PATH"/hnppublic/sample_public.org/sample_public_4", F_OK), 0); - EXPECT_EQ(HnpSymlinkCheck(HNP_BASE_PATH"/hnppublic/bin/out", "../sample_public.org/sample_public_4/bin/out"), true); + EXPECT_EQ(access(HNP_BASE_PATH"/hnppublic/sample_public.org/sample_public_4", F_OK), -1); + EXPECT_EQ(HnpSymlinkCheck(HNP_BASE_PATH"/hnppublic/bin/out", + "../sample_public.org/sample_public_4/bin/out"), false); // uninstall v4 HnpVersionV4Uninstall(); // check v2 v4 exist v1 v3 is uninstall EXPECT_EQ(access(HNP_BASE_PATH"/hnppublic/sample_public.org/sample_public_1", F_OK), -1); - EXPECT_EQ(access(HNP_BASE_PATH"/hnppublic/sample_public.org/sample_public_2", F_OK), 0); + EXPECT_EQ(access(HNP_BASE_PATH"/hnppublic/sample_public.org/sample_public_2", F_OK), -1); EXPECT_EQ(access(HNP_BASE_PATH"/hnppublic/sample_public.org/sample_public_3", F_OK), -1); - EXPECT_EQ(access(HNP_BASE_PATH"/hnppublic/sample_public.org/sample_public_4", F_OK), 0); - EXPECT_EQ(HnpSymlinkCheck(HNP_BASE_PATH"/hnppublic/bin/out", "../sample_public.org/sample_public_4/bin/out"), true); + EXPECT_EQ(access(HNP_BASE_PATH"/hnppublic/sample_public.org/sample_public_4", F_OK), -1); + EXPECT_EQ(HnpSymlinkCheck(HNP_BASE_PATH"/hnppublic/bin/out", + "../sample_public.org/sample_public_4/bin/out"), false); // uninstall v2 HnpVersionV2Uninstall();