summaryrefslogtreecommitdiffstatshomepage
path: root/extmod
diff options
context:
space:
mode:
authorDamien George <damien@micropython.org>2020-07-29 01:01:48 +1000
committerDamien George <damien@micropython.org>2020-08-25 17:35:19 +1000
commit2acc087880de39d7e17abc9344b8d2faba3478dd (patch)
treee7a8e21a14bad32ef1b78b351c8d754962e18d1c /extmod
parentee50a6effebf315c38d4a129dc9f65ee722eb5b6 (diff)
downloadmicropython-2acc087880de39d7e17abc9344b8d2faba3478dd.tar.gz
micropython-2acc087880de39d7e17abc9344b8d2faba3478dd.zip
extmod/vfs_lfs: Add mtime support to littlefs files.
This commit adds support for modification time of files on littlefs v2 filesystems, using file attributes. For some background see issue #6114. Features/properties of this implementation: - Only supported on littlefs2 (not littlefs1). - Uses littlefs2's general file attributes to store the timestamp. - The timestamp is 64-bits and stores nanoseconds since 1970/1/1 (if the range to the year 2554 is not enough then additional bits can be added to this timestamp by adding another file attribute). - mtime is enabled by default but can be disabled in the constructor, eg: uos.mount(uos.VfsLfs2(bdev, mtime=False), '/flash') - It's fully backwards compatible, existing littlefs2 filesystems will work without reformatting and timestamps will be added transparently to existing files (once they are opened for writing). - Files without timestamps will open correctly, and stat will just return 0 for their timestamp. - mtime can be disabled or enabled each mount time and timestamps will only be updated if mtime is enabled (otherwise they will be untouched). Signed-off-by: Damien George <damien@micropython.org>
Diffstat (limited to 'extmod')
-rw-r--r--extmod/vfs_lfs.c21
-rw-r--r--extmod/vfs_lfsx.c25
-rw-r--r--extmod/vfs_lfsx_file.c18
3 files changed, 57 insertions, 7 deletions
diff --git a/extmod/vfs_lfs.c b/extmod/vfs_lfs.c
index 90a1996f9c..a53f66f2d6 100644
--- a/extmod/vfs_lfs.c
+++ b/extmod/vfs_lfs.c
@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
- * Copyright (c) 2019 Damien P. George
+ * Copyright (c) 2019-2020 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -25,18 +25,20 @@
*/
#include "py/runtime.h"
+#include "py/mphal.h"
#include "extmod/vfs.h"
#include "extmod/vfs_lfs.h"
#if MICROPY_VFS && (MICROPY_VFS_LFS1 || MICROPY_VFS_LFS2)
-enum { LFS_MAKE_ARG_bdev, LFS_MAKE_ARG_readsize, LFS_MAKE_ARG_progsize, LFS_MAKE_ARG_lookahead };
+enum { LFS_MAKE_ARG_bdev, LFS_MAKE_ARG_readsize, LFS_MAKE_ARG_progsize, LFS_MAKE_ARG_lookahead, LFS_MAKE_ARG_mtime };
static const mp_arg_t lfs_make_allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_readsize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 32} },
{ MP_QSTR_progsize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 32} },
{ MP_QSTR_lookahead, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 32} },
+ { MP_QSTR_mtime, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
};
#if MICROPY_VFS_LFS1
@@ -98,9 +100,13 @@ mp_obj_t mp_vfs_lfs1_file_open(mp_obj_t self_in, mp_obj_t path_in, mp_obj_t mode
#define MP_TYPE_VFS_LFSx mp_type_vfs_lfs2
#define MP_TYPE_VFS_LFSx_(s) mp_type_vfs_lfs2##s
+// Attribute ids for lfs2_attr.type.
+#define LFS_ATTR_MTIME (1) // 64-bit little endian, nanoseconds since 1970/1/1
+
typedef struct _mp_obj_vfs_lfs2_t {
mp_obj_base_t base;
mp_vfs_blockdev_t blockdev;
+ bool enable_mtime;
vstr_t cur_dir;
struct lfs2_config config;
lfs2_t lfs;
@@ -109,14 +115,25 @@ typedef struct _mp_obj_vfs_lfs2_t {
typedef struct _mp_obj_vfs_lfs2_file_t {
mp_obj_base_t base;
mp_obj_vfs_lfs2_t *vfs;
+ uint8_t mtime[8];
lfs2_file_t file;
struct lfs2_file_config cfg;
+ struct lfs2_attr attrs[1];
uint8_t file_buffer[0];
} mp_obj_vfs_lfs2_file_t;
const char *mp_vfs_lfs2_make_path(mp_obj_vfs_lfs2_t *self, mp_obj_t path_in);
mp_obj_t mp_vfs_lfs2_file_open(mp_obj_t self_in, mp_obj_t path_in, mp_obj_t mode_in);
+STATIC void lfs_get_mtime(uint8_t buf[8]) {
+ uint64_t ns = mp_hal_time_ns();
+ // Store "ns" to "buf" in little-endian format (essentially htole64).
+ for (size_t i = 0; i < 8; ++i) {
+ buf[i] = ns;
+ ns >>= 8;
+ }
+}
+
#include "extmod/vfs_lfsx.c"
#include "extmod/vfs_lfsx_file.c"
diff --git a/extmod/vfs_lfsx.c b/extmod/vfs_lfsx.c
index 24816433be..511b741b0d 100644
--- a/extmod/vfs_lfsx.c
+++ b/extmod/vfs_lfsx.c
@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
- * Copyright (c) 2019 Damien P. George
+ * Copyright (c) 2019-2020 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -34,6 +34,7 @@
#include "py/objstr.h"
#include "py/mperrno.h"
#include "extmod/vfs.h"
+#include "lib/timeutils/timeutils.h"
STATIC int MP_VFS_LFSx(dev_ioctl)(const struct LFSx_API (config) * c, int cmd, int arg, bool must_return_int) {
mp_obj_t ret = mp_vfs_blockdev_ioctl(c->context, cmd, arg);
@@ -120,6 +121,9 @@ STATIC mp_obj_t MP_VFS_LFSx(make_new)(const mp_obj_type_t * type, size_t n_args,
self->base.type = type;
vstr_init(&self->cur_dir, 16);
vstr_add_byte(&self->cur_dir, '/');
+ #if LFS_BUILD_VERSION == 2
+ self->enable_mtime = args[LFS_MAKE_ARG_mtime].u_bool;
+ #endif
MP_VFS_LFSx(init_config)(self, args[LFS_MAKE_ARG_bdev].u_obj,
args[LFS_MAKE_ARG_readsize].u_int, args[LFS_MAKE_ARG_progsize].u_int, args[LFS_MAKE_ARG_lookahead].u_int);
int ret = LFSx_API(mount)(&self->lfs, &self->config);
@@ -352,6 +356,19 @@ STATIC mp_obj_t MP_VFS_LFSx(stat)(mp_obj_t self_in, mp_obj_t path_in) {
mp_raise_OSError(-ret);
}
+ mp_uint_t mtime = 0;
+ #if LFS_BUILD_VERSION == 2
+ uint8_t mtime_buf[8];
+ lfs2_ssize_t sz = lfs2_getattr(&self->lfs, path, LFS_ATTR_MTIME, &mtime_buf, sizeof(mtime_buf));
+ if (sz == sizeof(mtime_buf)) {
+ uint64_t ns = 0;
+ for (size_t i = sizeof(mtime_buf); i > 0; --i) {
+ ns = ns << 8 | mtime_buf[i - 1];
+ }
+ mtime = timeutils_seconds_since_2000_from_nanoseconds_since_1970(ns);
+ }
+ #endif
+
mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL));
t->items[0] = MP_OBJ_NEW_SMALL_INT(info.type == LFSx_MACRO(_TYPE_REG) ? MP_S_IFREG : MP_S_IFDIR); // st_mode
t->items[1] = MP_OBJ_NEW_SMALL_INT(0); // st_ino
@@ -360,9 +377,9 @@ STATIC mp_obj_t MP_VFS_LFSx(stat)(mp_obj_t self_in, mp_obj_t path_in) {
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_int_from_uint(info.size); // st_size
- t->items[7] = MP_OBJ_NEW_SMALL_INT(0); // st_atime
- t->items[8] = MP_OBJ_NEW_SMALL_INT(0); // st_mtime
- t->items[9] = MP_OBJ_NEW_SMALL_INT(0); // st_ctime
+ t->items[7] = MP_OBJ_NEW_SMALL_INT(mtime); // st_atime
+ t->items[8] = MP_OBJ_NEW_SMALL_INT(mtime); // st_mtime
+ t->items[9] = MP_OBJ_NEW_SMALL_INT(mtime); // st_ctime
return MP_OBJ_FROM_PTR(t);
}
diff --git a/extmod/vfs_lfsx_file.c b/extmod/vfs_lfsx_file.c
index f74b41837d..bc1a37b90b 100644
--- a/extmod/vfs_lfsx_file.c
+++ b/extmod/vfs_lfsx_file.c
@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
- * Copyright (c) 2019 Damien P. George
+ * Copyright (c) 2019-2020 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -101,6 +101,17 @@ mp_obj_t MP_VFS_LFSx(file_open)(mp_obj_t self_in, mp_obj_t path_in, mp_obj_t mod
#endif
o->cfg.buffer = &o->file_buffer[0];
+ #if LFS_BUILD_VERSION == 2
+ if (self->enable_mtime) {
+ lfs_get_mtime(&o->mtime[0]);
+ o->attrs[0].type = LFS_ATTR_MTIME;
+ o->attrs[0].buffer = &o->mtime[0];
+ o->attrs[0].size = sizeof(o->mtime);
+ o->cfg.attrs = &o->attrs[0];
+ o->cfg.attr_count = MP_ARRAY_SIZE(o->attrs);
+ }
+ #endif
+
const char *path = MP_VFS_LFSx(make_path)(self, path_in);
int ret = LFSx_API(file_opencfg)(&self->lfs, &o->file, path, flags, &o->cfg);
if (ret < 0) {
@@ -131,6 +142,11 @@ STATIC mp_uint_t MP_VFS_LFSx(file_read)(mp_obj_t self_in, void *buf, mp_uint_t s
STATIC mp_uint_t MP_VFS_LFSx(file_write)(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {
MP_OBJ_VFS_LFSx_FILE *self = MP_OBJ_TO_PTR(self_in);
MP_VFS_LFSx(check_open)(self);
+ #if LFS_BUILD_VERSION == 2
+ if (self->vfs->enable_mtime) {
+ lfs_get_mtime(&self->mtime[0]);
+ }
+ #endif
LFSx_API(ssize_t) sz = LFSx_API(file_write)(&self->vfs->lfs, &self->file, buf, size);
if (sz < 0) {
*errcode = -sz;