Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/littlefs-project/littlefs.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Haster <chaster@utexas.edu>2018-10-21 05:02:25 +0300
committerChristopher Haster <chaster@utexas.edu>2018-10-21 05:02:25 +0300
commitc8a39c4b23baa2b1dc5f41c8d0711e205035f4f4 (patch)
treea77722fb5c1b9175fb59e862abdd4c65dfb15a09
parent795dd8c7ab930892536c6c2ee7c29b8bfac477db (diff)
parentec4d8b68add6a7de021dc09ef08123ab323cbc38 (diff)
Merge remote-tracking branch 'origin/master' into v2-rebase-part2
-rw-r--r--.travis.yml56
-rw-r--r--Makefile3
-rw-r--r--README.md15
-rw-r--r--emubd/lfs_emubd.c4
-rw-r--r--lfs.c407
-rw-r--r--lfs.h19
-rwxr-xr-xtests/test_alloc.sh6
-rwxr-xr-xtests/test_dirs.sh63
-rwxr-xr-xtests/test_seek.sh2
-rwxr-xr-xtests/test_truncate.sh12
10 files changed, 358 insertions, 229 deletions
diff --git a/.travis.yml b/.travis.yml
index 255e84b..ccbcaa8 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -139,12 +139,15 @@ jobs:
- LFS_VERSION=$(grep -ox '#define LFS_VERSION .*' lfs.h | cut -d ' ' -f3)
- LFS_VERSION_MAJOR=$((0xffff & ($LFS_VERSION >> 16)))
- LFS_VERSION_MINOR=$((0xffff & ($LFS_VERSION >> 0)))
- # Grab latests patch from repo tags, default to 0
- - LFS_VERSION_PATCH=$(curl -f -u "$GEKY_BOT_RELEASES"
- https://api.github.com/repos/$TRAVIS_REPO_SLUG/git/refs
- | jq 'map(.ref | match(
- "refs/tags/v'"$LFS_VERSION_MAJOR"'\\.'"$LFS_VERSION_MINOR"'\\.(.*)$")
- .captures[].string | tonumber + 1) | max // 0')
+ # Grab latests patch from repo tags, default to 0, needs finagling to get past github's pagination api
+ - PREV_URL=https://api.github.com/repos/$TRAVIS_REPO_SLUG/git/refs/tags/v$LFS_VERSION_MAJOR.$LFS_VERSION_MINOR.
+ - PREV_URL=$(curl -u "$GEKY_BOT_RELEASES" "$PREV_URL" -I
+ | sed -n '/^Link/{s/.*<\(.*\)>; rel="last"/\1/;p;q0};$q1'
+ || echo $PREV_URL)
+ - LFS_VERSION_PATCH=$(curl -u "$GEKY_BOT_RELEASES" "$PREV_URL"
+ | jq 'map(.ref | match("\\bv.*\\..*\\.(.*)$";"g")
+ .captures[].string | tonumber) | max + 1'
+ || echo 0)
# We have our new version
- LFS_VERSION="v$LFS_VERSION_MAJOR.$LFS_VERSION_MINOR.$LFS_VERSION_PATCH"
- echo "VERSION $LFS_VERSION"
@@ -155,24 +158,35 @@ jobs:
| jq -re '.sha')
if [ "$TRAVIS_COMMIT" == "$CURRENT_COMMIT" ]
then
- # Build release notes
- PREV=$(git tag --sort=-v:refname -l "v*" | head -1)
- if [ ! -z "$PREV" ]
- then
- echo "PREV $PREV"
- CHANGES=$'### Changes\n\n'$( \
- git log --oneline $PREV.. --grep='^Merge' --invert-grep)
- printf "CHANGES\n%s\n\n" "$CHANGES"
- fi
- # Create the release
+ # Create a simple tag
curl -f -u "$GEKY_BOT_RELEASES" -X POST \
- https://api.github.com/repos/$TRAVIS_REPO_SLUG/releases \
+ https://api.github.com/repos/$TRAVIS_REPO_SLUG/git/refs \
-d "{
- \"tag_name\": \"$LFS_VERSION\",
- \"target_commitish\": \"$TRAVIS_COMMIT\",
- \"name\": \"${LFS_VERSION%.0}\",
- \"body\": $(jq -sR '.' <<< "$CHANGES")
+ \"ref\": \"refs/tags/$LFS_VERSION\",
+ \"sha\": \"$TRAVIS_COMMIT\"
}"
+ # Minor release?
+ if [[ "$LFS_VERSION" == *.0 ]]
+ then
+ # Build release notes
+ PREV=$(git tag --sort=-v:refname -l "v*.0" | head -1)
+ if [ ! -z "$PREV" ]
+ then
+ echo "PREV $PREV"
+ CHANGES=$'### Changes\n\n'$( \
+ git log --oneline $PREV.. --grep='^Merge' --invert-grep)
+ printf "CHANGES\n%s\n\n" "$CHANGES"
+ fi
+ # Create the release
+ curl -f -u "$GEKY_BOT_RELEASES" -X POST \
+ https://api.github.com/repos/$TRAVIS_REPO_SLUG/releases \
+ -d "{
+ \"tag_name\": \"$LFS_VERSION\",
+ \"name\": \"${LFS_VERSION%.0}\",
+ \"draft\": true,
+ \"body\": $(jq -sR '.' <<< "$CHANGES")
+ }"
+ fi
fi
# Manage statuses
diff --git a/Makefile b/Makefile
index a8b8852..79d9156 100644
--- a/Makefile
+++ b/Makefile
@@ -25,7 +25,8 @@ ifdef WORD
override CFLAGS += -m$(WORD)
endif
override CFLAGS += -I.
-override CFLAGS += -std=c99 -Wall -pedantic -Wshadow -Wunused-parameter
+override CFLAGS += -std=c99 -Wall -pedantic
+override CFLAGS += -Wshadow -Wunused-parameter -Wjump-misses-init -Wsign-compare
all: $(TARGET)
diff --git a/README.md b/README.md
index 45be6f4..d8c2c7b 100644
--- a/README.md
+++ b/README.md
@@ -176,3 +176,18 @@ handy.
[littlefs-js](https://github.com/geky/littlefs-js) - A javascript wrapper for
littlefs. I'm not sure why you would want this, but it is handy for demos.
You can see it in action [here](http://littlefs.geky.net/demo.html).
+
+[mklfs](https://github.com/whitecatboard/Lua-RTOS-ESP32/tree/master/components/mklfs/src) -
+A command line tool built by the [Lua RTOS](https://github.com/whitecatboard/Lua-RTOS-ESP32)
+guys for making littlefs images from a host PC. Supports Windows, Mac OS,
+and Linux.
+
+[SPIFFS](https://github.com/pellepl/spiffs) - Another excellent embedded
+filesystem for NOR flash. As a more traditional logging filesystem with full
+static wear-leveling, SPIFFS will likely outperform littlefs on small
+memories such as the internal flash on microcontrollers.
+
+[Dhara](https://github.com/dlbeer/dhara) - An interesting NAND flash
+translation layer designed for small MCUs. It offers static wear-leveling and
+power-resilience with only a fixed O(|address|) pointer structure stored on
+each block and in RAM.
diff --git a/emubd/lfs_emubd.c b/emubd/lfs_emubd.c
index de63057..3f31bfa 100644
--- a/emubd/lfs_emubd.c
+++ b/emubd/lfs_emubd.c
@@ -30,7 +30,7 @@ static inline void lfs_emubd_tole32(lfs_emubd_t *emu) {
emu->stats.prog_count = lfs_tole32(emu->stats.prog_count);
emu->stats.erase_count = lfs_tole32(emu->stats.erase_count);
- for (int i = 0; i < sizeof(emu->history.blocks) /
+ for (unsigned i = 0; i < sizeof(emu->history.blocks) /
sizeof(emu->history.blocks[0]); i++) {
emu->history.blocks[i] = lfs_tole32(emu->history.blocks[i]);
}
@@ -46,7 +46,7 @@ static inline void lfs_emubd_fromle32(lfs_emubd_t *emu) {
emu->stats.prog_count = lfs_fromle32(emu->stats.prog_count);
emu->stats.erase_count = lfs_fromle32(emu->stats.erase_count);
- for (int i = 0; i < sizeof(emu->history.blocks) /
+ for (unsigned i = 0; i < sizeof(emu->history.blocks) /
sizeof(emu->history.blocks[0]); i++) {
emu->history.blocks[i] = lfs_fromle32(emu->history.blocks[i]);
}
diff --git a/lfs.c b/lfs.c
index 32e626f..fc1b7a3 100644
--- a/lfs.c
+++ b/lfs.c
@@ -322,14 +322,14 @@ static inline void lfs_global_xor(struct lfs_globals *a,
const struct lfs_globals *b) {
uint32_t *a32 = (uint32_t *)a;
const uint32_t *b32 = (const uint32_t *)b;
- for (int i = 0; i < sizeof(struct lfs_globals)/4; i++) {
+ for (unsigned i = 0; i < sizeof(struct lfs_globals)/4; i++) {
a32[i] ^= b32[i];
}
}
static inline bool lfs_global_iszero(const struct lfs_globals *a) {
const uint32_t *a32 = (const uint32_t *)a;
- for (int i = 0; i < sizeof(struct lfs_globals)/4; i++) {
+ for (unsigned i = 0; i < sizeof(struct lfs_globals)/4; i++) {
if (a32[i] != 0) {
return false;
}
@@ -387,6 +387,7 @@ static inline void lfs_superblock_fromle32(lfs_superblock_t *superblock) {
superblock->name_max = lfs_fromle32(superblock->name_max);
superblock->inline_max = lfs_fromle32(superblock->inline_max);
superblock->attr_max = lfs_fromle32(superblock->attr_max);
+ superblock->file_max = lfs_fromle32(superblock->file_max);
}
static inline void lfs_superblock_tole32(lfs_superblock_t *superblock) {
@@ -396,6 +397,7 @@ static inline void lfs_superblock_tole32(lfs_superblock_t *superblock) {
superblock->name_max = lfs_tole32(superblock->name_max);
superblock->inline_max = lfs_tole32(superblock->inline_max);
superblock->attr_max = lfs_tole32(superblock->attr_max);
+ superblock->file_max = lfs_tole32(superblock->file_max);
}
@@ -1347,13 +1349,13 @@ commit:
(const lfs_block_t[2]){0, 1}) == 0) {
// we're writing too much to the superblock,
// should we expand?
- lfs_stag_t res = lfs_fs_size(lfs);
+ lfs_ssize_t res = lfs_fs_size(lfs);
if (res < 0) {
return res;
}
// do we have enough space to expand?
- if (res < lfs->cfg->block_count/2) {
+ if ((lfs_size_t)res < lfs->cfg->block_count/2) {
LFS_DEBUG("Expanding superblock at rev %"PRIu32,
dir->rev);
exhausted = true;
@@ -1376,93 +1378,95 @@ commit:
}
}
- // write out header
- uint32_t rev = lfs_tole32(dir->rev);
- err = lfs_commit_prog(lfs, &commit, &rev, sizeof(rev));
- if (err) {
- if (err == LFS_ERR_CORRUPT) {
- goto relocate;
+ if (true) {
+ // write out header
+ uint32_t rev = lfs_tole32(dir->rev);
+ err = lfs_commit_prog(lfs, &commit, &rev, sizeof(rev));
+ if (err) {
+ if (err == LFS_ERR_CORRUPT) {
+ goto relocate;
+ }
+ return err;
}
- return err;
- }
- // commit with a move
- for (uint16_t id = begin; id < end || commit.off < commit.ack; id++) {
- for (int pass = 0; pass < 2; pass++) {
- err = lfs_commit_move(lfs, &commit, pass,
- 0x003fe000, LFS_MKTAG(0, id, 0),
- -LFS_MKTAG(0, begin, 0),
- source, attrs);
- if (err && !(splitted && !overcompacting &&
- err == LFS_ERR_NOSPC)) {
- if (!overcompacting && err == LFS_ERR_NOSPC) {
- goto split;
- } else if (err == LFS_ERR_CORRUPT) {
- goto relocate;
+ // commit with a move
+ for (uint16_t id = begin; id < end || commit.off < commit.ack; id++) {
+ for (int pass = 0; pass < 2; pass++) {
+ err = lfs_commit_move(lfs, &commit, pass,
+ 0x003fe000, LFS_MKTAG(0, id, 0),
+ -LFS_MKTAG(0, begin, 0),
+ source, attrs);
+ if (err && !(splitted && !overcompacting &&
+ err == LFS_ERR_NOSPC)) {
+ if (!overcompacting && err == LFS_ERR_NOSPC) {
+ goto split;
+ } else if (err == LFS_ERR_CORRUPT) {
+ goto relocate;
+ }
+ return err;
}
- return err;
}
+
+ ackid = id;
}
- ackid = id;
- }
+ // reopen reserved space at the end
+ commit.end = lfs->cfg->block_size - 8;
- // reopen reserved space at the end
- commit.end = lfs->cfg->block_size - 8;
+ if (ackid >= end) {
+ // extra garbage attributes were written out during split,
+ // need to clean up
+ err = lfs_commit_attr(lfs, &commit,
+ LFS_MKTAG(LFS_TYPE_DELETE, ackid, 0), NULL);
+ if (err) {
+ if (err == LFS_ERR_CORRUPT) {
+ goto relocate;
+ }
+ return err;
+ }
+ }
- if (ackid >= end) {
- // extra garbage attributes were written out during split,
- // need to clean up
- err = lfs_commit_attr(lfs, &commit,
- LFS_MKTAG(LFS_TYPE_DELETE, ackid, 0), NULL);
- if (err) {
- if (err == LFS_ERR_CORRUPT) {
- goto relocate;
+ if (!relocated && !lfs_global_iszero(&lfs->locals)) {
+ // commit any globals, unless we're relocating,
+ // in which case our parent will steal our globals
+ err = lfs_commit_globals(lfs, &commit, &lfs->locals);
+ if (err) {
+ if (err == LFS_ERR_CORRUPT) {
+ goto relocate;
+ }
+ return err;
}
- return err;
}
- }
- if (!relocated && !lfs_global_iszero(&lfs->locals)) {
- // commit any globals, unless we're relocating,
- // in which case our parent will steal our globals
- err = lfs_commit_globals(lfs, &commit, &lfs->locals);
- if (err) {
- if (err == LFS_ERR_CORRUPT) {
- goto relocate;
+ if (!lfs_pair_isnull(dir->tail)) {
+ // commit tail, which may be new after last size check
+ lfs_pair_tole32(dir->tail);
+ err = lfs_commit_attr(lfs, &commit,
+ LFS_MKTAG(LFS_TYPE_TAIL + dir->split,
+ 0x1ff, sizeof(dir->tail)), dir->tail);
+ lfs_pair_fromle32(dir->tail);
+ if (err) {
+ if (err == LFS_ERR_CORRUPT) {
+ goto relocate;
+ }
+ return err;
}
- return err;
}
- }
- if (!lfs_pair_isnull(dir->tail)) {
- // commit tail, which may be new after last size check
- lfs_pair_tole32(dir->tail);
- err = lfs_commit_attr(lfs, &commit,
- LFS_MKTAG(LFS_TYPE_TAIL + dir->split,
- 0x1ff, sizeof(dir->tail)), dir->tail);
- lfs_pair_fromle32(dir->tail);
+ err = lfs_commit_crc(lfs, &commit, true);
if (err) {
if (err == LFS_ERR_CORRUPT) {
goto relocate;
}
return err;
}
- }
- err = lfs_commit_crc(lfs, &commit, true);
- if (err) {
- if (err == LFS_ERR_CORRUPT) {
- goto relocate;
- }
- return err;
+ // successful compaction, swap dir pair to indicate most recent
+ lfs_pair_swap(dir->pair);
+ dir->off = commit.off;
+ dir->etag = commit.ptag;
+ dir->erased = true;
}
-
- // successful compaction, swap dir pair to indicate most recent
- lfs_pair_swap(dir->pair);
- dir->off = commit.off;
- dir->etag = commit.ptag;
- dir->erased = true;
break;
split:
@@ -1560,7 +1564,7 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir,
// Wait, we have the move? Just cancel this out here
// We need to, or else the move can become outdated
cancelattr.tag = LFS_MKTAG(LFS_TYPE_DELETE, lfs->globals.id, 0);
- cancelattr.next = attrs;
+ cancelattr.next = attrs; // TODO need order
attrs = &cancelattr;
cancels.hasmove = lfs->globals.hasmove;
@@ -1602,11 +1606,7 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir,
attrcount += 1;
}
- while (true) {
- if (!dir->erased) {
- goto compact;
- }
-
+ if (dir->erased) {
// try to commit
struct lfs_commit commit = {
.block = dir->pair[0],
@@ -1668,18 +1668,15 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir,
dir->etag = commit.ptag;
// successful commit, update globals
lfs_global_zero(&lfs->locals);
- break;
-
+ } else {
compact:
// fall back to compaction
lfs_cache_drop(lfs, &lfs->pcache);
- err = lfs_dir_compact(lfs, dir, attrs, dir, 0, dir->count);
+ int err = lfs_dir_compact(lfs, dir, attrs, dir, 0, dir->count);
if (err) {
return err;
}
-
- break;
}
// update globals that are affected
@@ -2021,84 +2018,86 @@ static int lfs_ctz_extend(lfs_t *lfs,
}
LFS_ASSERT(nblock >= 2 && nblock <= lfs->cfg->block_count);
- err = lfs_bd_erase(lfs, nblock);
- if (err) {
- if (err == LFS_ERR_CORRUPT) {
- goto relocate;
+ if (true) {
+ err = lfs_bd_erase(lfs, nblock);
+ if (err) {
+ if (err == LFS_ERR_CORRUPT) {
+ goto relocate;
+ }
+ return err;
}
- return err;
- }
- if (size == 0) {
- *block = nblock;
- *off = 0;
- return 0;
- }
+ if (size == 0) {
+ *block = nblock;
+ *off = 0;
+ return 0;
+ }
- size -= 1;
- lfs_off_t index = lfs_ctz_index(lfs, &size);
- size += 1;
+ size -= 1;
+ lfs_off_t index = lfs_ctz_index(lfs, &size);
+ size += 1;
- // just copy out the last block if it is incomplete
- if (size != lfs->cfg->block_size) {
- for (lfs_off_t i = 0; i < size; i++) {
- uint8_t data;
- err = lfs_bd_read(lfs,
- NULL, rcache, size-i,
- head, i, &data, 1);
- if (err) {
- return err;
+ // just copy out the last block if it is incomplete
+ if (size != lfs->cfg->block_size) {
+ for (lfs_off_t i = 0; i < size; i++) {
+ uint8_t data;
+ err = lfs_bd_read(lfs,
+ NULL, rcache, size-i,
+ head, i, &data, 1);
+ if (err) {
+ return err;
+ }
+
+ err = lfs_bd_prog(lfs,
+ pcache, rcache, true,
+ nblock, i, &data, 1);
+ if (err) {
+ if (err == LFS_ERR_CORRUPT) {
+ goto relocate;
+ }
+ return err;
+ }
}
- err = lfs_bd_prog(lfs,
- pcache, rcache, true,
- nblock, i, &data, 1);
+ *block = nblock;
+ *off = size;
+ return 0;
+ }
+
+ // append block
+ index += 1;
+ lfs_size_t skips = lfs_ctz(index) + 1;
+
+ for (lfs_off_t i = 0; i < skips; i++) {
+ head = lfs_tole32(head);
+ err = lfs_bd_prog(lfs, pcache, rcache, true,
+ nblock, 4*i, &head, 4);
+ head = lfs_fromle32(head);
if (err) {
if (err == LFS_ERR_CORRUPT) {
goto relocate;
}
return err;
}
- }
-
- *block = nblock;
- *off = size;
- return 0;
- }
- // append block
- index += 1;
- lfs_size_t skips = lfs_ctz(index) + 1;
-
- for (lfs_off_t i = 0; i < skips; i++) {
- head = lfs_tole32(head);
- err = lfs_bd_prog(lfs, pcache, rcache, true,
- nblock, 4*i, &head, 4);
- head = lfs_fromle32(head);
- if (err) {
- if (err == LFS_ERR_CORRUPT) {
- goto relocate;
+ if (i != skips-1) {
+ err = lfs_bd_read(lfs,
+ NULL, rcache, sizeof(head),
+ head, 4*i, &head, sizeof(head));
+ head = lfs_fromle32(head);
+ if (err) {
+ return err;
+ }
}
- return err;
- }
- if (i != skips-1) {
- err = lfs_bd_read(lfs,
- NULL, rcache, sizeof(head),
- head, 4*i, &head, sizeof(head));
- head = lfs_fromle32(head);
- if (err) {
- return err;
- }
+ LFS_ASSERT(head >= 2 && head <= lfs->cfg->block_count);
}
- LFS_ASSERT(head >= 2 && head <= lfs->cfg->block_count);
+ *block = nblock;
+ *off = 4*skips;
+ return 0;
}
- *block = nblock;
- *off = 4*skips;
- return 0;
-
relocate:
LFS_DEBUG("Bad block at %"PRIu32, nblock);
@@ -2596,6 +2595,11 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file,
file->pos = file->ctz.size;
}
+ if (file->pos + size > lfs->file_max) {
+ // Larger than file limit?
+ return LFS_ERR_FBIG;
+ }
+
if (!(file->flags & LFS_F_WRITING) && file->pos > file->ctz.size) {
// fill with zeros
lfs_off_t pos = file->pos;
@@ -2704,24 +2708,24 @@ lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file,
return err;
}
- // update pos
+ // find new pos
+ lfs_off_t npos = file->pos;
if (whence == LFS_SEEK_SET) {
- file->pos = off;
+ npos = off;
} else if (whence == LFS_SEEK_CUR) {
- if (off < 0 && (lfs_off_t)-off > file->pos) {
- return LFS_ERR_INVAL;
- }
-
- file->pos = file->pos + off;
+ npos = file->pos + off;
} else if (whence == LFS_SEEK_END) {
- if (off < 0 && (lfs_off_t)-off > file->ctz.size) {
- return LFS_ERR_INVAL;
- }
+ npos = file->ctz.size + off;
+ }
- file->pos = file->ctz.size + off;
+ if (npos < 0 || npos > lfs->file_max) {
+ // file position out of range
+ return LFS_ERR_INVAL;
}
- return file->pos;
+ // update pos
+ file->pos = npos;
+ return npos;
}
int lfs_file_truncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) {
@@ -3112,6 +3116,12 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
lfs->attr_max = LFS_ATTR_MAX;
}
+ LFS_ASSERT(lfs->cfg->file_max <= LFS_FILE_MAX);
+ lfs->file_max = lfs->cfg->file_max;
+ if (!lfs->file_max) {
+ lfs->file_max = LFS_FILE_MAX;
+ }
+
// setup default state
lfs->root[0] = 0xffffffff;
lfs->root[1] = 0xffffffff;
@@ -3145,50 +3155,54 @@ static int lfs_deinit(lfs_t *lfs) {
}
int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) {
- int err = lfs_init(lfs, cfg);
- if (err) {
- return err;
- }
+ int err = 0;
+ if (true) {
+ err = lfs_init(lfs, cfg);
+ if (err) {
+ return err;
+ }
- // create free lookahead
- memset(lfs->free.buffer, 0, lfs->cfg->lookahead_size);
- lfs->free.off = 0;
- lfs->free.size = lfs_min(8*lfs->cfg->lookahead_size,
- lfs->cfg->block_count);
- lfs->free.i = 0;
- lfs_alloc_ack(lfs);
+ // create free lookahead
+ memset(lfs->free.buffer, 0, lfs->cfg->lookahead_size);
+ lfs->free.off = 0;
+ lfs->free.size = lfs_min(8*lfs->cfg->lookahead_size,
+ lfs->cfg->block_count);
+ lfs->free.i = 0;
+ lfs_alloc_ack(lfs);
- // create root dir
- lfs_mdir_t root;
- err = lfs_dir_alloc(lfs, &root);
- if (err) {
- goto cleanup;
- }
+ // create root dir
+ lfs_mdir_t root;
+ err = lfs_dir_alloc(lfs, &root);
+ if (err) {
+ goto cleanup;
+ }
- // write one superblock
- lfs_superblock_t superblock = {
- .version = LFS_DISK_VERSION,
- .block_size = lfs->cfg->block_size,
- .block_count = lfs->cfg->block_count,
- .name_max = lfs->name_max,
- .inline_max = lfs->inline_max,
- .attr_max = lfs->attr_max,
- };
-
- lfs_superblock_tole32(&superblock);
- err = lfs_dir_commit(lfs, &root,
- LFS_MKATTR(LFS_TYPE_INLINESTRUCT, 0,
- &superblock, sizeof(superblock),
- LFS_MKATTR(LFS_TYPE_SUPERBLOCK, 0, "littlefs", 8,
- NULL)));
- if (err) {
- goto cleanup;
- }
+ // write one superblock
+ lfs_superblock_t superblock = {
+ .version = LFS_DISK_VERSION,
+ .block_size = lfs->cfg->block_size,
+ .block_count = lfs->cfg->block_count,
+ .name_max = lfs->name_max,
+ .inline_max = lfs->inline_max,
+ .attr_max = lfs->attr_max,
+ .file_max = lfs->file_max,
+ };
- // sanity check that fetch works
- err = lfs_dir_fetch(lfs, &root, (const lfs_block_t[2]){0, 1});
- if (err) {
- goto cleanup;
+ lfs_superblock_tole32(&superblock);
+ err = lfs_dir_commit(lfs, &root,
+ LFS_MKATTR(LFS_TYPE_INLINESTRUCT, 0,
+ &superblock, sizeof(superblock),
+ LFS_MKATTR(LFS_TYPE_SUPERBLOCK, 0, "littlefs", 8,
+ NULL)));
+ if (err) {
+ goto cleanup;
+ }
+
+ // sanity check that fetch works
+ err = lfs_dir_fetch(lfs, &root, (const lfs_block_t[2]){0, 1});
+ if (err) {
+ goto cleanup;
+ }
}
cleanup:
@@ -3276,6 +3290,17 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
lfs->attr_max = superblock.attr_max;
}
+
+ if (superblock.file_max) {
+ if (superblock.file_max > lfs->file_max) {
+ LFS_ERROR("Unsupported file_max (%"PRIu32" > %"PRIu32")",
+ superblock.file_max, lfs->file_max);
+ err = LFS_ERR_INVAL;
+ goto cleanup;
+ }
+
+ lfs->file_max = superblock.file_max;
+ }
}
// has globals?
diff --git a/lfs.h b/lfs.h
index 10cb768..a8071a0 100644
--- a/lfs.h
+++ b/lfs.h
@@ -66,6 +66,15 @@ typedef uint32_t lfs_block_t;
#define LFS_ATTR_MAX 0x1ffe
#endif
+// Maximum size of a file in bytes, may be redefined to limit to support other
+// drivers. Limited on disk to <= 4294967296. However, above 2147483647 the
+// functions lfs_file_seek, lfs_file_size, and lfs_file_tell will return
+// incorrect values due to signed sizes. Stored in superblock and must be
+// respected by other littlefs drivers.
+#ifndef LFS_FILE_MAX
+#define LFS_FILE_MAX 2147483647
+#endif
+
// Possible error codes, these are negative to allow
// valid positive return values
enum lfs_error {
@@ -78,6 +87,7 @@ enum lfs_error {
LFS_ERR_ISDIR = -21, // Entry is a dir
LFS_ERR_NOTEMPTY = -39, // Dir is not empty
LFS_ERR_BADF = -9, // Bad file number
+ LFS_ERR_FBIG = -27, // File too large
LFS_ERR_INVAL = -22, // Invalid parameter
LFS_ERR_NOSPC = -28, // No space left on device
LFS_ERR_NOMEM = -12, // No more memory available
@@ -233,6 +243,11 @@ struct lfs_config {
// LFS_ATTR_MAX when zero. Stored in superblock and must be respected by
// other littlefs drivers.
lfs_size_t attr_max;
+
+ // Optional upper limit on files in bytes. No downside for larger files
+ // but must be <= LFS_FILE_MAX. Defaults to LFS_FILE_MAX when zero. Stored
+ // in superblock and must be respected by other littlefs drivers.
+ lfs_size_t file_max;
};
// File info structure
@@ -346,6 +361,7 @@ typedef struct lfs_superblock {
lfs_size_t name_max;
lfs_size_t inline_max;
lfs_size_t attr_max;
+ lfs_size_t file_max;
} lfs_superblock_t;
// The littlefs filesystem type
@@ -378,11 +394,10 @@ typedef struct lfs {
} free;
const struct lfs_config *cfg;
- lfs_size_t block_size;
- lfs_size_t block_count;
lfs_size_t name_max;
lfs_size_t inline_max;
lfs_size_t attr_max;
+ lfs_size_t file_max;
} lfs_t;
diff --git a/tests/test_alloc.sh b/tests/test_alloc.sh
index 21fee96..f924a29 100755
--- a/tests/test_alloc.sh
+++ b/tests/test_alloc.sh
@@ -32,18 +32,18 @@ lfs_alloc_singleproc() {
tests/test.py << TEST
const char *names[] = {"bacon", "eggs", "pancakes"};
lfs_mount(&lfs, &cfg) => 0;
- for (int n = 0; n < sizeof(names)/sizeof(names[0]); n++) {
+ for (unsigned n = 0; n < sizeof(names)/sizeof(names[0]); n++) {
sprintf((char*)buffer, "$1/%s", names[n]);
lfs_file_open(&lfs, &file[n], (char*)buffer,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
}
- for (int n = 0; n < sizeof(names)/sizeof(names[0]); n++) {
+ for (unsigned n = 0; n < sizeof(names)/sizeof(names[0]); n++) {
size = strlen(names[n]);
for (int i = 0; i < $SIZE; i++) {
lfs_file_write(&lfs, &file[n], names[n], size) => size;
}
}
- for (int n = 0; n < sizeof(names)/sizeof(names[0]); n++) {
+ for (unsigned n = 0; n < sizeof(names)/sizeof(names[0]); n++) {
lfs_file_close(&lfs, &file[n]) => 0;
}
lfs_unmount(&lfs) => 0;
diff --git a/tests/test_dirs.sh b/tests/test_dirs.sh
index 4aac945..5f2020f 100755
--- a/tests/test_dirs.sh
+++ b/tests/test_dirs.sh
@@ -326,13 +326,42 @@ tests/test.py << TEST
lfs_unmount(&lfs) => 0;
TEST
+echo "--- Multi-block rename ---"
+tests/test.py << TEST
+ lfs_mount(&lfs, &cfg) => 0;
+ for (int i = 0; i < $LARGESIZE; i++) {
+ sprintf((char*)buffer, "cactus/test%03d", i);
+ sprintf((char*)wbuffer, "cactus/tedd%03d", i);
+ lfs_rename(&lfs, (char*)buffer, (char*)wbuffer) => 0;
+ }
+ lfs_unmount(&lfs) => 0;
+TEST
+tests/test.py << TEST
+ lfs_mount(&lfs, &cfg) => 0;
+ lfs_dir_open(&lfs, &dir[0], "cactus") => 0;
+ lfs_dir_read(&lfs, &dir[0], &info) => 1;
+ strcmp(info.name, ".") => 0;
+ info.type => LFS_TYPE_DIR;
+ lfs_dir_read(&lfs, &dir[0], &info) => 1;
+ strcmp(info.name, "..") => 0;
+ info.type => LFS_TYPE_DIR;
+ for (int i = 0; i < $LARGESIZE; i++) {
+ sprintf((char*)buffer, "tedd%03d", i);
+ lfs_dir_read(&lfs, &dir[0], &info) => 1;
+ strcmp(info.name, (char*)buffer) => 0;
+ info.type => LFS_TYPE_DIR;
+ }
+ lfs_dir_read(&lfs, &dir[0], &info) => 0;
+ lfs_unmount(&lfs) => 0;
+TEST
+
echo "--- Multi-block remove ---"
tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0;
lfs_remove(&lfs, "cactus") => LFS_ERR_NOTEMPTY;
for (int i = 0; i < $LARGESIZE; i++) {
- sprintf((char*)buffer, "cactus/test%03d", i);
+ sprintf((char*)buffer, "cactus/tedd%03d", i);
lfs_remove(&lfs, (char*)buffer) => 0;
}
@@ -391,13 +420,43 @@ tests/test.py << TEST
lfs_unmount(&lfs) => 0;
TEST
+echo "--- Multi-block rename with files ---"
+tests/test.py << TEST
+ lfs_mount(&lfs, &cfg) => 0;
+ for (int i = 0; i < $LARGESIZE; i++) {
+ sprintf((char*)buffer, "prickly-pear/test%03d", i);
+ sprintf((char*)wbuffer, "prickly-pear/tedd%03d", i);
+ lfs_rename(&lfs, (char*)buffer, (char*)wbuffer) => 0;
+ }
+ lfs_unmount(&lfs) => 0;
+TEST
+tests/test.py << TEST
+ lfs_mount(&lfs, &cfg) => 0;
+ lfs_dir_open(&lfs, &dir[0], "prickly-pear") => 0;
+ lfs_dir_read(&lfs, &dir[0], &info) => 1;
+ strcmp(info.name, ".") => 0;
+ info.type => LFS_TYPE_DIR;
+ lfs_dir_read(&lfs, &dir[0], &info) => 1;
+ strcmp(info.name, "..") => 0;
+ info.type => LFS_TYPE_DIR;
+ for (int i = 0; i < $LARGESIZE; i++) {
+ sprintf((char*)buffer, "tedd%03d", i);
+ lfs_dir_read(&lfs, &dir[0], &info) => 1;
+ strcmp(info.name, (char*)buffer) => 0;
+ info.type => LFS_TYPE_REG;
+ info.size => 6;
+ }
+ lfs_dir_read(&lfs, &dir[0], &info) => 0;
+ lfs_unmount(&lfs) => 0;
+TEST
+
echo "--- Multi-block remove with files ---"
tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0;
lfs_remove(&lfs, "prickly-pear") => LFS_ERR_NOTEMPTY;
for (int i = 0; i < $LARGESIZE; i++) {
- sprintf((char*)buffer, "prickly-pear/test%03d", i);
+ sprintf((char*)buffer, "prickly-pear/tedd%03d", i);
lfs_remove(&lfs, (char*)buffer) => 0;
}
diff --git a/tests/test_seek.sh b/tests/test_seek.sh
index 609c250..2cd711a 100755
--- a/tests/test_seek.sh
+++ b/tests/test_seek.sh
@@ -301,7 +301,7 @@ tests/test.py << TEST
size = strlen("hedgehoghog");
const lfs_soff_t offsets[] = {512, 1020, 513, 1021, 511, 1019};
- for (int i = 0; i < sizeof(offsets) / sizeof(offsets[0]); i++) {
+ for (unsigned i = 0; i < sizeof(offsets) / sizeof(offsets[0]); i++) {
lfs_soff_t off = offsets[i];
memcpy(buffer, "hedgehoghog", size);
lfs_file_seek(&lfs, &file[0], off, LFS_SEEK_SET) => off;
diff --git a/tests/test_truncate.sh b/tests/test_truncate.sh
index da5ccaf..053b2e0 100755
--- a/tests/test_truncate.sh
+++ b/tests/test_truncate.sh
@@ -23,14 +23,14 @@ tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0;
- for (int i = 0; i < sizeof(startsizes)/sizeof(startsizes[0]); i++) {
+ for (unsigned i = 0; i < sizeof(startsizes)/sizeof(startsizes[0]); i++) {
sprintf((char*)buffer, "hairyhead%d", i);
lfs_file_open(&lfs, &file[0], (const char*)buffer,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
strcpy((char*)buffer, "hair");
size = strlen((char*)buffer);
- for (int j = 0; j < startsizes[i]; j += size) {
+ for (lfs_off_t j = 0; j < startsizes[i]; j += size) {
lfs_file_write(&lfs, &file[0], buffer, size) => size;
}
lfs_file_size(&lfs, &file[0]) => startsizes[i];
@@ -55,13 +55,13 @@ tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0;
- for (int i = 0; i < sizeof(startsizes)/sizeof(startsizes[0]); i++) {
+ for (unsigned i = 0; i < sizeof(startsizes)/sizeof(startsizes[0]); i++) {
sprintf((char*)buffer, "hairyhead%d", i);
lfs_file_open(&lfs, &file[0], (const char*)buffer, LFS_O_RDWR) => 0;
lfs_file_size(&lfs, &file[0]) => hotsizes[i];
size = strlen("hair");
- int j = 0;
+ lfs_off_t j = 0;
for (; j < startsizes[i] && j < hotsizes[i]; j += size) {
lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "hair", size) => 0;
@@ -87,13 +87,13 @@ tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0;
- for (int i = 0; i < sizeof(startsizes)/sizeof(startsizes[0]); i++) {
+ for (unsigned i = 0; i < sizeof(startsizes)/sizeof(startsizes[0]); i++) {
sprintf((char*)buffer, "hairyhead%d", i);
lfs_file_open(&lfs, &file[0], (const char*)buffer, LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file[0]) => coldsizes[i];
size = strlen("hair");
- int j = 0;
+ lfs_off_t j = 0;
for (; j < startsizes[i] && j < hotsizes[i] && j < coldsizes[i];
j += size) {
lfs_file_read(&lfs, &file[0], buffer, size) => size;