From b57e9babccbda3c4c4e2683ba8c871e01d62c4ef Mon Sep 17 00:00:00 2001 From: Jacob Schloss Date: Sun, 20 Jul 2025 03:21:16 -0700 Subject: [PATCH 1/4] Add lfs_file_movehandle and lfs_file_ishandleopen. Add lfs_file_movehandle to allow moving file handles in the rare case it is needed. Add lfs_file_ishandleopen to allow checking if a file handle is open. --- lfs.c | 41 +++++++++++++++++++++++++++++++++++++++++ lfs.h | 14 ++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/lfs.c b/lfs.c index 624f43cc..a4f980ca 100644 --- a/lfs.c +++ b/lfs.c @@ -6318,6 +6318,47 @@ lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file) { return res; } +int lfs_file_movehandle(lfs_t *lfs, lfs_file_t *old_file, lfs_file_t *new_file) +{ + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_file_movehandle(%p, %p, %p)", (void*)lfs, (void*)old_file, (void*)new_file); + LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)old_file)); + LFS_ASSERT(!lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)new_file)); + + *new_file = *old_file; + lfs_mlist_remove(lfs, (struct lfs_mlist*)old_file); + lfs_mlist_append(lfs, (struct lfs_mlist*)new_file); + + err = LFS_ERR_OK; + + LFS_TRACE("lfs_file_movehandle -> %d", err); + LFS_UNLOCK(lfs->cfg); + return err; +} + +int lfs_file_ishandleopen(lfs_t *lfs, lfs_file_t *file) +{ + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_file_ishandleopen(%p, %p)", (void*)lfs, (void*)file); + + if(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)) { + err = LFS_ERR_OK; + } + else { + err = LFS_ERR_BADF; + } + + LFS_TRACE("lfs_file_ishandleopen -> %d", err); + LFS_UNLOCK(lfs->cfg); + return err; +} + #ifndef LFS_READONLY int lfs_mkdir(lfs_t *lfs, const char *path) { int err = LFS_LOCK(lfs->cfg); diff --git a/lfs.h b/lfs.h index 215309c5..73d6c623 100644 --- a/lfs.h +++ b/lfs.h @@ -656,6 +656,20 @@ int lfs_file_rewind(lfs_t *lfs, lfs_file_t *file); // Returns the size of the file, or a negative error code on failure. lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file); +// Move a file handle +// +// Littlefs file handles are somewhat expensive to move. +// Try to avoid needing to move them. +// This allows moving a file handle from old_file to new_file when needed for abstraction. +// After this call, old_file is invalid. +// +// Returns a negative error code on failure. +int lfs_file_movehandle(lfs_t *lfs, lfs_file_t *old_file, lfs_file_t *new_file); + +// Check if a given file handle is open +// +// Returns LFS_ERR_OK if the file handle is open, else LFS_ERR_BADF +int lfs_file_ishandleopen(lfs_t *lfs, lfs_file_t *file); /// Directory operations /// From f9bdc40023b1106e8e793998d10fc4761b69341d Mon Sep 17 00:00:00 2001 From: Jacob Schloss Date: Sun, 20 Jul 2025 11:46:48 -0700 Subject: [PATCH 2/4] Always build in lfs_mlist_isopen since lfs_file_ishandleopen uses it --- lfs.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/lfs.c b/lfs.c index a4f980ca..dcca072a 100644 --- a/lfs.c +++ b/lfs.c @@ -503,7 +503,6 @@ static inline void lfs_superblock_tole32(lfs_superblock_t *superblock) { } #endif -#ifndef LFS_NO_ASSERT static bool lfs_mlist_isopen(struct lfs_mlist *head, struct lfs_mlist *node) { for (struct lfs_mlist **p = &head; *p; p = &(*p)->next) { @@ -514,7 +513,6 @@ static bool lfs_mlist_isopen(struct lfs_mlist *head, return false; } -#endif static void lfs_mlist_remove(lfs_t *lfs, struct lfs_mlist *mlist) { for (struct lfs_mlist **p = &lfs->mlist; *p; p = &(*p)->next) { From 4eed71302c25fea0ed1e3fddd1fdf69a4a0bd9b3 Mon Sep 17 00:00:00 2001 From: Jacob Schloss Date: Sun, 20 Jul 2025 11:46:57 -0700 Subject: [PATCH 3/4] Add unit tests for file_movehandle and file_ishandleopen --- tests/test_files.toml | 60 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/tests/test_files.toml b/tests/test_files.toml index 1ef41d47..5b662ffc 100644 --- a/tests/test_files.toml +++ b/tests/test_files.toml @@ -537,3 +537,63 @@ code = ''' } lfs_unmount(&lfs) => 0; ''' + +[cases.test_files_ishandleopen] +code = ''' + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_file_t file; + + lfs_file_ishandleopen(&lfs, &file) => LFS_ERR_BADF; + + lfs_file_open(&lfs, &file, "hello", LFS_O_CREAT | LFS_O_WRONLY) => 0; + + lfs_file_ishandleopen(&lfs, &file) => 0; + + lfs_file_close(&lfs, &file) => 0; + + lfs_file_ishandleopen(&lfs, &file) => LFS_ERR_BADF; + + lfs_unmount(&lfs) => 0; +''' + +[cases.test_files_movehandle] +defines.idx = [0, 1, 2] +code = ''' + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_file_t file[3]; + lfs_file_open(&lfs, &file[0], "a", LFS_O_CREAT | LFS_O_WRONLY) => 0; + lfs_file_open(&lfs, &file[1], "b", LFS_O_CREAT | LFS_O_WRONLY) => 0; + lfs_file_open(&lfs, &file[2], "c", LFS_O_CREAT | LFS_O_WRONLY) => 0; + + lfs_file_t file_new; + lfs_file_movehandle(&lfs, &file[idx], &file_new) => 0; + + for(int i = 0; i < 3; i++) + { + if(i == idx) { + continue; + } + + lfs_file_ishandleopen(&lfs, &file[i]) => 0; + } + lfs_file_ishandleopen(&lfs, &file_new) => 0; + + for(int i = 0; i < 3; i++) + { + if(i == idx) { + continue; + } + + lfs_file_close(&lfs, &file[i]) => 0; + lfs_file_ishandleopen(&lfs, &file[i]) => LFS_ERR_BADF; + } + + lfs_file_close(&lfs, &file_new) => 0; + lfs_file_ishandleopen(&lfs, &file_new) => LFS_ERR_BADF; + + lfs_unmount(&lfs) => 0; +''' From 056ba4288dc0f0d55cd3ba092862832340c205ce Mon Sep 17 00:00:00 2001 From: Jacob Schloss Date: Tue, 12 Aug 2025 19:48:36 -0700 Subject: [PATCH 4/4] Edit for style Edit for style --- lfs.c | 15 +++++++-------- lfs.h | 8 ++++---- tests/test_files.toml | 10 ++++------ 3 files changed, 15 insertions(+), 18 deletions(-) diff --git a/lfs.c b/lfs.c index dcca072a..ee868a31 100644 --- a/lfs.c +++ b/lfs.c @@ -6316,13 +6316,14 @@ lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file) { return res; } -int lfs_file_movehandle(lfs_t *lfs, lfs_file_t *old_file, lfs_file_t *new_file) -{ +int lfs_file_movehandle(lfs_t *lfs, lfs_file_t *old_file, + lfs_file_t *new_file) { int err = LFS_LOCK(lfs->cfg); if (err) { return err; } - LFS_TRACE("lfs_file_movehandle(%p, %p, %p)", (void*)lfs, (void*)old_file, (void*)new_file); + LFS_TRACE("lfs_file_movehandle(%p, %p, %p)", + (void*)lfs, (void*)old_file, (void*)new_file); LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)old_file)); LFS_ASSERT(!lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)new_file)); @@ -6337,18 +6338,16 @@ int lfs_file_movehandle(lfs_t *lfs, lfs_file_t *old_file, lfs_file_t *new_file) return err; } -int lfs_file_ishandleopen(lfs_t *lfs, lfs_file_t *file) -{ +int lfs_file_ishandleopen(lfs_t *lfs, lfs_file_t *file) { int err = LFS_LOCK(lfs->cfg); if (err) { return err; } LFS_TRACE("lfs_file_ishandleopen(%p, %p)", (void*)lfs, (void*)file); - if(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)) { + if (lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)) { err = LFS_ERR_OK; - } - else { + } else { err = LFS_ERR_BADF; } diff --git a/lfs.h b/lfs.h index 73d6c623..9292d38e 100644 --- a/lfs.h +++ b/lfs.h @@ -658,10 +658,10 @@ lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file); // Move a file handle // -// Littlefs file handles are somewhat expensive to move. -// Try to avoid needing to move them. -// This allows moving a file handle from old_file to new_file when needed for abstraction. -// After this call, old_file is invalid. +// littlefs's file handles are somewhat expensive to move. Try to avoid +// needing to move them. This allows moving a file handle from old_file +// to new_file when needed for abstraction. After this call, old_file is +// invalid. // // Returns a negative error code on failure. int lfs_file_movehandle(lfs_t *lfs, lfs_file_t *old_file, lfs_file_t *new_file); diff --git a/tests/test_files.toml b/tests/test_files.toml index 5b662ffc..4057ebc9 100644 --- a/tests/test_files.toml +++ b/tests/test_files.toml @@ -572,9 +572,8 @@ code = ''' lfs_file_t file_new; lfs_file_movehandle(&lfs, &file[idx], &file_new) => 0; - for(int i = 0; i < 3; i++) - { - if(i == idx) { + for (int i = 0; i < 3; i++) { + if (i == idx) { continue; } @@ -582,9 +581,8 @@ code = ''' } lfs_file_ishandleopen(&lfs, &file_new) => 0; - for(int i = 0; i < 3; i++) - { - if(i == idx) { + for (int i = 0; i < 3; i++) { + if (i == idx) { continue; }