* Copyright (c) 2022 Huawei Technologies Co.,Ltd.
*
* CBB 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/cm_utils/cm_file.c
*
* -------------------------------------------------------------------------
*/
#include "cm_file.h"
#include "cm_log.h"
#include "cm_profile_stat.h"
#ifdef WIN32
#else
#include <string.h>
#include <unistd.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
#define GS_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) {
CM_THROW_ERROR(ERR_DATAFILE_FSYNC, errno);
return CM_ERROR;
}
#endif
return CM_SUCCESS;
}
status_t cm_fdatasync_file(int32 file)
{
#ifndef WIN32
if (fdatasync(file) != 0) {
CM_THROW_ERROR(ERR_DATAFILE_FDATASYNC, errno);
return CM_ERROR;
}
#endif
return CM_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) > CM_FULL_PATH_BUFFER_SIZE) {
CM_THROW_ERROR(ERR_INVALID_FILE_NAME, file_name, (uint32)CM_FULL_PATH_BUFFER_SIZE);
return CM_ERROR;
}
*file = open(file_name, (int)mode, perm);
if ((*file) == -1) {
if ((mode & O_CREAT) != 0) {
CM_THROW_ERROR(ERR_CREATE_FILE, file_name, errno);
} else {
CM_THROW_ERROR(ERR_OPEN_FILE, file_name, errno);
}
return CM_ERROR;
}
return CM_SUCCESS;
}
status_t cm_chmod_file(uint32 perm, int32 fd)
{
#ifndef WIN32
int32 err_no = fchmod(fd, perm);
if (err_no != 0) {
CM_THROW_ERROR(ERR_CREATE_FILE, "", err_no);
return CM_ERROR;
}
#endif
return CM_SUCCESS;
}
status_t cm_fopen(const char *filename, const char *mode, uint32 perm, FILE **fp)
{
*fp = fopen(filename, mode);
if (*fp == NULL) {
CM_THROW_ERROR(ERR_OPEN_FILE, filename, errno);
return CM_ERROR;
}
#ifndef WIN32
int32 err_no = fchmod(cm_fileno(*fp), perm);
if (err_no != 0) {
(void)fclose(*fp);
*fp = NULL;
CM_THROW_ERROR(ERR_OPEN_FILE, filename, err_no);
return CM_ERROR;
}
#endif
return CM_SUCCESS;
}
status_t cm_open_file_ex(const char *file_name, uint32 mode, uint32 perm, int32 *file)
{
if (strlen(file_name) > CM_MAX_FILE_NAME_LEN) {
CM_THROW_ERROR(ERR_INVALID_FILE_NAME, file_name, (uint32)CM_MAX_FILE_NAME_LEN);
return CM_ERROR;
}
*file = open(file_name, (int)mode, perm);
if ((*file) == -1) {
if ((mode & O_CREAT) != 0) {
CM_THROW_ERROR(ERR_CREATE_FILE, file_name, errno);
} else {
CM_THROW_ERROR(ERR_OPEN_FILE, file_name, errno);
}
return CM_ERROR;
}
return CM_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) {
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 size, int32 *read_size)
{
int32 total_size = 0;
int32 curr_size;
do {
curr_size = read(file, (char *)buf + total_size, size);
if (curr_size == -1) {
CM_THROW_ERROR(ERR_READ_FILE, errno);
return CM_ERROR;
}
size -= curr_size;
total_size += curr_size;
} while (size > 0 && curr_size > 0);
if (read_size != NULL) {
*read_size = total_size;
}
return CM_SUCCESS;
}
status_t cm_write_file(int32 file, const void *buf, int32 size)
{
int32 write_size = 0;
int32 try_times = 0;
while (try_times < CM_WRITE_TRY_TIMES) {
write_size = write(file, buf, size);
if (write_size == 0) {
cm_sleep(5);
try_times++;
continue;
} else if (write_size == -1) {
CM_THROW_ERROR(ERR_WRITE_FILE, errno);
LOG_DEBUG_ERR("write file failed, errno = %d", errno);
return CM_ERROR;
} else {
break;
}
}
if (write_size != size) {
CM_THROW_ERROR(ERR_WRITE_FILE_PART_FINISH, write_size, size);
LOG_DEBUG_ERR("write file(part write) failed, errno = %d", errno);
return CM_ERROR;
}
return CM_SUCCESS;
}
status_t cm_pread_file(int32 file, void *buf, int size, int64 offset, int32 *read_size)
{
#ifdef WIN32
if (cm_seek_file(file, offset, SEEK_SET) != offset) {
CM_THROW_ERROR(ERR_SEEK_FILE, offset, SEEK_SET, errno);
return CM_ERROR;
}
if (cm_read_file(file, buf, size, read_size) != CM_SUCCESS) {
return CM_ERROR;
}
#else
int32 curr_size;
int32 total_size = 0;
do {
curr_size = pread64(file, (char *)buf + total_size, size, offset);
if (curr_size == -1) {
CM_THROW_ERROR(ERR_READ_FILE, errno);
return CM_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 CM_SUCCESS;
}
typedef struct st_disk_perf_t {
uint64 delay;
uint64 count;
uint64 size;
} disk_perf_t;
disk_perf_t g_disk_perf;
void cm_get_disk_delay(uint64 *delay, uint64 *count, uint64 *size)
{
static disk_perf_t pre_stat = {0};
disk_perf_t cur_stat = g_disk_perf;
*delay = cur_stat.delay - pre_stat.delay;
*count = cur_stat.count - pre_stat.count;
*size = cur_stat.size - pre_stat.size;
pre_stat = cur_stat;
}
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) {
CM_THROW_ERROR(ERR_SEEK_FILE, offset, SEEK_SET, errno);
return CM_ERROR;
}
if (cm_write_file(file, buf, size) != CM_SUCCESS) {
return CM_ERROR;
}
#else
int32 write_size;
int32 try_times = 0;
while (try_times < CM_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) {
CM_THROW_ERROR(ERR_WRITE_FILE, errno);
return CM_ERROR;
} else {
break;
}
}
if (write_size != size) {
CM_THROW_ERROR(ERR_WRITE_FILE_PART_FINISH, write_size, size);
return CM_ERROR;
}
#endif
return CM_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) != CM_SUCCESS) {
return CM_ERROR;
}
if (size != cm_seek_file(file, 0, SEEK_END)) {
cm_close_file(file);
CM_THROW_ERROR(ERR_SEEK_FILE, 0, SEEK_SET, errno);
return CM_ERROR;
}
cm_close_file(file);
return CM_SUCCESS;
}
status_t cm_create_dir(const char *dir_name)
{
if (make_dir(dir_name, S_IRWXU) != 0 && errno != EEXIST) {
CM_THROW_ERROR(ERR_CREATE_DIR, dir_name, errno);
return CM_ERROR;
}
return CM_SUCCESS;
}
status_t cm_rename_file(const char *src, const char *dst)
{
if (rename(src, dst) != 0) {
CM_THROW_ERROR(ERR_RENAME_FILE, src, dst, errno);
return CM_ERROR;
}
return CM_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)
{
uint32 flags = O_BINARY;
flags |= (!isdir) ? O_RDWR : O_RDONLY;
int32 fd = open(file, (int32)flags, 0);
if (fd < 0 && isdir && (errno == EISDIR || errno == EACCES)) {
return CM_SUCCESS;
} else if (fd < 0) {
CM_THROW_ERROR(ERR_OPEN_FILE, file, errno);
return CM_ERROR;
}
if (cm_fsync_file(fd) != CM_SUCCESS && !(isdir && (errno == EBADF || errno == EINVAL))) {
(void)close(fd);
return CM_ERROR;
}
(void)close(fd);
return CM_SUCCESS;
}
static status_t cm_fsync_parent_path(const char *fname)
{
char parentpath[CM_FILE_NAME_BUFFER_SIZE] = {0};
int32 ret = strncpy_s(parentpath, sizeof(parentpath), fname, strlen(fname));
if (ret != EOK) {
CM_THROW_ERROR(ERR_SYSTEM_CALL, ret);
return CM_ERROR;
}
cm_get_parent_dir(parentpath, (uint32)strlen(parentpath));
if (strlen(parentpath) == 0) {
parentpath[0] = '.';
parentpath[1] = '\0';
}
if (cm_fsync_file_ex(parentpath, CM_TRUE) != CM_SUCCESS) {
return CM_ERROR;
}
return CM_SUCCESS;
}
status_t cm_rename_file_durably(const char *src, const char *dst)
{
if (cm_fsync_file_ex(src, CM_FALSE) != CM_SUCCESS) {
return CM_ERROR;
}
if (rename(src, dst) != 0) {
CM_THROW_ERROR(ERR_RENAME_FILE, src, dst, errno);
return CM_ERROR;
}
if (cm_fsync_file_ex(dst, CM_FALSE) != CM_SUCCESS) {
return CM_ERROR;
}
if (cm_fsync_parent_path(dst) != CM_SUCCESS) {
return CM_ERROR;
}
return CM_SUCCESS;
}
status_t cm_copy_file_ex(const char *src, const char *dst, char *buf, uint32 buffer_size, bool32 over_write)
{
int32 src_file, dst_file, data_size;
uint32 mode;
if (cm_open_file(src, O_RDONLY | O_BINARY, &src_file) != CM_SUCCESS) {
return CM_ERROR;
}
int64 file_size = cm_file_size(src_file);
if (file_size < 0 || file_size > buffer_size) {
cm_close_file(src_file);
CM_THROW_ERROR(ERR_FILE_SIZE_MISMATCH, file_size, (uint64)buffer_size);
return CM_ERROR;
}
if (cm_seek_file(src_file, 0, SEEK_SET) != 0) {
cm_close_file(src_file);
LOG_RUN_ERR("seek file failed :%s.", src);
return CM_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) != CM_SUCCESS) {
cm_close_file(src_file);
return CM_ERROR;
}
if (cm_seek_file(dst_file, 0, SEEK_SET) != 0) {
cm_close_file(src_file);
cm_close_file(dst_file);
LOG_RUN_ERR("seek file failed :%s.", dst);
return CM_ERROR;
}
if (cm_read_file(src_file, buf, (int32)buffer_size, &data_size) != CM_SUCCESS) {
cm_close_file(src_file);
cm_close_file(dst_file);
return CM_ERROR;
}
while (data_size > 0) {
if (cm_write_file(dst_file, buf, data_size) != CM_SUCCESS) {
cm_close_file(src_file);
cm_close_file(dst_file);
return CM_ERROR;
}
if (cm_read_file(src_file, buf, (int32)buffer_size, &data_size) != CM_SUCCESS) {
cm_close_file(src_file);
cm_close_file(dst_file);
return CM_ERROR;
}
}
cm_close_file(src_file);
cm_close_file(dst_file);
return CM_SUCCESS;
}
status_t cm_copy_file(const char *src, const char *dst, bool32 over_write)
{
errno_t rc_memzero;
char *buf = (char *)cm_malloc_prot(GS_WRITE_BUFFER_SIZE);
if (buf == NULL) {
CM_THROW_ERROR(ERR_ALLOC_MEMORY, (uint64)GS_WRITE_BUFFER_SIZE, "copying file");
return CM_ERROR;
}
rc_memzero = memset_sp(buf, (uint32)GS_WRITE_BUFFER_SIZE, 0, (uint32)GS_WRITE_BUFFER_SIZE);
if (rc_memzero != EOK) {
CM_FREE_PROT_PTR(buf);
CM_THROW_ERROR(ERR_RESET_MEMORY, "buf");
return CM_ERROR;
}
status_t status = cm_copy_file_ex(src, dst, buf, GS_WRITE_BUFFER_SIZE, over_write);
CM_FREE_PROT_PTR(buf);
return status;
}
status_t cm_remove_file(const char *file_name)
{
if (remove(file_name) != 0) {
CM_THROW_ERROR(ERR_REMOVE_FILE, file_name, errno);
return CM_ERROR;
}
return CM_SUCCESS;
}
status_t cm_unlink_file(const char *file_name)
{
if (__unlink(file_name) != 0) {
CM_THROW_ERROR(ERR_REMOVE_FILE, file_name, errno);
return CM_ERROR;
}
return CM_SUCCESS;
}
bool32 cm_file_exist(const char *file_path)
{
int32 ret;
#ifdef WIN32
struct _stat stat_buf;
#else
struct stat stat_buf;
#endif
#ifdef WIN32
ret = _stat(file_path, &stat_buf);
#else
ret = stat(file_path, &stat_buf);
#endif
if (ret != 0) {
return CM_FALSE;
}
#ifdef WIN32
if (_S_IFREG == (stat_buf.st_mode & _S_IFREG)) {
#else
if (S_ISREG(stat_buf.st_mode)) {
#endif
return CM_TRUE;
}
return CM_FALSE;
}
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 CM_FALSE;
}
#ifdef WIN32
if (_S_IFDIR == (stat_buf.st_mode & _S_IFDIR)) {
#else
if (S_ISDIR(stat_buf.st_mode)) {
#endif
return CM_TRUE;
}
return CM_FALSE;
}
#define CM_PATH_SPECIAL_CHAR_NUM 9
bool32 cm_check_exist_special_char(const char *dir_path, uint32 size)
{
uint32 i, j;
char special_char[CM_PATH_SPECIAL_CHAR_NUM] = { '|', ';', '&', '$', '>', '<', '`', '!', '\n'};
for (i = 0; i < size; i++) {
for (j = 0; j < CM_PATH_SPECIAL_CHAR_NUM; j++) {
if (dir_path[i] == special_char[j]) {
return CM_TRUE;
}
}
}
return CM_FALSE;
}
#define CM_UDS_PATH_SPECIAL_CHAR_NUM 10
bool32 cm_check_uds_path_special_char(const char *dir_path, uint32 size)
{
uint32 i, j;
char special_char[CM_UDS_PATH_SPECIAL_CHAR_NUM] = { '|', ';', '&', '$', '>', '<', '`', '!', '\n', '%'};
for (i = 0; i < size; i++) {
for (j = 0; j < CM_UDS_PATH_SPECIAL_CHAR_NUM; j++) {
if (dir_path[i] == special_char[j]) {
return CM_TRUE;
}
}
}
return CM_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);
for (i = (int32)len; i >= 0; i--) {
if (file_name[i] == '\\' || file_name[i] == '/') {
break;
}
}
if (i < 0) {
errcode = strncpy_s(buf, (size_t)size, file_name, (size_t)len);
if (errcode != EOK) {
CM_THROW_ERROR(ERR_SYSTEM_CALL, errcode);
return;
}
return;
}
errcode = strncpy_s(buf, (size_t)size, file_name + i + 1, (size_t)(len - (uint32)i));
if (errcode != EOK) {
CM_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);
errno_t errcode = strncpy_s(buf, (size_t)size, file_name, (size_t)len);
if (errcode != EOK) {
CM_THROW_ERROR(ERR_SYSTEM_CALL, errcode);
return;
}
len = (uint32)strlen(buf);
for (i = (int32)len; 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/gauss/ to /home/gauss
*/
void cm_trim_home_path(char *home_path, uint32 len)
{
int32 i;
for (i = 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, (int32)mode) != 0) {
return CM_ERROR;
}
return CM_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[CM_MAX_PATH_LEN + 1];
size_t dir_len = strlen(dir_name);
uint32 i;
if (dir_len >= CM_MAX_PATH_LEN) {
LOG_DEBUG_ERR("the dir name's len is too big.");
return CM_ERROR;
}
errno_t errcode = strncpy_s(dir, (size_t)CM_MAX_PATH_LEN, dir_name, (size_t)dir_len);
if (errcode != EOK) {
CM_THROW_ERROR(ERR_SYSTEM_CALL, errcode);
return CM_ERROR;
}
if (dir[dir_len - 1] != '\\' && dir[dir_len - 1] != '/') {
if (dir_len < (CM_MAX_PATH_LEN - 1)) {
dir[dir_len] = '/';
dir_len++;
dir[dir_len] = '\0';
} else {
LOG_DEBUG_ERR("the dir name's len is too big.");
return CM_ERROR;
}
}
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) != CM_SUCCESS) {
return CM_ERROR;
}
dir[i] = '/';
}
}
return CM_SUCCESS;
}
status_t cm_truncate_file(int32 file, int64 offset)
{
#ifdef WIN32
if (_chsize_s(file, offset) != 0) {
#else
if (ftruncate(file, offset) != 0) {
#endif
CM_THROW_ERROR(ERR_TRUNCATE_FILE, offset, errno);
return CM_ERROR;
}
return CM_SUCCESS;
}
static bool32 cm_is_timeout(int32 timeout, int32 sleep_times, int32 sleeps)
{
if ((timeout == CM_WAIT_FOREVER) || (sleeps == 0)) {
return CM_FALSE;
}
return (bool32)((timeout / sleeps) < sleep_times);
}
status_t cm_fcntl(int32 fd, int32 cmd, struct flock *lock, int32 timeout)
{
#ifdef WIN32
return CM_SUCCESS;
#else
int32 sleep_times = 0;
while (CM_TRUE) {
if (fcntl(fd, cmd, lock) == 0) {
break;
}
if (cm_is_timeout(timeout, sleep_times, CM_SLEEP_TIME)) {
LOG_DEBUG_INF("fcntl failed and timeout, errno: %d.", errno);
return CM_ERROR;
}
if (cm_get_os_error() == EAGAIN || cm_get_os_error() == EINTR) {
LOG_DEBUG_INF("Linux return EAGAIN or EINTR errno: %d, try again.", errno);
cm_sleep(CM_SLEEP_TIME);
sleep_times++;
continue;
}
return CM_ERROR;
}
return CM_SUCCESS;
#endif
}
status_t cm_lock_fd(int32 fd, int32 timeout)
{
#ifdef WIN32
return CM_SUCCESS;
#else
struct flock lk;
lk.l_type = F_WRLCK;
lk.l_whence = SEEK_SET;
lk.l_start = lk.l_len = 0;
if (cm_fcntl(fd, F_SETLK, &lk, timeout) != CM_SUCCESS) {
CM_THROW_ERROR(ERR_LOCK_FILE, errno);
return CM_ERROR;
}
return CM_SUCCESS;
#endif
}
status_t cm_unlock_fd(int32 fd)
{
#ifdef WIN32
return CM_SUCCESS;
#else
struct flock lk;
lk.l_type = F_UNLCK;
lk.l_whence = SEEK_SET;
lk.l_start = lk.l_len = 0;
if (cm_fcntl(fd, F_SETLK, &lk, CM_WAIT_FOREVER) != CM_SUCCESS) {
CM_THROW_ERROR(ERR_UNLOCK_FILE, errno);
return CM_ERROR;
}
return CM_SUCCESS;
#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;
}
void cm_get_filesize(const char *filename, uint32 *filesize)
{
struct stat statbuf;
(void)stat(filename, &statbuf);
*filesize = (uint32)statbuf.st_size;
}
#ifdef __cplusplus
}
#endif