* Copyright (c) 2025 Huawei Technologies Co., Ltd.
* This program is free software, you can redistribute it and/or modify it under the terms and conditions of
* CANN Open Software License Agreement Version 2.0 (the "License").
* Please refer to the License for details. You may not use this file except in compliance with the License.
* 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 FITNESS FOR A PARTICULAR PURPOSE.
* See LICENSE in the root of the software repository for the full text of the License.
*/
#include "common/util/json_util.h"
#include <climits>
#include <fstream>
#include <thread>
#include <ext/stdio_filebuf.h>
#include <fcntl.h>
#include "common/fe_log.h"
#include "common/fe_utils.h"
#include "common/aicore_util_constants.h"
#include "common/fe_error_code.h"
#include "common/fe_report_error.h"
namespace fe {
const uint32_t kFlockRecursiveIntvl = 10;
const uint32_t kFlockRecursiveCntMax = 6000;
std::string RealPath(const std::string &path) {
if (path.empty()) {
FE_LOGI("Path string is nullptr.");
return "";
}
if (path.size() >= PATH_MAX) {
FE_LOGI("File path %s is too long!", path.c_str());
return "";
}
char *resoved_path = new(std::nothrow) char[PATH_MAX];
if (resoved_path == nullptr) {
FE_LOGI("New resoved_path not successfully.");
return "";
}
(void)memset_s(resoved_path, PATH_MAX, 0, PATH_MAX);
std::string res = "";
if (realpath(path.c_str(), resoved_path) != nullptr) {
res = resoved_path;
} else {
FE_LOGI("Path %s does not exist.", path.c_str());
}
delete[] resoved_path;
return res;
}
Status FcntlLockFile(const std::string &file, int fd, int type, uint32_t recursive_cnt) {
struct flock lock_arg;
lock_arg.l_whence = SEEK_SET;
lock_arg.l_start = 0;
lock_arg.l_len = 0;
lock_arg.l_type = type;
if (fcntl(fd, F_SETLK, &lock_arg) != 0) {
if (recursive_cnt == 0) {
if (type == F_UNLCK) {
FE_LOGW("Realse lock file(%s) failed.", file.c_str());
} else {
FE_LOGD("File(%s) is locked by %d.", file.c_str(), lock_arg.l_pid);
}
}
return FAILED;
}
return SUCCESS;
}
void LogOpenFileErrMsg(const std::string &file)
{
ErrorMessageDetail err_msg(EM_OPEN_FILE_FAILED, {file});
ReportErrorMessage(err_msg);
}
Status ReadJsonFile(const std::string &file, nlohmann::json &json_obj) {
std::string path = RealPath(file);
if (path.empty()) {
FE_LOGW("File path [%s] does not exist.", file.c_str());
return FAILED;
}
std::ifstream if_stream(path);
try {
if (!if_stream.is_open()) {
FE_LOGW("Failed to open %s, file is already opened.", file.c_str());
LogOpenFileErrMsg(file);
return FAILED;
}
if_stream >> json_obj;
if_stream.close();
} catch (const std::exception &e) {
FE_LOGW("Failed to convert file[%s] to Json. Exception message is %s", path.c_str(), e.what());
if_stream.close();
return ILLEGAL_JSON;
}
return SUCCESS;
}
Status ReadJsonFileByLock(const std::string &file, nlohmann::json &json_obj) {
std::string path = RealPath(file);
if (path.empty()) {
FE_LOGW("File path [%s] is not valid.", file.c_str());
LogOpenFileErrMsg(file);
return FAILED;
}
std::ifstream if_stream(path);
try {
if (!if_stream.is_open()) {
FE_LOGW("Failed to open %s, file is already opened.", file.c_str());
LogOpenFileErrMsg(file);
return FAILED;
}
uint32_t recursive_cnt = 0;
int ifs_fd = static_cast<__gnu_cxx::stdio_filebuf<char> *>(if_stream.rdbuf())->fd();
do {
if (FcntlLockFile(file, ifs_fd, F_RDLCK, recursive_cnt) == FAILED) {
std::this_thread::sleep_for(std::chrono::microseconds(kFlockRecursiveIntvl));
} else {
FE_LOGD("Lock file(%s).", file.c_str());
break;
}
if (recursive_cnt == kFlockRecursiveCntMax) {
FE_LOGE("Lock file(%s) failed, try %u times.", file.c_str(), kFlockRecursiveCntMax);
LogOpenFileErrMsg(file);
if_stream.close();
return FAILED;
}
recursive_cnt++;
} while (true);
if_stream >> json_obj;
(void)FcntlLockFile(file, ifs_fd, F_UNLCK, 0);
FE_LOGD("Release lock file(%s).", file.c_str());
if_stream.close();
} catch (const std::exception &e) {
FE_LOGW("Failed to convert file [%s] to json. Message is %s", path.c_str(), e.what());
if_stream.close();
LogOpenFileErrMsg(file);
return ILLEGAL_JSON;
}
return SUCCESS;
}
std::string GetSuffixJsonFile(const std::string &json_file_path, const std::string &suffix) {
if (json_file_path.empty()) {
FE_LOGW("Json file path is empty.");
return "";
}
string tmp_str = json_file_path;
size_t find_pos = json_file_path.find_last_of('.');
if (find_pos != std::string::npos) {
return tmp_str.insert(find_pos, suffix);
} else {
return "";
}
}
std::string GetJsonType(const nlohmann::json &json_object) {
std::string json_type;
switch (json_object.type()) {
case nlohmann::json::value_t::null:
json_type = "null";
break;
case nlohmann::json::value_t::object:
json_type = "object";
break;
case nlohmann::json::value_t::array:
json_type = "array";
break;
case nlohmann::json::value_t::string:
json_type = "string";
break;
case nlohmann::json::value_t::boolean:
json_type = "boolean";
break;
case nlohmann::json::value_t::number_integer:
json_type = "number_integer";
break;
case nlohmann::json::value_t::number_unsigned:
json_type = "number_unsigned";
break;
case nlohmann::json::value_t::number_float:
json_type = "number_float";
break;
case nlohmann::json::value_t::discarded:
json_type = "discarded";
break;
default:
json_type = "discarded";
break;
}
return json_type;
}
}