From fb3ae1784e1905709f82aadb7f1c8994682f9759 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 27 Jan 2017 15:13:32 +1100 Subject: [PATCH] extmod/vfs_fat: Rework to support new generic VFS sub-system. The VfsFat object can now be mounted by the generic VFS sub-system. --- extmod/vfs_fat.c | 127 ++++++++++++++++++++++++---------------- extmod/vfs_fat.h | 2 +- extmod/vfs_fat_diskio.c | 4 +- extmod/vfs_fat_file.c | 20 +++---- 4 files changed, 86 insertions(+), 67 deletions(-) diff --git a/extmod/vfs_fat.c b/extmod/vfs_fat.c index 36e5031a83..45f2991da7 100644 --- a/extmod/vfs_fat.c +++ b/extmod/vfs_fat.c @@ -28,6 +28,10 @@ #include "py/mpconfig.h" #if MICROPY_VFS_FAT +#if !MICROPY_VFS +#error "with MICROPY_VFS_FAT enabled, must also enable MICROPY_VFS" +#endif + #if !MICROPY_FATFS_OO #error "with MICROPY_VFS_FAT enabled, must also enable MICROPY_FATFS_OO" #endif @@ -44,21 +48,49 @@ #define mp_obj_fat_vfs_t fs_user_mount_t STATIC mp_obj_t fat_vfs_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { - mp_arg_check_num(n_args, n_kw, 2, 2, false); - mp_obj_fat_vfs_t *vfs = fatfs_mount_mkfs(n_args, args, (mp_map_t*)&mp_const_empty_map, false); + mp_arg_check_num(n_args, n_kw, 1, 1, false); + + // create new object + fs_user_mount_t *vfs = m_new_obj(fs_user_mount_t); vfs->base.type = type; + vfs->flags = FSUSER_FREE_OBJ; + vfs->str = NULL; + vfs->len = 0; + vfs->fatfs.drv = vfs; + + // load block protocol methods + mp_load_method(args[0], MP_QSTR_readblocks, vfs->readblocks); + mp_load_method_maybe(args[0], MP_QSTR_writeblocks, vfs->writeblocks); + mp_load_method_maybe(args[0], MP_QSTR_ioctl, vfs->u.ioctl); + if (vfs->u.ioctl[0] != MP_OBJ_NULL) { + // device supports new block protocol, so indicate it + vfs->flags |= FSUSER_HAVE_IOCTL; + } else { + // no ioctl method, so assume the device uses the old block protocol + mp_load_method_maybe(args[0], MP_QSTR_sync, vfs->u.old.sync); + mp_load_method(args[0], MP_QSTR_count, vfs->u.old.count); + } + return MP_OBJ_FROM_PTR(vfs); } STATIC mp_obj_t fat_vfs_mkfs(mp_obj_t bdev_in) { - mp_obj_t args[] = {bdev_in, MP_OBJ_NEW_QSTR(MP_QSTR_mkfs)}; - fatfs_mount_mkfs(2, args, (mp_map_t*)&mp_const_empty_map, true); + // create new object + fs_user_mount_t *vfs = MP_OBJ_TO_PTR(fat_vfs_make_new(&mp_fat_vfs_type, 1, 0, &bdev_in)); + + // make the filesystem + uint8_t working_buf[_MAX_SS]; + FRESULT res = f_mkfs(&vfs->fatfs, FM_FAT | FM_SFD, 0, working_buf, sizeof(working_buf)); + if (res != FR_OK) { + mp_raise_OSError(fresult_to_errno_table[res]); + } + return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_mkfs_fun_obj, fat_vfs_mkfs); STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(fat_vfs_mkfs_obj, MP_ROM_PTR(&fat_vfs_mkfs_fun_obj)); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(fat_vfs_open_obj, 2, fatfs_builtin_open_self); +STATIC MP_DEFINE_CONST_FUN_OBJ_3(fat_vfs_open_obj, fatfs_builtin_open_self); STATIC mp_obj_t fat_vfs_listdir_func(size_t n_args, const mp_obj_t *args) { mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(args[0]); @@ -163,37 +195,14 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_chdir_obj, fat_vfs_chdir); STATIC mp_obj_t fat_vfs_getcwd(mp_obj_t vfs_in) { mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_in); char buf[MICROPY_ALLOC_PATH_MAX + 1]; - memcpy(buf, self->str, self->len); - FRESULT res = f_getcwd(&self->fatfs, buf + self->len, sizeof(buf) - self->len); + FRESULT res = f_getcwd(&self->fatfs, buf, sizeof(buf)); if (res != FR_OK) { mp_raise_OSError(fresult_to_errno_table[res]); } - // remove trailing / if in root dir, because we prepended the mount point - size_t l = strlen(buf); - if (res == FR_OK && buf[l - 1] == '/') { - buf[l - 1] = 0; - } return mp_obj_new_str(buf, strlen(buf), false); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_getcwd_obj, fat_vfs_getcwd); -// Checks for path equality, ignoring trailing slashes: -// path_equal(/, /) -> true -// second argument must be in canonical form (meaning no trailing slash, unless it's just /) -STATIC bool path_equal(const char *path, const char *path_canonical) { - while (*path_canonical != '\0' && *path == *path_canonical) { - ++path; - ++path_canonical; - } - if (*path_canonical != '\0') { - return false; - } - while (*path == '/') { - ++path; - } - return *path == '\0'; -} - /// \function stat(path) /// Get the status of a file or directory. STATIC mp_obj_t fat_vfs_stat(mp_obj_t vfs_in, mp_obj_t path_in) { @@ -201,31 +210,14 @@ STATIC mp_obj_t fat_vfs_stat(mp_obj_t vfs_in, mp_obj_t path_in) { const char *path = mp_obj_str_get_str(path_in); FILINFO fno; - FRESULT res; - - if (path_equal(path, "/")) { + if (path[0] == 0 || (path[0] == '/' && path[1] == 0)) { // stat root directory fno.fsize = 0; fno.fdate = 0x2821; // Jan 1, 2000 fno.ftime = 0; fno.fattrib = AM_DIR; } else { - res = FR_NO_PATH; - for (size_t i = 0; i < MP_ARRAY_SIZE(MP_STATE_PORT(fs_user_mount)); ++i) { - fs_user_mount_t *vfs = MP_STATE_PORT(fs_user_mount)[i]; - if (vfs != NULL && path_equal(path, vfs->str)) { - // stat mounted device directory - fno.fsize = 0; - fno.fdate = 0x2821; // Jan 1, 2000 - fno.ftime = 0; - fno.fattrib = AM_DIR; - res = FR_OK; - } - } - if (res == FR_NO_PATH) { - // stat normal file - res = f_stat(&self->fatfs, path, &fno); - } + FRESULT res = f_stat(&self->fatfs, path, &fno); if (res != FR_OK) { mp_raise_OSError(fresult_to_errno_table[res]); } @@ -290,12 +282,42 @@ STATIC mp_obj_t fat_vfs_statvfs(mp_obj_t vfs_in, mp_obj_t path_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_statvfs_obj, fat_vfs_statvfs); -// Unmount the filesystem -STATIC mp_obj_t fat_vfs_umount(mp_obj_t vfs_in) { - fatfs_umount(((fs_user_mount_t *)vfs_in)->readblocks[1]); +STATIC mp_obj_t vfs_fat_mount(mp_obj_t self_in, mp_obj_t readonly, mp_obj_t mkfs) { + fs_user_mount_t *self = MP_OBJ_TO_PTR(self_in); + + // Read-only device indicated by writeblocks[0] == MP_OBJ_NULL. + // User can specify read-only device by: + // 1. readonly=True keyword argument + // 2. nonexistent writeblocks method (then writeblocks[0] == MP_OBJ_NULL already) + if (mp_obj_is_true(readonly)) { + self->writeblocks[0] = MP_OBJ_NULL; + } + + // mount the block device + FRESULT res = f_mount(&self->fatfs); + + // check if we need to make the filesystem + if (res == FR_NO_FILESYSTEM && mp_obj_is_true(mkfs)) { + uint8_t working_buf[_MAX_SS]; + res = f_mkfs(&self->fatfs, FM_FAT | FM_SFD, 0, working_buf, sizeof(working_buf)); + } + if (res != FR_OK) { + mp_raise_OSError(fresult_to_errno_table[res]); + } + return mp_const_none; } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_umount_obj, fat_vfs_umount); +STATIC MP_DEFINE_CONST_FUN_OBJ_3(vfs_fat_mount_obj, vfs_fat_mount); + +STATIC mp_obj_t vfs_fat_umount(mp_obj_t self_in) { + fs_user_mount_t *self = MP_OBJ_TO_PTR(self_in); + FRESULT res = f_umount(&self->fatfs); + if (res != FR_OK) { + mp_raise_OSError(fresult_to_errno_table[res]); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_umount_obj, vfs_fat_umount); STATIC const mp_rom_map_elem_t fat_vfs_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_mkfs), MP_ROM_PTR(&fat_vfs_mkfs_obj) }, @@ -309,6 +331,7 @@ STATIC const mp_rom_map_elem_t fat_vfs_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&fat_vfs_rename_obj) }, { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&fat_vfs_stat_obj) }, { MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&fat_vfs_statvfs_obj) }, + { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&vfs_fat_mount_obj) }, { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&fat_vfs_umount_obj) }, }; STATIC MP_DEFINE_CONST_DICT(fat_vfs_locals_dict, fat_vfs_locals_dict_table); diff --git a/extmod/vfs_fat.h b/extmod/vfs_fat.h index 441b35c045..52674eb6e4 100644 --- a/extmod/vfs_fat.h +++ b/extmod/vfs_fat.h @@ -32,7 +32,7 @@ extern const mp_obj_type_t mp_fat_vfs_type; struct _fs_user_mount_t *ff_get_vfs(const char **path); mp_obj_t fatfs_builtin_open(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kwargs); -mp_obj_t fatfs_builtin_open_self(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs); +mp_obj_t fatfs_builtin_open_self(mp_obj_t self_in, mp_obj_t path, mp_obj_t mode); MP_DECLARE_CONST_FUN_OBJ_KW(mp_builtin_open_obj); mp_obj_t fat_vfs_listdir(const char *path, bool is_str_type); diff --git a/extmod/vfs_fat_diskio.c b/extmod/vfs_fat_diskio.c index 9e91b26f7e..3bbd374358 100644 --- a/extmod/vfs_fat_diskio.c +++ b/extmod/vfs_fat_diskio.c @@ -28,7 +28,7 @@ */ #include "py/mpconfig.h" -#if MICROPY_FSUSERMOUNT +#if MICROPY_VFS || MICROPY_FSUSERMOUNT #include #include @@ -305,4 +305,4 @@ DRESULT disk_ioctl ( } #endif -#endif // MICROPY_FSUSERMOUNT +#endif // MICROPY_VFS || MICROPY_FSUSERMOUNT diff --git a/extmod/vfs_fat_file.c b/extmod/vfs_fat_file.c index ea332709e4..f5a1880363 100644 --- a/extmod/vfs_fat_file.c +++ b/extmod/vfs_fat_file.c @@ -27,7 +27,7 @@ #include "py/mpconfig.h" // *_ADHOC part is for cc3200 port which doesn't use general uPy // infrastructure and instead duplicates code. TODO: Resolve. -#if MICROPY_FSUSERMOUNT || MICROPY_FSUSERMOUNT_ADHOC +#if MICROPY_VFS || MICROPY_FSUSERMOUNT || MICROPY_FSUSERMOUNT_ADHOC #include #include @@ -224,13 +224,7 @@ STATIC mp_obj_t file_open(fs_user_mount_t *vfs, const mp_obj_type_t *type, mp_ar const char *fname = mp_obj_str_get_str(args[0].u_obj); #if MICROPY_FATFS_OO - if (vfs == NULL) { - vfs = ff_get_vfs(&fname); - if (vfs == NULL) { - m_del_obj(pyb_file_obj_t, o); - mp_raise_OSError(MP_ENOENT); - } - } + assert(vfs != NULL); FRESULT res = f_open(&vfs->fatfs, &o->fp, fname, mode); #else (void)vfs; @@ -320,12 +314,14 @@ mp_obj_t fatfs_builtin_open(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw } // Factory function for I/O stream classes -mp_obj_t fatfs_builtin_open_self(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { +mp_obj_t fatfs_builtin_open_self(mp_obj_t self_in, mp_obj_t path, mp_obj_t mode) { // TODO: analyze buffering args and instantiate appropriate type - fs_user_mount_t *self = MP_OBJ_TO_PTR(args[0]); + fs_user_mount_t *self = MP_OBJ_TO_PTR(self_in); mp_arg_val_t arg_vals[FILE_OPEN_NUM_ARGS]; - mp_arg_parse_all(n_args - 1, args + 1, kwargs, FILE_OPEN_NUM_ARGS, file_open_args, arg_vals); + arg_vals[0].u_obj = path; + arg_vals[1].u_obj = mode; + arg_vals[2].u_obj = mp_const_none; return file_open(self, &mp_type_textio, arg_vals); } -#endif // MICROPY_FSUSERMOUNT +#endif // MICROPY_VFS || MICROPY_FSUSERMOUNT