SimpleKernel 1.17.0
Loading...
Searching...
No Matches
fatfs.cpp
Go to the documentation of this file.
1
5#include "fatfs.hpp"
6
7#include <ff.h>
8
9#include "kernel_log.hpp"
10#include "kstd_cstring"
11#include "vfs.hpp"
12
13namespace fatfs {
14
15std::array<vfs::BlockDevice*, FF_VOLUMES> FatFsFileSystem::block_devices_{};
16
17namespace {
18
23auto FresultToErrorCode(FRESULT fr) -> ErrorCode {
24 switch (fr) {
25 case FR_OK:
27 case FR_NO_FILE:
28 case FR_NO_PATH:
30 case FR_EXIST:
32 case FR_DENIED:
33 case FR_WRITE_PROTECTED:
35 case FR_NOT_READY:
36 case FR_DISK_ERR:
38 case FR_NOT_ENABLED:
39 case FR_INVALID_DRIVE:
41 case FR_NOT_ENOUGH_CORE:
43 case FR_INVALID_NAME:
44 case FR_INVALID_PARAMETER:
45 case FR_INVALID_OBJECT:
47 case FR_TOO_MANY_OPEN_FILES:
49 case FR_INT_ERR:
50 case FR_MKFS_ABORTED:
51 default:
53 }
54}
55
59auto FresultToExpected(FRESULT fr) -> Expected<void> {
60 if (fr == FR_OK) {
61 return {};
62 }
63 return std::unexpected(Error{FresultToErrorCode(fr)});
64}
65
69auto FilInfoToFileType(const FILINFO& fi) -> vfs::FileType {
70 if ((fi.fattrib & AM_DIR) != 0) {
72 }
74}
75
76} // namespace
77
79 -> void {
80 if (pdrv < FF_VOLUMES) {
81 block_devices_[pdrv] = device;
82 }
83}
84
86 if (pdrv >= FF_VOLUMES) {
87 return nullptr;
88 }
89 return block_devices_[pdrv];
90}
91
93 : volume_id_(volume_id),
94 fatfs_obj_{},
95 inodes_{},
96 fil_pool_{},
97 dir_pool_{},
98 inode_ops_(this),
99 file_ops_(this) {}
100
102 if (mounted_) {
103 (void)Unmount();
104 }
105}
106
107auto FatFsFileSystem::GetName() const -> const char* { return "fatfs"; }
108
110 if (device == nullptr) {
111 klog::Err("FatFsFileSystem::Mount: device is nullptr");
112 return std::unexpected(Error{ErrorCode::kInvalidArgument});
113 }
114 if (volume_id_ >= FF_VOLUMES) {
115 return std::unexpected(Error{ErrorCode::kInvalidArgument});
116 }
117
118 // 注册块设备,使 diskio.cpp 的回调能够访问它
119 SetBlockDevice(volume_id_, device);
120
121 // 构造 FatFS 挂载路径:"0:/" 或 "1:/" 等
122 char path[4] = {static_cast<char>('0' + volume_id_), ':', '/', '\0'};
123
124 FRESULT fr = f_mount(&fatfs_obj_, path, 1);
125 if (fr != FR_OK) {
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)});
130 }
131
132 // 构建根 inode
133 FatInode* fi = AllocateFatInode();
134 if (fi == nullptr) {
135 (void)f_mount(nullptr, path, 0);
136 SetBlockDevice(volume_id_, nullptr);
137 return std::unexpected(Error{ErrorCode::kOutOfMemory});
138 }
139 fi->inode.ino = 0;
141 fi->inode.size = 0;
142 fi->inode.permissions = kRootDirPermissions;
143 fi->inode.link_count = 1;
144 fi->inode.fs = this;
145 fi->inode.ops = &inode_ops_;
146 fi->inode.fs_private = fi;
147 strncpy(fi->path.data(), path, fi->path.size() - 1);
148 fi->path[fi->path.size() - 1] = '\0';
149
150 root_inode_ = &fi->inode;
151 mounted_ = true;
152 return root_inode_;
153}
154
156 if (!mounted_) {
157 return {};
158 }
159 char path[4] = {static_cast<char>('0' + volume_id_), ':', '/', '\0'};
160 FRESULT fr = f_mount(nullptr, path, 0);
161 SetBlockDevice(volume_id_, nullptr);
162 mounted_ = false;
163 root_inode_ = nullptr;
164 for (auto& node : inodes_) {
165 if (node.in_use) {
166 if (node.dir != nullptr) {
167 (void)f_closedir(node.dir);
168 FreeDir(node.dir);
169 node.dir = nullptr;
170 }
171 }
172 node.in_use = false;
173 }
174 return FresultToExpected(fr);
175}
176
178 auto* dev = GetBlockDevice(volume_id_);
179 if (dev != nullptr) {
180 return dev->Flush();
181 }
182 return {};
183}
184
186 FatInode* fi = AllocateFatInode();
187 if (fi == nullptr) {
188 return std::unexpected(Error{ErrorCode::kOutOfMemory});
189 }
190 fi->inode.fs = this;
191 fi->inode.ops = &inode_ops_;
192 fi->inode.fs_private = fi;
193 return &fi->inode;
194}
195
197 if (inode == nullptr) {
198 return std::unexpected(Error{ErrorCode::kInvalidArgument});
199 }
200 auto* fi = static_cast<FatInode*>(inode->fs_private);
201 FreeFatInode(fi);
202 return {};
203}
204
205auto FatFsFileSystem::GetFileOps() -> vfs::FileOps* { return &file_ops_; }
206
208 for (auto& fi : inodes_) {
209 if (!fi.in_use) {
210 fi = FatInode{};
211 fi.in_use = true;
212 return &fi;
213 }
214 }
215 return nullptr;
216}
217
219 if (fi != nullptr) {
220 fi->in_use = false;
221 }
222}
223
225 for (auto& fh : fil_pool_) {
226 if (!fh.in_use) {
227 fh = FatFileHandle{};
228 fh.in_use = true;
229 return &fh.fil;
230 }
231 }
232 return nullptr;
233}
234
235auto FatFsFileSystem::FreeFil(FIL* fil) -> void {
236 for (auto& fh : fil_pool_) {
237 if (&fh.fil == fil) {
238 fh.in_use = false;
239 return;
240 }
241 }
242}
243
245 for (auto& dh : dir_pool_) {
246 if (!dh.in_use) {
247 dh = FatDirHandle{};
248 dh.in_use = true;
249 return &dh.dir;
250 }
251 }
252 return nullptr;
253}
254
255auto FatFsFileSystem::FreeDir(DIR* dir) -> void {
256 for (auto& dh : dir_pool_) {
257 if (&dh.dir == dir) {
258 dh.in_use = false;
259 return;
260 }
261 }
262}
263
265 -> Expected<void> {
266 auto* fi = static_cast<FatInode*>(inode->fs_private);
267 if (fi->fil != nullptr) {
268 // 已打开
269 return {};
270 }
271 FIL* fil = AllocateFil();
272 if (fil == nullptr) {
273 return std::unexpected(Error{ErrorCode::kFsFdTableFull});
274 }
275 BYTE fa_mode = 0;
276 // kOReadOnly == 0,需单独检查
277 if (open_flags == vfs::OpenFlags::kOReadOnly) {
278 fa_mode = FA_READ;
279 }
280 if ((open_flags & vfs::OpenFlags::kOWriteOnly) != 0U) {
281 fa_mode = FA_WRITE;
282 }
283 if ((open_flags & vfs::OpenFlags::kOReadWrite) != 0U) {
284 fa_mode = FA_READ | FA_WRITE;
285 }
286 if ((open_flags & vfs::OpenFlags::kOCreate) != 0U) {
287 fa_mode |= FA_OPEN_ALWAYS;
288 }
289 if ((open_flags & vfs::OpenFlags::kOTruncate) != 0U) {
290 fa_mode |= FA_CREATE_ALWAYS;
291 }
292 FRESULT fr = f_open(fil, fi->path.data(), fa_mode);
293 if (fr != FR_OK) {
294 FreeFil(fil);
295 return std::unexpected(Error{FresultToErrorCode(fr)});
296 }
297 fi->fil = fil;
298 return {};
299}
300
303 auto* dir_fi = static_cast<FatInode*>(dir->fs_private);
304
305 // 拼接完整路径:dir_path + name
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';
311
312 FILINFO fi_info;
313 FRESULT fr = f_stat(full_path.data(), &fi_info);
314 if (fr != FR_OK) {
315 return std::unexpected(Error{FresultToErrorCode(fr)});
316 }
317
318 auto inode_result = fs_->AllocateInode();
319 if (!inode_result) {
320 return std::unexpected(inode_result.error());
321 }
322 vfs::Inode* inode = *inode_result;
323 auto* new_fi = static_cast<FatInode*>(inode->fs_private);
324 inode->ino = 0;
325 inode->type = FilInfoToFileType(fi_info);
326 inode->size = fi_info.fsize;
327 inode->permissions = kDefaultFilePermissions;
328 inode->link_count = 1;
329 strncpy(new_fi->path.data(), full_path.data(), new_fi->path.size() - 1);
330 new_fi->path[new_fi->path.size() - 1] = '\0';
331 return inode;
332}
333
335 vfs::FileType type)
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';
343
344 if (type == vfs::FileType::kDirectory) {
345 FRESULT fr = f_mkdir(full_path.data());
346 if (fr != FR_OK) {
347 return std::unexpected(Error{FresultToErrorCode(fr)});
348 }
349 } else {
350 FIL fil;
351 FRESULT fr = f_open(&fil, full_path.data(), FA_CREATE_NEW | FA_WRITE);
352 if (fr != FR_OK) {
353 return std::unexpected(Error{FresultToErrorCode(fr)});
354 }
355 (void)f_close(&fil);
356 }
357
358 auto inode_result = fs_->AllocateInode();
359 if (!inode_result) {
360 return std::unexpected(inode_result.error());
361 }
362 vfs::Inode* inode = *inode_result;
363 auto* new_fi = static_cast<FatInode*>(inode->fs_private);
364 inode->ino = 0;
365 inode->type = type;
366 inode->size = 0;
367 inode->permissions = kDefaultFilePermissions;
368 inode->link_count = 1;
369 strncpy(new_fi->path.data(), full_path.data(), new_fi->path.size() - 1);
370 new_fi->path[new_fi->path.size() - 1] = '\0';
371 return inode;
372}
373
375 -> Expected<void> {
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()));
383}
384
387 return Create(dir, name, vfs::FileType::kDirectory);
388}
389
391 -> Expected<void> {
392 // f_unlink 同时处理文件和空目录
393 return Unlink(dir, name);
394}
395
397 size_t count) -> Expected<size_t> {
398 auto* fi = static_cast<FatInode*>(file->inode->fs_private);
399 if (fi->fil == nullptr) {
400 return std::unexpected(Error{ErrorCode::kFsInvalidFd});
401 }
402 UINT bytes_read = 0;
403 FRESULT fr = f_read(fi->fil, buf, static_cast<UINT>(count), &bytes_read);
404 if (fr != FR_OK) {
405 klog::Err("FatFsFileOps::Read: f_read failed ({})", static_cast<int>(fr));
406 return std::unexpected(Error{FresultToErrorCode(fr)});
407 }
408 file->offset += bytes_read;
409 return static_cast<size_t>(bytes_read);
410}
411
413 size_t count) -> Expected<size_t> {
414 auto* fi = static_cast<FatInode*>(file->inode->fs_private);
415 if (fi->fil == nullptr) {
416 return std::unexpected(Error{ErrorCode::kFsInvalidFd});
417 }
418 UINT bytes_written = 0;
419 FRESULT fr = f_write(fi->fil, buf, static_cast<UINT>(count), &bytes_written);
420 if (fr != FR_OK) {
421 klog::Err("FatFsFileOps::Write: f_write failed ({})", static_cast<int>(fr));
422 return std::unexpected(Error{FresultToErrorCode(fr)});
423 }
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);
427}
428
430 vfs::SeekWhence whence)
432 auto* fi = static_cast<FatInode*>(file->inode->fs_private);
433 if (fi->fil == nullptr) {
434 return std::unexpected(Error{ErrorCode::kFsInvalidFd});
435 }
436 FSIZE_t new_pos = 0;
437 switch (whence) {
439 new_pos = static_cast<FSIZE_t>(offset);
440 break;
442 new_pos =
443 static_cast<FSIZE_t>(static_cast<int64_t>(f_tell(fi->fil)) + offset);
444 break;
446 new_pos =
447 static_cast<FSIZE_t>(static_cast<int64_t>(f_size(fi->fil)) + offset);
448 break;
449 }
450 FRESULT fr = f_lseek(fi->fil, new_pos);
451 if (fr != FR_OK) {
452 return std::unexpected(Error{FresultToErrorCode(fr)});
453 }
454 file->offset = static_cast<uint64_t>(new_pos);
455 return static_cast<uint64_t>(new_pos);
456}
457
459 auto* fi = static_cast<FatInode*>(file->inode->fs_private);
460
461 // 如果有打开的 DIR,关闭并释放
462 if (fi->dir != nullptr) {
463 (void)f_closedir(fi->dir);
464 fs_->FreeDir(fi->dir);
465 fi->dir = nullptr;
466 }
467
468 // 关闭文件句柄(如果有)
469 if (fi->fil == nullptr) {
470 return {};
471 }
472 FRESULT fr = f_close(fi->fil);
473 fs_->FreeFil(fi->fil);
474 fi->fil = nullptr;
475 return FresultToExpected(fr);
476}
477
479 vfs::DirEntry* dirent, size_t count)
481 auto* fi = static_cast<FatInode*>(file->inode->fs_private);
482
483 // 首次调用时惰性初始化 DIR(保持迭代状态)
484 if (fi->dir == nullptr) {
485 DIR* dir = fs_->AllocateDir();
486 if (dir == nullptr) {
487 return std::unexpected(Error{ErrorCode::kFsFdTableFull});
488 }
489 FRESULT fr = f_opendir(dir, fi->path.data());
490 if (fr != FR_OK) {
491 fs_->FreeDir(dir);
492 return std::unexpected(Error{FresultToErrorCode(fr)});
493 }
494 fi->dir = dir;
495 }
496
497 size_t read_count = 0;
498 for (size_t i = 0; i < count; ++i) {
499 FILINFO fi_info;
500 FRESULT fr = f_readdir(fi->dir, &fi_info);
501 if (fr != FR_OK || fi_info.fname[0] == '\0') {
502 break;
503 }
504 dirent[i].ino = 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';
510 ++read_count;
511 }
512 file->offset += static_cast<uint64_t>(read_count);
513 return read_count;
514}
515
516} // namespace fatfs
auto Close(vfs::File *file) -> Expected< void > override
关闭文件,释放底层 FIL 对象
Definition fatfs.cpp:458
auto Read(vfs::File *file, void *buf, size_t count) -> Expected< size_t > override
从文件读取数据
Definition fatfs.cpp:396
auto Seek(vfs::File *file, int64_t offset, vfs::SeekWhence whence) -> Expected< uint64_t > override
移动文件读写位置
Definition fatfs.cpp:429
auto Write(vfs::File *file, const void *buf, size_t count) -> Expected< size_t > override
向文件写入数据
Definition fatfs.cpp:412
auto ReadDir(vfs::File *file, vfs::DirEntry *dirent, size_t count) -> Expected< size_t > override
读取目录条目
Definition fatfs.cpp:478
auto Lookup(vfs::Inode *dir, const char *name) -> Expected< vfs::Inode * > override
在目录中查找指定名称的 inode
Definition fatfs.cpp:301
auto Rmdir(vfs::Inode *dir, const char *name) -> Expected< void > override
删除目录中的空子目录
Definition fatfs.cpp:390
auto Create(vfs::Inode *dir, const char *name, vfs::FileType type) -> Expected< vfs::Inode * > override
在目录中创建文件或子目录
Definition fatfs.cpp:334
auto Unlink(vfs::Inode *dir, const char *name) -> Expected< void > override
删除目录中的文件条目
Definition fatfs.cpp:374
auto Mkdir(vfs::Inode *dir, const char *name) -> Expected< vfs::Inode * > override
在目录中创建子目录
Definition fatfs.cpp:385
auto FreeInode(vfs::Inode *inode) -> Expected< void > override
释放 inode
Definition fatfs.cpp:196
auto AllocateFatInode() -> FatInode *
从 inode 池中分配一个空闲槽位
Definition fatfs.cpp:207
FatFsFileSystem(uint8_t volume_id)
构造函数,绑定到指定 FatFS 卷号
Definition fatfs.cpp:92
auto FreeFil(FIL *fil) -> void
归还 FIL 对象到池中
Definition fatfs.cpp:235
static auto SetBlockDevice(uint8_t pdrv, vfs::BlockDevice *device) -> void
注册块设备(由 Mount 调用,供 diskio.cpp 的 C 回调使用)
Definition fatfs.cpp:78
auto AllocateFil() -> FIL *
从 FIL 池中分配一个空闲 FIL 对象
Definition fatfs.cpp:224
bool mounted_
当前卷是否已挂载
Definition fatfs.hpp:251
static std::array< vfs::BlockDevice *, FF_VOLUMES > block_devices_
每卷块设备注册表(静态,供 diskio.cpp C 回调访问)
Definition fatfs.hpp:290
auto Unmount() -> Expected< void > override
卸载 FatFS 卷
Definition fatfs.cpp:155
~FatFsFileSystem() override
Definition fatfs.cpp:101
auto FreeDir(DIR *dir) -> void
归还 DIR 对象到池中
Definition fatfs.cpp:255
auto AllocateDir() -> DIR *
从 DIR 池中分配一个空闲 DIR 对象
Definition fatfs.cpp:244
static auto GetBlockDevice(uint8_t pdrv) -> vfs::BlockDevice *
获取指定驱动器的块设备
Definition fatfs.cpp:85
auto Sync() -> Expected< void > override
刷新所有脏缓冲区
Definition fatfs.cpp:177
auto FreeFatInode(FatInode *fi) -> void
释放 inode 池槽位
Definition fatfs.cpp:218
auto AllocateInode() -> Expected< vfs::Inode * > override
分配新 inode(由 FatFS FILINFO 快照支撑)
Definition fatfs.cpp:185
auto GetFileOps() -> vfs::FileOps *override
返回本文件系统的 FileOps 实例
Definition fatfs.cpp:205
auto OpenFil(vfs::Inode *inode, vfs::OpenFlags open_flags) -> Expected< void >
为 inode 打开底层 FatFS FIL 对象
Definition fatfs.cpp:264
auto Mount(vfs::BlockDevice *device) -> Expected< vfs::Inode * > override
挂载 FatFS 卷
Definition fatfs.cpp:109
auto GetName() const -> const char *override
返回 "fatfs"
Definition fatfs.cpp:107
块设备抽象基类
File 操作接口
ErrorCode
内核错误码
Definition expected.hpp:11
@ kFsPermissionDenied
@ kInvalidArgument
std::expected< T, Error > Expected
std::expected 别名模板
Definition expected.hpp:365
#define FF_VOLUMES
Definition ffconf.h:33
auto Err(etl::format_string< Args... > fmt, Args &&... args) -> void
以 ERROR 级别记录日志
OpenFlags
文件打开标志(兼容 Linux O_* 定义)
Definition vfs_types.hpp:39
FileType
文件类型
Definition vfs_types.hpp:22
@ kRegular
普通文件
@ kDirectory
目录
SeekWhence
文件 seek 基准
Definition vfs_types.hpp:94
@ kSet
从文件开头
@ kCur
从当前位置
@ kEnd
从文件末尾
#define strlen
#define strncpy
错误类型,用于 std::expected
Definition expected.hpp:343
FatFS inode 私有数据
Definition fatfs.hpp:254
std::array< char, kPathBufSize > path
卷内绝对路径(供 FatFS 操作使用)
Definition fatfs.hpp:257
bool in_use
该槽位是否在使用
Definition fatfs.hpp:261
DIR * dir
DIR 对象(目录迭代状态);未迭代时为 nullptr.
Definition fatfs.hpp:263
目录项结构(用于 readdir)
File — 打开的文件实例(每次 open 产生一个)
Definition vfs.hpp:65
Inode — 文件元数据(独立于路径名)
Definition vfs.hpp:16
FileSystem * fs
所属文件系统
Definition vfs.hpp:30
uint32_t link_count
硬链接计数
Definition vfs.hpp:26
uint32_t permissions
权限位(简化版)
Definition vfs.hpp:24
uint64_t size
文件大小(字节)
Definition vfs.hpp:22
FileType type
文件类型
Definition vfs.hpp:20
InodeOps * ops
文件操作接口
Definition vfs.hpp:33
uint64_t ino
inode 编号(文件系统内唯一)
Definition vfs.hpp:18
void * fs_private
文件系统私有数据指针
Definition vfs.hpp:28