Commit fb3ae178 authored by Damien George's avatar Damien George
Browse files

extmod/vfs_fat: Rework to support new generic VFS sub-system.

The VfsFat object can now be mounted by the generic VFS sub-system.
parent dcb9ea72
...@@ -28,6 +28,10 @@ ...@@ -28,6 +28,10 @@
#include "py/mpconfig.h" #include "py/mpconfig.h"
#if MICROPY_VFS_FAT #if MICROPY_VFS_FAT
#if !MICROPY_VFS
#error "with MICROPY_VFS_FAT enabled, must also enable MICROPY_VFS"
#endif
#if !MICROPY_FATFS_OO #if !MICROPY_FATFS_OO
#error "with MICROPY_VFS_FAT enabled, must also enable MICROPY_FATFS_OO" #error "with MICROPY_VFS_FAT enabled, must also enable MICROPY_FATFS_OO"
#endif #endif
...@@ -44,21 +48,49 @@ ...@@ -44,21 +48,49 @@
#define mp_obj_fat_vfs_t fs_user_mount_t #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) { 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_arg_check_num(n_args, n_kw, 1, 1, false);
mp_obj_fat_vfs_t *vfs = fatfs_mount_mkfs(n_args, args, (mp_map_t*)&mp_const_empty_map, false);
// create new object
fs_user_mount_t *vfs = m_new_obj(fs_user_mount_t);
vfs->base.type = type; 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); return MP_OBJ_FROM_PTR(vfs);
} }
STATIC mp_obj_t fat_vfs_mkfs(mp_obj_t bdev_in) { 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)}; // create new object
fatfs_mount_mkfs(2, args, (mp_map_t*)&mp_const_empty_map, true); 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; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_mkfs_fun_obj, fat_vfs_mkfs); 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_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) { 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]); 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); ...@@ -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) { STATIC mp_obj_t fat_vfs_getcwd(mp_obj_t vfs_in) {
mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_in); mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_in);
char buf[MICROPY_ALLOC_PATH_MAX + 1]; char buf[MICROPY_ALLOC_PATH_MAX + 1];
memcpy(buf, self->str, self->len); FRESULT res = f_getcwd(&self->fatfs, buf, sizeof(buf));
FRESULT res = f_getcwd(&self->fatfs, buf + self->len, sizeof(buf) - self->len);
if (res != FR_OK) { if (res != FR_OK) {
mp_raise_OSError(fresult_to_errno_table[res]); 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); return mp_obj_new_str(buf, strlen(buf), false);
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_getcwd_obj, fat_vfs_getcwd); 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) /// \function stat(path)
/// Get the status of a file or directory. /// 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) { 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) { ...@@ -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); const char *path = mp_obj_str_get_str(path_in);
FILINFO fno; FILINFO fno;
FRESULT res; if (path[0] == 0 || (path[0] == '/' && path[1] == 0)) {
if (path_equal(path, "/")) {
// stat root directory // stat root directory
fno.fsize = 0; fno.fsize = 0;
fno.fdate = 0x2821; // Jan 1, 2000 fno.fdate = 0x2821; // Jan 1, 2000
fno.ftime = 0; fno.ftime = 0;
fno.fattrib = AM_DIR; fno.fattrib = AM_DIR;
} else { } else {
res = FR_NO_PATH; FRESULT res = f_stat(&self->fatfs, path, &fno);
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);
}
if (res != FR_OK) { if (res != FR_OK) {
mp_raise_OSError(fresult_to_errno_table[res]); 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) { ...@@ -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); STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_statvfs_obj, fat_vfs_statvfs);
// Unmount the filesystem STATIC mp_obj_t vfs_fat_mount(mp_obj_t self_in, mp_obj_t readonly, mp_obj_t mkfs) {
STATIC mp_obj_t fat_vfs_umount(mp_obj_t vfs_in) { fs_user_mount_t *self = MP_OBJ_TO_PTR(self_in);
fatfs_umount(((fs_user_mount_t *)vfs_in)->readblocks[1]);
// 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_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; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_umount_obj, fat_vfs_umount); 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[] = { 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) }, { 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[] = { ...@@ -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_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_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_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) }, { 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); STATIC MP_DEFINE_CONST_DICT(fat_vfs_locals_dict, fat_vfs_locals_dict_table);
......
...@@ -32,7 +32,7 @@ extern const mp_obj_type_t mp_fat_vfs_type; ...@@ -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); 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(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_DECLARE_CONST_FUN_OBJ_KW(mp_builtin_open_obj);
mp_obj_t fat_vfs_listdir(const char *path, bool is_str_type); mp_obj_t fat_vfs_listdir(const char *path, bool is_str_type);
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
*/ */
#include "py/mpconfig.h" #include "py/mpconfig.h"
#if MICROPY_FSUSERMOUNT #if MICROPY_VFS || MICROPY_FSUSERMOUNT
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
...@@ -305,4 +305,4 @@ DRESULT disk_ioctl ( ...@@ -305,4 +305,4 @@ DRESULT disk_ioctl (
} }
#endif #endif
#endif // MICROPY_FSUSERMOUNT #endif // MICROPY_VFS || MICROPY_FSUSERMOUNT
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
#include "py/mpconfig.h" #include "py/mpconfig.h"
// *_ADHOC part is for cc3200 port which doesn't use general uPy // *_ADHOC part is for cc3200 port which doesn't use general uPy
// infrastructure and instead duplicates code. TODO: Resolve. // infrastructure and instead duplicates code. TODO: Resolve.
#if MICROPY_FSUSERMOUNT || MICROPY_FSUSERMOUNT_ADHOC #if MICROPY_VFS || MICROPY_FSUSERMOUNT || MICROPY_FSUSERMOUNT_ADHOC
#include <stdio.h> #include <stdio.h>
#include <errno.h> #include <errno.h>
...@@ -224,13 +224,7 @@ STATIC mp_obj_t file_open(fs_user_mount_t *vfs, const mp_obj_type_t *type, mp_ar ...@@ -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); const char *fname = mp_obj_str_get_str(args[0].u_obj);
#if MICROPY_FATFS_OO #if MICROPY_FATFS_OO
if (vfs == NULL) { assert(vfs != NULL);
vfs = ff_get_vfs(&fname);
if (vfs == NULL) {
m_del_obj(pyb_file_obj_t, o);
mp_raise_OSError(MP_ENOENT);
}
}
FRESULT res = f_open(&vfs->fatfs, &o->fp, fname, mode); FRESULT res = f_open(&vfs->fatfs, &o->fp, fname, mode);
#else #else
(void)vfs; (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 ...@@ -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 // 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 // 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_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); return file_open(self, &mp_type_textio, arg_vals);
} }
#endif // MICROPY_FSUSERMOUNT #endif // MICROPY_VFS || MICROPY_FSUSERMOUNT
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment