#include #include #include "fs/littlefs/lfs.h" #include "vfs/vfs.h" #include "errors.h" #include "kprintf.h" #include "dlmalloc/malloc.h" #include "hal/hal.h" int32_t littlefs_cleanup(struct VfsMountPoint *vmp) { dlfree((void *)vmp->fs.littlefs.instance.cfg); int32_t err = vmp->backingsd->cleanup(vmp->backingsd); if (err != E_OK) { return err; } err = lfs_unmount(&vmp->fs.littlefs.instance); if (err < 0) { return E_BADIO; } return E_OK; } void littlefs_vobj_cleanup(struct VfsObj *vobj) { if (vobj->extra != NULL) { lfs_file_close(&vobj->vmp->fs.littlefs.instance, (lfs_file_t *)vobj->extra); dlfree(vobj->extra); } dlfree(vobj); } int32_t littlefs_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 = lfs_file_seek(&vobj->vmp->fs.littlefs.instance, (lfs_file_t *)vobj->extra, off, LFS_SEEK_SET); if (ok < 0) { spinlock_release(&vobj->spinlock); return E_BADIO; } ok = lfs_file_read(&vobj->vmp->fs.littlefs.instance, (lfs_file_t *)vobj->extra, buffer, n); if (ok < 0) { spinlock_release(&vobj->spinlock); return E_BADIO; } spinlock_release(&vobj->spinlock); return E_OK; } int32_t littlefs_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 = lfs_file_seek(&vobj->vmp->fs.littlefs.instance, (lfs_file_t *)vobj->extra, off, LFS_SEEK_SET); if (ok < 0) { spinlock_release(&vobj->spinlock); return E_BADIO; } ok = lfs_file_write(&vobj->vmp->fs.littlefs.instance, (lfs_file_t *)vobj->extra, buffer, n); if (ok < 0) { spinlock_release(&vobj->spinlock); return E_BADIO; } spinlock_release(&vobj->spinlock); return E_OK; } int32_t littlefs_stat(struct VfsMountPoint *vmp, const char *path, IoctlStat *statbuf) { struct lfs_info info; spinlock_acquire(&vmp->spinlock); int ok = lfs_stat(&vmp->fs.littlefs.instance, path, &info); if (ok < 0) { spinlock_release(&vmp->spinlock); return E_BADIO; } if (info.type == LFS_TYPE_REG) { statbuf->type = IOCTLSTAT_FILE; statbuf->size = info.size; } else if (info.type == LFS_TYPE_DIR) { statbuf->type = IOCTLSTAT_DIR; statbuf->size = 0; // TODO: find a better way than this... !!! lfs_dir_t dir; ok = lfs_dir_open(&vmp->fs.littlefs.instance, &dir, path); if (ok < 0) { spinlock_release(&vmp->spinlock); return E_BADIO; } struct lfs_info info2; while (lfs_dir_read(&vmp->fs.littlefs.instance, &dir, &info2) > 0) { statbuf->size++; } lfs_dir_close(&vmp->fs.littlefs.instance, &dir); } spinlock_release(&vmp->spinlock); return E_OK; } struct VfsObj *littlefs_open(struct VfsMountPoint *vmp, const char *path, uint32_t flags) { VfsObj *vobj = dlmalloc(sizeof(*vobj)); if (vobj == NULL) { return NULL; } hal_memset(vobj, 0, sizeof(*vobj)); spinlock_init(&vobj->spinlock); int lfs_flags = 0; lfs_file_t *file = dlmalloc(sizeof(*file)); if (file == NULL) { dlfree(vobj); return NULL; } spinlock_acquire(&vmp->spinlock); LittleFs *fs = &vmp->fs.littlefs; if (flags & VFS_FLAG_MAKE) { lfs_flags |= LFS_O_CREAT; } if (flags == VFS_FLAG_READ) { lfs_flags |= LFS_O_RDONLY; } else if (flags == VFS_FLAG_WRITE) { lfs_flags |= LFS_O_WRONLY; } else if ((flags & VFS_FLAG_READ) && (flags & VFS_FLAG_WRITE)) { lfs_flags |= LFS_O_RDWR; } int ok = lfs_file_open(&fs->instance, file, path, lfs_flags); if (ok < 0) { dlfree(vobj); dlfree(file); spinlock_release(&vmp->spinlock); return NULL; } vobj->flags = flags; vobj->extra = file; vobj->extrasize = sizeof(*file); vobj->vmp = vmp; vobj->cleanup = &littlefs_vobj_cleanup; vobj->read = &littlefs_vobj_read; vobj->write = &littlefs_vobj_write; hal_strcpy(vobj->path, path); spinlock_release(&vmp->spinlock); return vobj; } int32_t littlefs_fetchdirent(struct VfsMountPoint *vmp, const char *path, IoctlDirent *direntbuf, size_t idx) { size_t i = 0; struct lfs_info statinfo; int ok; spinlock_acquire(&vmp->spinlock); ok = lfs_stat(&vmp->fs.littlefs.instance, path, &statinfo); if (ok < 0) { spinlock_release(&vmp->spinlock); return E_BADIO; } if (statinfo.type != LFS_TYPE_DIR) { spinlock_release(&vmp->spinlock); return E_BADIO; } lfs_dir_t dir; ok = lfs_dir_open(&vmp->fs.littlefs.instance, &dir, path); if (ok < 0) { spinlock_release(&vmp->spinlock); return E_BADIO; } struct lfs_info entinfo; while (lfs_dir_read(&vmp->fs.littlefs.instance, &dir, &entinfo) > 0) { if (i == idx) { if (entinfo.type == LFS_TYPE_REG) { direntbuf->stat.type = IOCTLSTAT_FILE; direntbuf->stat.size = entinfo.size; } else if (entinfo.type == LFS_TYPE_DIR) { direntbuf->stat.type = IOCTLSTAT_DIR; } hal_memcpy(direntbuf->name, entinfo.name, sizeof(direntbuf->name)); break; } i++; } lfs_dir_close(&vmp->fs.littlefs.instance, &dir); spinlock_release(&vmp->spinlock); return E_OK; } int portlfs_read(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, void *buffer, lfs_size_t size) { VfsMountPoint *vmp = c->context; vmp->backingsd->read(vmp->backingsd, buffer, size, block * LITTLEFS_BLOCK_SIZE + off); return 0; } int portlfs_prog(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, const void *buffer, lfs_size_t size) { VfsMountPoint *vmp = c->context; vmp->backingsd->write(vmp->backingsd, buffer, size, block * LITTLEFS_BLOCK_SIZE + off); return 0; } int portlfs_erase(const struct lfs_config *c, lfs_block_t block) { (void)c; (void)block; return 0; } int portlfs_sync(const struct lfs_config *c) { (void)c; return 0; }