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

606 lines
18 KiB
C
Raw 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_user_common.c
*
* Author: saimen
*
* Create: 2022-06-08
*--------------------------------------------------------------------------*/
#include "sys_config.h"
#include "sys_typedef.h"
#include "sql_setting.h"
#include "time.h"
#include "fs_user_common.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
/**********************************************************************************************************************
* VARIABLES
*/
struct DelOldestObjectDef {
uint8_t cnt;
char path[PATH_TEMP_MAX_LENGTH];
}; //用来给删除最老的文件或目录的回调函数传递参数
/**********************************************************************************************************************
* LOCAL FUNCTIONS
*/
/// 通过参数arg回传扫描到的文件个数.
static int DirGetFileNumberCb(bool isDir, const char* path, int32_t ret, void* arg)
{
uint32_t *cnt = (void*)arg;
if(ret >= 0 && isDir == false) {
(*cnt)++;
}
return RET_SUCCESS;
}
/// 通过参数arg回传扫描到的子目录个数.
static int DirGetDirNumberCb(bool isDir, const char* path, int32_t ret, void* arg)
{
uint32_t *cnt = (void*)arg;
if(ret == 0 && isDir == true) {
(*cnt)++;
}
return RET_SUCCESS;
}
/// 比较arg传入的文件名字符串与扫描到的文件名字符串path的大小关系,通过arg回传较小的那一个.
static int DirGetOldestFileCb(bool isDir, const char *path, int32_t ret, void *arg)
{
char *pFile = (char*)arg;
if(ret >= 0 && isDir == false) {
if(strlen(pFile) == 0) {
strcpy(pFile, path);
} else {
if(strcmp(path, pFile) < 0) {
strcpy(pFile, path);
}
}
}
return RET_SUCCESS;
}
/// 比较arg传入的文件名字符串与扫描到的文件名字符串path的大小关系,通过arg回传较大的那一个.
static int DirGetNewestFileCb(bool isDir, const char *path, int32_t ret, void *arg)
{
char *pFile = (char*)arg;
if(ret >= 0 && isDir == false) {
if(strlen(pFile) == 0) {
strcpy(pFile, path);
} else {
if(strcmp(path, pFile) > 0) {
strcpy(pFile, path);
}
}
}
return RET_SUCCESS;
}
/// 比较arg传入的子目录名字符串与扫描到的子目录名字符串path的大小关系,通过arg回传较小的那一个.
static int DirGetOldestDirCb(bool isDir, const char *path, int32_t ret, void *arg)
{
char *pChildDir = (char*)arg;
if(ret == 0 && isDir == true) {
if(strlen(pChildDir) == 0) {
strcpy(pChildDir, path);
} else {
if(strcmp(path, pChildDir) < 0) {
strcpy(pChildDir, path);
}
}
}
return RET_SUCCESS;
}
/// 比较arg传入的子目录名字符串与扫描到的子目录名字符串path的大小关系,通过arg回传较大的那一个.
static int DirGetNewestDirCb(bool isDir, const char *path, int32_t ret, void *arg)
{
char *pChildDir = (char*)arg;
if(ret == 0 && isDir == true) {
if(strlen(pChildDir) == 0) {
strcpy(pChildDir, path);
} else {
if(strcmp(path, pChildDir) > 0) {
strcpy(pChildDir, path);
}
}
}
return RET_SUCCESS;
}
/// 比较arg域传入的文件名字符串与扫描到的文件名字符串path的大小关系,通过arg域回传较大的那一个,
/// 同时通过arg域统计文件数量并回传
static int DirDeleteOldestFileCb(bool isDir, const char *path, int32_t ret, void *arg)
{
struct DelOldestObjectDef *param = (struct DelOldestObjectDef*)arg;
if(ret >= 0 && isDir == false) {
if(param->cnt == 0) {
strcpy(param->path, path);
} else {
if(strcmp(path, param->path) < 0) {
strcpy(param->path, path);
}
}
param->cnt++;
}
return RET_SUCCESS;
}
/// 比较arg域传入的子目录名字符串与扫描到的子目录名字符串path的大小关系,通过arg域回传较大的那一个,
/// 同时通过arg域统计子目录数量并回传
static int DirDeleteOldestDirCb(bool isDir, const char *path, int32_t ret, void *arg)
{
struct DelOldestObjectDef *param = (struct DelOldestObjectDef*)arg;
if(ret == 0 && isDir == true) {
if(param->cnt == 0) {
strcpy(param->path, path);
} else {
if(strcmp(path, param->path) < 0) {
strcpy(param->path, path);
}
}
param->cnt++;
}
return RET_SUCCESS;
}
/**********************************************************************************************************************
* PUBLIC FUNCTIONS
*/
/**
* @brief 统计目录下的文件数量,包括子目录的文件.
* @param path:char*|目录的绝对路径.
* @retval int|返回统计结果,负数表示错误.
*/
int tjd_fs_user_get_file_number(const char *path)
{
int err = RET_SUCCESS;
uint32_t cnt = 0;
err = tjd_fs_api_dir_scan(path, DirGetFileNumberCb, &cnt);
return (err < 0) ? err : cnt;
}
/**
* @brief 统计目录下的文件数量,不包括子目录的文件.
* @param path:char*|目录的绝对路径.
* @retval int|返回统计结果,负数表示错误.
*/
int tjd_fs_user_get_file_number_exclude_child_dir(const char *path)
{
int err = RET_SUCCESS;
uint32_t cnt = 0;
err = tjd_fs_api_dir_scan_exclude_child_dir(path, DirGetFileNumberCb, &cnt);
return (err < 0) ? err : cnt;
}
/**
* @brief 统计目录下的子目录数量,不包括子目录的子目录.
* @param path:char*|目录的绝对路径.
* @retval int|返回统计结果,负数表示错误.
*/
int tjd_fs_user_get_dir_number_exclude_child_dir(const char *path)
{
int err = RET_SUCCESS;
uint32_t cnt = 0;
err = tjd_fs_api_dir_scan_exclude_child_dir(path, DirGetDirNumberCb, &cnt);
return (err < 0) ? err : cnt;
}
/**
* @brief 获取目录下最老文件的绝对路径,不包括子目录.
* @param path:char*|目录的绝对路径.
* @param buf:char*|最老文件绝对路径的缓存指针.
* @retval int|返回结果,0=目录为空,1=成功,负数=错误码.
*/
int tjd_fs_user_get_oldest_file_exclude_child_dir(const char *path, char *buf)
{
int err = RET_SUCCESS;
char pathCache[PATH_TEMP_MAX_LENGTH];
memset(pathCache, 0, sizeof(pathCache));
err = tjd_fs_api_dir_scan_exclude_child_dir(path, DirGetOldestFileCb, pathCache);
if(err < 0) {
return err;
}
if(strlen(pathCache) == 0) {
return 0;
} else {
strcpy(buf, pathCache);
return 1;
}
}
/**
* @brief 获取目录下最新文件的绝对路径,不包括子目录.
* @param path:char*|目录的绝对路径.
* @param buf:char*|最新文件绝对路径的缓存指针.
* @retval int|返回结果,0=目录为空,1=成功,负数=错误码.
*/
int tjd_fs_user_get_newest_file_exclude_child_dir(const char *path, char *buf)
{
int err = RET_SUCCESS;
char pathCache[PATH_TEMP_MAX_LENGTH];
memset(pathCache, 0, sizeof(pathCache));
err = tjd_fs_api_dir_scan_exclude_child_dir(path, DirGetNewestFileCb, pathCache);
if(err < 0) {
return err;
}
if(strlen(pathCache) == 0) {
return 0;
} else {
strcpy(buf, pathCache);
return 1;
}
}
/**
* @brief 获取目录下最老目录的绝对路径,不包括子目录.
* @param path:char*|目录的绝对路径.
* @param buf:char*|最老目录绝对路径的缓存指针.
* @retval int|返回结果,0=目录为空,1=成功,负数=错误码.
*/
int tjd_fs_user_get_oldest_dir_exclude_child_dir(const char *path, char *buf)
{
int err = RET_SUCCESS;
char pathCache[PATH_TEMP_MAX_LENGTH];
memset(pathCache, 0, sizeof(pathCache));
err = tjd_fs_api_dir_scan_exclude_child_dir(path, DirGetOldestDirCb, pathCache);
if(err < 0) {
return err;
}
if(strlen(pathCache) == 0) {
return 0;
} else {
strcpy(buf, pathCache);
return 1;
}
}
/**
* @brief 获取目录下最新目录的绝对路径,不包括子目录.
* @param path:char*|目录的绝对路径.
* @param buf:char*|最新目录绝对路径的缓存指针.
* @retval int|返回结果,0=目录为空,1=成功,负数=错误码.
*/
int tjd_fs_user_get_newest_dir_exclude_child_dir(const char *path, char *buf)
{
int err = RET_SUCCESS;
char pathCache[PATH_TEMP_MAX_LENGTH];
memset(pathCache, 0, sizeof(pathCache));
err = tjd_fs_api_dir_scan_exclude_child_dir(path, DirGetNewestDirCb, pathCache);
if(err < 0) {
return err;
}
if(strlen(pathCache) == 0) {
return 0;
} else {
strcpy(buf, pathCache);
return 1;
}
}
/**
* @brief 当目录下的文件数量超过保留值时,删除最老的一个文件
* @param path:char*|目录的绝对路径.
* @param retain:UINT8|要保留的文件数量.
* @retval int|返回结果,非负数=剩余的文件数量,负数=错误码.
* @note 每次最多只能删除一个文件.不递归进入下一级子目录.
*/
int tjd_fs_user_delete_oldest_file_exclude_child_dir(const char *path, uint8_t retain)
{
int err = 0;
struct DelOldestObjectDef obj;
memset(&obj, 0, sizeof(struct DelOldestObjectDef));
err = tjd_fs_api_dir_scan_exclude_child_dir(path, DirDeleteOldestFileCb, &obj);
if(err < 0) {
return err;
}
static_print_debug("current file number %d\r\n", obj.cnt);
if(obj.cnt > retain) {
err = tjd_fs_api_unlink(obj.path);
if(err < 0) {
return err;
} else {
return obj.cnt - 1;
}
}
return obj.cnt;
}
/**
* @brief 当目录下的子目录数量超过保留值时,删除最老的一个文件
* @param path:char*|目录的绝对路径.
* @param retain:UINT8|要保留的子目录数量.
* @retval int|返回结果,非负数=剩余的子目录数量,负数=错误码.
* @note 每次最多只能删除一个子目录.不递归进入下一级子目录.
*/
int tjd_fs_user_delete_oldest_dir_exclude_child_dir(const char *path, uint8_t retain)
{
int err = 0;
struct DelOldestObjectDef obj;
memset(&obj, 0, sizeof(struct DelOldestObjectDef));
err = tjd_fs_api_dir_scan_exclude_child_dir(path, DirDeleteOldestDirCb, &obj);
if(err < 0) {
return err;
}
static_print_debug("current dir number %d\r\n", obj.cnt);
if(obj.cnt > retain) {
err = tjd_fs_api_path_remove(obj.path);
if(err < 0) {
return err;
} else {
return obj.cnt - 1;
}
}
return obj.cnt;
}
static int tjd_fs_user_del_file_periodically_cb(bool isDir, const char* path, int32_t ret, void* arg)
{
int err=RET_SUCCESS;
char dest[10] = {0};
uint8_t path_len=0;
uint32_t time_dest=0;
uint32_t time_file=0;
struct tm *pDat = arg;
time_dest =10000*pDat->tm_year+100*pDat->tm_mon+pDat->tm_mday;
static_print_debug("tjd_fs_user_del_file_periodically_cb time_dest=%d\r\n",time_dest);
if(ret >= 0)
{
if(isDir)
{
static_print_debug("dir:%s\r\n", path);
}
else
{
static_print_debug("file | %s | %d Bytes\r\n", path, ret);
path_len = strlen(path);
static_print_debug("file len is %d\r\n",path_len);
strncpy(dest, path+path_len-12, 8);
time_file=strtol(dest,NULL,10);
if(time_file<=time_dest)
{
//delete file
err = tjd_fs_api_unlink(path);
static_print_debug("tjd_fs_user_del_file_periodically_cb del file name is:%s,err=%d\r\n",path,err);
}
else
{
//do not need to del file
static_print_debug("tjd_fs_user_del_file_periodically_cb do not del file name is:%s\r\n",path);
}
}
}
else
{
static_print_debug("scan path %s err %d\r\n", path, ret);
}
return RET_SUCCESS;
}
/*
功能删除指定路径下指定日期及该日期前所有如20211103.txt的文件
参数1path 指定路径
参数2time 指定日期
*/
int tjd_fs_user_remove_file_periodically(const char *path, void *time)
{
tjd_fs_api_dir_scan(path, tjd_fs_user_del_file_periodically_cb, time);
return 0;
}
static int tjd_fs_user_del_dir_periodically_cb(bool isDir, const char* path, int32_t ret, void* arg)
{
int err=RET_SUCCESS;
char dest[10] = {0};
uint8_t path_len=0;
uint32_t time_dest=0;
uint32_t time_file=0;
struct tm *pDat = arg;
time_dest =10000*pDat->tm_year+100*pDat->tm_mon+pDat->tm_mday;
static_print_debug("tjd_fs_user_del_file_periodically_cb time_dest=%d\r\n",time_dest);
if(ret >= 0)
{
if(isDir)
{
static_print_debug("dir:%s\r\n", path);
path_len = strlen(path);
//static_print_debug("file len is %d\r\n",path_len);
strncpy(dest, path+path_len-8, 8);
time_file=strtol(dest,NULL,10);
static_print_debug("tjd_fs_user_del_file_periodically_cb time_file=%d\r\n",time_file);
if(time_file<=time_dest)
{
//delete file
//err = tjd_fs_api_unlink(path);
err = tjd_fs_api_path_remove(path);
static_print_debug("tjd_fs_user_del_file_periodically_cb del file name is:%s,err=%d\r\n",path,err);
}
else
{
//do not need to del file
static_print_debug("tjd_fs_user_del_file_periodically_cb do not del file name is:%s\r\n",path);
}
}
else
{
static_print_debug("file | %s | %d Bytes\r\n", path, ret);
}
}
else
{
static_print_debug("scan path %s err %d\r\n", path, ret);
}
return 0;
}
/*
功能删除指定路径下指定日期及该日期前所有如20211103的目录
参数1path 指定路径 const char DIR_SPORT_OUTDOR_RUN[] "/FD/data_sport/outdor_run";
参数2time 指定日期 如20211104 则删除20211104及该日期以前的所有目录
*/
int tjd_fs_user_remove_dir_periodically(const char *path,void *time)
{
tjd_fs_api_dir_scan_exclude_child_dir(path, tjd_fs_user_del_dir_periodically_cb, time);
return 0;
}
/**
* @brief 打印文本文件的内容.
* @param path:const char *|文件的绝对路径.
* @retval int|返回结果,0=成功,负数表示错误码.
*/
int tjd_fs_user_print_text_file(const char *path)
{
#define TEXT_PRINT_BUF_MAX_SIZE 256
int err = 0;
uint16_t i = 0;
uint32_t total = 0;
uint8_t buf[TEXT_PRINT_BUF_MAX_SIZE + 1];
if(tjd_fs_api_file_exist(path) != RET_SUCCESS) {
return 0;
}
static_print_debug("\r\n**** Start Print %s Content ****\r\n", path);
do {
err = tjd_fs_api_file_load(path, i * TEXT_PRINT_BUF_MAX_SIZE, buf, TEXT_PRINT_BUF_MAX_SIZE);
if(err <= 0) {
break;
} else if(err == TEXT_PRINT_BUF_MAX_SIZE) {
buf[TEXT_PRINT_BUF_MAX_SIZE] = 0;
static_print_debug("%s", buf);
total += TEXT_PRINT_BUF_MAX_SIZE;
} else {
buf[err] = 0;
total += err;
static_print_debug("%s", buf);
break;
}
i++;
} while(1);
static_print_debug("\r\n**** End Print Total Bytes %d ****\r\n", total);
return 0;
}
/* 文件系统通过字符串创建路径 ************************************************************ */
/**
* @brief 创建目录
* @param dir,上层目录path 要建立的路径
* @retval int | 返回错误代码, 0=原来没有此目录情况下创建1=原来有此目录的情况下不创建
*/
int tjd_fs_user_create_dir_by_str(const char *dir,const char *path)
{
int err = 0;
char fullPath[PATH_TEMP_MAX_LENGTH];
uint32_t temp_size=0;
bool temp_isdir=0;
snprintf(fullPath, PATH_TEMP_MAX_LENGTH, "%s%s%s", dir, "/", path);
err = tjd_fs_api_path_exist(fullPath, &temp_size, &temp_isdir);
if(err == 0) {
static_print_debug("dir already exists\r\n");
} else {
err = tjd_fs_user_create_dir(fullPath);
if(err != 0) {
static_print_warn("mkdir %s failed, err code:%d\r\n", fullPath, err);
} else {
static_print_debug("mkdir %s success.\r\n", fullPath);
}
}
return err;
}
int tjd_fs_user_dir_init(void)
{
//创建一级目录
return 0;
}
int tjd_fs_user_mount(bool format)
{
int err = 0;
return err;
}
void tjd_fs_user_init(bool format)
{
static uint8_t count=0;
uint32_t temp_size=0;
bool temp_isdir=0;
repetition:
tjd_fs_user_mount(format);
tjd_fs_user_dir_init();
tjd_fs_user_print_dir_list("/");
if(tjd_fs_api_path_exist(TJD_FS_DIR_SYS, &temp_size, &temp_isdir) != RET_SUCCESS && count < 3)
{
count++;
tjd_fs_api_format();
goto repetition;
}
}
//待保留的文件及目录
static const char *retain_file_dir[] = {
TJD_FS_DIR_UPDATE,
};
int tjd_fs_user_factory_reset(void)
{
tjd_fs_api_path_remove(TJD_FS_DIR_USER);
// tjd_fs_api_path_remove(TJD_FS_DIR_SYS);//
log_api_save_at_power_off();
return 0;
}