summaryrefslogtreecommitdiff
path: root/extmod/vfs_fat.c
diff options
context:
space:
mode:
Diffstat (limited to 'extmod/vfs_fat.c')
-rw-r--r--extmod/vfs_fat.c127
1 files changed, 75 insertions, 52 deletions
diff --git a/extmod/vfs_fat.c b/extmod/vfs_fat.c
index 36e5031a8..45f2991da 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_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, 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[] = {
{ 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);