#include #include #include "fs/fatfs/fat_context.h" #include "fs/fatfs/fat_filelib.h" #include "sysdefs/fs.h" #include "vfs/vfs.h" #include "dlmalloc/malloc.h" #include "std/string.h" #include "spinlock/spinlock.h" #include "util/util.h" #include "errors.h" #include "kprintf.h" // REF: https://github.com/ultraembedded/fat_io_lib/blob/master/examples/sd_card_generic/sd.c int32_t fatfs_cleanup(struct VfsMountPoint *vmp) { fl_shutdown(&vmp->fs.fatfs.instance); return E_OK; } void fatfs_vobj_cleanup(struct VfsObj *vobj) { if (vobj->extra != NULL) { fl_fclose(&vobj->vmp->fs.fatfs.instance, vobj->extra); } dlfree(vobj); } int32_t fatfs_vobj_read(struct VfsObj *vobj, uint8_t *const buffer, size_t n, size_t off) { if (!(vobj->flags & VFS_FLAG_READ)) { return E_INVALIDOPER; } spinlock_acquire(&vobj->spinlock); int ok = fl_fseek(&vobj->vmp->fs.fatfs.instance, vobj->extra, off, SEEK_SET); if (ok < 0) { spinlock_release(&vobj->spinlock); return E_BADIO; } ok = fl_fread(&vobj->vmp->fs.fatfs.instance, buffer, 1, n, vobj->extra); if (ok < 0) { spinlock_release(&vobj->spinlock); return E_BADIO; } spinlock_release(&vobj->spinlock); return E_OK; } int32_t fatfs_vobj_write(struct VfsObj *vobj, const uint8_t *const buffer, size_t n, size_t off) { if (!(vobj->flags & VFS_FLAG_WRITE)) { return E_INVALIDOPER; } spinlock_acquire(&vobj->spinlock); int ok = fl_fseek(&vobj->vmp->fs.fatfs.instance, vobj->extra, off, SEEK_SET); if (ok < 0) { spinlock_release(&vobj->spinlock); return E_BADIO; } ok = fl_fwrite(&vobj->vmp->fs.fatfs.instance, buffer, 1, n, vobj->extra); if (ok < 0) { spinlock_release(&vobj->spinlock); return E_BADIO; } spinlock_release(&vobj->spinlock); return E_OK; } struct VfsObj *fatfs_open(struct VfsMountPoint *vmp, const char *path, uint32_t flags) { VfsObj *vobj = dlmalloc(sizeof(*vobj)); if (vobj == NULL) { return NULL; } memset(vobj, 0, sizeof(*vobj)); spinlock_init(&vobj->spinlock); char *mods = dlmalloc(4); memset(mods, 0, 4); spinlock_acquire(&vmp->spinlock); FatFs *fs = &vmp->fs.fatfs; if ((flags & VFS_FLAG_READ) && !(flags & VFS_FLAG_WRITE) && !(flags & VFS_FLAG_MAKE)) { strcpy(mods, "rb"); } else if (!(flags & VFS_FLAG_READ) && (flags & VFS_FLAG_WRITE) && !(flags & VFS_FLAG_MAKE)) { strcpy(mods, "wb"); } else if ((flags & VFS_FLAG_READ) && (flags & VFS_FLAG_WRITE) && !(flags & VFS_FLAG_MAKE)) { strcpy(mods, "rb+"); } else if (!(flags & VFS_FLAG_READ) && (flags & VFS_FLAG_WRITE) && (flags & VFS_FLAG_MAKE)) { strcpy(mods, "wb"); } else if ((flags & VFS_FLAG_READ) && (flags & VFS_FLAG_WRITE) && (flags & VFS_FLAG_MAKE)) { strcpy(mods, "wb+"); } void *f = fl_fopen(&fs->instance, path, mods); dlfree(mods); if (f == NULL) { dlfree(vobj); spinlock_release(&vmp->spinlock); return NULL; } vobj->flags = flags; vobj->extra = f; vobj->vmp = vmp; vobj->cleanup = &fatfs_vobj_cleanup; vobj->read = &fatfs_vobj_read; vobj->write = &fatfs_vobj_write; spinlock_release(&vmp->spinlock); return vobj; } int32_t fatfs_stat(struct VfsMountPoint *vmp, const char *path, FsStat *statbuf) { spinlock_acquire(&vmp->spinlock); if (fl_is_dir(&vmp->fs.fatfs.instance, path)) { FL_DIR dirstat; if (fl_opendir(&vmp->fs.fatfs.instance, path, &dirstat) == NULL) { spinlock_release(&vmp->spinlock); return E_NOENTRY; } statbuf->type = FSSTAT_DIR; statbuf->size = 0; fl_dirent dirent; while (fl_readdir(&vmp->fs.fatfs.instance, &dirstat, &dirent) == 0) { statbuf->size++; } fl_closedir(&vmp->fs.fatfs.instance, &dirstat); } else { FL_FILE *f = fl_fopen(&vmp->fs.fatfs.instance, path, "r"); statbuf->type = FSSTAT_FILE; statbuf->size = f->filelength; fl_fclose(&vmp->fs.fatfs.instance, f); } spinlock_release(&vmp->spinlock); return E_OK; } int32_t fatfs_fetchdirent(struct VfsMountPoint *vmp, const char *path, FsDirent *direntbuf, size_t idx) { spinlock_acquire(&vmp->spinlock); FL_DIR dirstat; FL_DIR *d = fl_opendir(&vmp->fs.fatfs.instance, path, &dirstat); if (d == NULL) { spinlock_release(&vmp->spinlock); return E_BADIO; } fl_dirent dirent; size_t i = 0; while (fl_readdir(&vmp->fs.fatfs.instance, d, &dirent) == 0) { if (i == idx) { direntbuf->stat.type = dirent.is_dir ? FSSTAT_DIR : FSSTAT_FILE; direntbuf->stat.size = dirent.is_dir ? 0 : dirent.size; strncpy(direntbuf->name, dirent.filename, sizeof(direntbuf->name)); break; } i++; } fl_closedir(&vmp->fs.fatfs.instance, d); spinlock_release(&vmp->spinlock); return E_OK; } int32_t fatfs_mkdir(struct VfsMountPoint *vmp, const char *path) { spinlock_acquire(&vmp->spinlock); int err = fl_createdirectory(&vmp->fs.fatfs.instance, path); spinlock_release(&vmp->spinlock); return err == 0 ? E_OK : E_BADIO; } int32_t fatfs_delete(struct VfsMountPoint *vmp, const char *path) { spinlock_acquire(&vmp->spinlock); int err = fl_remove(&vmp->fs.fatfs.instance, path); spinlock_release(&vmp->spinlock); return err == 0 ? E_OK : E_BADIO; } int portfatfs_diskio_read(struct fat_ctx *ctx, uint32_t sector, uint8_t *buffer, uint32_t sector_count) { VfsMountPoint *vmp = ctx->extra; if (sector_count == 0) { return 0; } uint64_t byteaddr = (uint64_t)sector * FAT_SECTOR_SIZE; ptrdiff_t sector1 = byteaddr / vmp->backingsd->sectorsize; ptrdiff_t sector_off = byteaddr % vmp->backingsd->sectorsize; int32_t ret = vmp->backingsd->read(vmp->backingsd, (uint8_t *const)buffer, sector1, sector_off, sector_count * FAT_SECTOR_SIZE); if (ret != E_OK) { return 0; } return 1; } int portfatfs_diskio_write(struct fat_ctx *ctx, uint32_t sector, uint8_t *buffer, uint32_t sector_count) { VfsMountPoint *vmp = ctx->extra; if (sector_count == 0) { return 0; } uint64_t byteaddr = (uint64_t)sector * FAT_SECTOR_SIZE; ptrdiff_t sector1 = byteaddr / vmp->backingsd->sectorsize; ptrdiff_t sector_off = byteaddr % vmp->backingsd->sectorsize; int32_t ret = vmp->backingsd->write(vmp->backingsd, (const uint8_t *const)buffer, sector1, sector_off, sector_count * FAT_SECTOR_SIZE); if (ret != E_OK) { return 0; } return 1; }