Compare commits

..

11 Commits

Author SHA1 Message Date
Christopher Haster
5f885f0af1 Adopted per-member static configurations
Instead of 1. defining LFS_STATICCFG and 2. defining all LFS_READ_SIZE,
LFS_PROG_SIZE, etc. Configuration can now be made static by defining
LFS_READ_SIZE, LFS_PROG_SIZE, etc. Thanks to a really large ifdef, if
all configurations are provided, LFS_STATICCFG will be defined and the
RAM cost fully removed.

Additionally, we can remove the ROM cost of each struct cfg member,
allowing code savings when config is only partially defined, which is
perhaps more common.

This moves all of the configuration logic in lfs.h, which has the nice
side effect of keeping all of the decision making in the same location.

The only catch is that we need to differentiate between the cfg->*_max
and *_MAX limits. To do this I've renamed the configuration *_max to
*_limit. Note that these two are slightly different, with *_max
indicating the maximum supported by the current driver, and *_limit
the maximum supported by the specific instance of littlefs. However if
you do define a *_LIMIT, I've added an override for the relevant *_MAX,
since I can't think of a time where you _wouldn't_ want to do that.

---

This also required some tweaks in scripts/test.py in order to populate
the lfs_cfg struct correctly. This happens since the test defines
overlap littlefs's configuration defines. This does change what is being
tested a bit, but hopefully that's not a real issue.

Suggested by tim-nordell-nimbelink
2020-12-14 23:50:39 -06:00
Christopher Haster
fe42d102a5 Added make build as an alias for make all 2020-11-28 20:11:36 -06:00
Christopher Haster
499083765c Renamed cache_size -> buffer_size
This makes littlefs's usage of the term "cache" an entirely internal
concept and hopefully avoids some confusion about the usefulness of
throwing RAM > block_size at these buffers.

The term cache isn't entirely inaccurate, these buffers do act as
single-line caches, however more often the term cache is used to
describe multi-line caches. Maybe this will be added in littlefs's
future, but the code-size cost makes this change not worth the overhead
at the moment.
2020-11-28 20:11:36 -06:00
Christopher Haster
aa46bb68ca Made it easier to debug generated test files
Added internal lineno tracking of generated test files so that test.py
can reset the generated #line directives after a test case. This helps
debug issues with the generated glue code itself, which would previously
end up with invalid/unhelpful lineno information in error messages.

Also changed suffix from .c.t to .tc
2020-11-28 20:11:36 -06:00
Christopher Haster
190eb833a2 Changed bd callbacks to use "bd_" prefix
This makes the block-device related operations more clearly block-device
related operations, and helps avoid possible conflicts with user
provided `lfs_bd_read/prog/erase` functions in the LFS_STATICCFG mode.
2020-11-28 20:11:36 -06:00
Christopher Haster
30ed816feb Standardized on externally provided config structs in the block devices
I have another branch where I tried exploring inlined config structs
backed by RAM, but this did not work out due to additional RAM and ROM costs.

Changing the bds to follow this was surprisingly annoying, as they had a
lot of shared geometry that was previously in a single shared config
object, and the way that testbd contains either of rambd and filebd made
configuring all three of these a bit complicated.

Ended up settling on a lfs_testbd_cfg that contains optional pointers to
lfs_rambd_cfg and lfs_filebd_cfg. These can be NULL, but only if that
bd goes unused.
2020-11-28 20:11:36 -06:00
Christopher Haster
a7cdd563f6 Changed callbacks to take user-provided context directly
This is a style change to make littlefs's callbacks consistent with most
callback declarations found in C. That is, taking in a user-provided
`void*`.

Previously, these callbacks took a pointer to the config struct itself,
which indirectly contained a user provided context, and this gets the
job done, but taking in a callback with a `void*` is arguably more
expected, has a better chance of integrating with C++/OS-specific code,
and is more likely to be optimized out by a clever compiler.

---

As a part of these changes, the geometry for the test bds needed to be
moved into bd specific configuration objects. This is a good change as
it also allows for testing situations where littlefs's geometry does not
match the underlying bd.
2020-11-28 20:02:18 -06:00
Christopher Haster
a549413077 Rename config structs to cfg structs
Since this is already going to be a breaking API change, this renames
structs/variables named _config -> _cfg. This is in order to be
consistent with functions such as lfs_file_opencfg.
2020-11-28 19:52:21 -06:00
Christopher Haster
3f6f88778a Added minimal build+size reporting to CI based on static config 2020-11-28 19:51:08 -06:00
Christopher Haster
c44427f9ec Exploring ideas for static configuration
As an embedded library, littlefs's configuration straddles two worlds.
In most cases the configuration is usually constant at build time, but
when integrated into OSs, the configuration needs to be dynamically
configurable.

To help with this, littlefs has a separate lfs_config struct that can be
placed into ROM when possible.

But you know what's better than ROM configuration? Truely inlinable
static configuration known at compile-time. In addition to avoiding the
RAM cost, compile-time configuration allows for additional compiler
optimizations, such as constexpr-elimination and removal of unused
code-paths.

So how to enable static configuration?

1. define LFS_STATICCFG
2. implement callbacks as global functions:
   - lfs_read
   - lfs_prog
   - lfs_erase
   - lfs_sync
2. define the now-required constants that configure littlefs:
   - LFS_READ_SIZE
   - LFS_PROG_SIZE
   - LFS_BLOCK_SIZE
   - LFS_BLOCK_COUNT
   - LFS_BLOCK_CYCLES
   - LFS_CACHE_SIZE
   - LFS_LOOKAHEAD_SIZE
   - LFS_READ_BUFFER (optional)
   - LFS_PROG_BUFFER (optional)
   - LFS_LOOKAHEAD_BUFFER (optional)
   - LFS_NAME_MAX (optional)
   - LFS_FILE_MAX (optional)
   - LFS_ATTR_MAX (optional)

Note, there is a separate configuration for the file configuration, this
can be enabled/disabled independently of LFS_STATICCFG. You will likely
want to define this as well if you are looking for the smallest code
size.

In order to avoid a mess of #ifdefs, the internals of littlefs use a
simple macro that redirects to either the dynamic or static config at
compile time:

    #ifdef LFS_STATICCFG
    #define LFS_CFG_READ_SIZE(lfs) ((void)lfs, LFS_READ_SIZE)
    #else
    #define LFS_CFG_READ_SIZE(lfs) lfs->cfg->read_size
    #endif

Unfortunately it does look like there still may be a lot of issues
related to warnings of comparisons against constants... If only C had
a way to ignore warnings on individual statements...

Original idea by apmorton
2020-11-28 19:15:24 -06:00
Christopher Haster
ef9ba2d912 A number of small lfs_util.h QOL changes
- Changed the name of the LFS_CONFIG macro to LFS_UTIL to avoid
  confusion with the lfs_config struct. This also hints that LFS_UTIL
  is related to lfs_util.h.

  LFS_UTIL allows the user to override lfs_util.h so they can provide
  their own system-level dependencies such as malloc, tracing, builtins,
  stdint definitions, string.h, and others.

- Removed stdlib includes from lfs.h, these should all go through
  lfs_util.h to let users override these definitions if stdlib is
  unavailable on their system.

- Moved error code definitions to lfs_util.h. This lets users override
  the error codes to replace them with their own error codes and avoid
  a translation layer in some situations. Note the error codes must
  still be in the range of a negative int.

- Used proper stdint definitions in lfs_scmp.
2020-11-28 18:58:10 -06:00
38 changed files with 2346 additions and 3513 deletions

View File

@@ -1,26 +0,0 @@
name: post-release
on:
release:
branches: [master]
types: [released]
jobs:
post-release:
runs-on: ubuntu-18.04
steps:
# trigger post-release in dependency repo, this indirection allows the
# dependency repo to be updated often without affecting this repo. At
# the time of this comment, the dependency repo is responsible for
# creating PRs for other dependent repos post-release.
- name: trigger-post-release
continue-on-error: true
run: |
curl -sS -X POST -H "authorization: token ${{secrets.BOT_TOKEN}}" \
"$GITHUB_API_URL/repos/${{secrets.POST_RELEASE_REPO}}/dispatches" \
-d "$(jq -n '{
event_type: "post-release",
client_payload: {
repo: env.GITHUB_REPOSITORY,
version: "${{github.event.release.tag_name}}"}}' \
| tee /dev/stderr)"

View File

