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