/* * 模块名称:cfg_file_store (模拟器后端) * 模块功能:cfg_file 存储后端——模拟器工作目录宿主文件 sim_config.ini; * 原子写 = 临时文件 sim_config.ini.tmp + rename;mtime 变更令牌 = * 宿主文件 mtime(秒级);旧版遗留文件 sim_netcfg.bin 供迁移读取 * 适用平台:PC 模拟器 * 作者:王建锋 * 创建日期:2026-09-14 * 修改记录: * v1.0 2026-09-14 王建锋 创建初始版本 */ /* 头文件包含区 */ #include #include #include #include "cfg_file_store.h" /* 静态变量定义区 */ static const char s_path[] = "sim_config.ini"; static const char s_path_tmp[] = "sim_config.ini.tmp"; static const char s_path_legacy[] = "sim_netcfg.bin"; /* 函数定义区 */ /* * 函数功能:读文件(最多 cap 字节) * 入口参数:p_path - 文件路径 const char * * p_buf - 接收缓冲(不可为 NULL) uint8_t * * cap - 缓冲容量 size_t * p_nread - 实际读字节数输出(不可为 NULL) size_t * * 返回值:0 - 成功;-1 - 文件缺失/读失败 int * 限定条件:无 */ int cfg_store_read(const char *p_path, uint8_t *p_buf, size_t cap, size_t *p_nread) { FILE *fp; size_t n; if (p_buf == NULL || p_nread == NULL) { return -1; } fp = fopen(p_path, "rb"); if (fp == NULL) { return -1; } n = fread(p_buf, 1u, cap, fp); (void)fclose(fp); *p_nread = n; return 0; } /* * 函数功能:原子写文件(先写 sim_config.ini.tmp,成功后 rename 覆盖目标) * 入口参数:p_path - 目标文件路径 const char * * p_buf - 待写数据(不可为 NULL) const uint8_t * * len - 数据长度 size_t * 返回值:0 - 成功;-1 - 写/改名失败(临时文件清理) int * 限定条件:MSVC rename() 不覆盖已存在目标(C1117),须先 remove 再 rename * (tmp 已完整写盘关闭后操作,中断窗口仅毫秒级;目标丢失时引擎 * 下次加载自动重建出厂模板,与 MCU 端 f_rename 直接替换等效) */ int cfg_store_write_atomic(const char *p_path, const uint8_t *p_buf, size_t len) { FILE *fp; size_t n; if (p_buf == NULL) { return -1; } fp = fopen(s_path_tmp, "wb"); if (fp == NULL) { return -1; } n = fwrite(p_buf, 1u, len, fp); (void)fclose(fp); if (n != len) { (void)remove(s_path_tmp); return -1; } (void)remove(p_path); /* 目标可能不存在(首写):remove 失败忽略 */ if (rename(s_path_tmp, p_path) != 0) { (void)remove(s_path_tmp); return -1; } return 0; } /* * 函数功能:文件状态(size + mtime 变更令牌) * 入口参数:p_path - 文件路径 const char * * p_st - 输出(不可为 NULL) cfg_file_stat_t * * 返回值:0 - 成功;-1 - 文件缺失/读失败 int * 限定条件:无 */ int cfg_store_stat(const char *p_path, cfg_file_stat_t *p_st) { struct stat st; if (p_st == NULL) { return -1; } if (stat(p_path, &st) != 0) { return -1; } p_st->size = (uint32_t)st.st_size; p_st->mtime = (uint32_t)st.st_mtime; return 0; } /* * 函数功能:删除文件 * 入口参数:p_path - 文件路径 const char * * 返回值:0 - 成功;-1 - 文件缺失/删除失败 int * 限定条件:无 */ int cfg_store_remove(const char *p_path) { if (remove(p_path) != 0) { return -1; } return 0; } /* * 函数功能:取配置文件路径 * 入口参数:无 * 返回值:"sim_config.ini"(模拟器工作目录) const char * * 限定条件:无 */ const char *cfg_store_config_path(void) { return s_path; } /* * 函数功能:取配置文件临时文件路径 * 入口参数:无 * 返回值:"sim_config.ini.tmp" const char * * 限定条件:无 */ const char *cfg_store_tmp_path(void) { return s_path_tmp; } /* * 函数功能:取旧版配置遗留文件路径 * 入口参数:无 * 返回值:"sim_netcfg.bin"(与 MCU 端旧格式一致,两端可互读) const char * * 限定条件:无 */ const char *cfg_store_legacy_path(void) { return s_path_legacy; }