/* fat32_io.h — Deshab 用户态共享 FAT32 读写库(static inline,无库) * * 前置条件:包含者已定义 u8/u16/u32/u64/i64 基础类型。 * 通过 f32_init() 注入 block_read/block_write 函数指针(来自 dkm_kernel_api + 0xA8)。 * * 能力:FAT32 根目录文件的读/写/删/列举,支持 FAT 链跟随、多簇文件。 * 限制:仅根目录(不支持子目录,Phase 2.2 fileman 将扩展);单文件最大 256KB。 * * 用法: * f32_init(block_read, block_write) — 初始化(block_write 可为 NULL,仅读场景) * f32_name_to_83("file.txt", name11) — "file.txt" → 11 字符 8.3 名 * f32_read_root_file(name11, &data, &size) — 读根目录文件到 f32_data 缓冲 * f32_write_root_file(name11, data, size) — 写/替换根目录文件 * f32_delete_root_file(name11) — 删除根目录文件 * f32_list_root(emit_cb, user_data) — 列举根目录 * * 缓冲区:每个包含本头的 .elf 独立持有 256KB g_disk + 4KB g_cluster + 256KB g_fdata(共 ~516KB BSS)。 * 与 net_stack.h 同模式,接受 static 缓冲的代价以换取无库依赖。 */ #ifndef DESHAB_FAT32_IO_H #define DESHAB_FAT32_IO_H /* ---- block 设备函数类型(与 shell/DSK 一致:index 参数固定 0) ---- */ typedef int (*f32_block_read_fn)(u32 index, u64 lba, u32 count, void *buf); typedef int (*f32_block_write_fn)(u32 index, u64 lba, u32 count, const void *buf); static f32_block_read_fn f32_blk_read = 0; static f32_block_write_fn f32_blk_write = 0; /* ---- FAT32 BPB / 目录项结构(packed,与 DSK/shell 一致) ---- */ typedef struct __attribute__((packed)) { u8 jmp[3]; char oem[8]; u16 bps; u8 spc; u16 rsvd; u8 fc; u16 root_ent; u16 ts16; u8 media; u16 spf16; u16 spt; u16 heads; u32 hidden; u32 ts32; u32 spf; u16 flags; u16 ver; u32 root_clus; u16 fsi; u16 bkboot; u8 res[12]; u8 drv; u8 ntfl; u8 sig; u32 ser; char lbl[11]; char typ[8]; u8 code[420]; u16 boot_sig; } f32_bpb; typedef struct __attribute__((packed)) { char name[11]; u8 attr; u8 ntr; u8 ctenth; u16 ctime; u16 cdate; u16 adate; u16 chigh; u16 wtime; u16 wdate; u16 clow; u32 fsize; } f32_dirent; /* ---- 内部小工具 ---- */ static inline u32 f32_r32(const u8 *p) { return (u32)p[0]|((u32)p[1]<<8)|((u32)p[2]<<16)|((u32)p[3]<<24); } static inline u16 f32_r16(const u8 *p) { return (u16)p[0]|((u16)p[1]<<8); } static inline int f32_neq11(const char *a, const char *b) { for (int i = 0; i < 11; i++) if (a[i] != b[i]) return 0; return 1; } /* ---- 批量读写缓冲区(与 DSK/shell 对齐:256 扇区覆盖 BPB+FAT+根目录+小文件) ---- */ static u8 f32_disk[131072]; /* 256 扇区 BPB+FAT+根目录缓存 */ static u8 f32_cluster[4096]; /* 单簇缓冲 */ static u8 f32_data[262144]; /* 文件数据缓冲(最大 256KB) */ static int f32_disk_loaded = 0; /* f32_disk 是否已加载 BPB+FAT */ /* 初始化:注入 block_read/block_write 函数指针 */ static inline void f32_init(f32_block_read_fn rd, f32_block_write_fn wr) { f32_blk_read = rd; f32_blk_write = wr; f32_disk_loaded = 0; } static inline int f32_read_sectors(u32 lba, u32 count, u8 *out) { return f32_blk_read ? f32_blk_read(0, lba, count, out) : -1; } static inline int f32_write_sectors(u32 lba, u32 count, const u8 *buf) { return f32_blk_write ? f32_blk_write(0, lba, count, buf) : -1; } /* 确保 f32_disk 已加载 BPB+FAT+根目录(256 扇区) */ static inline int f32_disk_load(void) { if (f32_disk_loaded) return 0; if (f32_read_sectors(0, 256, f32_disk) != 0) return -1; const f32_bpb *bpb = (const f32_bpb *)f32_disk; if (bpb->boot_sig != 0xAA55 || bpb->bps != 512) return -2; if (bpb->spf == 0 || bpb->root_clus < 2) return -3; f32_disk_loaded = 1; return 0; } /* ---- 8.3 名字转换 ---- */ /* "file.txt" / "NAME" → 11 字符 8.3 名(大写,空格填充) * 返回 0 成功,-1 失败(过长或非法字符) */ static inline int f32_name_to_83(const char *in, char out[11]) { for (int i = 0; i < 11; i++) out[i] = ' '; int inlen = 0; while (in[inlen] && inlen < 13) inlen++; if (inlen == 0 || inlen > 12) return -1; int dot = -1; for (int i = 0; i < inlen; i++) if (in[i] == '.') dot = i; int base_end = (dot >= 0) ? dot : inlen; if (base_end == 0 || base_end > 8) return -1; for (int j = 0; j < base_end; j++) { char c = in[j]; if (c >= 'a' && c <= 'z') c -= 32; if (c == '.' || c == ' ' || c == '/' || c == '\\') return -1; out[j] = c; } if (dot >= 0) { int extlen = inlen - dot - 1; if (extlen > 3) return -1; for (int j = 0; j < extlen; j++) { char c = in[dot + 1 + j]; if (c >= 'a' && c <= 'z') c -= 32; if (c == '.' || c == ' ' || c == '/' || c == '\\') return -1; out[8 + j] = c; } } return 0; } /* 11 字符 8.3 名 → 可显示字符串(如 "README.TXT") */ static inline void f32_name_from_83(const char in[11], char out[13]) { int p = 0; for (int j = 0; j < 8; j++) { if (in[j] == ' ') break; out[p++] = in[j]; } if (in[8] != ' ') { out[p++] = '.'; for (int j = 8; j < 11; j++) { if (in[j] == ' ') break; out[p++] = in[j]; } } out[p] = 0; } /* ---- 根目录文件查找 ---- */ /* 在根目录簇链中查找 11 字符名,输出首簇号与文件大小 */ static inline int f32_find_in_root(const u8 *clus, u32 clus_sectors, const char *target, u32 *out_clus, u32 *out_size, u32 *out_idx) { const f32_dirent *dir = (const f32_dirent *)clus; for (u32 e = 0; e * 32 < clus_sectors * 512; e++) { if (dir[e].name[0] == 0) break; if ((u8)dir[e].name[0] == 0xE5) continue; if (dir[e].attr == 0x0F) continue; if (dir[e].attr & 0x08) continue; if (f32_neq11(dir[e].name, target)) { *out_clus = (u32)f32_r16((const u8*)&dir[e].clow) | ((u32)f32_r16((const u8*)&dir[e].chigh) << 16); *out_size = dir[e].fsize; if (out_idx) *out_idx = e; return 0; } } return -1; } /* 读取根目录下指定 8.3 名文件到 f32_data。 * 返回 0 成功,*out_data 指向 f32_data,*out_size 为字节数;非 0 失败。 */ static inline int f32_read_root_file(const char *name11, u8 **out_data, u32 *out_size) { if (f32_disk_load() != 0) return -1; const f32_bpb *bpb = (const f32_bpb *)f32_disk; u32 data_lba = bpb->rsvd + (u32)bpb->fc * bpb->spf; u32 fat_byte_off = bpb->rsvd * 512; u32 spc = bpb->spc; u32 clus = bpb->root_clus; u32 found_clus = 0, found_size = 0; int found = 0; while (clus >= 2 && clus < 0x0FFFFFF8 && !found) { u32 lba = data_lba + (clus - 2) * spc; const u8 *cb; if ((u64)lba * 512 + (u64)spc * 512 <= 256ULL * 512) cb = f32_disk + (u64)lba * 512; else { if (f32_read_sectors(lba, 8, f32_cluster) != 0) return -4; cb = f32_cluster; } if (f32_find_in_root(cb, spc, name11, &found_clus, &found_size, 0) == 0) { found = 1; break; } u32 fo = fat_byte_off + clus * 4; if (fo + 4 > sizeof(f32_disk)) break; clus = f32_r32(f32_disk + fo) & 0x0FFFFFFF; } if (!found) return -5; if (found_size > sizeof(f32_data)) return -6; u8 *dst = f32_data; u32 remaining = found_size; u32 fc = found_clus; while (fc >= 2 && fc < 0x0FFFFFF8 && remaining > 0) { u32 fc_lba = data_lba + (fc - 2) * spc; u32 fc_bytes = spc * 512; if (fc_bytes > remaining) fc_bytes = remaining; const u8 *fb; if ((u64)fc_lba * 512 + (u64)spc * 512 <= 256ULL * 512) fb = f32_disk + (u64)fc_lba * 512; else { if (f32_read_sectors(fc_lba, 8, f32_cluster) != 0) return -7; fb = f32_cluster; } for (u32 b = 0; b < fc_bytes; b++) dst[b] = fb[b]; dst += fc_bytes; remaining -= fc_bytes; u32 fo = fat_byte_off + fc * 4; if (fo + 4 > sizeof(f32_disk)) break; fc = f32_r32(f32_disk + fo) & 0x0FFFFFFF; } *out_data = f32_data; *out_size = found_size; return 0; } /* 写入根目录下指定 8.3 名文件(存在则替换,不存在则新建)。 * 依赖 f32_disk 已加载 BPB+FAT。返回 0 成功。 */ static inline int f32_write_root_file(const char *name11, const u8 *data, u32 size) { if (f32_disk_load() != 0) return -1; if (!f32_blk_write) return -10; /* 写入前重新加载 BPB+FAT,保证与盘上一致 */ if (f32_read_sectors(0, 256, f32_disk) != 0) return -2; const f32_bpb *bpb = (const f32_bpb *)f32_disk; u32 spc = bpb->spc; u32 fat_lba = bpb->rsvd; u32 fat_sectors = bpb->spf; u32 data_lba = bpb->rsvd + (u32)bpb->fc * bpb->spf; u32 fat_byte_off = bpb->rsvd * 512; u32 root_clus = bpb->root_clus; u32 cluster_bytes = spc * 512; u32 root_lba = data_lba + (root_clus - 2) * spc; u8 *root_buf = f32_disk + (u64)root_lba * 512; u32 max_entries = cluster_bytes / 32; f32_dirent *dir = (f32_dirent *)root_buf; int free_entry = -1; u32 existing_clus = 0; int found = 0; u32 existing_idx = 0; for (u32 e = 0; e < max_entries; e++) { if (dir[e].name[0] == 0) { if (free_entry < 0) free_entry = (int)e; break; } if ((u8)dir[e].name[0] == 0xE5) { if (free_entry < 0) free_entry = (int)e; continue; } if (dir[e].attr == 0x0F) continue; if (dir[e].attr & 0x08) continue; if (f32_neq11(dir[e].name, name11)) { existing_clus = (u32)f32_r16((const u8*)&dir[e].clow) | ((u32)f32_r16((const u8*)&dir[e].chigh) << 16); found = 1; existing_idx = e; if (free_entry < 0) free_entry = (int)e; break; } } u32 bytes_needed = size > 0 ? size : 1; u32 clusters_needed = (bytes_needed + cluster_bytes - 1) / cluster_bytes; u32 first_clus = 0; u32 prev_clus = 0; if (found && existing_clus >= 2) { first_clus = existing_clus; u32 cur = existing_clus; u32 count = 0; while (cur >= 2 && cur < 0x0FFFFFF8 && count < clusters_needed) { prev_clus = cur; u32 fo = fat_byte_off + cur * 4; if (fo + 4 > sizeof(f32_disk)) break; cur = f32_r32(f32_disk + fo) & 0x0FFFFFFF; count++; } while (count < clusters_needed) { u32 newc = 0; for (u32 c = 2; c < (fat_sectors * 512) / 4; c++) { u32 fo = fat_byte_off + c * 4; if (fo + 4 > sizeof(f32_disk)) break; if ((f32_r32(f32_disk + fo) & 0x0FFFFFFF) == 0) { newc = c; break; } } if (newc == 0) return -3; u32 pfo = fat_byte_off + prev_clus * 4; if (pfo + 4 <= sizeof(f32_disk)) { f32_disk[pfo] = (u8)(newc & 0xFF); f32_disk[pfo+1] = (u8)((newc >> 8) & 0xFF); f32_disk[pfo+2] = (u8)((newc >> 16) & 0xFF); f32_disk[pfo+3] = (u8)((newc >> 24) & 0x0F); } prev_clus = newc; count++; } if (prev_clus >= 2) { u32 fo = fat_byte_off + prev_clus * 4; if (fo + 4 <= sizeof(f32_disk)) { f32_disk[fo] = 0xF8; f32_disk[fo+1] = 0xFF; f32_disk[fo+2] = 0xFF; f32_disk[fo+3] = 0x0F; } } /* 释放多余旧簇 */ u32 next = 0; u32 fo = fat_byte_off + prev_clus * 4; if (fo + 4 <= sizeof(f32_disk)) next = f32_r32(f32_disk + fo) & 0x0FFFFFFF; while (next >= 2 && next < 0x0FFFFFF8) { u32 nfo = fat_byte_off + next * 4; u32 nn = 0; if (nfo + 4 <= sizeof(f32_disk)) nn = f32_r32(f32_disk + nfo) & 0x0FFFFFFF; f32_disk[nfo] = 0; f32_disk[nfo+1] = 0; f32_disk[nfo+2] = 0; f32_disk[nfo+3] = 0; next = nn; } } else { if (free_entry < 0) return -4; for (u32 i = 0; i < clusters_needed; i++) { u32 newc = 0; for (u32 c = 2; c < (fat_sectors * 512) / 4; c++) { u32 fo = fat_byte_off + c * 4; if (fo + 4 > sizeof(f32_disk)) break; if ((f32_r32(f32_disk + fo) & 0x0FFFFFFF) == 0) { newc = c; break; } } if (newc == 0) return -3; if (i == 0) first_clus = newc; if (prev_clus >= 2) { u32 pfo = fat_byte_off + prev_clus * 4; f32_disk[pfo] = (u8)(newc & 0xFF); f32_disk[pfo+1] = (u8)((newc >> 8) & 0xFF); f32_disk[pfo+2] = (u8)((newc >> 16) & 0xFF); f32_disk[pfo+3] = (u8)((newc >> 24) & 0x0F); } prev_clus = newc; } if (prev_clus >= 2) { u32 fo = fat_byte_off + prev_clus * 4; f32_disk[fo] = 0xF8; f32_disk[fo+1] = 0xFF; f32_disk[fo+2] = 0xFF; f32_disk[fo+3] = 0x0F; } } /* 写数据到簇 */ u32 remaining = size; const u8 *src = data; u32 cur = first_clus; u32 ci = 0; while (cur >= 2 && cur < 0x0FFFFFF8 && ci < clusters_needed) { u32 clba = data_lba + (cur - 2) * spc; u32 chunk = remaining < cluster_bytes ? remaining : cluster_bytes; if ((u64)clba * 512 + cluster_bytes <= 256ULL * 512) { u8 *dst = f32_disk + (u64)clba * 512; for (u32 b = 0; b < chunk; b++) dst[b] = src[b]; for (u32 b = chunk; b < cluster_bytes; b++) dst[b] = 0; } else { if (f32_read_sectors(clba, spc, f32_cluster) != 0) return -5; for (u32 b = 0; b < chunk; b++) f32_cluster[b] = src[b]; for (u32 b = chunk; b < cluster_bytes; b++) f32_cluster[b] = 0; if (f32_write_sectors(clba, spc, f32_cluster) != 0) return -6; } src += chunk; remaining -= chunk; ci++; u32 fo = fat_byte_off + cur * 4; if (fo + 4 > sizeof(f32_disk)) break; cur = f32_r32(f32_disk + fo) & 0x0FFFFFFF; } /* 更新目录项 */ u32 entry_idx = found ? existing_idx : (u32)free_entry; f32_dirent *e = &dir[entry_idx]; if (!found) { for (int i = 0; i < 11; i++) e->name[i] = name11[i]; e->attr = 0x20; e->ntr = 0; e->ctenth = 0; e->ctime = 0; e->cdate = 0; e->adate = 0; } e->chigh = (u16)((first_clus >> 16) & 0xFFFF); e->clow = (u16)(first_clus & 0xFFFF); e->fsize = size; /* 回写 FAT(两份)+ 根目录 + 缓冲区内的数据簇 */ for (u32 f = 0; f < bpb->fc; f++) { u32 flba = fat_lba + f * fat_sectors; if (f32_write_sectors(flba, fat_sectors, f32_disk + (u64)flba * 512) != 0) return -7; } u32 root_dir_lba = data_lba + (root_clus - 2) * spc; if ((u64)root_dir_lba * 512 + cluster_bytes <= 256ULL * 512) { if (f32_write_sectors(root_dir_lba, spc, f32_disk + (u64)root_dir_lba * 512) != 0) return -8; } cur = first_clus; ci = 0; while (cur >= 2 && cur < 0x0FFFFFF8 && ci < clusters_needed) { u32 clba = data_lba + (cur - 2) * spc; if ((u64)clba * 512 + cluster_bytes <= 256ULL * 512) { if (f32_write_sectors(clba, spc, f32_disk + (u64)clba * 512) != 0) return -9; } u32 fo = fat_byte_off + cur * 4; if (fo + 4 > sizeof(f32_disk)) break; cur = f32_r32(f32_disk + fo) & 0x0FFFFFFF; ci++; } f32_disk_loaded = 0; /* 下次操作重新加载,避免使用脏缓存 */ return 0; } /* 删除根目录下指定 8.3 名文件:清空簇链 + 标记目录项为 0xE5。 * 返回 0 成功,-1 未找到,其他负值失败。 */ static inline int f32_delete_root_file(const char *name11) { if (f32_disk_load() != 0) return -2; if (!f32_blk_write) return -10; if (f32_read_sectors(0, 256, f32_disk) != 0) return -3; const f32_bpb *bpb = (const f32_bpb *)f32_disk; u32 spc = bpb->spc; u32 fat_lba = bpb->rsvd; u32 fat_sectors = bpb->spf; u32 data_lba = bpb->rsvd + (u32)bpb->fc * bpb->spf; u32 fat_byte_off = bpb->rsvd * 512; u32 root_clus = bpb->root_clus; u32 root_lba = data_lba + (root_clus - 2) * spc; u8 *root_buf = f32_disk + (u64)root_lba * 512; u32 max_entries = (spc * 512) / 32; f32_dirent *dir = (f32_dirent *)root_buf; u32 found_idx = 0xFFFFFFFFu; for (u32 e = 0; e < max_entries; e++) { if (dir[e].name[0] == 0) break; if ((u8)dir[e].name[0] == 0xE5) continue; if (dir[e].attr == 0x0F) continue; if (dir[e].attr & 0x08) continue; if (f32_neq11(dir[e].name, name11)) { found_idx = e; break; } } if (found_idx == 0xFFFFFFFFu) return -1; /* 释放簇链 */ u32 cur = (u32)f32_r16((const u8*)&dir[found_idx].clow) | ((u32)f32_r16((const u8*)&dir[found_idx].chigh) << 16); while (cur >= 2 && cur < 0x0FFFFFF8) { u32 fo = fat_byte_off + cur * 4; u32 next = 0; if (fo + 4 <= sizeof(f32_disk)) next = f32_r32(f32_disk + fo) & 0x0FFFFFFF; f32_disk[fo] = 0; f32_disk[fo+1] = 0; f32_disk[fo+2] = 0; f32_disk[fo+3] = 0; cur = next; } /* 标记目录项为已删除 */ dir[found_idx].name[0] = (char)0xE5; /* 回写 FAT + 根目录 */ for (u32 f = 0; f < bpb->fc; f++) { u32 flba = fat_lba + f * fat_sectors; if (f32_write_sectors(flba, fat_sectors, f32_disk + (u64)flba * 512) != 0) return -4; } if (f32_write_sectors(root_lba, spc, f32_disk + (u64)root_lba * 512) != 0) return -5; f32_disk_loaded = 0; return 0; } /* 列举根目录条目回调签名:返回 0 继续,非 0 停止 */ typedef int (*f32_list_cb)(const char *name, u32 size, u8 attr, void *user_data); /* 列出根目录所有文件/目录,调用回调输出。 * 回调返回非 0 立即停止。返回 0 成功(含回调提前停止),负值失败。 */ static inline int f32_list_root(f32_list_cb emit, void *user_data) { if (f32_disk_load() != 0) return -1; const f32_bpb *bpb = (const f32_bpb *)f32_disk; u32 data_lba = bpb->rsvd + (u32)bpb->fc * bpb->spf; u32 fat_byte_off = bpb->rsvd * 512; u32 spc = bpb->spc; u32 clus = bpb->root_clus; while (clus >= 2 && clus < 0x0FFFFFF8) { u32 lba = data_lba + (clus - 2) * spc; const u8 *cb; if ((u64)lba * 512 + (u64)spc * 512 <= 256ULL * 512) cb = f32_disk + (u64)lba * 512; else { if (f32_read_sectors(lba, 8, f32_cluster) != 0) return -4; cb = f32_cluster; } const f32_dirent *dir = (const f32_dirent *)cb; for (u32 e = 0; e * 32 < spc * 512; e++) { if (dir[e].name[0] == 0) goto done; if ((u8)dir[e].name[0] == 0xE5) continue; if (dir[e].attr == 0x0F) continue; if (dir[e].attr & 0x08) continue; char disp[13]; f32_name_from_83(dir[e].name, disp); if (emit(disp, dir[e].fsize, dir[e].attr, user_data) != 0) goto done; } u32 fo = fat_byte_off + clus * 4; if (fo + 4 > sizeof(f32_disk)) break; clus = f32_r32(f32_disk + fo) & 0x0FFFFFFF; } done: return 0; } /* ---- 子目录遍历支持(Phase 2.2 fileman 扩展) ---- */ /* 目录条目(供 fileman 等工具使用) */ typedef struct { char name[13]; /* 8.3 显示名 */ u32 clus; /* 首簇号 */ u32 size; /* 文件大小(目录为 0) */ u8 attr; u8 is_dir; } f32_entry; typedef int (*f32_list_entry_cb)(const f32_entry *e, void *user_data); /* 列举指定目录簇的内容。 * dir_clus = 0 表示根目录(自动从 BPB 取 root_clus)。 * 回调返回非 0 立即停止。返回 0 成功,负值失败。 */ static inline int f32_list_dir(u32 dir_clus, f32_list_entry_cb emit, void *user_data) { if (f32_disk_load() != 0) return -1; const f32_bpb *bpb = (const f32_bpb *)f32_disk; u32 data_lba = bpb->rsvd + (u32)bpb->fc * bpb->spf; u32 fat_byte_off = bpb->rsvd * 512; u32 spc = bpb->spc; u32 clus = (dir_clus == 0) ? bpb->root_clus : dir_clus; while (clus >= 2 && clus < 0x0FFFFFF8) { u32 lba = data_lba + (clus - 2) * spc; const u8 *cb; if ((u64)lba * 512 + (u64)spc * 512 <= 256ULL * 512) cb = f32_disk + (u64)lba * 512; else { if (f32_read_sectors(lba, 8, f32_cluster) != 0) return -4; cb = f32_cluster; } const f32_dirent *dir = (const f32_dirent *)cb; for (u32 e = 0; e * 32 < spc * 512; e++) { if (dir[e].name[0] == 0) goto done; if ((u8)dir[e].name[0] == 0xE5) continue; if (dir[e].attr == 0x0F) continue; if (dir[e].attr & 0x08) continue; /* 跳过 "." 和 ".." 条目 */ if (dir[e].name[0] == '.' && (dir[e].name[1] == ' ' || dir[e].name[1] == '.')) continue; f32_entry fe; f32_name_from_83(dir[e].name, fe.name); fe.clus = (u32)f32_r16((const u8*)&dir[e].clow) | ((u32)f32_r16((const u8*)&dir[e].chigh) << 16); fe.size = dir[e].fsize; fe.attr = dir[e].attr; fe.is_dir = (dir[e].attr & 0x10) ? 1 : 0; if (emit(&fe, user_data) != 0) goto done; } u32 fo = fat_byte_off + clus * 4; if (fo + 4 > sizeof(f32_disk)) break; clus = f32_r32(f32_disk + fo) & 0x0FFFFFFF; } done: return 0; } /* 按首簇号 + 大小读取文件内容到 out_buf。 * out_buf 至少 size 字节容量。返回 0 成功,负值失败。 */ static inline int f32_read_file_by_clus(u32 clus, u32 size, u8 *out_buf, u32 buf_cap) { if (f32_disk_load() != 0) return -1; if (size > buf_cap) size = buf_cap; const f32_bpb *bpb = (const f32_bpb *)f32_disk; u32 data_lba = bpb->rsvd + (u32)bpb->fc * bpb->spf; u32 fat_byte_off = bpb->rsvd * 512; u32 spc = bpb->spc; u32 remaining = size; u8 *dst = out_buf; u32 fc = clus; while (fc >= 2 && fc < 0x0FFFFFF8 && remaining > 0) { u32 fc_lba = data_lba + (fc - 2) * spc; u32 fc_bytes = spc * 512; if (fc_bytes > remaining) fc_bytes = remaining; const u8 *fb; if ((u64)fc_lba * 512 + (u64)spc * 512 <= 256ULL * 512) fb = f32_disk + (u64)fc_lba * 512; else { if (f32_read_sectors(fc_lba, 8, f32_cluster) != 0) return -7; fb = f32_cluster; } for (u32 b = 0; b < fc_bytes; b++) dst[b] = fb[b]; dst += fc_bytes; remaining -= fc_bytes; u32 fo = fat_byte_off + fc * 4; if (fo + 4 > sizeof(f32_disk)) break; fc = f32_r32(f32_disk + fo) & 0x0FFFFFFF; } return 0; } #endif /* DESHAB_FAT32_IO_H */