files md5 6f6b0a6d; 0 warning; 宿主 test_fsx 全过(路径安全/格式化/排序/虚拟化/写操作/文本嗅探); qemu 离屏冒烟通过 SDK 缺口记录: listview 仅单行 label(本 App 用 custom 画布自绘行); common 档字库中文缺字(未声明 fonts:full) 真机待验证: 列表渲染/滚动手感/IME 重命名/弹窗交互
119 lines
5.8 KiB
C
119 lines
5.8 KiB
C
/* logic/fsx.h — 文件管理器业务逻辑接口(纯 C,不依赖 meow_ui.h / meow_view)。
|
||
*
|
||
* 分层契约(沿用 hello_app/logic/logic.h 的约定):
|
||
* - UI→业务 = 纯函数命令 + 查询(fsx_*);业务不回调 UI,UI 按返回值/err 自绘。
|
||
* - 本模块只含 libc + 标准头,因此可宿主编译(gcc 直接测),也可交叉编译进 MIPS 应用。
|
||
*
|
||
* 宿主可验证的纯逻辑(test/test_fsx.c 驱动):
|
||
* - 路径安全:fsx_within_sd / fsx_join / fsx_sanitize_name / fsx_is_root / fsx_basename
|
||
* - 展示格式化:fsx_fmt_size / fsx_fmt_time
|
||
* - 列表数据源:fsx_visible_range(虚拟化可见行)/ fsx_sort_entries(目录优先)
|
||
* - 目录枚举/写操作:fsx_scan_dir / fsx_delete / fsx_rename_into / fsx_mkdir / fsx_stat_path
|
||
* (这些做真 IO,仍可宿主测:指向临时目录)
|
||
*/
|
||
#ifndef FSX_H
|
||
#define FSX_H
|
||
|
||
#include <stddef.h>
|
||
|
||
/* TF 卡根(挂载点)。写操作只允许在它之下。
|
||
* 允许编译期 -DFSX_SD_ROOT=... 覆写(宿主测试指向临时目录,便于测写操作)。 */
|
||
#ifndef FSX_SD_ROOT
|
||
#define FSX_SD_ROOT "/usr/data/mnt/sd_0"
|
||
#endif
|
||
|
||
#define FSX_MAX_NAME 256 /* 文件名/路径分量上限(exFAT 255 字节)×... 保守 */
|
||
#define FSX_MAX_PATH 512 /* 一条完整路径上限 */
|
||
#define FSX_MAX_ENTRIES 1024/* 单目录缓存项上限(大目录截断 + 列表虚拟化只画可见行) */
|
||
|
||
/* 返回码(等价负 errno;0=成功)。与 errno 数值一致,便于 App 判空态/权限态。 */
|
||
#define FSX_ERR_IO (-1)
|
||
#define FSX_ERR_NOENT (-2) /* 路径不存在(卡不在/目录被移除) */
|
||
#define FSX_ERR_EACCES (-13) /* 权限拒绝 */
|
||
#define FSX_ERR_ENOTDIR (-20) /* 不是目录 */
|
||
|
||
/* 单个目录项快照(App 持有数组;fsx_scan_dir 填充)。 */
|
||
typedef struct fsx_entry {
|
||
char name[FSX_MAX_NAME]; /* 文件名(不含路径) */
|
||
char path[FSX_MAX_PATH]; /* 绝对路径(在卡内,fsx_join 构造) */
|
||
int is_dir; /* 1=目录 */
|
||
int is_link; /* 1=符号链接(v1 视为文件,不追链) */
|
||
long long size; /* 字节(目录=0) */
|
||
long long mtime; /* 修改时间(Unix 秒) */
|
||
} fsx_entry;
|
||
|
||
/* ============================================================ */
|
||
/* 路径安全(纯逻辑,写操作红线) */
|
||
/* ============================================================ */
|
||
|
||
/* 1=path 严格落在 FSX_SD_ROOT 之下(或等于根),且不含任何 ".." 分量。
|
||
* 拒绝 "/usr/data/mnt/sd_0evil" 这类前缀伪装,也拒绝 "../" 越界。 */
|
||
int fsx_within_sd(const char *path);
|
||
|
||
/* 1=path 精确等于 FSX_SD_ROOT。 */
|
||
int fsx_is_root(const char *path);
|
||
|
||
/* 安全拼接:base + "/" + name → out。name 须无 '/'、非 ".."、非空(通常已 sanitize)。
|
||
* 返回 0=成功;-1=参数非法/输出超长。 */
|
||
int fsx_join(const char *base, const char *name, char *out, int outsz);
|
||
|
||
/* 校验+清洗新建/重命名名(供 mkdir/rename):拒绝空/超长/含 '/'、'\\'、':'、以 '.' 开头、
|
||
* 含 ".."、含控制字符。清洗后拷入 out 并去尾随空白。返回 0=合法;负数=非法(-EINVAL)。 */
|
||
int fsx_sanitize_name(const char *name, char *out, int outsz);
|
||
|
||
/* 返回 path 最后一个 '/' 之后的分量(借用指针,不改写)。 */
|
||
const char *fsx_basename(const char *path);
|
||
|
||
/* 拷贝 path 的目录部分(去掉最后分量)到 out;根目录返回 FSX_SD_ROOT。返回 0=成功。 */
|
||
int fsx_dirname(const char *path, char *out, int outsz);
|
||
|
||
/* ============================================================ */
|
||
/* 展示格式化(纯逻辑) */
|
||
/* ============================================================ */
|
||
|
||
/* "123 B" / "1.2 KB" / "3.4 MB" / "1.2 GB"。 */
|
||
void fsx_fmt_size(long long size, char *out, int outsz);
|
||
|
||
/* "YYYY-MM-DD HH:MM"(本地时区)。 */
|
||
void fsx_fmt_time(long long mtime, char *out, int outsz);
|
||
|
||
/* ============================================================ */
|
||
/* 目录枚举 / 排序 / 虚拟化(列表数据源) */
|
||
/* ============================================================ */
|
||
|
||
/* 扫 path 目录到 entries[0..max),目录优先 + 名称升序。*out_count=读到的项数。
|
||
* 超过 max 截断(大目录:只缓存前 max 项,配合虚拟化渲染)。
|
||
* 返回 0=成功;<0=负 errno(-2=无卡/不存在;-13=权限)。空目录=0 且 count=0。 */
|
||
int fsx_scan_dir(const char *path, fsx_entry *entries, int max, int *out_count);
|
||
|
||
/* 目录优先,其次 name 升序(strcmp,字节序)。 */
|
||
void fsx_sort_entries(fsx_entry *entries, int n);
|
||
|
||
/* 虚拟化:给定总行数/行高/滚动/视口高,算可见 [first,last)。越界安全。 */
|
||
void fsx_visible_range(int count, int item_h, int scroll, int viewport_h,
|
||
int *first, int *last);
|
||
|
||
/* 最大滚动偏移:max(0, count*item_h - viewport_h)。 */
|
||
int fsx_max_scroll(int count, int item_h, int viewport_h);
|
||
|
||
/* ============================================================ */
|
||
/* 写/查操作(全部先 fsx_within_sd 校验;0=成功,<0=负 errno) */
|
||
/* ============================================================ */
|
||
|
||
/* 删除:目录(须空)rmdir,否则 unlink。 */
|
||
int fsx_delete(const char *path);
|
||
|
||
/* 重命名 *path 为 *new_name(同名目录下)。目标已存在→-EEXIST。 */
|
||
int fsx_rename_into(const char *path, const char *new_name);
|
||
|
||
/* 在 base 目录下新建子目录 name。 */
|
||
int fsx_mkdir(const char *base, const char *name);
|
||
|
||
/* stat 一个路径填 entry(lstat,不追符号链)。0=成功,<0=负 errno。 */
|
||
int fsx_stat_path(const char *path, fsx_entry *out);
|
||
|
||
/* 简单文本判定:按扩展名白名单(用于读预览)。1=视为文本。 */
|
||
int fsx_is_text_path(const char *path);
|
||
|
||
#endif /* FSX_H */
|