mirror of
https://gitee.com/openharmony/third_party_littlefs
synced 2024-11-23 06:50:37 +00:00
Merge remote-tracking branch 'origin/master' into v2-rebase-part2
This commit is contained in:
commit
c8a39c4b23
56
.travis.yml
56
.travis.yml
@ -139,12 +139,15 @@ jobs:
|
|||||||
- LFS_VERSION=$(grep -ox '#define LFS_VERSION .*' lfs.h | cut -d ' ' -f3)
|
- LFS_VERSION=$(grep -ox '#define LFS_VERSION .*' lfs.h | cut -d ' ' -f3)
|
||||||
- LFS_VERSION_MAJOR=$((0xffff & ($LFS_VERSION >> 16)))
|
- LFS_VERSION_MAJOR=$((0xffff & ($LFS_VERSION >> 16)))
|
||||||
- LFS_VERSION_MINOR=$((0xffff & ($LFS_VERSION >> 0)))
|
- LFS_VERSION_MINOR=$((0xffff & ($LFS_VERSION >> 0)))
|
||||||
# Grab latests patch from repo tags, default to 0
|
# Grab latests patch from repo tags, default to 0, needs finagling to get past github's pagination api
|
||||||
- LFS_VERSION_PATCH=$(curl -f -u "$GEKY_BOT_RELEASES"
|
- PREV_URL=https://api.github.com/repos/$TRAVIS_REPO_SLUG/git/refs/tags/v$LFS_VERSION_MAJOR.$LFS_VERSION_MINOR.
|
||||||
https://api.github.com/repos/$TRAVIS_REPO_SLUG/git/refs
|
- PREV_URL=$(curl -u "$GEKY_BOT_RELEASES" "$PREV_URL" -I
|
||||||
| jq 'map(.ref | match(
|
| sed -n '/^Link/{s/.*<\(.*\)>; rel="last"/\1/;p;q0};$q1'
|
||||||
"refs/tags/v'"$LFS_VERSION_MAJOR"'\\.'"$LFS_VERSION_MINOR"'\\.(.*)$")
|
|| echo $PREV_URL)
|
||||||
.captures[].string | tonumber + 1) | max // 0')
|
- 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
|
# We have our new version
|
||||||
- LFS_VERSION="v$LFS_VERSION_MAJOR.$LFS_VERSION_MINOR.$LFS_VERSION_PATCH"
|
- LFS_VERSION="v$LFS_VERSION_MAJOR.$LFS_VERSION_MINOR.$LFS_VERSION_PATCH"
|
||||||
- echo "VERSION $LFS_VERSION"
|
- echo "VERSION $LFS_VERSION"
|
||||||
@ -155,24 +158,35 @@ jobs:
|
|||||||
| jq -re '.sha')
|
| jq -re '.sha')
|
||||||
if [ "$TRAVIS_COMMIT" == "$CURRENT_COMMIT" ]
|
if [ "$TRAVIS_COMMIT" == "$CURRENT_COMMIT" ]
|
||||||
then
|
then
|
||||||
# Build release notes
|
# Create a simple tag
|
||||||
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
|
|
||||||
curl -f -u "$GEKY_BOT_RELEASES" -X POST \
|
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 "{
|
-d "{
|
||||||
\"tag_name\": \"$LFS_VERSION\",
|
\"ref\": \"refs/tags/$LFS_VERSION\",
|
||||||
\"target_commitish\": \"$TRAVIS_COMMIT\",
|
\"sha\": \"$TRAVIS_COMMIT\"
|
||||||
\"name\": \"${LFS_VERSION%.0}\",
|
|
||||||
\"body\": $(jq -sR '.' <<< "$CHANGES")
|
|
||||||
}"
|
}"
|
||||||
|
# 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
|
fi
|
||||||
|
|
||||||
# Manage statuses
|
# Manage statuses
|
||||||
|
3
Makefile
3
Makefile
@ -25,7 +25,8 @@ ifdef WORD
|
|||||||
override CFLAGS += -m$(WORD)
|
override CFLAGS += -m$(WORD)
|
||||||
endif
|
endif
|
||||||
override CFLAGS += -I.
|
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)
|
all: $(TARGET)
|
||||||
|
15
README.md
15
README.md
@ -176,3 +176,18 @@ handy.
|
|||||||
[littlefs-js](https://github.com/geky/littlefs-js) - A javascript wrapper for
|
[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.
|
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).
|
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.
|
||||||
|
@ -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.prog_count = lfs_tole32(emu->stats.prog_count);
|
||||||
emu->stats.erase_count = lfs_tole32(emu->stats.erase_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++) {
|
sizeof(emu->history.blocks[0]); i++) {
|
||||||
emu->history.blocks[i] = lfs_tole32(emu->history.blocks[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.prog_count = lfs_fromle32(emu->stats.prog_count);
|
||||||
emu->stats.erase_count = lfs_fromle32(emu->stats.erase_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++) {
|
sizeof(emu->history.blocks[0]); i++) {
|
||||||
emu->history.blocks[i] = lfs_fromle32(emu->history.blocks[i]);
|
emu->history.blocks[i] = lfs_fromle32(emu->history.blocks[i]);
|
||||||
}
|
}
|
||||||
|
431
lfs.c
431
lfs.c
@ -322,14 +322,14 @@ static inline void lfs_global_xor(struct lfs_globals *a,
|
|||||||
const struct lfs_globals *b) {
|
const struct lfs_globals *b) {
|
||||||
uint32_t *a32 = (uint32_t *)a;
|
uint32_t *a32 = (uint32_t *)a;
|
||||||
const uint32_t *b32 = (const uint32_t *)b;
|
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];
|
a32[i] ^= b32[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool lfs_global_iszero(const struct lfs_globals *a) {
|
static inline bool lfs_global_iszero(const struct lfs_globals *a) {
|
||||||
const uint32_t *a32 = (const uint32_t *)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) {
|
if (a32[i] != 0) {
|
||||||
return false;
|
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->name_max = lfs_fromle32(superblock->name_max);
|
||||||
superblock->inline_max = lfs_fromle32(superblock->inline_max);
|
superblock->inline_max = lfs_fromle32(superblock->inline_max);
|
||||||
superblock->attr_max = lfs_fromle32(superblock->attr_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) {
|
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->name_max = lfs_tole32(superblock->name_max);
|
||||||
superblock->inline_max = lfs_tole32(superblock->inline_max);
|
superblock->inline_max = lfs_tole32(superblock->inline_max);
|
||||||
superblock->attr_max = lfs_tole32(superblock->attr_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) {
|
(const lfs_block_t[2]){0, 1}) == 0) {
|
||||||
// we're writing too much to the superblock,
|
// we're writing too much to the superblock,
|
||||||
// should we expand?
|
// should we expand?
|
||||||
lfs_stag_t res = lfs_fs_size(lfs);
|
lfs_ssize_t res = lfs_fs_size(lfs);
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
// do we have enough space to expand?
|
// 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,
|
LFS_DEBUG("Expanding superblock at rev %"PRIu32,
|
||||||
dir->rev);
|
dir->rev);
|
||||||
exhausted = true;
|
exhausted = true;
|
||||||
@ -1376,93 +1378,95 @@ commit:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// write out header
|
if (true) {
|
||||||
uint32_t rev = lfs_tole32(dir->rev);
|
// write out header
|
||||||
err = lfs_commit_prog(lfs, &commit, &rev, sizeof(rev));
|
uint32_t rev = lfs_tole32(dir->rev);
|
||||||
if (err) {
|
err = lfs_commit_prog(lfs, &commit, &rev, sizeof(rev));
|
||||||
if (err == LFS_ERR_CORRUPT) {
|
if (err) {
|
||||||
goto relocate;
|
if (err == LFS_ERR_CORRUPT) {
|
||||||
|
goto relocate;
|
||||||
|
}
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
// commit with a move
|
// commit with a move
|
||||||
for (uint16_t id = begin; id < end || commit.off < commit.ack; id++) {
|
for (uint16_t id = begin; id < end || commit.off < commit.ack; id++) {
|
||||||
for (int pass = 0; pass < 2; pass++) {
|
for (int pass = 0; pass < 2; pass++) {
|
||||||
err = lfs_commit_move(lfs, &commit, pass,
|
err = lfs_commit_move(lfs, &commit, pass,
|
||||||
0x003fe000, LFS_MKTAG(0, id, 0),
|
0x003fe000, LFS_MKTAG(0, id, 0),
|
||||||
-LFS_MKTAG(0, begin, 0),
|
-LFS_MKTAG(0, begin, 0),
|
||||||
source, attrs);
|
source, attrs);
|
||||||
if (err && !(splitted && !overcompacting &&
|
if (err && !(splitted && !overcompacting &&
|
||||||
err == LFS_ERR_NOSPC)) {
|
err == LFS_ERR_NOSPC)) {
|
||||||
if (!overcompacting && err == LFS_ERR_NOSPC) {
|
if (!overcompacting && err == LFS_ERR_NOSPC) {
|
||||||
goto split;
|
goto split;
|
||||||
} else if (err == LFS_ERR_CORRUPT) {
|
} else if (err == LFS_ERR_CORRUPT) {
|
||||||
|
goto relocate;
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ackid = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
goto relocate;
|
||||||
}
|
}
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ackid = id;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// reopen reserved space at the end
|
if (!lfs_pair_isnull(dir->tail)) {
|
||||||
commit.end = lfs->cfg->block_size - 8;
|
// 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (ackid >= end) {
|
err = lfs_commit_crc(lfs, &commit, true);
|
||||||
// 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) {
|
||||||
if (err == LFS_ERR_CORRUPT) {
|
if (err == LFS_ERR_CORRUPT) {
|
||||||
goto relocate;
|
goto relocate;
|
||||||
}
|
}
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!relocated && !lfs_global_iszero(&lfs->locals)) {
|
// successful compaction, swap dir pair to indicate most recent
|
||||||
// commit any globals, unless we're relocating,
|
lfs_pair_swap(dir->pair);
|
||||||
// in which case our parent will steal our globals
|
dir->off = commit.off;
|
||||||
err = lfs_commit_globals(lfs, &commit, &lfs->locals);
|
dir->etag = commit.ptag;
|
||||||
if (err) {
|
dir->erased = true;
|
||||||
if (err == LFS_ERR_CORRUPT) {
|
|
||||||
goto relocate;
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
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;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
split:
|
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
|
// Wait, we have the move? Just cancel this out here
|
||||||
// We need to, or else the move can become outdated
|
// We need to, or else the move can become outdated
|
||||||
cancelattr.tag = LFS_MKTAG(LFS_TYPE_DELETE, lfs->globals.id, 0);
|
cancelattr.tag = LFS_MKTAG(LFS_TYPE_DELETE, lfs->globals.id, 0);
|
||||||
cancelattr.next = attrs;
|
cancelattr.next = attrs; // TODO need order
|
||||||
attrs = &cancelattr;
|
attrs = &cancelattr;
|
||||||
|
|
||||||
cancels.hasmove = lfs->globals.hasmove;
|
cancels.hasmove = lfs->globals.hasmove;
|
||||||
@ -1602,11 +1606,7 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir,
|
|||||||
attrcount += 1;
|
attrcount += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (true) {
|
if (dir->erased) {
|
||||||
if (!dir->erased) {
|
|
||||||
goto compact;
|
|
||||||
}
|
|
||||||
|
|
||||||
// try to commit
|
// try to commit
|
||||||
struct lfs_commit commit = {
|
struct lfs_commit commit = {
|
||||||
.block = dir->pair[0],
|
.block = dir->pair[0],
|
||||||
@ -1668,18 +1668,15 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir,
|
|||||||
dir->etag = commit.ptag;
|
dir->etag = commit.ptag;
|
||||||
// successful commit, update globals
|
// successful commit, update globals
|
||||||
lfs_global_zero(&lfs->locals);
|
lfs_global_zero(&lfs->locals);
|
||||||
break;
|
} else {
|
||||||
|
|
||||||
compact:
|
compact:
|
||||||
// fall back to compaction
|
// fall back to compaction
|
||||||
lfs_cache_drop(lfs, &lfs->pcache);
|
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) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// update globals that are affected
|
// update globals that are affected
|
||||||
@ -2021,60 +2018,8 @@ static int lfs_ctz_extend(lfs_t *lfs,
|
|||||||
}
|
}
|
||||||
LFS_ASSERT(nblock >= 2 && nblock <= lfs->cfg->block_count);
|
LFS_ASSERT(nblock >= 2 && nblock <= lfs->cfg->block_count);
|
||||||
|
|
||||||
err = lfs_bd_erase(lfs, nblock);
|
if (true) {
|
||||||
if (err) {
|
err = lfs_bd_erase(lfs, nblock);
|
||||||
if (err == LFS_ERR_CORRUPT) {
|
|
||||||
goto relocate;
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (size == 0) {
|
|
||||||
*block = nblock;
|
|
||||||
*off = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = lfs_bd_prog(lfs,
|
|
||||||
pcache, rcache, true,
|
|
||||||
nblock, i, &data, 1);
|
|
||||||
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) {
|
||||||
if (err == LFS_ERR_CORRUPT) {
|
if (err == LFS_ERR_CORRUPT) {
|
||||||
goto relocate;
|
goto relocate;
|
||||||
@ -2082,22 +2027,76 @@ static int lfs_ctz_extend(lfs_t *lfs,
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i != skips-1) {
|
if (size == 0) {
|
||||||
err = lfs_bd_read(lfs,
|
*block = nblock;
|
||||||
NULL, rcache, sizeof(head),
|
*off = 0;
|
||||||
head, 4*i, &head, sizeof(head));
|
return 0;
|
||||||
head = lfs_fromle32(head);
|
|
||||||
if (err) {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LFS_ASSERT(head >= 2 && head <= lfs->cfg->block_count);
|
size -= 1;
|
||||||
}
|
lfs_off_t index = lfs_ctz_index(lfs, &size);
|
||||||
|
size += 1;
|
||||||
|
|
||||||
*block = nblock;
|
// just copy out the last block if it is incomplete
|
||||||
*off = 4*skips;
|
if (size != lfs->cfg->block_size) {
|
||||||
return 0;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
*block = nblock;
|
||||||
|
*off = 4*skips;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
relocate:
|
relocate:
|
||||||
LFS_DEBUG("Bad block at %"PRIu32, nblock);
|
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;
|
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) {
|
if (!(file->flags & LFS_F_WRITING) && file->pos > file->ctz.size) {
|
||||||
// fill with zeros
|
// fill with zeros
|
||||||
lfs_off_t pos = file->pos;
|
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;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// update pos
|
// find new pos
|
||||||
|
lfs_off_t npos = file->pos;
|
||||||
if (whence == LFS_SEEK_SET) {
|
if (whence == LFS_SEEK_SET) {
|
||||||
file->pos = off;
|
npos = off;
|
||||||
} else if (whence == LFS_SEEK_CUR) {
|
} else if (whence == LFS_SEEK_CUR) {
|
||||||
if (off < 0 && (lfs_off_t)-off > file->pos) {
|
npos = file->pos + off;
|
||||||
return LFS_ERR_INVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
file->pos = file->pos + off;
|
|
||||||
} else if (whence == LFS_SEEK_END) {
|
} else if (whence == LFS_SEEK_END) {
|
||||||
if (off < 0 && (lfs_off_t)-off > file->ctz.size) {
|
npos = file->ctz.size + off;
|
||||||
return LFS_ERR_INVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
file->pos = file->ctz.size + off;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return file->pos;
|
if (npos < 0 || npos > lfs->file_max) {
|
||||||
|
// file position out of range
|
||||||
|
return LFS_ERR_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update pos
|
||||||
|
file->pos = npos;
|
||||||
|
return npos;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lfs_file_truncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) {
|
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->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
|
// setup default state
|
||||||
lfs->root[0] = 0xffffffff;
|
lfs->root[0] = 0xffffffff;
|
||||||
lfs->root[1] = 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 lfs_format(lfs_t *lfs, const struct lfs_config *cfg) {
|
||||||
int err = lfs_init(lfs, cfg);
|
int err = 0;
|
||||||
if (err) {
|
if (true) {
|
||||||
return err;
|
err = lfs_init(lfs, cfg);
|
||||||
}
|
if (err) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
// create free lookahead
|
// create free lookahead
|
||||||
memset(lfs->free.buffer, 0, lfs->cfg->lookahead_size);
|
memset(lfs->free.buffer, 0, lfs->cfg->lookahead_size);
|
||||||
lfs->free.off = 0;
|
lfs->free.off = 0;
|
||||||
lfs->free.size = lfs_min(8*lfs->cfg->lookahead_size,
|
lfs->free.size = lfs_min(8*lfs->cfg->lookahead_size,
|
||||||
lfs->cfg->block_count);
|
lfs->cfg->block_count);
|
||||||
lfs->free.i = 0;
|
lfs->free.i = 0;
|
||||||
lfs_alloc_ack(lfs);
|
lfs_alloc_ack(lfs);
|
||||||
|
|
||||||
// create root dir
|
// create root dir
|
||||||
lfs_mdir_t root;
|
lfs_mdir_t root;
|
||||||
err = lfs_dir_alloc(lfs, &root);
|
err = lfs_dir_alloc(lfs, &root);
|
||||||
if (err) {
|
if (err) {
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
// write one superblock
|
// write one superblock
|
||||||
lfs_superblock_t superblock = {
|
lfs_superblock_t superblock = {
|
||||||
.version = LFS_DISK_VERSION,
|
.version = LFS_DISK_VERSION,
|
||||||
.block_size = lfs->cfg->block_size,
|
.block_size = lfs->cfg->block_size,
|
||||||
.block_count = lfs->cfg->block_count,
|
.block_count = lfs->cfg->block_count,
|
||||||
.name_max = lfs->name_max,
|
.name_max = lfs->name_max,
|
||||||
.inline_max = lfs->inline_max,
|
.inline_max = lfs->inline_max,
|
||||||
.attr_max = lfs->attr_max,
|
.attr_max = lfs->attr_max,
|
||||||
};
|
.file_max = lfs->file_max,
|
||||||
|
};
|
||||||
|
|
||||||
lfs_superblock_tole32(&superblock);
|
lfs_superblock_tole32(&superblock);
|
||||||
err = lfs_dir_commit(lfs, &root,
|
err = lfs_dir_commit(lfs, &root,
|
||||||
LFS_MKATTR(LFS_TYPE_INLINESTRUCT, 0,
|
LFS_MKATTR(LFS_TYPE_INLINESTRUCT, 0,
|
||||||
&superblock, sizeof(superblock),
|
&superblock, sizeof(superblock),
|
||||||
LFS_MKATTR(LFS_TYPE_SUPERBLOCK, 0, "littlefs", 8,
|
LFS_MKATTR(LFS_TYPE_SUPERBLOCK, 0, "littlefs", 8,
|
||||||
NULL)));
|
NULL)));
|
||||||
if (err) {
|
if (err) {
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
// sanity check that fetch works
|
// sanity check that fetch works
|
||||||
err = lfs_dir_fetch(lfs, &root, (const lfs_block_t[2]){0, 1});
|
err = lfs_dir_fetch(lfs, &root, (const lfs_block_t[2]){0, 1});
|
||||||
if (err) {
|
if (err) {
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
@ -3276,6 +3290,17 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
|
|||||||
|
|
||||||
lfs->attr_max = superblock.attr_max;
|
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?
|
// has globals?
|
||||||
|
19
lfs.h
19
lfs.h
@ -66,6 +66,15 @@ typedef uint32_t lfs_block_t;
|
|||||||
#define LFS_ATTR_MAX 0x1ffe
|
#define LFS_ATTR_MAX 0x1ffe
|
||||||
#endif
|
#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
|
// Possible error codes, these are negative to allow
|
||||||
// valid positive return values
|
// valid positive return values
|
||||||
enum lfs_error {
|
enum lfs_error {
|
||||||
@ -78,6 +87,7 @@ enum lfs_error {
|
|||||||
LFS_ERR_ISDIR = -21, // Entry is a dir
|
LFS_ERR_ISDIR = -21, // Entry is a dir
|
||||||
LFS_ERR_NOTEMPTY = -39, // Dir is not empty
|
LFS_ERR_NOTEMPTY = -39, // Dir is not empty
|
||||||
LFS_ERR_BADF = -9, // Bad file number
|
LFS_ERR_BADF = -9, // Bad file number
|
||||||
|
LFS_ERR_FBIG = -27, // File too large
|
||||||
LFS_ERR_INVAL = -22, // Invalid parameter
|
LFS_ERR_INVAL = -22, // Invalid parameter
|
||||||
LFS_ERR_NOSPC = -28, // No space left on device
|
LFS_ERR_NOSPC = -28, // No space left on device
|
||||||
LFS_ERR_NOMEM = -12, // No more memory available
|
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
|
// LFS_ATTR_MAX when zero. Stored in superblock and must be respected by
|
||||||
// other littlefs drivers.
|
// other littlefs drivers.
|
||||||
lfs_size_t attr_max;
|
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
|
// File info structure
|
||||||
@ -346,6 +361,7 @@ typedef struct lfs_superblock {
|
|||||||
lfs_size_t name_max;
|
lfs_size_t name_max;
|
||||||
lfs_size_t inline_max;
|
lfs_size_t inline_max;
|
||||||
lfs_size_t attr_max;
|
lfs_size_t attr_max;
|
||||||
|
lfs_size_t file_max;
|
||||||
} lfs_superblock_t;
|
} lfs_superblock_t;
|
||||||
|
|
||||||
// The littlefs filesystem type
|
// The littlefs filesystem type
|
||||||
@ -378,11 +394,10 @@ typedef struct lfs {
|
|||||||
} free;
|
} free;
|
||||||
|
|
||||||
const struct lfs_config *cfg;
|
const struct lfs_config *cfg;
|
||||||
lfs_size_t block_size;
|
|
||||||
lfs_size_t block_count;
|
|
||||||
lfs_size_t name_max;
|
lfs_size_t name_max;
|
||||||
lfs_size_t inline_max;
|
lfs_size_t inline_max;
|
||||||
lfs_size_t attr_max;
|
lfs_size_t attr_max;
|
||||||
|
lfs_size_t file_max;
|
||||||
} lfs_t;
|
} lfs_t;
|
||||||
|
|
||||||
|
|
||||||
|
@ -32,18 +32,18 @@ lfs_alloc_singleproc() {
|
|||||||
tests/test.py << TEST
|
tests/test.py << TEST
|
||||||
const char *names[] = {"bacon", "eggs", "pancakes"};
|
const char *names[] = {"bacon", "eggs", "pancakes"};
|
||||||
lfs_mount(&lfs, &cfg) => 0;
|
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]);
|
sprintf((char*)buffer, "$1/%s", names[n]);
|
||||||
lfs_file_open(&lfs, &file[n], (char*)buffer,
|
lfs_file_open(&lfs, &file[n], (char*)buffer,
|
||||||
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
|
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]);
|
size = strlen(names[n]);
|
||||||
for (int i = 0; i < $SIZE; i++) {
|
for (int i = 0; i < $SIZE; i++) {
|
||||||
lfs_file_write(&lfs, &file[n], names[n], size) => size;
|
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_file_close(&lfs, &file[n]) => 0;
|
||||||
}
|
}
|
||||||
lfs_unmount(&lfs) => 0;
|
lfs_unmount(&lfs) => 0;
|
||||||
|
@ -326,13 +326,42 @@ tests/test.py << TEST
|
|||||||
lfs_unmount(&lfs) => 0;
|
lfs_unmount(&lfs) => 0;
|
||||||
TEST
|
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 ---"
|
echo "--- Multi-block remove ---"
|
||||||
tests/test.py << TEST
|
tests/test.py << TEST
|
||||||
lfs_mount(&lfs, &cfg) => 0;
|
lfs_mount(&lfs, &cfg) => 0;
|
||||||
lfs_remove(&lfs, "cactus") => LFS_ERR_NOTEMPTY;
|
lfs_remove(&lfs, "cactus") => LFS_ERR_NOTEMPTY;
|
||||||
|
|
||||||
for (int i = 0; i < $LARGESIZE; i++) {
|
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;
|
lfs_remove(&lfs, (char*)buffer) => 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -391,13 +420,43 @@ tests/test.py << TEST
|
|||||||
lfs_unmount(&lfs) => 0;
|
lfs_unmount(&lfs) => 0;
|
||||||
TEST
|
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 ---"
|
echo "--- Multi-block remove with files ---"
|
||||||
tests/test.py << TEST
|
tests/test.py << TEST
|
||||||
lfs_mount(&lfs, &cfg) => 0;
|
lfs_mount(&lfs, &cfg) => 0;
|
||||||
lfs_remove(&lfs, "prickly-pear") => LFS_ERR_NOTEMPTY;
|
lfs_remove(&lfs, "prickly-pear") => LFS_ERR_NOTEMPTY;
|
||||||
|
|
||||||
for (int i = 0; i < $LARGESIZE; i++) {
|
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;
|
lfs_remove(&lfs, (char*)buffer) => 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -301,7 +301,7 @@ tests/test.py << TEST
|
|||||||
size = strlen("hedgehoghog");
|
size = strlen("hedgehoghog");
|
||||||
const lfs_soff_t offsets[] = {512, 1020, 513, 1021, 511, 1019};
|
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];
|
lfs_soff_t off = offsets[i];
|
||||||
memcpy(buffer, "hedgehoghog", size);
|
memcpy(buffer, "hedgehoghog", size);
|
||||||
lfs_file_seek(&lfs, &file[0], off, LFS_SEEK_SET) => off;
|
lfs_file_seek(&lfs, &file[0], off, LFS_SEEK_SET) => off;
|
||||||
|
@ -23,14 +23,14 @@ tests/test.py << TEST
|
|||||||
|
|
||||||
lfs_mount(&lfs, &cfg) => 0;
|
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);
|
sprintf((char*)buffer, "hairyhead%d", i);
|
||||||
lfs_file_open(&lfs, &file[0], (const char*)buffer,
|
lfs_file_open(&lfs, &file[0], (const char*)buffer,
|
||||||
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
|
||||||
|
|
||||||
strcpy((char*)buffer, "hair");
|
strcpy((char*)buffer, "hair");
|
||||||
size = strlen((char*)buffer);
|
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_write(&lfs, &file[0], buffer, size) => size;
|
||||||
}
|
}
|
||||||
lfs_file_size(&lfs, &file[0]) => startsizes[i];
|
lfs_file_size(&lfs, &file[0]) => startsizes[i];
|
||||||
@ -55,13 +55,13 @@ tests/test.py << TEST
|
|||||||
|
|
||||||
lfs_mount(&lfs, &cfg) => 0;
|
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);
|
sprintf((char*)buffer, "hairyhead%d", i);
|
||||||
lfs_file_open(&lfs, &file[0], (const char*)buffer, LFS_O_RDWR) => 0;
|
lfs_file_open(&lfs, &file[0], (const char*)buffer, LFS_O_RDWR) => 0;
|
||||||
lfs_file_size(&lfs, &file[0]) => hotsizes[i];
|
lfs_file_size(&lfs, &file[0]) => hotsizes[i];
|
||||||
|
|
||||||
size = strlen("hair");
|
size = strlen("hair");
|
||||||
int j = 0;
|
lfs_off_t j = 0;
|
||||||
for (; j < startsizes[i] && j < hotsizes[i]; j += size) {
|
for (; j < startsizes[i] && j < hotsizes[i]; j += size) {
|
||||||
lfs_file_read(&lfs, &file[0], buffer, size) => size;
|
lfs_file_read(&lfs, &file[0], buffer, size) => size;
|
||||||
memcmp(buffer, "hair", size) => 0;
|
memcmp(buffer, "hair", size) => 0;
|
||||||
@ -87,13 +87,13 @@ tests/test.py << TEST
|
|||||||
|
|
||||||
lfs_mount(&lfs, &cfg) => 0;
|
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);
|
sprintf((char*)buffer, "hairyhead%d", i);
|
||||||
lfs_file_open(&lfs, &file[0], (const char*)buffer, LFS_O_RDONLY) => 0;
|
lfs_file_open(&lfs, &file[0], (const char*)buffer, LFS_O_RDONLY) => 0;
|
||||||
lfs_file_size(&lfs, &file[0]) => coldsizes[i];
|
lfs_file_size(&lfs, &file[0]) => coldsizes[i];
|
||||||
|
|
||||||
size = strlen("hair");
|
size = strlen("hair");
|
||||||
int j = 0;
|
lfs_off_t j = 0;
|
||||||
for (; j < startsizes[i] && j < hotsizes[i] && j < coldsizes[i];
|
for (; j < startsizes[i] && j < hotsizes[i] && j < coldsizes[i];
|
||||||
j += size) {
|
j += size) {
|
||||||
lfs_file_read(&lfs, &file[0], buffer, size) => size;
|
lfs_file_read(&lfs, &file[0], buffer, size) => size;
|
||||||
|
Loading…
Reference in New Issue
Block a user