* Copyright (c) 2021-2025 Huawei Device 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.
*/
#include "utils_directory.h"
#include <cstring>
#include <dirent.h>
#include <memory>
#include <sys/types.h>
#include <system_error>
#include <unistd.h>
#include "dfs_error.h"
#include "directory_ex.h"
#include "hisysevent.h"
#include "utils_log.h"
namespace OHOS {
namespace Storage {
namespace DistributedFile {
namespace Utils {
using namespace std;
namespace {
static const uint32_t STAT_MODE_DIR = 0771;
}
std::string GetAnonyString(const std::string &value)
{
constexpr size_t shortIdLength = 20;
constexpr size_t plaintextLength = 4;
constexpr size_t minIdLength = 3;
std::string res;
std::string tmpStr("******");
size_t strLen = value.length();
if (strLen < minIdLength) {
return tmpStr;
}
if (strLen <= shortIdLength) {
res += value[0];
res += tmpStr;
res += value[strLen - 1];
} else {
res.append(value, 0, plaintextLength);
res += tmpStr;
res.append(value, strLen - plaintextLength, plaintextLength);
}
return res;
}
void SysEventWrite(string &uid)
{
if (uid.empty()) {
LOGE("uid is empty.");
return;
}
int32_t ret = DEMO_SYNC_SYS_EVENT("PERMISSION_EXCEPTION",
HiviewDFX::HiSysEvent::EventType::SECURITY,
"CALLER_UID", uid,
"PERMISSION_NAME", "account");
if (ret != ERR_OK) {
LOGE("report PERMISSION_EXCEPTION error %{public}d", ret);
}
}
void SysEventFileParse(int64_t maxTime)
{
int32_t ret = DEMO_SYNC_SYS_EVENT("INDEX_FILE_PARSE",
HiviewDFX::HiSysEvent::EventType::STATISTIC,
"MAX_TIME", maxTime);
if (ret != ERR_OK) {
LOGE("report INDEX_FILE_PARSE error %{public}d", ret);
}
}
void RadarDotsReportOpenSession(struct RadarInfo &info)
{
int32_t res = ERR_OK;
if (info.state == StageRes::STAGE_SUCCESS) {
res = DEMO_SYNC_SYS_EVENT(DISTRIBUTEDFILE_CONNECT_BEHAVIOR,
HiviewDFX::HiSysEvent::EventType::BEHAVIOR,
"ORG_PKG", ORGPKGNAME,
"TO_CALL_PKG", SOFTBUSNAME,
"FUNC", info.funcName,
"BIZ_SCENE", static_cast<int32_t>(BizScene::DFS_CONNECT),
"BIZ_STAGE", static_cast<int32_t>(BizStage::DFS_OPEN_SESSION),
"BIZ_STATE", static_cast<int32_t>(BizState::BIZ_STATE_START),
"STAGE_RES", static_cast<int32_t>(StageRes::STAGE_SUCCESS),
"LOCAL_SESS_NAME", info.localSessionName,
"PEER_SESS_NAME", info.peerSessionName);
} else {
res = DEMO_SYNC_SYS_EVENT(DISTRIBUTEDFILE_CONNECT_BEHAVIOR,
HiviewDFX::HiSysEvent::EventType::BEHAVIOR,
"ORG_PKG", ORGPKGNAME,
"TO_CALL_PKG", SOFTBUSNAME,
"FUNC", info.funcName,
"BIZ_SCENE", static_cast<int32_t>(BizScene::DFS_CONNECT),
"BIZ_STAGE", static_cast<int32_t>(BizStage::DFS_OPEN_SESSION),
"BIZ_STATE", static_cast<int32_t>(BizState::BIZ_STATE_END),
"STAGE_RES", static_cast<int32_t>(StageRes::STAGE_FAIL),
"LOCAL_SESS_NAME", info.localSessionName,
"PEER_SESS_NAME", info.peerSessionName,
"ERROR_CODE", std::abs(info.errCode));
}
if (res != ERR_OK) {
LOGE("report RadarDotsReportOpenSession error %{public}d", res);
}
}
void RadarDotsOpenSession(const std::string funcName, const std::string &sessionName,
const std::string &peerSssionName, int32_t errCode, StageRes state)
{
struct RadarInfo info = {
.funcName = funcName,
.localSessionName = sessionName,
.peerSessionName = peerSssionName,
.errCode = errCode,
.state = state,
};
RadarDotsReportOpenSession(info);
}
void RadarDotsReportSendFile(struct RadarInfo &info)
{
int32_t res = ERR_OK;
if (info.state == StageRes::STAGE_SUCCESS) {
res = DEMO_SYNC_SYS_EVENT(DISTRIBUTEDFILE_CONNECT_BEHAVIOR,
HiviewDFX::HiSysEvent::EventType::BEHAVIOR,
"ORG_PKG", ORGPKGNAME,
"TO_CALL_PKG", SOFTBUSNAME,
"FUNC", info.funcName,
"BIZ_SCENE", static_cast<int32_t>(BizScene::DFS_CONNECT),
"BIZ_STAGE", static_cast<int32_t>(BizStage::DFS_SENDFILE),
"BIZ_STATE", static_cast<int32_t>(BizState::BIZ_STATE_END),
"STAGE_RES", static_cast<int32_t>(StageRes::STAGE_SUCCESS),
"LOCAL_SESS_NAME", info.localSessionName,
"PEER_SESS_NAME", info.peerSessionName);
} else {
res = DEMO_SYNC_SYS_EVENT(DISTRIBUTEDFILE_CONNECT_BEHAVIOR,
HiviewDFX::HiSysEvent::EventType::BEHAVIOR,
"ORG_PKG", ORGPKGNAME,
"TO_CALL_PKG", SOFTBUSNAME,
"FUNC", info.funcName,
"BIZ_SCENE", static_cast<int32_t>(BizScene::DFS_CONNECT),
"BIZ_STAGE", static_cast<int32_t>(BizStage::DFS_SENDFILE),
"BIZ_STATE", static_cast<int32_t>(BizState::BIZ_STATE_END),
"STAGE_RES", static_cast<int32_t>(StageRes::STAGE_FAIL),
"LOCAL_SESS_NAME", info.localSessionName,
"PEER_SESS_NAME", info.peerSessionName,
"ERROR_CODE", std::abs(info.errCode));
}
if (res != ERR_OK) {
LOGE("report RadarDotsReportSendFile error %{public}d", res);
}
}
void RadarDotsSendFile(const std::string funcName, const std::string &sessionName,
const std::string &peerSssionName, int32_t errCode, StageRes state)
{
struct RadarInfo info = {
.funcName = funcName,
.localSessionName = sessionName,
.peerSessionName = peerSssionName,
.errCode = errCode,
.state = state,
};
RadarDotsReportSendFile(info);
}
void ForceCreateDirectory(const string &path, function<void(const string &)> onSubDirCreated)
{
string::size_type index = 0;
do {
string subPath;
index = path.find('/', index + 1);
if (index == string::npos) {
subPath = path;
} else {
subPath = path.substr(0, index);
}
if (access(subPath.c_str(), F_OK) != 0) {
if (mkdir(subPath.c_str(), STAT_MODE_DIR) != 0) {
LOGE("failed to mkdir, errno:%{public}d", errno);
return;
}
onSubDirCreated(subPath);
}
} while (index != string::npos);
}
void ForceCreateDirectory(const string &path)
{
ForceCreateDirectory(path, nullptr);
}
void ForceCreateDirectory(const string &path, mode_t mode)
{
ForceCreateDirectory(path, [mode](const string &subPath) {
if (chmod(subPath.c_str(), mode) == -1) {
LOGE("failed to chmod, errno:%{public}d", errno);
}
});
}
void ForceCreateDirectory(const string &path, mode_t mode, uid_t uid, gid_t gid)
{
ForceCreateDirectory(path, [mode, uid, gid](const string &subPath) {
if (chmod(subPath.c_str(), mode) == -1 || chown(subPath.c_str(), uid, gid) == -1) {
LOGE("failed to chmod or chown, errno:%{public}d", errno);
}
});
}
void ForceRemoveDirectory(const string &path)
{
if (!OHOS::ForceRemoveDirectory(path)) {
LOGE("failed to forcibly remove directory, errno:%{public}d", errno);
}
}
bool ForceRemoveDirectoryDeepFirst(const string& path)
{
string subPath;
bool ret = true;
DIR *dir = opendir(path.c_str());
if (dir == nullptr) {
LOGE("opendir failed, path = %{public}s, err:%{public}d", GetAnonyString(path).c_str(), errno);
return false;
}
while (true) {
struct dirent *ptr = readdir(dir);
if (ptr == nullptr) {
break;
}
if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0) {
continue;
}
subPath = IncludeTrailingPathDelimiter(path) + string(ptr->d_name);
if (ptr->d_type == DT_DIR) {
if (!ForceRemoveDirectoryDeepFirst(subPath)) {
ret = false;
}
} else if (access(subPath.c_str(), F_OK) == 0) {
if (remove(subPath.c_str()) != 0) {
closedir(dir);
LOGE("remove failed, subPath = %{public}s, err:%{public}d",
GetAnonyString(subPath).c_str(), errno);
return false;
}
}
}
closedir(dir);
string currentPath = ExcludeTrailingPathDelimiter(path);
if (access(currentPath.c_str(), F_OK) == 0) {
if (remove(currentPath.c_str()) != 0) {
LOGE("remove failed, currentPath = %{public}s, err:%{public}d",
GetAnonyString(currentPath).c_str(), errno);
return false;
}
}
return ret && (access(path.c_str(), F_OK) != 0);
}
bool IsFile(const std::string &path)
{
if (path.empty()) {
return false;
}
struct stat buf = {};
if (stat(path.c_str(), &buf) != 0) {
LOGE("stat failed, errno = %{public}d", errno);
return false;
}
return S_ISREG(buf.st_mode);
}
bool IsFolder(const std::string &name)
{
if (name.empty()) {
return false;
}
struct stat buf = {};
if (stat(name.c_str(), &buf) != 0) {
LOGE("stat failed, errno = %{public}d", errno);
return false;
}
return S_ISDIR(buf.st_mode);
}
std::vector<std::string> GetFilePath(const std::string &name)
{
std::vector<std::string> path;
if (!IsFolder(name)) {
path.emplace_back(name);
return path;
}
std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(name.data()), &closedir);
if (dir) {
struct dirent *ent = nullptr;
while ((ent = readdir(dir.get())) != nullptr) {
auto tmpPath = std::string(name).append("/").append(ent->d_name);
if (strcmp(ent->d_name, "..") == 0 || strcmp(ent->d_name, ".") == 0) {
continue;
} else if (IsFolder(tmpPath)) {
auto dirPath = GetFilePath(tmpPath);
path.insert(path.end(), dirPath.begin(), dirPath.end());
} else {
path.emplace_back(tmpPath);
}
}
}
return path;
}
int32_t ChangeOwnerRecursive(const std::string &path, uid_t uid, gid_t gid)
{
std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(path.c_str()), &closedir);
if (dir == nullptr) {
LOGE("Directory is null");
return -1;
}
struct dirent *entry = nullptr;
while ((entry = readdir(dir.get())) != nullptr) {
if (entry->d_type == DT_DIR) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
continue;
}
std::string subPath = path + "/" + entry->d_name;
if (chown(subPath.c_str(), uid, gid) == -1) {
LOGE("Change owner recursive failed");
return -1;
}
return ChangeOwnerRecursive(subPath, uid, gid);
} else {
std::string filePath = path + "/" + entry->d_name;
if (chown(filePath.c_str(), uid, gid) == -1) {
LOGE("Change owner recursive failed");
return -1;
}
}
}
return 0;
}
bool IsInt32(const nlohmann::json &jsonObj, const std::string &key)
{
bool res = jsonObj.contains(key) && jsonObj[key].is_number_integer() && jsonObj[key] >= INT32_MIN &&
jsonObj[key] <= INT32_MAX;
if (!res) {
LOGE("the key %{public}s in jsonObj is invalid.", key.c_str());
}
return res;
}
}
}
}
}