#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static int fat1_diskio_read(struct fatfs_ctx* ctx, uint32_t sector, uint8_t* buffer, uint32_t sector_count) { uint64_t fd; struct vfs_volume* volume = ctx->udata; struct device* back_device = volume->back_device; if (sector_count == 0) return 0; size_t sector_size; size_t phys_sector, phys_sector_count; int ret; spin_lock(&back_device->lock, &fd); ret = device_op(back_device, XDRV_GET_SECTOR_SIZE, ctx->proc, ctx->rctx, &fd, §or_size); if (ret < 0) { spin_unlock(&back_device->lock, fd); return 0; } vfs_translate(sector, sector_count, FAT_SECTOR_SIZE, sector_size, &phys_sector, &phys_sector_count); ret = device_op(back_device, XDRV_READ, ctx->proc, ctx->rctx, &fd, &phys_sector, &phys_sector_count, buffer); if (ret < 0) { spin_unlock(&back_device->lock, fd); return 0; } spin_unlock(&back_device->lock, fd); return 1; } static int fat1_diskio_write(struct fatfs_ctx* ctx, uint32_t sector, uint8_t* buffer, uint32_t sector_count) { uint64_t fd; struct vfs_volume* volume = ctx->udata; struct device* back_device = volume->back_device; if (sector_count == 0) return 0; size_t sector_size; size_t phys_sector, phys_sector_count; int ret; spin_lock(&back_device->lock, &fd); ret = device_op(back_device, XDRV_GET_SECTOR_SIZE, ctx->proc, ctx->rctx, &fd, §or_size); if (ret < 0) { spin_unlock(&back_device->lock, fd); return 0; } vfs_translate(sector, sector_count, FAT_SECTOR_SIZE, sector_size, &phys_sector, &phys_sector_count); ret = device_op(back_device, XDRV_WRITE, ctx->proc, ctx->rctx, &fd, &phys_sector, &phys_sector_count, buffer); if (ret < 0) { spin_unlock(&back_device->lock, fd); return 0; } spin_unlock(&back_device->lock, fd); return 1; } DEFINE_VFS_MOUNT(fatfs_mount) { struct fatfs_ctx* fatfs_ctx = malloc(sizeof(*fatfs_ctx)); int r; if (fatfs_ctx == NULL) return -ST_OOM_ERROR; memset(fatfs_ctx, 0, sizeof(*fatfs_ctx)); fatfs_ctx->udata = volume; volume->udata = fatfs_ctx; fl_init(fatfs_ctx); fatfs_ctx->_fs.disk_io.read_media = &fat1_diskio_read; fatfs_ctx->_fs.disk_io.write_media = &fat1_diskio_write; fatfs_ctx->proc = proc; fatfs_ctx->rctx = rctx; if (format) { r = volume->driver_ops.format(volume, proc, rctx); if (r < 0) return -ST_FORMAT_ERROR; } r = fl_attach_media(fatfs_ctx, &fat1_diskio_read, &fat1_diskio_write); if (r < 0) return -ST_MOUNT_ERROR; return ST_OK; } DEFINE_VFS_UNMOUNT(fatfs_unmount) { struct fatfs_ctx* fatfs_ctx = volume->udata; free(fatfs_ctx); return ST_OK; } DEFINE_VFS_FORMAT(fatfs16_format) { uint64_t fd; struct fatfs_ctx* fatfs_ctx = volume->udata; struct device* back_device = volume->back_device; size_t total_size; fatfs_ctx->proc = proc; fatfs_ctx->rctx = rctx; spin_lock(&back_device->lock, &fd); device_op(back_device, XDRV_GET_SIZE, proc, rctx, &fd, &total_size); spin_unlock(&back_device->lock, fd); size_t sectors = div_align_up(total_size, FAT_SECTOR_SIZE); int r = fatfs_format_fat16(fatfs_ctx, &fatfs_ctx->_fs, sectors, "mop3 fat16"); return r < 0 ? -ST_FORMAT_ERROR : ST_OK; } DEFINE_VFS_FORMAT(fatfs32_format) { uint64_t fd; struct fatfs_ctx* fatfs_ctx = volume->udata; struct device* back_device = volume->back_device; size_t total_size; fatfs_ctx->proc = proc; fatfs_ctx->rctx = rctx; spin_lock(&back_device->lock, &fd); device_op(back_device, XDRV_GET_SIZE, proc, rctx, &fd, &total_size); spin_unlock(&back_device->lock, fd); size_t sectors = div_align_up(total_size, FAT_SECTOR_SIZE); int r = fatfs_format_fat32(fatfs_ctx, &fatfs_ctx->_fs, sectors, "mop3 fat32"); return r < 0 ? -ST_FORMAT_ERROR : ST_OK; } DEFINE_VFS_DESCRIBE(fatfs_describe) { struct fatfs_ctx* fatfs_ctx = volume->udata; fatfs_ctx->proc = proc; fatfs_ctx->rctx = rctx; if (fl_is_dir(fatfs_ctx, path)) { FL_DIR dir; if (fl_opendir(fatfs_ctx, path, &dir) == NULL) return -ST_NOT_FOUND; desc->type = FS_DIR; desc->size = 0; fl_dirent dirent; while (fl_readdir(fatfs_ctx, &dir, &dirent) == 0) desc->size++; fl_closedir(fatfs_ctx, &dir); } else { FL_FILE* file = fl_fopen(fatfs_ctx, path, "r"); if (file == NULL) return -ST_NOT_FOUND; desc->type = FS_FILE; desc->size = file->filelength; fl_fclose(fatfs_ctx, file); } return ST_OK; } DEFINE_VFS_READ_FILE(fatfs_read_file) { struct fatfs_ctx* fatfs_ctx = volume->udata; fatfs_ctx->proc = proc; fatfs_ctx->rctx = rctx; if (fl_is_dir(fatfs_ctx, path)) return -ST_NOT_FOUND; FL_FILE* file = fl_fopen(fatfs_ctx, path, "rb"); if (file == NULL) return -ST_NOT_FOUND; fl_fseek(fatfs_ctx, file, off, SEEK_SET); fl_fread(fatfs_ctx, buffer, 1, size, file); fl_fclose(fatfs_ctx, file); return ST_OK; } DEFINE_VFS_WRITE_FILE(fatfs_write_file) { struct fatfs_ctx* fatfs_ctx = volume->udata; fatfs_ctx->proc = proc; fatfs_ctx->rctx = rctx; if (fl_is_dir(fatfs_ctx, path)) return -ST_NOT_FOUND; FL_FILE* file; if ((flags & WF_TRUNCATE) && off == 0) { file = fl_fopen(fatfs_ctx, path, "wb+"); } else { file = fl_fopen(fatfs_ctx, path, "rb+"); } if (file == NULL) return -ST_NOT_FOUND; fl_fseek(fatfs_ctx, file, off, SEEK_SET); fl_fwrite(fatfs_ctx, buffer, 1, size, file); fl_fclose(fatfs_ctx, file); return ST_OK; } DEFINE_VFS_READ_DIR_ENTRY(fatfs_read_dir_entry) { struct fatfs_ctx* fatfs_ctx = volume->udata; FL_DIR dir; fatfs_ctx->proc = proc; fatfs_ctx->rctx = rctx; if (!fl_is_dir(fatfs_ctx, path)) return -ST_NOT_FOUND; if (fl_opendir(fatfs_ctx, path, &dir) == NULL) return -ST_NOT_FOUND; fl_dirent dirent; size_t dirent_num = 0; while (fl_readdir(fatfs_ctx, &dir, &dirent) == 0) { if (dirent_num == entry_num) { strncat(entry->path, path, PATH_MAX); if (strcmp(path, "/") != 0) strncat(entry->path, "/", PATH_MAX); strncat(entry->path, dirent.filename, PATH_MAX); break; } dirent_num++; } fl_closedir(fatfs_ctx, &dir); return ST_OK; } DEFINE_VFS_CREATE_FILE(fatfs_create_file) { struct fatfs_ctx* fatfs_ctx = volume->udata; fatfs_ctx->proc = proc; fatfs_ctx->rctx = rctx; FL_FILE* file = fl_fopen(fatfs_ctx, path, "ab+"); if (file == NULL) return -ST_NOT_FOUND; fl_fclose(fatfs_ctx, file); return ST_OK; } DEFINE_VFS_CREATE_DIR(fatfs_create_dir) { struct fatfs_ctx* fatfs_ctx = volume->udata; fatfs_ctx->proc = proc; fatfs_ctx->rctx = rctx; int r = fl_createdirectory(fatfs_ctx, path); return r == 0 ? ST_OK : -ST_CREATE_DIR_ERROR; } DEFINE_VFS_REMOVE(fatfs_remove) { struct fatfs_ctx* fatfs_ctx = volume->udata; fatfs_ctx->proc = proc; fatfs_ctx->rctx = rctx; int r = fl_remove(fatfs_ctx, path); return r == 0 ? ST_OK : -ST_REMOVE_ERROR; }