summaryrefslogtreecommitdiffstatshomepage
path: root/extmod/vfs_fat.c
diff options
context:
space:
mode:
Diffstat (limited to 'extmod/vfs_fat.c')
-rw-r--r--extmod/vfs_fat.c165
1 files changed, 145 insertions, 20 deletions
diff --git a/extmod/vfs_fat.c b/extmod/vfs_fat.c
index c52adfbe08..a4a81370f9 100644
--- a/extmod/vfs_fat.c
+++ b/extmod/vfs_fat.c
@@ -28,12 +28,14 @@
#include "py/mpconfig.h"
#if MICROPY_VFS_FAT
+#include <string.h>
#include "py/nlr.h"
#include "py/runtime.h"
#include "lib/fatfs/ff.h"
#include "lib/fatfs/diskio.h"
#include "extmod/vfs_fat_file.h"
-#include "fsusermount.h"
+#include "extmod/fsusermount.h"
+#include "timeutils.h"
#define mp_obj_fat_vfs_t fs_user_mount_t
@@ -79,12 +81,11 @@ STATIC mp_obj_t fat_vfs_remove(mp_obj_t vfs_in, mp_obj_t path_in) {
const char *path = mp_obj_str_get_str(path_in);
// TODO check that path is actually a file before trying to unlink it
FRESULT res = f_unlink(path);
- switch (res) {
- case FR_OK:
- return mp_const_none;
- default:
- // TODO: standard errno's
- nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "Error removing file '%s'", path));
+ if (res == FR_OK) {
+ return mp_const_none;
+ } else {
+ nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError,
+ MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res])));
}
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_remove_obj, fat_vfs_remove);
@@ -94,11 +95,11 @@ STATIC mp_obj_t fat_vfs_rename(mp_obj_t vfs_in, mp_obj_t path_in, mp_obj_t path_
const char *old_path = mp_obj_str_get_str(path_in);
const char *new_path = mp_obj_str_get_str(path_out);
FRESULT res = f_rename(old_path, new_path);
- switch (res) {
- case FR_OK:
- return mp_const_none;
- default:
- nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "Error renaming file '%s' to '%s'", old_path, new_path));
+ if (res == FR_OK) {
+ return mp_const_none;
+ } else {
+ nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError,
+ MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res])));
}
}
@@ -108,25 +109,149 @@ STATIC mp_obj_t fat_vfs_mkdir(mp_obj_t vfs_in, mp_obj_t path_o) {
(void)vfs_in;
const char *path = mp_obj_str_get_str(path_o);
FRESULT res = f_mkdir(path);
- switch (res) {
- case FR_OK:
- return mp_const_none;
- case FR_EXIST:
- // TODO should be FileExistsError
- nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "File exists: '%s'", path));
- default:
- nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "Error creating directory '%s'", path));
+ if (res == FR_OK) {
+ return mp_const_none;
+ } else {
+ nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError,
+ MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res])));
}
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_mkdir_obj, fat_vfs_mkdir);
+/// Change current directory.
+STATIC mp_obj_t fat_vfs_chdir(mp_obj_t vfs_in, mp_obj_t path_in) {
+ (void)vfs_in;
+ const char *path;
+ path = mp_obj_str_get_str(path_in);
+
+ FRESULT res = f_chdrive(path);
+
+ if (res == FR_OK) {
+ res = f_chdir(path);
+ }
+
+ if (res != FR_OK) {
+ nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError,
+ MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res])));
+ }
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_chdir_obj, fat_vfs_chdir);
+
+/// Get the current directory.
+STATIC mp_obj_t fat_vfs_getcwd(mp_obj_t vfs_in) {
+ (void)vfs_in;
+ char buf[MICROPY_ALLOC_PATH_MAX + 1];
+ FRESULT res = f_getcwd(buf, sizeof buf);
+
+ if (res != FR_OK) {
+ nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res])));
+ }
+
+ 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) {
+ (void)vfs_in;
+ const char *path = mp_obj_str_get_str(path_in);
+
+ FILINFO fno;
+#if _USE_LFN
+ fno.lfname = NULL;
+ fno.lfsize = 0;
+#endif
+ FRESULT res;
+
+ if (path_equal(path, "/")) {
+ // stat root directory
+ fno.fsize = 0;
+ fno.fdate = 0;
+ 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 = 0;
+ fno.ftime = 0;
+ fno.fattrib = AM_DIR;
+ res = FR_OK;
+ }
+ }
+ if (res == FR_NO_PATH) {
+ // stat normal file
+ res = f_stat(path, &fno);
+ }
+ if (res != FR_OK) {
+ nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError,
+ MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res])));
+ }
+ }
+
+ mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL));
+ mp_int_t mode = 0;
+ if (fno.fattrib & AM_DIR) {
+ mode |= 0x4000; // stat.S_IFDIR
+ } else {
+ mode |= 0x8000; // stat.S_IFREG
+ }
+ mp_int_t seconds = timeutils_seconds_since_2000(
+ 1980 + ((fno.fdate >> 9) & 0x7f),
+ (fno.fdate >> 5) & 0x0f,
+ fno.fdate & 0x1f,
+ (fno.ftime >> 11) & 0x1f,
+ (fno.ftime >> 5) & 0x3f,
+ 2 * (fno.ftime & 0x1f)
+ );
+ t->items[0] = MP_OBJ_NEW_SMALL_INT(mode); // st_mode
+ t->items[1] = MP_OBJ_NEW_SMALL_INT(0); // st_ino
+ t->items[2] = MP_OBJ_NEW_SMALL_INT(0); // st_dev
+ t->items[3] = MP_OBJ_NEW_SMALL_INT(0); // st_nlink
+ t->items[4] = MP_OBJ_NEW_SMALL_INT(0); // st_uid
+ t->items[5] = MP_OBJ_NEW_SMALL_INT(0); // st_gid
+ t->items[6] = MP_OBJ_NEW_SMALL_INT(fno.fsize); // st_size
+ t->items[7] = MP_OBJ_NEW_SMALL_INT(seconds); // st_atime
+ t->items[8] = MP_OBJ_NEW_SMALL_INT(seconds); // st_mtime
+ t->items[9] = MP_OBJ_NEW_SMALL_INT(seconds); // st_ctime
+
+ return MP_OBJ_FROM_PTR(t);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_stat_obj, fat_vfs_stat);
+
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_open), MP_ROM_PTR(&fat_vfs_open_obj) },
{ MP_ROM_QSTR(MP_QSTR_listdir), MP_ROM_PTR(&fat_vfs_listdir_obj) },
{ MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&fat_vfs_mkdir_obj) },
+ { MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&fat_vfs_chdir_obj) },
+ { MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&fat_vfs_getcwd_obj) },
{ MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&fat_vfs_remove_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) },
};
STATIC MP_DEFINE_CONST_DICT(fat_vfs_locals_dict, fat_vfs_locals_dict_table);