FFernwehwarning fix
b39f856c创建于 8 天前历史提交
/*
 * Copyright (c) Huawei Device Co., Ltd. 2026-2026. All rights reserved.
 * 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 "system_utils.h"

#include <algorithm>
#include <cctype>
#include <cmath>
#include <ctime>
#include <fstream>
#include <limits>
#include <filesystem>
#include <regex>
#include <sstream>
#include <sys/stat.h>
#include "file_uri.h"

#include "application_context.h"
#include "hilog_object_editor.h"

namespace OHOS {
namespace ObjectEditor {
namespace SystemUtils {

namespace {
constexpr int32_t HOURS_OF_ONE_DAY = 24;
constexpr int32_t BEIJING_TIME_ZONE = 8;
constexpr int32_t NUMBER_BASE = 10;
constexpr int32_t TIME_FORMAT_SIZE = 64;
constexpr const char* FILE_MANAGER_AUTHORITY = "docs";
constexpr const char* MEDIA_AUTHORITY = "media";
} // namespace

std::string GetRealPath(const std::string &path)
{
    if (path.empty()) {
        OBJECT_EDITOR_LOGE(ObjectEditorDomain::COMMON, "path is empty");
        return "";
    }
    char resolvedPath[PATH_MAX] = {0};
    if (realpath(path.c_str(), resolvedPath) == nullptr) {
        OBJECT_EDITOR_LOGE(ObjectEditorDomain::COMMON, "realpath failed, path: %{private}s, errno: %{public}d",
            path.c_str(), errno);
        return "";
    }
    size_t len = strnlen(resolvedPath, PATH_MAX);
    if (len == 0 || len >= PATH_MAX) {
        OBJECT_EDITOR_LOGE(ObjectEditorDomain::COMMON, "realpath result invalid, len: %{public}zu", len);
        return "";
    }
    return std::string(resolvedPath, len);
}

// LCOV_EXCL_START
uint64_t GetFileSize(const std::string &filePath)
{
    if (filePath.empty() ||
        filePath.find("..") != std::string::npos ||
        filePath.find("~") != std::string::npos ||
        filePath.find("\\") != std::string::npos ||
        filePath.find("/") == 0) {
        OBJECT_EDITOR_LOGE(ObjectEditorDomain::COMMON, "File path is invalid");
        return 0;
    }
    uint64_t fileSize = 0;
    struct stat statbuf;
    if (stat(filePath.c_str(), &statbuf) == 0) {
        fileSize = static_cast<uint64_t>(statbuf.st_size);
    } else {
        OBJECT_EDITOR_LOGE(ObjectEditorDomain::COMMON, "Get file size failed, errno: %{public}d", errno);
    }
    return fileSize;
}

std::string ReadFile(const std::string &filePath)
{
    std::string canonicalFilePath;
    if (!SystemUtils::ValidateAndNormalizePath(filePath, canonicalFilePath)) {
        OBJECT_EDITOR_LOGE(ObjectEditorDomain::COMMON, "Failed to validate and normalize path");
        return "";
    }
    std::ifstream in(canonicalFilePath, std::ios::in | std::ios::binary);
    if (!in.is_open()) {
        OBJECT_EDITOR_LOGE(ObjectEditorDomain::COMMON, "Open file failed, path: %{private}s",
            canonicalFilePath.c_str());
        return "";
    }
    std::stringstream inStr;
    inStr << in.rdbuf();
    in.close();
    return inStr.str();
}

std::vector<std::string> SplitString(const std::string &str, char pattern)
{
    std::stringstream iss(str);
    std::vector<std::string> result;
    std::string token;
    while (getline(iss, token, pattern)) {
        result.emplace_back(token);
    }
    return result;
}

void TrimString(std::string &inputStr)
{
    if (inputStr.empty()) {
        return;
    }
    inputStr.erase(inputStr.begin(), std::find_if(inputStr.begin(), inputStr.end(),
        [](unsigned char ch) {return !std::isspace(ch); }));
    inputStr.erase(std::find_if(inputStr.rbegin(), inputStr.rend(),
        [](unsigned char ch) {return !std::isspace(ch); }).base(), inputStr.end());
}

bool StringToULong(const char *input, unsigned long &num)
{
    if (input == nullptr) {
        return false;
    }
    char *endPtr = nullptr;
    unsigned long result = 0;
    errno = 0;
    result = strtoul(input, &endPtr, NUMBER_BASE);
    if (errno == ERANGE || endPtr == input || *endPtr != '\0') {
        return false;
    }
    num = result;
    return true;
}

bool StringToLong(const char *input, long &num)
{
    if (input == nullptr) {
        return false;
    }
    char *endPtr = nullptr;
    long result = 0;
    errno = 0;
    result = strtol(input, &endPtr, NUMBER_BASE);
    if (errno == ERANGE || endPtr == input || *endPtr != '\0') {
        return false;
    }
    num = result;
    return true;
}

bool StringToFloat(const char *input, float &num)
{
    if (input == nullptr) {
        return false;
    }
    char *endPtr = nullptr;
    errno = 0;
    float result = strtof(input, &endPtr);
    if (endPtr == input || errno == ERANGE || *endPtr != '\0') {
        OBJECT_EDITOR_LOGE(ObjectEditorDomain::COMMON, "strtof failed, errno: %{public}d, input: %{private}s",
            errno, input);
        return false;
    }
    if (!std::isfinite(result)) {
        OBJECT_EDITOR_LOGE(ObjectEditorDomain::COMMON, "strtof result is not finite, input: %{private}s", input);
        return false;
    }
    num = result;
    return true;
}

bool StringToInt(const char *input, int &num)
{
    if (input == nullptr) {
        return false;
    }
    long numLong = 0;
    bool ret = StringToLong(input, numLong);
    if (!ret) {
        OBJECT_EDITOR_LOGE(ObjectEditorDomain::COMMON, "StringToLong failed, input: %{private}s", input);
        return false;
    }
    if (numLong < INT_MIN || numLong > INT_MAX) {
        OBJECT_EDITOR_LOGE(ObjectEditorDomain::COMMON, "StringToInt failed, input: %{private}s", input);
        return false;
    }
    num = static_cast<int>(numLong);
    return true;
}

bool HasSQLWildcard(const std::string &str)
{
    return str.find('%') != std::string::npos || str.find('_') != std::string::npos;
}

bool IsValidFileExt(const std::string &fileExt)
{
    return std::all_of(fileExt.begin(), fileExt.end(), [](char ch) {
        return std::isalnum(ch) || ch == '.';
    });
}

bool FileExtsHasFileExt(const std::string &fileExts, const std::string &fileExt)
{
    if (fileExts.empty()) {
        return false;
    }
    std::vector<std::string> extList = SplitString(fileExts, '|');
    if (std::find(extList.begin(), extList.end(), fileExt) != extList.end()) {
        return true;
    }
    return false;
}

std::string UTCToBeijingTime(int64_t utcTime)
{
    if (utcTime == 0) {
        return "";
    }
    time_t timeValue = static_cast<time_t>(utcTime);
    tm *timePtr = gmtime(&timeValue);
    if (timePtr == nullptr) {
        OBJECT_EDITOR_LOGE(ObjectEditorDomain::COMMON, "gmtime failed, utcTime: %{private}s", ctime(&timeValue));
        return "";
    }
    timePtr->tm_hour += BEIJING_TIME_ZONE;
    if (timePtr->tm_hour >= HOURS_OF_ONE_DAY) {
        timePtr->tm_hour -= HOURS_OF_ONE_DAY;
        timePtr->tm_mday++;
    }
    char buffer[TIME_FORMAT_SIZE] = {0x00};
    if (strftime(buffer, TIME_FORMAT_SIZE, "%Y-%m-%d %H:%M:%S", timePtr) == 0) {
        OBJECT_EDITOR_LOGE(ObjectEditorDomain::COMMON, "strftime failed, utcTime: %{private}s", ctime(&timeValue));
        return "";
    }
    return std::string(buffer);
}

std::string GetFileSuffix(const std::string &filePath)
{
    if (filePath.empty()) {
        return "";
    }
    size_t dotPos = filePath.find_last_of('.');
    if (dotPos == std::string::npos) {
        return "";
    }
    std::string fileType = filePath.substr(dotPos);
    if (fileType.empty()) {
        return "";
    }
    std::transform(fileType.begin(), fileType.end(),
        fileType.begin(), [](char c) { return static_cast<char>(std::tolower(c)); });
    return fileType;
}

std::string GetUriFromPath(const std::string &path)
{
    AppFileService::ModuleFileUri::FileUri fileUri(path);
    return fileUri.ToString();
}

std::string GetPathFromUri(const std::string &uri)
{
    return AppFileService::ModuleFileUri::FileUri(uri).GetRealPath();
}

bool IsAppSandboxPath(const std::string &path)
{
    Uri uri(SystemUtils::GetUriFromPath(path));
    std::string authority = uri.GetAuthority();
    return authority != FILE_MANAGER_AUTHORITY && authority != MEDIA_AUTHORITY;
}

std::string GetSubstrByPrefix(const std::string &str, const std::string &prefix)
{
    size_t pos = str.find(prefix);
    if ((pos == std::string::npos) || (pos == str.size() - prefix.size())) {
        OBJECT_EDITOR_LOGE(ObjectEditorDomain::COMMON, "find value fail, str:%{private}s, prefix:%{private}s",
            str.c_str(), prefix.c_str());
        return "";
    }
    return str.substr(pos + prefix.size());
}

bool GetIntByPrefix(const std::string &str, const std::string &prefix, int &num)
{
    std::string strValue = GetSubstrByPrefix(str, prefix);
    if (!StringToInt(strValue.c_str(), num)) {
        OBJECT_EDITOR_LOGE(ObjectEditorDomain::COMMON, "StringToInt fail, str:%{private}s, prefix:%{private}s",
            str.c_str(), prefix.c_str());
        return false;
    }
    return true;
}

bool ValidateAndNormalizePath(const std::string &inputPath, std::string &canonicalFileName)
{
    if (inputPath.empty()) {
        OBJECT_EDITOR_LOGE(ObjectEditorDomain::COMMON, "input path is empty");
        return false;
    }
    std::filesystem::path path(inputPath);
    std::string directory = path.parent_path().string() + "/";
    std::string filenameTemp = path.filename().string();
    std::unique_ptr<char, decltype(&free)> canonicalDirPath(realpath(directory.c_str(), nullptr), &free);
    if (canonicalDirPath == nullptr) {
        OBJECT_EDITOR_LOGE(ObjectEditorDomain::COMMON, "canonical directory path is null");
        return false;
    }
    canonicalFileName = std::string(canonicalDirPath.get()) + "/" + filenameTemp;
    std::unique_ptr<char, decltype(&free)> finalPath(realpath(canonicalFileName.c_str(), nullptr), &free);
    if (finalPath != nullptr) {
        std::string finalStr(finalPath.get());
        std::string canonicalDirStr(canonicalDirPath.get());
        // 验证最终路径仍以允许的目录为前缀
        if (finalStr.find(canonicalDirStr) != 0) {
            OBJECT_EDITOR_LOGE(ObjectEditorDomain::COMMON, "path escaped sandbox");
            return false;
        }
        canonicalFileName = finalStr;
    }
    return true;
}

std::string GetBundleName()
{
    auto context = AbilityRuntime::Context::GetApplicationContext();
    if (context == nullptr) {
        OBJECT_EDITOR_LOGE(ObjectEditorDomain::COMMON, "application context is null");
        return "";
    }
    return context->GetBundleName();
}

// LCOV_EXCL_STOP
} // namespace SystemUtils
} // namespace ObjectEditor
} // namespace OHOS