411 lines
12 KiB
C
411 lines
12 KiB
C
/*----------------------------------------------------------------------------
|
||
* Copyright (c) Fenda Technologies Co., Ltd. 2021. All rights reserved.
|
||
*
|
||
* Description: fs_api_ext.c
|
||
*
|
||
* Author: saimen
|
||
*
|
||
* Create: 2024-06-28
|
||
*--------------------------------------------------------------------------*/
|
||
#include "sys_typedef.h"
|
||
#include "sys_config.h"
|
||
#include "fs_api_ext.h"
|
||
#include <fcntl.h>
|
||
#include <sys/stat.h>
|
||
#include <unistd.h>
|
||
#include "dirent.h"
|
||
|
||
/**********************************************************************************************************************
|
||
* DEFINE
|
||
*/
|
||
#define ENABLE_STATIC_PRINT false
|
||
#define static_print_error(...) sys_fs_log_e(__VA_ARGS__) //错误信息打印一般常开
|
||
#define static_print_warn(...) sys_fs_log_w(__VA_ARGS__) //警告信息打印一般常开
|
||
#if ENABLE_STATIC_PRINT
|
||
#define static_print_debug(...) sys_fs_log_d(__VA_ARGS__)
|
||
#else
|
||
#define static_print_debug(...)
|
||
#endif
|
||
|
||
#define PATH_TEMP_MAX_LENGTH 64
|
||
|
||
/**********************************************************************************************************************
|
||
* PUBLIC FUNCTIONS
|
||
*/
|
||
/// 判断目录是否存在,如果存在,返回0
|
||
int tjd_fs_api_path_exist(const char *path, uint32_t *size, bool *is_dir)
|
||
{
|
||
int ret = RET_SUCCESS;
|
||
struct stat fileStat = {0};
|
||
int32_t c = stat(path, &fileStat);
|
||
if (ret == -1) {
|
||
return RET_ERROR;
|
||
} else{
|
||
*size = fileStat.st_size;
|
||
*is_dir = S_ISDIR(fileStat.st_mode)? true: false;
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
/// 删除目录, 包括其下的文件及子目录
|
||
int tjd_fs_api_path_remove(const char *path)
|
||
{
|
||
struct stat fileStat;
|
||
char fullPath[PATH_TEMP_MAX_LENGTH];
|
||
int32_t ret = stat(path, &fileStat);
|
||
if (ret != 0) {
|
||
static_print_warn("file stat failed");
|
||
return RET_ERROR;
|
||
}
|
||
|
||
if (!S_ISDIR(fileStat.st_mode)) {
|
||
if (unlink(path) != 0) {
|
||
static_print_warn("remove file failed, errno");
|
||
return RET_ERROR;
|
||
}
|
||
return RET_SUCCESS;
|
||
}
|
||
|
||
DIR *dir = opendir(path);
|
||
if (dir != NULL) {
|
||
do {
|
||
struct dirent *dire = readdir(dir);
|
||
if(dire ==NULL){
|
||
ret = RET_ERROR;
|
||
break;
|
||
}
|
||
static_print_debug("Remove d_type=%d <%s>", dire->d_type, dire->d_name);
|
||
if (dire->d_type == DT_REG) { /* only care about files. */
|
||
memset(fullPath, 0, sizeof(fullPath));
|
||
sprintf(fullPath, "%s/%s", path, dire->d_name);
|
||
ret = unlink(fullPath);
|
||
if(ret != RET_SUCCESS) {
|
||
static_print_warn("file_remove failed[%s]",fullPath);
|
||
break;
|
||
}
|
||
}else if(dire->d_type == DT_DIR){
|
||
if((strcmp(dire->d_name, ".") != 0) && (strcmp(dire->d_name, "..")) != 0) {
|
||
memset(fullPath, 0, sizeof(fullPath));
|
||
sprintf(fullPath, "%s/%s", path, dire->d_name);
|
||
ret = tjd_fs_api_path_remove(fullPath);
|
||
if(ret != RET_SUCCESS) {
|
||
static_print_warn("path_remove failed[%s]",fullPath);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
} while(1);
|
||
}
|
||
closedir(dir);
|
||
if(ret == RET_SUCCESS){
|
||
rmdir(path);
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
/// 扫描目录,不递归进入下一层目录
|
||
int tjd_fs_api_dir_scan_exclude_child_dir(const char *path, int (*cb)(bool, const char*, int32_t, void*), void* arg)
|
||
{
|
||
int ret = RET_SUCCESS;
|
||
char fullPath[PATH_TEMP_MAX_LENGTH]={0};
|
||
struct dirent *dire = NULL;
|
||
|
||
DIR *dir = opendir(path);
|
||
if (dir != NULL) {
|
||
do {
|
||
dire = readdir(dir);
|
||
|
||
if(dire <= 0) {
|
||
break; //返回0表示读取完毕,正数表示成功,负数表示失败
|
||
}
|
||
|
||
memset(fullPath, 0, sizeof(fullPath));
|
||
if(path[strlen(path) - 1] == '/' || path[strlen(path) - 1] == '\\') {
|
||
sprintf(fullPath, "%s%s", path, dire->d_name);
|
||
} else {
|
||
sprintf(fullPath, "%s/%s", path, dire->d_name);
|
||
}
|
||
|
||
if(dire->d_type == DT_DIR) {
|
||
if((strcmp(dire->d_name, ".") != 0) && (strcmp(dire->d_name, "..")) != 0) {
|
||
cb(true, fullPath, 0, arg); // 0:empty
|
||
}
|
||
} else { //DT_REG 文件类
|
||
cb(false, fullPath, dire->d_ino, arg);//dire->d_ino代表文件大小
|
||
}
|
||
} while(1);
|
||
|
||
ret = closedir(dir);
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
/// 扫描目录
|
||
int tjd_fs_api_dir_scan(const char *path, int (*cb)(bool, const char*, int32_t, void*), void* arg)
|
||
{
|
||
int ret = RET_SUCCESS;
|
||
char fullPath[PATH_TEMP_MAX_LENGTH]={0};
|
||
struct dirent *dire = NULL;
|
||
static char s_level = 0;
|
||
|
||
static_print_debug("tjd_fs_api_dir_scan_start: %s\r\n",path);
|
||
|
||
DIR *dir = opendir(path);
|
||
if (dir != NULL) {
|
||
do {
|
||
dire = readdir(dir);
|
||
/* 目录名为空表示扫描结束 */
|
||
if(dire <= 0) {
|
||
break; //返回0表示读取完毕,正数表示成功,负数表示失败
|
||
}
|
||
|
||
memset(fullPath, 0, sizeof(fullPath));
|
||
if(path[strlen(path) - 1] == '/' || path[strlen(path) - 1] == '\\') {
|
||
sprintf(fullPath, "%s%s", path, dire->d_name);
|
||
} else {
|
||
sprintf(fullPath, "%s/%s", path, dire->d_name);
|
||
}
|
||
static_print_debug("fs_dir_scan_%d: %s-%d-%d-%d",s_level, fullPath,dire->d_type,dire->d_reclen,dire->d_off);
|
||
if(dire->d_type == DT_DIR) {
|
||
if((strcmp(dire->d_name, ".") != 0) && (strcmp(dire->d_name, "..")) != 0) {
|
||
cb(true, fullPath, -1*dire->d_type, arg); //取负数与info.size区别开
|
||
ret = tjd_fs_api_dir_scan(fullPath, cb, arg);
|
||
if(ret != RET_SUCCESS) {
|
||
break;
|
||
}
|
||
}
|
||
} else { //DT_REG 文件类
|
||
struct stat fileStat;
|
||
stat(fullPath, &fileStat);
|
||
cb(false, fullPath, fileStat.st_size, arg);//dire->d_ino代表文件大小?
|
||
}
|
||
|
||
} while(1);
|
||
|
||
ret = closedir(dir);
|
||
}
|
||
|
||
static_print_debug("tjd_fs_api_dir_scan_out: \r\n");
|
||
return ret;
|
||
}
|
||
|
||
/// 文件存储
|
||
int tjd_fs_api_file_store(const char *path, uint32_t oft, const void *buffer, uint32_t size)
|
||
{
|
||
int ret = RET_SUCCESS;
|
||
int len;
|
||
|
||
int32_t fd = open(path, O_WRONLY | O_CREAT);
|
||
if(ret != RET_SUCCESS) {
|
||
return ret;
|
||
}
|
||
if(oft==0xffffffff)//oft为0xffffffff时,默认直接写文件结尾
|
||
{
|
||
lseek(fd, 0, SEEK_END);
|
||
}
|
||
else if(oft > 0)
|
||
{
|
||
ret = lseek(fd, oft, SEEK_SET);
|
||
if(ret != oft) {
|
||
goto CLOSE;
|
||
}
|
||
}
|
||
|
||
if(size > 0) {
|
||
len = write(fd, buffer, size);
|
||
} else {
|
||
len = 0;
|
||
}
|
||
|
||
CLOSE:
|
||
ret = close(fd);
|
||
if(ret == RET_SUCCESS) {
|
||
ret = len;
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
/// 文件追加
|
||
int tjd_fs_api_file_append(const char *path, const void *buffer, uint32_t size)
|
||
{
|
||
int ret = RET_SUCCESS;
|
||
int len;
|
||
|
||
int32_t fd = open(path, O_WRONLY | O_CREAT | O_APPEND);
|
||
if(fd <= 0) {
|
||
return ret;
|
||
}
|
||
|
||
|
||
if(size > 0) {
|
||
len = write(fd, buffer, size);
|
||
} else {
|
||
len = 0;
|
||
}
|
||
|
||
ret = close(fd);
|
||
if(ret == RET_SUCCESS) {
|
||
ret = len;
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
/// 文件装载
|
||
int tjd_fs_api_file_load(const char *path, uint32_t oft, void *buffer, uint32_t size)
|
||
{
|
||
int ret = RET_SUCCESS;
|
||
int len;
|
||
|
||
static_print_debug("tjd_fs_api_file_load_1:%s-%d-%d\r\n",path,oft,size);
|
||
int32_t fd = open(path, O_RDONLY);
|
||
if(fd <= 0) {
|
||
return ret;
|
||
}
|
||
|
||
if(oft==0xffffffff)//参数为0xffffffff时,默认读文件的最后size个字节
|
||
{
|
||
ret = lseek(fd, -(size), SEEK_END);
|
||
}
|
||
else if(oft > 0) {
|
||
ret = lseek(fd, oft, SEEK_SET);
|
||
if(ret != oft) {
|
||
goto CLOSE;
|
||
}
|
||
}
|
||
|
||
if(size > 0) {
|
||
len = read(fd, buffer, size);
|
||
} else {
|
||
len = 0;
|
||
}
|
||
|
||
CLOSE:
|
||
ret = close(fd);
|
||
if(ret == RET_SUCCESS) {
|
||
ret = len;
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
/**
|
||
* @brief 获取文件的目录信息,目录信息为绝对路径.
|
||
*/
|
||
int tjd_fs_api_get_dir_by_full_path(const char *path, char *buf)
|
||
{
|
||
if(path == NULL) {
|
||
return 0;
|
||
}
|
||
|
||
uint32_t length = strlen(path);
|
||
uint32_t i = length - 1;
|
||
|
||
while(1) {
|
||
if(path[i] == '/' || path[i] == '\\') {
|
||
// strncpy(buf, path, i + 1);
|
||
// buf[i + 1] = '\0';
|
||
strncpy(buf, path, i );
|
||
buf[i] = '\0';
|
||
return strlen(buf);
|
||
}
|
||
if(i == 0) {
|
||
return 0;
|
||
}
|
||
i--;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 根据文件绝对路径,获取文件名.
|
||
*/
|
||
int tjd_fs_api_get_file_name_by_full_path(const char *path, char *file_name)
|
||
{
|
||
if(path == NULL) {
|
||
return 0;
|
||
}
|
||
uint32_t length = strlen(path);
|
||
uint32_t i = length - 1;
|
||
while(1) {
|
||
if(path[i] == '/' || path[i] == '\\') {
|
||
strcpy(file_name, path + i + 1);
|
||
return strlen(file_name);
|
||
}
|
||
if(i == 0) {
|
||
return 0;
|
||
}
|
||
i--;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 创建目录,可以创建多级目录.
|
||
* @param path:char*|目录的绝对路径.
|
||
* @retval int|返回错误代码,0=成功.
|
||
*/
|
||
int tjd_fs_api_full_dir_create(const char *path)
|
||
{
|
||
char pathCache[PATH_TEMP_MAX_LENGTH];
|
||
int err = RET_SUCCESS;
|
||
uint32_t pos = 0;
|
||
uint32_t temp_size=0;
|
||
bool temp_isdir=0;
|
||
|
||
if(tjd_fs_api_path_exist(path, &temp_size, &temp_isdir) == 0) {
|
||
return 0;
|
||
}
|
||
|
||
memset(pathCache, 0 ,sizeof(pathCache));
|
||
while((*(path + pos) != '.') && ((*(path + pos) != '\0'))) {
|
||
pos++;
|
||
if(*(path + pos) == '/' || *(path + pos) == '\\' || *(path + pos) == '\0') {
|
||
memcpy(pathCache, path, pos);
|
||
err = tjd_fs_api_path_exist(pathCache, &temp_size, &temp_isdir);
|
||
if(err == 0) {
|
||
continue;
|
||
} else {
|
||
if((err = tjd_fs_api_full_dir_create(pathCache)) != RET_SUCCESS) {
|
||
static_print_warn("create dir %s failed, err code %d\r\n", pathCache, err);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return err;
|
||
}
|
||
|
||
/**********************************************************************************************************************
|
||
* TEST FUNCTIONS
|
||
*/
|
||
// 打印扫描目录传回的子目录或文件信息.
|
||
static int tjd_fs_api_print_path_files_cb(bool isDir, const char* path, int32_t ret, void* arg)
|
||
{
|
||
if(ret >= 0) {
|
||
if(isDir) {
|
||
static_print_warn("dir | %s", path);
|
||
} else {
|
||
static_print_warn("file | %s | %d Bytes", path, ret);
|
||
}
|
||
} else {
|
||
static_print_warn("scan path %s err %d", path, ret);
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @brief 展开目录详情.
|
||
* @param path:char*|目录的绝对路径.
|
||
* @retval void|无.
|
||
* @note 该函数用于打印调试.
|
||
*/
|
||
void tjd_fs_api_print_dir_list(const char *path)
|
||
{
|
||
static_print_warn("---- print path:%s ----", path);
|
||
tjd_fs_api_dir_scan(path, tjd_fs_api_print_path_files_cb, NULL);
|
||
} |