606 lines
18 KiB
C
606 lines
18 KiB
C
/*----------------------------------------------------------------------------
|
||
* 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的文件
|
||
参数1:path 指定路径
|
||
参数2:time 指定日期
|
||
*/
|
||
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的目录
|
||
参数1:path 指定路径 const char DIR_SPORT_OUTDOR_RUN[] "/FD/data_sport/outdor_run";
|
||
参数2:time 指定日期 如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;
|
||
}
|
||
|