Skip to content

Instantly share code, notes, and snippets.

@rojer
Created February 27, 2024 16:35
Show Gist options
  • Save rojer/cf1a99497c1f1e807fe0e44c059daa17 to your computer and use it in GitHub Desktop.
Save rojer/cf1a99497c1f1e807fe0e44c059daa17 to your computer and use it in GitHub Desktop.
diff --git a/littlefs/lfs.c b/littlefs/lfs.c
index a152687..105915b 100644
--- a/littlefs/lfs.c
+++ b/littlefs/lfs.c
@@ -4323,6 +4323,70 @@ cleanup:
}
#endif
+static int lfs_rawprobe(lfs_t *lfs, const struct lfs_config *cfg, lfs_superblock_t *superblock) {
+ int err = lfs_init(lfs, cfg);
+ if (err) {
+ return err;
+ }
+
+ // scan directory blocks for superblock
+ lfs_mdir_t dir = {.tail = {0, 1}};
+ lfs_block_t tortoise[2] = {LFS_BLOCK_NULL, LFS_BLOCK_NULL};
+ lfs_size_t tortoise_i = 1;
+ lfs_size_t tortoise_period = 1;
+ while (!lfs_pair_isnull(dir.tail)) {
+ // detect cycles with Brent's algorithm
+ if (lfs_pair_issync(dir.tail, tortoise)) {
+ err = LFS_ERR_CORRUPT;
+ goto cleanup;
+ }
+ if (tortoise_i == tortoise_period) {
+ tortoise[0] = dir.tail[0];
+ tortoise[1] = dir.tail[1];
+ tortoise_i = 0;
+ tortoise_period *= 2;
+ }
+ tortoise_i += 1;
+
+ // fetch next block in tail list
+ lfs_stag_t tag = lfs_dir_fetchmatch(lfs, &dir, dir.tail,
+ LFS_MKTAG(0x7ff, 0x3ff, 0),
+ LFS_MKTAG(LFS_TYPE_SUPERBLOCK, 0, 8),
+ NULL,
+ lfs_dir_find_match, &(struct lfs_dir_find_match){
+ lfs, "littlefs", 8});
+ if (tag < 0) {
+ err = tag;
+ goto cleanup;
+ }
+
+ // has superblock?
+ if (tag && !lfs_tag_isdelete(tag)) {
+ // update root
+ lfs->root[0] = dir.pair[0];
+ lfs->root[1] = dir.pair[1];
+
+ // grab superblock
+ tag = lfs_dir_get(lfs, &dir, LFS_MKTAG(0x7ff, 0x3ff, 0),
+ LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(*superblock)),
+ superblock);
+ if (tag < 0) {
+ err = tag;
+ goto cleanup;
+ }
+ lfs_superblock_fromle32(superblock);
+ err = LFS_ERR_OK;
+ goto cleanup;
+ }
+ }
+
+ err = LFS_ERR_NOENT;
+
+cleanup:
+ lfs_rawunmount(lfs);
+ return err;
+}
+
static int lfs_rawmount(lfs_t *lfs, const struct lfs_config *cfg) {
int err = lfs_init(lfs, cfg);
if (err) {
@@ -5782,6 +5846,35 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) {
}
#endif
+int lfs_probe(lfs_t *lfs, const struct lfs_config *cfg, lfs_superblock_t *superblock) {
+ int err = LFS_LOCK(cfg);
+ if (err) {
+ return err;
+ }
+ LFS_TRACE("lfs_probe(%p, %p {.context=%p, "
+ ".read=%p, .prog=%p, .erase=%p, .sync=%p, "
+ ".read_size=%"PRIu32", .prog_size=%"PRIu32", "
+ ".block_size=%"PRIu32", .block_count=%"PRIu32", "
+ ".block_cycles=%"PRIu32", .cache_size=%"PRIu32", "
+ ".lookahead_size=%"PRIu32", .read_buffer=%p, "
+ ".prog_buffer=%p, .lookahead_buffer=%p, "
+ ".name_max=%"PRIu32", .file_max=%"PRIu32", "
+ ".attr_max=%"PRIu32"})",
+ (void*)lfs, (void*)cfg, cfg->context,
+ (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog,
+ (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync,
+ cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count,
+ cfg->block_cycles, cfg->cache_size, cfg->lookahead_size,
+ cfg->read_buffer, cfg->prog_buffer, cfg->lookahead_buffer,
+ cfg->name_max, cfg->file_max, cfg->attr_max);
+
+ err = lfs_rawprobe(lfs, cfg, superblock);
+
+ LFS_TRACE("lfs_probe -> %d", err);
+ LFS_UNLOCK(cfg);
+ return err;
+}
+
int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
int err = LFS_LOCK(cfg);
if (err) {
diff --git a/littlefs/lfs.h b/littlefs/lfs.h
index 9eeab23..e6253ee 100644
--- a/littlefs/lfs.h
+++ b/littlefs/lfs.h
@@ -473,6 +473,9 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *config);
// Returns a negative error code on failure.
int lfs_mount(lfs_t *lfs, const struct lfs_config *config);
+// Probes for a valid LFS and returns superblock contents if successful.
+int lfs_probe(lfs_t *lfs, const struct lfs_config *config, lfs_superblock_t *superblock);
+
// Unmounts a littlefs
//
// Does nothing besides releasing any allocated resources.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment