VCarContainer/base/FileManager/FileManager.cpp

526 lines
15 KiB
C++

/*
* Copyright (c) 2020.Huawei Technologies Co., Ltd. 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 "FileManager.h"
#include <ctime>
#include <string>
namespace {
const int BUFFER_SIZE = 2048;
#ifndef _WIN32
const mode_t DEFAULT_FILE_PERMISSION = 0077;
#endif
}
#ifndef _WIN32
mode_t SetFileDefaultUmask()
{
return umask(DEFAULT_FILE_PERMISSION);
}
mode_t SetFileUmask(mode_t newUmask)
{
return umask(newUmask);
}
#endif
/**
* Check whether the file exists.
*
* @param filePath the file path we want to check
* @return APP_ERR_OK if file exists, error code otherwise
*/
APP_ERROR ExistFile(const std::string &filePath)
{
std::string resolvedPath;
APP_ERROR ret = GetRealPath(filePath, resolvedPath);
if (ret != APP_ERR_OK) {
return ret;
}
#ifndef _WIN32
struct stat fileStat = {0};
if (stat(resolvedPath.c_str(), &fileStat) == 0 && S_ISREG(fileStat.st_mode)) {
#else
DWORD fileStat = GetFileAttributes((LPCSTR)resolvedPath.c_str());
if ((fileStat == FILE_ATTRIBUTE_ARCHIVE) || (fileStat == FILE_ATTRIBUTE_NORMAL) ||
(fileStat == FILE_ATTRIBUTE_DIRECTORY)) {
#endif
return APP_ERR_OK;
}
return APP_ERR_COMM_FAILURE;
}
/**
* Split the input path string with delimiter
*
* @param str path string
* @param delimiters a set of delimiter
* @return the vector of splitted path
*/
std::vector<std::string> SplitPath(const std::string &str, const std::set<char> delimiters)
{
std::vector<std::string> result;
std::string temp = str;
auto start = temp.begin();
auto it = temp.begin();
for (; it != temp.end(); ++it) {
if (delimiters.find(*it) != delimiters.end()) {
if (it != start) {
result.emplace_back(start, it);
} else {
result.emplace_back("");
}
start = it + 1;
}
}
result.emplace_back(start, it);
return result;
}
/**
* Create a directory
*
* @param dirPath the directory we want to create
* @return APP_ERR_OK if create success, error code otherwise
*/
APP_ERROR CreateDir(const std::string &dirPath)
{
#ifndef _WIN32
SetFileDefaultUmask();
if (dirPath.length() > PATH_MAX) {
LogError << dirPath << "is larger than " << std::to_string(PATH_MAX) << ".";
return APP_ERR_COMM_NO_EXIST;
}
#else
if (dirPath.length() > MAX_PATH) {
LogError << dirPath << "is larger than " << std::to_string(MAX_PATH) << ".";
}
return APP_ERR_COMM_NO_EXIST;
#endif
// Check the write authority of directory, if not exist, create it
int dirExist = access(dirPath.c_str(), W_OK);
if (-1 == dirExist) {
#ifdef _WIN32
if (_mkdir(dirPath.c_str()) == -1) {
#else
if (mkdir(dirPath.c_str(), S_IRUSR | S_IWUSR | S_IXUSR) == -1) {
#endif
return APP_ERR_COMM_NO_EXIST;
}
}
return APP_ERR_OK;
}
/**
* Create directory recursively
*
* @param file target directory to create
*/
void CreateDirRecursively(const std::string &file)
{
CreateDirRecursivelyByFile(file);
if (access(file.c_str(), 0) != 0) {
#ifndef _WIN32
int result = mkdir(file.c_str(), S_IRUSR | S_IWUSR | S_IXUSR); // for linux
#else
int result = _mkdir(file.c_str());
#endif
if (result < 0) {
LogError << "mkdir logs file " << file << " fail.";
return;
}
}
}
/**
* Create directory recursively by file
*
* @param file target file to create
*/
void CreateDirRecursivelyByFile(const std::string &file)
{
size_t pos = file.rfind('/'); // for linux
std::string filePath = file.substr(0, pos);
if (access(filePath.c_str(), 0) != 0) {
CreateDirRecursivelyByFile(filePath);
#ifndef _WIN32
int result = mkdir(filePath.c_str(), S_IRUSR | S_IWUSR | S_IXUSR); // for linux
#else
int result = _mkdir(filePath.c_str());
#endif
if (result < 0) {
LogError << "mkdir logs file " << filePath << " fail.";
return;
}
}
}
/**
* Read a file, store it into the RawData structure
*
* @param filePath file to read to
* @param fileData RawData structure to store in
* @return APP_ERR_OK if create success, error code otherwise
*/
APP_ERROR ReadFile(const std::string &filePath, RawData &fileData)
{
std::string resolvedPath;
APP_ERROR ret = GetRealPath(filePath, resolvedPath);
if (ret != APP_ERR_OK) {
return ret;
}
// Open file with reading mode
FILE *fp = fopen(resolvedPath.c_str(), "rb");
if (fp == nullptr) {
LogError << "Failed to open file";
return APP_ERR_COMM_OPEN_FAIL;
}
// Get the length of input file
fseek(fp, 0, SEEK_END);
long fileSize = ftell(fp);
fseek(fp, 0, SEEK_SET);
// If file not empty, read it into FileInfo and return it
if (fileSize > 0) {
fileData.lenOfByte = fileSize;
fileData.data = std::make_shared<uint8_t>();
fileData.data.reset(new uint8_t[fileSize], std::default_delete<uint8_t[]>());
size_t readRet = fread(fileData.data.get(), 1, fileSize, fp);
if (readRet <= 0) {
fclose(fp);
return APP_ERR_COMM_READ_FAIL;
}
fclose(fp);
return APP_ERR_OK;
}
fclose(fp);
return APP_ERR_COMM_FAILURE;
}
/**
* Read a binary file, store the data into a uint8_t array
*
* @param fileName the file for reading
* @param buffShared a shared pointer to a uint8_t array for storing file
* @param buffLength the length of the array
* @return APP_ERR_OK if create success, error code otherwise
*/
APP_ERROR ReadBinaryFile(const std::string &fileName, std::shared_ptr<uint8_t> &buffShared, int &buffLength)
{
// read binary file
std::ifstream inFile(fileName, std::ios::in | std::ios::binary);
if (!inFile) {
LogError << "FaceFeatureLib: read file " << fileName << " fail.";
return APP_ERR_COMM_READ_FAIL;
}
// get length of file:
inFile.seekg(0, inFile.end);
buffLength = inFile.tellg();
inFile.seekg(0, inFile.beg);
auto tempShared = std::make_shared<uint8_t>();
tempShared.reset(new uint8_t[buffLength], std::default_delete<uint8_t[]>());
inFile.read((char *)tempShared.get(), buffLength);
inFile.close();
buffShared = tempShared;
LogDebug << "read file: fileName=" << fileName << ", size=" << buffLength << ".";
return APP_ERR_OK;
}
/**
* Read a file with specified offset
* Only used in Jpegd
*
* @param fileName the file for reading
* @param fileData RawData structure to store in
* @param offset offset for file
* @return APP_ERR_OK if create success, error code otherwise
*/
APP_ERROR ReadFileWithOffset(const std::string &fileName, RawData &fileData, const uint32_t offset)
{
std::string resolvedPath;
APP_ERROR ret = GetRealPath(fileName, resolvedPath);
if (ret != APP_ERR_OK) {
return ret;
}
// Open file with reading mode
FILE *fp = fopen(resolvedPath.c_str(), "rb");
if (fp == nullptr) {
LogError << "Failed to open file";
return APP_ERR_COMM_OPEN_FAIL;
}
// Get the length of input file
fseek(fp, 0, SEEK_END);
long fileSize = ftell(fp);
fseek(fp, 0, SEEK_SET);
// If file not empty, read it into FileInfo and return it
if (fileSize > 0) {
fileData.lenOfByte = fileSize;
fileData.data = std::make_shared<uint8_t>();
fileData.data.reset(new uint8_t[fileSize + offset], std::default_delete<uint8_t[]>());
size_t readRet = fread(fileData.data.get(), 1, fileSize, fp);
if (readRet <= 0) {
fclose(fp);
return APP_ERR_COMM_READ_FAIL;
}
fclose(fp);
return APP_ERR_OK;
}
fclose(fp);
return APP_ERR_COMM_FAILURE;
}
APP_ERROR GetRealPath(const std::string &srcPath, std::string &resolvedPath)
{
// Get the absolute path of input file
#ifndef _WIN32
char path[PATH_MAX + 1] = {0};
if ((strlen(srcPath.c_str()) > PATH_MAX) || (realpath(srcPath.c_str(), path) == nullptr)) {
#else
#pragma comment(lib, "Shlwapi.lib")
char path[MAX_PATH + 1] = {0};
if ((strlen(srcPath.c_str()) > MAX_PATH) || (_fullpath(path, srcPath.c_str(), MAX_PATH) == nullptr)) {
#endif
LogError << "Failed to get canonicalize path----" << srcPath;
return APP_ERR_COMM_NO_EXIST;
}
resolvedPath = path;
return APP_ERR_OK;
}
/**
* Get the extension name of input file
*
* @param filePath the file for reading extension name
* @return extension name of the file
*/
std::string GetExtension(const std::string &filePath)
{
std::set<char> delims { '.' };
std::vector<std::string> path = SplitPath(filePath, delims);
return path[path.size() - 1];
}
/**
* Get file canonical name
*
* @param filePath absolute path of the target file
* @return filename of the file
*/
std::string GetName(const std::string &filePath)
{
std::set<char> delims { '/' };
std::vector<std::string> path = SplitPath(filePath, delims);
return (path.size() < 1) ? "" : path[path.size() - 1];
}
/**
* Get the Parent of input file
*
* @param filePath file for looking for parent
* @return parent of the file
*/
std::string GetParent(const std::string &filePath)
{
std::set<char> delims { '/' };
std::vector<std::string> path = SplitPath(filePath, delims);
return (path.size() < TWO) ? "" : path[path.size() - TWO];
}
/**
* Change the current directory
*
* @param dir target directory to change to
* @return APP_ERR_OK if create success, error code otherwise
*/
APP_ERROR ChangeDir(const std::string &dir)
{
std::string resolvedPath;
APP_ERROR ret = GetRealPath(dir, resolvedPath);
if (ret != APP_ERR_OK) {
return ret;
}
#ifndef _WIN32
char path[PATH_MAX + 1] = {0};
resolvedPath.copy(path, resolvedPath.length());
char *dName = dirname(path);
if (dName == nullptr) {
return APP_ERR_COMM_NO_EXIST;
}
#else
char path[MAX_PATH + 1] = {0};
resolvedPath.copy(path, resolvedPath.length());
if (!PathRemoveFileSpecA(path)) {
return APP_ERR_COMM_NO_EXIST;
}
char *dName = path;
#endif
if (chdir(dName) != 0) {
return APP_ERR_COMM_NO_EXIST;
}
return APP_ERR_OK;
}
/**
* Append stream to file
*
* @param fileName to append to
* @param stream content of string
* @param streamLength length of string
*/
void SaveFileAppend(const std::string &fileName, const std::string &stream, const int streamLength)
{
LogDebug << "saving binary file by app: fileName=" << fileName << ", streamLength=" << streamLength;
std::ofstream outfile(fileName, std::ios::app | std::ofstream::binary);
outfile.write(stream.c_str(), streamLength);
outfile.close();
}
/**
* Overwrite a file with stream
*
* @param fileName to overwrite to
* @param stream content of string
* @param streamLength length of string
*/
void SaveFileOverwrite(const std::string &fileName, const std::string &stream, const int streamLength)
{
LogDebug << "Saving binary file by over write: fileName=" << fileName << ", streamLength=" << streamLength;
std::ofstream outfile(fileName, std::ios::out | std::ofstream::binary);
outfile.write(stream.c_str(), streamLength);
outfile.close();
}
/**
* Copy file
*
* @param srcFile from source
* @param destFile to destination
*/
void CopyFile(const std::string &srcFile, const std::string &destFile)
{
std::ifstream in(srcFile, std::ios::binary);
if (!in) {
LogError << "Failed to get source file, it may be not exists. srcFile=" << srcFile;
return;
}
std::ofstream out(destFile, std::ios::binary);
if (!out) {
LogError << "Failed to save destination file. destFile=" << destFile;
in.close();
return;
}
char flush[BUFFER_SIZE];
while (!in.eof()) {
in.read(flush, BUFFER_SIZE);
out.write(flush, in.gcount());
}
out.close();
in.close();
}
/**
* Save file with timestamp under specified folder
*
* @param dataBuffer buffer of file
* @param bufferSize buffer size
* @param folderName specified folder will be created if it not existed
* @param fileName file name without suffix, the finally name will append time stamp to it
* @param fileSuffix suffix name of file
*/
APP_ERROR SaveFileWithTimeStamp(std::shared_ptr<void> dataBuffer, uint32_t bufferSize, std::string folderName,
std::string fileName, std::string fileSuffix)
{
#ifndef _WIN32
SetFileDefaultUmask();
#endif
APP_ERROR ret;
if (folderName.length() != 0) {
ret = CreateDir(folderName);
if (ret != APP_ERR_OK) {
return ret;
}
}
// Result file name use the time stamp as a suffix
std::string timeString;
GetCurTimeString(timeString);
// Create file under folderName directory
std::stringstream resultPathName;
if (folderName.length() == 0) {
resultPathName << "./" << fileName << "_" << timeString << fileSuffix;
} else {
resultPathName << folderName << "/" << fileName << "_" << timeString << fileSuffix;
}
std::string resolvedPath;
ret = GetRealPath(resultPathName.str(), resolvedPath);
if (ret != APP_ERR_OK) {
return ret;
}
FILE *fp = fopen(resolvedPath.c_str(), "wb");
if (fp == nullptr) {
LogError << "Failed to open file";
return APP_ERR_COMM_OPEN_FAIL;
}
uint32_t result = fwrite(dataBuffer.get(), 1, bufferSize, fp);
if (result != bufferSize) {
LogError << "Failed to write file";
fclose(fp);
return APP_ERR_COMM_WRITE_FAIL;
}
LogInfo << "Write result to file successfully";
uint32_t ff = fflush(fp);
if (ff != 0) {
LogError << "Failed to fflush file";
fclose(fp);
return APP_ERR_COMM_DESTORY_FAIL;
}
uint32_t fc = fclose(fp);
if (fc != 0) {
LogError << "Failed to fclose file";
return APP_ERR_COMM_DESTORY_FAIL;
}
return APP_ERR_OK;
}
/**
* Convert the current time to the format "%Y%m%d%H%M%S"
*
* @param timeString buffer to save the time string with format "%Y%m%d%H%M%S"
*/
void GetCurTimeString(std::string &timeString)
{
// Result file name use the time stamp as a suffix
const int timeZoneDiff = 28800; // 8 hour time difference
const int timeStringSize = 32;
char timeStr[timeStringSize] = {0};
time_t tmValue = time(nullptr) + timeZoneDiff;
struct tm tmStruct = {0};
#ifdef _WIN32
if (0 == gmtime_s(&tmStruct, &tmValue)) {
#else
if (nullptr != gmtime_r(&tmValue, &tmStruct)) {
#endif
strftime(timeStr, sizeof(timeStr), "%Y%m%d%H%M%S", &tmStruct);
}
timeString = timeStr;
return;
}