Files
TAIXIN/sdk/lib/fs/fatfs/osal_file.c

609 lines
12 KiB
C
Raw Normal View History

#include "typesdef.h"
#include "fatfs/ff.h"
// #include "osal.h"
#include <string.h>
#include "osal_file.h"
#include "osal/string.h"
#include "osal/task.h"
#include "lib/common/common.h"
// 结构体申请空间函数
#ifdef MORE_SRAM
#define FILE_MALLOC os_malloc_psram
#define FILE_FREE os_free_psram
#define FILE_ZALLOC os_zalloc_psram
#else
#define FILE_MALLOC os_malloc
#define FILE_FREE os_free
#define FILE_ZALLOC os_zalloc
#endif
uint32_t file_mode(const char *mode)
{
uint32_t flags = 0;
if (!mode) {
return 0;
}
switch (mode[0]) {
case 'r':
flags |= FA_READ;
break;
case 'w':
flags |= FA_WRITE | FA_CREATE_ALWAYS;
break;
case 'a':
flags |= FA_WRITE | FA_OPEN_APPEND;
break;
default:
return 0;
}
for (const char *p = mode + 1; *p; p++) {
if(*p == '+')
{
flags |= FA_READ | FA_WRITE;
}
}
return flags;
}
F_FILE *osal_open(const char *filename, int oflags, int mode)
{
uint32_t res;
FIL *fp = FILE_MALLOC(sizeof(FIL));
if (!fp)
{
return 0;
}
res = f_open(fp, filename, mode);
if (res == FR_OK)
{
return fp;
}
else
{
os_printf("%s res:%d\tfilename:%s\n", __FUNCTION__, res, filename);
set_errno(res);
FILE_FREE(fp);
return 0; // return NULL;
}
}
F_FILE *osal_fopen(const char *filename, const char *mode)
{
return osal_open(filename, 0, file_mode(mode));
}
// 返回值是读取到的字节数,与标准c返回值有一点点区别
uint32_t osal_fread(void *ptr, uint32_t size, uint32_t nmemb, F_FILE *fp)
{
#ifdef WIN32
return fread(ptr, size, nmemb, fp);
#else
uint32_t readLen;
uint32_t res = f_read(fp, ptr, size * nmemb, &readLen);
if (res == FR_OK)
{
return readLen;
}
else
{
os_printf("%s res:%d\n", __FUNCTION__, res);
set_errno(res);
return 0;
}
#endif
}
uint32_t osal_fwrite(void *ptr, uint32_t size, uint32_t nmemb, F_FILE *fp)
{
#ifdef WIN32
return fwrite(ptr, size, nmemb, fp);
#else
uint32_t writeLen;
uint32_t res = f_write(fp, ptr, size * nmemb, &writeLen);
if (res == FR_OK)
{
return writeLen;
}
else
{
set_errno(res);
return 0;
}
#endif
// return size*nmemb;
}
int osal_fclose(F_FILE *fp)
{
#ifdef WIN32
return fclose(fp);
#else
int res = f_close(fp);
FILE_FREE(fp);
if (!res)
{
set_errno(res);
}
return res;
#endif
}
uint32_t osal_ftell(F_FILE *fp)
{
#ifdef WIN32
return ftell(fp);
#else
return f_tell(fp);
#endif
}
uint32_t osal_fseek(F_FILE *fp, uint32_t offset)
{
#ifdef WIN32
return fseek(fp, offset, SEEK_SET);
#else
return f_lseek(fp, offset);
#endif
}
uint32_t osal_fsize(F_FILE *fp)
{
#ifdef WIN32
uint32_t tmp;
uint32_t size;
tmp = osal_ftell(fp);
fseek(fp, 0, SEEK_END);
size = osal_ftell(fp);
fseek(fp, tmp, SEEK_SET);
return size;
#else
return f_size(fp);
#endif
}
char *osal_getcwd(char *buf, uint32_t len)
{
if (FR_OK != f_getcwd(buf, len))
{
return NULL;
}
return buf;
}
int osal_chdir(char *buf)
{
int res;
if (buf[1] == ':')
{
f_chdrive(buf);
if (FR_OK != f_chdir(buf + 2))
{
return -1;
}
}
else
{
res = f_chdir(buf);
if (FR_OK != res)
{
os_printf("buf:%s\tres:%d\r\n", buf, res);
return -1;
}
}
return 0;
}
struct diriter
{
DIR dir;
FILINFO fil;
};
void *osal_opendir(const char *path)
{
struct diriter *dir;
dir = FILE_MALLOC(sizeof(struct diriter));
if (!dir)
{
return NULL;
}
if (f_opendir(&dir->dir, path) == FR_OK)
{
return dir;
}
FILE_FREE(dir);
return NULL;
}
void osal_closedir(void *HDIR)
{
struct diriter *dir = (struct diriter *) HDIR;
if (!dir)
{
return;
}
FILE_FREE(dir);
}
void *osal_readdir(void *HDIR)
{
struct diriter *dir = (struct diriter *) HDIR;
if (!dir)
{
return NULL;
}
if (f_readdir(&dir->dir, &dir->fil) != FR_OK)
{
return NULL;
}
if (dir->dir.sect == 0)
{
return NULL;
}
return &dir->fil;
}
char *osal_dirent_name(void *HFIL)
{
FILINFO *fil = (FILINFO *) HFIL;
if (!fil)
{
return NULL;
}
return fil->fname;
}
int osal_dirent_isdir(void *HFIL)
{
FILINFO *fil = (FILINFO *) HFIL;
if (!fil)
{
return 0;
}
return fil->fattrib & AM_DIR;
}
uint32_t osal_dirent_date(void *HFIL)
{
FILINFO *fil = (FILINFO *) HFIL;
return fil->fdate;
}
uint32_t osal_dirent_time(void *HFIL)
{
FILINFO *fil = (FILINFO *) HFIL;
if (!fil)
{
return 0;
}
return fil->ftime;
}
uint32_t osal_dirent_size(void *HFIL)
{
FILINFO *fil = (FILINFO *) HFIL;
return fil->fsize;
}
uint32_t osal_fmkdir(const char *dir)
{
return f_mkdir(dir);
}
FRESULT osal_stat(const TCHAR *path, FILINFO *fno)
{
return f_stat(path, fno);
}
FRESULT osal_unlink(const TCHAR *path)
{
return f_unlink(path);
}
FRESULT osal_rename(const TCHAR *oldpath, const TCHAR *newpath)
{
return f_rename(oldpath, newpath);
}
FRESULT osal_fchmod(const TCHAR *path, uint8 attr, uint8 mask)
{
return f_chmod(path, attr, mask);
}
FRESULT osal_fstat(const TCHAR *path, FILINFO *fno)
{
return f_stat(path, fno);
}
// 判断是否存在某个文件
FRESULT osal_fexist(const char *name)
{
FIL *fp;
fp = osal_fopen(name, "rb");
if (fp)
{
osal_fclose(fp);
return 0;
}
return 1;
}
FRESULT osal_ftruncate(F_FILE *fp)
{
return f_truncate(fp);
}
FRESULT osal_fsync(void *fp)
{
return f_sync((FIL *) fp);
}
/******************************************************************************
*
*****************************************************************************/
FRESULT osal_fatfsfree(const char *path, uint32_t *totalsize, uint32_t *freesize)
{
FATFS *fs;
DWORD fre_clust, fre_sect, tot_sect;
FRESULT res = f_getfree(path, &fre_clust, &fs);
if (!res)
{
tot_sect = (fs->n_fatent - 2) * fs->csize;
fre_sect = fre_clust * fs->csize;
if(totalsize)
*totalsize = tot_sect / 2 / 1024;
if(freesize)
*freesize = fre_sect / 2 / 1024;
}
else
{
os_printf("%s:%d\tres:%d\n",__FUNCTION__,__LINE__,res);
}
return res;
}
// 需要保证path有足够的空间(比filepath大)
FRESULT osal_auto_create_dirs(const char *filepath, char *path,uint8_t ishid)
{
FRESULT fr;
DIR dir;
char *p; // 用于遍历路径的指针
// 1. 从文件路径中提取目录路径
strcpy(path, filepath);
// 找到最后一个路径分隔符,将其后的内容(文件名)截断
p = strrchr(path, '/');
if (p == NULL)
{
// 如果路径中没有目录,只有文件名,则无需创建目录
return FR_OK;
}
*p = '\0'; // 现在path里就是纯目录路径了
// 2. 尝试打开该目录,如果成功说明目录已存在
fr = f_opendir(&dir, path);
if (fr == FR_OK)
{
f_closedir(&dir);
return FR_OK; // 目录已存在,直接返回成功
}
// 3. 如果目录不存在,则开始逐级创建
// 从根目录开始遍历路径
p = path;
if (*p == '/')
{
p++; // 如果以'/'开头,跳过第一个(根据你的实际路径格式调整)
}
while ((p = strchr(p, '/')) != NULL)
{
*p = '\0'; // 在分隔符处临时截断,得到当前要检查的子路径
// 尝试打开当前层级的目录
fr = f_opendir(&dir, path);
if (fr == FR_OK)
{
f_closedir(&dir); // 当前层级目录存在,继续下一级
}
else if (fr == FR_NO_PATH)
{
// 当前层级目录不存在,创建它
fr = f_mkdir(path);
if (fr != FR_OK && fr != FR_EXIST)
{ // 忽略FR_EXIST错误可能其他线程已创建
return fr; // 创建失败,返回错误
}
if(ishid)
{
f_chmod(path,AM_HID,AM_HID);
}
}
else
{
return fr; // 其他错误,返回
}
*p = '/'; // 恢复分隔符
p++; // 移动到下一级
}
// 4. 最后再尝试一次打开最终目录,确保创建成功
fr = f_opendir(&dir, path);
if (fr == FR_OK)
{
f_closedir(&dir);
return FR_OK;
}
else
{
// 最终目录创建仍未成功
fr = f_mkdir(path);
if (fr != FR_OK && fr != FR_EXIST)
{
}
if(ishid)
{
f_chmod(path,AM_HID,AM_HID);
}
return fr;
}
}
FRESULT delete_directory_recursive(const TCHAR *path)
{
FRESULT res = 0;
uint8_t *dir_buf = (uint8_t *)(FILE_MALLOC(sizeof(DIR) + sizeof(FILINFO) + 256));
if (!dir_buf)
{
res = FR_DENIED;
goto delete_directory_end;
}
DIR *dir = (DIR *)dir_buf;
FILINFO *fno = (FILINFO *)(dir_buf + sizeof(DIR));
TCHAR *full_path = (TCHAR *)(dir_buf + sizeof(DIR) + sizeof(FILINFO));
res = f_opendir(dir, path);
if (res != FR_OK)
{
goto delete_directory_end;
}
while (1)
{
res = f_readdir(dir, fno);
if (res != FR_OK || fno->fname[0] == 0)
{
break;
}
// 检查是否是 "." (当前目录) 或 ".." (上级目录)
if ((fno->fname[0] == '.' && fno->fname[1] == '\0') || (fno->fname[0] == '.' && fno->fname[1] == '.' && fno->fname[2] == '\0')) {
continue;
}
snprintf(full_path, 256, "%s/%s", path, fno->fname);
if (fno->fattrib & AM_DIR)
{
res = delete_directory_recursive(full_path);
if (res != FR_OK)
{
f_closedir(dir);
goto delete_directory_end;
}
else
{
_os_printf("delete dir %s\r\n", full_path);
}
}
else
{
res = f_unlink(full_path);
if (res != FR_OK)
{
_os_printf("delete file %s, res: %d\r\n", full_path, res);
f_closedir(dir);
goto delete_directory_end;
}
else
{
_os_printf("delete file %s\r\n", full_path);
}
}
}
f_closedir(dir);
res = f_unlink(path);
delete_directory_end:
if(dir_buf)
{
FILE_FREE(dir_buf);
}
return res;
}
FRESULT osal_unlink_dir(const TCHAR *path, uint8_t force)
{
// 使用普通删除方式(只能删除空目录)
if (force == 0)
{
return f_unlink(path);
}
// 强制删除目录及其所有内容
else if (force == 1)
{
return delete_directory_recursive(path);
}
return FR_INVALID_PARAMETER;
}
FRESULT rename_dir_in_directory(const TCHAR *path, const TCHAR *base_path)
{
FRESULT res;
DIR dir;
static int file_count = 1;
// 打开目录
res = f_opendir(&dir, path);
if (res != FR_OK)
{
return res;
}
TCHAR new_path[256];
os_sprintf(new_path, "%s/ERR%d", base_path, file_count++);
res = f_rename(path, new_path);
while (res != FR_OK)
{
f_closedir(&dir);
os_printf("rename file error\r\n");
res = rename_dir_in_directory(path, base_path);
if (res == FR_OK)
{
break;
}
}
_os_printf("dir rename success, new path: %s\r\n", new_path);
f_closedir(&dir);
return FR_OK;
}
F_FILE *osal_fopen_auto(const char *filename, const char *mode,uint8_t ishid)
{
F_FILE *fp = osal_open(filename, 0, file_mode(mode));
FRESULT res;
if (!fp)
{
if (get_errno() == FR_NO_PATH)
{
char path[128]; // 路径缓冲区,根据需求调整大小,用的是任务栈,注意太大的话有可能任务栈也需要加大
res = osal_auto_create_dirs(filename, path,ishid);
// 如果创建目录成功,重新创建文件
if (!res)
{
fp = osal_open(filename, 0, file_mode(mode));
}
}
}
return fp;
}