mcu_hi3321_watch/tjd/fs/fs_api_ext.c
2025-05-26 20:15:20 +08:00

411 lines
12 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*----------------------------------------------------------------------------
* 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);
}