diff --git a/lfs.c b/lfs.c index 624f43cc..ee868a31 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) { @@ -6318,6 +6316,46 @@ 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..9292d38e 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'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); + +// 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 /// diff --git a/tests/test_files.toml b/tests/test_files.toml index 1ef41d47..4057ebc9 100644 --- a/tests/test_files.toml +++ b/tests/test_files.toml @@ -537,3 +537,61 @@ 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; +'''