Port fat_io_lib, mount atasd0mp1 as sys:
This commit is contained in:
225
kernel/fs/portfatfs/portfatfs.c
Normal file
225
kernel/fs/portfatfs/portfatfs.c
Normal file
@ -0,0 +1,225 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#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;
|
||||
}
|
||||
Reference in New Issue
Block a user