10#include "kstd_cstring"
23auto FresultToErrorCode(FRESULT fr) ->
ErrorCode {
33 case FR_WRITE_PROTECTED:
39 case FR_INVALID_DRIVE:
41 case FR_NOT_ENOUGH_CORE:
44 case FR_INVALID_PARAMETER:
45 case FR_INVALID_OBJECT:
47 case FR_TOO_MANY_OPEN_FILES:
63 return std::unexpected(
Error{FresultToErrorCode(fr)});
70 if ((fi.fattrib & AM_DIR) != 0) {
81 block_devices_[pdrv] = device;
89 return block_devices_[pdrv];
93 : volume_id_(volume_id),
110 if (device ==
nullptr) {
111 klog::Err(
"FatFsFileSystem::Mount: device is nullptr");
119 SetBlockDevice(volume_id_, device);
122 char path[4] = {
static_cast<char>(
'0' + volume_id_),
':',
'/',
'\0'};
124 FRESULT fr = f_mount(&fatfs_obj_, path, 1);
126 SetBlockDevice(volume_id_,
nullptr);
127 klog::Err(
"FatFsFileSystem::Mount: f_mount failed ({})",
128 static_cast<int>(fr));
129 return std::unexpected(
Error{FresultToErrorCode(fr)});
135 (void)f_mount(
nullptr, path, 0);
136 SetBlockDevice(volume_id_,
nullptr);
148 fi->
path[fi->
path.size() - 1] =
'\0';
150 root_inode_ = &fi->
inode;
159 char path[4] = {
static_cast<char>(
'0' + volume_id_),
':',
'/',
'\0'};
160 FRESULT fr = f_mount(
nullptr, path, 0);
161 SetBlockDevice(volume_id_,
nullptr);
163 root_inode_ =
nullptr;
164 for (
auto& node : inodes_) {
166 if (node.dir !=
nullptr) {
167 (void)f_closedir(node.dir);
174 return FresultToExpected(fr);
178 auto* dev = GetBlockDevice(volume_id_);
179 if (dev !=
nullptr) {
197 if (inode ==
nullptr) {
200 auto* fi =
static_cast<FatInode*
>(inode->fs_private);
208 for (
auto& fi : inodes_) {
225 for (
auto& fh : fil_pool_) {
236 for (
auto& fh : fil_pool_) {
237 if (&fh.fil == fil) {
245 for (
auto& dh : dir_pool_) {
256 for (
auto& dh : dir_pool_) {
257 if (&dh.dir == dir) {
266 auto* fi =
static_cast<FatInode*
>(inode->fs_private);
267 if (fi->fil !=
nullptr) {
271 FIL* fil = AllocateFil();
272 if (fil ==
nullptr) {
284 fa_mode = FA_READ | FA_WRITE;
287 fa_mode |= FA_OPEN_ALWAYS;
290 fa_mode |= FA_CREATE_ALWAYS;
292 FRESULT fr = f_open(fil, fi->path.data(), fa_mode);
295 return std::unexpected(
Error{FresultToErrorCode(fr)});
303 auto* dir_fi =
static_cast<FatInode*
>(dir->fs_private);
306 std::array<char, kPathBufSize> full_path{};
307 strncpy(full_path.data(), dir_fi->path.data(), full_path.size() - 1);
308 size_t dir_len =
strlen(full_path.data());
309 strncpy(full_path.data() + dir_len, name, full_path.size() - dir_len - 1);
310 full_path[full_path.size() - 1] =
'\0';
313 FRESULT fr = f_stat(full_path.data(), &fi_info);
315 return std::unexpected(
Error{FresultToErrorCode(fr)});
318 auto inode_result = fs_->AllocateInode();
320 return std::unexpected(inode_result.error());
325 inode->
type = FilInfoToFileType(fi_info);
326 inode->
size = fi_info.fsize;
329 strncpy(new_fi->path.data(), full_path.data(), new_fi->path.size() - 1);
330 new_fi->path[new_fi->path.size() - 1] =
'\0';
337 auto* dir_fi =
static_cast<FatInode*
>(dir->fs_private);
338 std::array<char, kPathBufSize> full_path{};
339 strncpy(full_path.data(), dir_fi->path.data(), full_path.size() - 1);
340 size_t dir_len =
strlen(full_path.data());
341 strncpy(full_path.data() + dir_len, name, full_path.size() - dir_len - 1);
342 full_path[full_path.size() - 1] =
'\0';
345 FRESULT fr = f_mkdir(full_path.data());
347 return std::unexpected(
Error{FresultToErrorCode(fr)});
351 FRESULT fr = f_open(&fil, full_path.data(), FA_CREATE_NEW | FA_WRITE);
353 return std::unexpected(
Error{FresultToErrorCode(fr)});
358 auto inode_result = fs_->AllocateInode();
360 return std::unexpected(inode_result.error());
369 strncpy(new_fi->path.data(), full_path.data(), new_fi->path.size() - 1);
370 new_fi->path[new_fi->path.size() - 1] =
'\0';
376 auto* dir_fi =
static_cast<FatInode*
>(dir->fs_private);
377 std::array<char, kPathBufSize> full_path{};
378 strncpy(full_path.data(), dir_fi->path.data(), full_path.size() - 1);
379 size_t dir_len =
strlen(full_path.data());
380 strncpy(full_path.data() + dir_len, name, full_path.size() - dir_len - 1);
381 full_path[full_path.size() - 1] =
'\0';
382 return FresultToExpected(f_unlink(full_path.data()));
393 return Unlink(dir, name);
398 auto* fi =
static_cast<FatInode*
>(file->inode->fs_private);
399 if (fi->fil ==
nullptr) {
403 FRESULT fr = f_read(fi->fil, buf,
static_cast<UINT
>(count), &bytes_read);
405 klog::Err(
"FatFsFileOps::Read: f_read failed ({})",
static_cast<int>(fr));
406 return std::unexpected(
Error{FresultToErrorCode(fr)});
408 file->offset += bytes_read;
409 return static_cast<size_t>(bytes_read);
414 auto* fi =
static_cast<FatInode*
>(file->inode->fs_private);
415 if (fi->fil ==
nullptr) {
418 UINT bytes_written = 0;
419 FRESULT fr = f_write(fi->fil, buf,
static_cast<UINT
>(count), &bytes_written);
421 klog::Err(
"FatFsFileOps::Write: f_write failed ({})",
static_cast<int>(fr));
422 return std::unexpected(
Error{FresultToErrorCode(fr)});
424 file->offset += bytes_written;
425 file->inode->size =
static_cast<uint64_t
>(f_size(fi->fil));
426 return static_cast<size_t>(bytes_written);
432 auto* fi =
static_cast<FatInode*
>(file->inode->fs_private);
433 if (fi->fil ==
nullptr) {
439 new_pos =
static_cast<FSIZE_t
>(offset);
443 static_cast<FSIZE_t
>(
static_cast<int64_t
>(f_tell(fi->fil)) + offset);
447 static_cast<FSIZE_t
>(
static_cast<int64_t
>(f_size(fi->fil)) + offset);
450 FRESULT fr = f_lseek(fi->fil, new_pos);
452 return std::unexpected(
Error{FresultToErrorCode(fr)});
454 file->offset =
static_cast<uint64_t
>(new_pos);
455 return static_cast<uint64_t
>(new_pos);
459 auto* fi =
static_cast<FatInode*
>(file->inode->fs_private);
462 if (fi->dir !=
nullptr) {
463 (void)f_closedir(fi->dir);
464 fs_->FreeDir(fi->dir);
469 if (fi->fil ==
nullptr) {
472 FRESULT fr = f_close(fi->fil);
473 fs_->FreeFil(fi->fil);
475 return FresultToExpected(fr);
481 auto* fi =
static_cast<FatInode*
>(file->inode->fs_private);
484 if (fi->dir ==
nullptr) {
485 DIR* dir = fs_->AllocateDir();
486 if (dir ==
nullptr) {
489 FRESULT fr = f_opendir(dir, fi->path.data());
492 return std::unexpected(
Error{FresultToErrorCode(fr)});
497 size_t read_count = 0;
498 for (
size_t i = 0; i < count; ++i) {
500 FRESULT fr = f_readdir(fi->dir, &fi_info);
501 if (fr != FR_OK || fi_info.fname[0] ==
'\0') {
505 dirent[i].type =
static_cast<uint8_t
>((fi_info.fattrib & AM_DIR) != 0
508 strncpy(dirent[i].name, fi_info.fname,
sizeof(dirent[i].name) - 1);
509 dirent[i].name[
sizeof(dirent[i].name) - 1] =
'\0';
512 file->offset +=
static_cast<uint64_t
>(read_count);
auto Close(vfs::File *file) -> Expected< void > override
关闭文件,释放底层 FIL 对象
auto Read(vfs::File *file, void *buf, size_t count) -> Expected< size_t > override
从文件读取数据
auto Seek(vfs::File *file, int64_t offset, vfs::SeekWhence whence) -> Expected< uint64_t > override
移动文件读写位置
auto Write(vfs::File *file, const void *buf, size_t count) -> Expected< size_t > override
向文件写入数据
auto ReadDir(vfs::File *file, vfs::DirEntry *dirent, size_t count) -> Expected< size_t > override
读取目录条目
auto Lookup(vfs::Inode *dir, const char *name) -> Expected< vfs::Inode * > override
在目录中查找指定名称的 inode
auto Rmdir(vfs::Inode *dir, const char *name) -> Expected< void > override
删除目录中的空子目录
auto Create(vfs::Inode *dir, const char *name, vfs::FileType type) -> Expected< vfs::Inode * > override
在目录中创建文件或子目录
auto Unlink(vfs::Inode *dir, const char *name) -> Expected< void > override
删除目录中的文件条目
auto Mkdir(vfs::Inode *dir, const char *name) -> Expected< vfs::Inode * > override
在目录中创建子目录
auto FreeInode(vfs::Inode *inode) -> Expected< void > override
释放 inode
auto AllocateFatInode() -> FatInode *
从 inode 池中分配一个空闲槽位
FatFsFileSystem(uint8_t volume_id)
构造函数,绑定到指定 FatFS 卷号
auto FreeFil(FIL *fil) -> void
归还 FIL 对象到池中
static auto SetBlockDevice(uint8_t pdrv, vfs::BlockDevice *device) -> void
注册块设备(由 Mount 调用,供 diskio.cpp 的 C 回调使用)
auto AllocateFil() -> FIL *
从 FIL 池中分配一个空闲 FIL 对象
static std::array< vfs::BlockDevice *, FF_VOLUMES > block_devices_
每卷块设备注册表(静态,供 diskio.cpp C 回调访问)
auto Unmount() -> Expected< void > override
卸载 FatFS 卷
~FatFsFileSystem() override
auto FreeDir(DIR *dir) -> void
归还 DIR 对象到池中
auto AllocateDir() -> DIR *
从 DIR 池中分配一个空闲 DIR 对象
static auto GetBlockDevice(uint8_t pdrv) -> vfs::BlockDevice *
获取指定驱动器的块设备
auto Sync() -> Expected< void > override
刷新所有脏缓冲区
auto FreeFatInode(FatInode *fi) -> void
释放 inode 池槽位
auto AllocateInode() -> Expected< vfs::Inode * > override
分配新 inode(由 FatFS FILINFO 快照支撑)
auto GetFileOps() -> vfs::FileOps *override
返回本文件系统的 FileOps 实例
auto OpenFil(vfs::Inode *inode, vfs::OpenFlags open_flags) -> Expected< void >
为 inode 打开底层 FatFS FIL 对象
auto Mount(vfs::BlockDevice *device) -> Expected< vfs::Inode * > override
挂载 FatFS 卷
auto GetName() const -> const char *override
返回 "fatfs"
std::expected< T, Error > Expected
std::expected 别名模板
auto Err(etl::format_string< Args... > fmt, Args &&... args) -> void
以 ERROR 级别记录日志
OpenFlags
文件打开标志(兼容 Linux O_* 定义)
std::array< char, kPathBufSize > path
卷内绝对路径(供 FatFS 操作使用)
DIR * dir
DIR 对象(目录迭代状态);未迭代时为 nullptr.
File — 打开的文件实例(每次 open 产生一个)
uint32_t permissions
权限位(简化版)
uint64_t ino
inode 编号(文件系统内唯一)
void * fs_private
文件系统私有数据指针