@@ -1,215 +0,0 @@
name: release
on:
workflow_run:
workflows: [test]
branches: [master]
types: [completed]
jobs:
release:
runs-on: ubuntu-18.04
# need to manually check for a couple things
# - tests passed?
# - we are the most recent commit on master?
if: ${{github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.head_sha == github.sha}}
steps:
- uses: actions/checkout@v2
with:
ref: ${{github.event.workflow_run.head_sha}}
# need workflow access since we push branches
# containing workflows
token: ${{secrets.BOT_TOKEN}}
# need all tags
fetch-depth: 0
# try to get results from tests
- uses: dawidd6/action-download-artifact@v2
continue-on-error: true
with:
workflow: ${{github.event.workflow_run.name}}
run_id: ${{github.event.workflow_run.id}}
name: results
path: results
- name: find-version
run: |
# rip version from lfs.h
LFS_VERSION="$(grep -o '^#define LFS_VERSION .*$' lfs.h \
| awk '{print $3}')"
LFS_VERSION_MAJOR="$((0xffff & ($LFS_VERSION >> 16)))"
LFS_VERSION_MINOR="$((0xffff & ($LFS_VERSION >> 0)))"
# find a new patch version based on what we find in our tags
LFS_VERSION_PATCH="$( \
( git describe --tags --abbrev=0 \
--match="v$LFS_VERSION_MAJOR.$LFS_VERSION_MINOR.*" \
|| echo 'v0.0.-1' ) \
| awk -F '.' '{print $3+1}')"
# found new version
LFS_VERSION="v$LFS_VERSION_MAJOR`
`.$LFS_VERSION_MINOR`
`.$LFS_VERSION_PATCH"
echo "LFS_VERSION=$LFS_VERSION"
echo "LFS_VERSION=$LFS_VERSION" >> $GITHUB_ENV
echo "LFS_VERSION_MAJOR=$LFS_VERSION_MAJOR" >> $GITHUB_ENV
echo "LFS_VERSION_MINOR=$LFS_VERSION_MINOR" >> $GITHUB_ENV
echo "LFS_VERSION_PATCH=$LFS_VERSION_PATCH" >> $GITHUB_ENV
# try to find previous version?
- name: find-prev-version
continue-on-error: true
run: |
LFS_PREV_VERSION="$(git describe --tags --abbrev=0 --match 'v*')"
echo "LFS_PREV_VERSION=$LFS_PREV_VERSION"
echo "LFS_PREV_VERSION=$LFS_PREV_VERSION" >> $GITHUB_ENV
# try to find results from tests
- name: collect-results
run: |
# previous results to compare against?
[ -n "$LFS_PREV_VERSION" ] && curl -sS \
"$GITHUB_API_URL/repos/$GITHUB_REPOSITORY/`
`status/$LFS_PREV_VERSION" \
| jq -re 'select(.sha != env.GITHUB_SHA) | .statuses[]' \
>> prev-results.json \
|| true
# unfortunately these each have their own format
[ -e results/code-thumb.csv ] && ( \
export PREV="$(jq -re '
select(.context == "results / code").description
| capture("Code size is (?<result>[0-9]+)").result' \
prev-results.json || echo 0)"
./scripts/code.py -u results/code-thumb.csv -s | awk '
NR==2 {printf "Code size,%d B",$2}
NR==2 && ENVIRON["PREV"]+0 != 0 {
printf " (%+.1f%%)",100*($2-ENVIRON["PREV"])/ENVIRON["PREV"]}
NR==2 {printf "\n"}' \
>> results.csv)
[ -e results/code-thumb-readonly.csv ] && ( \
export PREV="$(jq -re '
select(.context == "results / code (readonly)").description
| capture("Code size is (?<result>[0-9]+)").result' \
prev-results.json || echo 0)"
./scripts/code.py -u results/code-thumb-readonly.csv -s | awk '
NR==2 {printf "Code size<br/>(readonly),%d B",$2}
NR==2 && ENVIRON["PREV"]+0 != 0 {
printf " (%+.1f%%)",100*($2-ENVIRON["PREV"])/ENVIRON["PREV"]}
NR==2 {printf "\n"}' \
>> results.csv)
[ -e results/code-thumb-threadsafe.csv ] && ( \
export PREV="$(jq -re '
select(.context == "results / code (threadsafe)").description
| capture("Code size is (?<result>[0-9]+)").result' \
prev-results.json || echo 0)"
./scripts/code.py -u results/code-thumb-threadsafe.csv -s | awk '
NR==2 {printf "Code size<br/>(threadsafe),%d B",$2}
NR==2 && ENVIRON["PREV"]+0 != 0 {
printf " (%+.1f%%)",100*($2-ENVIRON["PREV"])/ENVIRON["PREV"]}
NR==2 {printf "\n"}' \
>> results.csv)
[ -e results/code-thumb-migrate.csv ] && ( \
export PREV="$(jq -re '
select(.context == "results / code (migrate)").description
| capture("Code size is (?<result>[0-9]+)").result' \
prev-results.json || echo 0)"
./scripts/code.py -u results/code-thumb-migrate.csv -s | awk '
NR==2 {printf "Code size<br/>(migrate),%d B",$2}
NR==2 && ENVIRON["PREV"]+0 != 0 {
printf " (%+.1f%%)",100*($2-ENVIRON["PREV"])/ENVIRON["PREV"]}
NR==2 {printf "\n"}' \
>> results.csv)
[ -e results/code-thumb-error-asserts.csv ] && ( \
export PREV="$(jq -re '
select(.context == "results / code (error-asserts)").description
| capture("Code size is (?<result>[0-9]+)").result' \
prev-results.json || echo 0)"
./scripts/code.py -u results/code-thumb-error-asserts.csv -s | awk '
NR==2 {printf "Code size<br/>(error-asserts),%d B",$2}
NR==2 && ENVIRON["PREV"]+0 != 0 {
printf " (%+.1f%%)",100*($2-ENVIRON["PREV"])/ENVIRON["PREV"]}
NR==2 {printf "\n"}' \
>> results.csv)
[ -e results/coverage.csv ] && ( \
export PREV="$(jq -re '
select(.context == "results / coverage").description
| capture("Coverage is (?<result>[0-9\\.]+)").result' \
prev-results.json || echo 0)"
./scripts/coverage.py -u results/coverage.csv -s | awk -F '[ /%]+' '
NR==2 {printf "Coverage,%.1f%% of %d lines",$4,$3}
NR==2 && ENVIRON["PREV"]+0 != 0 {
printf " (%+.1f%%)",$4-ENVIRON["PREV"]}
NR==2 {printf "\n"}' \
>> results.csv)
# transpose to GitHub table
[ -e results.csv ] || exit 0
awk -F ',' '
{label[NR]=$1; value[NR]=$2}
END {
for (r=1; r<=NR; r++) {printf "| %s ",label[r]}; printf "|\n";
for (r=1; r<=NR; r++) {printf "|:--"}; printf "|\n";
for (r=1; r<=NR; r++) {printf "| %s ",value[r]}; printf "|\n"}' \
results.csv > results.txt
echo "RESULTS:"
cat results.txt
# find changes from history
- name: collect-changes
run: |
[ -n "$LFS_PREV_VERSION" ] || exit 0
# use explicit link to github commit so that release notes can
# be copied elsewhere
git log "$LFS_PREV_VERSION.." \
--grep='^Merge' --invert-grep \
--format="format:[\`%h\`](`
`https://github.com/$GITHUB_REPOSITORY/commit/%h) %s" \
> changes.txt
echo "CHANGES:"
cat changes.txt
# create and update major branches (vN and vN-prefix)
- name: create-major-branches
run: |
# create major branch
git branch "v$LFS_VERSION_MAJOR" HEAD
# create major prefix branch
git config user.name ${{secrets.BOT_USER}}
git config user.email ${{secrets.BOT_EMAIL}}
git fetch "https://github.com/$GITHUB_REPOSITORY.git" \
"v$LFS_VERSION_MAJOR-prefix" || true
./scripts/prefix.py "lfs$LFS_VERSION_MAJOR"
git branch "v$LFS_VERSION_MAJOR-prefix" $( \
git commit-tree $(git write-tree) \
$(git rev-parse --verify -q FETCH_HEAD | sed -e 's/^/-p /') \
-p HEAD \
-m "Generated v$LFS_VERSION_MAJOR prefixes")
git reset --hard
# push!
git push --atomic origin \
"v$LFS_VERSION_MAJOR" \
"v$LFS_VERSION_MAJOR-prefix"
# build release notes
- name: create-release
run: |
# create release and patch version tag (vN.N.N)
# only draft if not a patch release
[ -e results.txt ] && export RESULTS="$(cat results.txt)"
[ -e changes.txt ] && export CHANGES="$(cat changes.txt)"
curl -sS -X POST -H "authorization: token ${{secrets.BOT_TOKEN}}" \
"$GITHUB_API_URL/repos/$GITHUB_REPOSITORY/releases" \
-d "$(jq -n '{
tag_name: env.LFS_VERSION,
name: env.LFS_VERSION | rtrimstr(".0"),
target_commitish: "${{github.event.workflow_run.head_sha}}",
draft: env.LFS_VERSION | endswith(".0"),
body: [env.RESULTS, env.CHANGES | select(.)] | join("\n\n")}' \
| tee /dev/stderr)"

View File

@@ -1,55 +0,0 @@
name: status
on:
workflow_run:
workflows: [test]
types: [completed]
jobs:
status:
runs-on: ubuntu-18.04
steps:
# custom statuses?
- uses: dawidd6/action-download-artifact@v2
continue-on-error: true
with:
workflow: ${{github.event.workflow_run.name}}
run_id: ${{github.event.workflow_run.id}}
name: status
path: status
- name: update-status
continue-on-error: true
run: |
ls status
for s in $(shopt -s nullglob ; echo status/*.json)
do
# parse requested status
export STATE="$(jq -er '.state' $s)"
export CONTEXT="$(jq -er '.context' $s)"
export DESCRIPTION="$(jq -er '.description' $s)"
# help lookup URL for job/steps because GitHub makes
# it VERY HARD to link to specific jobs
export TARGET_URL="$(
jq -er '.target_url // empty' $s || (
export TARGET_JOB="$(jq -er '.target_job' $s)"
export TARGET_STEP="$(jq -er '.target_step // ""' $s)"
curl -sS -H "authorization: token ${{secrets.BOT_TOKEN}}" \
"$GITHUB_API_URL/repos/$GITHUB_REPOSITORY/actions/runs/`
`${{github.event.workflow_run.id}}/jobs" \
| jq -er '.jobs[]
| select(.name == env.TARGET_JOB)
| .html_url
+ "?check_suite_focus=true"
+ ((.steps[]
| select(.name == env.TARGET_STEP)
| "#step:\(.number):0") // "")'))"
# update status
curl -sS -X POST -H "authorization: token ${{secrets.BOT_TOKEN}}" \
"$GITHUB_API_URL/repos/$GITHUB_REPOSITORY/statuses/`
`${{github.event.workflow_run.head_sha}}" \
-d "$(jq -n '{
state: env.STATE,
context: env.CONTEXT,
description: env.DESCRIPTION,
target_url: env.TARGET_URL}' \
| tee /dev/stderr)"
done

View File

@@ -1,446 +0,0 @@
name: test
on: [push, pull_request]
env:
CFLAGS: -Werror
MAKEFLAGS: -j
jobs:
# run tests
test:
runs-on: ubuntu-18.04
strategy:
fail-fast: false
matrix:
arch: [x86_64, thumb, mips, powerpc]
steps:
- uses: actions/checkout@v2
- name: install
run: |
# need toml, also pip3 isn't installed by default?
sudo apt-get update -qq
sudo apt-get install -qq python3 python3-pip lcov
sudo pip3 install toml
gcc --version
# setup a ram-backed disk to speed up reentrant tests
mkdir disks
sudo mount -t tmpfs -o size=100m tmpfs disks
TESTFLAGS="$TESTFLAGS --disk=disks/disk"
# collect coverage
mkdir -p coverage
TESTFLAGS="$TESTFLAGS --coverage=`
`coverage/${{github.job}}-${{matrix.arch}}.info"
echo "TESTFLAGS=$TESTFLAGS" >> $GITHUB_ENV
# cross-compile with ARM Thumb (32-bit, little-endian)
- name: install-thumb
if: ${{matrix.arch == 'thumb'}}
run: |
sudo apt-get install -qq \
gcc-arm-linux-gnueabi \
libc6-dev-armel-cross \
qemu-user
echo "CC=arm-linux-gnueabi-gcc -mthumb --static" >> $GITHUB_ENV
echo "EXEC=qemu-arm" >> $GITHUB_ENV
arm-linux-gnueabi-gcc --version
qemu-arm -version
# cross-compile with MIPS (32-bit, big-endian)
- name: install-mips
if: ${{matrix.arch == 'mips'}}
run: |
sudo apt-get install -qq \
gcc-mips-linux-gnu \
libc6-dev-mips-cross \
qemu-user
echo "CC=mips-linux-gnu-gcc --static" >> $GITHUB_ENV
echo "EXEC=qemu-mips" >> $GITHUB_ENV
mips-linux-gnu-gcc --version
qemu-mips -version
# cross-compile with PowerPC (32-bit, big-endian)
- name: install-powerpc
if: ${{matrix.arch == 'powerpc'}}
run: |
sudo apt-get install -qq \
gcc-powerpc-linux-gnu \
libc6-dev-powerpc-cross \
qemu-user
echo "CC=powerpc-linux-gnu-gcc --static" >> $GITHUB_ENV
echo "EXEC=qemu-ppc" >> $GITHUB_ENV
powerpc-linux-gnu-gcc --version
qemu-ppc -version
# make sure example can at least compile
- name: test-example
run: |
sed -n '/``` c/,/```/{/```/d; p}' README.md > test.c
make all CFLAGS+=" \
-Duser_provided_block_device_read=NULL \
-Duser_provided_block_device_prog=NULL \
-Duser_provided_block_device_erase=NULL \
-Duser_provided_block_device_sync=NULL \
-include stdio.h"
rm test.c
# test configurations
# normal+reentrant tests
- name: test-default
run: |
make clean
make test TESTFLAGS+="-nrk"
# NOR flash: read/prog = 1 block = 4KiB
- name: test-nor
run: |
make clean
make test TESTFLAGS+="-nrk \
-DLFS_READ_SIZE=1 -DLFS_BLOCK_SIZE=4096"
# SD/eMMC: read/prog = 512 block = 512
- name: test-emmc
run: |
make clean
make test TESTFLAGS+="-nrk \
-DLFS_READ_SIZE=512 -DLFS_BLOCK_SIZE=512"
# NAND flash: read/prog = 4KiB block = 32KiB
- name: test-nand
run: |
make clean
make test TESTFLAGS+="-nrk \
-DLFS_READ_SIZE=4096 -DLFS_BLOCK_SIZE=\(32*1024\)"
# other extreme geometries that are useful for various corner cases
- name: test-no-intrinsics
run: |
make clean
make test TESTFLAGS+="-nrk \
-DLFS_NO_INTRINSICS"
- name: test-byte-writes
# it just takes too long to test byte-level writes when in qemu,
# should be plenty covered by the other configurations
if: ${{matrix.arch == 'x86_64'}}
run: |
make clean
make test TESTFLAGS+="-nrk \
-DLFS_READ_SIZE=1 -DLFS_CACHE_SIZE=1"
- name: test-block-cycles
run: |
make clean
make test TESTFLAGS+="-nrk \
-DLFS_BLOCK_CYCLES=1"
- name: test-odd-block-count
run: |
make clean
make test TESTFLAGS+="-nrk \
-DLFS_BLOCK_COUNT=1023 -DLFS_LOOKAHEAD_SIZE=256"
- name: test-odd-block-size
run: |
make clean
make test TESTFLAGS+="-nrk \
-DLFS_READ_SIZE=11 -DLFS_BLOCK_SIZE=704"
# upload coverage for later coverage
- name: upload-coverage
uses: actions/upload-artifact@v2
with:
name: coverage
path: coverage
retention-days: 1
# update results
- name: results-code
run: |
mkdir -p results
make clean
make code \
CFLAGS+=" \
-DLFS_NO_ASSERT \
-DLFS_NO_DEBUG \
-DLFS_NO_WARN \
-DLFS_NO_ERROR" \
CODEFLAGS+="-o results/code-${{matrix.arch}}.csv"
- name: results-code-readonly
run: |
mkdir -p results
make clean
make code \
CFLAGS+=" \
-DLFS_NO_ASSERT \
-DLFS_NO_DEBUG \
-DLFS_NO_WARN \
-DLFS_NO_ERROR \
-DLFS_READONLY" \
CODEFLAGS+="-o results/code-${{matrix.arch}}-readonly.csv"
- name: results-code-threadsafe
run: |
mkdir -p results
make clean
make code \
CFLAGS+=" \
-DLFS_NO_ASSERT \
-DLFS_NO_DEBUG \
-DLFS_NO_WARN \
-DLFS_NO_ERROR \
-DLFS_THREADSAFE" \
CODEFLAGS+="-o results/code-${{matrix.arch}}-threadsafe.csv"
- name: results-code-migrate
run: |
mkdir -p results
make clean
make code \
CFLAGS+=" \
-DLFS_NO_ASSERT \
-DLFS_NO_DEBUG \
-DLFS_NO_WARN \
-DLFS_NO_ERROR \
-DLFS_MIGRATE" \
CODEFLAGS+="-o results/code-${{matrix.arch}}-migrate.csv"
- name: results-code-error-asserts
run: |
mkdir -p results
make clean
make code \
CFLAGS+=" \
-DLFS_NO_DEBUG \
-DLFS_NO_WARN \
-DLFS_NO_ERROR \
-D'LFS_ASSERT(test)=do {if(!(test)) {return -1;}} while(0)'" \
CODEFLAGS+="-o results/code-${{matrix.arch}}-error-asserts.csv"
- name: upload-results
uses: actions/upload-artifact@v2
with:
name: results
path: results
# limit reporting to Thumb, otherwise there would be too many numbers
# flying around for the results to be easily readable
- name: collect-status
if: ${{matrix.arch == 'thumb'}}
run: |
mkdir -p status
for f in $(shopt -s nullglob ; echo results/code*.csv)
do
export STEP="results-code$(
echo $f | sed -n 's/.*code-.*-\(.*\).csv/-\1/p')"
export CONTEXT="results / code$(
echo $f | sed -n 's/.*code-.*-\(.*\).csv/ (\1)/p')"
export PREV="$(curl -sS \
"$GITHUB_API_URL/repos/$GITHUB_REPOSITORY/status/master" \
| jq -re 'select(.sha != env.GITHUB_SHA) | .statuses[]
| select(.context == env.CONTEXT).description
| capture("Code size is (?<result>[0-9]+)").result' \
|| echo 0)"
export DESCRIPTION="$(./scripts/code.py -u $f -s | awk '
NR==2 {printf "Code size is %d B",$2}
NR==2 && ENVIRON["PREV"]+0 != 0 {
printf " (%+.1f%%)",100*($2-ENVIRON["PREV"])/ENVIRON["PREV"]}')"
jq -n '{
state: "success",
context: env.CONTEXT,
description: env.DESCRIPTION,
target_job: "${{github.job}} (${{matrix.arch}})",
target_step: env.STEP}' \
| tee status/code$(
echo $f | sed -n 's/.*code-.*-\(.*\).csv/-\1/p').json
done
- name: upload-status
if: ${{matrix.arch == 'thumb'}}
uses: actions/upload-artifact@v2
with:
name: status
path: status
retention-days: 1
# run under Valgrind to check for memory errors
valgrind:
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
- name: install
run: |
# need toml, also pip3 isn't installed by default?
sudo apt-get update -qq
sudo apt-get install -qq python3 python3-pip
sudo pip3 install toml
- name: install-valgrind
run: |
sudo apt-get update -qq
sudo apt-get install -qq valgrind
valgrind --version
# normal tests, we don't need to test all geometries
- name: test-valgrind
run: make test TESTFLAGS+="-k --valgrind"
# self-host with littlefs-fuse for a fuzz-like test
fuse:
runs-on: ubuntu-18.04
if: ${{!endsWith(github.ref, '-prefix')}}
steps:
- uses: actions/checkout@v2
- name: install
run: |
# need toml, also pip3 isn't installed by default?
sudo apt-get update -qq
sudo apt-get install -qq python3 python3-pip libfuse-dev
sudo pip3 install toml
fusermount -V
gcc --version
- uses: actions/checkout@v2
with:
repository: littlefs-project/littlefs-fuse
ref: v2
path: littlefs-fuse
- name: setup
run: |
# copy our new version into littlefs-fuse
rm -rf littlefs-fuse/littlefs/*
cp -r $(git ls-tree --name-only HEAD) littlefs-fuse/littlefs
# setup disk for littlefs-fuse
mkdir mount
sudo chmod a+rw /dev/loop0
dd if=/dev/zero bs=512 count=128K of=disk
losetup /dev/loop0 disk
- name: test
run: |
# self-host test
make -C littlefs-fuse
littlefs-fuse/lfs --format /dev/loop0
littlefs-fuse/lfs /dev/loop0 mount
ls mount
mkdir mount/littlefs
cp -r $(git ls-tree --name-only HEAD) mount/littlefs
cd mount/littlefs
stat .
ls -flh
make -B test
# test migration using littlefs-fuse
migrate:
runs-on: ubuntu-18.04
if: ${{!endsWith(github.ref, '-prefix')}}
steps:
- uses: actions/checkout@v2
- name: install
run: |
# need toml, also pip3 isn't installed by default?
sudo apt-get update -qq
sudo apt-get install -qq python3 python3-pip libfuse-dev
sudo pip3 install toml
fusermount -V
gcc --version
- uses: actions/checkout@v2
with:
repository: littlefs-project/littlefs-fuse
ref: v2
path: v2
- uses: actions/checkout@v2
with:
repository: littlefs-project/littlefs-fuse
ref: v1
path: v1
- name: setup
run: |
# copy our new version into littlefs-fuse
rm -rf v2/littlefs/*
cp -r $(git ls-tree --name-only HEAD) v2/littlefs
# setup disk for littlefs-fuse
mkdir mount
sudo chmod a+rw /dev/loop0
dd if=/dev/zero bs=512 count=128K of=disk
losetup /dev/loop0 disk
- name: test
run: |
# compile v1 and v2
make -C v1
make -C v2
# run self-host test with v1
v1/lfs --format /dev/loop0
v1/lfs /dev/loop0 mount
ls mount
mkdir mount/littlefs
cp -r $(git ls-tree --name-only HEAD) mount/littlefs
cd mount/littlefs
stat .
ls -flh
make -B test
# attempt to migrate
cd ../..
fusermount -u mount
v2/lfs --migrate /dev/loop0
v2/lfs /dev/loop0 mount
# run self-host test with v2 right where we left off
ls mount
cd mount/littlefs
stat .
ls -flh
make -B test
# collect coverage info
coverage:
runs-on: ubuntu-18.04
needs: [test]
steps:
- uses: actions/checkout@v2
- name: install
run: |
sudo apt-get update -qq
sudo apt-get install -qq python3 python3-pip lcov
sudo pip3 install toml
# yes we continue-on-error nearly every step, continue-on-error
# at job level apparently still marks a job as failed, which isn't
# what we want
- uses: actions/download-artifact@v2
continue-on-error: true
with:
name: coverage
path: coverage
- name: results-coverage
continue-on-error: true
run: |
mkdir -p results
lcov $(for f in coverage/*.info ; do echo "-a $f" ; done) \
-o results/coverage.info
./scripts/coverage.py results/coverage.info -o results/coverage.csv
- name: upload-results
uses: actions/upload-artifact@v2
with:
name: results
path: results
- name: collect-status
run: |
mkdir -p status
[ -e results/coverage.csv ] || exit 0
export STEP="results-coverage"
export CONTEXT="results / coverage"
export PREV="$(curl -sS \
"$GITHUB_API_URL/repos/$GITHUB_REPOSITORY/status/master" \
| jq -re 'select(.sha != env.GITHUB_SHA) | .statuses[]
| select(.context == env.CONTEXT).description
| capture("Coverage is (?<result>[0-9\\.]+)").result' \
|| echo 0)"
export DESCRIPTION="$(
./scripts/coverage.py -u results/coverage.csv -s | awk -F '[ /%]+' '
NR==2 {printf "Coverage is %.1f%% of %d lines",$4,$3}
NR==2 && ENVIRON["PREV"]+0 != 0 {
printf " (%+.1f%%)",$4-ENVIRON["PREV"]}')"
jq -n '{
state: "success",
context: env.CONTEXT,
description: env.DESCRIPTION,
target_job: "${{github.job}}",
target_step: env.STEP}' \
| tee status/coverage.json
- name: upload-status
uses: actions/upload-artifact@v2
with:
name: status
path: status
retention-days: 1

460
.travis.yml Normal file
View File

@@ -0,0 +1,460 @@
# environment variables
env:
global:
- CFLAGS=-Werror
- MAKEFLAGS=-j
# cache installation dirs
cache:
pip: true
directories:
- $HOME/.cache/apt
# common installation
_: &install-common
# need toml, also pip3 isn't installed by default?
- sudo apt-get install python3 python3-pip
- sudo pip3 install toml
# setup a ram-backed disk to speed up reentrant tests
- mkdir disks
- sudo mount -t tmpfs -o size=100m tmpfs disks
- export TFLAGS="$TFLAGS --disk=disks/disk"
# test cases
_: &test-example
# make sure example can at least compile
- sed -n '/``` c/,/```/{/```/d; p}' README.md > test.c &&
make all CFLAGS+="
-Duser_provided_block_device_read=NULL
-Duser_provided_block_device_prog=NULL
-Duser_provided_block_device_erase=NULL
-Duser_provided_block_device_sync=NULL
-include stdio.h"
# default tests
_: &test-default
# normal+reentrant tests
- make test TFLAGS+="-nrk"
# common real-life geometries
_: &test-nor
# NOR flash: read/prog = 1 block = 4KiB
- make test TFLAGS+="-nrk -DLFS_READ_SIZE=1 -DLFS_BLOCK_SIZE=4096"
_: &test-emmc
# eMMC: read/prog = 512 block = 512
- make test TFLAGS+="-nrk -DLFS_READ_SIZE=512 -DLFS_BLOCK_SIZE=512"
_: &test-nand
# NAND flash: read/prog = 4KiB block = 32KiB
- make test TFLAGS+="-nrk -DLFS_READ_SIZE=4096 -DLFS_BLOCK_SIZE=\(32*1024\)"
# other extreme geometries that are useful for testing various corner cases
_: &test-no-intrinsics
- make test TFLAGS+="-nrk -DLFS_NO_INTRINSICS"
_: &test-no-inline
- make test TFLAGS+="-nrk -DLFS_INLINE_MAX=0"
_: &test-byte-writes
- make test TFLAGS+="-nrk -DLFS_READ_SIZE=1 -DLFS_BUFFER_SIZE=1"
_: &test-block-cycles
- make test TFLAGS+="-nrk -DLFS_BLOCK_CYCLES=1"
_: &test-odd-block-count
- make test TFLAGS+="-nrk -DLFS_BLOCK_COUNT=1023 -DLFS_LOOKAHEAD_SIZE=256"
_: &test-odd-block-size
- make test TFLAGS+="-nrk -DLFS_READ_SIZE=11 -DLFS_BLOCK_SIZE=704"
# report size
_: &report-size
# compile and find the code size with the smallest configuration
- make -j1 clean size
OBJ="$(ls lfs*.c | sed 's/\.c/\.o/' | tr '\n' ' ')"
CFLAGS+="-DLFS_NO_ASSERT -DLFS_NO_DEBUG -DLFS_NO_WARN -DLFS_NO_ERROR"
| tee sizes
# update status if we succeeded, compare with master if possible
- |
if [ "$TRAVIS_TEST_RESULT" -eq 0 ]
then
CURR=$(tail -n1 sizes | awk '{print $1}')
PREV=$(curl -u "$GEKY_BOT_STATUSES" https://api.github.com/repos/$TRAVIS_REPO_SLUG/status/master \
| jq -re "select(.sha != \"$TRAVIS_COMMIT\")
| .statuses[] | select(.context == \"${TRAVIS_BUILD_STAGE_NAME,,}/$NAME\").description
| capture(\"code size is (?<size>[0-9]+)\").size" \
|| echo 0)
STATUS="Passed, code size is ${CURR}B"
if [ "$PREV" -ne 0 ]
then
STATUS="$STATUS ($(python -c "print '%+.2f' % (100*($CURR-$PREV)/$PREV.0)")%)"
fi
fi
# stage control
stages:
- name: test
- name: deploy
if: branch = master AND type = push
# job control
jobs:
# native testing
- &x86
stage: test
env:
- NAME=littlefs-x86
install: *install-common
script: [*test-example, *report-size]
- {<<: *x86, script: [*test-default, *report-size]}
- {<<: *x86, script: [*test-nor, *report-size]}
- {<<: *x86, script: [*test-emmc, *report-size]}
- {<<: *x86, script: [*test-nand, *report-size]}
- {<<: *x86, script: [*test-no-intrinsics, *report-size]}
- {<<: *x86, script: [*test-no-inline, *report-size]}
- {<<: *x86, script: [*test-byte-writes, *report-size]}
- {<<: *x86, script: [*test-block-cycles, *report-size]}
- {<<: *x86, script: [*test-odd-block-count, *report-size]}
- {<<: *x86, script: [*test-odd-block-size, *report-size]}
# cross-compile with ARM (thumb mode)
- &arm
stage: test
env:
- NAME=littlefs-arm
- CC="arm-linux-gnueabi-gcc --static -mthumb"
- TFLAGS="$TFLAGS --exec=qemu-arm"
install:
- *install-common
- sudo apt-get install
gcc-arm-linux-gnueabi
libc6-dev-armel-cross
qemu-user
- arm-linux-gnueabi-gcc --version
- qemu-arm -version
script: [*test-example, *report-size]
- {<<: *arm, script: [*test-default, *report-size]}
- {<<: *arm, script: [*test-nor, *report-size]}
- {<<: *arm, script: [*test-emmc, *report-size]}
- {<<: *arm, script: [*test-nand, *report-size]}
- {<<: *arm, script: [*test-no-intrinsics, *report-size]}
- {<<: *arm, script: [*test-no-inline, *report-size]}
# it just takes way to long to run byte-level writes in qemu,
# note this is still tested in the native tests
#- {<<: *arm, script: [*test-byte-writes, *report-size]}
- {<<: *arm, script: [*test-block-cycles, *report-size]}
- {<<: *arm, script: [*test-odd-block-count, *report-size]}
- {<<: *arm, script: [*test-odd-block-size, *report-size]}
# cross-compile with MIPS
- &mips
stage: test
env:
- NAME=littlefs-mips
- CC="mips-linux-gnu-gcc --static"
- TFLAGS="$TFLAGS --exec=qemu-mips"
install:
- *install-common
- sudo apt-get install
gcc-mips-linux-gnu
libc6-dev-mips-cross
qemu-user
- mips-linux-gnu-gcc --version
- qemu-mips -version
script: [*test-example, *report-size]
- {<<: *mips, script: [*test-default, *report-size]}
- {<<: *mips, script: [*test-nor, *report-size]}
- {<<: *mips, script: [*test-emmc, *report-size]}
- {<<: *mips, script: [*test-nand, *report-size]}
- {<<: *mips, script: [*test-no-intrinsics, *report-size]}
- {<<: *mips, script: [*test-no-inline, *report-size]}
# it just takes way to long to run byte-level writes in qemu,
# note this is still tested in the native tests
#- {<<: *mips, script: [*test-byte-writes, *report-size]}
- {<<: *mips, script: [*test-block-cycles, *report-size]}
- {<<: *mips, script: [*test-odd-block-count, *report-size]}
- {<<: *mips, script: [*test-odd-block-size, *report-size]}
# cross-compile with PowerPC
- &powerpc
stage: test
env:
- NAME=littlefs-powerpc
- CC="powerpc-linux-gnu-gcc --static"
- TFLAGS="$TFLAGS --exec=qemu-ppc"
install:
- *install-common
- sudo apt-get install
gcc-powerpc-linux-gnu
libc6-dev-powerpc-cross
qemu-user
- powerpc-linux-gnu-gcc --version
- qemu-ppc -version
script: [*test-example, *report-size]
- {<<: *powerpc, script: [*test-default, *report-size]}
- {<<: *powerpc, script: [*test-nor, *report-size]}
- {<<: *powerpc, script: [*test-emmc, *report-size]}
- {<<: *powerpc, script: [*test-nand, *report-size]}
- {<<: *powerpc, script: [*test-no-intrinsics, *report-size]}
- {<<: *powerpc, script: [*test-no-inline, *report-size]}
# it just takes way to long to run byte-level writes in qemu,
# note this is still tested in the native tests
#- {<<: *powerpc, script: [*test-byte-writes, *report-size]}
- {<<: *powerpc, script: [*test-block-cycles, *report-size]}
- {<<: *powerpc, script: [*test-odd-block-count, *report-size]}
- {<<: *powerpc, script: [*test-odd-block-size, *report-size]}
# test under valgrind, checking for memory errors
- &valgrind
stage: test
env:
- NAME=littlefs-valgrind
install:
- *install-common
- sudo apt-get install valgrind
- valgrind --version
script:
- make test TFLAGS+="-k --valgrind"
# test minimal compilation using static configs
- stage: test
env:
- NAME=littlefs-minimal
- CC="arm-linux-gnueabi-gcc --static -mthumb"
- CFLAGS="-Werror
-DLFS_BD_READ
-DLFS_BD_PROG
-DLFS_BD_ERASE
-DLFS_BD_SYNC
-DLFS_READ_SIZE=16
-DLFS_PROG_SIZE=16
-DLFS_BLOCK_SIZE=512
-DLFS_BLOCK_COUNT=1024
-DLFS_BLOCK_CYCLES=1024
-DLFS_BUFFER_SIZE=64
-DLFS_LOOKAHEAD_SIZE=16
-DLFS_NAME_LIMIT=0
-DLFS_FILE_LIMIT=0
-DLFS_ATTR_LIMIT=0
-DLFS_NO_ASSERT -DLFS_NO_DEBUG -DLFS_NO_WARN -DLFS_NO_ERROR"
if: branch !~ -prefix$
install:
- *install-common
- sudo apt-get install
gcc-arm-linux-gnueabi
libc6-dev-armel-cross
- arm-linux-gnueabi-gcc --version
# report-size will compile littlefs and report the size
script: [*report-size]
# self-host with littlefs-fuse for fuzz test
- stage: test
env:
- NAME=littlefs-fuse
if: branch !~ -prefix$
install:
- *install-common
- sudo apt-get install libfuse-dev
- git clone --depth 1 https://github.com/geky/littlefs-fuse -b v2
- fusermount -V
- gcc --version
# setup disk for littlefs-fuse
- rm -rf littlefs-fuse/littlefs/*
- cp -r $(git ls-tree --name-only HEAD) littlefs-fuse/littlefs
- mkdir mount
- sudo chmod a+rw /dev/loop0
- dd if=/dev/zero bs=512 count=128K of=disk
- losetup /dev/loop0 disk
script:
# self-host test
- make -C littlefs-fuse
- littlefs-fuse/lfs --format /dev/loop0
- littlefs-fuse/lfs /dev/loop0 mount
- ls mount
- mkdir mount/littlefs
- cp -r $(git ls-tree --name-only HEAD) mount/littlefs
- cd mount/littlefs
- stat .
- ls -flh
- make -B test
# test migration using littlefs-fuse
- stage: test
env:
- NAME=littlefs-migration
if: branch !~ -prefix$
install:
- *install-common
- sudo apt-get install libfuse-dev
- git clone --depth 1 https://github.com/geky/littlefs-fuse -b v2 v2
- git clone --depth 1 https://github.com/geky/littlefs-fuse -b v1 v1
- fusermount -V
- gcc --version
# setup disk for littlefs-fuse
- rm -rf v2/littlefs/*
- cp -r $(git ls-tree --name-only HEAD) v2/littlefs
- mkdir mount
- sudo chmod a+rw /dev/loop0
- dd if=/dev/zero bs=512 count=128K of=disk
- losetup /dev/loop0 disk
script:
# compile v1 and v2
- make -C v1
- make -C v2
# run self-host test with v1
- v1/lfs --format /dev/loop0
- v1/lfs /dev/loop0 mount
- ls mount
- mkdir mount/littlefs
- cp -r $(git ls-tree --name-only HEAD) mount/littlefs
- cd mount/littlefs
- stat .
- ls -flh
- make -B test
# attempt to migrate
- cd ../..
- fusermount -u mount
- v2/lfs --migrate /dev/loop0
- v2/lfs /dev/loop0 mount
# run self-host test with v2 right where we left off
- ls mount
- cd mount/littlefs
- stat .
- ls -flh
- make -B test
# automatically create releases
- stage: deploy
env:
- NAME=deploy
script:
- |
bash << 'SCRIPT'
set -ev
# Find version defined in lfs.h
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, 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"
# Check that we're the most recent commit
CURRENT_COMMIT=$(curl -f -u "$GEKY_BOT_RELEASES" \
https://api.github.com/repos/$TRAVIS_REPO_SLUG/commits/master \
| jq -re '.sha')
[ "$TRAVIS_COMMIT" == "$CURRENT_COMMIT" ] || exit 0
# Create major branch
git branch v$LFS_VERSION_MAJOR HEAD
# Create major prefix branch
git config user.name "geky bot"
git config user.email "bot@geky.net"
git fetch https://github.com/$TRAVIS_REPO_SLUG.git \
--depth=50 v$LFS_VERSION_MAJOR-prefix || true
./scripts/prefix.py lfs$LFS_VERSION_MAJOR
git branch v$LFS_VERSION_MAJOR-prefix $( \
git commit-tree $(git write-tree) \
$(git rev-parse --verify -q FETCH_HEAD | sed -e 's/^/-p /') \
-p HEAD \
-m "Generated v$LFS_VERSION_MAJOR prefixes")
git reset --hard
# Update major version branches (vN and vN-prefix)
git push --atomic https://$GEKY_BOT_RELEASES@github.com/$TRAVIS_REPO_SLUG.git \
v$LFS_VERSION_MAJOR \
v$LFS_VERSION_MAJOR-prefix
# Build release notes
PREV=$(git tag --sort=-v:refname -l "v*" | head -1)
if [ ! -z "$PREV" ]
then
echo "PREV $PREV"
CHANGES=$(git log --oneline $PREV.. --grep='^Merge' --invert-grep)
printf "CHANGES\n%s\n\n" "$CHANGES"
fi
case ${GEKY_BOT_DRAFT:-minor} in
true) DRAFT=true ;;
minor) DRAFT=$(jq -R 'endswith(".0")' <<< "$LFS_VERSION") ;;
false) DRAFT=false ;;
esac
# Create the release and patch version tag (vN.N.N)
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}\",
\"target_commitish\": \"$TRAVIS_COMMIT\",
\"draft\": $DRAFT,
\"body\": $(jq -sR '.' <<< "$CHANGES")
}" #"
SCRIPT
# manage statuses
before_install:
- |
# don't clobber other (not us) failures
if ! curl https://api.github.com/repos/$TRAVIS_REPO_SLUG/status/${TRAVIS_PULL_REQUEST_SHA:-$TRAVIS_COMMIT} \
| jq -e ".statuses[] | select(
.context == \"${TRAVIS_BUILD_STAGE_NAME,,}/$NAME\" and
.state == \"failure\" and
(.target_url | endswith(\"$TRAVIS_JOB_NUMBER\") | not))"
then
curl -u "$GEKY_BOT_STATUSES" -X POST \
https://api.github.com/repos/$TRAVIS_REPO_SLUG/statuses/${TRAVIS_PULL_REQUEST_SHA:-$TRAVIS_COMMIT} \
-d "{
\"context\": \"${TRAVIS_BUILD_STAGE_NAME,,}/$NAME\",
\"state\": \"pending\",
\"description\": \"${STATUS:-In progress}\",
\"target_url\": \"$TRAVIS_JOB_WEB_URL#$TRAVIS_JOB_NUMBER\"
}"
fi
after_failure:
- |
# don't clobber other (not us) failures
if ! curl https://api.github.com/repos/$TRAVIS_REPO_SLUG/status/${TRAVIS_PULL_REQUEST_SHA:-$TRAVIS_COMMIT} \
| jq -e ".statuses[] | select(
.context == \"${TRAVIS_BUILD_STAGE_NAME,,}/$NAME\" and
.state == \"failure\" and
(.target_url | endswith(\"$TRAVIS_JOB_NUMBER\") | not))"
then
curl -u "$GEKY_BOT_STATUSES" -X POST \
https://api.github.com/repos/$TRAVIS_REPO_SLUG/statuses/${TRAVIS_PULL_REQUEST_SHA:-$TRAVIS_COMMIT} \
-d "{
\"context\": \"${TRAVIS_BUILD_STAGE_NAME,,}/$NAME\",
\"state\": \"failure\",
\"description\": \"${STATUS:-Failed}\",
\"target_url\": \"$TRAVIS_JOB_WEB_URL#$TRAVIS_JOB_NUMBER\"
}"
fi
after_success:
- |
# don't clobber other (not us) failures
# only update if we were last job to mark in progress,
# this isn't perfect but is probably good enough
if ! curl https://api.github.com/repos/$TRAVIS_REPO_SLUG/status/${TRAVIS_PULL_REQUEST_SHA:-$TRAVIS_COMMIT} \
| jq -e ".statuses[] | select(
.context == \"${TRAVIS_BUILD_STAGE_NAME,,}/$NAME\" and
(.state == \"failure\" or .state == \"pending\") and
(.target_url | endswith(\"$TRAVIS_JOB_NUMBER\") | not))"
then
curl -u "$GEKY_BOT_STATUSES" -X POST \
https://api.github.com/repos/$TRAVIS_REPO_SLUG/statuses/${TRAVIS_PULL_REQUEST_SHA:-$TRAVIS_COMMIT} \
-d "{
\"context\": \"${TRAVIS_BUILD_STAGE_NAME,,}/$NAME\",
\"state\": \"success\",
\"description\": \"${STATUS:-Passed}\",
\"target_url\": \"$TRAVIS_JOB_WEB_URL#$TRAVIS_JOB_NUMBER\"
}"
fi

View File

@@ -1,4 +1,3 @@
Copyright (c) 2022, The littlefs authors.
Copyright (c) 2017, Arm Limited. All rights reserved. Copyright (c) 2017, Arm Limited. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, Redistribution and use in source and binary forms, with or without modification,

View File

@@ -1,39 +1,25 @@
ifdef BUILDDIR TARGET = lfs.a
# make sure BUILDDIR ends with a slash
override BUILDDIR := $(BUILDDIR)/
# bit of a hack, but we want to make sure BUILDDIR directory structure
# is correct before any commands
$(if $(findstring n,$(MAKEFLAGS)),, $(shell mkdir -p \
$(BUILDDIR) \
$(BUILDDIR)bd \
$(BUILDDIR)tests))
endif
# overridable target/src/tools/flags/etc
ifneq ($(wildcard test.c main.c),) ifneq ($(wildcard test.c main.c),)
TARGET ?= $(BUILDDIR)lfs override TARGET = lfs
else
TARGET ?= $(BUILDDIR)lfs.a
endif endif
CC ?= gcc CC ?= gcc
AR ?= ar AR ?= ar
SIZE ?= size SIZE ?= size
CTAGS ?= ctags
NM ?= nm
LCOV ?= lcov
SRC ?= $(wildcard *.c) SRC += $(wildcard *.c bd/*.c)
OBJ := $(SRC:%.c=$(BUILDDIR)%.o) OBJ := $(SRC:.c=.o)
DEP := $(SRC:%.c=$(BUILDDIR)%.d) DEP := $(SRC:.c=.d)
ASM := $(SRC:%.c=$(BUILDDIR)%.s) ASM := $(SRC:.c=.s)
ifdef DEBUG ifdef DEBUG
override CFLAGS += -O0 -g3 override CFLAGS += -O0 -g3
else else
override CFLAGS += -Os override CFLAGS += -Os
endif endif
ifdef WORD
override CFLAGS += -m$(WORD)
endif
ifdef TRACE ifdef TRACE
override CFLAGS += -DLFS_YES_TRACE override CFLAGS += -DLFS_YES_TRACE
endif endif
@@ -42,73 +28,40 @@ override CFLAGS += -std=c99 -Wall -pedantic
override CFLAGS += -Wextra -Wshadow -Wjump-misses-init -Wundef override CFLAGS += -Wextra -Wshadow -Wjump-misses-init -Wundef
ifdef VERBOSE ifdef VERBOSE
override TESTFLAGS += -v override TFLAGS += -v
override CODEFLAGS += -v
override COVERAGEFLAGS += -v
endif
ifdef EXEC
override TESTFLAGS += --exec="$(EXEC)"
endif
ifdef BUILDDIR
override TESTFLAGS += --build-dir="$(BUILDDIR:/=)"
override CODEFLAGS += --build-dir="$(BUILDDIR:/=)"
endif
ifneq ($(NM),nm)
override CODEFLAGS += --nm-tool="$(NM)"
endif endif
# commands
.PHONY: all build
all build: $(TARGET) all build: $(TARGET)
.PHONY: asm
asm: $(ASM) asm: $(ASM)
.PHONY: size
size: $(OBJ) size: $(OBJ)
$(SIZE) -t $^ $(SIZE) -t $^
.PHONY: tags
tags:
$(CTAGS) --totals --c-types=+p $(shell find -H -name '*.h') $(SRC)
.PHONY: code
code: $(OBJ)
./scripts/code.py $^ $(CODEFLAGS)
.PHONY: test
test: test:
./scripts/test.py $(TESTFLAGS) ./scripts/test.py $(TFLAGS)
.SECONDEXPANSION: .SECONDEXPANSION:
test%: tests/test$$(firstword $$(subst \#, ,%)).toml test%: tests/test$$(firstword $$(subst \#, ,%)).toml
./scripts/test.py $@ $(TESTFLAGS) ./scripts/test.py $@ $(TFLAGS)
.PHONY: coverage
coverage:
./scripts/coverage.py $(BUILDDIR)tests/*.toml.info $(COVERAGEFLAGS)
# rules
-include $(DEP) -include $(DEP)
.SUFFIXES:
$(BUILDDIR)lfs: $(OBJ) lfs: $(OBJ)
$(CC) $(CFLAGS) $^ $(LFLAGS) -o $@ $(CC) $(CFLAGS) $^ $(LFLAGS) -o $@
$(BUILDDIR)%.a: $(OBJ) %.a: $(OBJ)
$(AR) rcs $@ $^ $(AR) rcs $@ $^
$(BUILDDIR)%.o: %.c %.o: %.c
$(CC) -c -MMD $(CFLAGS) $< -o $@ $(CC) -c -MMD $(CFLAGS) $< -o $@
$(BUILDDIR)%.s: %.c %.s: %.c
$(CC) -S $(CFLAGS) $< -o $@ $(CC) -S $(CFLAGS) $< -o $@
# clean everything
.PHONY: clean
clean: clean:
rm -f $(TARGET) rm -f $(TARGET)
rm -f $(OBJ) rm -f $(OBJ)
rm -f $(DEP) rm -f $(DEP)
rm -f $(ASM) rm -f $(ASM)
rm -f $(BUILDDIR)tests/*.toml.* rm -f tests/*.toml.*

View File

@@ -39,7 +39,7 @@ lfs_t lfs;
lfs_file_t file; lfs_file_t file;
// configuration of the filesystem is provided by this struct // configuration of the filesystem is provided by this struct
const struct lfs_config cfg = { const struct lfs_cfg cfg = {
// block device operations // block device operations
.read = user_provided_block_device_read, .read = user_provided_block_device_read,
.prog = user_provided_block_device_prog, .prog = user_provided_block_device_prog,
@@ -192,7 +192,7 @@ More details on how littlefs works can be found in [DESIGN.md](DESIGN.md) and
## Testing ## Testing
The littlefs comes with a test suite designed to run on a PC using the The littlefs comes with a test suite designed to run on a PC using the
[emulated block device](bd/lfs_testbd.h) found in the `bd` directory. [emulated block device](emubd/lfs_emubd.h) found in the emubd directory.
The tests assume a Linux environment and can be started with make: The tests assume a Linux environment and can be started with make:
``` bash ``` bash
@@ -221,11 +221,6 @@ License Identifiers that are here available: http://spdx.org/licenses/
- [littlefs-js] - A javascript wrapper for littlefs. I'm not sure why you would - [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 want this, but it is handy for demos. You can see it in action
[here][littlefs-js-demo]. [here][littlefs-js-demo].
- [littlefs-python] - A Python wrapper for littlefs. The project allows you
to create images of the filesystem on your PC. Check if littlefs will fit
your needs, create images for a later download to the target memory or
inspect the content of a binary image of the target memory.
- [mklfs] - A command line tool built by the [Lua RTOS] guys for making - [mklfs] - A command line tool built by the [Lua RTOS] guys for making
littlefs images from a host PC. Supports Windows, Mac OS, and Linux. littlefs images from a host PC. Supports Windows, Mac OS, and Linux.
@@ -255,4 +250,3 @@ License Identifiers that are here available: http://spdx.org/licenses/
[LittleFileSystem]: https://os.mbed.com/docs/mbed-os/v5.12/apis/littlefilesystem.html [LittleFileSystem]: https://os.mbed.com/docs/mbed-os/v5.12/apis/littlefilesystem.html
[SPIFFS]: https://github.com/pellepl/spiffs [SPIFFS]: https://github.com/pellepl/spiffs
[Dhara]: https://github.com/dlbeer/dhara [Dhara]: https://github.com/dlbeer/dhara
[littlefs-python]: https://pypi.org/project/littlefs-python/

View File

@@ -1,7 +1,6 @@
/* /*
* Block device emulated in a file * Block device emulated in a file
* *
* Copyright (c) 2022, The littlefs authors.
* Copyright (c) 2017, Arm Limited. All rights reserved. * Copyright (c) 2017, Arm Limited. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause * SPDX-License-Identifier: BSD-3-Clause
*/ */
@@ -11,21 +10,16 @@
#include <unistd.h> #include <unistd.h>
#include <errno.h> #include <errno.h>
int lfs_filebd_createcfg(const struct lfs_config *cfg, const char *path, int lfs_filebd_createcfg(lfs_filebd_t *bd, const char *path,
const struct lfs_filebd_config *bdcfg) { const struct lfs_filebd_cfg *cfg) {
LFS_FILEBD_TRACE("lfs_filebd_createcfg(%p {.context=%p, " LFS_FILEBD_TRACE("lfs_filebd_createcfg(%p, \"%s\", %p {"
".read=%p, .prog=%p, .erase=%p, .sync=%p, "
".read_size=%"PRIu32", .prog_size=%"PRIu32", " ".read_size=%"PRIu32", .prog_size=%"PRIu32", "
".block_size=%"PRIu32", .block_count=%"PRIu32"}, " ".erase_size=%"PRIu32", .erase_count=%"PRIu32", "
"\"%s\", " ".erase_value=%"PRId32"})",
"%p {.erase_value=%"PRId32"})", (void*)bd, path, (void*)cfg,
(void*)cfg, cfg->context, cfg->read_size, cfg->prog_size, cfg->erase_size, cfg->erase_count,
(void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, cfg->erase_value);
(void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, bd->cfg = cfg;
cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count,
path, (void*)bdcfg, bdcfg->erase_value);
lfs_filebd_t *bd = cfg->context;
bd->cfg = bdcfg;
// open file // open file
bd->fd = open(path, O_RDWR | O_CREAT, 0666); bd->fd = open(path, O_RDWR | O_CREAT, 0666);
@@ -39,26 +33,8 @@ int lfs_filebd_createcfg(const struct lfs_config *cfg, const char *path,
return 0; return 0;
} }
int lfs_filebd_create(const struct lfs_config *cfg, const char *path) { int lfs_filebd_destroy(lfs_filebd_t *bd) {
LFS_FILEBD_TRACE("lfs_filebd_create(%p {.context=%p, " LFS_FILEBD_TRACE("lfs_filebd_destroy(%p)", (void*)bd);
".read=%p, .prog=%p, .erase=%p, .sync=%p, "
".read_size=%"PRIu32", .prog_size=%"PRIu32", "
".block_size=%"PRIu32", .block_count=%"PRIu32"}, "
"\"%s\")",
(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,
path);
static const struct lfs_filebd_config defaults = {.erase_value=-1};
int err = lfs_filebd_createcfg(cfg, path, &defaults);
LFS_FILEBD_TRACE("lfs_filebd_create -> %d", err);
return err;
}
int lfs_filebd_destroy(const struct lfs_config *cfg) {
LFS_FILEBD_TRACE("lfs_filebd_destroy(%p)", (void*)cfg);
lfs_filebd_t *bd = cfg->context;
int err = close(bd->fd); int err = close(bd->fd);
if (err < 0) { if (err < 0) {
err = -errno; err = -errno;
@@ -69,17 +45,16 @@ int lfs_filebd_destroy(const struct lfs_config *cfg) {
return 0; return 0;
} }
int lfs_filebd_read(const struct lfs_config *cfg, lfs_block_t block, int lfs_filebd_read(lfs_filebd_t *bd, lfs_block_t block,
lfs_off_t off, void *buffer, lfs_size_t size) { lfs_off_t off, void *buffer, lfs_size_t size) {
LFS_FILEBD_TRACE("lfs_filebd_read(%p, " LFS_FILEBD_TRACE("lfs_filebd_read(%p, "
"0x%"PRIx32", %"PRIu32", %p, %"PRIu32")", "0x%"PRIx32", %"PRIu32", %p, %"PRIu32")",
(void*)cfg, block, off, buffer, size); (void*)bd, block, off, buffer, size);
lfs_filebd_t *bd = cfg->context;
// check if read is valid // check if read is valid
LFS_ASSERT(off % cfg->read_size == 0); LFS_ASSERT(off % bd->cfg->read_size == 0);
LFS_ASSERT(size % cfg->read_size == 0); LFS_ASSERT(size % bd->cfg->read_size == 0);
LFS_ASSERT(block < cfg->block_count); LFS_ASSERT(block < bd->cfg->erase_count);
// zero for reproducability (in case file is truncated) // zero for reproducability (in case file is truncated)
if (bd->cfg->erase_value != -1) { if (bd->cfg->erase_value != -1) {
@@ -88,7 +63,7 @@ int lfs_filebd_read(const struct lfs_config *cfg, lfs_block_t block,
// read // read
off_t res1 = lseek(bd->fd, off_t res1 = lseek(bd->fd,
(off_t)block*cfg->block_size + (off_t)off, SEEK_SET); (off_t)block*bd->cfg->erase_size + (off_t)off, SEEK_SET);
if (res1 < 0) { if (res1 < 0) {
int err = -errno; int err = -errno;
LFS_FILEBD_TRACE("lfs_filebd_read -> %d", err); LFS_FILEBD_TRACE("lfs_filebd_read -> %d", err);
@@ -106,21 +81,21 @@ int lfs_filebd_read(const struct lfs_config *cfg, lfs_block_t block,
return 0; return 0;
} }
int lfs_filebd_prog(const struct lfs_config *cfg, lfs_block_t block, int lfs_filebd_prog(lfs_filebd_t *bd, lfs_block_t block,
lfs_off_t off, const void *buffer, lfs_size_t size) { lfs_off_t off, const void *buffer, lfs_size_t size) {
LFS_FILEBD_TRACE("lfs_filebd_prog(%p, 0x%"PRIx32", %"PRIu32", %p, %"PRIu32")", LFS_FILEBD_TRACE("lfs_filebd_prog(%p, "
(void*)cfg, block, off, buffer, size); "0x%"PRIx32", %"PRIu32", %p, %"PRIu32")",
lfs_filebd_t *bd = cfg->context; (void*)bd, block, off, buffer, size);
// check if write is valid // check if write is valid
LFS_ASSERT(off % cfg->prog_size == 0); LFS_ASSERT(off % bd->cfg->prog_size == 0);
LFS_ASSERT(size % cfg->prog_size == 0); LFS_ASSERT(size % bd->cfg->prog_size == 0);
LFS_ASSERT(block < cfg->block_count); LFS_ASSERT(block < bd->cfg->erase_count);
// check that data was erased? only needed for testing // check that data was erased? only needed for testing
if (bd->cfg->erase_value != -1) { if (bd->cfg->erase_value != -1) {
off_t res1 = lseek(bd->fd, off_t res1 = lseek(bd->fd,
(off_t)block*cfg->block_size + (off_t)off, SEEK_SET); (off_t)block*bd->cfg->erase_size + (off_t)off, SEEK_SET);
if (res1 < 0) { if (res1 < 0) {
int err = -errno; int err = -errno;
LFS_FILEBD_TRACE("lfs_filebd_prog -> %d", err); LFS_FILEBD_TRACE("lfs_filebd_prog -> %d", err);
@@ -142,7 +117,7 @@ int lfs_filebd_prog(const struct lfs_config *cfg, lfs_block_t block,
// program data // program data
off_t res1 = lseek(bd->fd, off_t res1 = lseek(bd->fd,
(off_t)block*cfg->block_size + (off_t)off, SEEK_SET); (off_t)block*bd->cfg->erase_size + (off_t)off, SEEK_SET);
if (res1 < 0) { if (res1 < 0) {
int err = -errno; int err = -errno;
LFS_FILEBD_TRACE("lfs_filebd_prog -> %d", err); LFS_FILEBD_TRACE("lfs_filebd_prog -> %d", err);
@@ -160,23 +135,22 @@ int lfs_filebd_prog(const struct lfs_config *cfg, lfs_block_t block,
return 0; return 0;
} }
int lfs_filebd_erase(const struct lfs_config *cfg, lfs_block_t block) { int lfs_filebd_erase(lfs_filebd_t *bd, lfs_block_t block) {
LFS_FILEBD_TRACE("lfs_filebd_erase(%p, 0x%"PRIx32")", (void*)cfg, block); LFS_FILEBD_TRACE("lfs_filebd_erase(%p, 0x%"PRIx32")", (void*)bd, block);
lfs_filebd_t *bd = cfg->context;
// check if erase is valid // check if erase is valid
LFS_ASSERT(block < cfg->block_count); LFS_ASSERT(block < bd->cfg->erase_count);
// erase, only needed for testing // erase, only needed for testing
if (bd->cfg->erase_value != -1) { if (bd->cfg->erase_value != -1) {
off_t res1 = lseek(bd->fd, (off_t)block*cfg->block_size, SEEK_SET); off_t res1 = lseek(bd->fd, (off_t)block*bd->cfg->erase_size, SEEK_SET);
if (res1 < 0) { if (res1 < 0) {
int err = -errno; int err = -errno;
LFS_FILEBD_TRACE("lfs_filebd_erase -> %d", err); LFS_FILEBD_TRACE("lfs_filebd_erase -> %d", err);
return err; return err;
} }
for (lfs_off_t i = 0; i < cfg->block_size; i++) { for (lfs_off_t i = 0; i < bd->cfg->erase_size; i++) {
ssize_t res2 = write(bd->fd, &(uint8_t){bd->cfg->erase_value}, 1); ssize_t res2 = write(bd->fd, &(uint8_t){bd->cfg->erase_value}, 1);
if (res2 < 0) { if (res2 < 0) {
int err = -errno; int err = -errno;
@@ -190,10 +164,10 @@ int lfs_filebd_erase(const struct lfs_config *cfg, lfs_block_t block) {
return 0; return 0;
} }
int lfs_filebd_sync(const struct lfs_config *cfg) { int lfs_filebd_sync(lfs_filebd_t *bd) {
LFS_FILEBD_TRACE("lfs_filebd_sync(%p)", (void*)cfg); LFS_FILEBD_TRACE("lfs_filebd_sync(%p)", (void*)bd);
// file sync // file sync
lfs_filebd_t *bd = cfg->context;
int err = fsync(bd->fd); int err = fsync(bd->fd);
if (err) { if (err) {
err = -errno; err = -errno;

View File

@@ -1,7 +1,6 @@
/* /*
* Block device emulated in a file * Block device emulated in a file
* *
* Copyright (c) 2022, The littlefs authors.
* Copyright (c) 2017, Arm Limited. All rights reserved. * Copyright (c) 2017, Arm Limited. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause * SPDX-License-Identifier: BSD-3-Clause
*/ */
@@ -9,11 +8,9 @@
#define LFS_FILEBD_H #define LFS_FILEBD_H
#include "lfs.h" #include "lfs.h"
#include "lfs_util.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" extern "C" {
{
#endif #endif
@@ -25,7 +22,21 @@ extern "C"
#endif #endif
// filebd config (optional) // filebd config (optional)
struct lfs_filebd_config { struct lfs_filebd_cfg {
// Minimum size of block read. All read operations must be a
// multiple of this value.
lfs_size_t read_size;
// Minimum size of block program. All program operations must be a
// multiple of this value.
lfs_size_t prog_size;
// Size of an erasable block.
lfs_size_t erase_size;
// Number of erasable blocks on the device.
lfs_size_t erase_count;
// 8-bit erase value to use for simulating erases. -1 does not simulate // 8-bit erase value to use for simulating erases. -1 does not simulate
// erases, which can speed up testing by avoiding all the extra block-device // erases, which can speed up testing by avoiding all the extra block-device
// operations to store the erase value. // operations to store the erase value.
@@ -35,40 +46,39 @@ struct lfs_filebd_config {
// filebd state // filebd state
typedef struct lfs_filebd { typedef struct lfs_filebd {
int fd; int fd;
const struct lfs_filebd_config *cfg; const struct lfs_filebd_cfg *cfg;
} lfs_filebd_t; } lfs_filebd_t;
// Create a file block device using the geometry in lfs_config // Create a file block device using the geometry in lfs_filebd_cfg
int lfs_filebd_create(const struct lfs_config *cfg, const char *path); int lfs_filebd_createcfg(lfs_filebd_t *bd, const char *path,
int lfs_filebd_createcfg(const struct lfs_config *cfg, const char *path, const struct lfs_filebd_cfg *cfg);
const struct lfs_filebd_config *bdcfg);
// Clean up memory associated with block device // Clean up memory associated with block device
int lfs_filebd_destroy(const struct lfs_config *cfg); int lfs_filebd_destroy(lfs_filebd_t *bd);
// Read a block // Read a block
int lfs_filebd_read(const struct lfs_config *cfg, lfs_block_t block, int lfs_filebd_read(lfs_filebd_t *bd, lfs_block_t block,
lfs_off_t off, void *buffer, lfs_size_t size); lfs_off_t off, void *buffer, lfs_size_t size);
// Program a block // Program a block
// //
// The block must have previously been erased. // The block must have previously been erased.
int lfs_filebd_prog(const struct lfs_config *cfg, lfs_block_t block, int lfs_filebd_prog(lfs_filebd_t *bd, lfs_block_t block,
lfs_off_t off, const void *buffer, lfs_size_t size); lfs_off_t off, const void *buffer, lfs_size_t size);
// Erase a block // Erase a block
// //
// A block must be erased before being programmed. The // A block must be erased before being programmed. The
// state of an erased block is undefined. // state of an erased block is undefined.
int lfs_filebd_erase(const struct lfs_config *cfg, lfs_block_t block); int lfs_filebd_erase(lfs_filebd_t *bd, lfs_block_t block);
// Sync the block device // Sync the block device
int lfs_filebd_sync(const struct lfs_config *cfg); int lfs_filebd_sync(lfs_filebd_t *bd);
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ }
#endif #endif
#endif #endif

View File

@@ -1,32 +1,27 @@
/* /*
* Block device emulated in RAM * Block device emulated in RAM
* *
* Copyright (c) 2022, The littlefs authors.
* Copyright (c) 2017, Arm Limited. All rights reserved. * Copyright (c) 2017, Arm Limited. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause * SPDX-License-Identifier: BSD-3-Clause
*/ */
#include "bd/lfs_rambd.h" #include "bd/lfs_rambd.h"
int lfs_rambd_createcfg(const struct lfs_config *cfg, int lfs_rambd_createcfg(lfs_rambd_t *bd,
const struct lfs_rambd_config *bdcfg) { const struct lfs_rambd_cfg *cfg) {
LFS_RAMBD_TRACE("lfs_rambd_createcfg(%p {.context=%p, " LFS_RAMBD_TRACE("lfs_filebd_createcfg(%p, %p {"
".read=%p, .prog=%p, .erase=%p, .sync=%p, "
".read_size=%"PRIu32", .prog_size=%"PRIu32", " ".read_size=%"PRIu32", .prog_size=%"PRIu32", "
".block_size=%"PRIu32", .block_count=%"PRIu32"}, " ".erase_size=%"PRIu32", .erase_count=%"PRIu32", "
"%p {.erase_value=%"PRId32", .buffer=%p})", ".erase_value=%"PRId32", .buffer=%p})",
(void*)cfg, cfg->context, (void*)bd, (void*)cfg,
(void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, cfg->read_size, cfg->prog_size, cfg->erase_size, cfg->erase_count,
(void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, cfg->erase_value, cfg->buffer);
cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, bd->cfg = cfg;
(void*)bdcfg, bdcfg->erase_value, bdcfg->buffer);
lfs_rambd_t *bd = cfg->context;
bd->cfg = bdcfg;
// allocate buffer? // allocate buffer?
if (bd->cfg->buffer) { if (bd->cfg->buffer) {
bd->buffer = bd->cfg->buffer; bd->buffer = bd->cfg->buffer;
} else { } else {
bd->buffer = lfs_malloc(cfg->block_size * cfg->block_count); bd->buffer = lfs_malloc(bd->cfg->erase_size * bd->cfg->erase_count);
if (!bd->buffer) { if (!bd->buffer) {
LFS_RAMBD_TRACE("lfs_rambd_createcfg -> %d", LFS_ERR_NOMEM); LFS_RAMBD_TRACE("lfs_rambd_createcfg -> %d", LFS_ERR_NOMEM);
return LFS_ERR_NOMEM; return LFS_ERR_NOMEM;
@@ -36,32 +31,16 @@ int lfs_rambd_createcfg(const struct lfs_config *cfg,
// zero for reproducability? // zero for reproducability?
if (bd->cfg->erase_value != -1) { if (bd->cfg->erase_value != -1) {
memset(bd->buffer, bd->cfg->erase_value, memset(bd->buffer, bd->cfg->erase_value,
cfg->block_size * cfg->block_count); bd->cfg->erase_size * bd->cfg->erase_count);
} }
LFS_RAMBD_TRACE("lfs_rambd_createcfg -> %d", 0); LFS_RAMBD_TRACE("lfs_rambd_createcfg -> %d", 0);
return 0; return 0;
} }
int lfs_rambd_create(const struct lfs_config *cfg) { int lfs_rambd_destroy(lfs_rambd_t *bd) {
LFS_RAMBD_TRACE("lfs_rambd_create(%p {.context=%p, " LFS_RAMBD_TRACE("lfs_rambd_destroy(%p)", (void*)bd);
".read=%p, .prog=%p, .erase=%p, .sync=%p, "
".read_size=%"PRIu32", .prog_size=%"PRIu32", "
".block_size=%"PRIu32", .block_count=%"PRIu32"})",
(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);
static const struct lfs_rambd_config defaults = {.erase_value=-1};
int err = lfs_rambd_createcfg(cfg, &defaults);
LFS_RAMBD_TRACE("lfs_rambd_create -> %d", err);
return err;
}
int lfs_rambd_destroy(const struct lfs_config *cfg) {
LFS_RAMBD_TRACE("lfs_rambd_destroy(%p)", (void*)cfg);
// clean up memory // clean up memory
lfs_rambd_t *bd = cfg->context;
if (!bd->cfg->buffer) { if (!bd->cfg->buffer) {
lfs_free(bd->buffer); lfs_free(bd->buffer);
} }
@@ -69,73 +48,70 @@ int lfs_rambd_destroy(const struct lfs_config *cfg) {
return 0; return 0;
} }
int lfs_rambd_read(const struct lfs_config *cfg, lfs_block_t block, int lfs_rambd_read(lfs_rambd_t *bd, lfs_block_t block,
lfs_off_t off, void *buffer, lfs_size_t size) { lfs_off_t off, void *buffer, lfs_size_t size) {
LFS_RAMBD_TRACE("lfs_rambd_read(%p, " LFS_RAMBD_TRACE("lfs_rambd_read(%p, "
"0x%"PRIx32", %"PRIu32", %p, %"PRIu32")", "0x%"PRIx32", %"PRIu32", %p, %"PRIu32")",
(void*)cfg, block, off, buffer, size); (void*)bd, block, off, buffer, size);
lfs_rambd_t *bd = cfg->context;
// check if read is valid // check if read is valid
LFS_ASSERT(off % cfg->read_size == 0); LFS_ASSERT(off % bd->cfg->read_size == 0);
LFS_ASSERT(size % cfg->read_size == 0); LFS_ASSERT(size % bd->cfg->read_size == 0);
LFS_ASSERT(block < cfg->block_count); LFS_ASSERT(block < bd->cfg->erase_count);
// read data // read data
memcpy(buffer, &bd->buffer[block*cfg->block_size + off], size); memcpy(buffer, &bd->buffer[block*bd->cfg->erase_size + off], size);
LFS_RAMBD_TRACE("lfs_rambd_read -> %d", 0); LFS_RAMBD_TRACE("lfs_rambd_read -> %d", 0);
return 0; return 0;
} }
int lfs_rambd_prog(const struct lfs_config *cfg, lfs_block_t block, int lfs_rambd_prog(lfs_rambd_t *bd, lfs_block_t block,
lfs_off_t off, const void *buffer, lfs_size_t size) { lfs_off_t off, const void *buffer, lfs_size_t size) {
LFS_RAMBD_TRACE("lfs_rambd_prog(%p, " LFS_RAMBD_TRACE("lfs_rambd_prog(%p, "
"0x%"PRIx32", %"PRIu32", %p, %"PRIu32")", "0x%"PRIx32", %"PRIu32", %p, %"PRIu32")",
(void*)cfg, block, off, buffer, size); (void*)bd, block, off, buffer, size);
lfs_rambd_t *bd = cfg->context;
// check if write is valid // check if write is valid
LFS_ASSERT(off % cfg->prog_size == 0); LFS_ASSERT(off % bd->cfg->prog_size == 0);
LFS_ASSERT(size % cfg->prog_size == 0); LFS_ASSERT(size % bd->cfg->prog_size == 0);
LFS_ASSERT(block < cfg->block_count); LFS_ASSERT(block < bd->cfg->erase_count);
// check that data was erased? only needed for testing // check that data was erased? only needed for testing
if (bd->cfg->erase_value != -1) { if (bd->cfg->erase_value != -1) {
for (lfs_off_t i = 0; i < size; i++) { for (lfs_off_t i = 0; i < size; i++) {
LFS_ASSERT(bd->buffer[block*cfg->block_size + off + i] == LFS_ASSERT(bd->buffer[block*bd->cfg->erase_size + off + i] ==
bd->cfg->erase_value); bd->cfg->erase_value);
} }
} }
// program data // program data
memcpy(&bd->buffer[block*cfg->block_size + off], buffer, size); memcpy(&bd->buffer[block*bd->cfg->erase_size + off], buffer, size);
LFS_RAMBD_TRACE("lfs_rambd_prog -> %d", 0); LFS_RAMBD_TRACE("lfs_rambd_prog -> %d", 0);
return 0; return 0;
} }
int lfs_rambd_erase(const struct lfs_config *cfg, lfs_block_t block) { int lfs_rambd_erase(lfs_rambd_t *bd, lfs_block_t block) {
LFS_RAMBD_TRACE("lfs_rambd_erase(%p, 0x%"PRIx32")", (void*)cfg, block); LFS_RAMBD_TRACE("lfs_rambd_erase(%p, 0x%"PRIx32")", (void*)bd, block);
lfs_rambd_t *bd = cfg->context;
// check if erase is valid // check if erase is valid
LFS_ASSERT(block < cfg->block_count); LFS_ASSERT(block < bd->cfg->erase_count);
// erase, only needed for testing // erase, only needed for testing
if (bd->cfg->erase_value != -1) { if (bd->cfg->erase_value != -1) {
memset(&bd->buffer[block*cfg->block_size], memset(&bd->buffer[block*bd->cfg->erase_size],
bd->cfg->erase_value, cfg->block_size); bd->cfg->erase_value, bd->cfg->erase_size);
} }
LFS_RAMBD_TRACE("lfs_rambd_erase -> %d", 0); LFS_RAMBD_TRACE("lfs_rambd_erase -> %d", 0);
return 0; return 0;
} }
int lfs_rambd_sync(const struct lfs_config *cfg) { int lfs_rambd_sync(lfs_rambd_t *bd) {
LFS_RAMBD_TRACE("lfs_rambd_sync(%p)", (void*)cfg); LFS_RAMBD_TRACE("lfs_rambd_sync(%p)", (void*)bd);
// sync does nothing because we aren't backed by anything real // sync does nothing because we aren't backed by anything real
(void)cfg; (void)bd;
LFS_RAMBD_TRACE("lfs_rambd_sync -> %d", 0); LFS_RAMBD_TRACE("lfs_rambd_sync -> %d", 0);
return 0; return 0;
} }

View File

@@ -1,7 +1,6 @@
/* /*
* Block device emulated in RAM * Block device emulated in RAM
* *
* Copyright (c) 2022, The littlefs authors.
* Copyright (c) 2017, Arm Limited. All rights reserved. * Copyright (c) 2017, Arm Limited. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause * SPDX-License-Identifier: BSD-3-Clause
*/ */
@@ -9,11 +8,9 @@
#define LFS_RAMBD_H #define LFS_RAMBD_H
#include "lfs.h" #include "lfs.h"
#include "lfs_util.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" extern "C" {
{
#endif #endif
@@ -25,9 +22,24 @@ extern "C"
#endif #endif
// rambd config (optional) // rambd config (optional)
struct lfs_rambd_config { struct lfs_rambd_cfg {
// 8-bit erase value to simulate erasing with. -1 indicates no erase // Minimum size of block read. All read operations must be a
// occurs, which is still a valid block device // multiple of this value.
lfs_size_t read_size;
// Minimum size of block program. All program operations must be a
// multiple of this value.
lfs_size_t prog_size;
// Size of an erasable block.
lfs_size_t erase_size;
// Number of erasable blocks on the device.
lfs_size_t erase_count;
// 8-bit erase value to use for simulating erases. -1 does not simulate
// erases, which can speed up testing by avoiding all the extra block-device
// operations to store the erase value.
int32_t erase_value; int32_t erase_value;
// Optional statically allocated buffer for the block device. // Optional statically allocated buffer for the block device.
@@ -37,40 +49,39 @@ struct lfs_rambd_config {
// rambd state // rambd state
typedef struct lfs_rambd { typedef struct lfs_rambd {
uint8_t *buffer; uint8_t *buffer;
const struct lfs_rambd_config *cfg; const struct lfs_rambd_cfg *cfg;
} lfs_rambd_t; } lfs_rambd_t;
// Create a RAM block device using the geometry in lfs_config // Create a RAM block device using the geometry in lfs_cfg
int lfs_rambd_create(const struct lfs_config *cfg); int lfs_rambd_createcfg(lfs_rambd_t *bd,
int lfs_rambd_createcfg(const struct lfs_config *cfg, const struct lfs_rambd_cfg *cfg);
const struct lfs_rambd_config *bdcfg);
// Clean up memory associated with block device // Clean up memory associated with block device
int lfs_rambd_destroy(const struct lfs_config *cfg); int lfs_rambd_destroy(lfs_rambd_t *bd);
// Read a block // Read a block
int lfs_rambd_read(const struct lfs_config *cfg, lfs_block_t block, int lfs_rambd_read(lfs_rambd_t *bd, lfs_block_t block,
lfs_off_t off, void *buffer, lfs_size_t size); lfs_off_t off, void *buffer, lfs_size_t size);
// Program a block // Program a block
// //
// The block must have previously been erased. // The block must have previously been erased.
int lfs_rambd_prog(const struct lfs_config *cfg, lfs_block_t block, int lfs_rambd_prog(lfs_rambd_t *bd, lfs_block_t block,
lfs_off_t off, const void *buffer, lfs_size_t size); lfs_off_t off, const void *buffer, lfs_size_t size);
// Erase a block // Erase a block
// //
// A block must be erased before being programmed. The // A block must be erased before being programmed. The
// state of an erased block is undefined. // state of an erased block is undefined.
int lfs_rambd_erase(const struct lfs_config *cfg, lfs_block_t block); int lfs_rambd_erase(lfs_rambd_t *bd, lfs_block_t block);
// Sync the block device // Sync the block device
int lfs_rambd_sync(const struct lfs_config *cfg); int lfs_rambd_sync(lfs_rambd_t *bd);
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ }
#endif #endif
#endif #endif

View File

@@ -2,7 +2,6 @@
* Testing block device, wraps filebd and rambd while providing a bunch * Testing block device, wraps filebd and rambd while providing a bunch
* of hooks for testing littlefs in various conditions. * of hooks for testing littlefs in various conditions.
* *
* Copyright (c) 2022, The littlefs authors.
* Copyright (c) 2017, Arm Limited. All rights reserved. * Copyright (c) 2017, Arm Limited. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause * SPDX-License-Identifier: BSD-3-Clause
*/ */
@@ -11,25 +10,20 @@
#include <stdlib.h> #include <stdlib.h>
int lfs_testbd_createcfg(const struct lfs_config *cfg, const char *path, int lfs_testbd_createcfg(lfs_testbd_t *bd, const char *path,
const struct lfs_testbd_config *bdcfg) { const struct lfs_testbd_cfg *cfg) {
LFS_TESTBD_TRACE("lfs_testbd_createcfg(%p {.context=%p, " LFS_TESTBD_TRACE("lfs_testbd_createcfg(%p, \"%s\", %p {"
".read=%p, .prog=%p, .erase=%p, .sync=%p, "
".read_size=%"PRIu32", .prog_size=%"PRIu32", " ".read_size=%"PRIu32", .prog_size=%"PRIu32", "
".block_size=%"PRIu32", .block_count=%"PRIu32"}, " ".erase_size=%"PRIu32", .erase_count=%"PRIu32", "
"\"%s\", " ".erase_value=%"PRId32", .erase_cycles=%"PRIu32", "
"%p {.erase_value=%"PRId32", .erase_cycles=%"PRIu32", "
".badblock_behavior=%"PRIu8", .power_cycles=%"PRIu32", " ".badblock_behavior=%"PRIu8", .power_cycles=%"PRIu32", "
".buffer=%p, .wear_buffer=%p})", ".buffer=%p, .wear_buffer=%p})",
(void*)cfg, cfg->context, (void*)bd, path, (void*)cfg,
(void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, cfg->read_size, cfg->prog_size, cfg->erase_size, cfg->erase_count,
(void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, cfg->erase_value, cfg->erase_cycles,
cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, cfg->badblock_behavior, cfg->power_cycles,
path, (void*)bdcfg, bdcfg->erase_value, bdcfg->erase_cycles, cfg->buffer, cfg->wear_buffer);
bdcfg->badblock_behavior, bdcfg->power_cycles, bd->cfg = cfg;
bdcfg->buffer, bdcfg->wear_buffer);
lfs_testbd_t *bd = cfg->context;
bd->cfg = bdcfg;
// setup testing things // setup testing things
bd->persist = path; bd->persist = path;
@@ -39,122 +33,94 @@ int lfs_testbd_createcfg(const struct lfs_config *cfg, const char *path,
if (bd->cfg->wear_buffer) { if (bd->cfg->wear_buffer) {
bd->wear = bd->cfg->wear_buffer; bd->wear = bd->cfg->wear_buffer;
} else { } else {
bd->wear = lfs_malloc(sizeof(lfs_testbd_wear_t)*cfg->block_count); bd->wear = lfs_malloc(sizeof(lfs_testbd_wear_t)*cfg->erase_count);
if (!bd->wear) { if (!bd->wear) {
LFS_TESTBD_TRACE("lfs_testbd_createcfg -> %d", LFS_ERR_NOMEM); LFS_TESTBD_TRACE("lfs_testbd_createcfg -> %d", LFS_ERR_NOMEM);
return LFS_ERR_NOMEM; return LFS_ERR_NOMEM;
} }
} }
memset(bd->wear, 0, sizeof(lfs_testbd_wear_t) * cfg->block_count); memset(bd->wear, 0, sizeof(lfs_testbd_wear_t) * bd->cfg->erase_count);
} }
// create underlying block device // create underlying block device
if (bd->persist) { if (bd->persist) {
bd->u.file.cfg = (struct lfs_filebd_config){ int err = lfs_filebd_createcfg(&bd->impl.filebd, path,
.erase_value = bd->cfg->erase_value, bd->cfg->filebd_cfg);
};
int err = lfs_filebd_createcfg(cfg, path, &bd->u.file.cfg);
LFS_TESTBD_TRACE("lfs_testbd_createcfg -> %d", err); LFS_TESTBD_TRACE("lfs_testbd_createcfg -> %d", err);
return err; return err;
} else { } else {
bd->u.ram.cfg = (struct lfs_rambd_config){ int err = lfs_rambd_createcfg(&bd->impl.rambd,
.erase_value = bd->cfg->erase_value, bd->cfg->rambd_cfg);
.buffer = bd->cfg->buffer,
};
int err = lfs_rambd_createcfg(cfg, &bd->u.ram.cfg);
LFS_TESTBD_TRACE("lfs_testbd_createcfg -> %d", err); LFS_TESTBD_TRACE("lfs_testbd_createcfg -> %d", err);
return err; return err;
} }
} }
int lfs_testbd_create(const struct lfs_config *cfg, const char *path) { int lfs_testbd_destroy(lfs_testbd_t *bd) {
LFS_TESTBD_TRACE("lfs_testbd_create(%p {.context=%p, " LFS_TESTBD_TRACE("lfs_testbd_destroy(%p)", (void*)bd);
".read=%p, .prog=%p, .erase=%p, .sync=%p, "
".read_size=%"PRIu32", .prog_size=%"PRIu32", "
".block_size=%"PRIu32", .block_count=%"PRIu32"}, "
"\"%s\")",
(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,
path);
static const struct lfs_testbd_config defaults = {.erase_value=-1};
int err = lfs_testbd_createcfg(cfg, path, &defaults);
LFS_TESTBD_TRACE("lfs_testbd_create -> %d", err);
return err;
}
int lfs_testbd_destroy(const struct lfs_config *cfg) {
LFS_TESTBD_TRACE("lfs_testbd_destroy(%p)", (void*)cfg);
lfs_testbd_t *bd = cfg->context;
if (bd->cfg->erase_cycles && !bd->cfg->wear_buffer) { if (bd->cfg->erase_cycles && !bd->cfg->wear_buffer) {
lfs_free(bd->wear); lfs_free(bd->wear);
} }
if (bd->persist) { if (bd->persist) {
int err = lfs_filebd_destroy(cfg); int err = lfs_filebd_destroy(&bd->impl.filebd);
LFS_TESTBD_TRACE("lfs_testbd_destroy -> %d", err); LFS_TESTBD_TRACE("lfs_testbd_destroy -> %d", err);
return err; return err;
} else { } else {
int err = lfs_rambd_destroy(cfg); int err = lfs_rambd_destroy(&bd->impl.rambd);
LFS_TESTBD_TRACE("lfs_testbd_destroy -> %d", err); LFS_TESTBD_TRACE("lfs_testbd_destroy -> %d", err);
return err; return err;
} }
} }
/// Internal mapping to block devices /// /// Internal mapping to block devices ///
static int lfs_testbd_rawread(const struct lfs_config *cfg, lfs_block_t block, static int lfs_testbd_rawread(lfs_testbd_t *bd, lfs_block_t block,
lfs_off_t off, void *buffer, lfs_size_t size) { lfs_off_t off, void *buffer, lfs_size_t size) {
lfs_testbd_t *bd = cfg->context;
if (bd->persist) { if (bd->persist) {
return lfs_filebd_read(cfg, block, off, buffer, size); return lfs_filebd_read(&bd->impl.filebd, block, off, buffer, size);
} else { } else {
return lfs_rambd_read(cfg, block, off, buffer, size); return lfs_rambd_read(&bd->impl.rambd, block, off, buffer, size);
} }
} }
static int lfs_testbd_rawprog(const struct lfs_config *cfg, lfs_block_t block, static int lfs_testbd_rawprog(lfs_testbd_t *bd, lfs_block_t block,
lfs_off_t off, const void *buffer, lfs_size_t size) { lfs_off_t off, const void *buffer, lfs_size_t size) {
lfs_testbd_t *bd = cfg->context;
if (bd->persist) { if (bd->persist) {
return lfs_filebd_prog(cfg, block, off, buffer, size); return lfs_filebd_prog(&bd->impl.filebd, block, off, buffer, size);
} else { } else {
return lfs_rambd_prog(cfg, block, off, buffer, size); return lfs_rambd_prog(&bd->impl.rambd, block, off, buffer, size);
} }
} }
static int lfs_testbd_rawerase(const struct lfs_config *cfg, static int lfs_testbd_rawerase(lfs_testbd_t *bd,
lfs_block_t block) { lfs_block_t block) {
lfs_testbd_t *bd = cfg->context;
if (bd->persist) { if (bd->persist) {
return lfs_filebd_erase(cfg, block); return lfs_filebd_erase(&bd->impl.filebd, block);
} else { } else {
return lfs_rambd_erase(cfg, block); return lfs_rambd_erase(&bd->impl.rambd, block);
} }
} }
static int lfs_testbd_rawsync(const struct lfs_config *cfg) { static int lfs_testbd_rawsync(lfs_testbd_t *bd) {
lfs_testbd_t *bd = cfg->context;
if (bd->persist) { if (bd->persist) {
return lfs_filebd_sync(cfg); return lfs_filebd_sync(&bd->impl.filebd);
} else { } else {
return lfs_rambd_sync(cfg); return lfs_rambd_sync(&bd->impl.rambd);
} }
} }
/// block device API /// /// block device API ///
int lfs_testbd_read(const struct lfs_config *cfg, lfs_block_t block, int lfs_testbd_read(lfs_testbd_t *bd, lfs_block_t block,
lfs_off_t off, void *buffer, lfs_size_t size) { lfs_off_t off, void *buffer, lfs_size_t size) {
LFS_TESTBD_TRACE("lfs_testbd_read(%p, " LFS_TESTBD_TRACE("lfs_testbd_read(%p, "
"0x%"PRIx32", %"PRIu32", %p, %"PRIu32")", "0x%"PRIx32", %"PRIu32", %p, %"PRIu32")",
(void*)cfg, block, off, buffer, size); (void*)bd, block, off, buffer, size);
lfs_testbd_t *bd = cfg->context;
// check if read is valid // check if read is valid
LFS_ASSERT(off % cfg->read_size == 0); LFS_ASSERT(off % bd->cfg->read_size == 0);
LFS_ASSERT(size % cfg->read_size == 0); LFS_ASSERT(size % bd->cfg->read_size == 0);
LFS_ASSERT(block < cfg->block_count); LFS_ASSERT(block < bd->cfg->erase_count);
// block bad? // block bad?
if (bd->cfg->erase_cycles && bd->wear[block] >= bd->cfg->erase_cycles && if (bd->cfg->erase_cycles && bd->wear[block] >= bd->cfg->erase_cycles &&
@@ -164,22 +130,21 @@ int lfs_testbd_read(const struct lfs_config *cfg, lfs_block_t block,
} }
// read // read
int err = lfs_testbd_rawread(cfg, block, off, buffer, size); int err = lfs_testbd_rawread(bd, block, off, buffer, size);
LFS_TESTBD_TRACE("lfs_testbd_read -> %d", err); LFS_TESTBD_TRACE("lfs_testbd_read -> %d", err);
return err; return err;
} }
int lfs_testbd_prog(const struct lfs_config *cfg, lfs_block_t block, int lfs_testbd_prog(lfs_testbd_t *bd, lfs_block_t block,
lfs_off_t off, const void *buffer, lfs_size_t size) { lfs_off_t off, const void *buffer, lfs_size_t size) {
LFS_TESTBD_TRACE("lfs_testbd_prog(%p, " LFS_TESTBD_TRACE("lfs_testbd_prog(%p, "
"0x%"PRIx32", %"PRIu32", %p, %"PRIu32")", "0x%"PRIx32", %"PRIu32", %p, %"PRIu32")",
(void*)cfg, block, off, buffer, size); (void*)bd, block, off, buffer, size);
lfs_testbd_t *bd = cfg->context;
// check if write is valid // check if write is valid
LFS_ASSERT(off % cfg->prog_size == 0); LFS_ASSERT(off % bd->cfg->prog_size == 0);
LFS_ASSERT(size % cfg->prog_size == 0); LFS_ASSERT(size % bd->cfg->prog_size == 0);
LFS_ASSERT(block < cfg->block_count); LFS_ASSERT(block < bd->cfg->erase_count);
// block bad? // block bad?
if (bd->cfg->erase_cycles && bd->wear[block] >= bd->cfg->erase_cycles) { if (bd->cfg->erase_cycles && bd->wear[block] >= bd->cfg->erase_cycles) {
@@ -197,7 +162,7 @@ int lfs_testbd_prog(const struct lfs_config *cfg, lfs_block_t block,
} }
// prog // prog
int err = lfs_testbd_rawprog(cfg, block, off, buffer, size); int err = lfs_testbd_rawprog(bd, block, off, buffer, size);
if (err) { if (err) {
LFS_TESTBD_TRACE("lfs_testbd_prog -> %d", err); LFS_TESTBD_TRACE("lfs_testbd_prog -> %d", err);
return err; return err;
@@ -208,7 +173,7 @@ int lfs_testbd_prog(const struct lfs_config *cfg, lfs_block_t block,
bd->power_cycles -= 1; bd->power_cycles -= 1;
if (bd->power_cycles == 0) { if (bd->power_cycles == 0) {
// sync to make sure we persist the last changes // sync to make sure we persist the last changes
LFS_ASSERT(lfs_testbd_rawsync(cfg) == 0); assert(lfs_testbd_rawsync(bd) == 0);
// simulate power loss // simulate power loss
exit(33); exit(33);
} }
@@ -218,12 +183,11 @@ int lfs_testbd_prog(const struct lfs_config *cfg, lfs_block_t block,
return 0; return 0;
} }
int lfs_testbd_erase(const struct lfs_config *cfg, lfs_block_t block) { int lfs_testbd_erase(lfs_testbd_t *bd, lfs_block_t block) {
LFS_TESTBD_TRACE("lfs_testbd_erase(%p, 0x%"PRIx32")", (void*)cfg, block); LFS_TESTBD_TRACE("lfs_testbd_erase(%p, 0x%"PRIx32")", (void*)bd, block);
lfs_testbd_t *bd = cfg->context;
// check if erase is valid // check if erase is valid
LFS_ASSERT(block < cfg->block_count); LFS_ASSERT(block < bd->cfg->erase_count);
// block bad? // block bad?
if (bd->cfg->erase_cycles) { if (bd->cfg->erase_cycles) {
@@ -244,7 +208,7 @@ int lfs_testbd_erase(const struct lfs_config *cfg, lfs_block_t block) {
} }
// erase // erase
int err = lfs_testbd_rawerase(cfg, block); int err = lfs_testbd_rawerase(bd, block);
if (err) { if (err) {
LFS_TESTBD_TRACE("lfs_testbd_erase -> %d", err); LFS_TESTBD_TRACE("lfs_testbd_erase -> %d", err);
return err; return err;
@@ -255,7 +219,7 @@ int lfs_testbd_erase(const struct lfs_config *cfg, lfs_block_t block) {
bd->power_cycles -= 1; bd->power_cycles -= 1;
if (bd->power_cycles == 0) { if (bd->power_cycles == 0) {
// sync to make sure we persist the last changes // sync to make sure we persist the last changes
LFS_ASSERT(lfs_testbd_rawsync(cfg) == 0); assert(lfs_testbd_rawsync(bd) == 0);
// simulate power loss // simulate power loss
exit(33); exit(33);
} }
@@ -265,36 +229,34 @@ int lfs_testbd_erase(const struct lfs_config *cfg, lfs_block_t block) {
return 0; return 0;
} }
int lfs_testbd_sync(const struct lfs_config *cfg) { int lfs_testbd_sync(lfs_testbd_t *bd) {
LFS_TESTBD_TRACE("lfs_testbd_sync(%p)", (void*)cfg); LFS_TESTBD_TRACE("lfs_testbd_sync(%p)", (void*)bd);
int err = lfs_testbd_rawsync(cfg); int err = lfs_testbd_rawsync(bd);
LFS_TESTBD_TRACE("lfs_testbd_sync -> %d", err); LFS_TESTBD_TRACE("lfs_testbd_sync -> %d", err);
return err; return err;
} }
/// simulated wear operations /// /// simulated wear operations ///
lfs_testbd_swear_t lfs_testbd_getwear(const struct lfs_config *cfg, lfs_testbd_swear_t lfs_testbd_getwear(lfs_testbd_t *bd,
lfs_block_t block) { lfs_block_t block) {
LFS_TESTBD_TRACE("lfs_testbd_getwear(%p, %"PRIu32")", (void*)cfg, block); LFS_TESTBD_TRACE("lfs_testbd_getwear(%p, %"PRIu32")", (void*)bd, block);
lfs_testbd_t *bd = cfg->context;
// check if block is valid // check if block is valid
LFS_ASSERT(bd->cfg->erase_cycles); LFS_ASSERT(bd->cfg->erase_cycles);
LFS_ASSERT(block < cfg->block_count); LFS_ASSERT(block < bd->cfg->erase_count);
LFS_TESTBD_TRACE("lfs_testbd_getwear -> %"PRIu32, bd->wear[block]); LFS_TESTBD_TRACE("lfs_testbd_getwear -> %"PRIu32, bd->wear[block]);
return bd->wear[block]; return bd->wear[block];
} }
int lfs_testbd_setwear(const struct lfs_config *cfg, int lfs_testbd_setwear(lfs_testbd_t *bd,
lfs_block_t block, lfs_testbd_wear_t wear) { lfs_block_t block, lfs_testbd_wear_t wear) {
LFS_TESTBD_TRACE("lfs_testbd_setwear(%p, %"PRIu32")", (void*)cfg, block); LFS_TESTBD_TRACE("lfs_testbd_setwear(%p, %"PRIu32")", (void*)bd, block);
lfs_testbd_t *bd = cfg->context;
// check if block is valid // check if block is valid
LFS_ASSERT(bd->cfg->erase_cycles); LFS_ASSERT(bd->cfg->erase_cycles);
LFS_ASSERT(block < cfg->block_count); LFS_ASSERT(block < bd->cfg->erase_count);
bd->wear[block] = wear; bd->wear[block] = wear;

View File

@@ -2,7 +2,6 @@
* Testing block device, wraps filebd and rambd while providing a bunch * Testing block device, wraps filebd and rambd while providing a bunch
* of hooks for testing littlefs in various conditions. * of hooks for testing littlefs in various conditions.
* *
* Copyright (c) 2022, The littlefs authors.
* Copyright (c) 2017, Arm Limited. All rights reserved. * Copyright (c) 2017, Arm Limited. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause * SPDX-License-Identifier: BSD-3-Clause
*/ */
@@ -10,13 +9,11 @@
#define LFS_TESTBD_H #define LFS_TESTBD_H
#include "lfs.h" #include "lfs.h"
#include "lfs_util.h"
#include "bd/lfs_rambd.h" #include "bd/lfs_rambd.h"
#include "bd/lfs_filebd.h" #include "bd/lfs_filebd.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" extern "C" {
{
#endif #endif
@@ -46,7 +43,26 @@ typedef uint32_t lfs_testbd_wear_t;
typedef int32_t lfs_testbd_swear_t; typedef int32_t lfs_testbd_swear_t;
// testbd config, this is required for testing // testbd config, this is required for testing
struct lfs_testbd_config { struct lfs_testbd_cfg {
// Block device specific configuration, see the related config structs.
// May be NULL if the underlying implementation goes unused.
const struct lfs_rambd_cfg *rambd_cfg;
const struct lfs_filebd_cfg *filebd_cfg;
// Minimum size of block read. All read operations must be a
// multiple of this value.
lfs_size_t read_size;
// Minimum size of block program. All program operations must be a
// multiple of this value.
lfs_size_t prog_size;
// Size of an erasable block.
lfs_size_t erase_size;
// Number of erasable blocks on the device.
lfs_size_t erase_count;
// 8-bit erase value to use for simulating erases. -1 does not simulate // 8-bit erase value to use for simulating erases. -1 does not simulate
// erases, which can speed up testing by avoiding all the extra block-device // erases, which can speed up testing by avoiding all the extra block-device
// operations to store the erase value. // operations to store the erase value.
@@ -63,9 +79,6 @@ struct lfs_testbd_config {
// the program with exit. Simulates power-loss. 0 disables. // the program with exit. Simulates power-loss. 0 disables.
uint32_t power_cycles; uint32_t power_cycles;
// Optional buffer for RAM block device.
void *buffer;
// Optional buffer for wear // Optional buffer for wear
void *wear_buffer; void *wear_buffer;
}; };
@@ -73,70 +86,63 @@ struct lfs_testbd_config {
// testbd state // testbd state
typedef struct lfs_testbd { typedef struct lfs_testbd {
union { union {
struct { lfs_filebd_t filebd;
lfs_filebd_t bd; lfs_rambd_t rambd;
struct lfs_filebd_config cfg; } impl;
} file;
struct {
lfs_rambd_t bd;
struct lfs_rambd_config cfg;
} ram;
} u;
bool persist; bool persist;
uint32_t power_cycles; uint32_t power_cycles;
lfs_testbd_wear_t *wear; lfs_testbd_wear_t *wear;
const struct lfs_testbd_config *cfg; const struct lfs_testbd_cfg *cfg;
} lfs_testbd_t; } lfs_testbd_t;
/// Block device API /// /// Block device API ///
// Create a test block device using the geometry in lfs_config // Create a test block device using the geometry in lfs_cfg
// //
// Note that filebd is used if a path is provided, if path is NULL // Note that filebd is used if a path is provided, if path is NULL
// testbd will use rambd which can be much faster. // testbd will use rambd which can be much faster.
int lfs_testbd_create(const struct lfs_config *cfg, const char *path); int lfs_testbd_createcfg(lfs_testbd_t *bd, const char *path,
int lfs_testbd_createcfg(const struct lfs_config *cfg, const char *path, const struct lfs_testbd_cfg *cfg);
const struct lfs_testbd_config *bdcfg);
// Clean up memory associated with block device // Clean up memory associated with block device
int lfs_testbd_destroy(const struct lfs_config *cfg); int lfs_testbd_destroy(lfs_testbd_t *bd);
// Read a block // Read a block
int lfs_testbd_read(const struct lfs_config *cfg, lfs_block_t block, int lfs_testbd_read(lfs_testbd_t *bd, lfs_block_t block,
lfs_off_t off, void *buffer, lfs_size_t size); lfs_off_t off, void *buffer, lfs_size_t size);
// Program a block // Program a block
// //
// The block must have previously been erased. // The block must have previously been erased.
int lfs_testbd_prog(const struct lfs_config *cfg, lfs_block_t block, int lfs_testbd_prog(lfs_testbd_t *bd, lfs_block_t block,
lfs_off_t off, const void *buffer, lfs_size_t size); lfs_off_t off, const void *buffer, lfs_size_t size);
// Erase a block // Erase a block
// //
// A block must be erased before being programmed. The // A block must be erased before being programmed. The
// state of an erased block is undefined. // state of an erased block is undefined.
int lfs_testbd_erase(const struct lfs_config *cfg, lfs_block_t block); int lfs_testbd_erase(lfs_testbd_t *bd, lfs_block_t block);
// Sync the block device // Sync the block device
int lfs_testbd_sync(const struct lfs_config *cfg); int lfs_testbd_sync(lfs_testbd_t *bd);
/// Additional extended API for driving test features /// /// Additional extended API for driving test features ///
// Get simulated wear on a given block // Get simulated wear on a given block
lfs_testbd_swear_t lfs_testbd_getwear(const struct lfs_config *cfg, lfs_testbd_swear_t lfs_testbd_getwear(lfs_testbd_t *bd,
lfs_block_t block); lfs_block_t block);
// Manually set simulated wear on a given block // Manually set simulated wear on a given block
int lfs_testbd_setwear(const struct lfs_config *cfg, int lfs_testbd_setwear(lfs_testbd_t *bd,
lfs_block_t block, lfs_testbd_wear_t wear); lfs_block_t block, lfs_testbd_wear_t wear);
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ }
#endif #endif
#endif #endif

1758
lfs.c

File diff suppressed because it is too large Load Diff

411
lfs.h
View File

@@ -1,20 +1,16 @@
/* /*
* The little filesystem * The little filesystem
* *
* Copyright (c) 2022, The littlefs authors.
* Copyright (c) 2017, Arm Limited. All rights reserved. * Copyright (c) 2017, Arm Limited. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause * SPDX-License-Identifier: BSD-3-Clause
*/ */
#ifndef LFS_H #ifndef LFS_H
#define LFS_H #define LFS_H
#include <stdint.h>
#include <stdbool.h>
#include "lfs_util.h" #include "lfs_util.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" extern "C" {
{
#endif #endif
@@ -23,7 +19,7 @@ extern "C"
// Software library version // Software library version
// Major (top-nibble), incremented on backwards incompatible changes // Major (top-nibble), incremented on backwards incompatible changes
// Minor (bottom-nibble), incremented on feature additions // Minor (bottom-nibble), incremented on feature additions
#define LFS_VERSION 0x00020004 #define LFS_VERSION 0x00020002
#define LFS_VERSION_MAJOR (0xffff & (LFS_VERSION >> 16)) #define LFS_VERSION_MAJOR (0xffff & (LFS_VERSION >> 16))
#define LFS_VERSION_MINOR (0xffff & (LFS_VERSION >> 0)) #define LFS_VERSION_MINOR (0xffff & (LFS_VERSION >> 0))
@@ -50,8 +46,13 @@ typedef uint32_t lfs_block_t;
// info struct. Limited to <= 1022. Stored in superblock and must be // info struct. Limited to <= 1022. Stored in superblock and must be
// respected by other littlefs drivers. // respected by other littlefs drivers.
#ifndef LFS_NAME_MAX #ifndef LFS_NAME_MAX
#if defined(LFS_NAME_LIMIT) && \
LFS_NAME_LIMIT > 0 && LFS_NAME_MAX <= 1022
#define LFS_NAME_MAX LFS_NAME_LIMIT
#else
#define LFS_NAME_MAX 255 #define LFS_NAME_MAX 255
#endif #endif
#endif
// Maximum size of a file in bytes, may be redefined to limit to support other // 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 // drivers. Limited on disk to <= 4294967296. However, above 2147483647 the
@@ -59,34 +60,24 @@ typedef uint32_t lfs_block_t;
// incorrect values due to using signed integers. Stored in superblock and // incorrect values due to using signed integers. Stored in superblock and
// must be respected by other littlefs drivers. // must be respected by other littlefs drivers.
#ifndef LFS_FILE_MAX #ifndef LFS_FILE_MAX
#if defined(LFS_FILE_LIMIT) && \
LFS_FILE_LIMIT > 0 && LFS_FILE_LIMIT <= 4294967296
#define LFS_FILE_MAX LFS_FILE_LIMIT
#else
#define LFS_FILE_MAX 2147483647 #define LFS_FILE_MAX 2147483647
#endif #endif
#endif
// Maximum size of custom attributes in bytes, may be redefined, but there is // Maximum size of custom attributes in bytes, may be redefined, but there is
// no real benefit to using a smaller LFS_ATTR_MAX. Limited to <= 1022. // no real benefit to using a smaller LFS_ATTR_MAX. Limited to <= 1022.
#ifndef LFS_ATTR_MAX #ifndef LFS_ATTR_MAX
#if defined(LFS_ATTR_LIMIT) && \
LFS_ATTR_LIMIT > 0 && LFS_ATTR_LIMIT <= 1022
#define LFS_ATTR_MAX LFS_FILE_LIMIT
#else
#define LFS_ATTR_MAX 1022 #define LFS_ATTR_MAX 1022
#endif #endif
#endif
// Possible error codes, these are negative to allow
// valid positive return values
enum lfs_error {
LFS_ERR_OK = 0, // No error
LFS_ERR_IO = -5, // Error during device operation
LFS_ERR_CORRUPT = -84, // Corrupted
LFS_ERR_NOENT = -2, // No directory entry
LFS_ERR_EXIST = -17, // Entry already exists
LFS_ERR_NOTDIR = -20, // Entry is not a dir
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
LFS_ERR_NOATTR = -61, // No data/attr available
LFS_ERR_NAMETOOLONG = -36, // File name too long
};
// File types // File types
enum lfs_type { enum lfs_type {
@@ -125,25 +116,20 @@ enum lfs_type {
enum lfs_open_flags { enum lfs_open_flags {
// open flags // open flags
LFS_O_RDONLY = 1, // Open a file as read only LFS_O_RDONLY = 1, // Open a file as read only
#ifndef LFS_READONLY
LFS_O_WRONLY = 2, // Open a file as write only LFS_O_WRONLY = 2, // Open a file as write only
LFS_O_RDWR = 3, // Open a file as read and write LFS_O_RDWR = 3, // Open a file as read and write
LFS_O_CREAT = 0x0100, // Create a file if it does not exist LFS_O_CREAT = 0x0100, // Create a file if it does not exist
LFS_O_EXCL = 0x0200, // Fail if a file already exists LFS_O_EXCL = 0x0200, // Fail if a file already exists
LFS_O_TRUNC = 0x0400, // Truncate the existing file to zero size LFS_O_TRUNC = 0x0400, // Truncate the existing file to zero size
LFS_O_APPEND = 0x0800, // Move to end of file on every write LFS_O_APPEND = 0x0800, // Move to end of file on every write
#endif
// internally used flags // internally used flags
#ifndef LFS_READONLY
LFS_F_DIRTY = 0x010000, // File does not match storage LFS_F_DIRTY = 0x010000, // File does not match storage
LFS_F_WRITING = 0x020000, // File has been written since last flush LFS_F_WRITING = 0x020000, // File has been written since last flush
#endif
LFS_F_READING = 0x040000, // File has been read since last flush LFS_F_READING = 0x040000, // File has been read since last flush
#ifndef LFS_READONLY LFS_F_ERRED = 0x080000, // An error occured during write
LFS_F_ERRED = 0x080000, // An error occurred during write
#endif
LFS_F_INLINE = 0x100000, // Currently inlined in directory entry LFS_F_INLINE = 0x100000, // Currently inlined in directory entry
LFS_F_OPENED = 0x200000, // File has been opened
}; };
// File seek flags // File seek flags
@@ -155,115 +141,297 @@ enum lfs_whence_flags {
// Configuration provided during initialization of the littlefs // Configuration provided during initialization of the littlefs
struct lfs_config {
// If every config option is provided at compile time, littlefs switches
// to "LFS_STATICCFG" mode. The dynamic lfs_cfg struct is not included in
// the lfs_t struct, and *cfg functions are no longer available.
#if defined(LFS_BD_READ) && \
defined(LFS_BD_PROG) && \
defined(LFS_BD_ERASE) && \
defined(LFS_BD_SYNC) && \
defined(LFS_READ_SIZE) && \
defined(LFS_PROG_SIZE) && \
defined(LFS_BLOCK_SIZE) && \
defined(LFS_BLOCK_COUNT) && \
defined(LFS_BLOCK_CYCLES) && \
defined(LFS_BUFFER_SIZE) && \
defined(LFS_LOOKAHEAD_SIZE) && \
defined(LFS_READ_BUFFER) && \
defined(LFS_PROG_BUFFER) && \
defined(LFS_LOOKAHEAD_BUFFER) && \
defined(LFS_NAME_LIMIT) && \
defined(LFS_FILE_LIMIT) && \
defined(LFS_ATTR_LIMIT)
#define LFS_STATICCFG
#endif
// Dynamic config struct
#ifndef LFS_STATICCFG
struct lfs_cfg {
#endif
// Opaque user provided context that can be used to pass // Opaque user provided context that can be used to pass
// information to the block device operations // information to the block device operations
void *context; #if !(defined(LFS_BD_READ) && \
defined(LFS_BD_PROG) && \
defined(LFS_BD_ERASE) && \
defined(LFS_BD_SYNC))
void *bd_ctx;
#endif
// Read a region in a block. Negative error codes are propogated // Read a region in a block. Negative error codes are propogated
// to the user. // to the user.
int (*read)(const struct lfs_config *c, lfs_block_t block, #ifndef LFS_BD_READ
int (*bd_read)(void *ctx, lfs_block_t block,
lfs_off_t off, void *buffer, lfs_size_t size); lfs_off_t off, void *buffer, lfs_size_t size);
#define LFS_CFG_BD_READ(cfg, block, off, buffer, size) \
(cfg)->bd_read((cfg)->bd_ctx, block, off, buffer, size)
#else
#define LFS_CFG_BD_READ(cfg, block, off, buffer, size) \
lfs_bd_read(block, off, buffer, size)
#endif
// Program a region in a block. The block must have previously // Program a region in a block. The block must have previously
// been erased. Negative error codes are propogated to the user. // been erased. Negative error codes are propogated to the user.
// May return LFS_ERR_CORRUPT if the block should be considered bad. // May return LFS_ERR_CORRUPT if the block should be considered bad.
int (*prog)(const struct lfs_config *c, lfs_block_t block, #ifndef LFS_BD_PROG
int (*bd_prog)(void *ctx, lfs_block_t block,
lfs_off_t off, const void *buffer, lfs_size_t size); lfs_off_t off, const void *buffer, lfs_size_t size);
#define LFS_CFG_BD_PROG(cfg, block, off, buffer, size) \
(cfg)->bd_prog((cfg)->bd_ctx, block, off, buffer, size)
#else
#define LFS_CFG_BD_PROG(cfg, block, off, buffer, size) \
lfs_bd_prog(block, off, buffer, size)
#endif
// Erase a block. A block must be erased before being programmed. // Erase a block. A block must be erased before being programmed.
// The state of an erased block is undefined. Negative error codes // The state of an erased block is undefined. Negative error codes
// are propogated to the user. // are propogated to the user.
// May return LFS_ERR_CORRUPT if the block should be considered bad. // May return LFS_ERR_CORRUPT if the block should be considered bad.
int (*erase)(const struct lfs_config *c, lfs_block_t block); #ifndef LFS_BD_ERASE
int (*bd_erase)(void *ctx, lfs_block_t block);
#define LFS_CFG_BD_ERASE(cfg, block) \
(cfg)->bd_erase((cfg)->bd_ctx, block)
#else
#define LFS_CFG_BD_ERASE(cfg, block) \
lfs_bd_erase(block)
#endif
// Sync the state of the underlying block device. Negative error codes // Sync the state of the underlying block device. Negative error codes
// are propogated to the user. // are propogated to the user.
int (*sync)(const struct lfs_config *c); #ifndef LFS_BD_SYNC
int (*bd_sync)(void *ctx);
#ifdef LFS_THREADSAFE #define LFS_CFG_BD_SYNC(cfg) \
// Lock the underlying block device. Negative error codes (cfg)->bd_sync((cfg)->bd_ctx)
// are propogated to the user. #else
int (*lock)(const struct lfs_config *c); #define LFS_CFG_BD_SYNC(cfg) \
lfs_bd_sync()
// Unlock the underlying block device. Negative error codes #endif
// are propogated to the user.
int (*unlock)(const struct lfs_config *c);
#endif
// Minimum size of a block read. All read operations will be a // Minimum size of a block read. All read operations will be a
// multiple of this value. // multiple of this value.
#ifndef LFS_READ_SIZE
lfs_size_t read_size; lfs_size_t read_size;
#define LFS_CFG_READ_SIZE(cfg) (cfg)->read_size
#else
#define LFS_CFG_READ_SIZE(cfg) LFS_READ_SIZE
#endif
// Minimum size of a block program. All program operations will be a // Minimum size of a block program. All program operations will be a
// multiple of this value. // multiple of this value.
#ifndef LFS_PROG_SIZE
lfs_size_t prog_size; lfs_size_t prog_size;
#define LFS_CFG_PROG_SIZE(cfg) (cfg)->prog_size
#else
#define LFS_CFG_PROG_SIZE(cfg) LFS_PROG_SIZE
#endif
// Size of an erasable block. This does not impact ram consumption and // Size of an erasable block. This does not impact ram consumption and
// may be larger than the physical erase size. However, non-inlined files // may be larger than the physical erase size. However, non-inlined files
// take up at minimum one block. Must be a multiple of the read // take up at minimum one block. Must be a multiple of the read
// and program sizes. // and program sizes.
#ifndef LFS_BLOCK_SIZE
lfs_size_t block_size; lfs_size_t block_size;
#define LFS_CFG_BLOCK_SIZE(cfg) (cfg)->block_size
#else
#define LFS_CFG_BLOCK_SIZE(cfg) LFS_BLOCK_SIZE
#endif
// Number of erasable blocks on the device. // Number of erasable blocks on the device.
#ifndef LFS_BLOCK_COUNT
lfs_size_t block_count; lfs_size_t block_count;
#define LFS_CFG_BLOCK_COUNT(cfg) (cfg)->block_count
#else
#define LFS_CFG_BLOCK_COUNT(cfg) LFS_BLOCK_COUNT
#endif
// Number of erase cycles before littlefs evicts metadata logs and moves // Number of erase cycles before littlefs evicts metadata logs and moves
// the metadata to another block. Suggested values are in the // the metadata to another block. Suggested values are in the
// range 100-1000, with large values having better performance at the cost // range 100-1000, with large values having better performance at the cost
// of less consistent wear distribution. // of less consistent wear distribution.
// //
// Set to -1 to disable block-level wear-leveling. // Set to -1 to disable block-level wear-leveling.
#ifndef LFS_BLOCK_CYCLES
int32_t block_cycles; int32_t block_cycles;
#define LFS_CFG_BLOCK_CYCLES(cfg) (cfg)->block_cycles
#else
#define LFS_CFG_BLOCK_CYCLES(cfg) LFS_BLOCK_CYCLES
#endif
// Size of block caches. Each cache buffers a portion of a block in RAM. // Size of internal buffers used to cache slices of blocks in RAM.
// The littlefs needs a read cache, a program cache, and one additional // The littlefs needs a read buffer, a program buffer, and one additional
// cache per file. Larger caches can improve performance by storing more // buffer per file. Larger buffers can improve performance by storing more
// data and reducing the number of disk accesses. Must be a multiple of // data and reducing the number of disk accesses. Must be a multiple of
// the read and program sizes, and a factor of the block size. // the read and program sizes, and a factor of the block size.
lfs_size_t cache_size; #ifndef LFS_BUFFER_SIZE
lfs_size_t buffer_size;
#define LFS_CFG_BUFFER_SIZE(cfg) (cfg)->buffer_size
#else
#define LFS_CFG_BUFFER_SIZE(cfg) LFS_BUFFER_SIZE
#endif
// Size of the lookahead buffer in bytes. A larger lookahead buffer // Size of the lookahead buffer in bytes. A larger lookahead buffer
// increases the number of blocks found during an allocation pass. The // increases the number of blocks found during an allocation pass. The
// lookahead buffer is stored as a compact bitmap, so each byte of RAM // lookahead buffer is stored as a compact bitmap, so each byte of RAM
// can track 8 blocks. Must be a multiple of 8. // can track 8 blocks. Must be a multiple of 8.
#ifndef LFS_LOOKAHEAD_SIZE
lfs_size_t lookahead_size; lfs_size_t lookahead_size;
#define LFS_CFG_LOOKAHEAD_SIZE(cfg) (cfg)->lookahead_size
#else
#define LFS_CFG_LOOKAHEAD_SIZE(cfg) LFS_LOOKAHEAD_SIZE
#endif
// Optional statically allocated read buffer. Must be cache_size. // Optional statically allocated read buffer. Must be cache_size.
// By default lfs_malloc is used to allocate this buffer. // By default lfs_malloc is used to allocate this buffer.
#ifndef LFS_READ_BUFFER
void *read_buffer; void *read_buffer;
#define LFS_CFG_READ_BUFFER(cfg) (cfg)->read_buffer
#else
#define LFS_CFG_READ_BUFFER(cfg) LFS_READ_BUFFER
#endif
// Optional statically allocated program buffer. Must be cache_size. // Optional statically allocated program buffer. Must be cache_size.
// By default lfs_malloc is used to allocate this buffer. // By default lfs_malloc is used to allocate this buffer.
#ifndef LFS_PROG_BUFFER
void *prog_buffer; void *prog_buffer;
#define LFS_CFG_PROG_BUFFER(cfg) (cfg)->prog_buffer
#else
#define LFS_CFG_PROG_BUFFER(cfg) LFS_PROG_BUFFER
#endif
// Optional statically allocated lookahead buffer. Must be lookahead_size // Optional statically allocated lookahead buffer. Must be lookahead_size
// and aligned to a 32-bit boundary. By default lfs_malloc is used to // and aligned to a 32-bit boundary. By default lfs_malloc is used to
// allocate this buffer. // allocate this buffer.
#ifndef LFS_LOOKAHEAD_BUFFER
void *lookahead_buffer; void *lookahead_buffer;
#define LFS_CFG_LOOKAHEAD_BUFFER(cfg) (cfg)->lookahead_buffer
#else
#define LFS_CFG_LOOKAHEAD_BUFFER(cfg) LFS_LOOKAHEAD_BUFFER
#endif
// Optional upper limit on length of file names in bytes. No downside for // Optional upper limit on length of file names in bytes. No downside for
// larger names except the size of the info struct which is controlled by // larger names except the size of the info struct which is controlled by
// the LFS_NAME_MAX define. Defaults to LFS_NAME_MAX when zero. Stored in // the LFS_NAME_MAX define. Defaults to LFS_NAME_MAX when zero. Stored in
// superblock and must be respected by other littlefs drivers. // superblock and must be respected by other littlefs drivers.
lfs_size_t name_max; #ifndef LFS_NAME_LIMIT
lfs_size_t name_limit;
#define LFS_CFG_NAME_LIMIT(cfg) (cfg)->name_limit
#else
#define LFS_CFG_NAME_LIMIT(cfg) LFS_NAME_LIMIT
#endif
// Optional upper limit on files in bytes. No downside for larger files // 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 // but must be <= LFS_FILE_MAX. Defaults to LFS_FILE_MAX when zero. Stored
// in superblock and must be respected by other littlefs drivers. // in superblock and must be respected by other littlefs drivers.
lfs_size_t file_max; #ifndef LFS_FILE_LIMIT
lfs_size_t file_limit;
#define LFS_CFG_FILE_LIMIT(cfg) (cfg)->file_limit
#else
#define LFS_CFG_FILE_LIMIT(cfg) LFS_FILE_LIMIT
#endif
// Optional upper limit on custom attributes in bytes. No downside for // Optional upper limit on custom attributes in bytes. No downside for
// larger attributes size but must be <= LFS_ATTR_MAX. Defaults to // larger attributes size but must be <= LFS_ATTR_MAX. Defaults to
// LFS_ATTR_MAX when zero. // LFS_ATTR_MAX when zero.
lfs_size_t attr_max; #ifndef LFS_ATTR_LIMIT
lfs_size_t attr_limit;
// Optional upper limit on total space given to metadata pairs in bytes. On #define LFS_CFG_ATTR_LIMIT(cfg) (cfg)->attr_limit
// devices with large blocks (e.g. 128kB) setting this to a low size (2-8kB) #else
// can help bound the metadata compaction time. Must be <= block_size. #define LFS_CFG_ATTR_LIMIT(cfg) LFS_ATTR_LIMIT
// Defaults to block_size when zero. #endif
lfs_size_t metadata_max; #ifndef LFS_STATICCFG
}; };
#endif
// Configurable callbacks are a bit special, when LFS_BD_* is defined,
// LFS_CFG_* instead expands into a call to an extern lfs_bd_*, which
// must be defined by the user. This preserves type-safety of the
// callbacks.
#ifdef LFS_BD_READ
extern int lfs_bd_read(lfs_block_t block,
lfs_off_t off, void *buffer, lfs_size_t size);
#endif
#ifdef LFS_BD_PROG
extern int lfs_bd_prog(lfs_block_t block,
lfs_off_t off, const void *buffer, lfs_size_t size);
#endif
#ifdef LFS_BD_ERASE
extern int lfs_bd_erase(lfs_block_t block);
#endif
#ifdef LFS_BD_SYNC
extern int lfs_bd_sync(void);
#endif
// If every config option is provided at compile time, littlefs switches
// to "LFS_FILE_STATICCFG" mode. The dynamic lfs_file_cfg struct is not
// included in the lfs_file_t struct, and *cfg functions are no longer
// available.
#if defined(LFS_FILE_BUFFER) && \
defined(LFS_FILE_ATTRS) && \
defined(LFS_FILE_ATTR_COUNT)
#define LFS_STATICCFG
#endif
#ifndef LFS_FILE_STATICCFG
// Optional configuration provided during lfs_file_opencfg
struct lfs_file_cfg {
#endif
// Optional statically allocated file buffer. Must be cache_size.
// By default lfs_malloc is used to allocate this buffer.
#ifndef LFS_FILE_BUFFER
void *buffer;
#define LFS_FILE_CFG_BUFFER(cfg) (cfg)->buffer
#else
#define LFS_FILE_CFG_BUFFER(cfg) LFS_FILE_BUFFER
#endif
// Optional list of custom attributes related to the file. If the file
// is opened with read access, these attributes will be read from disk
// during the open call. If the file is opened with write access, the
// attributes will be written to disk every file sync or close. This
// write occurs atomically with update to the file's contents.
//
// Custom attributes are uniquely identified by an 8-bit type and limited
// to LFS_ATTR_MAX bytes. When read, if the stored attribute is smaller
// than the buffer, it will be padded with zeros. If the stored attribute
// is larger, then it will be silently truncated. If the attribute is not
// found, it will be created implicitly.
#ifndef LFS_FILE_ATTRS
struct lfs_attr *attrs;
#define LFS_FILE_CFG_ATTRS(cfg) (cfg)->attrs
#else
#define LFS_FILE_CFG_ATTRS(cfg) LFS_FILE_ATTRS
#endif
// Number of custom attributes in the list
#ifndef LFS_FILE_ATTR_COUNT
lfs_size_t attr_count;
#define LFS_FILE_CFG_ATTR_COUNT(cfg) (cfg)->attr_count
#else
#define LFS_FILE_CFG_ATTR_COUNT(cfg) LFS_FILE_ATTR_COUNT
#endif
#ifndef LFS_FILE_STATICCFG
};
#endif
// File info structure // File info structure
struct lfs_info { struct lfs_info {
@@ -294,29 +462,6 @@ struct lfs_attr {
lfs_size_t size; lfs_size_t size;
}; };
// Optional configuration provided during lfs_file_opencfg
struct lfs_file_config {
// Optional statically allocated file buffer. Must be cache_size.
// By default lfs_malloc is used to allocate this buffer.
void *buffer;
// Optional list of custom attributes related to the file. If the file
// is opened with read access, these attributes will be read from disk
// during the open call. If the file is opened with write access, the
// attributes will be written to disk every file sync or close. This
// write occurs atomically with update to the file's contents.
//
// Custom attributes are uniquely identified by an 8-bit type and limited
// to LFS_ATTR_MAX bytes. When read, if the stored attribute is smaller
// than the buffer, it will be padded with zeros. If the stored attribute
// is larger, then it will be silently truncated. If the attribute is not
// found, it will be created implicitly.
struct lfs_attr *attrs;
// Number of custom attributes in the list
lfs_size_t attr_count;
};
/// internal littlefs data structures /// /// internal littlefs data structures ///
typedef struct lfs_cache { typedef struct lfs_cache {
@@ -366,16 +511,18 @@ typedef struct lfs_file {
lfs_off_t off; lfs_off_t off;
lfs_cache_t cache; lfs_cache_t cache;
const struct lfs_file_config *cfg; #ifndef LFS_FILE_STATICCFG
const struct lfs_file_cfg *cfg;
#endif
} lfs_file_t; } lfs_file_t;
typedef struct lfs_superblock { typedef struct lfs_superblock {
uint32_t version; uint32_t version;
lfs_size_t block_size; lfs_size_t block_size;
lfs_size_t block_count; lfs_size_t block_count;
lfs_size_t name_max; lfs_size_t name_limit;
lfs_size_t file_max; lfs_size_t file_limit;
lfs_size_t attr_max; lfs_size_t attr_limit;
} lfs_superblock_t; } lfs_superblock_t;
typedef struct lfs_gstate { typedef struct lfs_gstate {
@@ -409,10 +556,12 @@ typedef struct lfs {
uint32_t *buffer; uint32_t *buffer;
} free; } free;
const struct lfs_config *cfg; #ifndef LFS_STATICCFG
lfs_size_t name_max; const struct lfs_cfg *cfg;
lfs_size_t file_max; #endif
lfs_size_t attr_max; lfs_size_t name_limit;
lfs_size_t file_limit;
lfs_size_t attr_limit;
#ifdef LFS_MIGRATE #ifdef LFS_MIGRATE
struct lfs1 *lfs1; struct lfs1 *lfs1;
@@ -422,18 +571,38 @@ typedef struct lfs {
/// Filesystem functions /// /// Filesystem functions ///
#ifndef LFS_READONLY #if defined(LFS_STATICCFG)
// Format a block device with the littlefs // Format a block device with littlefs
//
// Requires a littlefs object. This clobbers the littlefs object, and does
// not leave the filesystem mounted.
//
// Returns a negative error code on failure.
int lfs_format(lfs_t *lfs);
#endif
#if !defined(LFS_STATICCFG)
// Format a block device with littlefs with per-filesystem configuration
// //
// Requires a littlefs object and config struct. This clobbers the littlefs // Requires a littlefs object and config struct. This clobbers the littlefs
// object, and does not leave the filesystem mounted. The config struct must // object, and does not leave the filesystem mounted. The config struct must
// be zeroed for defaults and backwards compatibility. // be zeroed for defaults and backwards compatibility.
// //
// Returns a negative error code on failure. // Returns a negative error code on failure.
int lfs_format(lfs_t *lfs, const struct lfs_config *config); int lfs_formatcfg(lfs_t *lfs, const struct lfs_cfg *config);
#endif #endif
// Mounts a littlefs #if defined(LFS_STATICCFG)
// Mounts littlefs
//
// Requires a littlefs object and static configuration.
//
// Returns a negative error code on failure.
int lfs_mount(lfs_t *lfs);
#endif
#if !defined(LFS_STATICCFG)
// Mounts a littlefs with per-filesystem configuration
// //
// Requires a littlefs object and config struct. Multiple filesystems // Requires a littlefs object and config struct. Multiple filesystems
// may be mounted simultaneously with multiple littlefs objects. Both // may be mounted simultaneously with multiple littlefs objects. Both
@@ -441,7 +610,8 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *config);
// be zeroed for defaults and backwards compatibility. // be zeroed for defaults and backwards compatibility.
// //
// Returns a negative error code on failure. // Returns a negative error code on failure.
int lfs_mount(lfs_t *lfs, const struct lfs_config *config); int lfs_mountcfg(lfs_t *lfs, const struct lfs_cfg *config);
#endif
// Unmounts a littlefs // Unmounts a littlefs
// //
@@ -451,15 +621,12 @@ int lfs_unmount(lfs_t *lfs);
/// General operations /// /// General operations ///
#ifndef LFS_READONLY
// Removes a file or directory // Removes a file or directory
// //
// If removing a directory, the directory must be empty. // If removing a directory, the directory must be empty.
// Returns a negative error code on failure. // Returns a negative error code on failure.
int lfs_remove(lfs_t *lfs, const char *path); int lfs_remove(lfs_t *lfs, const char *path);
#endif
#ifndef LFS_READONLY
// Rename or move a file or directory // Rename or move a file or directory
// //
// If the destination exists, it must match the source in type. // If the destination exists, it must match the source in type.
@@ -467,7 +634,6 @@ int lfs_remove(lfs_t *lfs, const char *path);
// //
// Returns a negative error code on failure. // Returns a negative error code on failure.
int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath); int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath);
#endif
// Find info about a file or directory // Find info about a file or directory
// //
@@ -490,7 +656,6 @@ int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info);
lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path, lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path,
uint8_t type, void *buffer, lfs_size_t size); uint8_t type, void *buffer, lfs_size_t size);
#ifndef LFS_READONLY
// Set custom attributes // Set custom attributes
// //
// Custom attributes are uniquely identified by an 8-bit type and limited // Custom attributes are uniquely identified by an 8-bit type and limited
@@ -500,16 +665,13 @@ lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path,
// Returns a negative error code on failure. // Returns a negative error code on failure.
int lfs_setattr(lfs_t *lfs, const char *path, int lfs_setattr(lfs_t *lfs, const char *path,
uint8_t type, const void *buffer, lfs_size_t size); uint8_t type, const void *buffer, lfs_size_t size);
#endif
#ifndef LFS_READONLY
// Removes a custom attribute // Removes a custom attribute
// //
// If an attribute is not found, nothing happens. // If an attribute is not found, nothing happens.
// //
// Returns a negative error code on failure. // Returns a negative error code on failure.
int lfs_removeattr(lfs_t *lfs, const char *path, uint8_t type); int lfs_removeattr(lfs_t *lfs, const char *path, uint8_t type);
#endif
/// File operations /// /// File operations ///
@@ -523,7 +685,8 @@ int lfs_removeattr(lfs_t *lfs, const char *path, uint8_t type);
int lfs_file_open(lfs_t *lfs, lfs_file_t *file, int lfs_file_open(lfs_t *lfs, lfs_file_t *file,
const char *path, int flags); const char *path, int flags);
// Open a file with extra configuration #if !defined(LFS_FILE_STATICCFG)
// Open a file with per-file configuration
// //
// The mode that the file is opened in is determined by the flags, which // The mode that the file is opened in is determined by the flags, which
// are values from the enum lfs_open_flags that are bitwise-ored together. // are values from the enum lfs_open_flags that are bitwise-ored together.
@@ -535,7 +698,8 @@ int lfs_file_open(lfs_t *lfs, lfs_file_t *file,
// Returns a negative error code on failure. // Returns a negative error code on failure.
int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file, int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file,
const char *path, int flags, const char *path, int flags,
const struct lfs_file_config *config); const struct lfs_file_cfg *config);
#endif
// Close a file // Close a file
// //
@@ -558,7 +722,6 @@ int lfs_file_sync(lfs_t *lfs, lfs_file_t *file);
lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file,
void *buffer, lfs_size_t size); void *buffer, lfs_size_t size);
#ifndef LFS_READONLY
// Write data to file // Write data to file
// //
// Takes a buffer and size indicating the data to write. The file will not // Takes a buffer and size indicating the data to write. The file will not
@@ -567,7 +730,6 @@ lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file,
// Returns the number of bytes written, or a negative error code on failure. // Returns the number of bytes written, or a negative error code on failure.
lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file,
const void *buffer, lfs_size_t size); const void *buffer, lfs_size_t size);
#endif
// Change the position of the file // Change the position of the file
// //
@@ -576,12 +738,10 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file,
lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file, lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file,
lfs_soff_t off, int whence); lfs_soff_t off, int whence);
#ifndef LFS_READONLY
// Truncates the size of the file to the specified size // Truncates the size of the file to the specified size
// //
// Returns a negative error code on failure. // Returns a negative error code on failure.
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);
#endif
// Return the position of the file // Return the position of the file
// //
@@ -604,12 +764,10 @@ lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file);
/// Directory operations /// /// Directory operations ///
#ifndef LFS_READONLY
// Create a directory // Create a directory
// //
// Returns a negative error code on failure. // Returns a negative error code on failure.
int lfs_mkdir(lfs_t *lfs, const char *path); int lfs_mkdir(lfs_t *lfs, const char *path);
#endif
// Open a directory // Open a directory
// //
@@ -671,26 +829,39 @@ lfs_ssize_t lfs_fs_size(lfs_t *lfs);
// Returns a negative error code on failure. // Returns a negative error code on failure.
int lfs_fs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data); int lfs_fs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data);
#ifndef LFS_READONLY #if defined(LFS_MIGRATE) && defined(LFS_STATICCFG)
#ifdef LFS_MIGRATE
// Attempts to migrate a previous version of littlefs // Attempts to migrate a previous version of littlefs
// //
// Behaves similarly to the lfs_format function. Attempts to mount // Behaves similarly to the lfs_format function. Attempts to mount
// the previous version of littlefs and update the filesystem so it can be // the previous version of littlefs and update the filesystem so it can be
// mounted with the current version of littlefs. // mounted with the current version of littlefs.
// //
// Requires a littlefs object. This clobbers the littlefs object, and does
// not leave the filesystem mounted.
//
// Returns a negative error code on failure.
int lfs_migrate(lfs_t *lfs, const struct lfs_cfg *cfg);
#endif
#if defined(LFS_MIGRATE) && !defined(LFS_STATICCFG)
// Attempts to migrate a previous version of littlefs with per-filesystem
// configuration
//
// Behaves similarly to the lfs_format function. Attempts to mount
// the previous version of littlefs and update the filesystem so it can be
// mounted with the current version of littlefs.
//
// Requires a littlefs object and config struct. This clobbers the littlefs // Requires a littlefs object and config struct. This clobbers the littlefs
// object, and does not leave the filesystem mounted. The config struct must // object, and does not leave the filesystem mounted. The config struct must
// be zeroed for defaults and backwards compatibility. // be zeroed for defaults and backwards compatibility.
// //
// Returns a negative error code on failure. // Returns a negative error code on failure.
int lfs_migrate(lfs_t *lfs, const struct lfs_config *cfg); int lfs_migratecfg(lfs_t *lfs, const struct lfs_cfg *cfg);
#endif
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ }
#endif #endif
#endif #endif

View File

@@ -1,14 +1,13 @@
/* /*
* lfs util functions * lfs util functions
* *
* Copyright (c) 2022, The littlefs authors.
* Copyright (c) 2017, Arm Limited. All rights reserved. * Copyright (c) 2017, Arm Limited. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause * SPDX-License-Identifier: BSD-3-Clause
*/ */
#include "lfs_util.h" #include "lfs_util.h"
// Only compile if user does not provide custom config // Only compile if user does not provide custom config
#ifndef LFS_CONFIG #ifndef LFS_UTIL
// Software CRC implementation with small lookup table // Software CRC implementation with small lookup table

View File

@@ -1,23 +1,23 @@
/* /*
* lfs utility functions * lfs utility functions
* *
* Copyright (c) 2022, The littlefs authors.
* Copyright (c) 2017, Arm Limited. All rights reserved. * Copyright (c) 2017, Arm Limited. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause * SPDX-License-Identifier: BSD-3-Clause
*
* Can be overridden by users with their own configuration by defining
* LFS_UTIL as a header file (-DLFS_UTIL=my_lfs_util.h)
*
* If LFS_UTIL is defined, none of the default definitions will be
* emitted and must be provided by the user's header file. To start, I would
* suggest copying lfs_util.h and modifying as needed.
*/ */
#ifndef LFS_UTIL_H #ifndef LFS_UTIL_H
#define LFS_UTIL_H #define LFS_UTIL_H
// Users can override lfs_util.h with their own configuration by defining #ifdef LFS_UTIL
// LFS_CONFIG as a header file to include (-DLFS_CONFIG=lfs_config.h).
//
// If LFS_CONFIG is used, none of the default utils will be emitted and must be
// provided by the config file. To start, I would suggest copying lfs_util.h
// and modifying as needed.
#ifdef LFS_CONFIG
#define LFS_STRINGIZE(x) LFS_STRINGIZE2(x) #define LFS_STRINGIZE(x) LFS_STRINGIZE2(x)
#define LFS_STRINGIZE2(x) #x #define LFS_STRINGIZE2(x) #x
#include LFS_STRINGIZE(LFS_CONFIG) #include LFS_STRINGIZE(LFS_UTIL)
#else #else
// System includes // System includes
@@ -40,17 +40,37 @@
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
extern "C" extern "C" {
{
#endif #endif
// Possible error codes, these are negative to allow valid positive
// return values. May be redefined to system-specific error codes as long
// as they fit in a negative integer.
enum lfs_error {
LFS_ERR_OK = 0, // No error
LFS_ERR_IO = -5, // Error during device operation
LFS_ERR_CORRUPT = -84, // Corrupted
LFS_ERR_NOENT = -2, // No directory entry
LFS_ERR_EXIST = -17, // Entry already exists
LFS_ERR_NOTDIR = -20, // Entry is not a dir
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
LFS_ERR_NOATTR = -61, // No data/attr available
LFS_ERR_NAMETOOLONG = -36, // File name too long
};
// Macros, may be replaced by system specific wrappers. Arguments to these // Macros, may be replaced by system specific wrappers. Arguments to these
// macros must not have side-effects as the macros can be removed for a smaller // macros must not have side-effects as the macros can be removed for a smaller
// code footprint // code footprint
// Logging functions // Logging functions
#ifndef LFS_TRACE
#ifdef LFS_YES_TRACE #ifdef LFS_YES_TRACE
#define LFS_TRACE_(fmt, ...) \ #define LFS_TRACE_(fmt, ...) \
printf("%s:%d:trace: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) printf("%s:%d:trace: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
@@ -58,9 +78,7 @@ extern "C"
#else #else
#define LFS_TRACE(...) #define LFS_TRACE(...)
#endif #endif
#endif
#ifndef LFS_DEBUG
#ifndef LFS_NO_DEBUG #ifndef LFS_NO_DEBUG
#define LFS_DEBUG_(fmt, ...) \ #define LFS_DEBUG_(fmt, ...) \
printf("%s:%d:debug: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) printf("%s:%d:debug: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
@@ -68,9 +86,7 @@ extern "C"
#else #else
#define LFS_DEBUG(...) #define LFS_DEBUG(...)
#endif #endif
#endif
#ifndef LFS_WARN
#ifndef LFS_NO_WARN #ifndef LFS_NO_WARN
#define LFS_WARN_(fmt, ...) \ #define LFS_WARN_(fmt, ...) \
printf("%s:%d:warn: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) printf("%s:%d:warn: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
@@ -78,9 +94,7 @@ extern "C"
#else #else
#define LFS_WARN(...) #define LFS_WARN(...)
#endif #endif
#endif
#ifndef LFS_ERROR
#ifndef LFS_NO_ERROR #ifndef LFS_NO_ERROR
#define LFS_ERROR_(fmt, ...) \ #define LFS_ERROR_(fmt, ...) \
printf("%s:%d:error: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) printf("%s:%d:error: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
@@ -88,16 +102,13 @@ extern "C"
#else #else
#define LFS_ERROR(...) #define LFS_ERROR(...)
#endif #endif
#endif
// Runtime assertions // Runtime assertions
#ifndef LFS_ASSERT
#ifndef LFS_NO_ASSERT #ifndef LFS_NO_ASSERT
#define LFS_ASSERT(test) assert(test) #define LFS_ASSERT(test) assert(test)
#else #else
#define LFS_ASSERT(test) #define LFS_ASSERT(test)
#endif #endif
#endif
// Builtin functions, these may be replaced by more efficient // Builtin functions, these may be replaced by more efficient
@@ -161,8 +172,8 @@ static inline uint32_t lfs_popc(uint32_t a) {
// Find the sequence comparison of a and b, this is the distance // Find the sequence comparison of a and b, this is the distance
// between a and b ignoring overflow // between a and b ignoring overflow
static inline int lfs_scmp(uint32_t a, uint32_t b) { static inline int32_t lfs_scmp(uint32_t a, uint32_t b) {
return (int)(unsigned)(a - b); return (int32_t)(uint32_t)(a - b);
} }
// Convert between 32-bit little-endian and native order // Convert between 32-bit little-endian and native order
@@ -238,7 +249,7 @@ static inline void lfs_free(void *p) {
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ }
#endif #endif
#endif #endif

View File

@@ -1,214 +0,0 @@
#!/usr/bin/env python3
#
# Script to find code size at the function level. Basically just a bit wrapper
# around nm with some extra conveniences for comparing builds. Heavily inspired
# by Linux's Bloat-O-Meter.
#
import os
import glob
import itertools as it
import subprocess as sp
import shlex
import re
import csv
import collections as co
OBJ_PATHS = ['*.o', 'bd/*.o']
def collect(paths, **args):
results = co.defaultdict(lambda: 0)
pattern = re.compile(
'^(?P<size>[0-9a-fA-F]+)' +
' (?P<type>[%s])' % re.escape(args['type']) +
' (?P<func>.+?)$')
for path in paths:
# note nm-tool may contain extra args
cmd = args['nm_tool'] + ['--size-sort', path]
if args.get('verbose'):
print(' '.join(shlex.quote(c) for c in cmd))
proc = sp.Popen(cmd,
stdout=sp.PIPE,
stderr=sp.PIPE if not args.get('verbose') else None,
universal_newlines=True)
for line in proc.stdout:
m = pattern.match(line)
if m:
results[(path, m.group('func'))] += int(m.group('size'), 16)
proc.wait()
if proc.returncode != 0:
if not args.get('verbose'):
for line in proc.stderr:
sys.stdout.write(line)
sys.exit(-1)
flat_results = []
for (file, func), size in results.items():
# map to source files
if args.get('build_dir'):
file = re.sub('%s/*' % re.escape(args['build_dir']), '', file)
# discard internal functions
if func.startswith('__'):
continue
# discard .8449 suffixes created by optimizer
func = re.sub('\.[0-9]+', '', func)
flat_results.append((file, func, size))
return flat_results
def main(**args):
# find sizes
if not args.get('use', None):
# find .o files
paths = []
for path in args['obj_paths']:
if os.path.isdir(path):
path = path + '/*.o'
for path in glob.glob(path):
paths.append(path)
if not paths:
print('no .obj files found in %r?' % args['obj_paths'])
sys.exit(-1)
results = collect(paths, **args)
else:
with open(args['use']) as f:
r = csv.DictReader(f)
results = [
( result['file'],
result['function'],
int(result['size']))
for result in r]
total = 0
for _, _, size in results:
total += size
# find previous results?
if args.get('diff'):
with open(args['diff']) as f:
r = csv.DictReader(f)
prev_results = [
( result['file'],
result['function'],
int(result['size']))
for result in r]
prev_total = 0
for _, _, size in prev_results:
prev_total += size
# write results to CSV
if args.get('output'):
with open(args['output'], 'w') as f:
w = csv.writer(f)
w.writerow(['file', 'function', 'size'])
for file, func, size in sorted(results):
w.writerow((file, func, size))
# print results
def dedup_entries(results, by='function'):
entries = co.defaultdict(lambda: 0)
for file, func, size in results:
entry = (file if by == 'file' else func)
entries[entry] += size
return entries
def diff_entries(olds, news):
diff = co.defaultdict(lambda: (0, 0, 0, 0))
for name, new in news.items():
diff[name] = (0, new, new, 1.0)
for name, old in olds.items():
_, new, _, _ = diff[name]
diff[name] = (old, new, new-old, (new-old)/old if old else 1.0)
return diff
def print_header(by=''):
if not args.get('diff'):
print('%-36s %7s' % (by, 'size'))
else:
print('%-36s %7s %7s %7s' % (by, 'old', 'new', 'diff'))
def print_entries(by='function'):
entries = dedup_entries(results, by=by)
if not args.get('diff'):
print_header(by=by)
for name, size in sorted(entries.items()):
print("%-36s %7d" % (name, size))
else:
prev_entries = dedup_entries(prev_results, by=by)
diff = diff_entries(prev_entries, entries)
print_header(by='%s (%d added, %d removed)' % (by,
sum(1 for old, _, _, _ in diff.values() if not old),
sum(1 for _, new, _, _ in diff.values() if not new)))
for name, (old, new, diff, ratio) in sorted(diff.items(),
key=lambda x: (-x[1][3], x)):
if ratio or args.get('all'):
print("%-36s %7s %7s %+7d%s" % (name,
old or "-",
new or "-",
diff,
' (%+.1f%%)' % (100*ratio) if ratio else ''))
def print_totals():
if not args.get('diff'):
print("%-36s %7d" % ('TOTAL', total))
else:
ratio = (total-prev_total)/prev_total if prev_total else 1.0
print("%-36s %7s %7s %+7d%s" % (
'TOTAL',
prev_total if prev_total else '-',
total if total else '-',
total-prev_total,
' (%+.1f%%)' % (100*ratio) if ratio else ''))
if args.get('quiet'):
pass
elif args.get('summary'):
print_header()
print_totals()
elif args.get('files'):
print_entries(by='file')
print_totals()
else:
print_entries(by='function')
print_totals()
if __name__ == "__main__":
import argparse
import sys
parser = argparse.ArgumentParser(
description="Find code size at the function level.")
parser.add_argument('obj_paths', nargs='*', default=OBJ_PATHS,
help="Description of where to find *.o files. May be a directory \
or a list of paths. Defaults to %r." % OBJ_PATHS)
parser.add_argument('-v', '--verbose', action='store_true',
help="Output commands that run behind the scenes.")
parser.add_argument('-o', '--output',
help="Specify CSV file to store results.")
parser.add_argument('-u', '--use',
help="Don't compile and find code sizes, instead use this CSV file.")
parser.add_argument('-d', '--diff',
help="Specify CSV file to diff code size against.")
parser.add_argument('-a', '--all', action='store_true',
help="Show all functions, not just the ones that changed.")
parser.add_argument('--files', action='store_true',
help="Show file-level code sizes. Note this does not include padding! "
"So sizes may differ from other tools.")
parser.add_argument('-s', '--summary', action='store_true',
help="Only show the total code size.")
parser.add_argument('-q', '--quiet', action='store_true',
help="Don't show anything, useful with -o.")
parser.add_argument('--type', default='tTrRdDbB',
help="Type of symbols to report, this uses the same single-character "
"type-names emitted by nm. Defaults to %(default)r.")
parser.add_argument('--nm-tool', default=['nm'], type=lambda x: x.split(),
help="Path to the nm tool to use.")
parser.add_argument('--build-dir',
help="Specify the relative build directory. Used to map object files \
to the correct source files.")
sys.exit(main(**vars(parser.parse_args())))

View File

@@ -1,254 +0,0 @@
#!/usr/bin/env python3
#
# Parse and report coverage info from .info files generated by lcov
#
import os
import glob
import csv
import re
import collections as co
import bisect as b
INFO_PATHS = ['tests/*.toml.info']
def collect(paths, **args):
file = None
funcs = []
lines = co.defaultdict(lambda: 0)
pattern = re.compile(
'^(?P<file>SF:/?(?P<file_name>.*))$'
'|^(?P<func>FN:(?P<func_lineno>[0-9]*),(?P<func_name>.*))$'
'|^(?P<line>DA:(?P<line_lineno>[0-9]*),(?P<line_hits>[0-9]*))$')
for path in paths:
with open(path) as f:
for line in f:
m = pattern.match(line)
if m and m.group('file'):
file = m.group('file_name')
elif m and file and m.group('func'):
funcs.append((file, int(m.group('func_lineno')),
m.group('func_name')))
elif m and file and m.group('line'):
lines[(file, int(m.group('line_lineno')))] += (
int(m.group('line_hits')))
# map line numbers to functions
funcs.sort()
def func_from_lineno(file, lineno):
i = b.bisect(funcs, (file, lineno))
if i and funcs[i-1][0] == file:
return funcs[i-1][2]
else:
return None
# reduce to function info
reduced_funcs = co.defaultdict(lambda: (0, 0))
for (file, line_lineno), line_hits in lines.items():
func = func_from_lineno(file, line_lineno)
if not func:
continue
hits, count = reduced_funcs[(file, func)]
reduced_funcs[(file, func)] = (hits + (line_hits > 0), count + 1)
results = []
for (file, func), (hits, count) in reduced_funcs.items():
# discard internal/testing functions (test_* injected with
# internal testing)
if func.startswith('__') or func.startswith('test_'):
continue
# discard .8449 suffixes created by optimizer
func = re.sub('\.[0-9]+', '', func)
results.append((file, func, hits, count))
return results
def main(**args):
# find coverage
if not args.get('use'):
# find *.info files
paths = []
for path in args['info_paths']:
if os.path.isdir(path):
path = path + '/*.gcov'
for path in glob.glob(path):
paths.append(path)
if not paths:
print('no .info files found in %r?' % args['info_paths'])
sys.exit(-1)
results = collect(paths, **args)
else:
with open(args['use']) as f:
r = csv.DictReader(f)
results = [
( result['file'],
result['function'],
int(result['hits']),
int(result['count']))
for result in r]
total_hits, total_count = 0, 0
for _, _, hits, count in results:
total_hits += hits
total_count += count
# find previous results?
if args.get('diff'):
with open(args['diff']) as f:
r = csv.DictReader(f)
prev_results = [
( result['file'],
result['function'],
int(result['hits']),
int(result['count']))
for result in r]
prev_total_hits, prev_total_count = 0, 0
for _, _, hits, count in prev_results:
prev_total_hits += hits
prev_total_count += count
# write results to CSV
if args.get('output'):
with open(args['output'], 'w') as f:
w = csv.writer(f)
w.writerow(['file', 'function', 'hits', 'count'])
for file, func, hits, count in sorted(results):
w.writerow((file, func, hits, count))
# print results
def dedup_entries(results, by='function'):
entries = co.defaultdict(lambda: (0, 0))
for file, func, hits, count in results:
entry = (file if by == 'file' else func)
entry_hits, entry_count = entries[entry]
entries[entry] = (entry_hits + hits, entry_count + count)
return entries
def diff_entries(olds, news):
diff = co.defaultdict(lambda: (0, 0, 0, 0, 0, 0, 0))
for name, (new_hits, new_count) in news.items():
diff[name] = (
0, 0,
new_hits, new_count,
new_hits, new_count,
(new_hits/new_count if new_count else 1.0) - 1.0)
for name, (old_hits, old_count) in olds.items():
_, _, new_hits, new_count, _, _, _ = diff[name]
diff[name] = (
old_hits, old_count,
new_hits, new_count,
new_hits-old_hits, new_count-old_count,
((new_hits/new_count if new_count else 1.0)
- (old_hits/old_count if old_count else 1.0)))
return diff
def print_header(by=''):
if not args.get('diff'):
print('%-36s %19s' % (by, 'hits/line'))
else:
print('%-36s %19s %19s %11s' % (by, 'old', 'new', 'diff'))
def print_entries(by='function'):
entries = dedup_entries(results, by=by)
if not args.get('diff'):
print_header(by=by)
for name, (hits, count) in sorted(entries.items()):
print("%-36s %11s %7s" % (name,
'%d/%d' % (hits, count)
if count else '-',
'%.1f%%' % (100*hits/count)
if count else '-'))
else:
prev_entries = dedup_entries(prev_results, by=by)
diff = diff_entries(prev_entries, entries)
print_header(by='%s (%d added, %d removed)' % (by,
sum(1 for _, old, _, _, _, _, _ in diff.values() if not old),
sum(1 for _, _, _, new, _, _, _ in diff.values() if not new)))
for name, (
old_hits, old_count,
new_hits, new_count,
diff_hits, diff_count, ratio) in sorted(diff.items(),
key=lambda x: (-x[1][6], x)):
if ratio or args.get('all'):
print("%-36s %11s %7s %11s %7s %11s%s" % (name,
'%d/%d' % (old_hits, old_count)
if old_count else '-',
'%.1f%%' % (100*old_hits/old_count)
if old_count else '-',
'%d/%d' % (new_hits, new_count)
if new_count else '-',
'%.1f%%' % (100*new_hits/new_count)
if new_count else '-',
'%+d/%+d' % (diff_hits, diff_count),
' (%+.1f%%)' % (100*ratio) if ratio else ''))
def print_totals():
if not args.get('diff'):
print("%-36s %11s %7s" % ('TOTAL',
'%d/%d' % (total_hits, total_count)
if total_count else '-',
'%.1f%%' % (100*total_hits/total_count)
if total_count else '-'))
else:
ratio = ((total_hits/total_count
if total_count else 1.0)
- (prev_total_hits/prev_total_count
if prev_total_count else 1.0))
print("%-36s %11s %7s %11s %7s %11s%s" % ('TOTAL',
'%d/%d' % (prev_total_hits, prev_total_count)
if prev_total_count else '-',
'%.1f%%' % (100*prev_total_hits/prev_total_count)
if prev_total_count else '-',
'%d/%d' % (total_hits, total_count)
if total_count else '-',
'%.1f%%' % (100*total_hits/total_count)
if total_count else '-',
'%+d/%+d' % (total_hits-prev_total_hits,
total_count-prev_total_count),
' (%+.1f%%)' % (100*ratio) if ratio else ''))
if args.get('quiet'):
pass
elif args.get('summary'):
print_header()
print_totals()
elif args.get('files'):
print_entries(by='file')
print_totals()
else:
print_entries(by='function')
print_totals()
if __name__ == "__main__":
import argparse
import sys
parser = argparse.ArgumentParser(
description="Parse and report coverage info from .info files \
generated by lcov")
parser.add_argument('info_paths', nargs='*', default=INFO_PATHS,
help="Description of where to find *.info files. May be a directory \
or list of paths. *.info files will be merged to show the total \
coverage. Defaults to %r." % INFO_PATHS)
parser.add_argument('-v', '--verbose', action='store_true',
help="Output commands that run behind the scenes.")
parser.add_argument('-o', '--output',
help="Specify CSV file to store results.")
parser.add_argument('-u', '--use',
help="Don't do any work, instead use this CSV file.")
parser.add_argument('-d', '--diff',
help="Specify CSV file to diff code size against.")
parser.add_argument('-a', '--all', action='store_true',
help="Show all functions, not just the ones that changed.")
parser.add_argument('--files', action='store_true',
help="Show file-level coverage.")
parser.add_argument('-s', '--summary', action='store_true',
help="Only show the total coverage.")
parser.add_argument('-q', '--quiet', action='store_true',
help="Don't show anything, useful with -o.")
sys.exit(main(**vars(parser.parse_args())))

View File

@@ -106,7 +106,7 @@ def main(args):
struct.unpack('<HH', superblock[1].data[0:4].ljust(4, b'\xff')))) struct.unpack('<HH', superblock[1].data[0:4].ljust(4, b'\xff'))))
print("%-47s%s" % ("littlefs v%s.%s" % version, print("%-47s%s" % ("littlefs v%s.%s" % version,
"data (truncated, if it fits)" "data (truncated, if it fits)"
if not any([args.no_truncate, args.log, args.all]) else "")) if not any([args.no_truncate, args.tags, args.log, args.all]) else ""))
# print gstate # print gstate
print("gstate 0x%s" % ''.join('%02x' % c for c in gstate)) print("gstate 0x%s" % ''.join('%02x' % c for c in gstate))

View File

@@ -20,58 +20,57 @@ import pty
import errno import errno
import signal import signal
TEST_PATHS = 'tests' TESTDIR = 'tests'
RULES = """ RULES = """
# add block devices to sources
TESTSRC ?= $(SRC) $(wildcard bd/*.c)
define FLATTEN define FLATTEN
%(path)s%%$(subst /,.,$(target)): $(target) tests/%$(subst /,.,$(target)): $(target)
./scripts/explode_asserts.py $$< -o $$@ ./scripts/explode_asserts.py $$< -o $$@
endef endef
$(foreach target,$(TESTSRC),$(eval $(FLATTEN))) $(foreach target,$(SRC),$(eval $(FLATTEN)))
-include tests/*.d
-include %(path)s*.d
.SECONDARY: .SECONDARY:
%.test: %.test.o $(foreach f,$(subst /,.,$(SRC:.c=.o)),%.$f)
%(path)s.test: %(path)s.test.o \\
$(foreach t,$(subst /,.,$(TESTSRC:.c=.o)),%(path)s.$t)
$(CC) $(CFLAGS) $^ $(LFLAGS) -o $@ $(CC) $(CFLAGS) $^ $(LFLAGS) -o $@
# needed in case builddir is different
%(path)s%%.o: %(path)s%%.c
$(CC) -c -MMD $(CFLAGS) $< -o $@
""" """
COVERAGE_RULES = """ BEFORE_MAIN = """
%(path)s.test: override CFLAGS += -fprofile-arcs -ftest-coverage const char *lfs_testbd_path;
uint32_t lfs_testbd_cycles;
# delete lingering coverage int lfs_testbd_readctx(void *ctx, lfs_block_t block,
%(path)s.test: | %(path)s.info.clean lfs_off_t off, void *buffer, lfs_size_t size) {
.PHONY: %(path)s.info.clean return lfs_testbd_read((lfs_testbd_t*)ctx, block, off, buffer, size);
%(path)s.info.clean: }
rm -f %(path)s*.gcda
# accumulate coverage info int lfs_testbd_progctx(void *ctx, lfs_block_t block,
.PHONY: %(path)s.info lfs_off_t off, const void *buffer, lfs_size_t size) {
%(path)s.info: return lfs_testbd_prog((lfs_testbd_t*)ctx, block, off, buffer, size);
$(strip $(LCOV) -c \\ }
$(addprefix -d ,$(wildcard %(path)s*.gcda)) \\
--rc 'geninfo_adjust_src_path=$(shell pwd)' \\ int lfs_testbd_erasectx(void *ctx, lfs_block_t block) {
-o $@) return lfs_testbd_erase((lfs_testbd_t*)ctx, block);
$(LCOV) -e $@ $(addprefix /,$(SRC)) -o $@ }
ifdef COVERAGETARGET
$(strip $(LCOV) -a $@ \\ int lfs_testbd_syncctx(void *ctx) {
$(addprefix -a ,$(wildcard $(COVERAGETARGET))) \\ return lfs_testbd_sync((lfs_testbd_t*)ctx);
-o $(COVERAGETARGET)) }
endif
""" """
GLOBALS = """ BEFORE_TESTS = """
//////////////// AUTOGENERATED TEST //////////////// //////////////// AUTOGENERATED TEST ////////////////
#include "lfs.h" #include "lfs.h"
#include "bd/lfs_testbd.h" #include "bd/lfs_testbd.h"
#include <stdio.h> #include <stdio.h>
extern const char *lfs_testbd_path; extern const char *lfs_testbd_path;
extern uint32_t lfs_testbd_cycles; extern uint32_t lfs_testbd_cycles;
extern int lfs_testbd_readctx(void *ctx, lfs_block_t block,
lfs_off_t off, void *buffer, lfs_size_t size);
extern int lfs_testbd_progctx(void *ctx, lfs_block_t block,
lfs_off_t off, const void *buffer, lfs_size_t size);
extern int lfs_testbd_erasectx(void *ctx, lfs_block_t block);
extern int lfs_testbd_syncctx(void *ctx);
""" """
DEFINES = { DEFINES = {
'LFS_READ_SIZE': 16, 'LFS_READ_SIZE': 16,
@@ -79,12 +78,23 @@ DEFINES = {
'LFS_BLOCK_SIZE': 512, 'LFS_BLOCK_SIZE': 512,
'LFS_BLOCK_COUNT': 1024, 'LFS_BLOCK_COUNT': 1024,
'LFS_BLOCK_CYCLES': -1, 'LFS_BLOCK_CYCLES': -1,
'LFS_CACHE_SIZE': '(64 % LFS_PROG_SIZE == 0 ? 64 : LFS_PROG_SIZE)', 'LFS_BUFFER_SIZE': '(64 % LFS_PROG_SIZE == 0 ? 64 : LFS_PROG_SIZE)',
'LFS_LOOKAHEAD_SIZE': 16, 'LFS_LOOKAHEAD_SIZE': 16,
'LFS_ERASE_VALUE': 0xff, 'LFS_ERASE_VALUE': 0xff,
'LFS_ERASE_CYCLES': 0, 'LFS_ERASE_CYCLES': 0,
'LFS_BADBLOCK_BEHAVIOR': 'LFS_TESTBD_BADBLOCK_PROGERROR', 'LFS_BADBLOCK_BEHAVIOR': 'LFS_TESTBD_BADBLOCK_PROGERROR',
} }
CFG = {
'read_size': 'LFS_READ_SIZE',
'prog_size': 'LFS_PROG_SIZE',
'read_size': 'LFS_READ_SIZE',
'prog_size': 'LFS_PROG_SIZE',
'block_size': 'LFS_BLOCK_SIZE',
'block_count': 'LFS_BLOCK_COUNT',
'block_cycles': 'LFS_BLOCK_CYCLES',
'buffer_size': 'LFS_BUFFER_SIZE',
'lookahead_size': 'LFS_LOOKAHEAD_SIZE',
}
PROLOGUE = """ PROLOGUE = """
// prologue // prologue
__attribute__((unused)) lfs_t lfs; __attribute__((unused)) lfs_t lfs;
@@ -97,33 +107,45 @@ PROLOGUE = """
__attribute__((unused)) lfs_size_t size; __attribute__((unused)) lfs_size_t size;
__attribute__((unused)) int err; __attribute__((unused)) int err;
__attribute__((unused)) const struct lfs_config cfg = { __attribute__((unused)) const struct lfs_cfg cfg = {
.context = &bd, .bd_ctx = &bd,
.read = lfs_testbd_read, .bd_read = lfs_testbd_readctx,
.prog = lfs_testbd_prog, .bd_prog = lfs_testbd_progctx,
.erase = lfs_testbd_erase, .bd_erase = lfs_testbd_erasectx,
.sync = lfs_testbd_sync, .bd_sync = lfs_testbd_syncctx,
.read_size = LFS_READ_SIZE, %(cfg)s
.prog_size = LFS_PROG_SIZE,
.block_size = LFS_BLOCK_SIZE,
.block_count = LFS_BLOCK_COUNT,
.block_cycles = LFS_BLOCK_CYCLES,
.cache_size = LFS_CACHE_SIZE,
.lookahead_size = LFS_LOOKAHEAD_SIZE,
}; };
__attribute__((unused)) const struct lfs_testbd_config bdcfg = { __attribute__((unused)) const struct lfs_testbd_cfg bdcfg = {
.rambd_cfg = &(const struct lfs_rambd_cfg){
.read_size = LFS_READ_SIZE,
.prog_size = LFS_PROG_SIZE,
.erase_size = LFS_BLOCK_SIZE,
.erase_count = LFS_BLOCK_COUNT,
.erase_value = LFS_ERASE_VALUE,
},
.filebd_cfg = &(const struct lfs_filebd_cfg){
.read_size = LFS_READ_SIZE,
.prog_size = LFS_PROG_SIZE,
.erase_size = LFS_BLOCK_SIZE,
.erase_count = LFS_BLOCK_COUNT,
.erase_value = LFS_ERASE_VALUE,
},
.read_size = LFS_READ_SIZE,
.prog_size = LFS_PROG_SIZE,
.erase_size = LFS_BLOCK_SIZE,
.erase_count = LFS_BLOCK_COUNT,
.erase_value = LFS_ERASE_VALUE, .erase_value = LFS_ERASE_VALUE,
.erase_cycles = LFS_ERASE_CYCLES, .erase_cycles = LFS_ERASE_CYCLES,
.badblock_behavior = LFS_BADBLOCK_BEHAVIOR, .badblock_behavior = LFS_BADBLOCK_BEHAVIOR,
.power_cycles = lfs_testbd_cycles, .power_cycles = lfs_testbd_cycles,
}; };
lfs_testbd_createcfg(&cfg, lfs_testbd_path, &bdcfg) => 0; lfs_testbd_createcfg(&bd, lfs_testbd_path, &bdcfg) => 0;
""" """
EPILOGUE = """ EPILOGUE = """
// epilogue // epilogue
lfs_testbd_destroy(&cfg) => 0; lfs_testbd_destroy(&bd) => 0;
""" """
PASS = '\033[32m✓\033[0m' PASS = '\033[32m✓\033[0m'
FAIL = '\033[31m✗\033[0m' FAIL = '\033[31m✗\033[0m'
@@ -150,8 +172,6 @@ class TestCase:
self.if_ = config.get('if', None) self.if_ = config.get('if', None)
self.in_ = config.get('in', None) self.in_ = config.get('in', None)
self.result = None
def __str__(self): def __str__(self):
if hasattr(self, 'permno'): if hasattr(self, 'permno'):
if any(k not in self.case.defines for k in self.defines): if any(k not in self.case.defines for k in self.defines):
@@ -187,7 +207,11 @@ class TestCase:
for k in sorted(self.perms[0].defines) for k in sorted(self.perms[0].defines)
if k not in self.defines))) if k not in self.defines)))
f.write(PROLOGUE) f.write(PROLOGUE % dict(
cfg='\n'.join(
8*' '+'.%s = %s,\n' % (k, d)
for k, d in sorted(CFG.items())
if d not in self.suite.defines)))
f.write('\n') f.write('\n')
f.write(4*' '+'// test case %d\n' % self.caseno) f.write(4*' '+'// test case %d\n' % self.caseno)
f.write(4*' '+'#line %d "%s"\n' % (self.code_lineno, self.suite.path)) f.write(4*' '+'#line %d "%s"\n' % (self.code_lineno, self.suite.path))
@@ -196,6 +220,7 @@ class TestCase:
f.write(self.code) f.write(self.code)
# epilogue # epilogue
f.write(4*' '+'#line %d "%s"\n' % (f.lineno+1, f.path))
f.write(EPILOGUE) f.write(EPILOGUE)
f.write('}\n') f.write('}\n')
@@ -212,7 +237,7 @@ class TestCase:
len(self.filter) >= 2 and len(self.filter) >= 2 and
self.filter[1] != self.permno): self.filter[1] != self.permno):
return False return False
elif args.get('no_internal') and self.in_ is not None: elif args.get('no_internal', False) and self.in_ is not None:
return False return False
elif self.if_ is not None: elif self.if_ is not None:
if_ = self.if_ if_ = self.if_
@@ -246,7 +271,7 @@ class TestCase:
try: try:
with open(disk, 'w') as f: with open(disk, 'w') as f:
f.truncate(0) f.truncate(0)
if args.get('verbose'): if args.get('verbose', False):
print('truncate --size=0', disk) print('truncate --size=0', disk)
except FileNotFoundError: except FileNotFoundError:
pass pass
@@ -270,14 +295,14 @@ class TestCase:
'-ex', 'r']) '-ex', 'r'])
ncmd.extend(['--args'] + cmd) ncmd.extend(['--args'] + cmd)
if args.get('verbose'): if args.get('verbose', False):
print(' '.join(shlex.quote(c) for c in ncmd)) print(' '.join(shlex.quote(c) for c in ncmd))
signal.signal(signal.SIGINT, signal.SIG_IGN) signal.signal(signal.SIGINT, signal.SIG_IGN)
sys.exit(sp.call(ncmd)) sys.exit(sp.call(ncmd))
# run test case! # run test case!
mpty, spty = pty.openpty() mpty, spty = pty.openpty()
if args.get('verbose'): if args.get('verbose', False):
print(' '.join(shlex.quote(c) for c in cmd)) print(' '.join(shlex.quote(c) for c in cmd))
proc = sp.Popen(cmd, stdout=spty, stderr=spty) proc = sp.Popen(cmd, stdout=spty, stderr=spty)
os.close(spty) os.close(spty)
@@ -292,10 +317,8 @@ class TestCase:
if e.errno == errno.EIO: if e.errno == errno.EIO:
break break
raise raise
if not line:
break;
stdout.append(line) stdout.append(line)
if args.get('verbose'): if args.get('verbose', False):
sys.stdout.write(line) sys.stdout.write(line)
# intercept asserts # intercept asserts
m = re.match( m = re.match(
@@ -334,7 +357,7 @@ class ValgrindTestCase(TestCase):
return not self.leaky and super().shouldtest(**args) return not self.leaky and super().shouldtest(**args)
def test(self, exec=[], **args): def test(self, exec=[], **args):
verbose = args.get('verbose') verbose = args.get('verbose', False)
uninit = (self.defines.get('LFS_ERASE_VALUE', None) == -1) uninit = (self.defines.get('LFS_ERASE_VALUE', None) == -1)
exec = [ exec = [
'valgrind', 'valgrind',
@@ -386,17 +409,12 @@ class TestSuite:
self.name = os.path.basename(path) self.name = os.path.basename(path)
if self.name.endswith('.toml'): if self.name.endswith('.toml'):
self.name = self.name[:-len('.toml')] self.name = self.name[:-len('.toml')]
if args.get('build_dir'): self.path = path
self.toml = path
self.path = args['build_dir'] + '/' + path
else:
self.toml = path
self.path = path
self.classes = classes self.classes = classes
self.defines = defines.copy() self.defines = defines.copy()
self.filter = filter self.filter = filter
with open(self.toml) as f: with open(path) as f:
# load tests # load tests
config = toml.load(f) config = toml.load(f)
@@ -506,31 +524,44 @@ class TestSuite:
return self.perms return self.perms
def build(self, **args): def build(self, **args):
# intercept writes to keep track of linenos
def lineno_open(path, flags):
f = open(path, flags)
f.path = path
f.lineno = 1
write = f.write
def lineno_write(s):
f.lineno += s.count('\n')
write(s)
f.write = lineno_write
return f
# build test files # build test files
tf = open(self.path + '.test.tc', 'w') tf = lineno_open(self.path + '.test.tc', 'w')
tf.write(GLOBALS) tf.write(BEFORE_TESTS)
if self.code is not None: if self.code is not None:
tf.write('#line %d "%s"\n' % (self.code_lineno, self.path)) tf.write('#line %d "%s"\n' % (self.code_lineno, self.path))
tf.write(self.code) tf.write(self.code)
tf.write('#line %d "%s"\n' % (tf.lineno+1, tf.path))
tfs = {None: tf} tfs = {None: tf}
for case in self.cases: for case in self.cases:
if case.in_ not in tfs: if case.in_ not in tfs:
tfs[case.in_] = open(self.path+'.'+ tfs[case.in_] = lineno_open(self.path+'.'+
re.sub('(\.c)?$', '.tc', case.in_.replace('/', '.')), 'w') case.in_.replace('/', '.')[:-2]+'.tc', 'w')
tfs[case.in_].write('#line 1 "%s"\n' % case.in_) tfs[case.in_].write('#line 1 "%s"\n' % case.in_)
with open(case.in_) as f: with open(case.in_) as f:
for line in f: for line in f:
tfs[case.in_].write(line) tfs[case.in_].write(line)
tfs[case.in_].write('\n') tfs[case.in_].write('\n')
tfs[case.in_].write(GLOBALS) tfs[case.in_].write(BEFORE_TESTS)
tfs[case.in_].write('\n') tfs[case.in_].write('\n')
case.build(tfs[case.in_], **args) case.build(tfs[case.in_], **args)
tf.write(BEFORE_MAIN)
tf.write('\n') tf.write('\n')
tf.write('const char *lfs_testbd_path;\n')
tf.write('uint32_t lfs_testbd_cycles;\n')
tf.write('int main(int argc, char **argv) {\n') tf.write('int main(int argc, char **argv) {\n')
tf.write(4*' '+'int case_ = (argc > 1) ? atoi(argv[1]) : 0;\n') tf.write(4*' '+'int case_ = (argc > 1) ? atoi(argv[1]) : 0;\n')
tf.write(4*' '+'int perm = (argc > 2) ? atoi(argv[2]) : 0;\n') tf.write(4*' '+'int perm = (argc > 2) ? atoi(argv[2]) : 0;\n')
@@ -556,33 +587,25 @@ class TestSuite:
# write makefiles # write makefiles
with open(self.path + '.mk', 'w') as mk: with open(self.path + '.mk', 'w') as mk:
mk.write(RULES.replace(4*' ', '\t') % dict(path=self.path)) mk.write(RULES.replace(4*' ', '\t'))
mk.write('\n') mk.write('\n')
# add coverage hooks?
if args.get('coverage'):
mk.write(COVERAGE_RULES.replace(4*' ', '\t') % dict(
path=self.path))
mk.write('\n')
# add truely global defines globally # add truely global defines globally
for k, v in sorted(self.defines.items()): for k, v in sorted(self.defines.items()):
mk.write('%s.test: override CFLAGS += -D%s=%r\n' mk.write('%s: override CFLAGS += -D%s=%r\n' % (
% (self.path, k, v)) self.path+'.test', k, v))
for path in tfs: for path in tfs:
if path is None: if path is None:
mk.write('%s: %s | %s\n' % ( mk.write('%s: %s | %s\n' % (
self.path+'.test.c', self.path+'.test.c',
self.toml, self.path,
self.path+'.test.tc')) self.path+'.test.tc'))
else: else:
mk.write('%s: %s %s | %s\n' % ( mk.write('%s: %s %s | %s\n' % (
self.path+'.'+path.replace('/', '.'), self.path+'.'+path.replace('/', '.'),
self.toml, self.path, path,
path, self.path+'.'+path.replace('/', '.')[:-2]+'.tc'))
self.path+'.'+re.sub('(\.c)?$', '.tc',
path.replace('/', '.'))))
mk.write('\t./scripts/explode_asserts.py $| -o $@\n') mk.write('\t./scripts/explode_asserts.py $| -o $@\n')
self.makefile = self.path + '.mk' self.makefile = self.path + '.mk'
@@ -605,7 +628,7 @@ class TestSuite:
if not args.get('verbose', True): if not args.get('verbose', True):
sys.stdout.write(FAIL) sys.stdout.write(FAIL)
sys.stdout.flush() sys.stdout.flush()
if not args.get('keep_going'): if not args.get('keep_going', False):
if not args.get('verbose', True): if not args.get('verbose', True):
sys.stdout.write('\n') sys.stdout.write('\n')
raise raise
@@ -627,30 +650,30 @@ def main(**args):
# and what class of TestCase to run # and what class of TestCase to run
classes = [] classes = []
if args.get('normal'): if args.get('normal', False):
classes.append(TestCase) classes.append(TestCase)
if args.get('reentrant'): if args.get('reentrant', False):
classes.append(ReentrantTestCase) classes.append(ReentrantTestCase)
if args.get('valgrind'): if args.get('valgrind', False):
classes.append(ValgrindTestCase) classes.append(ValgrindTestCase)
if not classes: if not classes:
classes = [TestCase] classes = [TestCase]
suites = [] suites = []
for testpath in args['test_paths']: for testpath in args['testpaths']:
# optionally specified test case/perm # optionally specified test case/perm
testpath, *filter = testpath.split('#') testpath, *filter = testpath.split('#')
filter = [int(f) for f in filter] filter = [int(f) for f in filter]
# figure out the suite's toml file # figure out the suite's toml file
if os.path.isdir(testpath): if os.path.isdir(testpath):
testpath = testpath + '/*.toml' testpath = testpath + '/test_*.toml'
elif os.path.isfile(testpath): elif os.path.isfile(testpath):
testpath = testpath testpath = testpath
elif testpath.endswith('.toml'): elif testpath.endswith('.toml'):
testpath = TEST_PATHS + '/' + testpath testpath = TESTDIR + '/' + testpath
else: else:
testpath = TEST_PATHS + '/' + testpath + '.toml' testpath = TESTDIR + '/' + testpath + '.toml'
# find tests # find tests
for path in glob.glob(testpath): for path in glob.glob(testpath):
@@ -676,7 +699,7 @@ def main(**args):
list(it.chain.from_iterable(['-f', m] for m in makefiles)) + list(it.chain.from_iterable(['-f', m] for m in makefiles)) +
[target for target in targets]) [target for target in targets])
mpty, spty = pty.openpty() mpty, spty = pty.openpty()
if args.get('verbose'): if args.get('verbose', False):
print(' '.join(shlex.quote(c) for c in cmd)) print(' '.join(shlex.quote(c) for c in cmd))
proc = sp.Popen(cmd, stdout=spty, stderr=spty) proc = sp.Popen(cmd, stdout=spty, stderr=spty)
os.close(spty) os.close(spty)
@@ -689,17 +712,15 @@ def main(**args):
if e.errno == errno.EIO: if e.errno == errno.EIO:
break break
raise raise
if not line:
break;
stdout.append(line) stdout.append(line)
if args.get('verbose'): if args.get('verbose', False):
sys.stdout.write(line) sys.stdout.write(line)
# intercept warnings # intercept warnings
m = re.match( m = re.match(
'^{0}([^:]+):(\d+):(?:\d+:)?{0}{1}:{0}(.*)$' '^{0}([^:]+):(\d+):(?:\d+:)?{0}{1}:{0}(.*)$'
.format('(?:\033\[[\d;]*.| )*', 'warning'), .format('(?:\033\[[\d;]*.| )*', 'warning'),
line) line)
if m and not args.get('verbose'): if m and not args.get('verbose', False):
try: try:
with open(m.group(1)) as f: with open(m.group(1)) as f:
lineno = int(m.group(2)) lineno = int(m.group(2))
@@ -712,26 +733,27 @@ def main(**args):
except: except:
pass pass
proc.wait() proc.wait()
if proc.returncode != 0: if proc.returncode != 0:
if not args.get('verbose'): if not args.get('verbose', False):
for line in stdout: for line in stdout:
sys.stdout.write(line) sys.stdout.write(line)
sys.exit(-1) sys.exit(-3)
print('built %d test suites, %d test cases, %d permutations' % ( print('built %d test suites, %d test cases, %d permutations' % (
len(suites), len(suites),
sum(len(suite.cases) for suite in suites), sum(len(suite.cases) for suite in suites),
sum(len(suite.perms) for suite in suites))) sum(len(suite.perms) for suite in suites)))
total = 0 filtered = 0
for suite in suites: for suite in suites:
for perm in suite.perms: for perm in suite.perms:
total += perm.shouldtest(**args) filtered += perm.shouldtest(**args)
if total != sum(len(suite.perms) for suite in suites): if filtered != sum(len(suite.perms) for suite in suites):
print('filtered down to %d permutations' % total) print('filtered down to %d permutations' % filtered)
# only requested to build? # only requested to build?
if args.get('build'): if args.get('build', False):
return 0 return 0
print('====== testing ======') print('====== testing ======')
@@ -746,12 +768,15 @@ def main(**args):
failed = 0 failed = 0
for suite in suites: for suite in suites:
for perm in suite.perms: for perm in suite.perms:
if not hasattr(perm, 'result'):
continue
if perm.result == PASS: if perm.result == PASS:
passed += 1 passed += 1
elif isinstance(perm.result, TestFailure): else:
sys.stdout.write( sys.stdout.write(
"\033[01m{path}:{lineno}:\033[01;31mfailure:\033[m " "\033[01m{path}:{lineno}:\033[01;31mfailure:\033[m "
"{perm} failed\n".format( "{perm} failed with {returncode}\n".format(
perm=perm, path=perm.suite.path, lineno=perm.lineno, perm=perm, path=perm.suite.path, lineno=perm.lineno,
returncode=perm.result.returncode or 0)) returncode=perm.result.returncode or 0))
if perm.result.stdout: if perm.result.stdout:
@@ -769,33 +794,11 @@ def main(**args):
sys.stdout.write('\n') sys.stdout.write('\n')
failed += 1 failed += 1
if args.get('coverage'): if args.get('gdb', False):
# collect coverage info
# why -j1? lcov doesn't work in parallel because of gcov limitations
cmd = (['make', '-j1', '-f', 'Makefile'] +
list(it.chain.from_iterable(['-f', m] for m in makefiles)) +
(['COVERAGETARGET=%s' % args['coverage']]
if isinstance(args['coverage'], str) else []) +
[suite.path + '.info' for suite in suites
if any(perm.result == PASS for perm in suite.perms)])
if args.get('verbose'):
print(' '.join(shlex.quote(c) for c in cmd))
proc = sp.Popen(cmd,
stdout=sp.PIPE if not args.get('verbose') else None,
stderr=sp.STDOUT if not args.get('verbose') else None,
universal_newlines=True)
proc.wait()
if proc.returncode != 0:
if not args.get('verbose'):
for line in proc.stdout:
sys.stdout.write(line)
sys.exit(-1)
if args.get('gdb'):
failure = None failure = None
for suite in suites: for suite in suites:
for perm in suite.perms: for perm in suite.perms:
if isinstance(perm.result, TestFailure): if getattr(perm, 'result', PASS) != PASS:
failure = perm.result failure = perm.result
if failure is not None: if failure is not None:
print('======= gdb ======') print('======= gdb ======')
@@ -803,22 +806,20 @@ def main(**args):
failure.case.test(failure=failure, **args) failure.case.test(failure=failure, **args)
sys.exit(0) sys.exit(0)
print('tests passed %d/%d (%.2f%%)' % (passed, total, print('tests passed: %d' % passed)
100*(passed/total if total else 1.0))) print('tests failed: %d' % failed)
print('tests failed %d/%d (%.2f%%)' % (failed, total,
100*(failed/total if total else 1.0)))
return 1 if failed > 0 else 0 return 1 if failed > 0 else 0
if __name__ == "__main__": if __name__ == "__main__":
import argparse import argparse
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description="Run parameterized tests in various configurations.") description="Run parameterized tests in various configurations.")
parser.add_argument('test_paths', nargs='*', default=[TEST_PATHS], parser.add_argument('testpaths', nargs='*', default=[TESTDIR],
help="Description of test(s) to run. By default, this is all tests \ help="Description of test(s) to run. By default, this is all tests \
found in the \"{0}\" directory. Here, you can specify a different \ found in the \"{0}\" directory. Here, you can specify a different \
directory of tests, a specific file, a suite by name, and even \ directory of tests, a specific file, a suite by name, and even a \
specific test cases and permutations. For example \ specific test case by adding brackets. For example \
\"test_dirs#1\" or \"{0}/test_dirs.toml#1#1\".".format(TEST_PATHS)) \"test_dirs[0]\" or \"{0}/test_dirs.toml[0]\".".format(TESTDIR))
parser.add_argument('-D', action='append', default=[], parser.add_argument('-D', action='append', default=[],
help="Overriding parameter definitions.") help="Overriding parameter definitions.")
parser.add_argument('-v', '--verbose', action='store_true', parser.add_argument('-v', '--verbose', action='store_true',
@@ -839,19 +840,10 @@ if __name__ == "__main__":
help="Run tests normally.") help="Run tests normally.")
parser.add_argument('-r', '--reentrant', action='store_true', parser.add_argument('-r', '--reentrant', action='store_true',
help="Run reentrant tests with simulated power-loss.") help="Run reentrant tests with simulated power-loss.")
parser.add_argument('--valgrind', action='store_true', parser.add_argument('-V', '--valgrind', action='store_true',
help="Run non-leaky tests under valgrind to check for memory leaks.") help="Run non-leaky tests under valgrind to check for memory leaks.")
parser.add_argument('--exec', default=[], type=lambda e: e.split(), parser.add_argument('-e', '--exec', default=[], type=lambda e: e.split(' '),
help="Run tests with another executable prefixed on the command line.") help="Run tests with another executable prefixed on the command line.")
parser.add_argument('--disk', parser.add_argument('-d', '--disk',
help="Specify a file to use for persistent/reentrant tests.") help="Specify a file to use for persistent/reentrant tests.")
parser.add_argument('--coverage', type=lambda x: x if x else True,
nargs='?', const='',
help="Collect coverage information during testing. This uses lcov/gcov \
to accumulate coverage information into *.info files. May also \
a path to a *.info file to accumulate coverage info into.")
parser.add_argument('--build-dir',
help="Build relative to the specified directory instead of the \
current directory.")
sys.exit(main(**vars(parser.parse_args()))) sys.exit(main(**vars(parser.parse_args())))

View File

@@ -9,12 +9,12 @@ code = '''
const char *names[FILES] = {"bacon", "eggs", "pancakes"}; const char *names[FILES] = {"bacon", "eggs", "pancakes"};
lfs_file_t files[FILES]; lfs_file_t files[FILES];
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "breakfast") => 0; lfs_mkdir(&lfs, "breakfast") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
for (int n = 0; n < FILES; n++) { for (int n = 0; n < FILES; n++) {
sprintf(path, "breakfast/%s", names[n]); sprintf(path, "breakfast/%s", names[n]);
lfs_file_open(&lfs, &files[n], path, lfs_file_open(&lfs, &files[n], path,
@@ -31,7 +31,7 @@ code = '''
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
for (int n = 0; n < FILES; n++) { for (int n = 0; n < FILES; n++) {
sprintf(path, "breakfast/%s", names[n]); sprintf(path, "breakfast/%s", names[n]);
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
@@ -51,13 +51,13 @@ define.SIZE = '(((LFS_BLOCK_SIZE-8)*(LFS_BLOCK_COUNT-6)) / FILES)'
code = ''' code = '''
const char *names[FILES] = {"bacon", "eggs", "pancakes"}; const char *names[FILES] = {"bacon", "eggs", "pancakes"};
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "breakfast") => 0; lfs_mkdir(&lfs, "breakfast") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
for (int n = 0; n < FILES; n++) { for (int n = 0; n < FILES; n++) {
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
sprintf(path, "breakfast/%s", names[n]); sprintf(path, "breakfast/%s", names[n]);
lfs_file_open(&lfs, &file, path, lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
@@ -70,7 +70,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
} }
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
for (int n = 0; n < FILES; n++) { for (int n = 0; n < FILES; n++) {
sprintf(path, "breakfast/%s", names[n]); sprintf(path, "breakfast/%s", names[n]);
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
@@ -92,14 +92,14 @@ code = '''
const char *names[FILES] = {"bacon", "eggs", "pancakes"}; const char *names[FILES] = {"bacon", "eggs", "pancakes"};
lfs_file_t files[FILES]; lfs_file_t files[FILES];
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
for (int c = 0; c < CYCLES; c++) { for (int c = 0; c < CYCLES; c++) {
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "breakfast") => 0; lfs_mkdir(&lfs, "breakfast") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
for (int n = 0; n < FILES; n++) { for (int n = 0; n < FILES; n++) {
sprintf(path, "breakfast/%s", names[n]); sprintf(path, "breakfast/%s", names[n]);
lfs_file_open(&lfs, &files[n], path, lfs_file_open(&lfs, &files[n], path,
@@ -116,7 +116,7 @@ code = '''
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
for (int n = 0; n < FILES; n++) { for (int n = 0; n < FILES; n++) {
sprintf(path, "breakfast/%s", names[n]); sprintf(path, "breakfast/%s", names[n]);
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
@@ -129,7 +129,7 @@ code = '''
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
for (int n = 0; n < FILES; n++) { for (int n = 0; n < FILES; n++) {
sprintf(path, "breakfast/%s", names[n]); sprintf(path, "breakfast/%s", names[n]);
lfs_remove(&lfs, path) => 0; lfs_remove(&lfs, path) => 0;
@@ -146,15 +146,15 @@ define.CYCLES = [1, 10]
code = ''' code = '''
const char *names[FILES] = {"bacon", "eggs", "pancakes"}; const char *names[FILES] = {"bacon", "eggs", "pancakes"};
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
for (int c = 0; c < CYCLES; c++) { for (int c = 0; c < CYCLES; c++) {
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "breakfast") => 0; lfs_mkdir(&lfs, "breakfast") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
for (int n = 0; n < FILES; n++) { for (int n = 0; n < FILES; n++) {
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
sprintf(path, "breakfast/%s", names[n]); sprintf(path, "breakfast/%s", names[n]);
lfs_file_open(&lfs, &file, path, lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
@@ -167,7 +167,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
} }
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
for (int n = 0; n < FILES; n++) { for (int n = 0; n < FILES; n++) {
sprintf(path, "breakfast/%s", names[n]); sprintf(path, "breakfast/%s", names[n]);
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
@@ -180,7 +180,7 @@ code = '''
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
for (int n = 0; n < FILES; n++) { for (int n = 0; n < FILES; n++) {
sprintf(path, "breakfast/%s", names[n]); sprintf(path, "breakfast/%s", names[n]);
lfs_remove(&lfs, path) => 0; lfs_remove(&lfs, path) => 0;
@@ -192,8 +192,8 @@ code = '''
[[case]] # exhaustion test [[case]] # exhaustion test
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
size = strlen("exhaustion"); size = strlen("exhaustion");
memcpy(buffer, "exhaustion", size); memcpy(buffer, "exhaustion", size);
@@ -216,7 +216,7 @@ code = '''
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_RDONLY); lfs_file_open(&lfs, &file, "exhaustion", LFS_O_RDONLY);
size = strlen("exhaustion"); size = strlen("exhaustion");
lfs_file_size(&lfs, &file) => size; lfs_file_size(&lfs, &file) => size;
@@ -229,8 +229,8 @@ code = '''
[[case]] # exhaustion wraparound test [[case]] # exhaustion wraparound test
define.SIZE = '(((LFS_BLOCK_SIZE-8)*(LFS_BLOCK_COUNT-4)) / 3)' define.SIZE = '(((LFS_BLOCK_SIZE-8)*(LFS_BLOCK_COUNT-4)) / 3)'
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "padding", LFS_O_WRONLY | LFS_O_CREAT); lfs_file_open(&lfs, &file, "padding", LFS_O_WRONLY | LFS_O_CREAT);
size = strlen("buffering"); size = strlen("buffering");
@@ -263,7 +263,7 @@ code = '''
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_RDONLY); lfs_file_open(&lfs, &file, "exhaustion", LFS_O_RDONLY);
size = strlen("exhaustion"); size = strlen("exhaustion");
lfs_file_size(&lfs, &file) => size; lfs_file_size(&lfs, &file) => size;
@@ -276,8 +276,8 @@ code = '''
[[case]] # dir exhaustion test [[case]] # dir exhaustion test
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
// find out max file size // find out max file size
lfs_mkdir(&lfs, "exhaustiondir") => 0; lfs_mkdir(&lfs, "exhaustiondir") => 0;
@@ -328,8 +328,8 @@ in = "lfs.c"
define.LFS_ERASE_CYCLES = 0xffffffff define.LFS_ERASE_CYCLES = 0xffffffff
define.LFS_BADBLOCK_BEHAVIOR = 'LFS_TESTBD_BADBLOCK_READERROR' define.LFS_BADBLOCK_BEHAVIOR = 'LFS_TESTBD_BADBLOCK_READERROR'
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
// first fill to exhaustion to find available space // first fill to exhaustion to find available space
lfs_file_open(&lfs, &file, "pacman", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs_file_open(&lfs, &file, "pacman", LFS_O_WRONLY | LFS_O_CREAT) => 0;
strcpy((char*)buffer, "waka"); strcpy((char*)buffer, "waka");
@@ -358,11 +358,11 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// remount to force an alloc scan // remount to force an alloc scan
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
// but mark the head of our file as a "bad block", this is force our // but mark the head of our file as a "bad block", this is force our
// scan to bail early // scan to bail early
lfs_testbd_setwear(&cfg, fileblock, 0xffffffff) => 0; lfs_testbd_setwear(&bd, fileblock, 0xffffffff) => 0;
lfs_file_open(&lfs, &file, "ghost", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs_file_open(&lfs, &file, "ghost", LFS_O_WRONLY | LFS_O_CREAT) => 0;
strcpy((char*)buffer, "chomp"); strcpy((char*)buffer, "chomp");
size = strlen("chomp"); size = strlen("chomp");
@@ -377,7 +377,7 @@ code = '''
// now reverse the "bad block" and try to write the file again until we // now reverse the "bad block" and try to write the file again until we
// run out of space // run out of space
lfs_testbd_setwear(&cfg, fileblock, 0) => 0; lfs_testbd_setwear(&bd, fileblock, 0) => 0;
lfs_file_open(&lfs, &file, "ghost", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs_file_open(&lfs, &file, "ghost", LFS_O_WRONLY | LFS_O_CREAT) => 0;
strcpy((char*)buffer, "chomp"); strcpy((char*)buffer, "chomp");
size = strlen("chomp"); size = strlen("chomp");
@@ -393,7 +393,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// check that the disk isn't hurt // check that the disk isn't hurt
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "pacman", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, "pacman", LFS_O_RDONLY) => 0;
strcpy((char*)buffer, "waka"); strcpy((char*)buffer, "waka");
size = strlen("waka"); size = strlen("waka");
@@ -416,8 +416,8 @@ define.LFS_BLOCK_SIZE = 512
define.LFS_BLOCK_COUNT = 1024 define.LFS_BLOCK_COUNT = 1024
if = 'LFS_BLOCK_SIZE == 512 && LFS_BLOCK_COUNT == 1024' if = 'LFS_BLOCK_SIZE == 512 && LFS_BLOCK_COUNT == 1024'
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
// find out max file size // find out max file size
lfs_mkdir(&lfs, "exhaustiondir") => 0; lfs_mkdir(&lfs, "exhaustiondir") => 0;
@@ -487,22 +487,22 @@ define.LFS_BLOCK_SIZE = 512
define.LFS_BLOCK_COUNT = 1024 define.LFS_BLOCK_COUNT = 1024
if = 'LFS_BLOCK_SIZE == 512 && LFS_BLOCK_COUNT == 1024' if = 'LFS_BLOCK_SIZE == 512 && LFS_BLOCK_COUNT == 1024'
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
// create one block hole for half a directory // create one block hole for half a directory
lfs_file_open(&lfs, &file, "bump", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs_file_open(&lfs, &file, "bump", LFS_O_WRONLY | LFS_O_CREAT) => 0;
for (lfs_size_t i = 0; i < cfg.block_size; i += 2) { for (lfs_size_t i = 0; i < LFS_BLOCK_SIZE; i += 2) {
memcpy(&buffer[i], "hi", 2); memcpy(&buffer[i], "hi", 2);
} }
lfs_file_write(&lfs, &file, buffer, cfg.block_size) => cfg.block_size; lfs_file_write(&lfs, &file, buffer, LFS_BLOCK_SIZE) => LFS_BLOCK_SIZE;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0; for (lfs_size_t i = 0;
i < (cfg.block_count-4)*(cfg.block_size-8); i < (LFS_BLOCK_COUNT-4)*(LFS_BLOCK_SIZE-8);
i += size) { i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file, buffer, size) => size;
} }
@@ -510,7 +510,7 @@ code = '''
// remount to force reset of lookahead // remount to force reset of lookahead
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
// open hole // open hole
lfs_remove(&lfs, "bump") => 0; lfs_remove(&lfs, "bump") => 0;
@@ -518,10 +518,10 @@ code = '''
lfs_mkdir(&lfs, "splitdir") => 0; lfs_mkdir(&lfs, "splitdir") => 0;
lfs_file_open(&lfs, &file, "splitdir/bump", lfs_file_open(&lfs, &file, "splitdir/bump",
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS_O_WRONLY | LFS_O_CREAT) => 0;
for (lfs_size_t i = 0; i < cfg.block_size; i += 2) { for (lfs_size_t i = 0; i < LFS_BLOCK_SIZE; i += 2) {
memcpy(&buffer[i], "hi", 2); memcpy(&buffer[i], "hi", 2);
} }
lfs_file_write(&lfs, &file, buffer, 2*cfg.block_size) => LFS_ERR_NOSPC; lfs_file_write(&lfs, &file, buffer, 2*LFS_BLOCK_SIZE) => LFS_ERR_NOSPC;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
@@ -532,8 +532,8 @@ define.LFS_BLOCK_SIZE = 512
define.LFS_BLOCK_COUNT = 1024 define.LFS_BLOCK_COUNT = 1024
if = 'LFS_BLOCK_SIZE == 512 && LFS_BLOCK_COUNT == 1024' if = 'LFS_BLOCK_SIZE == 512 && LFS_BLOCK_COUNT == 1024'
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
// fill completely with two files // fill completely with two files
lfs_file_open(&lfs, &file, "exhaustion1", lfs_file_open(&lfs, &file, "exhaustion1",
@@ -541,7 +541,7 @@ code = '''
size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0; for (lfs_size_t i = 0;
i < ((cfg.block_count-2)/2)*(cfg.block_size-8); i < ((LFS_BLOCK_COUNT-2)/2)*(LFS_BLOCK_SIZE-8);
i += size) { i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file, buffer, size) => size;
} }
@@ -552,7 +552,7 @@ code = '''
size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0; for (lfs_size_t i = 0;
i < ((cfg.block_count-2+1)/2)*(cfg.block_size-8); i < ((LFS_BLOCK_COUNT-2+1)/2)*(LFS_BLOCK_SIZE-8);
i += size) { i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file, buffer, size) => size;
} }
@@ -560,7 +560,7 @@ code = '''
// remount to force reset of lookahead // remount to force reset of lookahead
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
// rewrite one file // rewrite one file
lfs_file_open(&lfs, &file, "exhaustion1", lfs_file_open(&lfs, &file, "exhaustion1",
@@ -569,7 +569,7 @@ code = '''
size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0; for (lfs_size_t i = 0;
i < ((cfg.block_count-2)/2)*(cfg.block_size-8); i < ((LFS_BLOCK_COUNT-2)/2)*(LFS_BLOCK_SIZE-8);
i += size) { i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file, buffer, size) => size;
} }
@@ -583,7 +583,7 @@ code = '''
size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0; for (lfs_size_t i = 0;
i < ((cfg.block_count-2+1)/2)*(cfg.block_size-8); i < ((LFS_BLOCK_COUNT-2+1)/2)*(LFS_BLOCK_SIZE-8);
i += size) { i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file, buffer, size) => size;
} }
@@ -597,8 +597,8 @@ define.LFS_BLOCK_SIZE = 512
define.LFS_BLOCK_COUNT = 1024 define.LFS_BLOCK_COUNT = 1024
if = 'LFS_BLOCK_SIZE == 512 && LFS_BLOCK_COUNT == 1024' if = 'LFS_BLOCK_SIZE == 512 && LFS_BLOCK_COUNT == 1024'
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
// fill completely with two files // fill completely with two files
lfs_file_open(&lfs, &file, "exhaustion1", lfs_file_open(&lfs, &file, "exhaustion1",
@@ -606,7 +606,7 @@ code = '''
size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0; for (lfs_size_t i = 0;
i < ((cfg.block_count-2)/2)*(cfg.block_size-8); i < ((LFS_BLOCK_COUNT-2)/2)*(LFS_BLOCK_SIZE-8);
i += size) { i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file, buffer, size) => size;
} }
@@ -617,7 +617,7 @@ code = '''
size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0; for (lfs_size_t i = 0;
i < ((cfg.block_count-2+1)/2)*(cfg.block_size-8); i < ((LFS_BLOCK_COUNT-2+1)/2)*(LFS_BLOCK_SIZE-8);
i += size) { i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file, buffer, size) => size;
} }
@@ -625,7 +625,7 @@ code = '''
// remount to force reset of lookahead // remount to force reset of lookahead
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
// rewrite one file with a hole of one block // rewrite one file with a hole of one block
lfs_file_open(&lfs, &file, "exhaustion1", lfs_file_open(&lfs, &file, "exhaustion1",
@@ -634,7 +634,7 @@ code = '''
size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0; for (lfs_size_t i = 0;
i < ((cfg.block_count-2)/2 - 1)*(cfg.block_size-8); i < ((LFS_BLOCK_COUNT-2)/2 - 1)*(LFS_BLOCK_SIZE-8);
i += size) { i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file, buffer, size) => size;
} }

View File

@@ -1,14 +1,14 @@
[[case]] # set/get attribute [[case]] # set/get attribute
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "hello") => 0; lfs_mkdir(&lfs, "hello") => 0;
lfs_file_open(&lfs, &file, "hello/hello", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs_file_open(&lfs, &file, "hello/hello", LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello"); lfs_file_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello");
lfs_file_close(&lfs, &file); lfs_file_close(&lfs, &file);
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
memset(buffer, 0, sizeof(buffer)); memset(buffer, 0, sizeof(buffer));
lfs_setattr(&lfs, "hello", 'A', "aaaa", 4) => 0; lfs_setattr(&lfs, "hello", 'A', "aaaa", 4) => 0;
lfs_setattr(&lfs, "hello", 'B', "bbbbbb", 6) => 0; lfs_setattr(&lfs, "hello", 'B', "bbbbbb", 6) => 0;
@@ -60,7 +60,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
memset(buffer, 0, sizeof(buffer)); memset(buffer, 0, sizeof(buffer));
lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4; lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "hello", 'B', buffer+4, 9) => 9; lfs_getattr(&lfs, "hello", 'B', buffer+4, 9) => 9;
@@ -78,15 +78,15 @@ code = '''
[[case]] # set/get root attribute [[case]] # set/get root attribute
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "hello") => 0; lfs_mkdir(&lfs, "hello") => 0;
lfs_file_open(&lfs, &file, "hello/hello", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs_file_open(&lfs, &file, "hello/hello", LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello"); lfs_file_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello");
lfs_file_close(&lfs, &file); lfs_file_close(&lfs, &file);
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
memset(buffer, 0, sizeof(buffer)); memset(buffer, 0, sizeof(buffer));
lfs_setattr(&lfs, "/", 'A', "aaaa", 4) => 0; lfs_setattr(&lfs, "/", 'A', "aaaa", 4) => 0;
lfs_setattr(&lfs, "/", 'B', "bbbbbb", 6) => 0; lfs_setattr(&lfs, "/", 'B', "bbbbbb", 6) => 0;
@@ -137,7 +137,7 @@ code = '''
lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
memset(buffer, 0, sizeof(buffer)); memset(buffer, 0, sizeof(buffer));
lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4; lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "/", 'B', buffer+4, 9) => 9; lfs_getattr(&lfs, "/", 'B', buffer+4, 9) => 9;
@@ -155,22 +155,22 @@ code = '''
[[case]] # set/get file attribute [[case]] # set/get file attribute
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "hello") => 0; lfs_mkdir(&lfs, "hello") => 0;
lfs_file_open(&lfs, &file, "hello/hello", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs_file_open(&lfs, &file, "hello/hello", LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello"); lfs_file_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello");
lfs_file_close(&lfs, &file); lfs_file_close(&lfs, &file);
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
memset(buffer, 0, sizeof(buffer)); memset(buffer, 0, sizeof(buffer));
struct lfs_attr attrs1[] = { struct lfs_attr attrs1[] = {
{'A', buffer, 4}, {'A', buffer, 4},
{'B', buffer+4, 6}, {'B', buffer+4, 6},
{'C', buffer+10, 5}, {'C', buffer+10, 5},
}; };
struct lfs_file_config cfg1 = {.attrs=attrs1, .attr_count=3}; struct lfs_file_cfg cfg1 = {.attrs=attrs1, .attr_count=3};
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0; lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0;
memcpy(buffer, "aaaa", 4); memcpy(buffer, "aaaa", 4);
@@ -228,7 +228,7 @@ code = '''
{'B', buffer+4, 9}, {'B', buffer+4, 9},
{'C', buffer+13, 5}, {'C', buffer+13, 5},
}; };
struct lfs_file_config cfg2 = {.attrs=attrs2, .attr_count=3}; struct lfs_file_cfg cfg2 = {.attrs=attrs2, .attr_count=3};
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDWR, &cfg2) => 0; lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDWR, &cfg2) => 0;
memcpy(buffer+4, "fffffffff", 9); memcpy(buffer+4, "fffffffff", 9);
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
@@ -238,14 +238,14 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
memset(buffer, 0, sizeof(buffer)); memset(buffer, 0, sizeof(buffer));
struct lfs_attr attrs3[] = { struct lfs_attr attrs3[] = {
{'A', buffer, 4}, {'A', buffer, 4},
{'B', buffer+4, 9}, {'B', buffer+4, 9},
{'C', buffer+13, 5}, {'C', buffer+13, 5},
}; };
struct lfs_file_config cfg3 = {.attrs=attrs3, .attr_count=3}; struct lfs_file_cfg cfg3 = {.attrs=attrs3, .attr_count=3};
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg3) => 0; lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg3) => 0;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
@@ -262,15 +262,15 @@ code = '''
[[case]] # deferred file attributes [[case]] # deferred file attributes
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "hello") => 0; lfs_mkdir(&lfs, "hello") => 0;
lfs_file_open(&lfs, &file, "hello/hello", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs_file_open(&lfs, &file, "hello/hello", LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello"); lfs_file_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello");
lfs_file_close(&lfs, &file); lfs_file_close(&lfs, &file);
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_setattr(&lfs, "hello/hello", 'B', "fffffffff", 9) => 0; lfs_setattr(&lfs, "hello/hello", 'B', "fffffffff", 9) => 0;
lfs_setattr(&lfs, "hello/hello", 'C', "ccccc", 5) => 0; lfs_setattr(&lfs, "hello/hello", 'C', "ccccc", 5) => 0;
@@ -280,7 +280,7 @@ code = '''
{'C', "", 0}, {'C', "", 0},
{'D', "hhhh", 4}, {'D', "hhhh", 4},
}; };
struct lfs_file_config cfg1 = {.attrs=attrs1, .attr_count=3}; struct lfs_file_cfg cfg1 = {.attrs=attrs1, .attr_count=3};
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0; lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0;

View File

@@ -16,12 +16,12 @@ define.NAMEMULT = 64
define.FILEMULT = 1 define.FILEMULT = 1
code = ''' code = '''
for (lfs_block_t badblock = 2; badblock < LFS_BLOCK_COUNT; badblock++) { for (lfs_block_t badblock = 2; badblock < LFS_BLOCK_COUNT; badblock++) {
lfs_testbd_setwear(&cfg, badblock-1, 0) => 0; lfs_testbd_setwear(&bd, badblock-1, 0) => 0;
lfs_testbd_setwear(&cfg, badblock, 0xffffffff) => 0; lfs_testbd_setwear(&bd, badblock, 0xffffffff) => 0;
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
for (int i = 1; i < 10; i++) { for (int i = 1; i < 10; i++) {
for (int j = 0; j < NAMEMULT; j++) { for (int j = 0; j < NAMEMULT; j++) {
buffer[j] = '0'+i; buffer[j] = '0'+i;
@@ -46,7 +46,7 @@ code = '''
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
for (int i = 1; i < 10; i++) { for (int i = 1; i < 10; i++) {
for (int j = 0; j < NAMEMULT; j++) { for (int j = 0; j < NAMEMULT; j++) {
buffer[j] = '0'+i; buffer[j] = '0'+i;
@@ -90,12 +90,12 @@ define.NAMEMULT = 64
define.FILEMULT = 1 define.FILEMULT = 1
code = ''' code = '''
for (lfs_block_t i = 0; i < (LFS_BLOCK_COUNT-2)/2; i++) { for (lfs_block_t i = 0; i < (LFS_BLOCK_COUNT-2)/2; i++) {
lfs_testbd_setwear(&cfg, i+2, 0xffffffff) => 0; lfs_testbd_setwear(&bd, i+2, 0xffffffff) => 0;
} }
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
for (int i = 1; i < 10; i++) { for (int i = 1; i < 10; i++) {
for (int j = 0; j < NAMEMULT; j++) { for (int j = 0; j < NAMEMULT; j++) {
buffer[j] = '0'+i; buffer[j] = '0'+i;
@@ -120,7 +120,7 @@ code = '''
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
for (int i = 1; i < 10; i++) { for (int i = 1; i < 10; i++) {
for (int j = 0; j < NAMEMULT; j++) { for (int j = 0; j < NAMEMULT; j++) {
buffer[j] = '0'+i; buffer[j] = '0'+i;
@@ -163,12 +163,12 @@ define.NAMEMULT = 64
define.FILEMULT = 1 define.FILEMULT = 1
code = ''' code = '''
for (lfs_block_t i = 0; i < (LFS_BLOCK_COUNT-2)/2; i++) { for (lfs_block_t i = 0; i < (LFS_BLOCK_COUNT-2)/2; i++) {
lfs_testbd_setwear(&cfg, (2*i) + 2, 0xffffffff) => 0; lfs_testbd_setwear(&bd, (2*i) + 2, 0xffffffff) => 0;
} }
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
for (int i = 1; i < 10; i++) { for (int i = 1; i < 10; i++) {
for (int j = 0; j < NAMEMULT; j++) { for (int j = 0; j < NAMEMULT; j++) {
buffer[j] = '0'+i; buffer[j] = '0'+i;
@@ -193,7 +193,7 @@ code = '''
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
for (int i = 1; i < 10; i++) { for (int i = 1; i < 10; i++) {
for (int j = 0; j < NAMEMULT; j++) { for (int j = 0; j < NAMEMULT; j++) {
buffer[j] = '0'+i; buffer[j] = '0'+i;
@@ -233,9 +233,9 @@ define.LFS_BADBLOCK_BEHAVIOR = [
'LFS_TESTBD_BADBLOCK_ERASENOOP', 'LFS_TESTBD_BADBLOCK_ERASENOOP',
] ]
code = ''' code = '''
lfs_testbd_setwear(&cfg, 0, 0xffffffff) => 0; lfs_testbd_setwear(&bd, 0, 0xffffffff) => 0;
lfs_testbd_setwear(&cfg, 1, 0xffffffff) => 0; lfs_testbd_setwear(&bd, 1, 0xffffffff) => 0;
lfs_format(&lfs, &cfg) => LFS_ERR_NOSPC; lfs_formatcfg(&lfs, &cfg) => LFS_ERR_NOSPC;
lfs_mount(&lfs, &cfg) => LFS_ERR_CORRUPT; lfs_mountcfg(&lfs, &cfg) => LFS_ERR_CORRUPT;
''' '''

View File

@@ -1,7 +1,7 @@
[[case]] # root [[case]] # root
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir, "/") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
@@ -17,16 +17,16 @@ code = '''
[[case]] # many directory creation [[case]] # many directory creation
define.N = 'range(0, 100, 3)' define.N = 'range(0, 100, 3)'
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
sprintf(path, "dir%03d", i); sprintf(path, "dir%03d", i);
lfs_mkdir(&lfs, path) => 0; lfs_mkdir(&lfs, path) => 0;
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir, "/") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
@@ -48,16 +48,16 @@ code = '''
[[case]] # many directory removal [[case]] # many directory removal
define.N = 'range(3, 100, 11)' define.N = 'range(3, 100, 11)'
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
sprintf(path, "removeme%03d", i); sprintf(path, "removeme%03d", i);
lfs_mkdir(&lfs, path) => 0; lfs_mkdir(&lfs, path) => 0;
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir, "/") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
@@ -75,14 +75,14 @@ code = '''
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs); lfs_unmount(&lfs);
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
sprintf(path, "removeme%03d", i); sprintf(path, "removeme%03d", i);
lfs_remove(&lfs, path) => 0; lfs_remove(&lfs, path) => 0;
} }
lfs_unmount(&lfs); lfs_unmount(&lfs);
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir, "/") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
@@ -98,16 +98,16 @@ code = '''
[[case]] # many directory rename [[case]] # many directory rename
define.N = 'range(3, 100, 11)' define.N = 'range(3, 100, 11)'
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
sprintf(path, "test%03d", i); sprintf(path, "test%03d", i);
lfs_mkdir(&lfs, path) => 0; lfs_mkdir(&lfs, path) => 0;
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir, "/") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
@@ -125,7 +125,7 @@ code = '''
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs); lfs_unmount(&lfs);
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
char oldpath[128]; char oldpath[128];
char newpath[128]; char newpath[128];
@@ -135,7 +135,7 @@ code = '''
} }
lfs_unmount(&lfs); lfs_unmount(&lfs);
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir, "/") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
@@ -158,10 +158,10 @@ code = '''
define.N = [5, 11] define.N = [5, 11]
reentrant = true reentrant = true
code = ''' code = '''
err = lfs_mount(&lfs, &cfg); err = lfs_mountcfg(&lfs, &cfg);
if (err) { if (err) {
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
} }
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
@@ -237,9 +237,9 @@ code = '''
[[case]] # file creation [[case]] # file creation
define.N = 'range(3, 100, 11)' define.N = 'range(3, 100, 11)'
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
sprintf(path, "file%03d", i); sprintf(path, "file%03d", i);
lfs_file_open(&lfs, &file, path, lfs_file_open(&lfs, &file, path,
@@ -248,7 +248,7 @@ code = '''
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir, "/") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
@@ -270,9 +270,9 @@ code = '''
[[case]] # file removal [[case]] # file removal
define.N = 'range(0, 100, 3)' define.N = 'range(0, 100, 3)'
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
sprintf(path, "removeme%03d", i); sprintf(path, "removeme%03d", i);
lfs_file_open(&lfs, &file, path, lfs_file_open(&lfs, &file, path,
@@ -281,7 +281,7 @@ code = '''
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir, "/") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
@@ -299,14 +299,14 @@ code = '''
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs); lfs_unmount(&lfs);
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
sprintf(path, "removeme%03d", i); sprintf(path, "removeme%03d", i);
lfs_remove(&lfs, path) => 0; lfs_remove(&lfs, path) => 0;
} }
lfs_unmount(&lfs); lfs_unmount(&lfs);
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir, "/") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
@@ -322,9 +322,9 @@ code = '''
[[case]] # file rename [[case]] # file rename
define.N = 'range(0, 100, 3)' define.N = 'range(0, 100, 3)'
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
sprintf(path, "test%03d", i); sprintf(path, "test%03d", i);
lfs_file_open(&lfs, &file, path, lfs_file_open(&lfs, &file, path,
@@ -333,7 +333,7 @@ code = '''
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir, "/") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
@@ -351,7 +351,7 @@ code = '''
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs); lfs_unmount(&lfs);
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
char oldpath[128]; char oldpath[128];
char newpath[128]; char newpath[128];
@@ -361,7 +361,7 @@ code = '''
} }
lfs_unmount(&lfs); lfs_unmount(&lfs);
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir, "/") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
@@ -384,10 +384,10 @@ code = '''
define.N = [5, 25] define.N = [5, 25]
reentrant = true reentrant = true
code = ''' code = '''
err = lfs_mount(&lfs, &cfg); err = lfs_mountcfg(&lfs, &cfg);
if (err) { if (err) {
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
} }
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
@@ -462,21 +462,21 @@ code = '''
[[case]] # nested directories [[case]] # nested directories
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "potato") => 0; lfs_mkdir(&lfs, "potato") => 0;
lfs_file_open(&lfs, &file, "burito", lfs_file_open(&lfs, &file, "burito",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "potato/baked") => 0; lfs_mkdir(&lfs, "potato/baked") => 0;
lfs_mkdir(&lfs, "potato/sweet") => 0; lfs_mkdir(&lfs, "potato/sweet") => 0;
lfs_mkdir(&lfs, "potato/fried") => 0; lfs_mkdir(&lfs, "potato/fried") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "potato") => 0; lfs_dir_open(&lfs, &dir, "potato") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
@@ -498,21 +498,21 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// try removing? // try removing?
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_remove(&lfs, "potato") => LFS_ERR_NOTEMPTY; lfs_remove(&lfs, "potato") => LFS_ERR_NOTEMPTY;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// try renaming? // try renaming?
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_rename(&lfs, "potato", "coldpotato") => 0; lfs_rename(&lfs, "potato", "coldpotato") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_rename(&lfs, "coldpotato", "warmpotato") => 0; lfs_rename(&lfs, "coldpotato", "warmpotato") => 0;
lfs_rename(&lfs, "warmpotato", "hotpotato") => 0; lfs_rename(&lfs, "warmpotato", "hotpotato") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_remove(&lfs, "potato") => LFS_ERR_NOENT; lfs_remove(&lfs, "potato") => LFS_ERR_NOENT;
lfs_remove(&lfs, "coldpotato") => LFS_ERR_NOENT; lfs_remove(&lfs, "coldpotato") => LFS_ERR_NOENT;
lfs_remove(&lfs, "warmpotato") => LFS_ERR_NOENT; lfs_remove(&lfs, "warmpotato") => LFS_ERR_NOENT;
@@ -520,7 +520,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// try cross-directory renaming // try cross-directory renaming
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "coldpotato") => 0; lfs_mkdir(&lfs, "coldpotato") => 0;
lfs_rename(&lfs, "hotpotato/baked", "coldpotato/baked") => 0; lfs_rename(&lfs, "hotpotato/baked", "coldpotato/baked") => 0;
lfs_rename(&lfs, "coldpotato", "hotpotato") => LFS_ERR_NOTEMPTY; lfs_rename(&lfs, "coldpotato", "hotpotato") => LFS_ERR_NOTEMPTY;
@@ -536,7 +536,7 @@ code = '''
lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY; lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "hotpotato") => 0; lfs_dir_open(&lfs, &dir, "hotpotato") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
@@ -558,7 +558,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// final remove // final remove
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY; lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY;
lfs_remove(&lfs, "hotpotato/baked") => 0; lfs_remove(&lfs, "hotpotato/baked") => 0;
lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY; lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY;
@@ -568,7 +568,7 @@ code = '''
lfs_remove(&lfs, "hotpotato") => 0; lfs_remove(&lfs, "hotpotato") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir, "/") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
@@ -587,8 +587,8 @@ code = '''
[[case]] # recursive remove [[case]] # recursive remove
define.N = [10, 100] define.N = [10, 100]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "prickly-pear") => 0; lfs_mkdir(&lfs, "prickly-pear") => 0;
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
sprintf(path, "prickly-pear/cactus%03d", i); sprintf(path, "prickly-pear/cactus%03d", i);
@@ -611,7 +611,7 @@ code = '''
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs); lfs_unmount(&lfs);
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_remove(&lfs, "prickly-pear") => LFS_ERR_NOTEMPTY; lfs_remove(&lfs, "prickly-pear") => LFS_ERR_NOTEMPTY;
lfs_dir_open(&lfs, &dir, "prickly-pear") => 0; lfs_dir_open(&lfs, &dir, "prickly-pear") => 0;
@@ -636,22 +636,22 @@ code = '''
lfs_remove(&lfs, "prickly-pear") => LFS_ERR_NOENT; lfs_remove(&lfs, "prickly-pear") => LFS_ERR_NOENT;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_remove(&lfs, "prickly-pear") => LFS_ERR_NOENT; lfs_remove(&lfs, "prickly-pear") => LFS_ERR_NOENT;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # other error cases [[case]] # other error cases
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "potato") => 0; lfs_mkdir(&lfs, "potato") => 0;
lfs_file_open(&lfs, &file, "burito", lfs_file_open(&lfs, &file, "burito",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "potato") => LFS_ERR_EXIST; lfs_mkdir(&lfs, "potato") => LFS_ERR_EXIST;
lfs_mkdir(&lfs, "burito") => LFS_ERR_EXIST; lfs_mkdir(&lfs, "burito") => LFS_ERR_EXIST;
@@ -696,7 +696,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// or on disk // or on disk
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir, "/") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
@@ -718,8 +718,8 @@ code = '''
[[case]] # directory seek [[case]] # directory seek
define.COUNT = [4, 128, 132] define.COUNT = [4, 128, 132]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "hello") => 0; lfs_mkdir(&lfs, "hello") => 0;
for (int i = 0; i < COUNT; i++) { for (int i = 0; i < COUNT; i++) {
sprintf(path, "hello/kitty%03d", i); sprintf(path, "hello/kitty%03d", i);
@@ -728,7 +728,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
for (int j = 2; j < COUNT; j++) { for (int j = 2; j < COUNT; j++) {
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "hello") => 0; lfs_dir_open(&lfs, &dir, "hello") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
@@ -779,8 +779,8 @@ code = '''
[[case]] # root seek [[case]] # root seek
define.COUNT = [4, 128, 132] define.COUNT = [4, 128, 132]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
for (int i = 0; i < COUNT; i++) { for (int i = 0; i < COUNT; i++) {
sprintf(path, "hi%03d", i); sprintf(path, "hi%03d", i);
lfs_mkdir(&lfs, path) => 0; lfs_mkdir(&lfs, path) => 0;
@@ -788,7 +788,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
for (int j = 2; j < COUNT; j++) { for (int j = 2; j < COUNT; j++) {
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir, "/") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);

View File

@@ -10,8 +10,8 @@ code = '''
uint8_t wbuffer[1024]; uint8_t wbuffer[1024];
uint8_t rbuffer[1024]; uint8_t rbuffer[1024];
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
// write hi0 20 // write hi0 20
sprintf(path, "hi0"); size = 20; sprintf(path, "hi0"); size = 20;
@@ -99,8 +99,8 @@ code = '''
uint8_t wbuffer[1024]; uint8_t wbuffer[1024];
uint8_t rbuffer[1024]; uint8_t rbuffer[1024];
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
// write hi0 20 // write hi0 20
sprintf(path, "hi0"); size = 20; sprintf(path, "hi0"); size = 20;
@@ -188,8 +188,8 @@ code = '''
uint8_t wbuffer[1024]; uint8_t wbuffer[1024];
uint8_t rbuffer[1024]; uint8_t rbuffer[1024];
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
// write hi0 200 // write hi0 200
sprintf(path, "hi0"); size = 200; sprintf(path, "hi0"); size = 200;
@@ -261,8 +261,8 @@ code = '''
uint8_t wbuffer[1024]; uint8_t wbuffer[1024];
uint8_t rbuffer[1024]; uint8_t rbuffer[1024];
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
// write hi0 200 // write hi0 200
sprintf(path, "hi0"); size = 200; sprintf(path, "hi0"); size = 200;
@@ -350,8 +350,8 @@ code = '''
uint8_t wbuffer[1024]; uint8_t wbuffer[1024];
uint8_t rbuffer[1024]; uint8_t rbuffer[1024];
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
// write hi0 200 // write hi0 200
sprintf(path, "hi0"); size = 200; sprintf(path, "hi0"); size = 200;
@@ -454,8 +454,8 @@ code = '''
uint8_t wbuffer[1024]; uint8_t wbuffer[1024];
uint8_t rbuffer[1024]; uint8_t rbuffer[1024];
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
// write hi0 200 // write hi0 200
sprintf(path, "hi0"); size = 200; sprintf(path, "hi0"); size = 200;
@@ -549,9 +549,9 @@ code = '''
[[case]] # create too big [[case]] # create too big
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
memset(path, 'm', 200); memset(path, 'm', 200);
path[200] = '\0'; path[200] = '\0';
@@ -574,9 +574,9 @@ code = '''
[[case]] # resize too big [[case]] # resize too big
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
memset(path, 'm', 200); memset(path, 'm', 200);
path[200] = '\0'; path[200] = '\0';

View File

@@ -9,10 +9,11 @@ define.INVALSET = [0x3, 0x1, 0x2]
in = "lfs.c" in = "lfs.c"
code = ''' code = '''
// create littlefs // create littlefs
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
// change tail-pointer to invalid pointers // change tail-pointer to invalid pointers
lfs_init(&lfs, &cfg) => 0; lfs.cfg = &cfg;
lfs_initcommon(&lfs) => 0;
lfs_mdir_t mdir; lfs_mdir_t mdir;
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS( lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS(
@@ -23,7 +24,7 @@ code = '''
lfs_deinit(&lfs) => 0; lfs_deinit(&lfs) => 0;
// test that mount fails gracefully // test that mount fails gracefully
lfs_mount(&lfs, &cfg) => LFS_ERR_CORRUPT; lfs_mountcfg(&lfs, &cfg) => LFS_ERR_CORRUPT;
''' '''
[[case]] # invalid dir pointer test [[case]] # invalid dir pointer test
@@ -31,14 +32,15 @@ define.INVALSET = [0x3, 0x1, 0x2]
in = "lfs.c" in = "lfs.c"
code = ''' code = '''
// create littlefs // create littlefs
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
// make a dir // make a dir
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "dir_here") => 0; lfs_mkdir(&lfs, "dir_here") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// change the dir pointer to be invalid // change the dir pointer to be invalid
lfs_init(&lfs, &cfg) => 0; lfs.cfg = &cfg;
lfs_initcommon(&lfs) => 0;
lfs_mdir_t mdir; lfs_mdir_t mdir;
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
// make sure id 1 == our directory // make sure id 1 == our directory
@@ -57,7 +59,7 @@ code = '''
// test that accessing our bad dir fails, note there's a number // test that accessing our bad dir fails, note there's a number
// of ways to access the dir, some can fail, but some don't // of ways to access the dir, some can fail, but some don't
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_stat(&lfs, "dir_here", &info) => 0; lfs_stat(&lfs, "dir_here", &info) => 0;
assert(strcmp(info.name, "dir_here") == 0); assert(strcmp(info.name, "dir_here") == 0);
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
@@ -77,16 +79,17 @@ in = "lfs.c"
define.SIZE = [10, 1000, 100000] # faked file size define.SIZE = [10, 1000, 100000] # faked file size
code = ''' code = '''
// create littlefs // create littlefs
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
// make a file // make a file
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "file_here", lfs_file_open(&lfs, &file, "file_here",
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// change the file pointer to be invalid // change the file pointer to be invalid
lfs_init(&lfs, &cfg) => 0; lfs.cfg = &cfg;
lfs_initcommon(&lfs) => 0;
lfs_mdir_t mdir; lfs_mdir_t mdir;
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
// make sure id 1 == our file // make sure id 1 == our file
@@ -103,7 +106,7 @@ code = '''
// test that accessing our bad file fails, note there's a number // test that accessing our bad file fails, note there's a number
// of ways to access the dir, some can fail, but some don't // of ways to access the dir, some can fail, but some don't
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_stat(&lfs, "file_here", &info) => 0; lfs_stat(&lfs, "file_here", &info) => 0;
assert(strcmp(info.name, "file_here") == 0); assert(strcmp(info.name, "file_here") == 0);
assert(info.type == LFS_TYPE_REG); assert(info.type == LFS_TYPE_REG);
@@ -125,9 +128,9 @@ define.SIZE = ['2*LFS_BLOCK_SIZE', '3*LFS_BLOCK_SIZE', '4*LFS_BLOCK_SIZE']
in = "lfs.c" in = "lfs.c"
code = ''' code = '''
// create littlefs // create littlefs
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
// make a file // make a file
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "file_here", lfs_file_open(&lfs, &file, "file_here",
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS_O_WRONLY | LFS_O_CREAT) => 0;
for (int i = 0; i < SIZE; i++) { for (int i = 0; i < SIZE; i++) {
@@ -137,7 +140,8 @@ code = '''
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// change pointer in CTZ skip-list to be invalid // change pointer in CTZ skip-list to be invalid
lfs_init(&lfs, &cfg) => 0; lfs.cfg = &cfg;
lfs_initcommon(&lfs) => 0;
lfs_mdir_t mdir; lfs_mdir_t mdir;
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
// make sure id 1 == our file and get our CTZ structure // make sure id 1 == our file and get our CTZ structure
@@ -154,17 +158,17 @@ code = '''
lfs_ctz_fromle32(&ctz); lfs_ctz_fromle32(&ctz);
// rewrite block to contain bad pointer // rewrite block to contain bad pointer
uint8_t bbuffer[LFS_BLOCK_SIZE]; uint8_t bbuffer[LFS_BLOCK_SIZE];
cfg.read(&cfg, ctz.head, 0, bbuffer, LFS_BLOCK_SIZE) => 0; lfs_testbd_read(&bd, ctz.head, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
uint32_t bad = lfs_tole32(0xcccccccc); uint32_t bad = lfs_tole32(0xcccccccc);
memcpy(&bbuffer[0], &bad, sizeof(bad)); memcpy(&bbuffer[0], &bad, sizeof(bad));
memcpy(&bbuffer[4], &bad, sizeof(bad)); memcpy(&bbuffer[4], &bad, sizeof(bad));
cfg.erase(&cfg, ctz.head) => 0; lfs_testbd_erase(&bd, ctz.head) => 0;
cfg.prog(&cfg, ctz.head, 0, bbuffer, LFS_BLOCK_SIZE) => 0; lfs_testbd_prog(&bd, ctz.head, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
lfs_deinit(&lfs) => 0; lfs_deinit(&lfs) => 0;
// test that accessing our bad file fails, note there's a number // test that accessing our bad file fails, note there's a number
// of ways to access the dir, some can fail, but some don't // of ways to access the dir, some can fail, but some don't
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_stat(&lfs, "file_here", &info) => 0; lfs_stat(&lfs, "file_here", &info) => 0;
assert(strcmp(info.name, "file_here") == 0); assert(strcmp(info.name, "file_here") == 0);
assert(info.type == LFS_TYPE_REG); assert(info.type == LFS_TYPE_REG);
@@ -187,10 +191,11 @@ define.INVALSET = [0x3, 0x1, 0x2]
in = "lfs.c" in = "lfs.c"
code = ''' code = '''
// create littlefs // create littlefs
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
// create an invalid gstate // create an invalid gstate
lfs_init(&lfs, &cfg) => 0; lfs.cfg = &cfg;
lfs_initcommon(&lfs) => 0;
lfs_mdir_t mdir; lfs_mdir_t mdir;
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
lfs_fs_prepmove(&lfs, 1, (lfs_block_t [2]){ lfs_fs_prepmove(&lfs, 1, (lfs_block_t [2]){
@@ -202,7 +207,7 @@ code = '''
// test that mount fails gracefully // test that mount fails gracefully
// mount may not fail, but our first alloc should fail when // mount may not fail, but our first alloc should fail when
// we try to fix the gstate // we try to fix the gstate
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "should_fail") => LFS_ERR_CORRUPT; lfs_mkdir(&lfs, "should_fail") => LFS_ERR_CORRUPT;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
@@ -213,10 +218,11 @@ code = '''
in = "lfs.c" in = "lfs.c"
code = ''' code = '''
// create littlefs // create littlefs
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
// change tail-pointer to point to ourself // change tail-pointer to point to ourself
lfs_init(&lfs, &cfg) => 0; lfs.cfg = &cfg;
lfs_initcommon(&lfs) => 0;
lfs_mdir_t mdir; lfs_mdir_t mdir;
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS( lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS(
@@ -225,20 +231,21 @@ code = '''
lfs_deinit(&lfs) => 0; lfs_deinit(&lfs) => 0;
// test that mount fails gracefully // test that mount fails gracefully
lfs_mount(&lfs, &cfg) => LFS_ERR_CORRUPT; lfs_mountcfg(&lfs, &cfg) => LFS_ERR_CORRUPT;
''' '''
[[case]] # metadata-pair threaded-list 2-length loop test [[case]] # metadata-pair threaded-list 2-length loop test
in = "lfs.c" in = "lfs.c"
code = ''' code = '''
// create littlefs with child dir // create littlefs with child dir
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "child") => 0; lfs_mkdir(&lfs, "child") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// find child // find child
lfs_init(&lfs, &cfg) => 0; lfs.cfg = &cfg;
lfs_initcommon(&lfs) => 0;
lfs_mdir_t mdir; lfs_mdir_t mdir;
lfs_block_t pair[2]; lfs_block_t pair[2];
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
@@ -255,20 +262,21 @@ code = '''
lfs_deinit(&lfs) => 0; lfs_deinit(&lfs) => 0;
// test that mount fails gracefully // test that mount fails gracefully
lfs_mount(&lfs, &cfg) => LFS_ERR_CORRUPT; lfs_mountcfg(&lfs, &cfg) => LFS_ERR_CORRUPT;
''' '''
[[case]] # metadata-pair threaded-list 1-length child loop test [[case]] # metadata-pair threaded-list 1-length child loop test
in = "lfs.c" in = "lfs.c"
code = ''' code = '''
// create littlefs with child dir // create littlefs with child dir
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "child") => 0; lfs_mkdir(&lfs, "child") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// find child // find child
lfs_init(&lfs, &cfg) => 0; lfs.cfg = &cfg;
lfs_initcommon(&lfs) => 0;
lfs_mdir_t mdir; lfs_mdir_t mdir;
lfs_block_t pair[2]; lfs_block_t pair[2];
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
@@ -284,5 +292,5 @@ code = '''
lfs_deinit(&lfs) => 0; lfs_deinit(&lfs) => 0;
// test that mount fails gracefully // test that mount fails gracefully
lfs_mount(&lfs, &cfg) => LFS_ERR_CORRUPT; lfs_mountcfg(&lfs, &cfg) => LFS_ERR_CORRUPT;
''' '''

View File

@@ -11,14 +11,14 @@ define.LFS_BADBLOCK_BEHAVIOR = [
] ]
define.FILES = 10 define.FILES = 10
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "roadrunner") => 0; lfs_mkdir(&lfs, "roadrunner") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
uint32_t cycle = 0; uint32_t cycle = 0;
while (true) { while (true) {
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
for (uint32_t i = 0; i < FILES; i++) { for (uint32_t i = 0; i < FILES; i++) {
// chose name, roughly random seed, and random 2^n size // chose name, roughly random seed, and random 2^n size
sprintf(path, "roadrunner/test%d", i); sprintf(path, "roadrunner/test%d", i);
@@ -71,7 +71,7 @@ code = '''
exhausted: exhausted:
// should still be readable // should still be readable
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
for (uint32_t i = 0; i < FILES; i++) { for (uint32_t i = 0; i < FILES; i++) {
// check for errors // check for errors
sprintf(path, "roadrunner/test%d", i); sprintf(path, "roadrunner/test%d", i);
@@ -96,11 +96,11 @@ define.LFS_BADBLOCK_BEHAVIOR = [
] ]
define.FILES = 10 define.FILES = 10
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
uint32_t cycle = 0; uint32_t cycle = 0;
while (true) { while (true) {
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
for (uint32_t i = 0; i < FILES; i++) { for (uint32_t i = 0; i < FILES; i++) {
// chose name, roughly random seed, and random 2^n size // chose name, roughly random seed, and random 2^n size
sprintf(path, "test%d", i); sprintf(path, "test%d", i);
@@ -153,7 +153,7 @@ code = '''
exhausted: exhausted:
// should still be readable // should still be readable
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
for (uint32_t i = 0; i < FILES; i++) { for (uint32_t i = 0; i < FILES; i++) {
// check for errors // check for errors
sprintf(path, "test%d", i); sprintf(path, "test%d", i);
@@ -180,18 +180,18 @@ code = '''
for (int run = 0; run < 2; run++) { for (int run = 0; run < 2; run++) {
for (lfs_block_t b = 0; b < LFS_BLOCK_COUNT; b++) { for (lfs_block_t b = 0; b < LFS_BLOCK_COUNT; b++) {
lfs_testbd_setwear(&cfg, b, lfs_testbd_setwear(&bd, b,
(b < run_block_count[run]) ? 0 : LFS_ERASE_CYCLES) => 0; (b < run_block_count[run]) ? 0 : LFS_ERASE_CYCLES) => 0;
} }
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "roadrunner") => 0; lfs_mkdir(&lfs, "roadrunner") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
uint32_t cycle = 0; uint32_t cycle = 0;
while (true) { while (true) {
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
for (uint32_t i = 0; i < FILES; i++) { for (uint32_t i = 0; i < FILES; i++) {
// chose name, roughly random seed, and random 2^n size // chose name, roughly random seed, and random 2^n size
sprintf(path, "roadrunner/test%d", i); sprintf(path, "roadrunner/test%d", i);
@@ -244,7 +244,7 @@ code = '''
exhausted: exhausted:
// should still be readable // should still be readable
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
for (uint32_t i = 0; i < FILES; i++) { for (uint32_t i = 0; i < FILES; i++) {
// check for errors // check for errors
sprintf(path, "roadrunner/test%d", i); sprintf(path, "roadrunner/test%d", i);
@@ -272,15 +272,15 @@ code = '''
for (int run = 0; run < 2; run++) { for (int run = 0; run < 2; run++) {
for (lfs_block_t b = 0; b < LFS_BLOCK_COUNT; b++) { for (lfs_block_t b = 0; b < LFS_BLOCK_COUNT; b++) {
lfs_testbd_setwear(&cfg, b, lfs_testbd_setwear(&bd, b,
(b < run_block_count[run]) ? 0 : LFS_ERASE_CYCLES) => 0; (b < run_block_count[run]) ? 0 : LFS_ERASE_CYCLES) => 0;
} }
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
uint32_t cycle = 0; uint32_t cycle = 0;
while (true) { while (true) {
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
for (uint32_t i = 0; i < FILES; i++) { for (uint32_t i = 0; i < FILES; i++) {
// chose name, roughly random seed, and random 2^n size // chose name, roughly random seed, and random 2^n size
sprintf(path, "test%d", i); sprintf(path, "test%d", i);
@@ -333,7 +333,7 @@ code = '''
exhausted: exhausted:
// should still be readable // should still be readable
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
for (uint32_t i = 0; i < FILES; i++) { for (uint32_t i = 0; i < FILES; i++) {
// check for errors // check for errors
sprintf(path, "test%d", i); sprintf(path, "test%d", i);
@@ -358,14 +358,14 @@ define.CYCLES = 100
define.FILES = 10 define.FILES = 10
if = 'LFS_BLOCK_CYCLES < CYCLES/10' if = 'LFS_BLOCK_CYCLES < CYCLES/10'
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "roadrunner") => 0; lfs_mkdir(&lfs, "roadrunner") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
uint32_t cycle = 0; uint32_t cycle = 0;
while (cycle < CYCLES) { while (cycle < CYCLES) {
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
for (uint32_t i = 0; i < FILES; i++) { for (uint32_t i = 0; i < FILES; i++) {
// chose name, roughly random seed, and random 2^n size // chose name, roughly random seed, and random 2^n size
sprintf(path, "roadrunner/test%d", i); sprintf(path, "roadrunner/test%d", i);
@@ -418,7 +418,7 @@ code = '''
exhausted: exhausted:
// should still be readable // should still be readable
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
for (uint32_t i = 0; i < FILES; i++) { for (uint32_t i = 0; i < FILES; i++) {
// check for errors // check for errors
sprintf(path, "roadrunner/test%d", i); sprintf(path, "roadrunner/test%d", i);
@@ -434,7 +434,7 @@ exhausted:
lfs_testbd_wear_t maxwear = 0; lfs_testbd_wear_t maxwear = 0;
// skip 0 and 1 as superblock movement is intentionally avoided // skip 0 and 1 as superblock movement is intentionally avoided
for (lfs_block_t b = 2; b < LFS_BLOCK_COUNT; b++) { for (lfs_block_t b = 2; b < LFS_BLOCK_COUNT; b++) {
lfs_testbd_wear_t wear = lfs_testbd_getwear(&cfg, b); lfs_testbd_wear_t wear = lfs_testbd_getwear(&bd, b);
printf("%08x: wear %d\n", b, wear); printf("%08x: wear %d\n", b, wear);
assert(wear >= 0); assert(wear >= 0);
if (wear < minwear) { if (wear < minwear) {
@@ -453,7 +453,7 @@ exhausted:
// find standard deviation^2 // find standard deviation^2
lfs_testbd_wear_t dev2 = 0; lfs_testbd_wear_t dev2 = 0;
for (lfs_block_t b = 2; b < LFS_BLOCK_COUNT; b++) { for (lfs_block_t b = 2; b < LFS_BLOCK_COUNT; b++) {
lfs_testbd_wear_t wear = lfs_testbd_getwear(&cfg, b); lfs_testbd_wear_t wear = lfs_testbd_getwear(&bd, b);
assert(wear >= 0); assert(wear >= 0);
lfs_testbd_swear_t diff = wear - avgwear; lfs_testbd_swear_t diff = wear - avgwear;
dev2 += diff*diff; dev2 += diff*diff;

View File

@@ -1,8 +1,8 @@
[[case]] # simple file test [[case]] # simple file test
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "hello", lfs_file_open(&lfs, &file, "hello",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
size = strlen("Hello World!")+1; size = strlen("Hello World!")+1;
@@ -11,7 +11,7 @@ code = '''
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "hello", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, "hello", LFS_O_RDONLY) => 0;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file, buffer, size) => size;
assert(strcmp((char*)buffer, "Hello World!") == 0); assert(strcmp((char*)buffer, "Hello World!") == 0);
@@ -23,10 +23,10 @@ code = '''
define.SIZE = [32, 8192, 262144, 0, 7, 8193] define.SIZE = [32, 8192, 262144, 0, 7, 8193]
define.CHUNKSIZE = [31, 16, 33, 1, 1023] define.CHUNKSIZE = [31, 16, 33, 1, 1023]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
// write // write
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", lfs_file_open(&lfs, &file, "avacado",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
srand(1); srand(1);
@@ -41,7 +41,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// read // read
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => SIZE; lfs_file_size(&lfs, &file) => SIZE;
srand(1); srand(1);
@@ -62,10 +62,10 @@ define.SIZE1 = [32, 8192, 131072, 0, 7, 8193]
define.SIZE2 = [32, 8192, 131072, 0, 7, 8193] define.SIZE2 = [32, 8192, 131072, 0, 7, 8193]
define.CHUNKSIZE = [31, 16, 1] define.CHUNKSIZE = [31, 16, 1]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
// write // write
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", lfs_file_open(&lfs, &file, "avacado",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
srand(1); srand(1);
@@ -80,7 +80,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// read // read
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => SIZE1; lfs_file_size(&lfs, &file) => SIZE1;
srand(1); srand(1);
@@ -96,7 +96,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// rewrite // rewrite
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY) => 0; lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY) => 0;
srand(2); srand(2);
for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) {
@@ -110,7 +110,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// read // read
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => lfs_max(SIZE1, SIZE2); lfs_file_size(&lfs, &file) => lfs_max(SIZE1, SIZE2);
srand(2); srand(2);
@@ -144,10 +144,10 @@ define.SIZE1 = [32, 8192, 131072, 0, 7, 8193]
define.SIZE2 = [32, 8192, 131072, 0, 7, 8193] define.SIZE2 = [32, 8192, 131072, 0, 7, 8193]
define.CHUNKSIZE = [31, 16, 1] define.CHUNKSIZE = [31, 16, 1]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
// write // write
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", lfs_file_open(&lfs, &file, "avacado",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
srand(1); srand(1);
@@ -162,7 +162,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// read // read
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => SIZE1; lfs_file_size(&lfs, &file) => SIZE1;
srand(1); srand(1);
@@ -178,7 +178,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// append // append
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY | LFS_O_APPEND) => 0; lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY | LFS_O_APPEND) => 0;
srand(2); srand(2);
for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) {
@@ -192,7 +192,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// read // read
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => SIZE1 + SIZE2; lfs_file_size(&lfs, &file) => SIZE1 + SIZE2;
srand(1); srand(1);
@@ -221,10 +221,10 @@ define.SIZE1 = [32, 8192, 131072, 0, 7, 8193]
define.SIZE2 = [32, 8192, 131072, 0, 7, 8193] define.SIZE2 = [32, 8192, 131072, 0, 7, 8193]
define.CHUNKSIZE = [31, 16, 1] define.CHUNKSIZE = [31, 16, 1]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
// write // write
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", lfs_file_open(&lfs, &file, "avacado",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
srand(1); srand(1);
@@ -239,7 +239,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// read // read
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => SIZE1; lfs_file_size(&lfs, &file) => SIZE1;
srand(1); srand(1);
@@ -255,7 +255,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// truncate // truncate
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY | LFS_O_TRUNC) => 0; lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY | LFS_O_TRUNC) => 0;
srand(2); srand(2);
for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) {
@@ -269,7 +269,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// read // read
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => SIZE2; lfs_file_size(&lfs, &file) => SIZE2;
srand(2); srand(2);
@@ -290,10 +290,10 @@ define.SIZE = [32, 0, 7, 2049]
define.CHUNKSIZE = [31, 16, 65] define.CHUNKSIZE = [31, 16, 65]
reentrant = true reentrant = true
code = ''' code = '''
err = lfs_mount(&lfs, &cfg); err = lfs_mountcfg(&lfs, &cfg);
if (err) { if (err) {
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
} }
err = lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY); err = lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY);
@@ -344,10 +344,10 @@ define = [
] ]
reentrant = true reentrant = true
code = ''' code = '''
err = lfs_mount(&lfs, &cfg); err = lfs_mountcfg(&lfs, &cfg);
if (err) { if (err) {
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
} }
err = lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY); err = lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY);
@@ -406,9 +406,9 @@ code = '''
[[case]] # many files [[case]] # many files
define.N = 300 define.N = 300
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
// create N files of 7 bytes // create N files of 7 bytes
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
sprintf(path, "file_%03d", i); sprintf(path, "file_%03d", i);
lfs_file_open(&lfs, &file, path, lfs_file_open(&lfs, &file, path,
@@ -431,9 +431,9 @@ code = '''
[[case]] # many files with power cycle [[case]] # many files with power cycle
define.N = 300 define.N = 300
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
// create N files of 7 bytes // create N files of 7 bytes
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
sprintf(path, "file_%03d", i); sprintf(path, "file_%03d", i);
lfs_file_open(&lfs, &file, path, lfs_file_open(&lfs, &file, path,
@@ -446,7 +446,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
char rbuffer[1024]; char rbuffer[1024];
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs_file_read(&lfs, &file, rbuffer, size) => size;
assert(strcmp(rbuffer, wbuffer) == 0); assert(strcmp(rbuffer, wbuffer) == 0);
@@ -459,10 +459,10 @@ code = '''
define.N = 300 define.N = 300
reentrant = true reentrant = true
code = ''' code = '''
err = lfs_mount(&lfs, &cfg); err = lfs_mountcfg(&lfs, &cfg);
if (err) { if (err) {
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
} }
// create N files of 7 bytes // create N files of 7 bytes
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {

View File

@@ -5,8 +5,8 @@ define.FILES = [4, 10, 26]
code = ''' code = '''
lfs_file_t files[FILES]; lfs_file_t files[FILES];
const char alphas[] = "abcdefghijklmnopqrstuvwxyz"; const char alphas[] = "abcdefghijklmnopqrstuvwxyz";
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
for (int j = 0; j < FILES; j++) { for (int j = 0; j < FILES; j++) {
sprintf(path, "%c", alphas[j]); sprintf(path, "%c", alphas[j]);
lfs_file_open(&lfs, &files[j], path, lfs_file_open(&lfs, &files[j], path,
@@ -64,8 +64,8 @@ define.SIZE = [10, 100]
define.FILES = [4, 10, 26] define.FILES = [4, 10, 26]
code = ''' code = '''
const char alphas[] = "abcdefghijklmnopqrstuvwxyz"; const char alphas[] = "abcdefghijklmnopqrstuvwxyz";
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
for (int j = 0; j < FILES; j++) { for (int j = 0; j < FILES; j++) {
sprintf(path, "%c", alphas[j]); sprintf(path, "%c", alphas[j]);
lfs_file_open(&lfs, &file, path, lfs_file_open(&lfs, &file, path,
@@ -77,7 +77,7 @@ code = '''
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "zzz", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs_file_open(&lfs, &file, "zzz", LFS_O_WRONLY | LFS_O_CREAT) => 0;
for (int j = 0; j < FILES; j++) { for (int j = 0; j < FILES; j++) {
lfs_file_write(&lfs, &file, (const void*)"~", 1) => 1; lfs_file_write(&lfs, &file, (const void*)"~", 1) => 1;
@@ -115,8 +115,8 @@ code = '''
[[case]] # remove inconveniently test [[case]] # remove inconveniently test
define.SIZE = [10, 100] define.SIZE = [10, 100]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_t files[3]; lfs_file_t files[3];
lfs_file_open(&lfs, &files[0], "e", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs_file_open(&lfs, &files[0], "e", LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_open(&lfs, &files[1], "f", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs_file_open(&lfs, &files[1], "f", LFS_O_WRONLY | LFS_O_CREAT) => 0;
@@ -180,10 +180,10 @@ code = '''
lfs_file_t files[FILES]; lfs_file_t files[FILES];
const char alphas[] = "abcdefghijklmnopqrstuvwxyz"; const char alphas[] = "abcdefghijklmnopqrstuvwxyz";
err = lfs_mount(&lfs, &cfg); err = lfs_mountcfg(&lfs, &cfg);
if (err) { if (err) {
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
} }
for (int j = 0; j < FILES; j++) { for (int j = 0; j < FILES; j++) {

View File

@@ -1,7 +1,7 @@
[[case]] # move file [[case]] # move file
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "a") => 0; lfs_mkdir(&lfs, "a") => 0;
lfs_mkdir(&lfs, "b") => 0; lfs_mkdir(&lfs, "b") => 0;
lfs_mkdir(&lfs, "c") => 0; lfs_mkdir(&lfs, "c") => 0;
@@ -13,11 +13,11 @@ code = '''
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_rename(&lfs, "a/hello", "c/hello") => 0; lfs_rename(&lfs, "a/hello", "c/hello") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "a") => 0; lfs_dir_open(&lfs, &dir, "a") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
@@ -57,8 +57,8 @@ code = '''
[[case]] # noop move, yes this is legal [[case]] # noop move, yes this is legal
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "hi") => 0; lfs_mkdir(&lfs, "hi") => 0;
lfs_rename(&lfs, "hi", "hi") => 0; lfs_rename(&lfs, "hi", "hi") => 0;
lfs_mkdir(&lfs, "hi/hi") => 0; lfs_mkdir(&lfs, "hi/hi") => 0;
@@ -74,8 +74,8 @@ code = '''
[[case]] # move file corrupt source [[case]] # move file corrupt source
in = "lfs.c" in = "lfs.c"
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "a") => 0; lfs_mkdir(&lfs, "a") => 0;
lfs_mkdir(&lfs, "b") => 0; lfs_mkdir(&lfs, "b") => 0;
lfs_mkdir(&lfs, "c") => 0; lfs_mkdir(&lfs, "c") => 0;
@@ -87,28 +87,28 @@ code = '''
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_rename(&lfs, "a/hello", "c/hello") => 0; lfs_rename(&lfs, "a/hello", "c/hello") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// corrupt the source // corrupt the source
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "a") => 0; lfs_dir_open(&lfs, &dir, "a") => 0;
lfs_block_t block = dir.m.pair[0]; lfs_block_t block = dir.m.pair[0];
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
uint8_t bbuffer[LFS_BLOCK_SIZE]; uint8_t bbuffer[LFS_BLOCK_SIZE];
cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; lfs_testbd_read(&bd, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
int off = LFS_BLOCK_SIZE-1; int off = LFS_BLOCK_SIZE-1;
while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) {
off -= 1; off -= 1;
} }
memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3);
cfg.erase(&cfg, block) => 0; lfs_testbd_erase(&bd, block) => 0;
cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; lfs_testbd_prog(&bd, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
cfg.sync(&cfg) => 0; lfs_testbd_sync(&bd) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "a") => 0; lfs_dir_open(&lfs, &dir, "a") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
@@ -150,8 +150,8 @@ code = '''
in = "lfs.c" in = "lfs.c"
if = 'LFS_PROG_SIZE <= 0x3fe' # only works with one crc per commit if = 'LFS_PROG_SIZE <= 0x3fe' # only works with one crc per commit
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "a") => 0; lfs_mkdir(&lfs, "a") => 0;
lfs_mkdir(&lfs, "b") => 0; lfs_mkdir(&lfs, "b") => 0;
lfs_mkdir(&lfs, "c") => 0; lfs_mkdir(&lfs, "c") => 0;
@@ -163,44 +163,44 @@ code = '''
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_rename(&lfs, "a/hello", "c/hello") => 0; lfs_rename(&lfs, "a/hello", "c/hello") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// corrupt the source // corrupt the source
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "a") => 0; lfs_dir_open(&lfs, &dir, "a") => 0;
lfs_block_t block = dir.m.pair[0]; lfs_block_t block = dir.m.pair[0];
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
uint8_t bbuffer[LFS_BLOCK_SIZE]; uint8_t bbuffer[LFS_BLOCK_SIZE];
cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; lfs_testbd_read(&bd, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
int off = LFS_BLOCK_SIZE-1; int off = LFS_BLOCK_SIZE-1;
while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) {
off -= 1; off -= 1;
} }
memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3);
cfg.erase(&cfg, block) => 0; lfs_testbd_erase(&bd, block) => 0;
cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; lfs_testbd_prog(&bd, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
cfg.sync(&cfg) => 0; lfs_testbd_sync(&bd) => 0;
// corrupt the destination // corrupt the destination
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "c") => 0; lfs_dir_open(&lfs, &dir, "c") => 0;
block = dir.m.pair[0]; block = dir.m.pair[0];
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; lfs_testbd_read(&bd, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
off = LFS_BLOCK_SIZE-1; off = LFS_BLOCK_SIZE-1;
while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) {
off -= 1; off -= 1;
} }
memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3);
cfg.erase(&cfg, block) => 0; lfs_testbd_erase(&bd, block) => 0;
cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; lfs_testbd_prog(&bd, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
cfg.sync(&cfg) => 0; lfs_testbd_sync(&bd) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "a") => 0; lfs_dir_open(&lfs, &dir, "a") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
@@ -242,8 +242,8 @@ code = '''
in = "lfs.c" in = "lfs.c"
if = 'LFS_PROG_SIZE <= 0x3fe' # only works with one crc per commit if = 'LFS_PROG_SIZE <= 0x3fe' # only works with one crc per commit
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "a") => 0; lfs_mkdir(&lfs, "a") => 0;
lfs_mkdir(&lfs, "b") => 0; lfs_mkdir(&lfs, "b") => 0;
lfs_mkdir(&lfs, "c") => 0; lfs_mkdir(&lfs, "c") => 0;
@@ -255,49 +255,49 @@ code = '''
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_rename(&lfs, "a/hello", "c/hello") => 0; lfs_rename(&lfs, "a/hello", "c/hello") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// corrupt the source // corrupt the source
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "a") => 0; lfs_dir_open(&lfs, &dir, "a") => 0;
lfs_block_t block = dir.m.pair[0]; lfs_block_t block = dir.m.pair[0];
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
uint8_t bbuffer[LFS_BLOCK_SIZE]; uint8_t bbuffer[LFS_BLOCK_SIZE];
cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; lfs_testbd_read(&bd, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
int off = LFS_BLOCK_SIZE-1; int off = LFS_BLOCK_SIZE-1;
while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) {
off -= 1; off -= 1;
} }
memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3);
cfg.erase(&cfg, block) => 0; lfs_testbd_erase(&bd, block) => 0;
cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; lfs_testbd_prog(&bd, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
cfg.sync(&cfg) => 0; lfs_testbd_sync(&bd) => 0;
// corrupt the destination // corrupt the destination
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "c") => 0; lfs_dir_open(&lfs, &dir, "c") => 0;
block = dir.m.pair[0]; block = dir.m.pair[0];
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; lfs_testbd_read(&bd, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
off = LFS_BLOCK_SIZE-1; off = LFS_BLOCK_SIZE-1;
while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) {
off -= 1; off -= 1;
} }
memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3);
cfg.erase(&cfg, block) => 0; lfs_testbd_erase(&bd, block) => 0;
cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; lfs_testbd_prog(&bd, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
cfg.sync(&cfg) => 0; lfs_testbd_sync(&bd) => 0;
// continue move // continue move
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_rename(&lfs, "a/hello", "c/hello") => 0; lfs_rename(&lfs, "a/hello", "c/hello") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "a") => 0; lfs_dir_open(&lfs, &dir, "a") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
@@ -338,10 +338,10 @@ code = '''
[[case]] # simple reentrant move file [[case]] # simple reentrant move file
reentrant = true reentrant = true
code = ''' code = '''
err = lfs_mount(&lfs, &cfg); err = lfs_mountcfg(&lfs, &cfg);
if (err) { if (err) {
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
} }
err = lfs_mkdir(&lfs, "a"); err = lfs_mkdir(&lfs, "a");
assert(!err || err == LFS_ERR_EXIST); assert(!err || err == LFS_ERR_EXIST);
@@ -354,7 +354,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
while (true) { while (true) {
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
// there should never exist _2_ hello files // there should never exist _2_ hello files
int count = 0; int count = 0;
if (lfs_stat(&lfs, "a/hello", &info) == 0) { if (lfs_stat(&lfs, "a/hello", &info) == 0) {
@@ -384,7 +384,7 @@ code = '''
assert(count <= 1); assert(count <= 1);
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
if (lfs_stat(&lfs, "a/hello", &info) == 0 && info.size > 0) { if (lfs_stat(&lfs, "a/hello", &info) == 0 && info.size > 0) {
lfs_rename(&lfs, "a/hello", "b/hello") => 0; lfs_rename(&lfs, "a/hello", "b/hello") => 0;
} else if (lfs_stat(&lfs, "b/hello", &info) == 0) { } else if (lfs_stat(&lfs, "b/hello", &info) == 0) {
@@ -407,7 +407,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
} }
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "a") => 0; lfs_dir_open(&lfs, &dir, "a") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
@@ -447,8 +447,8 @@ code = '''
[[case]] # move dir [[case]] # move dir
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "a") => 0; lfs_mkdir(&lfs, "a") => 0;
lfs_mkdir(&lfs, "b") => 0; lfs_mkdir(&lfs, "b") => 0;
lfs_mkdir(&lfs, "c") => 0; lfs_mkdir(&lfs, "c") => 0;
@@ -459,11 +459,11 @@ code = '''
lfs_mkdir(&lfs, "a/hi/ohayo") => 0; lfs_mkdir(&lfs, "a/hi/ohayo") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_rename(&lfs, "a/hi", "c/hi") => 0; lfs_rename(&lfs, "a/hi", "c/hi") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "a") => 0; lfs_dir_open(&lfs, &dir, "a") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
@@ -513,8 +513,8 @@ code = '''
[[case]] # move dir corrupt source [[case]] # move dir corrupt source
in = "lfs.c" in = "lfs.c"
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "a") => 0; lfs_mkdir(&lfs, "a") => 0;
lfs_mkdir(&lfs, "b") => 0; lfs_mkdir(&lfs, "b") => 0;
lfs_mkdir(&lfs, "c") => 0; lfs_mkdir(&lfs, "c") => 0;
@@ -525,28 +525,28 @@ code = '''
lfs_mkdir(&lfs, "a/hi/ohayo") => 0; lfs_mkdir(&lfs, "a/hi/ohayo") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_rename(&lfs, "a/hi", "c/hi") => 0; lfs_rename(&lfs, "a/hi", "c/hi") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// corrupt the source // corrupt the source
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "a") => 0; lfs_dir_open(&lfs, &dir, "a") => 0;
lfs_block_t block = dir.m.pair[0]; lfs_block_t block = dir.m.pair[0];
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
uint8_t bbuffer[LFS_BLOCK_SIZE]; uint8_t bbuffer[LFS_BLOCK_SIZE];
cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; lfs_testbd_read(&bd, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
int off = LFS_BLOCK_SIZE-1; int off = LFS_BLOCK_SIZE-1;
while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) {
off -= 1; off -= 1;
} }
memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3);
cfg.erase(&cfg, block) => 0; lfs_testbd_erase(&bd, block) => 0;
cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; lfs_testbd_prog(&bd, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
cfg.sync(&cfg) => 0; lfs_testbd_sync(&bd) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "a") => 0; lfs_dir_open(&lfs, &dir, "a") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
@@ -597,8 +597,8 @@ code = '''
in = "lfs.c" in = "lfs.c"
if = 'LFS_PROG_SIZE <= 0x3fe' # only works with one crc per commit if = 'LFS_PROG_SIZE <= 0x3fe' # only works with one crc per commit
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "a") => 0; lfs_mkdir(&lfs, "a") => 0;
lfs_mkdir(&lfs, "b") => 0; lfs_mkdir(&lfs, "b") => 0;
lfs_mkdir(&lfs, "c") => 0; lfs_mkdir(&lfs, "c") => 0;
@@ -609,44 +609,44 @@ code = '''
lfs_mkdir(&lfs, "a/hi/ohayo") => 0; lfs_mkdir(&lfs, "a/hi/ohayo") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_rename(&lfs, "a/hi", "c/hi") => 0; lfs_rename(&lfs, "a/hi", "c/hi") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// corrupt the source // corrupt the source
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "a") => 0; lfs_dir_open(&lfs, &dir, "a") => 0;
lfs_block_t block = dir.m.pair[0]; lfs_block_t block = dir.m.pair[0];
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
uint8_t bbuffer[LFS_BLOCK_SIZE]; uint8_t bbuffer[LFS_BLOCK_SIZE];
cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; lfs_testbd_read(&bd, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
int off = LFS_BLOCK_SIZE-1; int off = LFS_BLOCK_SIZE-1;
while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) {
off -= 1; off -= 1;
} }
memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3);
cfg.erase(&cfg, block) => 0; lfs_testbd_erase(&bd, block) => 0;
cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; lfs_testbd_prog(&bd, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
cfg.sync(&cfg) => 0; lfs_testbd_sync(&bd) => 0;
// corrupt the destination // corrupt the destination
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "c") => 0; lfs_dir_open(&lfs, &dir, "c") => 0;
block = dir.m.pair[0]; block = dir.m.pair[0];
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; lfs_testbd_read(&bd, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
off = LFS_BLOCK_SIZE-1; off = LFS_BLOCK_SIZE-1;
while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) {
off -= 1; off -= 1;
} }
memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3);
cfg.erase(&cfg, block) => 0; lfs_testbd_erase(&bd, block) => 0;
cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; lfs_testbd_prog(&bd, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
cfg.sync(&cfg) => 0; lfs_testbd_sync(&bd) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "a") => 0; lfs_dir_open(&lfs, &dir, "a") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
@@ -697,8 +697,8 @@ code = '''
in = "lfs.c" in = "lfs.c"
if = 'LFS_PROG_SIZE <= 0x3fe' # only works with one crc per commit if = 'LFS_PROG_SIZE <= 0x3fe' # only works with one crc per commit
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "a") => 0; lfs_mkdir(&lfs, "a") => 0;
lfs_mkdir(&lfs, "b") => 0; lfs_mkdir(&lfs, "b") => 0;
lfs_mkdir(&lfs, "c") => 0; lfs_mkdir(&lfs, "c") => 0;
@@ -709,49 +709,49 @@ code = '''
lfs_mkdir(&lfs, "a/hi/ohayo") => 0; lfs_mkdir(&lfs, "a/hi/ohayo") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_rename(&lfs, "a/hi", "c/hi") => 0; lfs_rename(&lfs, "a/hi", "c/hi") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// corrupt the source // corrupt the source
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "a") => 0; lfs_dir_open(&lfs, &dir, "a") => 0;
lfs_block_t block = dir.m.pair[0]; lfs_block_t block = dir.m.pair[0];
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
uint8_t bbuffer[LFS_BLOCK_SIZE]; uint8_t bbuffer[LFS_BLOCK_SIZE];
cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; lfs_testbd_read(&bd, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
int off = LFS_BLOCK_SIZE-1; int off = LFS_BLOCK_SIZE-1;
while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) {
off -= 1; off -= 1;
} }
memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3);
cfg.erase(&cfg, block) => 0; lfs_testbd_erase(&bd, block) => 0;
cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; lfs_testbd_prog(&bd, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
cfg.sync(&cfg) => 0; lfs_testbd_sync(&bd) => 0;
// corrupt the destination // corrupt the destination
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "c") => 0; lfs_dir_open(&lfs, &dir, "c") => 0;
block = dir.m.pair[0]; block = dir.m.pair[0];
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; lfs_testbd_read(&bd, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
off = LFS_BLOCK_SIZE-1; off = LFS_BLOCK_SIZE-1;
while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) {
off -= 1; off -= 1;
} }
memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3);
cfg.erase(&cfg, block) => 0; lfs_testbd_erase(&bd, block) => 0;
cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; lfs_testbd_prog(&bd, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
cfg.sync(&cfg) => 0; lfs_testbd_sync(&bd) => 0;
// continue move // continue move
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_rename(&lfs, "a/hi", "c/hi") => 0; lfs_rename(&lfs, "a/hi", "c/hi") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "a") => 0; lfs_dir_open(&lfs, &dir, "a") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
@@ -801,10 +801,10 @@ code = '''
[[case]] # simple reentrant move dir [[case]] # simple reentrant move dir
reentrant = true reentrant = true
code = ''' code = '''
err = lfs_mount(&lfs, &cfg); err = lfs_mountcfg(&lfs, &cfg);
if (err) { if (err) {
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
} }
err = lfs_mkdir(&lfs, "a"); err = lfs_mkdir(&lfs, "a");
assert(!err || err == LFS_ERR_EXIST); assert(!err || err == LFS_ERR_EXIST);
@@ -817,7 +817,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
while (true) { while (true) {
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
// there should never exist _2_ hi directories // there should never exist _2_ hi directories
int count = 0; int count = 0;
if (lfs_stat(&lfs, "a/hi", &info) == 0) { if (lfs_stat(&lfs, "a/hi", &info) == 0) {
@@ -843,7 +843,7 @@ code = '''
assert(count <= 1); assert(count <= 1);
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
if (lfs_stat(&lfs, "a/hi", &info) == 0) { if (lfs_stat(&lfs, "a/hi", &info) == 0) {
lfs_rename(&lfs, "a/hi", "b/hi") => 0; lfs_rename(&lfs, "a/hi", "b/hi") => 0;
} else if (lfs_stat(&lfs, "b/hi", &info) == 0) { } else if (lfs_stat(&lfs, "b/hi", &info) == 0) {
@@ -868,7 +868,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
} }
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "a") => 0; lfs_dir_open(&lfs, &dir, "a") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
@@ -917,8 +917,8 @@ code = '''
[[case]] # move state stealing [[case]] # move state stealing
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "a") => 0; lfs_mkdir(&lfs, "a") => 0;
lfs_mkdir(&lfs, "b") => 0; lfs_mkdir(&lfs, "b") => 0;
lfs_mkdir(&lfs, "c") => 0; lfs_mkdir(&lfs, "c") => 0;
@@ -930,17 +930,17 @@ code = '''
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_rename(&lfs, "a/hello", "b/hello") => 0; lfs_rename(&lfs, "a/hello", "b/hello") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_rename(&lfs, "b/hello", "c/hello") => 0; lfs_rename(&lfs, "b/hello", "c/hello") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_rename(&lfs, "c/hello", "d/hello") => 0; lfs_rename(&lfs, "c/hello", "d/hello") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "a/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; lfs_file_open(&lfs, &file, "a/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
lfs_file_open(&lfs, &file, "b/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; lfs_file_open(&lfs, &file, "b/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
lfs_file_open(&lfs, &file, "c/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; lfs_file_open(&lfs, &file, "c/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
@@ -954,12 +954,12 @@ code = '''
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_remove(&lfs, "b") => 0; lfs_remove(&lfs, "b") => 0;
lfs_remove(&lfs, "c") => 0; lfs_remove(&lfs, "c") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_stat(&lfs, "a", &info) => 0; lfs_stat(&lfs, "a", &info) => 0;
lfs_stat(&lfs, "b", &info) => LFS_ERR_NOENT; lfs_stat(&lfs, "b", &info) => LFS_ERR_NOENT;
lfs_stat(&lfs, "c", &info) => LFS_ERR_NOENT; lfs_stat(&lfs, "c", &info) => LFS_ERR_NOENT;
@@ -981,8 +981,8 @@ code = '''
# Other specific corner cases # Other specific corner cases
[[case]] # create + delete in same commit with neighbors [[case]] # create + delete in same commit with neighbors
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
// littlefs keeps files sorted, so we know the order these will be in // littlefs keeps files sorted, so we know the order these will be in
lfs_file_open(&lfs, &file, "/1.move_me", lfs_file_open(&lfs, &file, "/1.move_me",
@@ -1127,8 +1127,8 @@ code = '''
# Other specific corner cases # Other specific corner cases
[[case]] # create + delete + delete in same commit with neighbors [[case]] # create + delete + delete in same commit with neighbors
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
// littlefs keeps files sorted, so we know the order these will be in // littlefs keeps files sorted, so we know the order these will be in
lfs_file_open(&lfs, &file, "/1.move_me", lfs_file_open(&lfs, &file, "/1.move_me",
@@ -1283,8 +1283,8 @@ code = '''
[[case]] # create + delete in different dirs with neighbors [[case]] # create + delete in different dirs with neighbors
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
// littlefs keeps files sorted, so we know the order these will be in // littlefs keeps files sorted, so we know the order these will be in
lfs_mkdir(&lfs, "/dir.1") => 0; lfs_mkdir(&lfs, "/dir.1") => 0;
@@ -1523,8 +1523,8 @@ in = "lfs.c"
define.RELOCATIONS = 'range(0x3+1)' define.RELOCATIONS = 'range(0x3+1)'
define.LFS_ERASE_CYCLES = 0xffffffff define.LFS_ERASE_CYCLES = 0xffffffff
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "/parent") => 0; lfs_mkdir(&lfs, "/parent") => 0;
lfs_mkdir(&lfs, "/parent/child") => 0; lfs_mkdir(&lfs, "/parent/child") => 0;
@@ -1569,14 +1569,14 @@ code = '''
// force specific directories to relocate // force specific directories to relocate
if (RELOCATIONS & 0x1) { if (RELOCATIONS & 0x1) {
lfs_dir_open(&lfs, &dir, "/parent"); lfs_dir_open(&lfs, &dir, "/parent");
lfs_testbd_setwear(&cfg, dir.m.pair[0], 0xffffffff) => 0; lfs_testbd_setwear(&bd, dir.m.pair[0], 0xffffffff) => 0;
lfs_testbd_setwear(&cfg, dir.m.pair[1], 0xffffffff) => 0; lfs_testbd_setwear(&bd, dir.m.pair[1], 0xffffffff) => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
} }
if (RELOCATIONS & 0x2) { if (RELOCATIONS & 0x2) {
lfs_dir_open(&lfs, &dir, "/parent/child"); lfs_dir_open(&lfs, &dir, "/parent/child");
lfs_testbd_setwear(&cfg, dir.m.pair[0], 0xffffffff) => 0; lfs_testbd_setwear(&bd, dir.m.pair[0], 0xffffffff) => 0;
lfs_testbd_setwear(&cfg, dir.m.pair[1], 0xffffffff) => 0; lfs_testbd_setwear(&bd, dir.m.pair[1], 0xffffffff) => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
} }
@@ -1660,8 +1660,8 @@ in = "lfs.c"
define.RELOCATIONS = 'range(0x7+1)' define.RELOCATIONS = 'range(0x7+1)'
define.LFS_ERASE_CYCLES = 0xffffffff define.LFS_ERASE_CYCLES = 0xffffffff
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "/parent") => 0; lfs_mkdir(&lfs, "/parent") => 0;
lfs_mkdir(&lfs, "/parent/child") => 0; lfs_mkdir(&lfs, "/parent/child") => 0;
@@ -1707,20 +1707,20 @@ code = '''
// force specific directories to relocate // force specific directories to relocate
if (RELOCATIONS & 0x1) { if (RELOCATIONS & 0x1) {
lfs_dir_open(&lfs, &dir, "/parent"); lfs_dir_open(&lfs, &dir, "/parent");
lfs_testbd_setwear(&cfg, dir.m.pair[0], 0xffffffff) => 0; lfs_testbd_setwear(&bd, dir.m.pair[0], 0xffffffff) => 0;
lfs_testbd_setwear(&cfg, dir.m.pair[1], 0xffffffff) => 0; lfs_testbd_setwear(&bd, dir.m.pair[1], 0xffffffff) => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
} }
if (RELOCATIONS & 0x2) { if (RELOCATIONS & 0x2) {
lfs_dir_open(&lfs, &dir, "/parent/sibling"); lfs_dir_open(&lfs, &dir, "/parent/sibling");
lfs_testbd_setwear(&cfg, dir.m.pair[0], 0xffffffff) => 0; lfs_testbd_setwear(&bd, dir.m.pair[0], 0xffffffff) => 0;
lfs_testbd_setwear(&cfg, dir.m.pair[1], 0xffffffff) => 0; lfs_testbd_setwear(&bd, dir.m.pair[1], 0xffffffff) => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
} }
if (RELOCATIONS & 0x4) { if (RELOCATIONS & 0x4) {
lfs_dir_open(&lfs, &dir, "/parent/child"); lfs_dir_open(&lfs, &dir, "/parent/child");
lfs_testbd_setwear(&cfg, dir.m.pair[0], 0xffffffff) => 0; lfs_testbd_setwear(&bd, dir.m.pair[0], 0xffffffff) => 0;
lfs_testbd_setwear(&cfg, dir.m.pair[1], 0xffffffff) => 0; lfs_testbd_setwear(&bd, dir.m.pair[1], 0xffffffff) => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
} }

View File

@@ -2,8 +2,8 @@
in = "lfs.c" in = "lfs.c"
if = 'LFS_PROG_SIZE <= 0x3fe' # only works with one crc per commit if = 'LFS_PROG_SIZE <= 0x3fe' # only works with one crc per commit
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "parent") => 0; lfs_mkdir(&lfs, "parent") => 0;
lfs_mkdir(&lfs, "parent/orphan") => 0; lfs_mkdir(&lfs, "parent/orphan") => 0;
lfs_mkdir(&lfs, "parent/child") => 0; lfs_mkdir(&lfs, "parent/child") => 0;
@@ -13,29 +13,29 @@ code = '''
// corrupt the child's most recent commit, this should be the update // corrupt the child's most recent commit, this should be the update
// to the linked-list entry, which should orphan the orphan. Note this // to the linked-list entry, which should orphan the orphan. Note this
// makes a lot of assumptions about the remove operation. // makes a lot of assumptions about the remove operation.
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "parent/child") => 0; lfs_dir_open(&lfs, &dir, "parent/child") => 0;
lfs_block_t block = dir.m.pair[0]; lfs_block_t block = dir.m.pair[0];
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
uint8_t bbuffer[LFS_BLOCK_SIZE]; uint8_t bbuffer[LFS_BLOCK_SIZE];
cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; lfs_testbd_read(&bd, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
int off = LFS_BLOCK_SIZE-1; int off = LFS_BLOCK_SIZE-1;
while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) {
off -= 1; off -= 1;
} }
memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3);
cfg.erase(&cfg, block) => 0; lfs_testbd_erase(&bd, block) => 0;
cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; lfs_testbd_prog(&bd, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
cfg.sync(&cfg) => 0; lfs_testbd_sync(&bd) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT; lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT;
lfs_stat(&lfs, "parent/child", &info) => 0; lfs_stat(&lfs, "parent/child", &info) => 0;
lfs_fs_size(&lfs) => 8; lfs_fs_size(&lfs) => 8;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT; lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT;
lfs_stat(&lfs, "parent/child", &info) => 0; lfs_stat(&lfs, "parent/child", &info) => 0;
lfs_fs_size(&lfs) => 8; lfs_fs_size(&lfs) => 8;
@@ -48,7 +48,7 @@ code = '''
lfs_fs_size(&lfs) => 8; lfs_fs_size(&lfs) => 8;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT; lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT;
lfs_stat(&lfs, "parent/child", &info) => 0; lfs_stat(&lfs, "parent/child", &info) => 0;
lfs_stat(&lfs, "parent/otherchild", &info) => 0; lfs_stat(&lfs, "parent/otherchild", &info) => 0;
@@ -59,17 +59,17 @@ code = '''
[[case]] # reentrant testing for orphans, basically just spam mkdir/remove [[case]] # reentrant testing for orphans, basically just spam mkdir/remove
reentrant = true reentrant = true
# TODO fix this case, caused by non-DAG trees # TODO fix this case, caused by non-DAG trees
if = '!(DEPTH == 3 && LFS_CACHE_SIZE != 64)' if = '!(DEPTH == 3 && LFS_BUFFER_SIZE != 64)'
define = [ define = [
{FILES=6, DEPTH=1, CYCLES=20}, {FILES=6, DEPTH=1, CYCLES=20},
{FILES=26, DEPTH=1, CYCLES=20}, {FILES=26, DEPTH=1, CYCLES=20},
{FILES=3, DEPTH=3, CYCLES=20}, {FILES=3, DEPTH=3, CYCLES=20},
] ]
code = ''' code = '''
err = lfs_mount(&lfs, &cfg); err = lfs_mountcfg(&lfs, &cfg);
if (err) { if (err) {
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
} }
srand(1); srand(1);

View File

@@ -1,8 +1,8 @@
[[case]] # simple path test [[case]] # simple path test
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "tea") => 0; lfs_mkdir(&lfs, "tea") => 0;
lfs_mkdir(&lfs, "tea/hottea") => 0; lfs_mkdir(&lfs, "tea/hottea") => 0;
lfs_mkdir(&lfs, "tea/warmtea") => 0; lfs_mkdir(&lfs, "tea/warmtea") => 0;
@@ -23,8 +23,8 @@ code = '''
[[case]] # redundant slashes [[case]] # redundant slashes
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "tea") => 0; lfs_mkdir(&lfs, "tea") => 0;
lfs_mkdir(&lfs, "tea/hottea") => 0; lfs_mkdir(&lfs, "tea/hottea") => 0;
lfs_mkdir(&lfs, "tea/warmtea") => 0; lfs_mkdir(&lfs, "tea/warmtea") => 0;
@@ -47,8 +47,8 @@ code = '''
[[case]] # dot path test [[case]] # dot path test
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "tea") => 0; lfs_mkdir(&lfs, "tea") => 0;
lfs_mkdir(&lfs, "tea/hottea") => 0; lfs_mkdir(&lfs, "tea/hottea") => 0;
lfs_mkdir(&lfs, "tea/warmtea") => 0; lfs_mkdir(&lfs, "tea/warmtea") => 0;
@@ -73,8 +73,8 @@ code = '''
[[case]] # dot dot path test [[case]] # dot dot path test
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "tea") => 0; lfs_mkdir(&lfs, "tea") => 0;
lfs_mkdir(&lfs, "tea/hottea") => 0; lfs_mkdir(&lfs, "tea/hottea") => 0;
lfs_mkdir(&lfs, "tea/warmtea") => 0; lfs_mkdir(&lfs, "tea/warmtea") => 0;
@@ -103,8 +103,8 @@ code = '''
[[case]] # trailing dot path test [[case]] # trailing dot path test
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "tea") => 0; lfs_mkdir(&lfs, "tea") => 0;
lfs_mkdir(&lfs, "tea/hottea") => 0; lfs_mkdir(&lfs, "tea/hottea") => 0;
lfs_mkdir(&lfs, "tea/warmtea") => 0; lfs_mkdir(&lfs, "tea/warmtea") => 0;
@@ -125,8 +125,8 @@ code = '''
[[case]] # leading dot path test [[case]] # leading dot path test
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, ".milk") => 0; lfs_mkdir(&lfs, ".milk") => 0;
lfs_stat(&lfs, ".milk", &info) => 0; lfs_stat(&lfs, ".milk", &info) => 0;
strcmp(info.name, ".milk") => 0; strcmp(info.name, ".milk") => 0;
@@ -137,8 +137,8 @@ code = '''
[[case]] # root dot dot path test [[case]] # root dot dot path test
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "tea") => 0; lfs_mkdir(&lfs, "tea") => 0;
lfs_mkdir(&lfs, "tea/hottea") => 0; lfs_mkdir(&lfs, "tea/hottea") => 0;
lfs_mkdir(&lfs, "tea/warmtea") => 0; lfs_mkdir(&lfs, "tea/warmtea") => 0;
@@ -161,8 +161,8 @@ code = '''
[[case]] # invalid path tests [[case]] # invalid path tests
code = ''' code = '''
lfs_format(&lfs, &cfg); lfs_formatcfg(&lfs, &cfg);
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_stat(&lfs, "dirt", &info) => LFS_ERR_NOENT; lfs_stat(&lfs, "dirt", &info) => LFS_ERR_NOENT;
lfs_stat(&lfs, "dirt/ground", &info) => LFS_ERR_NOENT; lfs_stat(&lfs, "dirt/ground", &info) => LFS_ERR_NOENT;
lfs_stat(&lfs, "dirt/ground/earth", &info) => LFS_ERR_NOENT; lfs_stat(&lfs, "dirt/ground/earth", &info) => LFS_ERR_NOENT;
@@ -182,8 +182,8 @@ code = '''
[[case]] # root operations [[case]] # root operations
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_stat(&lfs, "/", &info) => 0; lfs_stat(&lfs, "/", &info) => 0;
assert(strcmp(info.name, "/") == 0); assert(strcmp(info.name, "/") == 0);
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
@@ -198,8 +198,8 @@ code = '''
[[case]] # root representations [[case]] # root representations
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_stat(&lfs, "/", &info) => 0; lfs_stat(&lfs, "/", &info) => 0;
assert(strcmp(info.name, "/") == 0); assert(strcmp(info.name, "/") == 0);
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
@@ -223,8 +223,8 @@ code = '''
[[case]] # superblock conflict test [[case]] # superblock conflict test
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_stat(&lfs, "littlefs", &info) => LFS_ERR_NOENT; lfs_stat(&lfs, "littlefs", &info) => LFS_ERR_NOENT;
lfs_remove(&lfs, "littlefs") => LFS_ERR_NOENT; lfs_remove(&lfs, "littlefs") => LFS_ERR_NOENT;
@@ -239,8 +239,8 @@ code = '''
[[case]] # max path test [[case]] # max path test
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "coffee") => 0; lfs_mkdir(&lfs, "coffee") => 0;
lfs_mkdir(&lfs, "coffee/hotcoffee") => 0; lfs_mkdir(&lfs, "coffee/hotcoffee") => 0;
lfs_mkdir(&lfs, "coffee/warmcoffee") => 0; lfs_mkdir(&lfs, "coffee/warmcoffee") => 0;
@@ -263,8 +263,8 @@ code = '''
[[case]] # really big path test [[case]] # really big path test
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "coffee") => 0; lfs_mkdir(&lfs, "coffee") => 0;
lfs_mkdir(&lfs, "coffee/hotcoffee") => 0; lfs_mkdir(&lfs, "coffee/hotcoffee") => 0;
lfs_mkdir(&lfs, "coffee/warmcoffee") => 0; lfs_mkdir(&lfs, "coffee/warmcoffee") => 0;

View File

@@ -4,9 +4,9 @@ define.ITERATIONS = 20
define.COUNT = 10 define.COUNT = 10
define.LFS_BLOCK_CYCLES = [8, 1] define.LFS_BLOCK_CYCLES = [8, 1]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
// fill up filesystem so only ~16 blocks are left // fill up filesystem so only ~16 blocks are left
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "padding", LFS_O_CREAT | LFS_O_WRONLY) => 0; lfs_file_open(&lfs, &file, "padding", LFS_O_CREAT | LFS_O_WRONLY) => 0;
memset(buffer, 0, 512); memset(buffer, 0, 512);
while (LFS_BLOCK_COUNT - lfs_fs_size(&lfs) > 16) { while (LFS_BLOCK_COUNT - lfs_fs_size(&lfs) > 16) {
@@ -17,7 +17,7 @@ code = '''
lfs_mkdir(&lfs, "child") => 0; lfs_mkdir(&lfs, "child") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
for (int j = 0; j < ITERATIONS; j++) { for (int j = 0; j < ITERATIONS; j++) {
for (int i = 0; i < COUNT; i++) { for (int i = 0; i < COUNT; i++) {
sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); sprintf(path, "child/test%03d_loooooooooooooooooong_name", i);
@@ -47,7 +47,7 @@ code = '''
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "child") => 0; lfs_dir_open(&lfs, &dir, "child") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
@@ -70,9 +70,9 @@ define.ITERATIONS = 20
define.COUNT = 10 define.COUNT = 10
define.LFS_BLOCK_CYCLES = [8, 1] define.LFS_BLOCK_CYCLES = [8, 1]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
// fill up filesystem so only ~16 blocks are left // fill up filesystem so only ~16 blocks are left
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "padding", LFS_O_CREAT | LFS_O_WRONLY) => 0; lfs_file_open(&lfs, &file, "padding", LFS_O_CREAT | LFS_O_WRONLY) => 0;
memset(buffer, 0, 512); memset(buffer, 0, 512);
while (LFS_BLOCK_COUNT - lfs_fs_size(&lfs) > 16) { while (LFS_BLOCK_COUNT - lfs_fs_size(&lfs) > 16) {
@@ -83,7 +83,7 @@ code = '''
lfs_mkdir(&lfs, "child") => 0; lfs_mkdir(&lfs, "child") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
for (int j = 0; j < ITERATIONS; j++) { for (int j = 0; j < ITERATIONS; j++) {
for (int i = 0; i < COUNT; i++) { for (int i = 0; i < COUNT; i++) {
sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); sprintf(path, "child/test%03d_loooooooooooooooooong_name", i);
@@ -148,17 +148,17 @@ code = '''
# almost every tree operation needs a relocation # almost every tree operation needs a relocation
reentrant = true reentrant = true
# TODO fix this case, caused by non-DAG trees # TODO fix this case, caused by non-DAG trees
if = '!(DEPTH == 3 && LFS_CACHE_SIZE != 64)' if = '!(DEPTH == 3 && LFS_BUFFER_SIZE != 64)'
define = [ define = [
{FILES=6, DEPTH=1, CYCLES=20, LFS_BLOCK_CYCLES=1}, {FILES=6, DEPTH=1, CYCLES=20, LFS_BLOCK_CYCLES=1},
{FILES=26, DEPTH=1, CYCLES=20, LFS_BLOCK_CYCLES=1}, {FILES=26, DEPTH=1, CYCLES=20, LFS_BLOCK_CYCLES=1},
{FILES=3, DEPTH=3, CYCLES=20, LFS_BLOCK_CYCLES=1}, {FILES=3, DEPTH=3, CYCLES=20, LFS_BLOCK_CYCLES=1},
] ]
code = ''' code = '''
err = lfs_mount(&lfs, &cfg); err = lfs_mountcfg(&lfs, &cfg);
if (err) { if (err) {
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
} }
srand(1); srand(1);
@@ -210,17 +210,17 @@ code = '''
[[case]] # reentrant testing for relocations, but now with random renames! [[case]] # reentrant testing for relocations, but now with random renames!
reentrant = true reentrant = true
# TODO fix this case, caused by non-DAG trees # TODO fix this case, caused by non-DAG trees
if = '!(DEPTH == 3 && LFS_CACHE_SIZE != 64)' if = '!(DEPTH == 3 && LFS_BUFFER_SIZE != 64)'
define = [ define = [
{FILES=6, DEPTH=1, CYCLES=20, LFS_BLOCK_CYCLES=1}, {FILES=6, DEPTH=1, CYCLES=20, LFS_BLOCK_CYCLES=1},
{FILES=26, DEPTH=1, CYCLES=20, LFS_BLOCK_CYCLES=1}, {FILES=26, DEPTH=1, CYCLES=20, LFS_BLOCK_CYCLES=1},
{FILES=3, DEPTH=3, CYCLES=20, LFS_BLOCK_CYCLES=1}, {FILES=3, DEPTH=3, CYCLES=20, LFS_BLOCK_CYCLES=1},
] ]
code = ''' code = '''
err = lfs_mount(&lfs, &cfg); err = lfs_mountcfg(&lfs, &cfg);
if (err) { if (err) {
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
} }
srand(1); srand(1);

View File

@@ -9,8 +9,8 @@ define = [
{COUNT=4, SKIP=2}, {COUNT=4, SKIP=2},
] ]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "kitty", lfs_file_open(&lfs, &file, "kitty",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
size = strlen("kittycatcat"); size = strlen("kittycatcat");
@@ -21,7 +21,7 @@ code = '''
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "kitty", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, "kitty", LFS_O_RDONLY) => 0;
lfs_soff_t pos = -1; lfs_soff_t pos = -1;
@@ -78,8 +78,8 @@ define = [
{COUNT=4, SKIP=2}, {COUNT=4, SKIP=2},
] ]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "kitty", lfs_file_open(&lfs, &file, "kitty",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
size = strlen("kittycatcat"); size = strlen("kittycatcat");
@@ -90,7 +90,7 @@ code = '''
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0; lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0;
lfs_soff_t pos = -1; lfs_soff_t pos = -1;
@@ -133,8 +133,8 @@ code = '''
define.COUNT = 132 define.COUNT = 132
define.OFFSETS = '"{512, 1020, 513, 1021, 511, 1019, 1441}"' define.OFFSETS = '"{512, 1020, 513, 1021, 511, 1019, 1441}"'
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "kitty", lfs_file_open(&lfs, &file, "kitty",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
size = strlen("kittycatcat"); size = strlen("kittycatcat");
@@ -145,7 +145,7 @@ code = '''
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0; lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0;
size = strlen("hedgehoghog"); size = strlen("hedgehoghog");
@@ -193,8 +193,8 @@ define = [
{COUNT=4, SKIP=3}, {COUNT=4, SKIP=3},
] ]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "kitty", lfs_file_open(&lfs, &file, "kitty",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
size = strlen("kittycatcat"); size = strlen("kittycatcat");
@@ -204,7 +204,7 @@ code = '''
} }
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0; lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0;
size = strlen("kittycatcat"); size = strlen("kittycatcat");
@@ -241,8 +241,8 @@ code = '''
[[case]] # inline write and seek [[case]] # inline write and seek
define.SIZE = [2, 4, 128, 132] define.SIZE = [2, 4, 128, 132]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "tinykitty", lfs_file_open(&lfs, &file, "tinykitty",
LFS_O_RDWR | LFS_O_CREAT) => 0; LFS_O_RDWR | LFS_O_CREAT) => 0;
int j = 0; int j = 0;
@@ -310,10 +310,10 @@ code = '''
define.COUNT = [4, 64, 128] define.COUNT = [4, 64, 128]
reentrant = true reentrant = true
code = ''' code = '''
err = lfs_mount(&lfs, &cfg); err = lfs_mountcfg(&lfs, &cfg);
if (err) { if (err) {
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
} }
err = lfs_file_open(&lfs, &file, "kitty", LFS_O_RDONLY); err = lfs_file_open(&lfs, &file, "kitty", LFS_O_RDONLY);
assert(!err || err == LFS_ERR_NOENT); assert(!err || err == LFS_ERR_NOENT);

View File

@@ -1,37 +1,37 @@
[[case]] # simple formatting test [[case]] # simple formatting test
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
''' '''
[[case]] # mount/unmount [[case]] # mount/unmount
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # reentrant format [[case]] # reentrant format
reentrant = true reentrant = true
code = ''' code = '''
err = lfs_mount(&lfs, &cfg); err = lfs_mountcfg(&lfs, &cfg);
if (err) { if (err) {
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # invalid mount [[case]] # invalid mount
code = ''' code = '''
lfs_mount(&lfs, &cfg) => LFS_ERR_CORRUPT; lfs_mountcfg(&lfs, &cfg) => LFS_ERR_CORRUPT;
''' '''
[[case]] # expanding superblock [[case]] # expanding superblock
define.LFS_BLOCK_CYCLES = [32, 33, 1] define.LFS_BLOCK_CYCLES = [32, 33, 1]
define.N = [10, 100, 1000] define.N = [10, 100, 1000]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
lfs_file_open(&lfs, &file, "dummy", lfs_file_open(&lfs, &file, "dummy",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
@@ -44,7 +44,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// one last check after power-cycle // one last check after power-cycle
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "dummy", lfs_file_open(&lfs, &file, "dummy",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
@@ -58,9 +58,9 @@ code = '''
define.LFS_BLOCK_CYCLES = [32, 33, 1] define.LFS_BLOCK_CYCLES = [32, 33, 1]
define.N = [10, 100, 1000] define.N = [10, 100, 1000]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
// remove lingering dummy? // remove lingering dummy?
err = lfs_stat(&lfs, "dummy", &info); err = lfs_stat(&lfs, "dummy", &info);
assert(err == 0 || (err == LFS_ERR_NOENT && i == 0)); assert(err == 0 || (err == LFS_ERR_NOENT && i == 0));
@@ -80,7 +80,7 @@ code = '''
} }
// one last check after power-cycle // one last check after power-cycle
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_stat(&lfs, "dummy", &info) => 0; lfs_stat(&lfs, "dummy", &info) => 0;
assert(strcmp(info.name, "dummy") == 0); assert(strcmp(info.name, "dummy") == 0);
assert(info.type == LFS_TYPE_REG); assert(info.type == LFS_TYPE_REG);
@@ -92,10 +92,10 @@ define.LFS_BLOCK_CYCLES = [2, 1]
define.N = 24 define.N = 24
reentrant = true reentrant = true
code = ''' code = '''
err = lfs_mount(&lfs, &cfg); err = lfs_mountcfg(&lfs, &cfg);
if (err) { if (err) {
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
} }
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
@@ -119,7 +119,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// one last check after power-cycle // one last check after power-cycle
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_stat(&lfs, "dummy", &info) => 0; lfs_stat(&lfs, "dummy", &info) => 0;
assert(strcmp(info.name, "dummy") == 0); assert(strcmp(info.name, "dummy") == 0);
assert(info.type == LFS_TYPE_REG); assert(info.type == LFS_TYPE_REG);

View File

@@ -2,8 +2,8 @@
define.MEDIUMSIZE = [32, 2048] define.MEDIUMSIZE = [32, 2048]
define.LARGESIZE = 8192 define.LARGESIZE = 8192
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "baldynoop", lfs_file_open(&lfs, &file, "baldynoop",
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS_O_WRONLY | LFS_O_CREAT) => 0;
@@ -17,7 +17,7 @@ code = '''
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "baldynoop", LFS_O_RDWR) => 0; lfs_file_open(&lfs, &file, "baldynoop", LFS_O_RDWR) => 0;
lfs_file_size(&lfs, &file) => LARGESIZE; lfs_file_size(&lfs, &file) => LARGESIZE;
@@ -27,7 +27,7 @@ code = '''
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "baldynoop", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, "baldynoop", LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => MEDIUMSIZE; lfs_file_size(&lfs, &file) => MEDIUMSIZE;
@@ -46,8 +46,8 @@ code = '''
define.MEDIUMSIZE = [32, 2048] define.MEDIUMSIZE = [32, 2048]
define.LARGESIZE = 8192 define.LARGESIZE = 8192
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "baldyread", lfs_file_open(&lfs, &file, "baldyread",
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS_O_WRONLY | LFS_O_CREAT) => 0;
@@ -61,7 +61,7 @@ code = '''
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "baldyread", LFS_O_RDWR) => 0; lfs_file_open(&lfs, &file, "baldyread", LFS_O_RDWR) => 0;
lfs_file_size(&lfs, &file) => LARGESIZE; lfs_file_size(&lfs, &file) => LARGESIZE;
@@ -78,7 +78,7 @@ code = '''
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "baldyread", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, "baldyread", LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => MEDIUMSIZE; lfs_file_size(&lfs, &file) => MEDIUMSIZE;
@@ -95,12 +95,12 @@ code = '''
[[case]] # write, truncate, and read [[case]] # write, truncate, and read
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "sequence", lfs_file_open(&lfs, &file, "sequence",
LFS_O_RDWR | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS_O_RDWR | LFS_O_CREAT | LFS_O_TRUNC) => 0;
size = lfs_min(lfs.cfg->cache_size, sizeof(buffer)/2); size = lfs_min(LFS_BUFFER_SIZE, sizeof(buffer)/2);
lfs_size_t qsize = size / 4; lfs_size_t qsize = size / 4;
uint8_t *wb = buffer; uint8_t *wb = buffer;
uint8_t *rb = buffer + size; uint8_t *rb = buffer + size;
@@ -149,8 +149,8 @@ code = '''
define.MEDIUMSIZE = [32, 2048] define.MEDIUMSIZE = [32, 2048]
define.LARGESIZE = 8192 define.LARGESIZE = 8192
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "baldywrite", lfs_file_open(&lfs, &file, "baldywrite",
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS_O_WRONLY | LFS_O_CREAT) => 0;
@@ -164,7 +164,7 @@ code = '''
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "baldywrite", LFS_O_RDWR) => 0; lfs_file_open(&lfs, &file, "baldywrite", LFS_O_RDWR) => 0;
lfs_file_size(&lfs, &file) => LARGESIZE; lfs_file_size(&lfs, &file) => LARGESIZE;
@@ -181,7 +181,7 @@ code = '''
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "baldywrite", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, "baldywrite", LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => MEDIUMSIZE; lfs_file_size(&lfs, &file) => MEDIUMSIZE;
@@ -202,10 +202,10 @@ define.MEDIUMSIZE = [32, 1024]
define.LARGESIZE = 2048 define.LARGESIZE = 2048
reentrant = true reentrant = true
code = ''' code = '''
err = lfs_mount(&lfs, &cfg); err = lfs_mountcfg(&lfs, &cfg);
if (err) { if (err) {
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
} }
err = lfs_file_open(&lfs, &file, "baldy", LFS_O_RDONLY); err = lfs_file_open(&lfs, &file, "baldy", LFS_O_RDONLY);
assert(!err || err == LFS_ERR_NOENT); assert(!err || err == LFS_ERR_NOENT);
@@ -312,8 +312,8 @@ code = '''
const lfs_off_t *hotsizes = configs[CONFIG].hotsizes; const lfs_off_t *hotsizes = configs[CONFIG].hotsizes;
const lfs_off_t *coldsizes = configs[CONFIG].coldsizes; const lfs_off_t *coldsizes = configs[CONFIG].coldsizes;
lfs_format(&lfs, &cfg) => 0; lfs_formatcfg(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
for (unsigned i = 0; i < COUNT; i++) { for (unsigned i = 0; i < COUNT; i++) {
sprintf(path, "hairyhead%d", i); sprintf(path, "hairyhead%d", i);
@@ -340,7 +340,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
for (unsigned i = 0; i < COUNT; i++) { for (unsigned i = 0; i < COUNT; i++) {
sprintf(path, "hairyhead%d", i); sprintf(path, "hairyhead%d", i);
@@ -367,7 +367,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mountcfg(&lfs, &cfg) => 0;
for (unsigned i = 0; i < COUNT; i++) { for (unsigned i = 0; i < COUNT; i++) {
sprintf(path, "hairyhead%d", i); sprintf(path, "hairyhead%d", i);
@@ -392,48 +392,3 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # noop truncate
define.MEDIUMSIZE = [32, 2048]
code = '''
lfs_format(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "baldynoop",
LFS_O_RDWR | LFS_O_CREAT) => 0;
strcpy((char*)buffer, "hair");
size = strlen((char*)buffer);
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) {
lfs_file_write(&lfs, &file, buffer, size) => size;
// this truncate should do nothing
lfs_file_truncate(&lfs, &file, j+size) => 0;
}
lfs_file_size(&lfs, &file) => MEDIUMSIZE;
lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0;
// should do nothing again
lfs_file_truncate(&lfs, &file, MEDIUMSIZE) => 0;
lfs_file_size(&lfs, &file) => MEDIUMSIZE;
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) {
lfs_file_read(&lfs, &file, buffer, size) => size;
memcmp(buffer, "hair", size) => 0;
}
lfs_file_read(&lfs, &file, buffer, size) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
// still there after reboot?
lfs_mount(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "baldynoop", LFS_O_RDWR) => 0;
lfs_file_size(&lfs, &file) => MEDIUMSIZE;
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) {
lfs_file_read(&lfs, &file, buffer, size) => size;
memcmp(buffer, "hair", size) => 0;
}
lfs_file_read(&lfs, &file, buffer, size) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
'''