* Copyright (c) 2024 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_fs.h"
#include <algorithm>
#include <cerrno>
#include <cstdint>
#include <cstdlib>
#include <dirent.h>
#include <dlfcn.h>
#include <fcntl.h>
#include <limits>
#include <linux/reboot.h>
#include <string>
#include <sys/reboot.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <vector>
#include "log/log.h"
namespace Updater {
namespace Utils {
constexpr long MAX_FILE_LENGTH = 4 * 1024 * 1024;
int MkdirRecursive(const std::string &pathName, mode_t mode)
{
size_t slashPos = 0;
struct stat info {};
while (true) {
slashPos = pathName.find_first_of("/", slashPos);
if (slashPos == std::string::npos) {
break;
}
if (slashPos == 0) {
slashPos++;
continue;
}
if (slashPos > PATH_MAX) {
LOG(ERROR) << "path too long for mkdir";
return -1;
}
auto subDir = pathName.substr(0, slashPos);
LOG(DEBUG) << "subDir : " << subDir;
if (stat(subDir.c_str(), &info) != 0) {
int ret = mkdir(subDir.c_str(), mode);
if (ret && errno != EEXIST) {
return ret;
}
}
slashPos++;
}
int ret = mkdir(pathName.c_str(), mode);
if (ret && errno != EEXIST) {
return ret;
}
return 0;
}
int64_t GetFilesFromDirectory(const std::string &path, std::vector<std::string> &files,
bool isRecursive)
{
struct stat sb {};
if (stat(path.c_str(), &sb) == -1) {
LOG(ERROR) << "Failed to stat";
return -1;
}
DIR *dirp = opendir(path.c_str());
if (dirp == nullptr) {
LOG(ERROR) << "Failed to opendir errno=" << errno;
return -1;
}
struct dirent *dp = nullptr;
int64_t totalSize = 0;
while ((dp = readdir(dirp)) != nullptr) {
std::string fileName = path + "/" + dp->d_name;
struct stat st {};
if (stat(fileName.c_str(), &st) == 0) {
std::string tmpName = dp->d_name;
if (tmpName == "." || tmpName == "..") {
continue;
}
if (isRecursive && S_ISDIR(st.st_mode)) {
totalSize += GetFilesFromDirectory(fileName, files, isRecursive);
}
files.push_back(fileName);
totalSize += st.st_size;
}
}
closedir(dirp);
dirp = nullptr;
return totalSize;
}
bool RemoveDir(const std::string &path)
{
if (path.empty() || path == "/") {
LOG(ERROR) << "input path is invalid.";
return false;
}
std::string strPath = path;
if (strPath.at(strPath.length() - 1) != '/') {
strPath.append("/");
}
DIR *d = opendir(strPath.c_str());
if (d != nullptr) {
struct dirent *dt = nullptr;
dt = readdir(d);
while (dt != nullptr) {
if (strcmp(dt->d_name, "..") == 0 || strcmp(dt->d_name, ".") == 0) {
dt = readdir(d);
continue;
}
struct stat st {};
auto file_name = strPath + std::string(dt->d_name);
if (stat(file_name.c_str(), &st) != 0) {
LOG(ERROR) << "stat fail, errno: " << errno;
}
if (S_ISDIR(st.st_mode)) {
RemoveDir(file_name);
} else {
remove(file_name.c_str());
}
dt = readdir(d);
}
closedir(d);
}
return rmdir(strPath.c_str()) == 0 ? true : false;
}
bool IsFileExist(const std::string &path)
{
struct stat st {};
if (stat(path.c_str(), &st) == 0 && S_ISREG(st.st_mode)) {
return true;
}
return false;
}
bool IsDirExist(const std::string &path)
{
struct stat st {};
if (stat(path.c_str(), &st) == 0 && S_ISDIR(st.st_mode)) {
return true;
}
return false;
}
bool ReadFileToString(int fd, std::string &content)
{
struct stat sb {};
if (fstat(fd, &sb) != -1 && sb.st_size > 0) {
content.resize(static_cast<size_t>(sb.st_size));
}
ssize_t n;
auto remaining = static_cast<size_t>(sb.st_size);
auto p = reinterpret_cast<char *>(content.data());
while (remaining > 0) {
n = read(fd, p, remaining);
if (n <= 0) {
return false;
}
p += n;
remaining -= static_cast<size_t>(n);
}
return true;
}
bool ReadStringFromProcFile(const std::string &filePath, std::string &content)
{
std::ifstream file(filePath.c_str());
if (!file.is_open()) {
LOG(ERROR) << "failed to open " << filePath << ", err: " << strerror(errno);
return false;
}
file.seekg(0, std::ios::end);
const long fileLength = file.tellg();
if (fileLength > MAX_FILE_LENGTH) {
LOG(ERROR) << "file oversize " << fileLength << ", max is " << MAX_FILE_LENGTH;
return false;
}
content.clear();
file.seekg(0, std::ios::beg);
std::copy(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>(), std::back_inserter(content));
return true;
}
}
}