* This file is part of the oGRAC project.
* Copyright (c) 2024 Huawei Technologies Co.,Ltd.
*
* oGRAC is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* 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 FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
* -------------------------------------------------------------------------
*
* cm_file.c
*
*
* IDENTIFICATION
* src/common/cm_file.c
*
* -------------------------------------------------------------------------
*/
#include "cm_common_module.h"
#include "cm_file.h"
#include "cm_log.h"
#include "cm_system.h"
#include "cm_date.h"
#include "cm_dbstor.h"
#ifdef WIN32
#else
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <poll.h>
#endif
#ifndef CM_FALLOC_KEEP_SIZE
#define CM_FALLOC_KEEP_SIZE 0x01
#endif
#ifndef CM_FALLOC_PUNCH_HOLE
#define CM_FALLOC_PUNCH_HOLE 0x02
#endif
#ifdef __cplusplus
extern "C" {
#endif
#define OG_WRITE_BUFFER_SIZE SIZE_M(2)
#define IS_DIR_SEPARATOR(c) ((c) == '/' || (c) == '\\')
* On Windows, a path may begin with "X:" or "//network/". Skip these and point to the effective start.
*/
#ifdef WIN32
static char *cm_skip_drive(const char *path)
{
if (IS_DIR_SEPARATOR(path[0]) && IS_DIR_SEPARATOR(path[1])) {
path += strlen("\\");
while (*path && !IS_DIR_SEPARATOR(*path)) {
path++;
}
} else if (isalpha((unsigned char)path[0]) && path[1] == ':') {
path += strlen("X:");
}
return (char *)path;
}
#else
#define cm_skip_drive(path) (path)
#endif
status_t cm_fsync_file(int32 file)
{
#ifndef WIN32
if (fsync(file) != 0) {
OG_THROW_ERROR(ERR_DATAFILE_FSYNC, errno);
return OG_ERROR;
}
#endif
return OG_SUCCESS;
}
status_t cm_fdatasync_file(int32 file)
{
#ifndef WIN32
if (fdatasync(file) != 0) {
OG_THROW_ERROR(ERR_DATAFILE_FDATASYNC, errno);
return OG_ERROR;
}
#endif
return OG_SUCCESS;
}
status_t cm_open_file(const char *file_name, uint32 mode, int32 *file)
{
uint32 perm = ((mode & O_CREAT) != 0) ? S_IRUSR | S_IWUSR : 0;
if (strlen(file_name) > OG_MAX_FILE_NAME_LEN) {
OG_THROW_ERROR(ERR_INVALID_FILE_NAME, file_name, (uint32)OG_MAX_FILE_NAME_LEN);
return OG_ERROR;
}
*file = open(file_name, (int)mode, perm);
if ((*file) == -1) {
if ((mode & O_CREAT) != 0) {
OG_THROW_ERROR(ERR_CREATE_FILE, file_name, errno);
} else {
OG_THROW_ERROR(ERR_OPEN_FILE, file_name, errno);
}
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t cm_reopen_file(int fd, const char* file_name, int* out_fd)
{
int32 old_fd = fd;
int32 new_fd = -1;
status_t ret = cm_open_file(file_name,
O_CREAT | O_RDWR | O_NONBLOCK | O_NDELAY | O_BINARY | O_CLOEXEC | O_SYNC | O_DIRECT,
&new_fd);
if (ret != OG_SUCCESS) {
OG_LOG_RUN_ERR("open file %s failed, error code %d.", file_name, errno);
return OG_ERROR;
}
cm_close_file(old_fd);
*out_fd = new_fd;
OG_LOG_RUN_INF("reopen file %s success, old_fd %d new_fd %d.", file_name, old_fd, new_fd);
return OG_SUCCESS;
}
status_t cm_get_file_path_depth(const char* file_name, const char* delim, int* depth)
{
if (file_name == NULL || delim == NULL || depth == NULL) {
OG_LOG_RUN_ERR("get file path depth failed, invalid param.");
return OG_ERROR;
}
if (strlen(file_name) == 0 || strlen(delim) == 0) {
OG_LOG_RUN_ERR("get file path depth failed, file name or delim is invalid.");
return OG_ERROR;
}
char file[OG_FILE_NAME_BUFFER_SIZE] = {0};
char* token = NULL;
char* context = NULL;
errno_t err = strcpy_sp(file, OG_MAX_FILE_NAME_LEN, file_name);
if (err != EOK) {
OG_THROW_ERROR(ERR_SYSTEM_CALL, err);
OG_LOG_RUN_ERR("Secure C lib has thrown an error %d", (err));
return OG_ERROR;
}
*depth = 0;
token = strtok_s(file, delim, &context);
while (token != NULL) {
(*depth)++;
token = strtok_s(NULL, delim, &context);
}
return OG_SUCCESS;
}
status_t cm_get_path_file_name(const char* path, char* file_name, uint32 name_len)
{
if (path == NULL || file_name == NULL) {
OG_LOG_RUN_ERR("get path file name failed, invalid param.");
return OG_ERROR;
}
char* p = strrchr(path, '/');
const char* s = (p == NULL ? path : p + 1);
errno_t err = strcpy_sp(file_name, name_len, s);
if (err != EOK) {
OG_THROW_ERROR(ERR_SYSTEM_CALL, err);
OG_LOG_RUN_ERR("Secure C lib has thrown an error %d", (err));
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t cm_get_dbs_root_dir_handle(char* fs_name, object_id_t* root_handle)
{
int ret = 0;
if (fs_name == NULL || root_handle == NULL) {
OG_LOG_RUN_ERR("get dbstor root dir fd failed, invalid param.");
return OG_ERROR;
}
ret = dbs_global_handle()->dbs_file_open_root(fs_name, root_handle);
if (ret != 0) {
OG_LOG_RUN_ERR("Failed(%d) open fs (%s) root dir.", ret, fs_name);
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t cm_get_dbs_dir_handle(object_id_t* phandle, char* dir_name, object_id_t* handle)
{
int ret = 0;
if (phandle == NULL || dir_name == NULL || handle == NULL) {
OG_LOG_RUN_ERR("get dbstor dir handle failed, invalid param.");
return OG_ERROR;
}
ret = dbs_global_handle()->dbs_file_open(phandle, dir_name, DIR_TYPE, handle);
if (ret != 0) {
ret = dbs_global_handle()->dbs_file_create(phandle, dir_name, DIR_TYPE, handle);
OG_LOG_RUN_INF("dir(%s) not exist, new create.", dir_name);
}
return (ret == 0 ? OG_SUCCESS : OG_ERROR);
}
status_t cm_open_dbs_dir_handle(object_id_t* phandle, char* dir_name, object_id_t* handle)
{
int ret = 0;
if (phandle == NULL || dir_name == NULL || handle == NULL) {
OG_LOG_RUN_ERR("get dbstor dir handle failed, invalid param.");
return OG_ERROR;
}
ret = dbs_global_handle()->dbs_file_open(phandle, dir_name, DIR_TYPE, handle);
return (ret == 0 ? OG_SUCCESS : OG_ERROR);
}
status_t cm_get_dbs_file_handle(object_id_t* phandle, char* file_name, object_id_t* handle)
{
int ret = 0;
if (phandle == NULL || file_name == NULL || handle == NULL) {
OG_LOG_RUN_ERR("get dbstor file handle failed, invalid param.");
return OG_ERROR;
}
ret = dbs_global_handle()->dbs_file_open(phandle, file_name, FILE_TYPE, handle);
if (ret != 0) {
OG_LOG_RUN_INF("file_name(%s) not exist, new create.", file_name);
ret = dbs_global_handle()->dbs_file_create(phandle, file_name, FILE_TYPE, handle);
}
if (ret != 0) {
OG_LOG_RUN_INF("Failed to create file: %s, ret is %d", file_name, ret);
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t cm_open_dbs_file(object_id_t* pHandle, char* file, object_id_t* handle)
{
status_t ret;
char file_name[OG_FILE_NAME_BUFFER_SIZE] = {0};
if (pHandle == NULL || file == NULL || handle == NULL) {
OG_LOG_RUN_ERR("get dbstor file fd failed, invalid param.");
return OG_ERROR;
}
ret = cm_get_path_file_name(file, file_name, OG_FILE_NAME_BUFFER_SIZE);
if (ret != OG_SUCCESS) {
OG_LOG_RUN_ERR("get path from file(%s) failed.", file);
return OG_ERROR;
}
int err = dbs_global_handle()->dbs_file_open(pHandle, file_name, FILE_TYPE, handle);
if (err != 0) {
OG_LOG_RUN_ERR("dbs open file_name(%s) failed.", file_name);
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t cm_get_dbs_file_path_handle(const char* path, const char* delim, object_id_t* handle_ids, int handle_len)
{
if (path == NULL || handle_ids == NULL || handle_len == 0) {
OG_LOG_RUN_ERR("get dbstor file path fd failed, invalid param.");
return OG_ERROR;
}
char* token = NULL;
char* context = NULL;
char file[OG_FILE_NAME_BUFFER_SIZE] = {0};
char fs_name[OG_FILE_NAME_BUFFER_SIZE] = {0};
int cur_depth = 0;
errno_t err = strcpy_sp(file, OG_MAX_FILE_NAME_LEN, path);
if (err != EOK) {
OG_THROW_ERROR(ERR_SYSTEM_CALL, err);
OG_LOG_RUN_ERR("Secure C lib has thrown an error %d", (err));
return OG_ERROR;
}
token = strtok_s(file, delim, &context);
while (token != NULL) {
if (cur_depth >= handle_len) {
OG_LOG_RUN_ERR("get dbs file(%s) fd failed, fd len exceed (%d - %d).", path, handle_len, cur_depth);
return OG_ERROR;
}
if (cur_depth == 0) {
MEMS_RETURN_IFERR(strcpy_sp(fs_name, OG_MAX_FILE_NAME_LEN, token));
if (cm_get_dbs_root_dir_handle(fs_name, &handle_ids[cur_depth]) != OG_SUCCESS) {
OG_LOG_RUN_ERR("get dbstor fs(%s) root dir(%s) fd failed.", fs_name, token);
return OG_ERROR;
}
} else if (cur_depth < handle_len - 1) {
if (cm_get_dbs_dir_handle(&handle_ids[cur_depth - 1], token, &handle_ids[cur_depth]) != OG_SUCCESS) {
OG_LOG_RUN_ERR("get dbstor fs(%s) dir(%s) fd failed.", fs_name, token);
return OG_ERROR;
}
} else if (cur_depth == handle_len - 1) {
if (cm_get_dbs_file_handle(&handle_ids[cur_depth - 1], token, &handle_ids[cur_depth]) != OG_SUCCESS) {
OG_LOG_RUN_ERR("get dbstor fs(%s) file(%s) fd failed.", fs_name, token);
return OG_ERROR;
}
}
cur_depth++;
token = strtok_s(NULL, delim, &context);
}
return OG_SUCCESS;
}
status_t cm_get_dbs_last_file_handle(const char* file, object_id_t* last_handle)
{
errno_t ret = 0;
int path_depth = 0;
if (cm_get_file_path_depth(file, "/", &path_depth) != OG_SUCCESS) {
OG_LOG_RUN_ERR("get dbstor file(%s) path depth failed.", file);
return OG_ERROR;
}
object_id_t* handle = (object_id_t *)malloc((path_depth + 1) * sizeof(object_id_t));
if (handle == NULL) {
OG_THROW_ERROR(ERR_ALLOC_MEMORY, (uint64)((path_depth + 1) * sizeof(object_id_t)), "dbs file fd");
return OG_ERROR;
}
if (cm_get_dbs_file_path_handle(file, "/", handle, path_depth) != OG_SUCCESS) {
OG_LOG_RUN_ERR("get dbstor file path fd failed, file %s, ret %d", file, ret);
CM_FREE_PTR(handle);
return OG_ERROR;
}
ret = memcpy_s((void *)last_handle, sizeof(object_id_t), (void *)&handle[path_depth - 1], sizeof(object_id_t));
if (ret != EOK) {
CM_FREE_PTR(handle);
OG_THROW_ERROR(ERR_SYSTEM_CALL, ret);
OG_LOG_RUN_ERR("Secure C lib has thrown an error %d", ret);
return OG_ERROR;
}
CM_FREE_PTR(handle);
return OG_SUCCESS;
}
status_t cm_get_dbs_full_dir_handle(const char* path, const char* delim, object_id_t* handle_ids, int handle_len)
{
if (path == NULL || handle_ids == NULL || handle_len == 0) {
OG_LOG_RUN_ERR("get dbstor file path fd failed, invalid param.");
return OG_ERROR;
}
char* token = NULL;
char* context = NULL;
char file[OG_FILE_NAME_BUFFER_SIZE] = {0};
char fs_name[OG_FILE_NAME_BUFFER_SIZE] = {0};
int cur_depth = 0;
errno_t err = strcpy_sp(file, OG_MAX_FILE_NAME_LEN, path);
if (err != EOK) {
OG_THROW_ERROR(ERR_SYSTEM_CALL, err);
OG_LOG_RUN_ERR("Secure C lib has thrown an error %d", (err));
return OG_ERROR;
}
token = strtok_s(file, delim, &context);
while (token != NULL) {
if (cur_depth >= handle_len) {
OG_LOG_RUN_ERR("get dbstor file(%s) fd failed, fd len exceed (%d - %d).", path, handle_len, cur_depth);
return OG_ERROR;
}
if (cur_depth == 0) {
MEMS_RETURN_IFERR(strcpy_sp(fs_name, OG_MAX_FILE_NAME_LEN, token));
if (cm_get_dbs_root_dir_handle(fs_name, &handle_ids[cur_depth]) != OG_SUCCESS) {
OG_LOG_RUN_ERR("get dbstor fs(%s) root dir(%s) fd failed.", fs_name, token);
return OG_ERROR;
}
} else if (cur_depth <= handle_len - 1) {
if (cm_get_dbs_dir_handle(&handle_ids[cur_depth - 1], token, &handle_ids[cur_depth]) != OG_SUCCESS) {
OG_LOG_RUN_ERR("get dbstor fs(%s) dir(%s) fd failed.", fs_name, token);
return OG_ERROR;
}
}
cur_depth++;
token = strtok_s(NULL, delim, &context);
}
return OG_SUCCESS;
}
status_t cm_get_dbs_last_dir_handle(const char* file, object_id_t* last_handle)
{
errno_t ret = 0;
int path_depth = 0;
if (cm_get_file_path_depth(file, "/", &path_depth) != OG_SUCCESS) {
OG_LOG_RUN_ERR("get dbstor file(%s) path depth failed.", file);
return OG_ERROR;
}
object_id_t* handle = (object_id_t *)malloc((path_depth + 1) * sizeof(object_id_t));
if (handle == NULL) {
OG_THROW_ERROR(ERR_ALLOC_MEMORY, (uint64)((path_depth + 1) * sizeof(object_id_t)), "dbs file fd");
return OG_ERROR;
}
if (cm_get_dbs_full_dir_handle(file, "/", handle, path_depth) != OG_SUCCESS) {
OG_LOG_RUN_ERR("get dbstor file path fd failed, file %s, ret %d", file, ret);
CM_FREE_PTR(handle);
return OG_ERROR;
}
ret = memcpy_s((void *)last_handle, sizeof(object_id_t), (void *)&handle[path_depth - 1], sizeof(object_id_t));
if (ret != EOK) {
CM_FREE_PTR(handle);
OG_THROW_ERROR(ERR_SYSTEM_CALL, ret);
OG_LOG_RUN_ERR("Secure C lib has thrown an error %d", ret);
return OG_ERROR;
}
CM_FREE_PTR(handle);
return OG_SUCCESS;
}
status_t cm_rm_dbs_dir_file(object_id_t* phandle, char* name)
{
int ret = 0;
if (phandle == NULL || name == NULL) {
OG_LOG_RUN_ERR("delete dbstor file or dir failed, invalid param.");
return OG_ERROR;
}
ret = dbs_global_handle()->dbs_file_remove(phandle, name);
if (ret != 0) {
OG_LOG_RUN_ERR("Failed(%d) delete file or dir(%s).", ret, name);
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t cm_chmod_file(uint32 perm, int32 fd)
{
#ifndef WIN32
int32 err_no = fchmod(fd, perm);
if (err_no != 0) {
OG_THROW_ERROR(ERR_CREATE_FILE, "", err_no);
return OG_ERROR;
}
#endif
return OG_SUCCESS;
}
status_t cm_fopen(const char *filename, const char *mode, uint32 perm, FILE **fp)
{
*fp = fopen(filename, mode);
if (*fp == NULL) {
OG_THROW_ERROR(ERR_OPEN_FILE, filename, errno);
return OG_ERROR;
}
#ifndef WIN32
int32 err_no = fchmod(cm_fileno(*fp), perm);
if (err_no != 0) {
fclose(*fp);
*fp = NULL;
OG_THROW_ERROR(ERR_OPEN_FILE, filename, err_no);
return OG_ERROR;
}
#endif
return OG_SUCCESS;
}
status_t cm_open_file_ex(const char *file_name, uint32 mode, uint32 perm, int32 *file)
{
if (strlen(file_name) > OG_MAX_FILE_NAME_LEN) {
OG_THROW_ERROR(ERR_INVALID_FILE_NAME, file_name, (uint32)OG_MAX_FILE_NAME_LEN);
return OG_ERROR;
}
*file = open(file_name, (int)mode, perm);
if ((*file) == -1) {
if ((mode & O_CREAT) != 0) {
OG_THROW_ERROR(ERR_CREATE_FILE, file_name, errno);
} else {
OG_THROW_ERROR(ERR_OPEN_FILE, file_name, errno);
}
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t cm_create_file(const char *file_name, uint32 mode, int32 *file)
{
return cm_open_file(file_name, mode | O_CREAT | O_TRUNC, file);
}
void cm_close_file(int32 file)
{
int32 ret;
if (file == -1) {
return;
}
ret = close(file);
if (ret != 0) {
OG_LOG_RUN_ERR("failed to close file with handle %d, error code %d", file, errno);
}
}
status_t cm_read_file(int32 file, void *buf, int32 len, int32 *read_size)
{
int32 total_size = 0;
int32 curr_size = 0;
int32 size = len;
do {
curr_size = read(file, (char *)buf + total_size, size);
if (curr_size == -1) {
OG_THROW_ERROR(ERR_READ_FILE, errno);
OG_LOG_RUN_ERR("read failed:error code:%d,%s", errno, strerror(errno));
return OG_ERROR;
}
size -= curr_size;
total_size += curr_size;
} while (size > 0 && curr_size > 0);
if (read_size != NULL) {
*read_size = total_size;
}
return OG_SUCCESS;
}
int32 cm_read_dbs_file(object_id_t* handle, uint64 offset, void* buf, uint32 length)
{
int64 start = cm_now();
uint32 read_size = 0;
int32 ret = dbs_global_handle()->dbs_file_read(handle, offset, (char *)buf, length, &read_size);
if (ret != 0) {
OG_THROW_ERROR(ERR_READ_FILE, ret);
OG_LOG_RUN_ERR("cm_read_dbs_file offset:%llu len:%u failed.", offset, length);
return ret;
}
if (read_size != length) {
OG_LOG_RUN_ERR("cm_read_dbs_file offset:%llu len:%u read_size:%u failed.", offset, length, read_size);
return OG_ERROR;
}
int64 end = cm_now();
if (end - start > 50 * MICROSECS_PER_MILLISEC) {
OG_LOG_RUN_WAR_LIMIT(LOG_PRINT_INTERVAL_SECOND_20, "cm_read_dbs_file %u elapsed:%lld(ms)",
length, (end - start) / MICROSECS_PER_MILLISEC);
}
return ret;
}
status_t cm_write_dbs_file(object_id_t* handle, uint64 offset, void* buf, uint32 length)
{
int64 start = cm_now();
int32 ret = dbs_global_handle()->dbs_file_write(handle, offset, (char *)buf, length);
if (ret != 0) {
OG_THROW_ERROR(ERR_WRITE_FILE, ret);
OG_LOG_RUN_ERR("cm_write_dbs_file write offset:%llu len:%u failed.", offset, length);
return OG_ERROR;
}
int64 end = cm_now();
if (end - start > 50 * MICROSECS_PER_MILLISEC) {
OG_LOG_RUN_WAR_LIMIT(LOG_PRINT_INTERVAL_SECOND_20, "cm_write_dbs_file %u elapsed:%lld(ms)",
length, (end - start) / MICROSECS_PER_MILLISEC);
}
return OG_SUCCESS;
}
status_t cm_io_poll(int32 fd, uint32 wait_type, int32 timeout_ms)
{
struct pollfd fds = {0};
int32 tv = (timeout_ms < 0 ? -1 : timeout_ms);
fds.fd = fd;
fds.events = (wait_type == FILE_WAIT_FOR_READ ? POLLIN : POLLOUT);
fds.revents = 0;
int32 ret = poll(&fds, 1, tv);
if (ret <= 0) {
OG_LOG_RUN_WAR("listen fd(%d) event_type(%u) failed(%d) errno(%d).", fd, wait_type, ret, errno);
}
return (ret > 0 ? OG_SUCCESS : OG_ERROR);
}
status_t cm_read_file_try_timeout(const char* file_name, int32* fd, void *buf, int32 len, int32 timeout_ms)
{
int32 try_times = 0;
int32 cur_fd = *fd;
int32 read_size = 0;
int64 start_time = cm_now();
int64 timeo_us = (int64)(timeout_ms * MICROSECS_PER_MILLISEC);
status_t ret = OG_SUCCESS;
do {
ret = cm_io_poll(cur_fd, FILE_WAIT_FOR_READ, FILE_POLL_TIMEOUT_MS);
if (ret != OG_SUCCESS) {
if (++try_times >= OG_WRITE_TRY_TIMES) {
cm_reopen_file(cur_fd, file_name, &cur_fd);
}
cm_sleep(REOPEN_SLEEP_TIMES);
continue;
}
try_times = 0;
ret = cm_read_file(cur_fd, buf, len, &read_size);
if (ret != OG_SUCCESS) {
if (++try_times >= OG_WRITE_TRY_TIMES) {
cm_reopen_file(cur_fd, file_name, &cur_fd);
}
cm_sleep(REOPEN_SLEEP_TIMES);
continue;
}
try_times = 0;
} while (start_time + timeo_us >= cm_now() && ret != OG_SUCCESS);
if (read_size != len) {
OG_LOG_RUN_WAR("read file (%s) fd(%d-%d) size(%d) neq size(%d).", file_name, cur_fd, *fd, read_size, len);
}
*fd = cur_fd;
return ret;
}
status_t cm_write_file(int32 file, const void *buf, int32 size)
{
int32 write_size = 0;
int32 try_times = 0;
while (try_times < OG_WRITE_TRY_TIMES) {
write_size = write(file, buf, size);
if (write_size == 0) {
cm_sleep(5);
try_times++;
continue;
} else if (write_size == -1) {
OG_THROW_ERROR(ERR_WRITE_FILE, errno);
OG_LOG_RUN_ERR("write failed:error code:%d,%s", errno, strerror(errno));
return OG_ERROR;
} else {
break;
}
}
if (write_size != size) {
OG_THROW_ERROR(ERR_WRITE_FILE_PART_FINISH, write_size, size);
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t cm_query_dir(const char *name, void *file_list, uint32 *file_num)
{
DIR *dir = opendir(name);
if (dir == NULL) {
OG_LOG_RUN_ERR("Failed to open directory: %s.", name);
return OG_ERROR;
}
cm_file_info *list = (cm_file_info *)file_list;
int32 ret;
uint32 num = 0;
struct dirent *entry;
struct stat entry_stat;
while ((entry = readdir(dir)) != NULL) {
if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) {
continue;
}
char full_path[OG_MAX_FILE_PATH_LENGH] = {0};
ret = snprintf_s(full_path, OG_MAX_FILE_PATH_LENGH, OG_MAX_FILE_PATH_LENGH - 1, "%s/%s", name, entry->d_name);
if (ret == -1) {
OG_LOG_RUN_ERR("Failed to strcat name to full path, the dir is %s, file name is %s.", name, entry->d_name);
(void)closedir(dir);
return OG_ERROR;
}
OG_LOG_RUN_INF("full path is %s.", full_path);
if (stat(full_path, &entry_stat) != 0) {
continue;
}
if (S_ISDIR(entry_stat.st_mode)) {
list[num].type = FILE_TYPE_DIR;
} else {
list[num].type = FILE_TYPE_FILE;
}
ret = strncpy_sp(list[num].file_name, CM_FILE_MAX_NAME_LEN, entry->d_name, strlen(entry->d_name));
if (ret != EOK) {
OG_LOG_RUN_ERR("Failed to copy name to file list, the dir is %s, file name is %s.", name, entry->d_name);
(void)closedir(dir);
return OG_ERROR;
}
num++;
}
*file_num = num;
(void)closedir(dir);
return OG_SUCCESS;
}
status_t cm_query_file_num(const char *name, uint32 *file_num)
{
DIR *dir = opendir(name);
if (dir == NULL) {
OG_LOG_RUN_ERR("Failed to open directory: %s.", name);
return OG_ERROR;
}
uint32 num = 0;
struct dirent *entry;
while ((entry = readdir(dir)) != NULL) {
if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) {
continue;
}
num++;
}
*file_num = num;
(void)closedir(dir);
return OG_SUCCESS;
}
status_t cm_pread_file(int32 file, void *buf, int length, int64 i_offset, int32 *read_size)
{
#ifdef WIN32
if (cm_seek_file(file, offset, SEEK_SET) != offset) {
OG_THROW_ERROR(ERR_SEEK_FILE, offset, SEEK_SET, errno);
return OG_ERROR;
}
if (cm_read_file(file, buf, size, read_size) != OG_SUCCESS) {
return OG_ERROR;
}
#else
int32 curr_size;
int32 total_size = 0;
int64 offset = i_offset;
int size = length;
do {
curr_size = pread64(file, (char *)buf + total_size, size, offset);
if (curr_size == -1) {
OG_THROW_ERROR(ERR_READ_FILE, errno);
return OG_ERROR;
}
total_size += curr_size;
offset += curr_size;
size -= curr_size;
} while (size > 0 && curr_size > 0);
if (read_size != NULL) {
*read_size = total_size;
}
#endif
return OG_SUCCESS;
}
status_t cm_pwrite_file(int32 file, const char *buf, int32 size, int64 offset)
{
#ifdef WIN32
if (cm_seek_file(file, offset, SEEK_SET) != offset) {
OG_THROW_ERROR(ERR_SEEK_FILE, offset, SEEK_SET, errno);
return OG_ERROR;
}
if (cm_write_file(file, buf, size) != OG_SUCCESS) {
return OG_ERROR;
}
#else
int32 write_size;
int32 try_times = 0;
while (try_times < OG_WRITE_TRY_TIMES) {
write_size = pwrite64(file, buf, size, offset);
if (write_size == 0) {
cm_sleep(5);
try_times++;
continue;
} else if (write_size == -1) {
OG_THROW_ERROR(ERR_WRITE_FILE, errno);
return OG_ERROR;
} else {
break;
}
}
if (write_size != size) {
OG_THROW_ERROR(ERR_WRITE_FILE_PART_FINISH, write_size, size);
return OG_ERROR;
}
#endif
return OG_SUCCESS;
}
int64 cm_seek_file(int32 file, int64 offset, int32 origin)
{
return (int64)lseek64(file, (off64_t)offset, origin);
}
status_t cm_check_file(const char *name, int64 size)
{
int32 file;
if (cm_open_file(name, O_BINARY | O_RDONLY, &file) != OG_SUCCESS) {
return OG_ERROR;
}
if (size != cm_seek_file(file, 0, SEEK_END)) {
cm_close_file(file);
OG_THROW_ERROR(ERR_SEEK_FILE, 0, SEEK_SET, errno);
return OG_ERROR;
}
cm_close_file(file);
return OG_SUCCESS;
}
status_t cm_create_dir(const char *dir_name)
{
if (make_dir(dir_name, S_IRWXU) != 0) {
OG_THROW_ERROR(ERR_CREATE_DIR, dir_name, errno);
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t cm_rename_file(const char *src, const char *dst)
{
#ifdef WIN32
uint32 loop = 0;
while (!MoveFileEx(src, dst, MOVEFILE_REPLACE_EXISTING)) {
DWORD err = GetLastError();
if ((err == ERROR_ACCESS_DENIED ||
err == ERROR_SHARING_VIOLATION ||
err == ERROR_LOCK_VIOLATION) && ++loop <= RENAME_DEFAULT_RETRYS) {
cm_sleep(RENAME_SLEEP_TIMES);
continue;
}
OG_THROW_ERROR(ERR_RENAME_FILE, src, dst, err);
#else
if (rename(src, dst) != 0) {
OG_THROW_ERROR(ERR_RENAME_FILE, src, dst, errno);
#endif
return OG_ERROR;
}
return OG_SUCCESS;
}
static void cm_get_parent_dir(char *path, uint32 len)
{
char *p = NULL;
if (len == 0) {
return;
}
path = cm_skip_drive(path);
if (path[0] == '\0') {
return;
}
for (p = path + strlen(path) - 1; IS_DIR_SEPARATOR(*p) && p > path; p--) {
;
}
for (; !IS_DIR_SEPARATOR(*p) && p > path; p--) {
;
}
for (; p > path && IS_DIR_SEPARATOR(*(p - 1)); p--) {
;
}
if (p == path && IS_DIR_SEPARATOR(*p)) {
p++;
}
*p = '\0';
}
static status_t cm_fsync_file_ex(const char *file, bool32 isdir)
{
int32 flags = O_BINARY;
flags |= (!isdir) ? O_RDWR : O_RDONLY;
int32 fd = open(file, flags, 0);
if (fd < 0 && isdir && (errno == EISDIR || errno == EACCES)) {
return OG_SUCCESS;
} else if (fd < 0) {
OG_THROW_ERROR(ERR_OPEN_FILE, file, errno);
return OG_ERROR;
}
if (cm_fsync_file(fd) != OG_SUCCESS && !(isdir && (errno == EBADF || errno == EINVAL))) {
close(fd);
return OG_ERROR;
}
close(fd);
return OG_SUCCESS;
}
static status_t cm_fsync_parent_path(const char *fname)
{
char parentpath[OG_FILE_NAME_BUFFER_SIZE] = {0};
int32 ret = strncpy_s(parentpath, sizeof(parentpath), fname, strlen(fname));
if (ret != EOK) {
OG_THROW_ERROR(ERR_SYSTEM_CALL, ret);
return OG_ERROR;
}
cm_get_parent_dir(parentpath, (uint32)strlen(parentpath));
if (strlen(parentpath) == 0) {
parentpath[0] = '.';
parentpath[1] = '\0';
}
if (cm_fsync_file_ex(parentpath, OG_TRUE) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t cm_rename_file_durably(const char *src, const char *dst)
{
if (cm_fsync_file_ex(src, OG_FALSE) != OG_SUCCESS) {
return OG_ERROR;
}
if (rename(src, dst) != 0) {
OG_THROW_ERROR(ERR_RENAME_FILE, src, dst, errno);
return OG_ERROR;
}
if (cm_fsync_file_ex(dst, OG_FALSE) != OG_SUCCESS) {
return OG_ERROR;
}
if (cm_fsync_parent_path(dst) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t cm_copy_file_ex(const char *src, const char *dst, char *buf, uint32 buffer_size, bool32 over_write)
{
int32 src_file;
int32 dst_file;
int32 data_size;
uint32 mode;
if (cm_open_file(src, O_RDONLY | O_BINARY, &src_file) != OG_SUCCESS) {
return OG_ERROR;
}
int64 file_size = cm_file_size(src_file);
if (file_size < 0 || file_size > buffer_size) {
cm_close_file(src_file);
OG_THROW_ERROR(ERR_FILE_SIZE_MISMATCH, file_size, (uint64)buffer_size);
return OG_ERROR;
}
if (cm_seek_file(src_file, 0, SEEK_SET) != 0) {
cm_close_file(src_file);
OG_LOG_RUN_ERR("seek file failed :%s.", src);
return OG_ERROR;
}
mode = over_write ? O_RDWR | O_BINARY | O_SYNC : O_RDWR | O_BINARY | O_EXCL | O_SYNC;
if (cm_create_file(dst, mode, &dst_file) != OG_SUCCESS) {
cm_close_file(src_file);
return OG_ERROR;
}
if (cm_seek_file(dst_file, 0, SEEK_SET) != 0) {
cm_close_file(src_file);
cm_close_file(dst_file);
OG_LOG_RUN_ERR("seek file failed :%s.", dst);
return OG_ERROR;
}
if (cm_read_file(src_file, buf, (int32)buffer_size, &data_size) != OG_SUCCESS) {
cm_close_file(src_file);
cm_close_file(dst_file);
return OG_ERROR;
}
while (data_size > 0) {
if (cm_write_file(dst_file, buf, data_size) != OG_SUCCESS) {
cm_close_file(src_file);
cm_close_file(dst_file);
return OG_ERROR;
}
if (cm_read_file(src_file, buf, (int32)buffer_size, &data_size) != OG_SUCCESS) {
cm_close_file(src_file);
cm_close_file(dst_file);
return OG_ERROR;
}
}
cm_close_file(src_file);
cm_close_file(dst_file);
return OG_SUCCESS;
}
status_t cm_copy_file(const char *src, const char *dst, bool32 over_write)
{
errno_t rc_memzero;
char *buf = (char *)malloc(OG_WRITE_BUFFER_SIZE);
if (buf == NULL) {
OG_THROW_ERROR(ERR_ALLOC_MEMORY, (uint64)OG_WRITE_BUFFER_SIZE, "copying file");
return OG_ERROR;
}
rc_memzero = memset_sp(buf, (uint32)OG_WRITE_BUFFER_SIZE, 0, (uint32)OG_WRITE_BUFFER_SIZE);
if (rc_memzero != EOK) {
CM_FREE_PTR(buf);
OG_THROW_ERROR(ERR_RESET_MEMORY, "buf");
return OG_ERROR;
}
status_t status = cm_copy_file_ex(src, dst, buf, OG_WRITE_BUFFER_SIZE, over_write);
CM_FREE_PTR(buf);
return status;
}
status_t cm_remove_file(const char *file_name)
{
if (remove(file_name) != 0) {
OG_LOG_RUN_ERR("remove file %s failed, error code %d.", file_name, errno);
OG_THROW_ERROR(ERR_REMOVE_FILE, file_name, errno);
return OG_ERROR;
}
return OG_SUCCESS;
}
#ifndef WIN32
status_t cm_remove_dir(const char *path)
{
struct dirent *dirp = NULL;
char *cwdir = getcwd(NULL, 0);
if (cwdir == NULL) {
OG_LOG_RUN_ERR("get current work directory failed, error code %d.", errno);
return OG_ERROR;
}
DIR *dir = opendir(path);
if (dir == NULL) {
free(cwdir);
OG_LOG_RUN_ERR("open directory %s failed, error code %d", path, errno);
return OG_ERROR;
}
if (chdir(path) == -1) {
free(cwdir);
(void)closedir(dir);
OG_LOG_RUN_ERR("change current work directory to %s failed, error code %d.", path, errno);
return OG_ERROR;
}
while ((dirp = readdir(dir)) != NULL) {
if ((strcmp(dirp->d_name, ".") == 0) || (strcmp(dirp->d_name, "..") == 0)) {
continue;
}
if (cm_dir_exist(dirp->d_name)) {
if (cm_remove_dir(dirp->d_name) == OG_SUCCESS) {
continue;
}
(void)closedir(dir);
free(cwdir);
return OG_ERROR;
}
if (cm_remove_file(dirp->d_name) != OG_SUCCESS) {
(void)closedir(dir);
free(cwdir);
return OG_ERROR;
}
}
(void)closedir(dir);
if (chdir(cwdir) == -1) {
OG_LOG_RUN_ERR("change current work directory to %s failed, error code %d.", cwdir, errno);
free(cwdir);
return OG_ERROR;
}
free(cwdir);
return(cm_remove_file(path));
}
#endif
bool32 cm_file_exist(const char *file_path)
{
int32 fd = open(file_path, O_RDONLY);
if (fd == -1) {
return OG_FALSE;
}
close(fd);
return OG_TRUE;
}
bool32 cm_dir_exist(const char *dir_path)
{
int32 ret;
#ifdef WIN32
struct _stat stat_buf;
#else
struct stat stat_buf;
#endif
#ifdef WIN32
ret = _stat(dir_path, &stat_buf);
#else
ret = stat(dir_path, &stat_buf);
#endif
if (ret != 0) {
return OG_FALSE;
}
#ifdef WIN32
if (_S_IFDIR == (stat_buf.st_mode & _S_IFDIR)) {
#else
if (S_ISDIR(stat_buf.st_mode)) {
#endif
return OG_TRUE;
}
return OG_FALSE;
}
bool32 cm_check_exist_special_char(const char *dir_path, uint32 size)
{
uint32 i;
uint32 j;
char special_char[9] = { '|', ';', '&', '$', '>', '<', '`', '!', '\n'};
for (i = 0; i < size; i++) {
for (j = 0; j < 9; j++) {
if (dir_path[i] == special_char[j]) {
return OG_TRUE;
}
}
}
return OG_FALSE;
}
bool32 cm_check_uds_path_special_char(const char *dir_path, uint32 size)
{
uint32 i;
uint32 j;
char special_char[10] = { '|', ';', '&', '$', '>', '<', '`', '!', '\n', '%'};
for (i = 0; i < size; i++) {
for (j = 0; j < 10; j++) {
if (dir_path[i] == special_char[j]) {
return OG_TRUE;
}
}
}
return OG_FALSE;
}
void cm_trim_dir(const char *file_name, uint32 size, char *buf)
{
int32 i;
uint32 len;
errno_t errcode = 0;
len = (uint32)strlen(file_name);
if (len == 0) {
buf[0] = '\0';
return;
}
for (i = (int32)len - 1; i >= 0; i--) {
if (file_name[i] == '\\' || file_name[i] == '/') {
break;
}
}
if (i == (int32)len - 1) {
buf[0] = '\0';
return;
} else if (i < 0) {
errcode = strncpy_s(buf, (size_t)size, file_name, (size_t)len);
if (errcode != EOK) {
OG_THROW_ERROR(ERR_SYSTEM_CALL, errcode);
return;
}
return;
}
errcode = strncpy_s(buf, (size_t)size, file_name + i + 1, (size_t)(len - (uint32)i - 1));
if (errcode != EOK) {
OG_THROW_ERROR(ERR_SYSTEM_CALL, errcode);
return;
}
return;
}
void cm_trim_filename(const char *file_name, uint32 size, char *buf)
{
int32 i;
uint32 len;
len = (uint32)strlen(file_name);
if (len == 0) {
buf[0] = '\0';
return;
}
errno_t errcode = strncpy_s(buf, (size_t)size, file_name, (size_t)len);
if (errcode != EOK) {
OG_THROW_ERROR(ERR_SYSTEM_CALL, errcode);
return;
}
len = (uint32)strlen(buf);
for (i = (int32)len - 1; i >= 0; i--) {
if (buf[i] == '\\' || buf[i] == '/') {
buf[i + 1] = '\0';
break;
}
}
}
* trim serial character '\' or '/' in the right of home path
* etc. transform /home/oGRAC/ to /home/oGRAC
*/
void cm_trim_home_path(char *home_path, uint32 len)
{
int32 i;
for (i = (int32)len - 1; i >= 0; i--) {
if (home_path[i] == '\\' || home_path[i] == '/') {
home_path[i] = '\0';
} else {
break;
}
}
}
status_t cm_access_file(const char *file_name, uint32 mode)
{
if (access(file_name, mode) != 0) {
OG_THROW_ERROR(ERR_FILE_ACCESS, errno);
return OG_ERROR;
}
return OG_SUCCESS;
}
bool32 cm_filename_equal(const text_t *text, const char *str)
{
#ifdef WIN32
return cm_text_str_equal_ins(text, str);
#else
return cm_text_str_equal(text, str);
#endif
}
status_t cm_create_dir_ex(const char *dir_name)
{
char dir[OG_MAX_FILE_NAME_LEN + 1];
size_t dir_len = strlen(dir_name);
uint32 i;
errno_t errcode = strncpy_s(dir, (size_t)OG_MAX_FILE_NAME_LEN, dir_name, (size_t)dir_len);
if (errcode != EOK) {
OG_THROW_ERROR(ERR_SYSTEM_CALL, errcode);
return OG_ERROR;
}
if (dir[dir_len - 1] != '\\' && dir[dir_len - 1] != '/') {
dir[dir_len] = '/';
dir_len++;
dir[dir_len] = '\0';
}
for (i = 0; i < dir_len; i++) {
if (dir[i] == '\\' || dir[i] == '/') {
if (i == 0) {
continue;
}
dir[i] = '\0';
if (cm_dir_exist(dir)) {
dir[i] = '/';
continue;
}
if (cm_create_dir(dir) != OG_SUCCESS) {
return OG_ERROR;
}
dir[i] = '/';
}
}
return OG_SUCCESS;
}
status_t cm_truncate_file(int32 fd, int64 offset)
{
#ifdef WIN32
if (_chsize_s(fd, offset) != 0) {
#else
if (ftruncate(fd, offset) != 0) {
#endif
OG_THROW_ERROR(ERR_TRUNCATE_FILE, offset, errno);
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t cm_fallocate_file(int32 fd, int32 mode, int64 offset, int64 len)
{
#ifdef WIN32
OG_LOG_RUN_ERR("fallocate not support on WINDOWS");
return OG_ERROR;
#else
if (fallocate(fd, mode, offset, len) != 0) {
OG_LOG_RUN_ERR("Failed to fallocate the file, mode: %d, offset: %lld, length: %lld, error code %d.", mode,
offset, len, errno);
OG_THROW_ERROR(ERR_FALLOCATE_FILE, errno);
return OG_ERROR;
}
return OG_SUCCESS;
#endif
}
status_t cm_lock_fd(int32 fd)
{
#ifdef WIN32
return OG_SUCCESS;
#else
struct flock lk;
lk.l_type = F_WRLCK;
lk.l_whence = SEEK_SET;
lk.l_start = lk.l_len = 0;
if (fcntl(fd, F_SETLK, &lk) != 0) {
OG_THROW_ERROR(ERR_LOCK_FILE, errno);
return OG_ERROR;
}
return OG_SUCCESS;
#endif
}
status_t cm_unlock_fd(int32 fd)
{
#ifdef WIN32
return OG_SUCCESS;
#else
struct flock lk;
lk.l_type = F_UNLCK;
lk.l_whence = SEEK_SET;
lk.l_start = lk.l_len = 0;
if (fcntl(fd, F_SETLK, &lk) != 0) {
OG_THROW_ERROR(ERR_UNLOCK_FILE, errno);
return OG_ERROR;
}
return OG_SUCCESS;
#endif
}
void cm_show_lock_info(int32 fd)
{
#ifndef WIN32
struct flock lk;
if (fcntl(fd, F_GETLK, &lk) == 0) {
OG_LOG_RUN_INF("The fd(%d) has been locked by process(%d) with type(%d).", fd, lk.l_pid, lk.l_type);
} else {
OG_LOG_RUN_WAR("Failed to get lock info by fd(%d), error code %d.", fd, errno);
}
#endif
}
uint32 cm_file_permissions(uint16 val)
{
uint16 usr_perm;
uint16 grp_perm;
uint16 oth_perm;
uint32 file_perm = 0;
usr_perm = (val / 100) % 10;
if (usr_perm & 1) {
file_perm |= S_IXUSR;
}
if (usr_perm & 2) {
file_perm |= S_IWUSR;
}
if (usr_perm & 4) {
file_perm |= S_IRUSR;
}
grp_perm = (val / 10) % 10;
if (grp_perm & 1) {
file_perm |= S_IXGRP;
}
if (grp_perm & 2) {
file_perm |= S_IWGRP;
}
if (grp_perm & 4) {
file_perm |= S_IRGRP;
}
oth_perm = val % 10;
if (oth_perm & 1) {
file_perm |= S_IXOTH;
}
if (oth_perm & 2) {
file_perm |= S_IWOTH;
}
if (oth_perm & 4) {
file_perm |= S_IROTH;
}
return file_perm;
}
#ifndef WIN32
status_t cm_verify_file_host(char *realfile)
{
char file_host[OG_FILE_NAME_BUFFER_SIZE];
if (cm_get_file_host_name(realfile, file_host) != OG_SUCCESS) {
return OG_ERROR;
}
if (!cm_str_equal(file_host, cm_sys_user_name())) {
return OG_ERROR;
}
return OG_SUCCESS;
}
#endif
void cm_get_filesize(const char *filename, int64 *filesize)
{
struct stat statbuf;
stat(filename, &statbuf);
*filesize = statbuf.st_size;
}
#define MAX_DUMP_ROW_SIZE 400
void cm_dump(cm_dump_t *dump, const char *str, ...)
{
uint32 size_left = dump->buf_size - dump->offset;
uint32 msg_size = MIN(size_left, MAX_DUMP_ROW_SIZE);
va_list args;
char *msg = dump->buf + dump->offset;
va_start(args, str);
int ret = vsnprintf_s(msg, msg_size, msg_size - 1, str, args);
va_end(args);
if (ret < 0) {
OG_THROW_ERROR(ERR_SYSTEM_CALL, ret);
return;
}
dump->offset += (uint32)strlen(msg);
}
status_t cm_dump_flush(cm_dump_t *dump)
{
if (cm_write_file(dump->handle, dump->buf, dump->offset) != OG_SUCCESS) {
return OG_ERROR;
}
dump->offset = 0;
return OG_SUCCESS;
}
status_t cm_file_punch_hole(int32 handle, uint64 offset, int len)
{
return cm_fallocate_file(handle, CM_FALLOC_PUNCH_HOLE | CM_FALLOC_KEEP_SIZE, offset, len);
}
status_t cm_file_get_status(const char *path, struct stat *stat_info)
{
#ifdef WIN32
OG_LOG_RUN_ERR("stat not support on WINDOWS");
return OG_ERROR;
#else
int ret = stat(path, stat_info);
if (ret && (errno == ENOENT || errno == ENOTDIR)) {
OG_THROW_ERROR(ERR_FILE_NOT_EXIST, "stat", "specifical");
return OG_ERROR;
} else if (ret) {
OG_THROW_ERROR(ERR_READ_FILE, errno);
return OG_ERROR;
}
return OG_SUCCESS;
#endif
}
#ifdef __cplusplus
}
#endif