spiffs: make OBJ_META_LEN configurable, make mtime support optional
- SPIFFS_OBJ_META_LEN can be set in sdkconfig - mtime support can be enabled in sdkconfig, if META_LENGTH is sufficient - add test for mtime updates
This commit is contained in:
parent
58f046715e
commit
c03b068931
4 changed files with 103 additions and 21 deletions
|
@ -88,6 +88,25 @@ config SPIFFS_USE_MAGIC_LENGTH
|
||||||
configured and formatted for 4 megabytes will not be accepted
|
configured and formatted for 4 megabytes will not be accepted
|
||||||
for mounting with a configuration defining the filesystem as 2 megabytes.
|
for mounting with a configuration defining the filesystem as 2 megabytes.
|
||||||
|
|
||||||
|
config SPIFFS_META_LENGTH
|
||||||
|
int "Size of per-file metadata field"
|
||||||
|
default 4
|
||||||
|
help
|
||||||
|
This option sets the number of extra bytes stored in the file header.
|
||||||
|
These bytes can be used in an application-specific manner.
|
||||||
|
Set this to at least 4 bytes to enable support for saving file
|
||||||
|
modification time.
|
||||||
|
|
||||||
|
config SPIFFS_USE_MTIME
|
||||||
|
bool "Save file modification time"
|
||||||
|
default "y"
|
||||||
|
depends on SPIFFS_META_LENGTH >= 4
|
||||||
|
help
|
||||||
|
If enabled, then the first 4 bytes of per-file metadata will be used
|
||||||
|
to store file modification time (mtime), accessible through
|
||||||
|
stat/fstat functions.
|
||||||
|
Modification time is updated when the file is opened.
|
||||||
|
|
||||||
menu "Debug Configuration"
|
menu "Debug Configuration"
|
||||||
|
|
||||||
config SPIFFS_DBG
|
config SPIFFS_DBG
|
||||||
|
|
|
@ -33,6 +33,10 @@
|
||||||
|
|
||||||
static const char * TAG = "SPIFFS";
|
static const char * TAG = "SPIFFS";
|
||||||
|
|
||||||
|
#ifdef CONFIG_SPIFFS_USE_MTIME
|
||||||
|
_Static_assert(CONFIG_SPIFFS_META_LENGTH >= sizeof(time_t),
|
||||||
|
"SPIFFS_META_LENGTH size should be >= sizeof(time_t)");
|
||||||
|
#endif //CONFIG_SPIFFS_USE_MTIME
|
||||||
/**
|
/**
|
||||||
* @brief SPIFFS definition structure
|
* @brief SPIFFS definition structure
|
||||||
*/
|
*/
|
||||||
|
@ -80,6 +84,8 @@ static long vfs_spiffs_telldir(void* ctx, DIR* pdir);
|
||||||
static void vfs_spiffs_seekdir(void* ctx, DIR* pdir, long offset);
|
static void vfs_spiffs_seekdir(void* ctx, DIR* pdir, long offset);
|
||||||
static int vfs_spiffs_mkdir(void* ctx, const char* name, mode_t mode);
|
static int vfs_spiffs_mkdir(void* ctx, const char* name, mode_t mode);
|
||||||
static int vfs_spiffs_rmdir(void* ctx, const char* name);
|
static int vfs_spiffs_rmdir(void* ctx, const char* name);
|
||||||
|
static void vfs_spiffs_update_mtime(spiffs *fs, spiffs_file f);
|
||||||
|
static time_t vfs_spiffs_get_mtime(const spiffs_stat* s);
|
||||||
|
|
||||||
static esp_spiffs_t * _efs[CONFIG_SPIFFS_MAX_PARTITIONS];
|
static esp_spiffs_t * _efs[CONFIG_SPIFFS_MAX_PARTITIONS];
|
||||||
|
|
||||||
|
@ -507,22 +513,16 @@ static int vfs_spiffs_open(void* ctx, const char * path, int flags, int mode)
|
||||||
{
|
{
|
||||||
assert(path);
|
assert(path);
|
||||||
esp_spiffs_t * efs = (esp_spiffs_t *)ctx;
|
esp_spiffs_t * efs = (esp_spiffs_t *)ctx;
|
||||||
int fd = SPIFFS_open(efs->fs, path, spiffs_mode_conv(flags), mode);
|
int spiffs_flags = spiffs_mode_conv(flags);
|
||||||
|
int fd = SPIFFS_open(efs->fs, path, spiffs_flags, mode);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
|
errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
|
||||||
SPIFFS_clearerr(efs->fs);
|
SPIFFS_clearerr(efs->fs);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#if SPIFFS_OBJ_META_LEN > 0
|
if (!(spiffs_flags & SPIFFS_RDONLY)) {
|
||||||
if (!(spiffs_mode_conv(flags) & SPIFFS_O_RDONLY))
|
vfs_spiffs_update_mtime(efs->fs, fd);
|
||||||
{
|
}
|
||||||
time_t t = time(NULL);
|
|
||||||
struct tm tmr;
|
|
||||||
localtime_r(&t, &tmr);
|
|
||||||
time_t meta = mktime(&tmr);
|
|
||||||
SPIFFS_fupdate_meta(efs->fs, fd, &meta);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -572,7 +572,6 @@ static off_t vfs_spiffs_lseek(void* ctx, int fd, off_t offset, int mode)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vfs_spiffs_fstat(void* ctx, int fd, struct stat * st)
|
static int vfs_spiffs_fstat(void* ctx, int fd, struct stat * st)
|
||||||
|
@ -588,7 +587,7 @@ static int vfs_spiffs_fstat(void* ctx, int fd, struct stat * st)
|
||||||
}
|
}
|
||||||
st->st_size = s.size;
|
st->st_size = s.size;
|
||||||
st->st_mode = S_IRWXU | S_IRWXG | S_IRWXO | S_IFREG;
|
st->st_mode = S_IRWXU | S_IRWXG | S_IRWXO | S_IFREG;
|
||||||
st->st_mtime = 0;
|
st->st_mtime = vfs_spiffs_get_mtime(&s);
|
||||||
st->st_atime = 0;
|
st->st_atime = 0;
|
||||||
st->st_ctime = 0;
|
st->st_ctime = 0;
|
||||||
return res;
|
return res;
|
||||||
|
@ -610,13 +609,7 @@ static int vfs_spiffs_stat(void* ctx, const char * path, struct stat * st)
|
||||||
st->st_size = s.size;
|
st->st_size = s.size;
|
||||||
st->st_mode = S_IRWXU | S_IRWXG | S_IRWXO;
|
st->st_mode = S_IRWXU | S_IRWXG | S_IRWXO;
|
||||||
st->st_mode |= (s.type == SPIFFS_TYPE_DIR)?S_IFDIR:S_IFREG;
|
st->st_mode |= (s.type == SPIFFS_TYPE_DIR)?S_IFDIR:S_IFREG;
|
||||||
#if SPIFFS_OBJ_META_LEN > 0
|
st->st_mtime = vfs_spiffs_get_mtime(&s);
|
||||||
time_t t =0;
|
|
||||||
memcpy(&t, s.meta, sizeof(time_t));
|
|
||||||
st->st_mtime = t;
|
|
||||||
#else
|
|
||||||
st->st_mtime = 0;
|
|
||||||
#endif
|
|
||||||
st->st_atime = 0;
|
st->st_atime = 0;
|
||||||
st->st_ctime = 0;
|
st->st_ctime = 0;
|
||||||
return res;
|
return res;
|
||||||
|
@ -786,3 +779,31 @@ static int vfs_spiffs_link(void* ctx, const char* n1, const char* n2)
|
||||||
errno = ENOTSUP;
|
errno = ENOTSUP;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void vfs_spiffs_update_mtime(spiffs *fs, spiffs_file fd)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_SPIFFS_USE_MTIME
|
||||||
|
time_t t = time(NULL);
|
||||||
|
spiffs_stat s;
|
||||||
|
int ret = SPIFFS_OK;
|
||||||
|
if (CONFIG_SPIFFS_META_LENGTH > sizeof(t)) {
|
||||||
|
ret = SPIFFS_fstat(fs, fd, &s);
|
||||||
|
}
|
||||||
|
if (ret == SPIFFS_OK) {
|
||||||
|
memcpy(s.meta, &t, sizeof(t));
|
||||||
|
ret = SPIFFS_fupdate_meta(fs, fd, s.meta);
|
||||||
|
}
|
||||||
|
if (ret != SPIFFS_OK) {
|
||||||
|
ESP_LOGW(TAG, "Failed to update mtime (%d)", ret);
|
||||||
|
}
|
||||||
|
#endif //CONFIG_SPIFFS_USE_MTIME
|
||||||
|
}
|
||||||
|
|
||||||
|
static time_t vfs_spiffs_get_mtime(const spiffs_stat* s)
|
||||||
|
{
|
||||||
|
time_t t = 0;
|
||||||
|
#ifdef CONFIG_SPIFFS_USE_MTIME
|
||||||
|
memcpy(&t, s->meta, sizeof(t));
|
||||||
|
#endif
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
|
@ -158,7 +158,7 @@ extern void spiffs_api_unlock(struct spiffs_t *fs);
|
||||||
// This is derived from following:
|
// This is derived from following:
|
||||||
// logical_page_size - (SPIFFS_OBJ_NAME_LEN + sizeof(spiffs_page_header) +
|
// logical_page_size - (SPIFFS_OBJ_NAME_LEN + sizeof(spiffs_page_header) +
|
||||||
// spiffs_object_ix_header fields + at least some LUT entries)
|
// spiffs_object_ix_header fields + at least some LUT entries)
|
||||||
#define SPIFFS_OBJ_META_LEN (4)
|
#define SPIFFS_OBJ_META_LEN (CONFIG_SPIFFS_META_LENGTH)
|
||||||
|
|
||||||
// Size of buffer allocated on stack used when copying data.
|
// Size of buffer allocated on stack used when copying data.
|
||||||
// Lower value generates more read/writes. No meaning having it bigger
|
// Lower value generates more read/writes. No meaning having it bigger
|
||||||
|
|
|
@ -505,3 +505,45 @@ TEST_CASE("multiple tasks can use same volume", "[spiffs]")
|
||||||
test_spiffs_concurrent("/spiffs/f");
|
test_spiffs_concurrent("/spiffs/f");
|
||||||
test_teardown();
|
test_teardown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_SPIFFS_USE_MTIME
|
||||||
|
TEST_CASE("mtime is updated when file is opened", "[spiffs]")
|
||||||
|
{
|
||||||
|
/* Open a file, check that mtime is set correctly */
|
||||||
|
const char* filename = "/spiffs/time";
|
||||||
|
test_setup();
|
||||||
|
time_t t_before_create = time(NULL);
|
||||||
|
test_spiffs_create_file_with_text(filename, "\n");
|
||||||
|
time_t t_after_create = time(NULL);
|
||||||
|
|
||||||
|
struct stat st;
|
||||||
|
TEST_ASSERT_EQUAL(0, stat(filename, &st));
|
||||||
|
printf("mtime=%d\n", (int) st.st_mtime);
|
||||||
|
TEST_ASSERT(st.st_mtime >= t_before_create
|
||||||
|
&& st.st_mtime <= t_after_create);
|
||||||
|
|
||||||
|
/* Wait a bit, open again, check that mtime is updated */
|
||||||
|
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
||||||
|
time_t t_before_open = time(NULL);
|
||||||
|
FILE *f = fopen(filename, "a");
|
||||||
|
time_t t_after_open = time(NULL);
|
||||||
|
TEST_ASSERT_EQUAL(0, fstat(fileno(f), &st));
|
||||||
|
printf("mtime=%d\n", (int) st.st_mtime);
|
||||||
|
TEST_ASSERT(st.st_mtime >= t_before_open
|
||||||
|
&& st.st_mtime <= t_after_open);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
/* Wait a bit, open for reading, check that mtime is not updated */
|
||||||
|
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
||||||
|
time_t t_before_open_ro = time(NULL);
|
||||||
|
f = fopen(filename, "r");
|
||||||
|
TEST_ASSERT_EQUAL(0, fstat(fileno(f), &st));
|
||||||
|
printf("mtime=%d\n", (int) st.st_mtime);
|
||||||
|
TEST_ASSERT(t_before_open_ro > t_after_open
|
||||||
|
&& st.st_mtime >= t_before_open
|
||||||
|
&& st.st_mtime <= t_after_open);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
test_teardown();
|
||||||
|
}
|
||||||
|
#endif // CONFIG_SPIFFS_USE_MTIME
|
||||||
|
|
Loading…
Reference in a new issue