Compare commits

..

17 Commits

Author SHA1 Message Date
geky-bot
7127786d39 Generated v2 prefixes 2022-03-22 06:01:37 +00:00
geky-bot
4dcad66e16 Generated v2 prefixes 2021-06-12 21:48:51 +00:00
geky-bot
b816d7f898 Generated v2 prefixes 2021-01-20 02:41:58 +00:00
geky bot
c40271bcf3 Generated v2 prefixes 2020-12-08 09:20:13 +00:00
geky bot
197ad15e47 Generated v2 prefixes 2020-04-09 12:00:34 +00:00
geky bot
3e7b9da578 Generated v2 prefixes 2020-04-01 03:33:16 +00:00
geky bot
1f204e6d84 Generated v2 prefixes 2019-12-02 01:09:00 +00:00
geky bot
893325aeb9 Generated v2 prefixes 2019-10-15 16:52:45 +00:00
geky bot
c39b1de658 Generated v2 prefixes 2019-09-19 16:38:42 +00:00
geky bot
f3608e84c7 Generated v2 prefixes 2019-08-09 01:20:09 +00:00
geky bot
c08e977799 Generated v2 prefixes 2019-07-29 07:12:22 +00:00
geky bot
bc7be77625 Generated v2 prefixes 2019-07-02 01:28:14 +00:00
geky bot
96c8b6dcb3 Generated v2 prefixes 2019-05-23 22:27:35 +00:00
geky bot
895767cc9d Generated v2 prefixes 2019-04-17 00:01:02 +00:00
geky bot
87d3abba61 Generated v2 prefixes 2019-04-16 03:28:41 +00:00
geky bot
19f4eae52c Generated v2 prefixes 2019-04-12 22:49:07 +00:00
geky bot
8d4fd46a4c Generated v2 prefixes 2019-04-11 02:08:05 +00:00
48 changed files with 10790 additions and 12732 deletions

View File

@@ -6,7 +6,7 @@ on:
jobs: jobs:
post-release: post-release:
runs-on: ubuntu-20.04 runs-on: ubuntu-18.04
steps: steps:
# trigger post-release in dependency repo, this indirection allows the # trigger post-release in dependency repo, this indirection allows the
# dependency repo to be updated often without affecting this repo. At # dependency repo to be updated often without affecting this repo. At

View File

@@ -7,7 +7,7 @@ on:
jobs: jobs:
release: release:
runs-on: ubuntu-20.04 runs-on: ubuntu-18.04
# need to manually check for a couple things # need to manually check for a couple things
# - tests passed? # - tests passed?
@@ -36,116 +36,135 @@ jobs:
- name: find-version - name: find-version
run: | run: |
# rip version from lfs.h # rip version from lfs2.h
LFS_VERSION="$(grep -o '^#define LFS_VERSION .*$' lfs.h \ LFS2_VERSION="$(grep -o '^#define LFS2_VERSION .*$' lfs2.h \
| awk '{print $3}')" | awk '{print $3}')"
LFS_VERSION_MAJOR="$((0xffff & ($LFS_VERSION >> 16)))" LFS2_VERSION_MAJOR="$((0xffff & ($LFS2_VERSION >> 16)))"
LFS_VERSION_MINOR="$((0xffff & ($LFS_VERSION >> 0)))" LFS2_VERSION_MINOR="$((0xffff & ($LFS2_VERSION >> 0)))"
# find a new patch version based on what we find in our tags # find a new patch version based on what we find in our tags
LFS_VERSION_PATCH="$( \ LFS2_VERSION_PATCH="$( \
( git describe --tags --abbrev=0 \ ( git describe --tags --abbrev=0 \
--match="v$LFS_VERSION_MAJOR.$LFS_VERSION_MINOR.*" \ --match="v$LFS2_VERSION_MAJOR.$LFS2_VERSION_MINOR.*" \
|| echo 'v0.0.-1' ) \ || echo 'v0.0.-1' ) \
| awk -F '.' '{print $3+1}')" | awk -F '.' '{print $3+1}')"
# found new version # found new version
LFS_VERSION="v$LFS_VERSION_MAJOR` LFS2_VERSION="v$LFS2_VERSION_MAJOR`
`.$LFS_VERSION_MINOR` `.$LFS2_VERSION_MINOR`
`.$LFS_VERSION_PATCH" `.$LFS2_VERSION_PATCH"
echo "LFS_VERSION=$LFS_VERSION" echo "LFS2_VERSION=$LFS2_VERSION"
echo "LFS_VERSION=$LFS_VERSION" >> $GITHUB_ENV echo "LFS2_VERSION=$LFS2_VERSION" >> $GITHUB_ENV
echo "LFS_VERSION_MAJOR=$LFS_VERSION_MAJOR" >> $GITHUB_ENV echo "LFS2_VERSION_MAJOR=$LFS2_VERSION_MAJOR" >> $GITHUB_ENV
echo "LFS_VERSION_MINOR=$LFS_VERSION_MINOR" >> $GITHUB_ENV echo "LFS2_VERSION_MINOR=$LFS2_VERSION_MINOR" >> $GITHUB_ENV
echo "LFS_VERSION_PATCH=$LFS_VERSION_PATCH" >> $GITHUB_ENV echo "LFS2_VERSION_PATCH=$LFS2_VERSION_PATCH" >> $GITHUB_ENV
# try to find previous version? # try to find previous version?
- name: find-prev-version - name: find-prev-version
continue-on-error: true continue-on-error: true
run: | run: |
LFS_PREV_VERSION="$(git describe --tags --abbrev=0 --match 'v*')" LFS2_PREV_VERSION="$(git describe --tags --abbrev=0 --match 'v*')"
echo "LFS_PREV_VERSION=$LFS_PREV_VERSION" echo "LFS2_PREV_VERSION=$LFS2_PREV_VERSION"
echo "LFS_PREV_VERSION=$LFS_PREV_VERSION" >> $GITHUB_ENV echo "LFS2_PREV_VERSION=$LFS2_PREV_VERSION" >> $GITHUB_ENV
# try to find results from tests # try to find results from tests
- name: collect-results - name: collect-results
run: | run: |
# previous results to compare against? # previous results to compare against?
[ -n "$LFS_PREV_VERSION" ] && curl -sS \ [ -n "$LFS2_PREV_VERSION" ] && curl -sS \
"$GITHUB_API_URL/repos/$GITHUB_REPOSITORY/` "$GITHUB_API_URL/repos/$GITHUB_REPOSITORY/`
`status/$LFS_PREV_VERSION?per_page=100" \ `status/$LFS2_PREV_VERSION" \
| jq -re 'select(.sha != env.GITHUB_SHA) | .statuses[]' \ | jq -re 'select(.sha != env.GITHUB_SHA) | .statuses[]' \
>> prev-results.json \ >> prev-results.json \
|| true || true
# build table for GitHub # unfortunately these each have their own format
echo "<table>" >> results.txt [ -e results/code-thumb.csv ] && ( \
echo "<thead>" >> results.txt export PREV="$(jq -re '
echo "<tr>" >> results.txt select(.context == "results / code").description
echo "<th align=left>Configuration</th>" >> results.txt | capture("Code size is (?<result>[0-9]+)").result' \
for r in Code Stack Structs Coverage prev-results.json || echo 0)"
do ./scripts/code.py -u results/code-thumb.csv -s | awk '
echo "<th align=right>$r</th>" >> results.txt NR==2 {printf "Code size,%d B",$2}
done NR==2 && ENVIRON["PREV"]+0 != 0 {
echo "</tr>" >> results.txt printf " (%+.1f%%)",100*($2-ENVIRON["PREV"])/ENVIRON["PREV"]}
echo "</thead>" >> results.txt NR==2 {printf "\n"}' \
>> results.csv)
echo "<tbody>" >> results.txt [ -e results/code-thumb-readonly.csv ] && ( \
for c in "" readonly threadsafe migrate error-asserts export PREV="$(jq -re '
do select(.context == "results / code (readonly)").description
echo "<tr>" >> results.txt | capture("Code size is (?<result>[0-9]+)").result' \
c_or_default=${c:-default} prev-results.json || echo 0)"
echo "<td align=left>${c_or_default^}</td>" >> results.txt ./scripts/code.py -u results/code-thumb-readonly.csv -s | awk '
for r in code stack structs NR==2 {printf "Code size<br/>(readonly),%d B",$2}
do NR==2 && ENVIRON["PREV"]+0 != 0 {
# per-config results printf " (%+.1f%%)",100*($2-ENVIRON["PREV"])/ENVIRON["PREV"]}
echo "<td align=right>" >> results.txt NR==2 {printf "\n"}' \
[ -e results/thumb${c:+-$c}.csv ] && ( \ >> results.csv)
export PREV="$(jq -re ' [ -e results/code-thumb-threadsafe.csv ] && ( \
select(.context == "'"results (thumb${c:+, $c}) / $r"'").description export PREV="$(jq -re '
| capture("(?<result>[0-9∞]+)").result' \ select(.context == "results / code (threadsafe)").description
prev-results.json || echo 0)" | capture("Code size is (?<result>[0-9]+)").result' \
./scripts/summary.py results/thumb${c:+-$c}.csv -f $r -Y | awk ' prev-results.json || echo 0)"
NR==2 {printf "%s B",$2} ./scripts/code.py -u results/code-thumb-threadsafe.csv -s | awk '
NR==2 && ENVIRON["PREV"]+0 != 0 { NR==2 {printf "Code size<br/>(threadsafe),%d B",$2}
printf " (%+.1f%%)",100*($2-ENVIRON["PREV"])/ENVIRON["PREV"]} NR==2 && ENVIRON["PREV"]+0 != 0 {
NR==2 {printf "\n"}' \ printf " (%+.1f%%)",100*($2-ENVIRON["PREV"])/ENVIRON["PREV"]}
| sed -e 's/ /\&nbsp;/g' \ NR==2 {printf "\n"}' \
>> results.txt) >> results.csv)
echo "</td>" >> results.txt [ -e results/code-thumb-migrate.csv ] && ( \
done export PREV="$(jq -re '
# coverage results select(.context == "results / code (migrate)").description
if [ -z $c ] | capture("Code size is (?<result>[0-9]+)").result' \
then prev-results.json || echo 0)"
echo "<td rowspan=0 align=right>" >> results.txt ./scripts/code.py -u results/code-thumb-migrate.csv -s | awk '
[ -e results/coverage.csv ] && ( \ NR==2 {printf "Code size<br/>(migrate),%d B",$2}
export PREV="$(jq -re ' NR==2 && ENVIRON["PREV"]+0 != 0 {
select(.context == "results / coverage").description printf " (%+.1f%%)",100*($2-ENVIRON["PREV"])/ENVIRON["PREV"]}
| capture("(?<result>[0-9\\.]+)").result' \ NR==2 {printf "\n"}' \
prev-results.json || echo 0)" >> results.csv)
./scripts/coverage.py -u results/coverage.csv -Y | awk -F '[ /%]+' ' [ -e results/code-thumb-error-asserts.csv ] && ( \
NR==2 {printf "%.1f%% of %d lines",$4,$3} export PREV="$(jq -re '
NR==2 && ENVIRON["PREV"]+0 != 0 { select(.context == "results / code (error-asserts)").description
printf " (%+.1f%%)",$4-ENVIRON["PREV"]} | capture("Code size is (?<result>[0-9]+)").result' \
NR==2 {printf "\n"}' \ prev-results.json || echo 0)"
| sed -e 's/ /\&nbsp;/g' \ ./scripts/code.py -u results/code-thumb-error-asserts.csv -s | awk '
>> results.txt) NR==2 {printf "Code size<br/>(error-asserts),%d B",$2}
echo "</td>" >> results.txt NR==2 && ENVIRON["PREV"]+0 != 0 {
fi printf " (%+.1f%%)",100*($2-ENVIRON["PREV"])/ENVIRON["PREV"]}
echo "</tr>" >> results.txt NR==2 {printf "\n"}' \
done >> results.csv)
echo "</tbody>" >> results.txt [ -e results/coverage.csv ] && ( \
echo "</table>" >> results.txt 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 cat results.txt
# find changes from history # find changes from history
- name: collect-changes - name: collect-changes
run: | run: |
[ -n "$LFS_PREV_VERSION" ] || exit 0 [ -n "$LFS2_PREV_VERSION" ] || exit 0
# use explicit link to github commit so that release notes can # use explicit link to github commit so that release notes can
# be copied elsewhere # be copied elsewhere
git log "$LFS_PREV_VERSION.." \ git log "$LFS2_PREV_VERSION.." \
--grep='^Merge' --invert-grep \ --grep='^Merge' --invert-grep \
--format="format:[\`%h\`](` --format="format:[\`%h\`](`
`https://github.com/$GITHUB_REPOSITORY/commit/%h) %s" \ `https://github.com/$GITHUB_REPOSITORY/commit/%h) %s" \
@@ -157,25 +176,25 @@ jobs:
- name: create-major-branches - name: create-major-branches
run: | run: |
# create major branch # create major branch
git branch "v$LFS_VERSION_MAJOR" HEAD git branch "v$LFS2_VERSION_MAJOR" HEAD
# create major prefix branch # create major prefix branch
git config user.name ${{secrets.BOT_USER}} git config user.name ${{secrets.BOT_USER}}
git config user.email ${{secrets.BOT_EMAIL}} git config user.email ${{secrets.BOT_EMAIL}}
git fetch "https://github.com/$GITHUB_REPOSITORY.git" \ git fetch "https://github.com/$GITHUB_REPOSITORY.git" \
"v$LFS_VERSION_MAJOR-prefix" || true "v$LFS2_VERSION_MAJOR-prefix" || true
./scripts/prefix.py "lfs$LFS_VERSION_MAJOR" ./scripts/prefix.py "lfs2$LFS2_VERSION_MAJOR"
git branch "v$LFS_VERSION_MAJOR-prefix" $( \ git branch "v$LFS2_VERSION_MAJOR-prefix" $( \
git commit-tree $(git write-tree) \ git commit-tree $(git write-tree) \
$(git rev-parse --verify -q FETCH_HEAD | sed -e 's/^/-p /') \ $(git rev-parse --verify -q FETCH_HEAD | sed -e 's/^/-p /') \
-p HEAD \ -p HEAD \
-m "Generated v$LFS_VERSION_MAJOR prefixes") -m "Generated v$LFS2_VERSION_MAJOR prefixes")
git reset --hard git reset --hard
# push! # push!
git push --atomic origin \ git push --atomic origin \
"v$LFS_VERSION_MAJOR" \ "v$LFS2_VERSION_MAJOR" \
"v$LFS_VERSION_MAJOR-prefix" "v$LFS2_VERSION_MAJOR-prefix"
# build release notes # build release notes
- name: create-release - name: create-release
@@ -187,10 +206,10 @@ jobs:
curl -sS -X POST -H "authorization: token ${{secrets.BOT_TOKEN}}" \ curl -sS -X POST -H "authorization: token ${{secrets.BOT_TOKEN}}" \
"$GITHUB_API_URL/repos/$GITHUB_REPOSITORY/releases" \ "$GITHUB_API_URL/repos/$GITHUB_REPOSITORY/releases" \
-d "$(jq -n '{ -d "$(jq -n '{
tag_name: env.LFS_VERSION, tag_name: env.LFS2_VERSION,
name: env.LFS_VERSION | rtrimstr(".0"), name: env.LFS2_VERSION | rtrimstr(".0"),
target_commitish: "${{github.event.workflow_run.head_sha}}", target_commitish: "${{github.event.workflow_run.head_sha}}",
draft: env.LFS_VERSION | endswith(".0"), draft: env.LFS2_VERSION | endswith(".0"),
body: [env.RESULTS, env.CHANGES | select(.)] | join("\n\n")}' \ body: [env.RESULTS, env.CHANGES | select(.)] | join("\n\n")}' \
| tee /dev/stderr)" | tee /dev/stderr)"

View File

@@ -6,7 +6,7 @@ on:
jobs: jobs:
status: status:
runs-on: ubuntu-20.04 runs-on: ubuntu-18.04
steps: steps:
# custom statuses? # custom statuses?
- uses: dawidd6/action-download-artifact@v2 - uses: dawidd6/action-download-artifact@v2

View File

@@ -8,7 +8,7 @@ env:
jobs: jobs:
# run tests # run tests
test: test:
runs-on: ubuntu-20.04 runs-on: ubuntu-18.04
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -18,27 +18,11 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: install - name: install
run: | run: |
# need a few additional tools # need toml, also pip3 isn't installed by default?
#
# note this includes gcc-10, which is required for -fcallgraph-info=su
sudo apt-get update -qq sudo apt-get update -qq
sudo apt-get install -qq gcc-10 python3 python3-pip lcov sudo apt-get install -qq python3 python3-pip lcov
sudo pip3 install toml sudo pip3 install toml
echo "CC=gcc-10" >> $GITHUB_ENV gcc --version
gcc-10 --version
lcov --version
python3 --version
# need newer lcov version for gcc-10
#sudo apt-get remove lcov
#wget https://launchpad.net/ubuntu/+archive/primary/+files/lcov_1.15-1_all.deb
#sudo apt install ./lcov_1.15-1_all.deb
#lcov --version
#which lcov
#ls -lha /usr/bin/lcov
wget https://github.com/linux-test-project/lcov/releases/download/v1.15/lcov-1.15.tar.gz
tar xf lcov-1.15.tar.gz
sudo make -C lcov-1.15 install
# setup a ram-backed disk to speed up reentrant tests # setup a ram-backed disk to speed up reentrant tests
mkdir disks mkdir disks
@@ -57,36 +41,36 @@ jobs:
if: ${{matrix.arch == 'thumb'}} if: ${{matrix.arch == 'thumb'}}
run: | run: |
sudo apt-get install -qq \ sudo apt-get install -qq \
gcc-10-arm-linux-gnueabi \ gcc-arm-linux-gnueabi \
libc6-dev-armel-cross \ libc6-dev-armel-cross \
qemu-user qemu-user
echo "CC=arm-linux-gnueabi-gcc-10 -mthumb --static" >> $GITHUB_ENV echo "CC=arm-linux-gnueabi-gcc -mthumb --static" >> $GITHUB_ENV
echo "EXEC=qemu-arm" >> $GITHUB_ENV echo "EXEC=qemu-arm" >> $GITHUB_ENV
arm-linux-gnueabi-gcc-10 --version arm-linux-gnueabi-gcc --version
qemu-arm -version qemu-arm -version
# cross-compile with MIPS (32-bit, big-endian) # cross-compile with MIPS (32-bit, big-endian)
- name: install-mips - name: install-mips
if: ${{matrix.arch == 'mips'}} if: ${{matrix.arch == 'mips'}}
run: | run: |
sudo apt-get install -qq \ sudo apt-get install -qq \
gcc-10-mips-linux-gnu \ gcc-mips-linux-gnu \
libc6-dev-mips-cross \ libc6-dev-mips-cross \
qemu-user qemu-user
echo "CC=mips-linux-gnu-gcc-10 --static" >> $GITHUB_ENV echo "CC=mips-linux-gnu-gcc --static" >> $GITHUB_ENV
echo "EXEC=qemu-mips" >> $GITHUB_ENV echo "EXEC=qemu-mips" >> $GITHUB_ENV
mips-linux-gnu-gcc-10 --version mips-linux-gnu-gcc --version
qemu-mips -version qemu-mips -version
# cross-compile with PowerPC (32-bit, big-endian) # cross-compile with PowerPC (32-bit, big-endian)
- name: install-powerpc - name: install-powerpc
if: ${{matrix.arch == 'powerpc'}} if: ${{matrix.arch == 'powerpc'}}
run: | run: |
sudo apt-get install -qq \ sudo apt-get install -qq \
gcc-10-powerpc-linux-gnu \ gcc-powerpc-linux-gnu \
libc6-dev-powerpc-cross \ libc6-dev-powerpc-cross \
qemu-user qemu-user
echo "CC=powerpc-linux-gnu-gcc-10 --static" >> $GITHUB_ENV echo "CC=powerpc-linux-gnu-gcc --static" >> $GITHUB_ENV
echo "EXEC=qemu-ppc" >> $GITHUB_ENV echo "EXEC=qemu-ppc" >> $GITHUB_ENV
powerpc-linux-gnu-gcc-10 --version powerpc-linux-gnu-gcc --version
qemu-ppc -version qemu-ppc -version
# make sure example can at least compile # make sure example can at least compile
@@ -112,25 +96,25 @@ jobs:
run: | run: |
make clean make clean
make test TESTFLAGS+="-nrk \ make test TESTFLAGS+="-nrk \
-DLFS_READ_SIZE=1 -DLFS_BLOCK_SIZE=4096" -DLFS2_READ_SIZE=1 -DLFS2_BLOCK_SIZE=4096"
# SD/eMMC: read/prog = 512 block = 512 # SD/eMMC: read/prog = 512 block = 512
- name: test-emmc - name: test-emmc
run: | run: |
make clean make clean
make test TESTFLAGS+="-nrk \ make test TESTFLAGS+="-nrk \
-DLFS_READ_SIZE=512 -DLFS_BLOCK_SIZE=512" -DLFS2_READ_SIZE=512 -DLFS2_BLOCK_SIZE=512"
# NAND flash: read/prog = 4KiB block = 32KiB # NAND flash: read/prog = 4KiB block = 32KiB
- name: test-nand - name: test-nand
run: | run: |
make clean make clean
make test TESTFLAGS+="-nrk \ make test TESTFLAGS+="-nrk \
-DLFS_READ_SIZE=4096 -DLFS_BLOCK_SIZE=\(32*1024\)" -DLFS2_READ_SIZE=4096 -DLFS2_BLOCK_SIZE=\(32*1024\)"
# other extreme geometries that are useful for various corner cases # other extreme geometries that are useful for various corner cases
- name: test-no-intrinsics - name: test-no-intrinsics
run: | run: |
make clean make clean
make test TESTFLAGS+="-nrk \ make test TESTFLAGS+="-nrk \
-DLFS_NO_INTRINSICS" -DLFS2_NO_INTRINSICS"
- name: test-byte-writes - name: test-byte-writes
# it just takes too long to test byte-level writes when in qemu, # it just takes too long to test byte-level writes when in qemu,
# should be plenty covered by the other configurations # should be plenty covered by the other configurations
@@ -138,22 +122,22 @@ jobs:
run: | run: |
make clean make clean
make test TESTFLAGS+="-nrk \ make test TESTFLAGS+="-nrk \
-DLFS_READ_SIZE=1 -DLFS_CACHE_SIZE=1" -DLFS2_READ_SIZE=1 -DLFS2_CACHE_SIZE=1"
- name: test-block-cycles - name: test-block-cycles
run: | run: |
make clean make clean
make test TESTFLAGS+="-nrk \ make test TESTFLAGS+="-nrk \
-DLFS_BLOCK_CYCLES=1" -DLFS2_BLOCK_CYCLES=1"
- name: test-odd-block-count - name: test-odd-block-count
run: | run: |
make clean make clean
make test TESTFLAGS+="-nrk \ make test TESTFLAGS+="-nrk \
-DLFS_BLOCK_COUNT=1023 -DLFS_LOOKAHEAD_SIZE=256" -DLFS2_BLOCK_COUNT=1023 -DLFS2_LOOKAHEAD_SIZE=256"
- name: test-odd-block-size - name: test-odd-block-size
run: | run: |
make clean make clean
make test TESTFLAGS+="-nrk \ make test TESTFLAGS+="-nrk \
-DLFS_READ_SIZE=11 -DLFS_BLOCK_SIZE=704" -DLFS2_READ_SIZE=11 -DLFS2_BLOCK_SIZE=704"
# upload coverage for later coverage # upload coverage for later coverage
- name: upload-coverage - name: upload-coverage
@@ -164,108 +148,102 @@ jobs:
retention-days: 1 retention-days: 1
# update results # update results
- name: results - name: results-code
run: | run: |
mkdir -p results mkdir -p results
make clean make clean
make lfs.csv \ make code \
CFLAGS+=" \ CFLAGS+=" \
-DLFS_NO_ASSERT \ -DLFS2_NO_ASSERT \
-DLFS_NO_DEBUG \ -DLFS2_NO_DEBUG \
-DLFS_NO_WARN \ -DLFS2_NO_WARN \
-DLFS_NO_ERROR" -DLFS2_NO_ERROR" \
cp lfs.csv results/${{matrix.arch}}.csv CODEFLAGS+="-o results/code-${{matrix.arch}}.csv"
./scripts/summary.py results/${{matrix.arch}}.csv - name: results-code-readonly
- name: results-readonly
run: | run: |
mkdir -p results mkdir -p results
make clean make clean
make lfs.csv \ make code \
CFLAGS+=" \ CFLAGS+=" \
-DLFS_NO_ASSERT \ -DLFS2_NO_ASSERT \
-DLFS_NO_DEBUG \ -DLFS2_NO_DEBUG \
-DLFS_NO_WARN \ -DLFS2_NO_WARN \
-DLFS_NO_ERROR \ -DLFS2_NO_ERROR \
-DLFS_READONLY" -DLFS2_READONLY" \
cp lfs.csv results/${{matrix.arch}}-readonly.csv CODEFLAGS+="-o results/code-${{matrix.arch}}-readonly.csv"
./scripts/summary.py results/${{matrix.arch}}-readonly.csv - name: results-code-threadsafe
- name: results-threadsafe
run: | run: |
mkdir -p results mkdir -p results
make clean make clean
make lfs.csv \ make code \
CFLAGS+=" \ CFLAGS+=" \
-DLFS_NO_ASSERT \ -DLFS2_NO_ASSERT \
-DLFS_NO_DEBUG \ -DLFS2_NO_DEBUG \
-DLFS_NO_WARN \ -DLFS2_NO_WARN \
-DLFS_NO_ERROR \ -DLFS2_NO_ERROR \
-DLFS_THREADSAFE" -DLFS2_THREADSAFE" \
cp lfs.csv results/${{matrix.arch}}-threadsafe.csv CODEFLAGS+="-o results/code-${{matrix.arch}}-threadsafe.csv"
./scripts/summary.py results/${{matrix.arch}}-threadsafe.csv - name: results-code-migrate
- name: results-migrate
run: | run: |
mkdir -p results mkdir -p results
make clean make clean
make lfs.csv \ make code \
CFLAGS+=" \ CFLAGS+=" \
-DLFS_NO_ASSERT \ -DLFS2_NO_ASSERT \
-DLFS_NO_DEBUG \ -DLFS2_NO_DEBUG \
-DLFS_NO_WARN \ -DLFS2_NO_WARN \
-DLFS_NO_ERROR \ -DLFS2_NO_ERROR \
-DLFS_MIGRATE" -DLFS2_MIGRATE" \
cp lfs.csv results/${{matrix.arch}}-migrate.csv CODEFLAGS+="-o results/code-${{matrix.arch}}-migrate.csv"
./scripts/summary.py results/${{matrix.arch}}-migrate.csv - name: results-code-error-asserts
- name: results-error-asserts
run: | run: |
mkdir -p results mkdir -p results
make clean make clean
make lfs.csv \ make code \
CFLAGS+=" \ CFLAGS+=" \
-DLFS_NO_DEBUG \ -DLFS2_NO_DEBUG \
-DLFS_NO_WARN \ -DLFS2_NO_WARN \
-DLFS_NO_ERROR \ -DLFS2_NO_ERROR \
-D'LFS_ASSERT(test)=do {if(!(test)) {return -1;}} while(0)'" -D'LFS2_ASSERT(test)=do {if(!(test)) {return -1;}} while(0)'" \
cp lfs.csv results/${{matrix.arch}}-error-asserts.csv CODEFLAGS+="-o results/code-${{matrix.arch}}-error-asserts.csv"
./scripts/summary.py results/${{matrix.arch}}-error-asserts.csv
- name: upload-results - name: upload-results
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v2
with: with:
name: results name: results
path: results path: results
# limit reporting to Thumb, otherwise there would be too many numbers
# create statuses with results # flying around for the results to be easily readable
- name: collect-status - name: collect-status
if: ${{matrix.arch == 'thumb'}}
run: | run: |
mkdir -p status mkdir -p status
for f in $(shopt -s nullglob ; echo results/*.csv) for f in $(shopt -s nullglob ; echo results/code*.csv)
do do
export STEP="results$( export STEP="results-code$(
echo $f | sed -n 's/[^-]*-\(.*\).csv/-\1/p')" echo $f | sed -n 's/.*code-.*-\(.*\).csv/-\1/p')"
for r in code stack structs export CONTEXT="results / code$(
do echo $f | sed -n 's/.*code-.*-\(.*\).csv/ (\1)/p')"
export CONTEXT="results (${{matrix.arch}}$( export PREV="$(curl -sS \
echo $f | sed -n 's/[^-]*-\(.*\).csv/, \1/p')) / $r" "$GITHUB_API_URL/repos/$GITHUB_REPOSITORY/status/master" \
export PREV="$(curl -sS \ | jq -re 'select(.sha != env.GITHUB_SHA) | .statuses[]
"$GITHUB_API_URL/repos/$GITHUB_REPOSITORY/status/master?per_page=100" \ | select(.context == env.CONTEXT).description
| jq -re 'select(.sha != env.GITHUB_SHA) | .statuses[] | capture("Code size is (?<result>[0-9]+)").result' \
| select(.context == env.CONTEXT).description || echo 0)"
| capture("(?<result>[0-9∞]+)").result' \ export DESCRIPTION="$(./scripts/code.py -u $f -s | awk '
|| echo 0)" NR==2 {printf "Code size is %d B",$2}
export DESCRIPTION="$(./scripts/summary.py $f -f $r -Y | awk ' NR==2 && ENVIRON["PREV"]+0 != 0 {
NR==2 {printf "%s B",$2} printf " (%+.1f%%)",100*($2-ENVIRON["PREV"])/ENVIRON["PREV"]}')"
NR==2 && ENVIRON["PREV"]+0 != 0 { jq -n '{
printf " (%+.1f%%)",100*($2-ENVIRON["PREV"])/ENVIRON["PREV"]}')" state: "success",
jq -n '{ context: env.CONTEXT,
state: "success", description: env.DESCRIPTION,
context: env.CONTEXT, target_job: "${{github.job}} (${{matrix.arch}})",
description: env.DESCRIPTION, target_step: env.STEP}' \
target_job: "${{github.job}} (${{matrix.arch}})", | tee status/code$(
target_step: env.STEP}' \ echo $f | sed -n 's/.*code-.*-\(.*\).csv/-\1/p').json
| tee status/$r-${{matrix.arch}}$(
echo $f | sed -n 's/[^-]*-\(.*\).csv/-\1/p').json
done
done done
- name: upload-status - name: upload-status
if: ${{matrix.arch == 'thumb'}}
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v2
with: with:
name: status name: status
@@ -274,7 +252,7 @@ jobs:
# run under Valgrind to check for memory errors # run under Valgrind to check for memory errors
valgrind: valgrind:
runs-on: ubuntu-20.04 runs-on: ubuntu-18.04
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: install - name: install
@@ -294,7 +272,7 @@ jobs:
# self-host with littlefs-fuse for a fuzz-like test # self-host with littlefs-fuse for a fuzz-like test
fuse: fuse:
runs-on: ubuntu-20.04 runs-on: ubuntu-18.04
if: ${{!endsWith(github.ref, '-prefix')}} if: ${{!endsWith(github.ref, '-prefix')}}
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
@@ -319,18 +297,16 @@ jobs:
# setup disk for littlefs-fuse # setup disk for littlefs-fuse
mkdir mount mkdir mount
LOOP=$(sudo losetup -f) sudo chmod a+rw /dev/loop0
sudo chmod a+rw $LOOP
dd if=/dev/zero bs=512 count=128K of=disk dd if=/dev/zero bs=512 count=128K of=disk
losetup $LOOP disk losetup /dev/loop0 disk
echo "LOOP=$LOOP" >> $GITHUB_ENV
- name: test - name: test
run: | run: |
# self-host test # self-host test
make -C littlefs-fuse make -C littlefs-fuse
littlefs-fuse/lfs --format $LOOP littlefs-fuse/lfs2 --format /dev/loop0
littlefs-fuse/lfs $LOOP mount littlefs-fuse/lfs2 /dev/loop0 mount
ls mount ls mount
mkdir mount/littlefs mkdir mount/littlefs
@@ -342,7 +318,7 @@ jobs:
# test migration using littlefs-fuse # test migration using littlefs-fuse
migrate: migrate:
runs-on: ubuntu-20.04 runs-on: ubuntu-18.04
if: ${{!endsWith(github.ref, '-prefix')}} if: ${{!endsWith(github.ref, '-prefix')}}
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
@@ -372,11 +348,9 @@ jobs:
# setup disk for littlefs-fuse # setup disk for littlefs-fuse
mkdir mount mkdir mount
LOOP=$(sudo losetup -f) sudo chmod a+rw /dev/loop0
sudo chmod a+rw $LOOP
dd if=/dev/zero bs=512 count=128K of=disk dd if=/dev/zero bs=512 count=128K of=disk
losetup $LOOP disk losetup /dev/loop0 disk
echo "LOOP=$LOOP" >> $GITHUB_ENV
- name: test - name: test
run: | run: |
# compile v1 and v2 # compile v1 and v2
@@ -384,8 +358,8 @@ jobs:
make -C v2 make -C v2
# run self-host test with v1 # run self-host test with v1
v1/lfs --format $LOOP v1/lfs2 --format /dev/loop0
v1/lfs $LOOP mount v1/lfs2 /dev/loop0 mount
ls mount ls mount
mkdir mount/littlefs mkdir mount/littlefs
@@ -399,8 +373,8 @@ jobs:
cd ../.. cd ../..
fusermount -u mount fusermount -u mount
v2/lfs --migrate $LOOP v2/lfs2 --migrate /dev/loop0
v2/lfs $LOOP mount v2/lfs2 /dev/loop0 mount
# run self-host test with v2 right where we left off # run self-host test with v2 right where we left off
ls mount ls mount
@@ -411,7 +385,7 @@ jobs:
# collect coverage info # collect coverage info
coverage: coverage:
runs-on: ubuntu-20.04 runs-on: ubuntu-18.04
needs: [test] needs: [test]
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
@@ -447,14 +421,14 @@ jobs:
export STEP="results-coverage" export STEP="results-coverage"
export CONTEXT="results / coverage" export CONTEXT="results / coverage"
export PREV="$(curl -sS \ export PREV="$(curl -sS \
"$GITHUB_API_URL/repos/$GITHUB_REPOSITORY/status/master?per_page=100" \ "$GITHUB_API_URL/repos/$GITHUB_REPOSITORY/status/master" \
| jq -re 'select(.sha != env.GITHUB_SHA) | .statuses[] | jq -re 'select(.sha != env.GITHUB_SHA) | .statuses[]
| select(.context == env.CONTEXT).description | select(.context == env.CONTEXT).description
| capture("(?<result>[0-9\\.]+)").result' \ | capture("Coverage is (?<result>[0-9\\.]+)").result' \
|| echo 0)" || echo 0)"
export DESCRIPTION="$( export DESCRIPTION="$(
./scripts/coverage.py -u results/coverage.csv -Y | awk -F '[ /%]+' ' ./scripts/coverage.py -u results/coverage.csv -s | awk -F '[ /%]+' '
NR==2 {printf "%.1f%% of %d lines",$4,$3} NR==2 {printf "Coverage is %.1f%% of %d lines",$4,$3}
NR==2 && ENVIRON["PREV"]+0 != 0 { NR==2 && ENVIRON["PREV"]+0 != 0 {
printf " (%+.1f%%)",$4-ENVIRON["PREV"]}')" printf " (%+.1f%%)",$4-ENVIRON["PREV"]}')"
jq -n '{ jq -n '{

4
.gitignore vendored
View File

@@ -2,12 +2,10 @@
*.o *.o
*.d *.d
*.a *.a
*.ci
*.csv
# Testing things # Testing things
blocks/ blocks/
lfs lfs2
test.c test.c
tests/*.toml.* tests/*.toml.*
scripts/__pycache__ scripts/__pycache__

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,

101
Makefile
View File

@@ -11,69 +11,50 @@ endif
# overridable target/src/tools/flags/etc # overridable target/src/tools/flags/etc
ifneq ($(wildcard test.c main.c),) ifneq ($(wildcard test.c main.c),)
TARGET ?= $(BUILDDIR)lfs TARGET ?= $(BUILDDIR)lfs2
else else
TARGET ?= $(BUILDDIR)lfs.a TARGET ?= $(BUILDDIR)lfs2.a
endif endif
CC ?= gcc CC ?= gcc
AR ?= ar AR ?= ar
SIZE ?= size SIZE ?= size
CTAGS ?= ctags CTAGS ?= ctags
NM ?= nm NM ?= nm
OBJDUMP ?= objdump LCOV ?= lcov
LCOV ?= lcov
SRC ?= $(wildcard *.c) SRC ?= $(wildcard *.c)
OBJ := $(SRC:%.c=$(BUILDDIR)%.o) OBJ := $(SRC:%.c=$(BUILDDIR)%.o)
DEP := $(SRC:%.c=$(BUILDDIR)%.d) DEP := $(SRC:%.c=$(BUILDDIR)%.d)
ASM := $(SRC:%.c=$(BUILDDIR)%.s) ASM := $(SRC:%.c=$(BUILDDIR)%.s)
CGI := $(SRC:%.c=$(BUILDDIR)%.ci)
ifdef DEBUG ifdef DEBUG
override CFLAGS += -O0 override CFLAGS += -O0 -g3
else else
override CFLAGS += -Os override CFLAGS += -Os
endif endif
ifdef TRACE ifdef TRACE
override CFLAGS += -DLFS_YES_TRACE override CFLAGS += -DLFS2_YES_TRACE
endif endif
override CFLAGS += -g3
override CFLAGS += -I. override CFLAGS += -I.
override CFLAGS += -std=c99 -Wall -pedantic 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 TESTFLAGS += -v
override CALLSFLAGS += -v override CODEFLAGS += -v
override CODEFLAGS += -v
override DATAFLAGS += -v
override STACKFLAGS += -v
override STRUCTSFLAGS += -v
override COVERAGEFLAGS += -v override COVERAGEFLAGS += -v
endif endif
ifdef EXEC ifdef EXEC
override TESTFLAGS += --exec="$(EXEC)" override TESTFLAGS += --exec="$(EXEC)"
endif endif
ifdef COVERAGE
override TESTFLAGS += --coverage
endif
ifdef BUILDDIR ifdef BUILDDIR
override TESTFLAGS += --build-dir="$(BUILDDIR:/=)" override TESTFLAGS += --build-dir="$(BUILDDIR:/=)"
override CALLSFLAGS += --build-dir="$(BUILDDIR:/=)" override CODEFLAGS += --build-dir="$(BUILDDIR:/=)"
override CODEFLAGS += --build-dir="$(BUILDDIR:/=)"
override DATAFLAGS += --build-dir="$(BUILDDIR:/=)"
override STACKFLAGS += --build-dir="$(BUILDDIR:/=)"
override STRUCTSFLAGS += --build-dir="$(BUILDDIR:/=)"
override COVERAGEFLAGS += --build-dir="$(BUILDDIR:/=)"
endif endif
ifneq ($(NM),nm) ifneq ($(NM),nm)
override CODEFLAGS += --nm-tool="$(NM)" override CODEFLAGS += --nm-tool="$(NM)"
override DATAFLAGS += --nm-tool="$(NM)"
endif
ifneq ($(OBJDUMP),objdump)
override STRUCTSFLAGS += --objdump-tool="$(OBJDUMP)"
endif endif
@@ -92,9 +73,9 @@ size: $(OBJ)
tags: tags:
$(CTAGS) --totals --c-types=+p $(shell find -H -name '*.h') $(SRC) $(CTAGS) --totals --c-types=+p $(shell find -H -name '*.h') $(SRC)
.PHONY: calls .PHONY: code
calls: $(CGI) code: $(OBJ)
./scripts/calls.py $^ $(CALLSFLAGS) ./scripts/code.py $^ $(CODEFLAGS)
.PHONY: test .PHONY: test
test: test:
@@ -103,71 +84,31 @@ test:
test%: tests/test$$(firstword $$(subst \#, ,%)).toml test%: tests/test$$(firstword $$(subst \#, ,%)).toml
./scripts/test.py $@ $(TESTFLAGS) ./scripts/test.py $@ $(TESTFLAGS)
.PHONY: code
code: $(OBJ)
./scripts/code.py $^ -S $(CODEFLAGS)
.PHONY: data
data: $(OBJ)
./scripts/data.py $^ -S $(DATAFLAGS)
.PHONY: stack
stack: $(CGI)
./scripts/stack.py $^ -S $(STACKFLAGS)
.PHONY: structs
structs: $(OBJ)
./scripts/structs.py $^ -S $(STRUCTSFLAGS)
.PHONY: coverage .PHONY: coverage
coverage: coverage:
./scripts/coverage.py $(BUILDDIR)tests/*.toml.info -s $(COVERAGEFLAGS) ./scripts/coverage.py $(BUILDDIR)tests/*.toml.info $(COVERAGEFLAGS)
.PHONY: summary
summary: $(BUILDDIR)lfs.csv
./scripts/summary.py -Y $^ $(SUMMARYFLAGS)
# rules # rules
-include $(DEP) -include $(DEP)
.SUFFIXES: .SUFFIXES:
$(BUILDDIR)lfs: $(OBJ) $(BUILDDIR)lfs2: $(OBJ)
$(CC) $(CFLAGS) $^ $(LFLAGS) -o $@ $(CC) $(CFLAGS) $^ $(LFLAGS) -o $@
$(BUILDDIR)lfs.a: $(OBJ) $(BUILDDIR)%.a: $(OBJ)
$(AR) rcs $@ $^ $(AR) rcs $@ $^
$(BUILDDIR)lfs.csv: $(OBJ) $(CGI)
./scripts/code.py $(OBJ) -q $(CODEFLAGS) -o $@
./scripts/data.py $(OBJ) -q -m $@ $(DATAFLAGS) -o $@
./scripts/stack.py $(CGI) -q -m $@ $(STACKFLAGS) -o $@
./scripts/structs.py $(OBJ) -q -m $@ $(STRUCTSFLAGS) -o $@
$(if $(COVERAGE),\
./scripts/coverage.py $(BUILDDIR)tests/*.toml.info \
-q -m $@ $(COVERAGEFLAGS) -o $@)
$(BUILDDIR)%.o: %.c $(BUILDDIR)%.o: %.c
$(CC) -c -MMD $(CFLAGS) $< -o $@ $(CC) -c -MMD $(CFLAGS) $< -o $@
$(BUILDDIR)%.s: %.c $(BUILDDIR)%.s: %.c
$(CC) -S $(CFLAGS) $< -o $@ $(CC) -S $(CFLAGS) $< -o $@
# gcc depends on the output file for intermediate file names, so
# we can't omit to .o output. We also need to serialize with the
# normal .o rule because otherwise we can end up with multiprocess
# problems with two instances of gcc modifying the same .o
$(BUILDDIR)%.ci: %.c | $(BUILDDIR)%.o
$(CC) -c -MMD -fcallgraph-info=su $(CFLAGS) $< -o $|
# clean everything # clean everything
.PHONY: clean .PHONY: clean
clean: clean:
rm -f $(BUILDDIR)lfs rm -f $(TARGET)
rm -f $(BUILDDIR)lfs.a
rm -f $(BUILDDIR)lfs.csv
rm -f $(OBJ) rm -f $(OBJ)
rm -f $(CGI)
rm -f $(DEP) rm -f $(DEP)
rm -f $(ASM) rm -f $(ASM)
rm -f $(BUILDDIR)tests/*.toml.* rm -f $(BUILDDIR)tests/*.toml.*

View File

@@ -32,14 +32,14 @@ main runs. The program can be interrupted at any time without losing track
of how many times it has been booted and without corrupting the filesystem: of how many times it has been booted and without corrupting the filesystem:
``` c ``` c
#include "lfs.h" #include "lfs2.h"
// variables used by the filesystem // variables used by the filesystem
lfs_t lfs; lfs2_t lfs2;
lfs_file_t file; lfs2_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 lfs2_config 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,
@@ -59,30 +59,30 @@ const struct lfs_config cfg = {
// entry point // entry point
int main(void) { int main(void) {
// mount the filesystem // mount the filesystem
int err = lfs_mount(&lfs, &cfg); int err = lfs2_mount(&lfs2, &cfg);
// reformat if we can't mount the filesystem // reformat if we can't mount the filesystem
// this should only happen on the first boot // this should only happen on the first boot
if (err) { if (err) {
lfs_format(&lfs, &cfg); lfs2_format(&lfs2, &cfg);
lfs_mount(&lfs, &cfg); lfs2_mount(&lfs2, &cfg);
} }
// read current count // read current count
uint32_t boot_count = 0; uint32_t boot_count = 0;
lfs_file_open(&lfs, &file, "boot_count", LFS_O_RDWR | LFS_O_CREAT); lfs2_file_open(&lfs2, &file, "boot_count", LFS2_O_RDWR | LFS2_O_CREAT);
lfs_file_read(&lfs, &file, &boot_count, sizeof(boot_count)); lfs2_file_read(&lfs2, &file, &boot_count, sizeof(boot_count));
// update boot count // update boot count
boot_count += 1; boot_count += 1;
lfs_file_rewind(&lfs, &file); lfs2_file_rewind(&lfs2, &file);
lfs_file_write(&lfs, &file, &boot_count, sizeof(boot_count)); lfs2_file_write(&lfs2, &file, &boot_count, sizeof(boot_count));
// remember the storage is not updated until the file is closed successfully // remember the storage is not updated until the file is closed successfully
lfs_file_close(&lfs, &file); lfs2_file_close(&lfs2, &file);
// release any resources we were using // release any resources we were using
lfs_unmount(&lfs); lfs2_unmount(&lfs2);
// print the boot count // print the boot count
printf("boot_count: %d\n", boot_count); printf("boot_count: %d\n", boot_count);
@@ -92,7 +92,7 @@ int main(void) {
## Usage ## Usage
Detailed documentation (or at least as much detail as is currently available) Detailed documentation (or at least as much detail as is currently available)
can be found in the comments in [lfs.h](lfs.h). can be found in the comments in [lfs2.h](lfs2.h).
littlefs takes in a configuration structure that defines how the filesystem littlefs takes in a configuration structure that defines how the filesystem
operates. The configuration struct provides the filesystem with the block operates. The configuration struct provides the filesystem with the block
@@ -100,9 +100,9 @@ device operations and dimensions, tweakable parameters that tradeoff memory
usage for performance, and optional static buffers if the user wants to avoid usage for performance, and optional static buffers if the user wants to avoid
dynamic memory. dynamic memory.
The state of the littlefs is stored in the `lfs_t` type which is left up The state of the littlefs is stored in the `lfs2_t` type which is left up
to the user to allocate, allowing multiple filesystems to be in use to the user to allocate, allowing multiple filesystems to be in use
simultaneously. With the `lfs_t` and configuration struct, a user can simultaneously. With the `lfs2_t` and configuration struct, a user can
format a block device or mount the filesystem. format a block device or mount the filesystem.
Once mounted, the littlefs provides a full set of POSIX-like file and Once mounted, the littlefs provides a full set of POSIX-like file and
@@ -119,11 +119,11 @@ Littlefs is written in C, and specifically should compile with any compiler
that conforms to the `C99` standard. that conforms to the `C99` standard.
All littlefs calls have the potential to return a negative error code. The All littlefs calls have the potential to return a negative error code. The
errors can be either one of those found in the `enum lfs_error` in errors can be either one of those found in the `enum lfs2_error` in
[lfs.h](lfs.h), or an error returned by the user's block device operations. [lfs2.h](lfs2.h), or an error returned by the user's block device operations.
In the configuration struct, the `prog` and `erase` function provided by the In the configuration struct, the `prog` and `erase` function provided by the
user may return a `LFS_ERR_CORRUPT` error if the implementation already can user may return a `LFS2_ERR_CORRUPT` error if the implementation already can
detect corrupt blocks. However, the wear leveling does not depend on the return detect corrupt blocks. However, the wear leveling does not depend on the return
code of these functions, instead all data is read back and checked for code of these functions, instead all data is read back and checked for
integrity. integrity.
@@ -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](bd/lfs2_testbd.h) found in the `bd` 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

34
SPEC.md
View File

@@ -253,7 +253,7 @@ Metadata tag fields:
What follows is an exhaustive list of metadata in littlefs. What follows is an exhaustive list of metadata in littlefs.
--- ---
#### `0x401` LFS_TYPE_CREATE #### `0x401` LFS2_TYPE_CREATE
Creates a new file with this id. Note that files in a metadata block Creates a new file with this id. Note that files in a metadata block
don't necessarily need a create tag. All a create does is move over any don't necessarily need a create tag. All a create does is move over any
@@ -264,14 +264,14 @@ The create and delete tags allow littlefs to keep files in a directory
ordered alphabetically by filename. ordered alphabetically by filename.
--- ---
#### `0x4ff` LFS_TYPE_DELETE #### `0x4ff` LFS2_TYPE_DELETE
Deletes the file with this id. An inverse to create, this tag moves over Deletes the file with this id. An inverse to create, this tag moves over
any files neighboring this id similar to a deletion from an imaginary any files neighboring this id similar to a deletion from an imaginary
array of files. array of files.
--- ---
#### `0x0xx` LFS_TYPE_NAME #### `0x0xx` LFS2_TYPE_NAME
Associates the id with a file name and file type. Associates the id with a file name and file type.
@@ -304,14 +304,14 @@ Name fields:
2. **file name** - File name stored as an ASCII string. 2. **file name** - File name stored as an ASCII string.
--- ---
#### `0x001` LFS_TYPE_REG #### `0x001` LFS2_TYPE_REG
Initializes the id + name as a regular file. Initializes the id + name as a regular file.
How each file is stored depends on its struct tag, which is described below. How each file is stored depends on its struct tag, which is described below.
--- ---
#### `0x002` LFS_TYPE_DIR #### `0x002` LFS2_TYPE_DIR
Initializes the id + name as a directory. Initializes the id + name as a directory.
@@ -320,7 +320,7 @@ each pair containing any number of files in alphabetical order. A pointer to
the directory is stored in the struct tag, which is described below. the directory is stored in the struct tag, which is described below.
--- ---
#### `0x0ff` LFS_TYPE_SUPERBLOCK #### `0x0ff` LFS2_TYPE_SUPERBLOCK
Initializes the id as a superblock entry. Initializes the id as a superblock entry.
@@ -405,7 +405,7 @@ as be the first entry written to the block. This means that the superblock
entry can be read from a device using offsets alone. entry can be read from a device using offsets alone.
--- ---
#### `0x2xx` LFS_TYPE_STRUCT #### `0x2xx` LFS2_TYPE_STRUCT
Associates the id with an on-disk data structure. Associates the id with an on-disk data structure.
@@ -416,7 +416,7 @@ Any type of struct supersedes all other structs associated with the id. For
example, appending a ctz-struct replaces an inline-struct on the same file. example, appending a ctz-struct replaces an inline-struct on the same file.
--- ---
#### `0x200` LFS_TYPE_DIRSTRUCT #### `0x200` LFS2_TYPE_DIRSTRUCT
Gives the id a directory data structure. Gives the id a directory data structure.
@@ -458,7 +458,7 @@ Dir-struct fields:
in the directory. in the directory.
--- ---
#### `0x201` LFS_TYPE_INLINESTRUCT #### `0x201` LFS2_TYPE_INLINESTRUCT
Gives the id an inline data structure. Gives the id an inline data structure.
@@ -482,7 +482,7 @@ Inline-struct fields:
1. **Inline data** - File data stored directly in the metadata-pair. 1. **Inline data** - File data stored directly in the metadata-pair.
--- ---
#### `0x202` LFS_TYPE_CTZSTRUCT #### `0x202` LFS2_TYPE_CTZSTRUCT
Gives the id a CTZ skip-list data structure. Gives the id a CTZ skip-list data structure.
@@ -537,7 +537,7 @@ CTZ-struct fields:
2. **File size (32-bits)** - Size of the file in bytes. 2. **File size (32-bits)** - Size of the file in bytes.
--- ---
#### `0x3xx` LFS_TYPE_USERATTR #### `0x3xx` LFS2_TYPE_USERATTR
Attaches a user attribute to an id. Attaches a user attribute to an id.
@@ -571,7 +571,7 @@ User-attr fields:
2. **Attr data** - The data associated with the user attribute. 2. **Attr data** - The data associated with the user attribute.
--- ---
#### `0x6xx` LFS_TYPE_TAIL #### `0x6xx` LFS2_TYPE_TAIL
Provides the tail pointer for the metadata pair itself. Provides the tail pointer for the metadata pair itself.
@@ -637,7 +637,7 @@ Tail fields:
2. **Metadata pair (8-bytes)** - Pointer to the next metadata-pair. 2. **Metadata pair (8-bytes)** - Pointer to the next metadata-pair.
--- ---
#### `0x600` LFS_TYPE_SOFTTAIL #### `0x600` LFS2_TYPE_SOFTTAIL
Provides a tail pointer that points to the next metadata pair in the Provides a tail pointer that points to the next metadata pair in the
filesystem. filesystem.
@@ -646,7 +646,7 @@ In this case, the next metadata pair is not a part of our current directory
and should only be followed when traversing the entire filesystem. and should only be followed when traversing the entire filesystem.
--- ---
#### `0x601` LFS_TYPE_HARDTAIL #### `0x601` LFS2_TYPE_HARDTAIL
Provides a tail pointer that points to the next metadata pair in the Provides a tail pointer that points to the next metadata pair in the
directory. directory.
@@ -657,7 +657,7 @@ metadata pair should only contain filenames greater than any filename in the
current pair. current pair.
--- ---
#### `0x7xx` LFS_TYPE_GSTATE #### `0x7xx` LFS2_TYPE_GSTATE
Provides delta bits for global state entries. Provides delta bits for global state entries.
@@ -687,7 +687,7 @@ is stored in the chunk field. Currently, the only global state is move state,
which is outlined below. which is outlined below.
--- ---
#### `0x7ff` LFS_TYPE_MOVESTATE #### `0x7ff` LFS2_TYPE_MOVESTATE
Provides delta bits for the global move state. Provides delta bits for the global move state.
@@ -740,7 +740,7 @@ Move state fields:
the move. the move.
--- ---
#### `0x5xx` LFS_TYPE_CRC #### `0x5xx` LFS2_TYPE_CRC
Last but not least, the CRC tag marks the end of a commit and provides a Last but not least, the CRC tag marks the end of a commit and provides a
checksum for any commits to the metadata block. checksum for any commits to the metadata block.

View File

@@ -1,23 +1,18 @@
/* /*
* 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
*/ */
#include "bd/lfs_filebd.h" #include "bd/lfs2_filebd.h"
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h> #include <unistd.h>
#include <errno.h> #include <errno.h>
#ifdef _WIN32 int lfs2_filebd_createcfg(const struct lfs2_config *cfg, const char *path,
#include <windows.h> const struct lfs2_filebd_config *bdcfg) {
#endif LFS2_FILEBD_TRACE("lfs2_filebd_createcfg(%p {.context=%p, "
int lfs_filebd_createcfg(const struct lfs_config *cfg, const char *path,
const struct lfs_filebd_config *bdcfg) {
LFS_FILEBD_TRACE("lfs_filebd_createcfg(%p {.context=%p, "
".read=%p, .prog=%p, .erase=%p, .sync=%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"}, " ".block_size=%"PRIu32", .block_count=%"PRIu32"}, "
@@ -28,28 +23,23 @@ int lfs_filebd_createcfg(const struct lfs_config *cfg, const char *path,
(void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync,
cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count,
path, (void*)bdcfg, bdcfg->erase_value); path, (void*)bdcfg, bdcfg->erase_value);
lfs_filebd_t *bd = cfg->context; lfs2_filebd_t *bd = cfg->context;
bd->cfg = bdcfg; bd->cfg = bdcfg;
// open file // open file
#ifdef _WIN32
bd->fd = open(path, O_RDWR | O_CREAT | O_BINARY, 0666);
#else
bd->fd = open(path, O_RDWR | O_CREAT, 0666); bd->fd = open(path, O_RDWR | O_CREAT, 0666);
#endif
if (bd->fd < 0) { if (bd->fd < 0) {
int err = -errno; int err = -errno;
LFS_FILEBD_TRACE("lfs_filebd_createcfg -> %d", err); LFS2_FILEBD_TRACE("lfs2_filebd_createcfg -> %d", err);
return err; return err;
} }
LFS_FILEBD_TRACE("lfs_filebd_createcfg -> %d", 0); LFS2_FILEBD_TRACE("lfs2_filebd_createcfg -> %d", 0);
return 0; return 0;
} }
int lfs_filebd_create(const struct lfs_config *cfg, const char *path) { int lfs2_filebd_create(const struct lfs2_config *cfg, const char *path) {
LFS_FILEBD_TRACE("lfs_filebd_create(%p {.context=%p, " LFS2_FILEBD_TRACE("lfs2_filebd_create(%p {.context=%p, "
".read=%p, .prog=%p, .erase=%p, .sync=%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"}, " ".block_size=%"PRIu32", .block_count=%"PRIu32"}, "
@@ -59,36 +49,36 @@ int lfs_filebd_create(const struct lfs_config *cfg, const char *path) {
(void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync,
cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count,
path); path);
static const struct lfs_filebd_config defaults = {.erase_value=-1}; static const struct lfs2_filebd_config defaults = {.erase_value=-1};
int err = lfs_filebd_createcfg(cfg, path, &defaults); int err = lfs2_filebd_createcfg(cfg, path, &defaults);
LFS_FILEBD_TRACE("lfs_filebd_create -> %d", err); LFS2_FILEBD_TRACE("lfs2_filebd_create -> %d", err);
return err; return err;
} }
int lfs_filebd_destroy(const struct lfs_config *cfg) { int lfs2_filebd_destroy(const struct lfs2_config *cfg) {
LFS_FILEBD_TRACE("lfs_filebd_destroy(%p)", (void*)cfg); LFS2_FILEBD_TRACE("lfs2_filebd_destroy(%p)", (void*)cfg);
lfs_filebd_t *bd = cfg->context; lfs2_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;
LFS_FILEBD_TRACE("lfs_filebd_destroy -> %d", err); LFS2_FILEBD_TRACE("lfs2_filebd_destroy -> %d", err);
return err; return err;
} }
LFS_FILEBD_TRACE("lfs_filebd_destroy -> %d", 0); LFS2_FILEBD_TRACE("lfs2_filebd_destroy -> %d", 0);
return 0; return 0;
} }
int lfs_filebd_read(const struct lfs_config *cfg, lfs_block_t block, int lfs2_filebd_read(const struct lfs2_config *cfg, lfs2_block_t block,
lfs_off_t off, void *buffer, lfs_size_t size) { lfs2_off_t off, void *buffer, lfs2_size_t size) {
LFS_FILEBD_TRACE("lfs_filebd_read(%p, " LFS2_FILEBD_TRACE("lfs2_filebd_read(%p, "
"0x%"PRIx32", %"PRIu32", %p, %"PRIu32")", "0x%"PRIx32", %"PRIu32", %p, %"PRIu32")",
(void*)cfg, block, off, buffer, size); (void*)cfg, block, off, buffer, size);
lfs_filebd_t *bd = cfg->context; lfs2_filebd_t *bd = cfg->context;
// check if read is valid // check if read is valid
LFS_ASSERT(off % cfg->read_size == 0); LFS2_ASSERT(off % cfg->read_size == 0);
LFS_ASSERT(size % cfg->read_size == 0); LFS2_ASSERT(size % cfg->read_size == 0);
LFS_ASSERT(block < cfg->block_count); LFS2_ASSERT(block < cfg->block_count);
// zero for reproducibility (in case file is truncated) // zero for reproducibility (in case file is truncated)
if (bd->cfg->erase_value != -1) { if (bd->cfg->erase_value != -1) {
@@ -100,31 +90,31 @@ int lfs_filebd_read(const struct lfs_config *cfg, lfs_block_t block,
(off_t)block*cfg->block_size + (off_t)off, SEEK_SET); (off_t)block*cfg->block_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); LFS2_FILEBD_TRACE("lfs2_filebd_read -> %d", err);
return err; return err;
} }
ssize_t res2 = read(bd->fd, buffer, size); ssize_t res2 = read(bd->fd, buffer, size);
if (res2 < 0) { if (res2 < 0) {
int err = -errno; int err = -errno;
LFS_FILEBD_TRACE("lfs_filebd_read -> %d", err); LFS2_FILEBD_TRACE("lfs2_filebd_read -> %d", err);
return err; return err;
} }
LFS_FILEBD_TRACE("lfs_filebd_read -> %d", 0); LFS2_FILEBD_TRACE("lfs2_filebd_read -> %d", 0);
return 0; return 0;
} }
int lfs_filebd_prog(const struct lfs_config *cfg, lfs_block_t block, int lfs2_filebd_prog(const struct lfs2_config *cfg, lfs2_block_t block,
lfs_off_t off, const void *buffer, lfs_size_t size) { lfs2_off_t off, const void *buffer, lfs2_size_t size) {
LFS_FILEBD_TRACE("lfs_filebd_prog(%p, 0x%"PRIx32", %"PRIu32", %p, %"PRIu32")", LFS2_FILEBD_TRACE("lfs2_filebd_prog(%p, 0x%"PRIx32", %"PRIu32", %p, %"PRIu32")",
(void*)cfg, block, off, buffer, size); (void*)cfg, block, off, buffer, size);
lfs_filebd_t *bd = cfg->context; lfs2_filebd_t *bd = cfg->context;
// check if write is valid // check if write is valid
LFS_ASSERT(off % cfg->prog_size == 0); LFS2_ASSERT(off % cfg->prog_size == 0);
LFS_ASSERT(size % cfg->prog_size == 0); LFS2_ASSERT(size % cfg->prog_size == 0);
LFS_ASSERT(block < cfg->block_count); LFS2_ASSERT(block < cfg->block_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) {
@@ -132,20 +122,20 @@ int lfs_filebd_prog(const struct lfs_config *cfg, lfs_block_t block,
(off_t)block*cfg->block_size + (off_t)off, SEEK_SET); (off_t)block*cfg->block_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); LFS2_FILEBD_TRACE("lfs2_filebd_prog -> %d", err);
return err; return err;
} }
for (lfs_off_t i = 0; i < size; i++) { for (lfs2_off_t i = 0; i < size; i++) {
uint8_t c; uint8_t c;
ssize_t res2 = read(bd->fd, &c, 1); ssize_t res2 = read(bd->fd, &c, 1);
if (res2 < 0) { if (res2 < 0) {
int err = -errno; int err = -errno;
LFS_FILEBD_TRACE("lfs_filebd_prog -> %d", err); LFS2_FILEBD_TRACE("lfs2_filebd_prog -> %d", err);
return err; return err;
} }
LFS_ASSERT(c == bd->cfg->erase_value); LFS2_ASSERT(c == bd->cfg->erase_value);
} }
} }
@@ -154,66 +144,62 @@ int lfs_filebd_prog(const struct lfs_config *cfg, lfs_block_t block,
(off_t)block*cfg->block_size + (off_t)off, SEEK_SET); (off_t)block*cfg->block_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); LFS2_FILEBD_TRACE("lfs2_filebd_prog -> %d", err);
return err; return err;
} }
ssize_t res2 = write(bd->fd, buffer, size); ssize_t res2 = write(bd->fd, buffer, size);
if (res2 < 0) { if (res2 < 0) {
int err = -errno; int err = -errno;
LFS_FILEBD_TRACE("lfs_filebd_prog -> %d", err); LFS2_FILEBD_TRACE("lfs2_filebd_prog -> %d", err);
return err; return err;
} }
LFS_FILEBD_TRACE("lfs_filebd_prog -> %d", 0); LFS2_FILEBD_TRACE("lfs2_filebd_prog -> %d", 0);
return 0; return 0;
} }
int lfs_filebd_erase(const struct lfs_config *cfg, lfs_block_t block) { int lfs2_filebd_erase(const struct lfs2_config *cfg, lfs2_block_t block) {
LFS_FILEBD_TRACE("lfs_filebd_erase(%p, 0x%"PRIx32")", (void*)cfg, block); LFS2_FILEBD_TRACE("lfs2_filebd_erase(%p, 0x%"PRIx32")", (void*)cfg, block);
lfs_filebd_t *bd = cfg->context; lfs2_filebd_t *bd = cfg->context;
// check if erase is valid // check if erase is valid
LFS_ASSERT(block < cfg->block_count); LFS2_ASSERT(block < cfg->block_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*cfg->block_size, SEEK_SET);
if (res1 < 0) { if (res1 < 0) {
int err = -errno; int err = -errno;
LFS_FILEBD_TRACE("lfs_filebd_erase -> %d", err); LFS2_FILEBD_TRACE("lfs2_filebd_erase -> %d", err);
return err; return err;
} }
for (lfs_off_t i = 0; i < cfg->block_size; i++) { for (lfs2_off_t i = 0; i < cfg->block_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;
LFS_FILEBD_TRACE("lfs_filebd_erase -> %d", err); LFS2_FILEBD_TRACE("lfs2_filebd_erase -> %d", err);
return err; return err;
} }
} }
} }
LFS_FILEBD_TRACE("lfs_filebd_erase -> %d", 0); LFS2_FILEBD_TRACE("lfs2_filebd_erase -> %d", 0);
return 0; return 0;
} }
int lfs_filebd_sync(const struct lfs_config *cfg) { int lfs2_filebd_sync(const struct lfs2_config *cfg) {
LFS_FILEBD_TRACE("lfs_filebd_sync(%p)", (void*)cfg); LFS2_FILEBD_TRACE("lfs2_filebd_sync(%p)", (void*)cfg);
// file sync // file sync
lfs_filebd_t *bd = cfg->context; lfs2_filebd_t *bd = cfg->context;
#ifdef _WIN32
int err = FlushFileBuffers((HANDLE) _get_osfhandle(fd)) ? 0 : -1;
#else
int err = fsync(bd->fd); int err = fsync(bd->fd);
#endif
if (err) { if (err) {
err = -errno; err = -errno;
LFS_FILEBD_TRACE("lfs_filebd_sync -> %d", 0); LFS2_FILEBD_TRACE("lfs2_filebd_sync -> %d", 0);
return err; return err;
} }
LFS_FILEBD_TRACE("lfs_filebd_sync -> %d", 0); LFS2_FILEBD_TRACE("lfs2_filebd_sync -> %d", 0);
return 0; return 0;
} }

73
bd/lfs2_filebd.h Normal file
View File

@@ -0,0 +1,73 @@
/*
* Block device emulated in a file
*
* Copyright (c) 2017, Arm Limited. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef LFS2_FILEBD_H
#define LFS2_FILEBD_H
#include "lfs2.h"
#include "lfs2_util.h"
#ifdef __cplusplus
extern "C"
{
#endif
// Block device specific tracing
#ifdef LFS2_FILEBD_YES_TRACE
#define LFS2_FILEBD_TRACE(...) LFS2_TRACE(__VA_ARGS__)
#else
#define LFS2_FILEBD_TRACE(...)
#endif
// filebd config (optional)
struct lfs2_filebd_config {
// 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;
};
// filebd state
typedef struct lfs2_filebd {
int fd;
const struct lfs2_filebd_config *cfg;
} lfs2_filebd_t;
// Create a file block device using the geometry in lfs2_config
int lfs2_filebd_create(const struct lfs2_config *cfg, const char *path);
int lfs2_filebd_createcfg(const struct lfs2_config *cfg, const char *path,
const struct lfs2_filebd_config *bdcfg);
// Clean up memory associated with block device
int lfs2_filebd_destroy(const struct lfs2_config *cfg);
// Read a block
int lfs2_filebd_read(const struct lfs2_config *cfg, lfs2_block_t block,
lfs2_off_t off, void *buffer, lfs2_size_t size);
// Program a block
//
// The block must have previously been erased.
int lfs2_filebd_prog(const struct lfs2_config *cfg, lfs2_block_t block,
lfs2_off_t off, const void *buffer, lfs2_size_t size);
// Erase a block
//
// A block must be erased before being programmed. The
// state of an erased block is undefined.
int lfs2_filebd_erase(const struct lfs2_config *cfg, lfs2_block_t block);
// Sync the block device
int lfs2_filebd_sync(const struct lfs2_config *cfg);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

View File

@@ -1,15 +1,14 @@
/* /*
* 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/lfs2_rambd.h"
int lfs_rambd_createcfg(const struct lfs_config *cfg, int lfs2_rambd_createcfg(const struct lfs2_config *cfg,
const struct lfs_rambd_config *bdcfg) { const struct lfs2_rambd_config *bdcfg) {
LFS_RAMBD_TRACE("lfs_rambd_createcfg(%p {.context=%p, " LFS2_RAMBD_TRACE("lfs2_rambd_createcfg(%p {.context=%p, "
".read=%p, .prog=%p, .erase=%p, .sync=%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"}, " ".block_size=%"PRIu32", .block_count=%"PRIu32"}, "
@@ -19,17 +18,17 @@ int lfs_rambd_createcfg(const struct lfs_config *cfg,
(void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync,
cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count,
(void*)bdcfg, bdcfg->erase_value, bdcfg->buffer); (void*)bdcfg, bdcfg->erase_value, bdcfg->buffer);
lfs_rambd_t *bd = cfg->context; lfs2_rambd_t *bd = cfg->context;
bd->cfg = bdcfg; 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 = lfs2_malloc(cfg->block_size * cfg->block_count);
if (!bd->buffer) { if (!bd->buffer) {
LFS_RAMBD_TRACE("lfs_rambd_createcfg -> %d", LFS_ERR_NOMEM); LFS2_RAMBD_TRACE("lfs2_rambd_createcfg -> %d", LFS2_ERR_NOMEM);
return LFS_ERR_NOMEM; return LFS2_ERR_NOMEM;
} }
} }
@@ -41,12 +40,12 @@ int lfs_rambd_createcfg(const struct lfs_config *cfg,
memset(bd->buffer, 0, cfg->block_size * cfg->block_count); memset(bd->buffer, 0, cfg->block_size * cfg->block_count);
} }
LFS_RAMBD_TRACE("lfs_rambd_createcfg -> %d", 0); LFS2_RAMBD_TRACE("lfs2_rambd_createcfg -> %d", 0);
return 0; return 0;
} }
int lfs_rambd_create(const struct lfs_config *cfg) { int lfs2_rambd_create(const struct lfs2_config *cfg) {
LFS_RAMBD_TRACE("lfs_rambd_create(%p {.context=%p, " LFS2_RAMBD_TRACE("lfs2_rambd_create(%p {.context=%p, "
".read=%p, .prog=%p, .erase=%p, .sync=%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"})", ".block_size=%"PRIu32", .block_count=%"PRIu32"})",
@@ -54,58 +53,58 @@ int lfs_rambd_create(const struct lfs_config *cfg) {
(void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog,
(void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync,
cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count); cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count);
static const struct lfs_rambd_config defaults = {.erase_value=-1}; static const struct lfs2_rambd_config defaults = {.erase_value=-1};
int err = lfs_rambd_createcfg(cfg, &defaults); int err = lfs2_rambd_createcfg(cfg, &defaults);
LFS_RAMBD_TRACE("lfs_rambd_create -> %d", err); LFS2_RAMBD_TRACE("lfs2_rambd_create -> %d", err);
return err; return err;
} }
int lfs_rambd_destroy(const struct lfs_config *cfg) { int lfs2_rambd_destroy(const struct lfs2_config *cfg) {
LFS_RAMBD_TRACE("lfs_rambd_destroy(%p)", (void*)cfg); LFS2_RAMBD_TRACE("lfs2_rambd_destroy(%p)", (void*)cfg);
// clean up memory // clean up memory
lfs_rambd_t *bd = cfg->context; lfs2_rambd_t *bd = cfg->context;
if (!bd->cfg->buffer) { if (!bd->cfg->buffer) {
lfs_free(bd->buffer); lfs2_free(bd->buffer);
} }
LFS_RAMBD_TRACE("lfs_rambd_destroy -> %d", 0); LFS2_RAMBD_TRACE("lfs2_rambd_destroy -> %d", 0);
return 0; return 0;
} }
int lfs_rambd_read(const struct lfs_config *cfg, lfs_block_t block, int lfs2_rambd_read(const struct lfs2_config *cfg, lfs2_block_t block,
lfs_off_t off, void *buffer, lfs_size_t size) { lfs2_off_t off, void *buffer, lfs2_size_t size) {
LFS_RAMBD_TRACE("lfs_rambd_read(%p, " LFS2_RAMBD_TRACE("lfs2_rambd_read(%p, "
"0x%"PRIx32", %"PRIu32", %p, %"PRIu32")", "0x%"PRIx32", %"PRIu32", %p, %"PRIu32")",
(void*)cfg, block, off, buffer, size); (void*)cfg, block, off, buffer, size);
lfs_rambd_t *bd = cfg->context; lfs2_rambd_t *bd = cfg->context;
// check if read is valid // check if read is valid
LFS_ASSERT(off % cfg->read_size == 0); LFS2_ASSERT(off % cfg->read_size == 0);
LFS_ASSERT(size % cfg->read_size == 0); LFS2_ASSERT(size % cfg->read_size == 0);
LFS_ASSERT(block < cfg->block_count); LFS2_ASSERT(block < cfg->block_count);
// read data // read data
memcpy(buffer, &bd->buffer[block*cfg->block_size + off], size); memcpy(buffer, &bd->buffer[block*cfg->block_size + off], size);
LFS_RAMBD_TRACE("lfs_rambd_read -> %d", 0); LFS2_RAMBD_TRACE("lfs2_rambd_read -> %d", 0);
return 0; return 0;
} }
int lfs_rambd_prog(const struct lfs_config *cfg, lfs_block_t block, int lfs2_rambd_prog(const struct lfs2_config *cfg, lfs2_block_t block,
lfs_off_t off, const void *buffer, lfs_size_t size) { lfs2_off_t off, const void *buffer, lfs2_size_t size) {
LFS_RAMBD_TRACE("lfs_rambd_prog(%p, " LFS2_RAMBD_TRACE("lfs2_rambd_prog(%p, "
"0x%"PRIx32", %"PRIu32", %p, %"PRIu32")", "0x%"PRIx32", %"PRIu32", %p, %"PRIu32")",
(void*)cfg, block, off, buffer, size); (void*)cfg, block, off, buffer, size);
lfs_rambd_t *bd = cfg->context; lfs2_rambd_t *bd = cfg->context;
// check if write is valid // check if write is valid
LFS_ASSERT(off % cfg->prog_size == 0); LFS2_ASSERT(off % cfg->prog_size == 0);
LFS_ASSERT(size % cfg->prog_size == 0); LFS2_ASSERT(size % cfg->prog_size == 0);
LFS_ASSERT(block < cfg->block_count); LFS2_ASSERT(block < cfg->block_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 (lfs2_off_t i = 0; i < size; i++) {
LFS_ASSERT(bd->buffer[block*cfg->block_size + off + i] == LFS2_ASSERT(bd->buffer[block*cfg->block_size + off + i] ==
bd->cfg->erase_value); bd->cfg->erase_value);
} }
} }
@@ -113,16 +112,16 @@ int lfs_rambd_prog(const struct lfs_config *cfg, lfs_block_t block,
// program data // program data
memcpy(&bd->buffer[block*cfg->block_size + off], buffer, size); memcpy(&bd->buffer[block*cfg->block_size + off], buffer, size);
LFS_RAMBD_TRACE("lfs_rambd_prog -> %d", 0); LFS2_RAMBD_TRACE("lfs2_rambd_prog -> %d", 0);
return 0; return 0;
} }
int lfs_rambd_erase(const struct lfs_config *cfg, lfs_block_t block) { int lfs2_rambd_erase(const struct lfs2_config *cfg, lfs2_block_t block) {
LFS_RAMBD_TRACE("lfs_rambd_erase(%p, 0x%"PRIx32")", (void*)cfg, block); LFS2_RAMBD_TRACE("lfs2_rambd_erase(%p, 0x%"PRIx32")", (void*)cfg, block);
lfs_rambd_t *bd = cfg->context; lfs2_rambd_t *bd = cfg->context;
// check if erase is valid // check if erase is valid
LFS_ASSERT(block < cfg->block_count); LFS2_ASSERT(block < cfg->block_count);
// erase, only needed for testing // erase, only needed for testing
if (bd->cfg->erase_value != -1) { if (bd->cfg->erase_value != -1) {
@@ -130,14 +129,14 @@ int lfs_rambd_erase(const struct lfs_config *cfg, lfs_block_t block) {
bd->cfg->erase_value, cfg->block_size); bd->cfg->erase_value, cfg->block_size);
} }
LFS_RAMBD_TRACE("lfs_rambd_erase -> %d", 0); LFS2_RAMBD_TRACE("lfs2_rambd_erase -> %d", 0);
return 0; return 0;
} }
int lfs_rambd_sync(const struct lfs_config *cfg) { int lfs2_rambd_sync(const struct lfs2_config *cfg) {
LFS_RAMBD_TRACE("lfs_rambd_sync(%p)", (void*)cfg); LFS2_RAMBD_TRACE("lfs2_rambd_sync(%p)", (void*)cfg);
// 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)cfg;
LFS_RAMBD_TRACE("lfs_rambd_sync -> %d", 0); LFS2_RAMBD_TRACE("lfs2_rambd_sync -> %d", 0);
return 0; return 0;
} }

75
bd/lfs2_rambd.h Normal file
View File

@@ -0,0 +1,75 @@
/*
* Block device emulated in RAM
*
* Copyright (c) 2017, Arm Limited. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef LFS2_RAMBD_H
#define LFS2_RAMBD_H
#include "lfs2.h"
#include "lfs2_util.h"
#ifdef __cplusplus
extern "C"
{
#endif
// Block device specific tracing
#ifdef LFS2_RAMBD_YES_TRACE
#define LFS2_RAMBD_TRACE(...) LFS2_TRACE(__VA_ARGS__)
#else
#define LFS2_RAMBD_TRACE(...)
#endif
// rambd config (optional)
struct lfs2_rambd_config {
// 8-bit erase value to simulate erasing with. -1 indicates no erase
// occurs, which is still a valid block device
int32_t erase_value;
// Optional statically allocated buffer for the block device.
void *buffer;
};
// rambd state
typedef struct lfs2_rambd {
uint8_t *buffer;
const struct lfs2_rambd_config *cfg;
} lfs2_rambd_t;
// Create a RAM block device using the geometry in lfs2_config
int lfs2_rambd_create(const struct lfs2_config *cfg);
int lfs2_rambd_createcfg(const struct lfs2_config *cfg,
const struct lfs2_rambd_config *bdcfg);
// Clean up memory associated with block device
int lfs2_rambd_destroy(const struct lfs2_config *cfg);
// Read a block
int lfs2_rambd_read(const struct lfs2_config *cfg, lfs2_block_t block,
lfs2_off_t off, void *buffer, lfs2_size_t size);
// Program a block
//
// The block must have previously been erased.
int lfs2_rambd_prog(const struct lfs2_config *cfg, lfs2_block_t block,
lfs2_off_t off, const void *buffer, lfs2_size_t size);
// Erase a block
//
// A block must be erased before being programmed. The
// state of an erased block is undefined.
int lfs2_rambd_erase(const struct lfs2_config *cfg, lfs2_block_t block);
// Sync the block device
int lfs2_rambd_sync(const struct lfs2_config *cfg);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

302
bd/lfs2_testbd.c Normal file
View File

@@ -0,0 +1,302 @@
/*
* Testing block device, wraps filebd and rambd while providing a bunch
* of hooks for testing littlefs in various conditions.
*
* Copyright (c) 2017, Arm Limited. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "bd/lfs2_testbd.h"
#include <stdlib.h>
int lfs2_testbd_createcfg(const struct lfs2_config *cfg, const char *path,
const struct lfs2_testbd_config *bdcfg) {
LFS2_TESTBD_TRACE("lfs2_testbd_createcfg(%p {.context=%p, "
".read=%p, .prog=%p, .erase=%p, .sync=%p, "
".read_size=%"PRIu32", .prog_size=%"PRIu32", "
".block_size=%"PRIu32", .block_count=%"PRIu32"}, "
"\"%s\", "
"%p {.erase_value=%"PRId32", .erase_cycles=%"PRIu32", "
".badblock_behavior=%"PRIu8", .power_cycles=%"PRIu32", "
".buffer=%p, .wear_buffer=%p})",
(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, (void*)bdcfg, bdcfg->erase_value, bdcfg->erase_cycles,
bdcfg->badblock_behavior, bdcfg->power_cycles,
bdcfg->buffer, bdcfg->wear_buffer);
lfs2_testbd_t *bd = cfg->context;
bd->cfg = bdcfg;
// setup testing things
bd->persist = path;
bd->power_cycles = bd->cfg->power_cycles;
if (bd->cfg->erase_cycles) {
if (bd->cfg->wear_buffer) {
bd->wear = bd->cfg->wear_buffer;
} else {
bd->wear = lfs2_malloc(sizeof(lfs2_testbd_wear_t)*cfg->block_count);
if (!bd->wear) {
LFS2_TESTBD_TRACE("lfs2_testbd_createcfg -> %d", LFS2_ERR_NOMEM);
return LFS2_ERR_NOMEM;
}
}
memset(bd->wear, 0, sizeof(lfs2_testbd_wear_t) * cfg->block_count);
}
// create underlying block device
if (bd->persist) {
bd->u.file.cfg = (struct lfs2_filebd_config){
.erase_value = bd->cfg->erase_value,
};
int err = lfs2_filebd_createcfg(cfg, path, &bd->u.file.cfg);
LFS2_TESTBD_TRACE("lfs2_testbd_createcfg -> %d", err);
return err;
} else {
bd->u.ram.cfg = (struct lfs2_rambd_config){
.erase_value = bd->cfg->erase_value,
.buffer = bd->cfg->buffer,
};
int err = lfs2_rambd_createcfg(cfg, &bd->u.ram.cfg);
LFS2_TESTBD_TRACE("lfs2_testbd_createcfg -> %d", err);
return err;
}
}
int lfs2_testbd_create(const struct lfs2_config *cfg, const char *path) {
LFS2_TESTBD_TRACE("lfs2_testbd_create(%p {.context=%p, "
".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 lfs2_testbd_config defaults = {.erase_value=-1};
int err = lfs2_testbd_createcfg(cfg, path, &defaults);
LFS2_TESTBD_TRACE("lfs2_testbd_create -> %d", err);
return err;
}
int lfs2_testbd_destroy(const struct lfs2_config *cfg) {
LFS2_TESTBD_TRACE("lfs2_testbd_destroy(%p)", (void*)cfg);
lfs2_testbd_t *bd = cfg->context;
if (bd->cfg->erase_cycles && !bd->cfg->wear_buffer) {
lfs2_free(bd->wear);
}
if (bd->persist) {
int err = lfs2_filebd_destroy(cfg);
LFS2_TESTBD_TRACE("lfs2_testbd_destroy -> %d", err);
return err;
} else {
int err = lfs2_rambd_destroy(cfg);
LFS2_TESTBD_TRACE("lfs2_testbd_destroy -> %d", err);
return err;
}
}
/// Internal mapping to block devices ///
static int lfs2_testbd_rawread(const struct lfs2_config *cfg, lfs2_block_t block,
lfs2_off_t off, void *buffer, lfs2_size_t size) {
lfs2_testbd_t *bd = cfg->context;
if (bd->persist) {
return lfs2_filebd_read(cfg, block, off, buffer, size);
} else {
return lfs2_rambd_read(cfg, block, off, buffer, size);
}
}
static int lfs2_testbd_rawprog(const struct lfs2_config *cfg, lfs2_block_t block,
lfs2_off_t off, const void *buffer, lfs2_size_t size) {
lfs2_testbd_t *bd = cfg->context;
if (bd->persist) {
return lfs2_filebd_prog(cfg, block, off, buffer, size);
} else {
return lfs2_rambd_prog(cfg, block, off, buffer, size);
}
}
static int lfs2_testbd_rawerase(const struct lfs2_config *cfg,
lfs2_block_t block) {
lfs2_testbd_t *bd = cfg->context;
if (bd->persist) {
return lfs2_filebd_erase(cfg, block);
} else {
return lfs2_rambd_erase(cfg, block);
}
}
static int lfs2_testbd_rawsync(const struct lfs2_config *cfg) {
lfs2_testbd_t *bd = cfg->context;
if (bd->persist) {
return lfs2_filebd_sync(cfg);
} else {
return lfs2_rambd_sync(cfg);
}
}
/// block device API ///
int lfs2_testbd_read(const struct lfs2_config *cfg, lfs2_block_t block,
lfs2_off_t off, void *buffer, lfs2_size_t size) {
LFS2_TESTBD_TRACE("lfs2_testbd_read(%p, "
"0x%"PRIx32", %"PRIu32", %p, %"PRIu32")",
(void*)cfg, block, off, buffer, size);
lfs2_testbd_t *bd = cfg->context;
// check if read is valid
LFS2_ASSERT(off % cfg->read_size == 0);
LFS2_ASSERT(size % cfg->read_size == 0);
LFS2_ASSERT(block < cfg->block_count);
// block bad?
if (bd->cfg->erase_cycles && bd->wear[block] >= bd->cfg->erase_cycles &&
bd->cfg->badblock_behavior == LFS2_TESTBD_BADBLOCK_READERROR) {
LFS2_TESTBD_TRACE("lfs2_testbd_read -> %d", LFS2_ERR_CORRUPT);
return LFS2_ERR_CORRUPT;
}
// read
int err = lfs2_testbd_rawread(cfg, block, off, buffer, size);
LFS2_TESTBD_TRACE("lfs2_testbd_read -> %d", err);
return err;
}
int lfs2_testbd_prog(const struct lfs2_config *cfg, lfs2_block_t block,
lfs2_off_t off, const void *buffer, lfs2_size_t size) {
LFS2_TESTBD_TRACE("lfs2_testbd_prog(%p, "
"0x%"PRIx32", %"PRIu32", %p, %"PRIu32")",
(void*)cfg, block, off, buffer, size);
lfs2_testbd_t *bd = cfg->context;
// check if write is valid
LFS2_ASSERT(off % cfg->prog_size == 0);
LFS2_ASSERT(size % cfg->prog_size == 0);
LFS2_ASSERT(block < cfg->block_count);
// block bad?
if (bd->cfg->erase_cycles && bd->wear[block] >= bd->cfg->erase_cycles) {
if (bd->cfg->badblock_behavior ==
LFS2_TESTBD_BADBLOCK_PROGERROR) {
LFS2_TESTBD_TRACE("lfs2_testbd_prog -> %d", LFS2_ERR_CORRUPT);
return LFS2_ERR_CORRUPT;
} else if (bd->cfg->badblock_behavior ==
LFS2_TESTBD_BADBLOCK_PROGNOOP ||
bd->cfg->badblock_behavior ==
LFS2_TESTBD_BADBLOCK_ERASENOOP) {
LFS2_TESTBD_TRACE("lfs2_testbd_prog -> %d", 0);
return 0;
}
}
// prog
int err = lfs2_testbd_rawprog(cfg, block, off, buffer, size);
if (err) {
LFS2_TESTBD_TRACE("lfs2_testbd_prog -> %d", err);
return err;
}
// lose power?
if (bd->power_cycles > 0) {
bd->power_cycles -= 1;
if (bd->power_cycles == 0) {
// sync to make sure we persist the last changes
LFS2_ASSERT(lfs2_testbd_rawsync(cfg) == 0);
// simulate power loss
exit(33);
}
}
LFS2_TESTBD_TRACE("lfs2_testbd_prog -> %d", 0);
return 0;
}
int lfs2_testbd_erase(const struct lfs2_config *cfg, lfs2_block_t block) {
LFS2_TESTBD_TRACE("lfs2_testbd_erase(%p, 0x%"PRIx32")", (void*)cfg, block);
lfs2_testbd_t *bd = cfg->context;
// check if erase is valid
LFS2_ASSERT(block < cfg->block_count);
// block bad?
if (bd->cfg->erase_cycles) {
if (bd->wear[block] >= bd->cfg->erase_cycles) {
if (bd->cfg->badblock_behavior ==
LFS2_TESTBD_BADBLOCK_ERASEERROR) {
LFS2_TESTBD_TRACE("lfs2_testbd_erase -> %d", LFS2_ERR_CORRUPT);
return LFS2_ERR_CORRUPT;
} else if (bd->cfg->badblock_behavior ==
LFS2_TESTBD_BADBLOCK_ERASENOOP) {
LFS2_TESTBD_TRACE("lfs2_testbd_erase -> %d", 0);
return 0;
}
} else {
// mark wear
bd->wear[block] += 1;
}
}
// erase
int err = lfs2_testbd_rawerase(cfg, block);
if (err) {
LFS2_TESTBD_TRACE("lfs2_testbd_erase -> %d", err);
return err;
}
// lose power?
if (bd->power_cycles > 0) {
bd->power_cycles -= 1;
if (bd->power_cycles == 0) {
// sync to make sure we persist the last changes
LFS2_ASSERT(lfs2_testbd_rawsync(cfg) == 0);
// simulate power loss
exit(33);
}
}
LFS2_TESTBD_TRACE("lfs2_testbd_prog -> %d", 0);
return 0;
}
int lfs2_testbd_sync(const struct lfs2_config *cfg) {
LFS2_TESTBD_TRACE("lfs2_testbd_sync(%p)", (void*)cfg);
int err = lfs2_testbd_rawsync(cfg);
LFS2_TESTBD_TRACE("lfs2_testbd_sync -> %d", err);
return err;
}
/// simulated wear operations ///
lfs2_testbd_swear_t lfs2_testbd_getwear(const struct lfs2_config *cfg,
lfs2_block_t block) {
LFS2_TESTBD_TRACE("lfs2_testbd_getwear(%p, %"PRIu32")", (void*)cfg, block);
lfs2_testbd_t *bd = cfg->context;
// check if block is valid
LFS2_ASSERT(bd->cfg->erase_cycles);
LFS2_ASSERT(block < cfg->block_count);
LFS2_TESTBD_TRACE("lfs2_testbd_getwear -> %"PRIu32, bd->wear[block]);
return bd->wear[block];
}
int lfs2_testbd_setwear(const struct lfs2_config *cfg,
lfs2_block_t block, lfs2_testbd_wear_t wear) {
LFS2_TESTBD_TRACE("lfs2_testbd_setwear(%p, %"PRIu32")", (void*)cfg, block);
lfs2_testbd_t *bd = cfg->context;
// check if block is valid
LFS2_ASSERT(bd->cfg->erase_cycles);
LFS2_ASSERT(block < cfg->block_count);
bd->wear[block] = wear;
LFS2_TESTBD_TRACE("lfs2_testbd_setwear -> %d", 0);
return 0;
}

View File

@@ -2,17 +2,16 @@
* 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
*/ */
#ifndef LFS_TESTBD_H #ifndef LFS2_TESTBD_H
#define LFS_TESTBD_H #define LFS2_TESTBD_H
#include "lfs.h" #include "lfs2.h"
#include "lfs_util.h" #include "lfs2_util.h"
#include "bd/lfs_rambd.h" #include "bd/lfs2_rambd.h"
#include "bd/lfs_filebd.h" #include "bd/lfs2_filebd.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" extern "C"
@@ -21,10 +20,10 @@ extern "C"
// Block device specific tracing // Block device specific tracing
#ifdef LFS_TESTBD_YES_TRACE #ifdef LFS2_TESTBD_YES_TRACE
#define LFS_TESTBD_TRACE(...) LFS_TRACE(__VA_ARGS__) #define LFS2_TESTBD_TRACE(...) LFS2_TRACE(__VA_ARGS__)
#else #else
#define LFS_TESTBD_TRACE(...) #define LFS2_TESTBD_TRACE(...)
#endif #endif
// Mode determining how "bad blocks" behave during testing. This simulates // Mode determining how "bad blocks" behave during testing. This simulates
@@ -33,20 +32,20 @@ extern "C"
// //
// Not that read-noop is not allowed. Read _must_ return a consistent (but // Not that read-noop is not allowed. Read _must_ return a consistent (but
// may be arbitrary) value on every read. // may be arbitrary) value on every read.
enum lfs_testbd_badblock_behavior { enum lfs2_testbd_badblock_behavior {
LFS_TESTBD_BADBLOCK_PROGERROR, LFS2_TESTBD_BADBLOCK_PROGERROR,
LFS_TESTBD_BADBLOCK_ERASEERROR, LFS2_TESTBD_BADBLOCK_ERASEERROR,
LFS_TESTBD_BADBLOCK_READERROR, LFS2_TESTBD_BADBLOCK_READERROR,
LFS_TESTBD_BADBLOCK_PROGNOOP, LFS2_TESTBD_BADBLOCK_PROGNOOP,
LFS_TESTBD_BADBLOCK_ERASENOOP, LFS2_TESTBD_BADBLOCK_ERASENOOP,
}; };
// Type for measuring wear // Type for measuring wear
typedef uint32_t lfs_testbd_wear_t; typedef uint32_t lfs2_testbd_wear_t;
typedef int32_t lfs_testbd_swear_t; typedef int32_t lfs2_testbd_swear_t;
// testbd config, this is required for testing // testbd config, this is required for testing
struct lfs_testbd_config { struct lfs2_testbd_config {
// 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.
@@ -71,68 +70,68 @@ struct lfs_testbd_config {
}; };
// testbd state // testbd state
typedef struct lfs_testbd { typedef struct lfs2_testbd {
union { union {
struct { struct {
lfs_filebd_t bd; lfs2_filebd_t bd;
struct lfs_filebd_config cfg; struct lfs2_filebd_config cfg;
} file; } file;
struct { struct {
lfs_rambd_t bd; lfs2_rambd_t bd;
struct lfs_rambd_config cfg; struct lfs2_rambd_config cfg;
} ram; } ram;
} u; } u;
bool persist; bool persist;
uint32_t power_cycles; uint32_t power_cycles;
lfs_testbd_wear_t *wear; lfs2_testbd_wear_t *wear;
const struct lfs_testbd_config *cfg; const struct lfs2_testbd_config *cfg;
} lfs_testbd_t; } lfs2_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 lfs2_config
// //
// 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 lfs2_testbd_create(const struct lfs2_config *cfg, const char *path);
int lfs_testbd_createcfg(const struct lfs_config *cfg, const char *path, int lfs2_testbd_createcfg(const struct lfs2_config *cfg, const char *path,
const struct lfs_testbd_config *bdcfg); const struct lfs2_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 lfs2_testbd_destroy(const struct lfs2_config *cfg);
// Read a block // Read a block
int lfs_testbd_read(const struct lfs_config *cfg, lfs_block_t block, int lfs2_testbd_read(const struct lfs2_config *cfg, lfs2_block_t block,
lfs_off_t off, void *buffer, lfs_size_t size); lfs2_off_t off, void *buffer, lfs2_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 lfs2_testbd_prog(const struct lfs2_config *cfg, lfs2_block_t block,
lfs_off_t off, const void *buffer, lfs_size_t size); lfs2_off_t off, const void *buffer, lfs2_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 lfs2_testbd_erase(const struct lfs2_config *cfg, lfs2_block_t block);
// Sync the block device // Sync the block device
int lfs_testbd_sync(const struct lfs_config *cfg); int lfs2_testbd_sync(const struct lfs2_config *cfg);
/// 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, lfs2_testbd_swear_t lfs2_testbd_getwear(const struct lfs2_config *cfg,
lfs_block_t block); lfs2_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 lfs2_testbd_setwear(const struct lfs2_config *cfg,
lfs_block_t block, lfs_testbd_wear_t wear); lfs2_block_t block, lfs2_testbd_wear_t wear);
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -1,74 +0,0 @@
/*
* Block device emulated in a file
*
* Copyright (c) 2022, The littlefs authors.
* Copyright (c) 2017, Arm Limited. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef LFS_FILEBD_H
#define LFS_FILEBD_H
#include "lfs.h"
#include "lfs_util.h"
#ifdef __cplusplus
extern "C"
{
#endif
// Block device specific tracing
#ifdef LFS_FILEBD_YES_TRACE
#define LFS_FILEBD_TRACE(...) LFS_TRACE(__VA_ARGS__)
#else
#define LFS_FILEBD_TRACE(...)
#endif
// filebd config (optional)
struct lfs_filebd_config {
// 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;
};
// filebd state
typedef struct lfs_filebd {
int fd;
const struct lfs_filebd_config *cfg;
} lfs_filebd_t;
// Create a file block device using the geometry in lfs_config
int lfs_filebd_create(const struct lfs_config *cfg, const char *path);
int lfs_filebd_createcfg(const struct lfs_config *cfg, const char *path,
const struct lfs_filebd_config *bdcfg);
// Clean up memory associated with block device
int lfs_filebd_destroy(const struct lfs_config *cfg);
// Read a block
int lfs_filebd_read(const struct lfs_config *cfg, lfs_block_t block,
lfs_off_t off, void *buffer, lfs_size_t size);
// Program a block
//
// The block must have previously been erased.
int lfs_filebd_prog(const struct lfs_config *cfg, lfs_block_t block,
lfs_off_t off, const void *buffer, lfs_size_t size);
// Erase a block
//
// A block must be erased before being programmed. The
// state of an erased block is undefined.
int lfs_filebd_erase(const struct lfs_config *cfg, lfs_block_t block);
// Sync the block device
int lfs_filebd_sync(const struct lfs_config *cfg);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

View File

@@ -1,76 +0,0 @@
/*
* Block device emulated in RAM
*
* Copyright (c) 2022, The littlefs authors.
* Copyright (c) 2017, Arm Limited. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef LFS_RAMBD_H
#define LFS_RAMBD_H
#include "lfs.h"
#include "lfs_util.h"
#ifdef __cplusplus
extern "C"
{
#endif
// Block device specific tracing
#ifdef LFS_RAMBD_YES_TRACE
#define LFS_RAMBD_TRACE(...) LFS_TRACE(__VA_ARGS__)
#else
#define LFS_RAMBD_TRACE(...)
#endif
// rambd config (optional)
struct lfs_rambd_config {
// 8-bit erase value to simulate erasing with. -1 indicates no erase
// occurs, which is still a valid block device
int32_t erase_value;
// Optional statically allocated buffer for the block device.
void *buffer;
};
// rambd state
typedef struct lfs_rambd {
uint8_t *buffer;
const struct lfs_rambd_config *cfg;
} lfs_rambd_t;
// Create a RAM block device using the geometry in lfs_config
int lfs_rambd_create(const struct lfs_config *cfg);
int lfs_rambd_createcfg(const struct lfs_config *cfg,
const struct lfs_rambd_config *bdcfg);
// Clean up memory associated with block device
int lfs_rambd_destroy(const struct lfs_config *cfg);
// Read a block
int lfs_rambd_read(const struct lfs_config *cfg, lfs_block_t block,
lfs_off_t off, void *buffer, lfs_size_t size);
// Program a block
//
// The block must have previously been erased.
int lfs_rambd_prog(const struct lfs_config *cfg, lfs_block_t block,
lfs_off_t off, const void *buffer, lfs_size_t size);
// Erase a block
//
// A block must be erased before being programmed. The
// state of an erased block is undefined.
int lfs_rambd_erase(const struct lfs_config *cfg, lfs_block_t block);
// Sync the block device
int lfs_rambd_sync(const struct lfs_config *cfg);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

View File

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

5819
lfs.c

File diff suppressed because it is too large Load Diff

5438
lfs2.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,16 +1,15 @@
/* /*
* 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 LFS2_H
#define LFS_H #define LFS2_H
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include "lfs_util.h" #include "lfs2_util.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" extern "C"
@@ -23,190 +22,190 @@ 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 0x00020005 #define LFS2_VERSION 0x00020004
#define LFS_VERSION_MAJOR (0xffff & (LFS_VERSION >> 16)) #define LFS2_VERSION_MAJOR (0xffff & (LFS2_VERSION >> 16))
#define LFS_VERSION_MINOR (0xffff & (LFS_VERSION >> 0)) #define LFS2_VERSION_MINOR (0xffff & (LFS2_VERSION >> 0))
// Version of On-disk data structures // Version of On-disk data structures
// 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_DISK_VERSION 0x00020000 #define LFS2_DISK_VERSION 0x00020000
#define LFS_DISK_VERSION_MAJOR (0xffff & (LFS_DISK_VERSION >> 16)) #define LFS2_DISK_VERSION_MAJOR (0xffff & (LFS2_DISK_VERSION >> 16))
#define LFS_DISK_VERSION_MINOR (0xffff & (LFS_DISK_VERSION >> 0)) #define LFS2_DISK_VERSION_MINOR (0xffff & (LFS2_DISK_VERSION >> 0))
/// Definitions /// /// Definitions ///
// Type definitions // Type definitions
typedef uint32_t lfs_size_t; typedef uint32_t lfs2_size_t;
typedef uint32_t lfs_off_t; typedef uint32_t lfs2_off_t;
typedef int32_t lfs_ssize_t; typedef int32_t lfs2_ssize_t;
typedef int32_t lfs_soff_t; typedef int32_t lfs2_soff_t;
typedef uint32_t lfs_block_t; typedef uint32_t lfs2_block_t;
// Maximum name size in bytes, may be redefined to reduce the size of the // Maximum name size in bytes, may be redefined to reduce the size of the
// 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 LFS2_NAME_MAX
#define LFS_NAME_MAX 255 #define LFS2_NAME_MAX 255
#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
// functions lfs_file_seek, lfs_file_size, and lfs_file_tell will return // functions lfs2_file_seek, lfs2_file_size, and lfs2_file_tell will return
// 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 LFS2_FILE_MAX
#define LFS_FILE_MAX 2147483647 #define LFS2_FILE_MAX 2147483647
#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 LFS2_ATTR_MAX. Limited to <= 1022.
#ifndef LFS_ATTR_MAX #ifndef LFS2_ATTR_MAX
#define LFS_ATTR_MAX 1022 #define LFS2_ATTR_MAX 1022
#endif #endif
// Possible error codes, these are negative to allow // Possible error codes, these are negative to allow
// valid positive return values // valid positive return values
enum lfs_error { enum lfs2_error {
LFS_ERR_OK = 0, // No error LFS2_ERR_OK = 0, // No error
LFS_ERR_IO = -5, // Error during device operation LFS2_ERR_IO = -5, // Error during device operation
LFS_ERR_CORRUPT = -84, // Corrupted LFS2_ERR_CORRUPT = -84, // Corrupted
LFS_ERR_NOENT = -2, // No directory entry LFS2_ERR_NOENT = -2, // No directory entry
LFS_ERR_EXIST = -17, // Entry already exists LFS2_ERR_EXIST = -17, // Entry already exists
LFS_ERR_NOTDIR = -20, // Entry is not a dir LFS2_ERR_NOTDIR = -20, // Entry is not a dir
LFS_ERR_ISDIR = -21, // Entry is a dir LFS2_ERR_ISDIR = -21, // Entry is a dir
LFS_ERR_NOTEMPTY = -39, // Dir is not empty LFS2_ERR_NOTEMPTY = -39, // Dir is not empty
LFS_ERR_BADF = -9, // Bad file number LFS2_ERR_BADF = -9, // Bad file number
LFS_ERR_FBIG = -27, // File too large LFS2_ERR_FBIG = -27, // File too large
LFS_ERR_INVAL = -22, // Invalid parameter LFS2_ERR_INVAL = -22, // Invalid parameter
LFS_ERR_NOSPC = -28, // No space left on device LFS2_ERR_NOSPC = -28, // No space left on device
LFS_ERR_NOMEM = -12, // No more memory available LFS2_ERR_NOMEM = -12, // No more memory available
LFS_ERR_NOATTR = -61, // No data/attr available LFS2_ERR_NOATTR = -61, // No data/attr available
LFS_ERR_NAMETOOLONG = -36, // File name too long LFS2_ERR_NAMETOOLONG = -36, // File name too long
}; };
// File types // File types
enum lfs_type { enum lfs2_type {
// file types // file types
LFS_TYPE_REG = 0x001, LFS2_TYPE_REG = 0x001,
LFS_TYPE_DIR = 0x002, LFS2_TYPE_DIR = 0x002,
// internally used types // internally used types
LFS_TYPE_SPLICE = 0x400, LFS2_TYPE_SPLICE = 0x400,
LFS_TYPE_NAME = 0x000, LFS2_TYPE_NAME = 0x000,
LFS_TYPE_STRUCT = 0x200, LFS2_TYPE_STRUCT = 0x200,
LFS_TYPE_USERATTR = 0x300, LFS2_TYPE_USERATTR = 0x300,
LFS_TYPE_FROM = 0x100, LFS2_TYPE_FROM = 0x100,
LFS_TYPE_TAIL = 0x600, LFS2_TYPE_TAIL = 0x600,
LFS_TYPE_GLOBALS = 0x700, LFS2_TYPE_GLOBALS = 0x700,
LFS_TYPE_CRC = 0x500, LFS2_TYPE_CRC = 0x500,
// internally used type specializations // internally used type specializations
LFS_TYPE_CREATE = 0x401, LFS2_TYPE_CREATE = 0x401,
LFS_TYPE_DELETE = 0x4ff, LFS2_TYPE_DELETE = 0x4ff,
LFS_TYPE_SUPERBLOCK = 0x0ff, LFS2_TYPE_SUPERBLOCK = 0x0ff,
LFS_TYPE_DIRSTRUCT = 0x200, LFS2_TYPE_DIRSTRUCT = 0x200,
LFS_TYPE_CTZSTRUCT = 0x202, LFS2_TYPE_CTZSTRUCT = 0x202,
LFS_TYPE_INLINESTRUCT = 0x201, LFS2_TYPE_INLINESTRUCT = 0x201,
LFS_TYPE_SOFTTAIL = 0x600, LFS2_TYPE_SOFTTAIL = 0x600,
LFS_TYPE_HARDTAIL = 0x601, LFS2_TYPE_HARDTAIL = 0x601,
LFS_TYPE_MOVESTATE = 0x7ff, LFS2_TYPE_MOVESTATE = 0x7ff,
// internal chip sources // internal chip sources
LFS_FROM_NOOP = 0x000, LFS2_FROM_NOOP = 0x000,
LFS_FROM_MOVE = 0x101, LFS2_FROM_MOVE = 0x101,
LFS_FROM_USERATTRS = 0x102, LFS2_FROM_USERATTRS = 0x102,
}; };
// File open flags // File open flags
enum lfs_open_flags { enum lfs2_open_flags {
// open flags // open flags
LFS_O_RDONLY = 1, // Open a file as read only LFS2_O_RDONLY = 1, // Open a file as read only
#ifndef LFS_READONLY #ifndef LFS2_READONLY
LFS_O_WRONLY = 2, // Open a file as write only LFS2_O_WRONLY = 2, // Open a file as write only
LFS_O_RDWR = 3, // Open a file as read and write LFS2_O_RDWR = 3, // Open a file as read and write
LFS_O_CREAT = 0x0100, // Create a file if it does not exist LFS2_O_CREAT = 0x0100, // Create a file if it does not exist
LFS_O_EXCL = 0x0200, // Fail if a file already exists LFS2_O_EXCL = 0x0200, // Fail if a file already exists
LFS_O_TRUNC = 0x0400, // Truncate the existing file to zero size LFS2_O_TRUNC = 0x0400, // Truncate the existing file to zero size
LFS_O_APPEND = 0x0800, // Move to end of file on every write LFS2_O_APPEND = 0x0800, // Move to end of file on every write
#endif #endif
// internally used flags // internally used flags
#ifndef LFS_READONLY #ifndef LFS2_READONLY
LFS_F_DIRTY = 0x010000, // File does not match storage LFS2_F_DIRTY = 0x010000, // File does not match storage
LFS_F_WRITING = 0x020000, // File has been written since last flush LFS2_F_WRITING = 0x020000, // File has been written since last flush
#endif #endif
LFS_F_READING = 0x040000, // File has been read since last flush LFS2_F_READING = 0x040000, // File has been read since last flush
#ifndef LFS_READONLY #ifndef LFS2_READONLY
LFS_F_ERRED = 0x080000, // An error occurred during write LFS2_F_ERRED = 0x080000, // An error occurred during write
#endif #endif
LFS_F_INLINE = 0x100000, // Currently inlined in directory entry LFS2_F_INLINE = 0x100000, // Currently inlined in directory entry
}; };
// File seek flags // File seek flags
enum lfs_whence_flags { enum lfs2_whence_flags {
LFS_SEEK_SET = 0, // Seek relative to an absolute position LFS2_SEEK_SET = 0, // Seek relative to an absolute position
LFS_SEEK_CUR = 1, // Seek relative to the current file position LFS2_SEEK_CUR = 1, // Seek relative to the current file position
LFS_SEEK_END = 2, // Seek relative to the end of the file LFS2_SEEK_END = 2, // Seek relative to the end of the file
}; };
// Configuration provided during initialization of the littlefs // Configuration provided during initialization of the littlefs
struct lfs_config { struct lfs2_config {
// 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; void *context;
// Read a region in a block. Negative error codes are propagated // Read a region in a block. Negative error codes are propagated
// to the user. // to the user.
int (*read)(const struct lfs_config *c, lfs_block_t block, int (*read)(const struct lfs2_config *c, lfs2_block_t block,
lfs_off_t off, void *buffer, lfs_size_t size); lfs2_off_t off, void *buffer, lfs2_size_t size);
// 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 propagated to the user. // been erased. Negative error codes are propagated to the user.
// May return LFS_ERR_CORRUPT if the block should be considered bad. // May return LFS2_ERR_CORRUPT if the block should be considered bad.
int (*prog)(const struct lfs_config *c, lfs_block_t block, int (*prog)(const struct lfs2_config *c, lfs2_block_t block,
lfs_off_t off, const void *buffer, lfs_size_t size); lfs2_off_t off, const void *buffer, lfs2_size_t size);
// 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 propagated to the user. // are propagated to the user.
// May return LFS_ERR_CORRUPT if the block should be considered bad. // May return LFS2_ERR_CORRUPT if the block should be considered bad.
int (*erase)(const struct lfs_config *c, lfs_block_t block); int (*erase)(const struct lfs2_config *c, lfs2_block_t block);
// Sync the state of the underlying block device. Negative error codes // Sync the state of the underlying block device. Negative error codes
// are propagated to the user. // are propagated to the user.
int (*sync)(const struct lfs_config *c); int (*sync)(const struct lfs2_config *c);
#ifdef LFS_THREADSAFE #ifdef LFS2_THREADSAFE
// Lock the underlying block device. Negative error codes // Lock the underlying block device. Negative error codes
// are propagated to the user. // are propagated to the user.
int (*lock)(const struct lfs_config *c); int (*lock)(const struct lfs2_config *c);
// Unlock the underlying block device. Negative error codes // Unlock the underlying block device. Negative error codes
// are propagated to the user. // are propagated to the user.
int (*unlock)(const struct lfs_config *c); int (*unlock)(const struct lfs2_config *c);
#endif #endif
// Minimum size of a block read in bytes. All read operations will be a // Minimum size of a block read in bytes. All read operations will be a
// multiple of this value. // multiple of this value.
lfs_size_t read_size; lfs2_size_t read_size;
// Minimum size of a block program in bytes. All program operations will be // Minimum size of a block program in bytes. All program operations will be
// a multiple of this value. // a multiple of this value.
lfs_size_t prog_size; lfs2_size_t prog_size;
// Size of an erasable block in bytes. This does not impact ram consumption // Size of an erasable block in bytes. This does not impact ram consumption
// and may be larger than the physical erase size. However, non-inlined // and 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 and // files take up at minimum one block. Must be a multiple of the read and
// program sizes. // program sizes.
lfs_size_t block_size; lfs2_size_t block_size;
// Number of erasable blocks on the device. // Number of erasable blocks on the device.
lfs_size_t block_count; lfs2_size_t block_count;
// 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
@@ -221,68 +220,68 @@ struct lfs_config {
// cache per file. Larger caches can improve performance by storing more // cache per file. Larger caches can improve performance by storing more
// data and reducing the number of disk accesses. Must be a multiple of the // 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. // read and program sizes, and a factor of the block size.
lfs_size_t cache_size; lfs2_size_t cache_size;
// 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.
lfs_size_t lookahead_size; lfs2_size_t lookahead_size;
// 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 lfs2_malloc is used to allocate this buffer.
void *read_buffer; void *read_buffer;
// 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 lfs2_malloc is used to allocate this buffer.
void *prog_buffer; void *prog_buffer;
// 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 lfs2_malloc is used to
// allocate this buffer. // allocate this buffer.
void *lookahead_buffer; void *lookahead_buffer;
// 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 LFS2_NAME_MAX define. Defaults to LFS2_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; lfs2_size_t name_max;
// 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 <= LFS2_FILE_MAX. Defaults to LFS2_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; lfs2_size_t file_max;
// 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 <= LFS2_ATTR_MAX. Defaults to
// LFS_ATTR_MAX when zero. // LFS2_ATTR_MAX when zero.
lfs_size_t attr_max; lfs2_size_t attr_max;
// Optional upper limit on total space given to metadata pairs in bytes. On // Optional upper limit on total space given to metadata pairs in bytes. On
// devices with large blocks (e.g. 128kB) setting this to a low size (2-8kB) // devices with large blocks (e.g. 128kB) setting this to a low size (2-8kB)
// can help bound the metadata compaction time. Must be <= block_size. // can help bound the metadata compaction time. Must be <= block_size.
// Defaults to block_size when zero. // Defaults to block_size when zero.
lfs_size_t metadata_max; lfs2_size_t metadata_max;
}; };
// File info structure // File info structure
struct lfs_info { struct lfs2_info {
// Type of the file, either LFS_TYPE_REG or LFS_TYPE_DIR // Type of the file, either LFS2_TYPE_REG or LFS2_TYPE_DIR
uint8_t type; uint8_t type;
// Size of the file, only valid for REG files. Limited to 32-bits. // Size of the file, only valid for REG files. Limited to 32-bits.
lfs_size_t size; lfs2_size_t size;
// Name of the file stored as a null-terminated string. Limited to // Name of the file stored as a null-terminated string. Limited to
// LFS_NAME_MAX+1, which can be changed by redefining LFS_NAME_MAX to // LFS2_NAME_MAX+1, which can be changed by redefining LFS2_NAME_MAX to
// reduce RAM. LFS_NAME_MAX is stored in superblock and must be // reduce RAM. LFS2_NAME_MAX is stored in superblock and must be
// respected by other littlefs drivers. // respected by other littlefs drivers.
char name[LFS_NAME_MAX+1]; char name[LFS2_NAME_MAX+1];
}; };
// Custom attribute structure, used to describe custom attributes // Custom attribute structure, used to describe custom attributes
// committed atomically during file writes. // committed atomically during file writes.
struct lfs_attr { struct lfs2_attr {
// 8-bit type of attribute, provided by user and used to // 8-bit type of attribute, provided by user and used to
// identify the attribute // identify the attribute
uint8_t type; uint8_t type;
@@ -290,14 +289,14 @@ struct lfs_attr {
// Pointer to buffer containing the attribute // Pointer to buffer containing the attribute
void *buffer; void *buffer;
// Size of attribute in bytes, limited to LFS_ATTR_MAX // Size of attribute in bytes, limited to LFS2_ATTR_MAX
lfs_size_t size; lfs2_size_t size;
}; };
// Optional configuration provided during lfs_file_opencfg // Optional configuration provided during lfs2_file_opencfg
struct lfs_file_config { struct lfs2_file_config {
// Optional statically allocated file buffer. Must be cache_size. // Optional statically allocated file buffer. Must be cache_size.
// By default lfs_malloc is used to allocate this buffer. // By default lfs2_malloc is used to allocate this buffer.
void *buffer; void *buffer;
// Optional list of custom attributes related to the file. If the file // Optional list of custom attributes related to the file. If the file
@@ -307,122 +306,122 @@ struct lfs_file_config {
// write occurs atomically with update to the file's contents. // write occurs atomically with update to the file's contents.
// //
// Custom attributes are uniquely identified by an 8-bit type and limited // 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 // to LFS2_ATTR_MAX bytes. When read, if the stored attribute is smaller
// than the buffer, it will be padded with zeros. If the stored attribute // 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 // is larger, then it will be silently truncated. If the attribute is not
// found, it will be created implicitly. // found, it will be created implicitly.
struct lfs_attr *attrs; struct lfs2_attr *attrs;
// Number of custom attributes in the list // Number of custom attributes in the list
lfs_size_t attr_count; lfs2_size_t attr_count;
}; };
/// internal littlefs data structures /// /// internal littlefs data structures ///
typedef struct lfs_cache { typedef struct lfs2_cache {
lfs_block_t block; lfs2_block_t block;
lfs_off_t off; lfs2_off_t off;
lfs_size_t size; lfs2_size_t size;
uint8_t *buffer; uint8_t *buffer;
} lfs_cache_t; } lfs2_cache_t;
typedef struct lfs_mdir { typedef struct lfs2_mdir {
lfs_block_t pair[2]; lfs2_block_t pair[2];
uint32_t rev; uint32_t rev;
lfs_off_t off; lfs2_off_t off;
uint32_t etag; uint32_t etag;
uint16_t count; uint16_t count;
bool erased; bool erased;
bool split; bool split;
lfs_block_t tail[2]; lfs2_block_t tail[2];
} lfs_mdir_t; } lfs2_mdir_t;
// littlefs directory type // littlefs directory type
typedef struct lfs_dir { typedef struct lfs2_dir {
struct lfs_dir *next; struct lfs2_dir *next;
uint16_t id; uint16_t id;
uint8_t type; uint8_t type;
lfs_mdir_t m; lfs2_mdir_t m;
lfs_off_t pos; lfs2_off_t pos;
lfs_block_t head[2]; lfs2_block_t head[2];
} lfs_dir_t; } lfs2_dir_t;
// littlefs file type // littlefs file type
typedef struct lfs_file { typedef struct lfs2_file {
struct lfs_file *next; struct lfs2_file *next;
uint16_t id; uint16_t id;
uint8_t type; uint8_t type;
lfs_mdir_t m; lfs2_mdir_t m;
struct lfs_ctz { struct lfs2_ctz {
lfs_block_t head; lfs2_block_t head;
lfs_size_t size; lfs2_size_t size;
} ctz; } ctz;
uint32_t flags; uint32_t flags;
lfs_off_t pos; lfs2_off_t pos;
lfs_block_t block; lfs2_block_t block;
lfs_off_t off; lfs2_off_t off;
lfs_cache_t cache; lfs2_cache_t cache;
const struct lfs_file_config *cfg; const struct lfs2_file_config *cfg;
} lfs_file_t; } lfs2_file_t;
typedef struct lfs_superblock { typedef struct lfs2_superblock {
uint32_t version; uint32_t version;
lfs_size_t block_size; lfs2_size_t block_size;
lfs_size_t block_count; lfs2_size_t block_count;
lfs_size_t name_max; lfs2_size_t name_max;
lfs_size_t file_max; lfs2_size_t file_max;
lfs_size_t attr_max; lfs2_size_t attr_max;
} lfs_superblock_t; } lfs2_superblock_t;
typedef struct lfs_gstate { typedef struct lfs2_gstate {
uint32_t tag; uint32_t tag;
lfs_block_t pair[2]; lfs2_block_t pair[2];
} lfs_gstate_t; } lfs2_gstate_t;
// The littlefs filesystem type // The littlefs filesystem type
typedef struct lfs { typedef struct lfs2 {
lfs_cache_t rcache; lfs2_cache_t rcache;
lfs_cache_t pcache; lfs2_cache_t pcache;
lfs_block_t root[2]; lfs2_block_t root[2];
struct lfs_mlist { struct lfs2_mlist {
struct lfs_mlist *next; struct lfs2_mlist *next;
uint16_t id; uint16_t id;
uint8_t type; uint8_t type;
lfs_mdir_t m; lfs2_mdir_t m;
} *mlist; } *mlist;
uint32_t seed; uint32_t seed;
lfs_gstate_t gstate; lfs2_gstate_t gstate;
lfs_gstate_t gdisk; lfs2_gstate_t gdisk;
lfs_gstate_t gdelta; lfs2_gstate_t gdelta;
struct lfs_free { struct lfs2_free {
lfs_block_t off; lfs2_block_t off;
lfs_block_t size; lfs2_block_t size;
lfs_block_t i; lfs2_block_t i;
lfs_block_t ack; lfs2_block_t ack;
uint32_t *buffer; uint32_t *buffer;
} free; } free;
const struct lfs_config *cfg; const struct lfs2_config *cfg;
lfs_size_t name_max; lfs2_size_t name_max;
lfs_size_t file_max; lfs2_size_t file_max;
lfs_size_t attr_max; lfs2_size_t attr_max;
#ifdef LFS_MIGRATE #ifdef LFS2_MIGRATE
struct lfs1 *lfs1; struct lfs21 *lfs21;
#endif #endif
} lfs_t; } lfs2_t;
/// Filesystem functions /// /// Filesystem functions ///
#ifndef LFS_READONLY #ifndef LFS2_READONLY
// Format a block device with the littlefs // Format a block device with the littlefs
// //
// Requires a littlefs object and config struct. This clobbers the littlefs // Requires a littlefs object and config struct. This clobbers the littlefs
@@ -430,117 +429,112 @@ typedef struct lfs {
// 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 lfs2_format(lfs2_t *lfs2, const struct lfs2_config *config);
#endif #endif
// Mounts a littlefs // Mounts a littlefs
// //
// 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
// lfs and config must be allocated while mounted. The config struct must // lfs2 and config must be allocated while 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_mount(lfs_t *lfs, const struct lfs_config *config); int lfs2_mount(lfs2_t *lfs2, const struct lfs2_config *config);
// Unmounts a littlefs // Unmounts a littlefs
// //
// Does nothing besides releasing any allocated resources. // Does nothing besides releasing any allocated resources.
// Returns a negative error code on failure. // Returns a negative error code on failure.
int lfs_unmount(lfs_t *lfs); int lfs2_unmount(lfs2_t *lfs2);
/// General operations /// /// General operations ///
#ifndef LFS_READONLY #ifndef LFS2_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 lfs2_remove(lfs2_t *lfs2, const char *path);
#endif #endif
#ifndef LFS_READONLY #ifndef LFS2_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.
// If the destination is a directory, the directory must be empty. // If the destination is a directory, the directory must be empty.
// //
// 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 lfs2_rename(lfs2_t *lfs2, const char *oldpath, const char *newpath);
#endif #endif
// Find info about a file or directory // Find info about a file or directory
// //
// Fills out the info structure, based on the specified file or directory. // Fills out the info structure, based on the specified file or directory.
// Returns a negative error code on failure. // Returns a negative error code on failure.
int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info); int lfs2_stat(lfs2_t *lfs2, const char *path, struct lfs2_info *info);
// Get a custom attribute // Get a custom attribute
// //
// Custom attributes are uniquely identified by an 8-bit type and limited // 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 // to LFS2_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, // the buffer, it will be padded with zeros. If the stored attribute is larger,
// then it will be silently truncated. If no attribute is found, the error // then it will be silently truncated. If no attribute is found, the error
// LFS_ERR_NOATTR is returned and the buffer is filled with zeros. // LFS2_ERR_NOATTR is returned and the buffer is filled with zeros.
// //
// Returns the size of the attribute, or a negative error code on failure. // Returns the size of the attribute, or a negative error code on failure.
// Note, the returned size is the size of the attribute on disk, irrespective // Note, the returned size is the size of the attribute on disk, irrespective
// of the size of the buffer. This can be used to dynamically allocate a buffer // of the size of the buffer. This can be used to dynamically allocate a buffer
// or check for existence. // or check for existence.
lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path, lfs2_ssize_t lfs2_getattr(lfs2_t *lfs2, const char *path,
uint8_t type, void *buffer, lfs_size_t size); uint8_t type, void *buffer, lfs2_size_t size);
#ifndef LFS_READONLY #ifndef LFS2_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
// to LFS_ATTR_MAX bytes. If an attribute is not found, it will be // to LFS2_ATTR_MAX bytes. If an attribute is not found, it will be
// implicitly created. // implicitly created.
// //
// Returns a negative error code on failure. // Returns a negative error code on failure.
int lfs_setattr(lfs_t *lfs, const char *path, int lfs2_setattr(lfs2_t *lfs2, const char *path,
uint8_t type, const void *buffer, lfs_size_t size); uint8_t type, const void *buffer, lfs2_size_t size);
#endif #endif
#ifndef LFS_READONLY #ifndef LFS2_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 lfs2_removeattr(lfs2_t *lfs2, const char *path, uint8_t type);
#endif #endif
/// File operations /// /// File operations ///
#ifndef LFS_NO_MALLOC
// Open a file // Open a file
// //
// 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 lfs2_open_flags that are bitwise-ored together.
// //
// Returns a negative error code on failure. // Returns a negative error code on failure.
int lfs_file_open(lfs_t *lfs, lfs_file_t *file, int lfs2_file_open(lfs2_t *lfs2, lfs2_file_t *file,
const char *path, int flags); const char *path, int flags);
// if LFS_NO_MALLOC is defined, lfs_file_open() will fail with LFS_ERR_NOMEM
// thus use lfs_file_opencfg() with config.buffer set.
#endif
// Open a file with extra configuration // Open a file with extra 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 lfs2_open_flags that are bitwise-ored together.
// //
// The config struct provides additional config options per file as described // The config struct provides additional config options per file as described
// above. The config struct must be allocated while the file is open, and the // above. The config struct must be allocated while the file is open, and the
// config struct must be zeroed for defaults and backwards compatibility. // config struct must be zeroed for defaults and backwards compatibility.
// //
// 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 lfs2_file_opencfg(lfs2_t *lfs2, lfs2_file_t *file,
const char *path, int flags, const char *path, int flags,
const struct lfs_file_config *config); const struct lfs2_file_config *config);
// Close a file // Close a file
// //
@@ -548,92 +542,92 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file,
// sync had been called and releases any allocated resources. // sync had been called and releases any allocated resources.
// //
// Returns a negative error code on failure. // Returns a negative error code on failure.
int lfs_file_close(lfs_t *lfs, lfs_file_t *file); int lfs2_file_close(lfs2_t *lfs2, lfs2_file_t *file);
// Synchronize a file on storage // Synchronize a file on storage
// //
// Any pending writes are written out to storage. // Any pending writes are written out to storage.
// Returns a negative error code on failure. // Returns a negative error code on failure.
int lfs_file_sync(lfs_t *lfs, lfs_file_t *file); int lfs2_file_sync(lfs2_t *lfs2, lfs2_file_t *file);
// Read data from file // Read data from file
// //
// Takes a buffer and size indicating where to store the read data. // Takes a buffer and size indicating where to store the read data.
// Returns the number of bytes read, or a negative error code on failure. // Returns the number of bytes read, or a negative error code on failure.
lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, lfs2_ssize_t lfs2_file_read(lfs2_t *lfs2, lfs2_file_t *file,
void *buffer, lfs_size_t size); void *buffer, lfs2_size_t size);
#ifndef LFS_READONLY #ifndef LFS2_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
// actually be updated on the storage until either sync or close is called. // actually be updated on the storage until either sync or close is called.
// //
// 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, lfs2_ssize_t lfs2_file_write(lfs2_t *lfs2, lfs2_file_t *file,
const void *buffer, lfs_size_t size); const void *buffer, lfs2_size_t size);
#endif #endif
// Change the position of the file // Change the position of the file
// //
// The change in position is determined by the offset and whence flag. // The change in position is determined by the offset and whence flag.
// Returns the new position of the file, or a negative error code on failure. // Returns the new position of the file, or a negative error code on failure.
lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file, lfs2_soff_t lfs2_file_seek(lfs2_t *lfs2, lfs2_file_t *file,
lfs_soff_t off, int whence); lfs2_soff_t off, int whence);
#ifndef LFS_READONLY #ifndef LFS2_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 lfs2_file_truncate(lfs2_t *lfs2, lfs2_file_t *file, lfs2_off_t size);
#endif #endif
// Return the position of the file // Return the position of the file
// //
// Equivalent to lfs_file_seek(lfs, file, 0, LFS_SEEK_CUR) // Equivalent to lfs2_file_seek(lfs2, file, 0, LFS2_SEEK_CUR)
// Returns the position of the file, or a negative error code on failure. // Returns the position of the file, or a negative error code on failure.
lfs_soff_t lfs_file_tell(lfs_t *lfs, lfs_file_t *file); lfs2_soff_t lfs2_file_tell(lfs2_t *lfs2, lfs2_file_t *file);
// Change the position of the file to the beginning of the file // Change the position of the file to the beginning of the file
// //
// Equivalent to lfs_file_seek(lfs, file, 0, LFS_SEEK_SET) // Equivalent to lfs2_file_seek(lfs2, file, 0, LFS2_SEEK_SET)
// Returns a negative error code on failure. // Returns a negative error code on failure.
int lfs_file_rewind(lfs_t *lfs, lfs_file_t *file); int lfs2_file_rewind(lfs2_t *lfs2, lfs2_file_t *file);
// Return the size of the file // Return the size of the file
// //
// Similar to lfs_file_seek(lfs, file, 0, LFS_SEEK_END) // Similar to lfs2_file_seek(lfs2, file, 0, LFS2_SEEK_END)
// Returns the size of the file, or a negative error code on failure. // Returns the size of the file, or a negative error code on failure.
lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file); lfs2_soff_t lfs2_file_size(lfs2_t *lfs2, lfs2_file_t *file);
/// Directory operations /// /// Directory operations ///
#ifndef LFS_READONLY #ifndef LFS2_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 lfs2_mkdir(lfs2_t *lfs2, const char *path);
#endif #endif
// Open a directory // Open a directory
// //
// Once open a directory can be used with read to iterate over files. // Once open a directory can be used with read to iterate over files.
// Returns a negative error code on failure. // Returns a negative error code on failure.
int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path); int lfs2_dir_open(lfs2_t *lfs2, lfs2_dir_t *dir, const char *path);
// Close a directory // Close a directory
// //
// Releases any allocated resources. // Releases any allocated resources.
// Returns a negative error code on failure. // Returns a negative error code on failure.
int lfs_dir_close(lfs_t *lfs, lfs_dir_t *dir); int lfs2_dir_close(lfs2_t *lfs2, lfs2_dir_t *dir);
// Read an entry in the directory // Read an entry in the directory
// //
// Fills out the info structure, based on the specified file or directory. // Fills out the info structure, based on the specified file or directory.
// Returns a positive value on success, 0 at the end of directory, // Returns a positive value on success, 0 at the end of directory,
// or a negative error code on failure. // or a negative error code on failure.
int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info); int lfs2_dir_read(lfs2_t *lfs2, lfs2_dir_t *dir, struct lfs2_info *info);
// Change the position of the directory // Change the position of the directory
// //
@@ -641,7 +635,7 @@ int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info);
// an absolute offset in the directory seek. // an absolute offset in the directory seek.
// //
// Returns a negative error code on failure. // Returns a negative error code on failure.
int lfs_dir_seek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off); int lfs2_dir_seek(lfs2_t *lfs2, lfs2_dir_t *dir, lfs2_off_t off);
// Return the position of the directory // Return the position of the directory
// //
@@ -649,12 +643,12 @@ int lfs_dir_seek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off);
// sense, but does indicate the current position in the directory iteration. // sense, but does indicate the current position in the directory iteration.
// //
// Returns the position of the directory, or a negative error code on failure. // Returns the position of the directory, or a negative error code on failure.
lfs_soff_t lfs_dir_tell(lfs_t *lfs, lfs_dir_t *dir); lfs2_soff_t lfs2_dir_tell(lfs2_t *lfs2, lfs2_dir_t *dir);
// Change the position of the directory to the beginning of the directory // Change the position of the directory to the beginning of the directory
// //
// Returns a negative error code on failure. // Returns a negative error code on failure.
int lfs_dir_rewind(lfs_t *lfs, lfs_dir_t *dir); int lfs2_dir_rewind(lfs2_t *lfs2, lfs2_dir_t *dir);
/// Filesystem-level filesystem operations /// Filesystem-level filesystem operations
@@ -665,7 +659,7 @@ int lfs_dir_rewind(lfs_t *lfs, lfs_dir_t *dir);
// size may be larger than the filesystem actually is. // size may be larger than the filesystem actually is.
// //
// Returns the number of allocated blocks, or a negative error code on failure. // Returns the number of allocated blocks, or a negative error code on failure.
lfs_ssize_t lfs_fs_size(lfs_t *lfs); lfs2_ssize_t lfs2_fs_size(lfs2_t *lfs2);
// Traverse through all blocks in use by the filesystem // Traverse through all blocks in use by the filesystem
// //
@@ -674,13 +668,13 @@ lfs_ssize_t lfs_fs_size(lfs_t *lfs);
// blocks are in use or how much of the storage is available. // blocks are in use or how much of the storage is available.
// //
// 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 lfs2_fs_traverse(lfs2_t *lfs2, int (*cb)(void*, lfs2_block_t), void *data);
#ifndef LFS_READONLY #ifndef LFS2_READONLY
#ifdef LFS_MIGRATE #ifdef LFS2_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 lfs2_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.
// //
@@ -689,7 +683,7 @@ int lfs_fs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data);
// 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 lfs2_migrate(lfs2_t *lfs2, const struct lfs2_config *cfg);
#endif #endif
#endif #endif

View File

@@ -1,18 +1,17 @@
/* /*
* lfs util functions * lfs2 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 "lfs2_util.h"
// Only compile if user does not provide custom config // Only compile if user does not provide custom config
#ifndef LFS_CONFIG #ifndef LFS2_CONFIG
// Software CRC implementation with small lookup table // Software CRC implementation with small lookup table
uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size) { uint32_t lfs2_crc(uint32_t crc, const void *buffer, size_t size) {
static const uint32_t rtable[16] = { static const uint32_t rtable[16] = {
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,

View File

@@ -1,23 +1,22 @@
/* /*
* lfs utility functions * lfs2 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
*/ */
#ifndef LFS_UTIL_H #ifndef LFS2_UTIL_H
#define LFS_UTIL_H #define LFS2_UTIL_H
// Users can override lfs_util.h with their own configuration by defining // Users can override lfs2_util.h with their own configuration by defining
// LFS_CONFIG as a header file to include (-DLFS_CONFIG=lfs_config.h). // LFS2_CONFIG as a header file to include (-DLFS2_CONFIG=lfs2_config.h).
// //
// If LFS_CONFIG is used, none of the default utils will be emitted and must be // If LFS2_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 // provided by the config file. To start, I would suggest copying lfs2_util.h
// and modifying as needed. // and modifying as needed.
#ifdef LFS_CONFIG #ifdef LFS2_CONFIG
#define LFS_STRINGIZE(x) LFS_STRINGIZE2(x) #define LFS2_STRINGIZE(x) LFS2_STRINGIZE2(x)
#define LFS_STRINGIZE2(x) #x #define LFS2_STRINGIZE2(x) #x
#include LFS_STRINGIZE(LFS_CONFIG) #include LFS2_STRINGIZE(LFS2_CONFIG)
#else #else
// System includes // System includes
@@ -26,16 +25,16 @@
#include <string.h> #include <string.h>
#include <inttypes.h> #include <inttypes.h>
#ifndef LFS_NO_MALLOC #ifndef LFS2_NO_MALLOC
#include <stdlib.h> #include <stdlib.h>
#endif #endif
#ifndef LFS_NO_ASSERT #ifndef LFS2_NO_ASSERT
#include <assert.h> #include <assert.h>
#endif #endif
#if !defined(LFS_NO_DEBUG) || \ #if !defined(LFS2_NO_DEBUG) || \
!defined(LFS_NO_WARN) || \ !defined(LFS2_NO_WARN) || \
!defined(LFS_NO_ERROR) || \ !defined(LFS2_NO_ERROR) || \
defined(LFS_YES_TRACE) defined(LFS2_YES_TRACE)
#include <stdio.h> #include <stdio.h>
#endif #endif
@@ -50,81 +49,81 @@ extern "C"
// code footprint // code footprint
// Logging functions // Logging functions
#ifndef LFS_TRACE #ifndef LFS2_TRACE
#ifdef LFS_YES_TRACE #ifdef LFS2_YES_TRACE
#define LFS_TRACE_(fmt, ...) \ #define LFS2_TRACE_(fmt, ...) \
printf("%s:%d:trace: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) printf("%s:%d:trace: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
#define LFS_TRACE(...) LFS_TRACE_(__VA_ARGS__, "") #define LFS2_TRACE(...) LFS2_TRACE_(__VA_ARGS__, "")
#else #else
#define LFS_TRACE(...) #define LFS2_TRACE(...)
#endif #endif
#endif #endif
#ifndef LFS_DEBUG #ifndef LFS2_DEBUG
#ifndef LFS_NO_DEBUG #ifndef LFS2_NO_DEBUG
#define LFS_DEBUG_(fmt, ...) \ #define LFS2_DEBUG_(fmt, ...) \
printf("%s:%d:debug: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) printf("%s:%d:debug: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
#define LFS_DEBUG(...) LFS_DEBUG_(__VA_ARGS__, "") #define LFS2_DEBUG(...) LFS2_DEBUG_(__VA_ARGS__, "")
#else #else
#define LFS_DEBUG(...) #define LFS2_DEBUG(...)
#endif #endif
#endif #endif
#ifndef LFS_WARN #ifndef LFS2_WARN
#ifndef LFS_NO_WARN #ifndef LFS2_NO_WARN
#define LFS_WARN_(fmt, ...) \ #define LFS2_WARN_(fmt, ...) \
printf("%s:%d:warn: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) printf("%s:%d:warn: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
#define LFS_WARN(...) LFS_WARN_(__VA_ARGS__, "") #define LFS2_WARN(...) LFS2_WARN_(__VA_ARGS__, "")
#else #else
#define LFS_WARN(...) #define LFS2_WARN(...)
#endif #endif
#endif #endif
#ifndef LFS_ERROR #ifndef LFS2_ERROR
#ifndef LFS_NO_ERROR #ifndef LFS2_NO_ERROR
#define LFS_ERROR_(fmt, ...) \ #define LFS2_ERROR_(fmt, ...) \
printf("%s:%d:error: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) printf("%s:%d:error: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
#define LFS_ERROR(...) LFS_ERROR_(__VA_ARGS__, "") #define LFS2_ERROR(...) LFS2_ERROR_(__VA_ARGS__, "")
#else #else
#define LFS_ERROR(...) #define LFS2_ERROR(...)
#endif #endif
#endif #endif
// Runtime assertions // Runtime assertions
#ifndef LFS_ASSERT #ifndef LFS2_ASSERT
#ifndef LFS_NO_ASSERT #ifndef LFS2_NO_ASSERT
#define LFS_ASSERT(test) assert(test) #define LFS2_ASSERT(test) assert(test)
#else #else
#define LFS_ASSERT(test) #define LFS2_ASSERT(test)
#endif #endif
#endif #endif
// Builtin functions, these may be replaced by more efficient // Builtin functions, these may be replaced by more efficient
// toolchain-specific implementations. LFS_NO_INTRINSICS falls back to a more // toolchain-specific implementations. LFS2_NO_INTRINSICS falls back to a more
// expensive basic C implementation for debugging purposes // expensive basic C implementation for debugging purposes
// Min/max functions for unsigned 32-bit numbers // Min/max functions for unsigned 32-bit numbers
static inline uint32_t lfs_max(uint32_t a, uint32_t b) { static inline uint32_t lfs2_max(uint32_t a, uint32_t b) {
return (a > b) ? a : b; return (a > b) ? a : b;
} }
static inline uint32_t lfs_min(uint32_t a, uint32_t b) { static inline uint32_t lfs2_min(uint32_t a, uint32_t b) {
return (a < b) ? a : b; return (a < b) ? a : b;
} }
// Align to nearest multiple of a size // Align to nearest multiple of a size
static inline uint32_t lfs_aligndown(uint32_t a, uint32_t alignment) { static inline uint32_t lfs2_aligndown(uint32_t a, uint32_t alignment) {
return a - (a % alignment); return a - (a % alignment);
} }
static inline uint32_t lfs_alignup(uint32_t a, uint32_t alignment) { static inline uint32_t lfs2_alignup(uint32_t a, uint32_t alignment) {
return lfs_aligndown(a + alignment-1, alignment); return lfs2_aligndown(a + alignment-1, alignment);
} }
// Find the smallest power of 2 greater than or equal to a // Find the smallest power of 2 greater than or equal to a
static inline uint32_t lfs_npw2(uint32_t a) { static inline uint32_t lfs2_npw2(uint32_t a) {
#if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM)) #if !defined(LFS2_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM))
return 32 - __builtin_clz(a-1); return 32 - __builtin_clz(a-1);
#else #else
uint32_t r = 0; uint32_t r = 0;
@@ -139,18 +138,18 @@ static inline uint32_t lfs_npw2(uint32_t a) {
} }
// Count the number of trailing binary zeros in a // Count the number of trailing binary zeros in a
// lfs_ctz(0) may be undefined // lfs2_ctz(0) may be undefined
static inline uint32_t lfs_ctz(uint32_t a) { static inline uint32_t lfs2_ctz(uint32_t a) {
#if !defined(LFS_NO_INTRINSICS) && defined(__GNUC__) #if !defined(LFS2_NO_INTRINSICS) && defined(__GNUC__)
return __builtin_ctz(a); return __builtin_ctz(a);
#else #else
return lfs_npw2((a & -a) + 1) - 1; return lfs2_npw2((a & -a) + 1) - 1;
#endif #endif
} }
// Count the number of binary ones in a // Count the number of binary ones in a
static inline uint32_t lfs_popc(uint32_t a) { static inline uint32_t lfs2_popc(uint32_t a) {
#if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM)) #if !defined(LFS2_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM))
return __builtin_popcount(a); return __builtin_popcount(a);
#else #else
a = a - ((a >> 1) & 0x55555555); a = a - ((a >> 1) & 0x55555555);
@@ -161,18 +160,18 @@ 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 int lfs2_scmp(uint32_t a, uint32_t b) {
return (int)(unsigned)(a - b); return (int)(unsigned)(a - b);
} }
// Convert between 32-bit little-endian and native order // Convert between 32-bit little-endian and native order
static inline uint32_t lfs_fromle32(uint32_t a) { static inline uint32_t lfs2_fromle32(uint32_t a) {
#if !defined(LFS_NO_INTRINSICS) && ( \ #if !defined(LFS2_NO_INTRINSICS) && ( \
(defined( BYTE_ORDER ) && defined( ORDER_LITTLE_ENDIAN ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \ (defined( BYTE_ORDER ) && defined( ORDER_LITTLE_ENDIAN ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \
(defined(__BYTE_ORDER ) && defined(__ORDER_LITTLE_ENDIAN ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \ (defined(__BYTE_ORDER ) && defined(__ORDER_LITTLE_ENDIAN ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \
(defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
return a; return a;
#elif !defined(LFS_NO_INTRINSICS) && ( \ #elif !defined(LFS2_NO_INTRINSICS) && ( \
(defined( BYTE_ORDER ) && defined( ORDER_BIG_ENDIAN ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \ (defined( BYTE_ORDER ) && defined( ORDER_BIG_ENDIAN ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \
(defined(__BYTE_ORDER ) && defined(__ORDER_BIG_ENDIAN ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \ (defined(__BYTE_ORDER ) && defined(__ORDER_BIG_ENDIAN ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \
(defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
@@ -185,18 +184,18 @@ static inline uint32_t lfs_fromle32(uint32_t a) {
#endif #endif
} }
static inline uint32_t lfs_tole32(uint32_t a) { static inline uint32_t lfs2_tole32(uint32_t a) {
return lfs_fromle32(a); return lfs2_fromle32(a);
} }
// Convert between 32-bit big-endian and native order // Convert between 32-bit big-endian and native order
static inline uint32_t lfs_frombe32(uint32_t a) { static inline uint32_t lfs2_frombe32(uint32_t a) {
#if !defined(LFS_NO_INTRINSICS) && ( \ #if !defined(LFS2_NO_INTRINSICS) && ( \
(defined( BYTE_ORDER ) && defined( ORDER_LITTLE_ENDIAN ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \ (defined( BYTE_ORDER ) && defined( ORDER_LITTLE_ENDIAN ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \
(defined(__BYTE_ORDER ) && defined(__ORDER_LITTLE_ENDIAN ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \ (defined(__BYTE_ORDER ) && defined(__ORDER_LITTLE_ENDIAN ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \
(defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
return __builtin_bswap32(a); return __builtin_bswap32(a);
#elif !defined(LFS_NO_INTRINSICS) && ( \ #elif !defined(LFS2_NO_INTRINSICS) && ( \
(defined( BYTE_ORDER ) && defined( ORDER_BIG_ENDIAN ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \ (defined( BYTE_ORDER ) && defined( ORDER_BIG_ENDIAN ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \
(defined(__BYTE_ORDER ) && defined(__ORDER_BIG_ENDIAN ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \ (defined(__BYTE_ORDER ) && defined(__ORDER_BIG_ENDIAN ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \
(defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
@@ -209,17 +208,17 @@ static inline uint32_t lfs_frombe32(uint32_t a) {
#endif #endif
} }
static inline uint32_t lfs_tobe32(uint32_t a) { static inline uint32_t lfs2_tobe32(uint32_t a) {
return lfs_frombe32(a); return lfs2_frombe32(a);
} }
// Calculate CRC-32 with polynomial = 0x04c11db7 // Calculate CRC-32 with polynomial = 0x04c11db7
uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size); uint32_t lfs2_crc(uint32_t crc, const void *buffer, size_t size);
// Allocate memory, only used if buffers are not provided to littlefs // Allocate memory, only used if buffers are not provided to littlefs
// Note, memory must be 64-bit aligned // Note, memory must be 64-bit aligned
static inline void *lfs_malloc(size_t size) { static inline void *lfs2_malloc(size_t size) {
#ifndef LFS_NO_MALLOC #ifndef LFS2_NO_MALLOC
return malloc(size); return malloc(size);
#else #else
(void)size; (void)size;
@@ -228,8 +227,8 @@ static inline void *lfs_malloc(size_t size) {
} }
// Deallocate memory, only used if buffers are not provided to littlefs // Deallocate memory, only used if buffers are not provided to littlefs
static inline void lfs_free(void *p) { static inline void lfs2_free(void *p) {
#ifndef LFS_NO_MALLOC #ifndef LFS2_NO_MALLOC
free(p); free(p);
#else #else
(void)p; (void)p;

View File

@@ -15,7 +15,7 @@ import csv
import collections as co import collections as co
OBJ_PATHS = ['*.o'] OBJ_PATHS = ['*.o', 'bd/*.o']
def collect(paths, **args): def collect(paths, **args):
results = co.defaultdict(lambda: 0) results = co.defaultdict(lambda: 0)
@@ -31,8 +31,7 @@ def collect(paths, **args):
proc = sp.Popen(cmd, proc = sp.Popen(cmd,
stdout=sp.PIPE, stdout=sp.PIPE,
stderr=sp.PIPE if not args.get('verbose') else None, stderr=sp.PIPE if not args.get('verbose') else None,
universal_newlines=True, universal_newlines=True)
errors='replace')
for line in proc.stdout: for line in proc.stdout:
m = pattern.match(line) m = pattern.match(line)
if m: if m:
@@ -49,30 +48,16 @@ def collect(paths, **args):
# map to source files # map to source files
if args.get('build_dir'): if args.get('build_dir'):
file = re.sub('%s/*' % re.escape(args['build_dir']), '', file) file = re.sub('%s/*' % re.escape(args['build_dir']), '', file)
# replace .o with .c, different scripts report .o/.c, we need to
# choose one if we want to deduplicate csv files
file = re.sub('\.o$', '.c', file)
# discard internal functions # discard internal functions
if not args.get('everything'): if func.startswith('__'):
if func.startswith('__'): continue
continue
# discard .8449 suffixes created by optimizer # discard .8449 suffixes created by optimizer
func = re.sub('\.[0-9]+', '', func) func = re.sub('\.[0-9]+', '', func)
flat_results.append((file, func, size)) flat_results.append((file, func, size))
return flat_results return flat_results
def main(**args): def main(**args):
def openio(path, mode='r'):
if path == '-':
if 'r' in mode:
return os.fdopen(os.dup(sys.stdin.fileno()), 'r')
else:
return os.fdopen(os.dup(sys.stdout.fileno()), 'w')
else:
return open(path, mode)
# find sizes # find sizes
if not args.get('use', None): if not args.get('use', None):
# find .o files # find .o files
@@ -90,14 +75,13 @@ def main(**args):
results = collect(paths, **args) results = collect(paths, **args)
else: else:
with openio(args['use']) as f: with open(args['use']) as f:
r = csv.DictReader(f) r = csv.DictReader(f)
results = [ results = [
( result['file'], ( result['file'],
result['name'], result['function'],
int(result['code_size'])) int(result['size']))
for result in r for result in r]
if result.get('code_size') not in {None, ''}]
total = 0 total = 0
for _, _, size in results: for _, _, size in results:
@@ -105,17 +89,13 @@ def main(**args):
# find previous results? # find previous results?
if args.get('diff'): if args.get('diff'):
try: with open(args['diff']) as f:
with openio(args['diff']) as f: r = csv.DictReader(f)
r = csv.DictReader(f) prev_results = [
prev_results = [ ( result['file'],
( result['file'], result['function'],
result['name'], int(result['size']))
int(result['code_size'])) for result in r]
for result in r
if result.get('code_size') not in {None, ''}]
except FileNotFoundError:
prev_results = []
prev_total = 0 prev_total = 0
for _, _, size in prev_results: for _, _, size in prev_results:
@@ -123,34 +103,14 @@ def main(**args):
# write results to CSV # write results to CSV
if args.get('output'): if args.get('output'):
merged_results = co.defaultdict(lambda: {}) with open(args['output'], 'w') as f:
other_fields = [] w = csv.writer(f)
w.writerow(['file', 'function', 'size'])
# merge? for file, func, size in sorted(results):
if args.get('merge'): w.writerow((file, func, size))
try:
with openio(args['merge']) as f:
r = csv.DictReader(f)
for result in r:
file = result.pop('file', '')
func = result.pop('name', '')
result.pop('code_size', None)
merged_results[(file, func)] = result
other_fields = result.keys()
except FileNotFoundError:
pass
for file, func, size in results:
merged_results[(file, func)]['code_size'] = size
with openio(args['output'], 'w') as f:
w = csv.DictWriter(f, ['file', 'name', *other_fields, 'code_size'])
w.writeheader()
for (file, func), result in sorted(merged_results.items()):
w.writerow({'file': file, 'name': func, **result})
# print results # print results
def dedup_entries(results, by='name'): def dedup_entries(results, by='function'):
entries = co.defaultdict(lambda: 0) entries = co.defaultdict(lambda: 0)
for file, func, size in results: for file, func, size in results:
entry = (file if by == 'file' else func) entry = (file if by == 'file' else func)
@@ -166,67 +126,45 @@ def main(**args):
diff[name] = (old, new, new-old, (new-old)/old if old else 1.0) diff[name] = (old, new, new-old, (new-old)/old if old else 1.0)
return diff return diff
def sorted_entries(entries):
if args.get('size_sort'):
return sorted(entries, key=lambda x: (-x[1], x))
elif args.get('reverse_size_sort'):
return sorted(entries, key=lambda x: (+x[1], x))
else:
return sorted(entries)
def sorted_diff_entries(entries):
if args.get('size_sort'):
return sorted(entries, key=lambda x: (-x[1][1], x))
elif args.get('reverse_size_sort'):
return sorted(entries, key=lambda x: (+x[1][1], x))
else:
return sorted(entries, key=lambda x: (-x[1][3], x))
def print_header(by=''): def print_header(by=''):
if not args.get('diff'): if not args.get('diff'):
print('%-36s %7s' % (by, 'size')) print('%-36s %7s' % (by, 'size'))
else: else:
print('%-36s %7s %7s %7s' % (by, 'old', 'new', 'diff')) print('%-36s %7s %7s %7s' % (by, 'old', 'new', 'diff'))
def print_entry(name, size): def print_entries(by='function'):
print("%-36s %7d" % (name, size))
def print_diff_entry(name, old, new, diff, ratio):
print("%-36s %7s %7s %+7d%s" % (name,
old or "-",
new or "-",
diff,
' (%+.1f%%)' % (100*ratio) if ratio else ''))
def print_entries(by='name'):
entries = dedup_entries(results, by=by) entries = dedup_entries(results, by=by)
if not args.get('diff'): if not args.get('diff'):
print_header(by=by) print_header(by=by)
for name, size in sorted_entries(entries.items()): for name, size in sorted(entries.items()):
print_entry(name, size) print("%-36s %7d" % (name, size))
else: else:
prev_entries = dedup_entries(prev_results, by=by) prev_entries = dedup_entries(prev_results, by=by)
diff = diff_entries(prev_entries, entries) diff = diff_entries(prev_entries, entries)
print_header(by='%s (%d added, %d removed)' % (by, print_header(by='%s (%d added, %d removed)' % (by,
sum(1 for old, _, _, _ in diff.values() if not old), sum(1 for old, _, _, _ in diff.values() if not old),
sum(1 for _, new, _, _ in diff.values() if not new))) sum(1 for _, new, _, _ in diff.values() if not new)))
for name, (old, new, diff, ratio) in sorted_diff_entries( for name, (old, new, diff, ratio) in sorted(diff.items(),
diff.items()): key=lambda x: (-x[1][3], x)):
if ratio or args.get('all'): if ratio or args.get('all'):
print_diff_entry(name, old, new, diff, ratio) print("%-36s %7s %7s %+7d%s" % (name,
old or "-",
new or "-",
diff,
' (%+.1f%%)' % (100*ratio) if ratio else ''))
def print_totals(): def print_totals():
if not args.get('diff'): if not args.get('diff'):
print_entry('TOTAL', total) print("%-36s %7d" % ('TOTAL', total))
else: else:
ratio = (0.0 if not prev_total and not total ratio = (total-prev_total)/prev_total if prev_total else 1.0
else 1.0 if not prev_total print("%-36s %7s %7s %+7d%s" % (
else (total-prev_total)/prev_total) 'TOTAL',
print_diff_entry('TOTAL', prev_total if prev_total else '-',
prev_total, total, total if total else '-',
total-prev_total, total-prev_total,
ratio) ' (%+.1f%%)' % (100*ratio) if ratio else ''))
if args.get('quiet'): if args.get('quiet'):
pass pass
@@ -237,7 +175,7 @@ def main(**args):
print_entries(by='file') print_entries(by='file')
print_totals() print_totals()
else: else:
print_entries(by='name') print_entries(by='function')
print_totals() print_totals()
if __name__ == "__main__": if __name__ == "__main__":
@@ -250,30 +188,22 @@ if __name__ == "__main__":
or a list of paths. Defaults to %r." % OBJ_PATHS) or a list of paths. Defaults to %r." % OBJ_PATHS)
parser.add_argument('-v', '--verbose', action='store_true', parser.add_argument('-v', '--verbose', action='store_true',
help="Output commands that run behind the scenes.") help="Output commands that run behind the scenes.")
parser.add_argument('-q', '--quiet', action='store_true',
help="Don't show anything, useful with -o.")
parser.add_argument('-o', '--output', parser.add_argument('-o', '--output',
help="Specify CSV file to store results.") help="Specify CSV file to store results.")
parser.add_argument('-u', '--use', parser.add_argument('-u', '--use',
help="Don't compile and find code sizes, instead use this CSV file.") help="Don't compile and find code sizes, instead use this CSV file.")
parser.add_argument('-d', '--diff', parser.add_argument('-d', '--diff',
help="Specify CSV file to diff code size against.") help="Specify CSV file to diff code size against.")
parser.add_argument('-m', '--merge',
help="Merge with an existing CSV file when writing to output.")
parser.add_argument('-a', '--all', action='store_true', parser.add_argument('-a', '--all', action='store_true',
help="Show all functions, not just the ones that changed.") help="Show all functions, not just the ones that changed.")
parser.add_argument('-A', '--everything', action='store_true', parser.add_argument('--files', action='store_true',
help="Include builtin and libc specific symbols.")
parser.add_argument('-s', '--size-sort', action='store_true',
help="Sort by size.")
parser.add_argument('-S', '--reverse-size-sort', action='store_true',
help="Sort by size, but backwards.")
parser.add_argument('-F', '--files', action='store_true',
help="Show file-level code sizes. Note this does not include padding! " help="Show file-level code sizes. Note this does not include padding! "
"So sizes may differ from other tools.") "So sizes may differ from other tools.")
parser.add_argument('-Y', '--summary', action='store_true', parser.add_argument('-s', '--summary', action='store_true',
help="Only show the total code size.") help="Only show the total code size.")
parser.add_argument('--type', default='tTrRdD', 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 " help="Type of symbols to report, this uses the same single-character "
"type-names emitted by nm. Defaults to %(default)r.") "type-names emitted by nm. Defaults to %(default)r.")
parser.add_argument('--nm-tool', default=['nm'], type=lambda x: x.split(), parser.add_argument('--nm-tool', default=['nm'], type=lambda x: x.split(),

View File

@@ -55,9 +55,8 @@ def collect(paths, **args):
for (file, func), (hits, count) in reduced_funcs.items(): for (file, func), (hits, count) in reduced_funcs.items():
# discard internal/testing functions (test_* injected with # discard internal/testing functions (test_* injected with
# internal testing) # internal testing)
if not args.get('everything'): if func.startswith('__') or func.startswith('test_'):
if func.startswith('__') or func.startswith('test_'): continue
continue
# discard .8449 suffixes created by optimizer # discard .8449 suffixes created by optimizer
func = re.sub('\.[0-9]+', '', func) func = re.sub('\.[0-9]+', '', func)
results.append((file, func, hits, count)) results.append((file, func, hits, count))
@@ -66,15 +65,6 @@ def collect(paths, **args):
def main(**args): def main(**args):
def openio(path, mode='r'):
if path == '-':
if 'r' in mode:
return os.fdopen(os.dup(sys.stdin.fileno()), 'r')
else:
return os.fdopen(os.dup(sys.stdout.fileno()), 'w')
else:
return open(path, mode)
# find coverage # find coverage
if not args.get('use'): if not args.get('use'):
# find *.info files # find *.info files
@@ -92,16 +82,14 @@ def main(**args):
results = collect(paths, **args) results = collect(paths, **args)
else: else:
with openio(args['use']) as f: with open(args['use']) as f:
r = csv.DictReader(f) r = csv.DictReader(f)
results = [ results = [
( result['file'], ( result['file'],
result['name'], result['function'],
int(result['coverage_hits']), int(result['hits']),
int(result['coverage_count'])) int(result['count']))
for result in r for result in r]
if result.get('coverage_hits') not in {None, ''}
if result.get('coverage_count') not in {None, ''}]
total_hits, total_count = 0, 0 total_hits, total_count = 0, 0
for _, _, hits, count in results: for _, _, hits, count in results:
@@ -110,19 +98,14 @@ def main(**args):
# find previous results? # find previous results?
if args.get('diff'): if args.get('diff'):
try: with open(args['diff']) as f:
with openio(args['diff']) as f: r = csv.DictReader(f)
r = csv.DictReader(f) prev_results = [
prev_results = [ ( result['file'],
( result['file'], result['function'],
result['name'], int(result['hits']),
int(result['coverage_hits']), int(result['count']))
int(result['coverage_count'])) for result in r]
for result in r
if result.get('coverage_hits') not in {None, ''}
if result.get('coverage_count') not in {None, ''}]
except FileNotFoundError:
prev_results = []
prev_total_hits, prev_total_count = 0, 0 prev_total_hits, prev_total_count = 0, 0
for _, _, hits, count in prev_results: for _, _, hits, count in prev_results:
@@ -131,36 +114,14 @@ def main(**args):
# write results to CSV # write results to CSV
if args.get('output'): if args.get('output'):
merged_results = co.defaultdict(lambda: {}) with open(args['output'], 'w') as f:
other_fields = [] w = csv.writer(f)
w.writerow(['file', 'function', 'hits', 'count'])
# merge? for file, func, hits, count in sorted(results):
if args.get('merge'): w.writerow((file, func, hits, count))
try:
with openio(args['merge']) as f:
r = csv.DictReader(f)
for result in r:
file = result.pop('file', '')
func = result.pop('name', '')
result.pop('coverage_hits', None)
result.pop('coverage_count', None)
merged_results[(file, func)] = result
other_fields = result.keys()
except FileNotFoundError:
pass
for file, func, hits, count in results:
merged_results[(file, func)]['coverage_hits'] = hits
merged_results[(file, func)]['coverage_count'] = count
with openio(args['output'], 'w') as f:
w = csv.DictWriter(f, ['file', 'name', *other_fields, 'coverage_hits', 'coverage_count'])
w.writeheader()
for (file, func), result in sorted(merged_results.items()):
w.writerow({'file': file, 'name': func, **result})
# print results # print results
def dedup_entries(results, by='name'): def dedup_entries(results, by='function'):
entries = co.defaultdict(lambda: (0, 0)) entries = co.defaultdict(lambda: (0, 0))
for file, func, hits, count in results: for file, func, hits, count in results:
entry = (file if by == 'file' else func) entry = (file if by == 'file' else func)
@@ -186,59 +147,23 @@ def main(**args):
- (old_hits/old_count if old_count else 1.0))) - (old_hits/old_count if old_count else 1.0)))
return diff return diff
def sorted_entries(entries):
if args.get('coverage_sort'):
return sorted(entries, key=lambda x: (-(x[1][0]/x[1][1] if x[1][1] else -1), x))
elif args.get('reverse_coverage_sort'):
return sorted(entries, key=lambda x: (+(x[1][0]/x[1][1] if x[1][1] else -1), x))
else:
return sorted(entries)
def sorted_diff_entries(entries):
if args.get('coverage_sort'):
return sorted(entries, key=lambda x: (-(x[1][2]/x[1][3] if x[1][3] else -1), x))
elif args.get('reverse_coverage_sort'):
return sorted(entries, key=lambda x: (+(x[1][2]/x[1][3] if x[1][3] else -1), x))
else:
return sorted(entries, key=lambda x: (-x[1][6], x))
def print_header(by=''): def print_header(by=''):
if not args.get('diff'): if not args.get('diff'):
print('%-36s %19s' % (by, 'hits/line')) print('%-36s %19s' % (by, 'hits/line'))
else: else:
print('%-36s %19s %19s %11s' % (by, 'old', 'new', 'diff')) print('%-36s %19s %19s %11s' % (by, 'old', 'new', 'diff'))
def print_entry(name, hits, count): def print_entries(by='function'):
print("%-36s %11s %7s" % (name,
'%d/%d' % (hits, count)
if count else '-',
'%.1f%%' % (100*hits/count)
if count else '-'))
def print_diff_entry(name,
old_hits, old_count,
new_hits, new_count,
diff_hits, diff_count,
ratio):
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_entries(by='name'):
entries = dedup_entries(results, by=by) entries = dedup_entries(results, by=by)
if not args.get('diff'): if not args.get('diff'):
print_header(by=by) print_header(by=by)
for name, (hits, count) in sorted_entries(entries.items()): for name, (hits, count) in sorted(entries.items()):
print_entry(name, hits, count) print("%-36s %11s %7s" % (name,
'%d/%d' % (hits, count)
if count else '-',
'%.1f%%' % (100*hits/count)
if count else '-'))
else: else:
prev_entries = dedup_entries(prev_results, by=by) prev_entries = dedup_entries(prev_results, by=by)
diff = diff_entries(prev_entries, entries) diff = diff_entries(prev_entries, entries)
@@ -248,28 +173,45 @@ def main(**args):
for name, ( for name, (
old_hits, old_count, old_hits, old_count,
new_hits, new_count, new_hits, new_count,
diff_hits, diff_count, ratio) in sorted_diff_entries( diff_hits, diff_count, ratio) in sorted(diff.items(),
diff.items()): key=lambda x: (-x[1][6], x)):
if ratio or args.get('all'): if ratio or args.get('all'):
print_diff_entry(name, print("%-36s %11s %7s %11s %7s %11s%s" % (name,
old_hits, old_count, '%d/%d' % (old_hits, old_count)
new_hits, new_count, if old_count else '-',
diff_hits, diff_count, '%.1f%%' % (100*old_hits/old_count)
ratio) 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(): def print_totals():
if not args.get('diff'): if not args.get('diff'):
print_entry('TOTAL', total_hits, total_count) 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: else:
ratio = ((total_hits/total_count ratio = ((total_hits/total_count
if total_count else 1.0) if total_count else 1.0)
- (prev_total_hits/prev_total_count - (prev_total_hits/prev_total_count
if prev_total_count else 1.0)) if prev_total_count else 1.0))
print_diff_entry('TOTAL', print("%-36s %11s %7s %11s %7s %11s%s" % ('TOTAL',
prev_total_hits, prev_total_count, '%d/%d' % (prev_total_hits, prev_total_count)
total_hits, total_count, if prev_total_count else '-',
total_hits-prev_total_hits, total_count-prev_total_count, '%.1f%%' % (100*prev_total_hits/prev_total_count)
ratio) 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'): if args.get('quiet'):
pass pass
@@ -280,7 +222,7 @@ def main(**args):
print_entries(by='file') print_entries(by='file')
print_totals() print_totals()
else: else:
print_entries(by='name') print_entries(by='function')
print_totals() print_totals()
if __name__ == "__main__": if __name__ == "__main__":
@@ -301,23 +243,12 @@ if __name__ == "__main__":
help="Don't do any work, instead use this CSV file.") help="Don't do any work, instead use this CSV file.")
parser.add_argument('-d', '--diff', parser.add_argument('-d', '--diff',
help="Specify CSV file to diff code size against.") help="Specify CSV file to diff code size against.")
parser.add_argument('-m', '--merge',
help="Merge with an existing CSV file when writing to output.")
parser.add_argument('-a', '--all', action='store_true', parser.add_argument('-a', '--all', action='store_true',
help="Show all functions, not just the ones that changed.") help="Show all functions, not just the ones that changed.")
parser.add_argument('-A', '--everything', action='store_true', parser.add_argument('--files', action='store_true',
help="Include builtin and libc specific symbols.")
parser.add_argument('-s', '--coverage-sort', action='store_true',
help="Sort by coverage.")
parser.add_argument('-S', '--reverse-coverage-sort', action='store_true',
help="Sort by coverage, but backwards.")
parser.add_argument('-F', '--files', action='store_true',
help="Show file-level coverage.") help="Show file-level coverage.")
parser.add_argument('-Y', '--summary', action='store_true', parser.add_argument('-s', '--summary', action='store_true',
help="Only show the total coverage.") help="Only show the total coverage.")
parser.add_argument('-q', '--quiet', action='store_true', parser.add_argument('-q', '--quiet', action='store_true',
help="Don't show anything, useful with -o.") help="Don't show anything, useful with -o.")
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()))) sys.exit(main(**vars(parser.parse_args())))

View File

@@ -1,283 +0,0 @@
#!/usr/bin/env python3
#
# Script to find data 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']
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,
errors='replace')
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)
# replace .o with .c, different scripts report .o/.c, we need to
# choose one if we want to deduplicate csv files
file = re.sub('\.o$', '.c', file)
# discard internal functions
if not args.get('everything'):
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):
def openio(path, mode='r'):
if path == '-':
if 'r' in mode:
return os.fdopen(os.dup(sys.stdin.fileno()), 'r')
else:
return os.fdopen(os.dup(sys.stdout.fileno()), 'w')
else:
return open(path, mode)
# 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 openio(args['use']) as f:
r = csv.DictReader(f)
results = [
( result['file'],
result['name'],
int(result['data_size']))
for result in r
if result.get('data_size') not in {None, ''}]
total = 0
for _, _, size in results:
total += size
# find previous results?
if args.get('diff'):
try:
with openio(args['diff']) as f:
r = csv.DictReader(f)
prev_results = [
( result['file'],
result['name'],
int(result['data_size']))
for result in r
if result.get('data_size') not in {None, ''}]
except FileNotFoundError:
prev_results = []
prev_total = 0
for _, _, size in prev_results:
prev_total += size
# write results to CSV
if args.get('output'):
merged_results = co.defaultdict(lambda: {})
other_fields = []
# merge?
if args.get('merge'):
try:
with openio(args['merge']) as f:
r = csv.DictReader(f)
for result in r:
file = result.pop('file', '')
func = result.pop('name', '')
result.pop('data_size', None)
merged_results[(file, func)] = result
other_fields = result.keys()
except FileNotFoundError:
pass
for file, func, size in results:
merged_results[(file, func)]['data_size'] = size
with openio(args['output'], 'w') as f:
w = csv.DictWriter(f, ['file', 'name', *other_fields, 'data_size'])
w.writeheader()
for (file, func), result in sorted(merged_results.items()):
w.writerow({'file': file, 'name': func, **result})
# print results
def dedup_entries(results, by='name'):
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 sorted_entries(entries):
if args.get('size_sort'):
return sorted(entries, key=lambda x: (-x[1], x))
elif args.get('reverse_size_sort'):
return sorted(entries, key=lambda x: (+x[1], x))
else:
return sorted(entries)
def sorted_diff_entries(entries):
if args.get('size_sort'):
return sorted(entries, key=lambda x: (-x[1][1], x))
elif args.get('reverse_size_sort'):
return sorted(entries, key=lambda x: (+x[1][1], x))
else:
return sorted(entries, key=lambda x: (-x[1][3], x))
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_entry(name, size):
print("%-36s %7d" % (name, size))
def print_diff_entry(name, old, new, diff, ratio):
print("%-36s %7s %7s %+7d%s" % (name,
old or "-",
new or "-",
diff,
' (%+.1f%%)' % (100*ratio) if ratio else ''))
def print_entries(by='name'):
entries = dedup_entries(results, by=by)
if not args.get('diff'):
print_header(by=by)
for name, size in sorted_entries(entries.items()):
print_entry(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_entries(
diff.items()):
if ratio or args.get('all'):
print_diff_entry(name, old, new, diff, ratio)
def print_totals():
if not args.get('diff'):
print_entry('TOTAL', total)
else:
ratio = (0.0 if not prev_total and not total
else 1.0 if not prev_total
else (total-prev_total)/prev_total)
print_diff_entry('TOTAL',
prev_total, total,
total-prev_total,
ratio)
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='name')
print_totals()
if __name__ == "__main__":
import argparse
import sys
parser = argparse.ArgumentParser(
description="Find data 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('-q', '--quiet', action='store_true',
help="Don't show anything, useful with -o.")
parser.add_argument('-o', '--output',
help="Specify CSV file to store results.")
parser.add_argument('-u', '--use',
help="Don't compile and find data sizes, instead use this CSV file.")
parser.add_argument('-d', '--diff',
help="Specify CSV file to diff data size against.")
parser.add_argument('-m', '--merge',
help="Merge with an existing CSV file when writing to output.")
parser.add_argument('-a', '--all', action='store_true',
help="Show all functions, not just the ones that changed.")
parser.add_argument('-A', '--everything', action='store_true',
help="Include builtin and libc specific symbols.")
parser.add_argument('-s', '--size-sort', action='store_true',
help="Sort by size.")
parser.add_argument('-S', '--reverse-size-sort', action='store_true',
help="Sort by size, but backwards.")
parser.add_argument('-F', '--files', action='store_true',
help="Show file-level data sizes. Note this does not include padding! "
"So sizes may differ from other tools.")
parser.add_argument('-Y', '--summary', action='store_true',
help="Only show the total data size.")
parser.add_argument('--type', default='dDbB',
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

@@ -3,8 +3,8 @@
import re import re
import sys import sys
PATTERN = ['LFS_ASSERT', 'assert'] PATTERN = ['LFS2_ASSERT', 'assert']
PREFIX = 'LFS' PREFIX = 'LFS2'
MAXWIDTH = 16 MAXWIDTH = 16
ASSERT = "__{PREFIX}_ASSERT_{TYPE}_{COMP}" ASSERT = "__{PREFIX}_ASSERT_{TYPE}_{COMP}"

View File

@@ -5,7 +5,7 @@
# conflict at compile time. # conflict at compile time.
# #
# example: # example:
# $ ./scripts/prefix.py lfs2 # $ ./scripts/prefix.py lfs22
import os import os
import os.path import os.path
@@ -16,7 +16,7 @@ import tempfile
import shutil import shutil
import subprocess import subprocess
DEFAULT_PREFIX = "lfs" DEFAULT_PREFIX = "lfs2"
def subn(from_prefix, to_prefix, name): def subn(from_prefix, to_prefix, name):
name, count1 = re.subn('\\b'+from_prefix, to_prefix, name) name, count1 = re.subn('\\b'+from_prefix, to_prefix, name)

View File

@@ -1,430 +0,0 @@
#!/usr/bin/env python3
#
# Script to find stack usage at the function level. Will detect recursion and
# report as infinite stack usage.
#
import os
import glob
import itertools as it
import re
import csv
import collections as co
import math as m
CI_PATHS = ['*.ci']
def collect(paths, **args):
# parse the vcg format
k_pattern = re.compile('([a-z]+)\s*:', re.DOTALL)
v_pattern = re.compile('(?:"(.*?)"|([a-z]+))', re.DOTALL)
def parse_vcg(rest):
def parse_vcg(rest):
node = []
while True:
rest = rest.lstrip()
m = k_pattern.match(rest)
if not m:
return (node, rest)
k, rest = m.group(1), rest[m.end(0):]
rest = rest.lstrip()
if rest.startswith('{'):
v, rest = parse_vcg(rest[1:])
assert rest[0] == '}', "unexpected %r" % rest[0:1]
rest = rest[1:]
node.append((k, v))
else:
m = v_pattern.match(rest)
assert m, "unexpected %r" % rest[0:1]
v, rest = m.group(1) or m.group(2), rest[m.end(0):]
node.append((k, v))
node, rest = parse_vcg(rest)
assert rest == '', "unexpected %r" % rest[0:1]
return node
# collect into functions
results = co.defaultdict(lambda: (None, None, 0, set()))
f_pattern = re.compile(
r'([^\\]*)\\n([^:]*)[^\\]*\\n([0-9]+) bytes \((.*)\)')
for path in paths:
with open(path) as f:
vcg = parse_vcg(f.read())
for k, graph in vcg:
if k != 'graph':
continue
for k, info in graph:
if k == 'node':
info = dict(info)
m = f_pattern.match(info['label'])
if m:
function, file, size, type = m.groups()
if not args.get('quiet') and type != 'static':
print('warning: found non-static stack for %s (%s)'
% (function, type))
_, _, _, targets = results[info['title']]
results[info['title']] = (
file, function, int(size), targets)
elif k == 'edge':
info = dict(info)
_, _, _, targets = results[info['sourcename']]
targets.add(info['targetname'])
else:
continue
if not args.get('everything'):
for source, (s_file, s_function, _, _) in list(results.items()):
# discard internal functions
if s_file.startswith('<') or s_file.startswith('/usr/include'):
del results[source]
# find maximum stack size recursively, this requires also detecting cycles
# (in case of recursion)
def find_limit(source, seen=None):
seen = seen or set()
if source not in results:
return 0
_, _, frame, targets = results[source]
limit = 0
for target in targets:
if target in seen:
# found a cycle
return float('inf')
limit_ = find_limit(target, seen | {target})
limit = max(limit, limit_)
return frame + limit
def find_deps(targets):
deps = set()
for target in targets:
if target in results:
t_file, t_function, _, _ = results[target]
deps.add((t_file, t_function))
return deps
# flatten into a list
flat_results = []
for source, (s_file, s_function, frame, targets) in results.items():
limit = find_limit(source)
deps = find_deps(targets)
flat_results.append((s_file, s_function, frame, limit, deps))
return flat_results
def main(**args):
def openio(path, mode='r'):
if path == '-':
if 'r' in mode:
return os.fdopen(os.dup(sys.stdin.fileno()), 'r')
else:
return os.fdopen(os.dup(sys.stdout.fileno()), 'w')
else:
return open(path, mode)
# find sizes
if not args.get('use', None):
# find .ci files
paths = []
for path in args['ci_paths']:
if os.path.isdir(path):
path = path + '/*.ci'
for path in glob.glob(path):
paths.append(path)
if not paths:
print('no .ci files found in %r?' % args['ci_paths'])
sys.exit(-1)
results = collect(paths, **args)
else:
with openio(args['use']) as f:
r = csv.DictReader(f)
results = [
( result['file'],
result['name'],
int(result['stack_frame']),
float(result['stack_limit']), # note limit can be inf
set())
for result in r
if result.get('stack_frame') not in {None, ''}
if result.get('stack_limit') not in {None, ''}]
total_frame = 0
total_limit = 0
for _, _, frame, limit, _ in results:
total_frame += frame
total_limit = max(total_limit, limit)
# find previous results?
if args.get('diff'):
try:
with openio(args['diff']) as f:
r = csv.DictReader(f)
prev_results = [
( result['file'],
result['name'],
int(result['stack_frame']),
float(result['stack_limit']),
set())
for result in r
if result.get('stack_frame') not in {None, ''}
if result.get('stack_limit') not in {None, ''}]
except FileNotFoundError:
prev_results = []
prev_total_frame = 0
prev_total_limit = 0
for _, _, frame, limit, _ in prev_results:
prev_total_frame += frame
prev_total_limit = max(prev_total_limit, limit)
# write results to CSV
if args.get('output'):
merged_results = co.defaultdict(lambda: {})
other_fields = []
# merge?
if args.get('merge'):
try:
with openio(args['merge']) as f:
r = csv.DictReader(f)
for result in r:
file = result.pop('file', '')
func = result.pop('name', '')
result.pop('stack_frame', None)
result.pop('stack_limit', None)
merged_results[(file, func)] = result
other_fields = result.keys()
except FileNotFoundError:
pass
for file, func, frame, limit, _ in results:
merged_results[(file, func)]['stack_frame'] = frame
merged_results[(file, func)]['stack_limit'] = limit
with openio(args['output'], 'w') as f:
w = csv.DictWriter(f, ['file', 'name', *other_fields, 'stack_frame', 'stack_limit'])
w.writeheader()
for (file, func), result in sorted(merged_results.items()):
w.writerow({'file': file, 'name': func, **result})
# print results
def dedup_entries(results, by='name'):
entries = co.defaultdict(lambda: (0, 0, set()))
for file, func, frame, limit, deps in results:
entry = (file if by == 'file' else func)
entry_frame, entry_limit, entry_deps = entries[entry]
entries[entry] = (
entry_frame + frame,
max(entry_limit, limit),
entry_deps | {file if by == 'file' else func
for file, func in deps})
return entries
def diff_entries(olds, news):
diff = co.defaultdict(lambda: (None, None, None, None, 0, 0, 0, set()))
for name, (new_frame, new_limit, deps) in news.items():
diff[name] = (
None, None,
new_frame, new_limit,
new_frame, new_limit,
1.0,
deps)
for name, (old_frame, old_limit, _) in olds.items():
_, _, new_frame, new_limit, _, _, _, deps = diff[name]
diff[name] = (
old_frame, old_limit,
new_frame, new_limit,
(new_frame or 0) - (old_frame or 0),
0 if m.isinf(new_limit or 0) and m.isinf(old_limit or 0)
else (new_limit or 0) - (old_limit or 0),
0.0 if m.isinf(new_limit or 0) and m.isinf(old_limit or 0)
else +float('inf') if m.isinf(new_limit or 0)
else -float('inf') if m.isinf(old_limit or 0)
else +0.0 if not old_limit and not new_limit
else +1.0 if not old_limit
else ((new_limit or 0) - (old_limit or 0))/(old_limit or 0),
deps)
return diff
def sorted_entries(entries):
if args.get('limit_sort'):
return sorted(entries, key=lambda x: (-x[1][1], x))
elif args.get('reverse_limit_sort'):
return sorted(entries, key=lambda x: (+x[1][1], x))
elif args.get('frame_sort'):
return sorted(entries, key=lambda x: (-x[1][0], x))
elif args.get('reverse_frame_sort'):
return sorted(entries, key=lambda x: (+x[1][0], x))
else:
return sorted(entries)
def sorted_diff_entries(entries):
if args.get('limit_sort'):
return sorted(entries, key=lambda x: (-(x[1][3] or 0), x))
elif args.get('reverse_limit_sort'):
return sorted(entries, key=lambda x: (+(x[1][3] or 0), x))
elif args.get('frame_sort'):
return sorted(entries, key=lambda x: (-(x[1][2] or 0), x))
elif args.get('reverse_frame_sort'):
return sorted(entries, key=lambda x: (+(x[1][2] or 0), x))
else:
return sorted(entries, key=lambda x: (-x[1][6], x))
def print_header(by=''):
if not args.get('diff'):
print('%-36s %7s %7s' % (by, 'frame', 'limit'))
else:
print('%-36s %15s %15s %15s' % (by, 'old', 'new', 'diff'))
def print_entry(name, frame, limit):
print("%-36s %7d %7s" % (name,
frame, '' if m.isinf(limit) else int(limit)))
def print_diff_entry(name,
old_frame, old_limit,
new_frame, new_limit,
diff_frame, diff_limit,
ratio):
print('%-36s %7s %7s %7s %7s %+7d %7s%s' % (name,
old_frame if old_frame is not None else "-",
('' if m.isinf(old_limit) else int(old_limit))
if old_limit is not None else "-",
new_frame if new_frame is not None else "-",
('' if m.isinf(new_limit) else int(new_limit))
if new_limit is not None else "-",
diff_frame,
('+∞' if diff_limit > 0 and m.isinf(diff_limit)
else '-∞' if diff_limit < 0 and m.isinf(diff_limit)
else '%+d' % diff_limit),
'' if not ratio
else ' (+∞%)' if ratio > 0 and m.isinf(ratio)
else ' (-∞%)' if ratio < 0 and m.isinf(ratio)
else ' (%+.1f%%)' % (100*ratio)))
def print_entries(by='name'):
# build optional tree of dependencies
def print_deps(entries, depth, print,
filter=lambda _: True,
prefixes=('', '', '', '')):
entries = entries if isinstance(entries, list) else list(entries)
filtered_entries = [(name, entry)
for name, entry in entries
if filter(name)]
for i, (name, entry) in enumerate(filtered_entries):
last = (i == len(filtered_entries)-1)
print(prefixes[0+last] + name, entry)
if depth > 0:
deps = entry[-1]
print_deps(entries, depth-1, print,
lambda name: name in deps,
( prefixes[2+last] + "|-> ",
prefixes[2+last] + "'-> ",
prefixes[2+last] + "| ",
prefixes[2+last] + " "))
entries = dedup_entries(results, by=by)
if not args.get('diff'):
print_header(by=by)
print_deps(
sorted_entries(entries.items()),
args.get('depth') or 0,
lambda name, entry: print_entry(name, *entry[:-1]))
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 old is None),
sum(1 for _, _, _, new, _, _, _, _ in diff.values() if new is None)))
print_deps(
filter(
lambda x: x[1][6] or args.get('all'),
sorted_diff_entries(diff.items())),
args.get('depth') or 0,
lambda name, entry: print_diff_entry(name, *entry[:-1]))
def print_totals():
if not args.get('diff'):
print_entry('TOTAL', total_frame, total_limit)
else:
diff_frame = total_frame - prev_total_frame
diff_limit = (
0 if m.isinf(total_limit or 0) and m.isinf(prev_total_limit or 0)
else (total_limit or 0) - (prev_total_limit or 0))
ratio = (
0.0 if m.isinf(total_limit or 0) and m.isinf(prev_total_limit or 0)
else +float('inf') if m.isinf(total_limit or 0)
else -float('inf') if m.isinf(prev_total_limit or 0)
else 0.0 if not prev_total_limit and not total_limit
else 1.0 if not prev_total_limit
else ((total_limit or 0) - (prev_total_limit or 0))/(prev_total_limit or 0))
print_diff_entry('TOTAL',
prev_total_frame, prev_total_limit,
total_frame, total_limit,
diff_frame, diff_limit,
ratio)
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='name')
print_totals()
if __name__ == "__main__":
import argparse
import sys
parser = argparse.ArgumentParser(
description="Find stack usage at the function level.")
parser.add_argument('ci_paths', nargs='*', default=CI_PATHS,
help="Description of where to find *.ci files. May be a directory \
or a list of paths. Defaults to %r." % CI_PATHS)
parser.add_argument('-v', '--verbose', action='store_true',
help="Output commands that run behind the scenes.")
parser.add_argument('-q', '--quiet', action='store_true',
help="Don't show anything, useful with -o.")
parser.add_argument('-o', '--output',
help="Specify CSV file to store results.")
parser.add_argument('-u', '--use',
help="Don't parse callgraph files, instead use this CSV file.")
parser.add_argument('-d', '--diff',
help="Specify CSV file to diff against.")
parser.add_argument('-m', '--merge',
help="Merge with an existing CSV file when writing to output.")
parser.add_argument('-a', '--all', action='store_true',
help="Show all functions, not just the ones that changed.")
parser.add_argument('-A', '--everything', action='store_true',
help="Include builtin and libc specific symbols.")
parser.add_argument('-s', '--limit-sort', action='store_true',
help="Sort by stack limit.")
parser.add_argument('-S', '--reverse-limit-sort', action='store_true',
help="Sort by stack limit, but backwards.")
parser.add_argument('--frame-sort', action='store_true',
help="Sort by stack frame size.")
parser.add_argument('--reverse-frame-sort', action='store_true',
help="Sort by stack frame size, but backwards.")
parser.add_argument('-L', '--depth', default=0, type=lambda x: int(x, 0),
nargs='?', const=float('inf'),
help="Depth of dependencies to show.")
parser.add_argument('-F', '--files', action='store_true',
help="Show file-level calls.")
parser.add_argument('-Y', '--summary', action='store_true',
help="Only show the total stack size.")
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,331 +0,0 @@
#!/usr/bin/env python3
#
# Script to find struct sizes.
#
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']
def collect(paths, **args):
decl_pattern = re.compile(
'^\s+(?P<no>[0-9]+)'
'\s+(?P<dir>[0-9]+)'
'\s+.*'
'\s+(?P<file>[^\s]+)$')
struct_pattern = re.compile(
'^(?:.*DW_TAG_(?P<tag>[a-z_]+).*'
'|^.*DW_AT_name.*:\s*(?P<name>[^:\s]+)\s*'
'|^.*DW_AT_decl_file.*:\s*(?P<decl>[0-9]+)\s*'
'|^.*DW_AT_byte_size.*:\s*(?P<size>[0-9]+)\s*)$')
results = co.defaultdict(lambda: 0)
for path in paths:
# find decl, we want to filter by structs in .h files
decls = {}
# note objdump-tool may contain extra args
cmd = args['objdump_tool'] + ['--dwarf=rawline', 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,
errors='replace')
for line in proc.stdout:
# find file numbers
m = decl_pattern.match(line)
if m:
decls[int(m.group('no'))] = m.group('file')
proc.wait()
if proc.returncode != 0:
if not args.get('verbose'):
for line in proc.stderr:
sys.stdout.write(line)
sys.exit(-1)
# collect structs as we parse dwarf info
found = False
name = None
decl = None
size = None
# note objdump-tool may contain extra args
cmd = args['objdump_tool'] + ['--dwarf=info', 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,
errors='replace')
for line in proc.stdout:
# state machine here to find structs
m = struct_pattern.match(line)
if m:
if m.group('tag'):
if (name is not None
and decl is not None
and size is not None):
decl = decls.get(decl, '?')
results[(decl, name)] = size
found = (m.group('tag') == 'structure_type')
name = None
decl = None
size = None
elif found and m.group('name'):
name = m.group('name')
elif found and name and m.group('decl'):
decl = int(m.group('decl'))
elif found and name and m.group('size'):
size = int(m.group('size'))
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, struct), size in results.items():
# map to source files
if args.get('build_dir'):
file = re.sub('%s/*' % re.escape(args['build_dir']), '', file)
# only include structs declared in header files in the current
# directory, ignore internal-only # structs (these are represented
# in other measurements)
if not args.get('everything'):
if not file.endswith('.h'):
continue
# replace .o with .c, different scripts report .o/.c, we need to
# choose one if we want to deduplicate csv files
file = re.sub('\.o$', '.c', file)
flat_results.append((file, struct, size))
return flat_results
def main(**args):
def openio(path, mode='r'):
if path == '-':
if 'r' in mode:
return os.fdopen(os.dup(sys.stdin.fileno()), 'r')
else:
return os.fdopen(os.dup(sys.stdout.fileno()), 'w')
else:
return open(path, mode)
# 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 openio(args['use']) as f:
r = csv.DictReader(f)
results = [
( result['file'],
result['name'],
int(result['struct_size']))
for result in r
if result.get('struct_size') not in {None, ''}]
total = 0
for _, _, size in results:
total += size
# find previous results?
if args.get('diff'):
try:
with openio(args['diff']) as f:
r = csv.DictReader(f)
prev_results = [
( result['file'],
result['name'],
int(result['struct_size']))
for result in r
if result.get('struct_size') not in {None, ''}]
except FileNotFoundError:
prev_results = []
prev_total = 0
for _, _, size in prev_results:
prev_total += size
# write results to CSV
if args.get('output'):
merged_results = co.defaultdict(lambda: {})
other_fields = []
# merge?
if args.get('merge'):
try:
with openio(args['merge']) as f:
r = csv.DictReader(f)
for result in r:
file = result.pop('file', '')
struct = result.pop('name', '')
result.pop('struct_size', None)
merged_results[(file, struct)] = result
other_fields = result.keys()
except FileNotFoundError:
pass
for file, struct, size in results:
merged_results[(file, struct)]['struct_size'] = size
with openio(args['output'], 'w') as f:
w = csv.DictWriter(f, ['file', 'name', *other_fields, 'struct_size'])
w.writeheader()
for (file, struct), result in sorted(merged_results.items()):
w.writerow({'file': file, 'name': struct, **result})
# print results
def dedup_entries(results, by='name'):
entries = co.defaultdict(lambda: 0)
for file, struct, size in results:
entry = (file if by == 'file' else struct)
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 sorted_entries(entries):
if args.get('size_sort'):
return sorted(entries, key=lambda x: (-x[1], x))
elif args.get('reverse_size_sort'):
return sorted(entries, key=lambda x: (+x[1], x))
else:
return sorted(entries)
def sorted_diff_entries(entries):
if args.get('size_sort'):
return sorted(entries, key=lambda x: (-x[1][1], x))
elif args.get('reverse_size_sort'):
return sorted(entries, key=lambda x: (+x[1][1], x))
else:
return sorted(entries, key=lambda x: (-x[1][3], x))
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_entry(name, size):
print("%-36s %7d" % (name, size))
def print_diff_entry(name, old, new, diff, ratio):
print("%-36s %7s %7s %+7d%s" % (name,
old or "-",
new or "-",
diff,
' (%+.1f%%)' % (100*ratio) if ratio else ''))
def print_entries(by='name'):
entries = dedup_entries(results, by=by)
if not args.get('diff'):
print_header(by=by)
for name, size in sorted_entries(entries.items()):
print_entry(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_entries(
diff.items()):
if ratio or args.get('all'):
print_diff_entry(name, old, new, diff, ratio)
def print_totals():
if not args.get('diff'):
print_entry('TOTAL', total)
else:
ratio = (0.0 if not prev_total and not total
else 1.0 if not prev_total
else (total-prev_total)/prev_total)
print_diff_entry('TOTAL',
prev_total, total,
total-prev_total,
ratio)
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='name')
print_totals()
if __name__ == "__main__":
import argparse
import sys
parser = argparse.ArgumentParser(
description="Find struct sizes.")
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('-q', '--quiet', action='store_true',
help="Don't show anything, useful with -o.")
parser.add_argument('-o', '--output',
help="Specify CSV file to store results.")
parser.add_argument('-u', '--use',
help="Don't compile and find struct sizes, instead use this CSV file.")
parser.add_argument('-d', '--diff',
help="Specify CSV file to diff struct size against.")
parser.add_argument('-m', '--merge',
help="Merge with an existing CSV file when writing to output.")
parser.add_argument('-a', '--all', action='store_true',
help="Show all functions, not just the ones that changed.")
parser.add_argument('-A', '--everything', action='store_true',
help="Include builtin and libc specific symbols.")
parser.add_argument('-s', '--size-sort', action='store_true',
help="Sort by size.")
parser.add_argument('-S', '--reverse-size-sort', action='store_true',
help="Sort by size, but backwards.")
parser.add_argument('-F', '--files', action='store_true',
help="Show file-level struct sizes.")
parser.add_argument('-Y', '--summary', action='store_true',
help="Only show the total struct size.")
parser.add_argument('--objdump-tool', default=['objdump'], type=lambda x: x.split(),
help="Path to the objdump 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,279 +0,0 @@
#!/usr/bin/env python3
#
# Script to summarize the outputs of other scripts. Operates on CSV files.
#
import functools as ft
import collections as co
import os
import csv
import re
import math as m
# displayable fields
Field = co.namedtuple('Field', 'name,parse,acc,key,fmt,repr,null,ratio')
FIELDS = [
# name, parse, accumulate, fmt, print, null
Field('code',
lambda r: int(r['code_size']),
sum,
lambda r: r,
'%7s',
lambda r: r,
'-',
lambda old, new: (new-old)/old),
Field('data',
lambda r: int(r['data_size']),
sum,
lambda r: r,
'%7s',
lambda r: r,
'-',
lambda old, new: (new-old)/old),
Field('stack',
lambda r: float(r['stack_limit']),
max,
lambda r: r,
'%7s',
lambda r: '' if m.isinf(r) else int(r),
'-',
lambda old, new: (new-old)/old),
Field('structs',
lambda r: int(r['struct_size']),
sum,
lambda r: r,
'%8s',
lambda r: r,
'-',
lambda old, new: (new-old)/old),
Field('coverage',
lambda r: (int(r['coverage_hits']), int(r['coverage_count'])),
lambda rs: ft.reduce(lambda a, b: (a[0]+b[0], a[1]+b[1]), rs),
lambda r: r[0]/r[1],
'%19s',
lambda r: '%11s %7s' % ('%d/%d' % (r[0], r[1]), '%.1f%%' % (100*r[0]/r[1])),
'%11s %7s' % ('-', '-'),
lambda old, new: ((new[0]/new[1]) - (old[0]/old[1])))
]
def main(**args):
def openio(path, mode='r'):
if path == '-':
if 'r' in mode:
return os.fdopen(os.dup(sys.stdin.fileno()), 'r')
else:
return os.fdopen(os.dup(sys.stdout.fileno()), 'w')
else:
return open(path, mode)
# find results
results = co.defaultdict(lambda: {})
for path in args.get('csv_paths', '-'):
try:
with openio(path) as f:
r = csv.DictReader(f)
for result in r:
file = result.pop('file', '')
name = result.pop('name', '')
prev = results[(file, name)]
for field in FIELDS:
try:
r = field.parse(result)
if field.name in prev:
results[(file, name)][field.name] = field.acc(
[prev[field.name], r])
else:
results[(file, name)][field.name] = r
except (KeyError, ValueError):
pass
except FileNotFoundError:
pass
# find fields
if args.get('all_fields'):
fields = FIELDS
elif args.get('fields') is not None:
fields_dict = {field.name: field for field in FIELDS}
fields = [fields_dict[f] for f in args['fields']]
else:
fields = []
for field in FIELDS:
if any(field.name in result for result in results.values()):
fields.append(field)
# find total for every field
total = {}
for result in results.values():
for field in fields:
if field.name in result and field.name in total:
total[field.name] = field.acc(
[total[field.name], result[field.name]])
elif field.name in result:
total[field.name] = result[field.name]
# find previous results?
if args.get('diff'):
prev_results = co.defaultdict(lambda: {})
try:
with openio(args['diff']) as f:
r = csv.DictReader(f)
for result in r:
file = result.pop('file', '')
name = result.pop('name', '')
prev = prev_results[(file, name)]
for field in FIELDS:
try:
r = field.parse(result)
if field.name in prev:
prev_results[(file, name)][field.name] = field.acc(
[prev[field.name], r])
else:
prev_results[(file, name)][field.name] = r
except (KeyError, ValueError):
pass
except FileNotFoundError:
pass
prev_total = {}
for result in prev_results.values():
for field in fields:
if field.name in result and field.name in prev_total:
prev_total[field.name] = field.acc(
[prev_total[field.name], result[field.name]])
elif field.name in result:
prev_total[field.name] = result[field.name]
# print results
def dedup_entries(results, by='name'):
entries = co.defaultdict(lambda: {})
for (file, func), result in results.items():
entry = (file if by == 'file' else func)
prev = entries[entry]
for field in fields:
if field.name in result and field.name in prev:
entries[entry][field.name] = field.acc(
[prev[field.name], result[field.name]])
elif field.name in result:
entries[entry][field.name] = result[field.name]
return entries
def sorted_entries(entries):
if args.get('sort') is not None:
field = {field.name: field for field in FIELDS}[args['sort']]
return sorted(entries, key=lambda x: (
-(field.key(x[1][field.name])) if field.name in x[1] else -1, x))
elif args.get('reverse_sort') is not None:
field = {field.name: field for field in FIELDS}[args['reverse_sort']]
return sorted(entries, key=lambda x: (
+(field.key(x[1][field.name])) if field.name in x[1] else -1, x))
else:
return sorted(entries)
def print_header(by=''):
if not args.get('diff'):
print('%-36s' % by, end='')
for field in fields:
print((' '+field.fmt) % field.name, end='')
print()
else:
print('%-36s' % by, end='')
for field in fields:
print((' '+field.fmt) % field.name, end='')
print(' %-9s' % '', end='')
print()
def print_entry(name, result):
print('%-36s' % name, end='')
for field in fields:
r = result.get(field.name)
if r is not None:
print((' '+field.fmt) % field.repr(r), end='')
else:
print((' '+field.fmt) % '-', end='')
print()
def print_diff_entry(name, old, new):
print('%-36s' % name, end='')
for field in fields:
n = new.get(field.name)
if n is not None:
print((' '+field.fmt) % field.repr(n), end='')
else:
print((' '+field.fmt) % '-', end='')
o = old.get(field.name)
ratio = (
0.0 if m.isinf(o or 0) and m.isinf(n or 0)
else +float('inf') if m.isinf(n or 0)
else -float('inf') if m.isinf(o or 0)
else 0.0 if not o and not n
else +1.0 if not o
else -1.0 if not n
else field.ratio(o, n))
print(' %-9s' % (
'' if not ratio
else '(+∞%)' if ratio > 0 and m.isinf(ratio)
else '(-∞%)' if ratio < 0 and m.isinf(ratio)
else '(%+.1f%%)' % (100*ratio)), end='')
print()
def print_entries(by='name'):
entries = dedup_entries(results, by=by)
if not args.get('diff'):
print_header(by=by)
for name, result in sorted_entries(entries.items()):
print_entry(name, result)
else:
prev_entries = dedup_entries(prev_results, by=by)
print_header(by='%s (%d added, %d removed)' % (by,
sum(1 for name in entries if name not in prev_entries),
sum(1 for name in prev_entries if name not in entries)))
for name, result in sorted_entries(entries.items()):
if args.get('all') or result != prev_entries.get(name, {}):
print_diff_entry(name, prev_entries.get(name, {}), result)
def print_totals():
if not args.get('diff'):
print_entry('TOTAL', total)
else:
print_diff_entry('TOTAL', prev_total, total)
if args.get('summary'):
print_header()
print_totals()
elif args.get('files'):
print_entries(by='file')
print_totals()
else:
print_entries(by='name')
print_totals()
if __name__ == "__main__":
import argparse
import sys
parser = argparse.ArgumentParser(
description="Summarize measurements")
parser.add_argument('csv_paths', nargs='*', default='-',
help="Description of where to find *.csv files. May be a directory \
or list of paths. *.csv files will be merged to show the total \
coverage.")
parser.add_argument('-d', '--diff',
help="Specify CSV file to diff against.")
parser.add_argument('-a', '--all', action='store_true',
help="Show all objects, not just the ones that changed.")
parser.add_argument('-e', '--all-fields', action='store_true',
help="Show all fields, even those with no results.")
parser.add_argument('-f', '--fields', type=lambda x: re.split('\s*,\s*', x),
help="Comma separated list of fields to print, by default all fields \
that are found in the CSV files are printed.")
parser.add_argument('-s', '--sort',
help="Sort by this field.")
parser.add_argument('-S', '--reverse-sort',
help="Sort by this field, but backwards.")
parser.add_argument('-F', '--files', action='store_true',
help="Show file-level calls.")
parser.add_argument('-Y', '--summary', action='store_true',
help="Only show the totals.")
sys.exit(main(**vars(parser.parse_args())))

View File

@@ -67,63 +67,63 @@ endif
""" """
GLOBALS = """ GLOBALS = """
//////////////// AUTOGENERATED TEST //////////////// //////////////// AUTOGENERATED TEST ////////////////
#include "lfs.h" #include "lfs2.h"
#include "bd/lfs_testbd.h" #include "bd/lfs2_testbd.h"
#include <stdio.h> #include <stdio.h>
extern const char *lfs_testbd_path; extern const char *lfs2_testbd_path;
extern uint32_t lfs_testbd_cycles; extern uint32_t lfs2_testbd_cycles;
""" """
DEFINES = { DEFINES = {
'LFS_READ_SIZE': 16, 'LFS2_READ_SIZE': 16,
'LFS_PROG_SIZE': 'LFS_READ_SIZE', 'LFS2_PROG_SIZE': 'LFS2_READ_SIZE',
'LFS_BLOCK_SIZE': 512, 'LFS2_BLOCK_SIZE': 512,
'LFS_BLOCK_COUNT': 1024, 'LFS2_BLOCK_COUNT': 1024,
'LFS_BLOCK_CYCLES': -1, 'LFS2_BLOCK_CYCLES': -1,
'LFS_CACHE_SIZE': '(64 % LFS_PROG_SIZE == 0 ? 64 : LFS_PROG_SIZE)', 'LFS2_CACHE_SIZE': '(64 % LFS2_PROG_SIZE == 0 ? 64 : LFS2_PROG_SIZE)',
'LFS_LOOKAHEAD_SIZE': 16, 'LFS2_LOOKAHEAD_SIZE': 16,
'LFS_ERASE_VALUE': 0xff, 'LFS2_ERASE_VALUE': 0xff,
'LFS_ERASE_CYCLES': 0, 'LFS2_ERASE_CYCLES': 0,
'LFS_BADBLOCK_BEHAVIOR': 'LFS_TESTBD_BADBLOCK_PROGERROR', 'LFS2_BADBLOCK_BEHAVIOR': 'LFS2_TESTBD_BADBLOCK_PROGERROR',
} }
PROLOGUE = """ PROLOGUE = """
// prologue // prologue
__attribute__((unused)) lfs_t lfs; __attribute__((unused)) lfs2_t lfs2;
__attribute__((unused)) lfs_testbd_t bd; __attribute__((unused)) lfs2_testbd_t bd;
__attribute__((unused)) lfs_file_t file; __attribute__((unused)) lfs2_file_t file;
__attribute__((unused)) lfs_dir_t dir; __attribute__((unused)) lfs2_dir_t dir;
__attribute__((unused)) struct lfs_info info; __attribute__((unused)) struct lfs2_info info;
__attribute__((unused)) char path[1024]; __attribute__((unused)) char path[1024];
__attribute__((unused)) uint8_t buffer[1024]; __attribute__((unused)) uint8_t buffer[1024];
__attribute__((unused)) lfs_size_t size; __attribute__((unused)) lfs2_size_t size;
__attribute__((unused)) int err; __attribute__((unused)) int err;
__attribute__((unused)) const struct lfs_config cfg = { __attribute__((unused)) const struct lfs2_config cfg = {
.context = &bd, .context = &bd,
.read = lfs_testbd_read, .read = lfs2_testbd_read,
.prog = lfs_testbd_prog, .prog = lfs2_testbd_prog,
.erase = lfs_testbd_erase, .erase = lfs2_testbd_erase,
.sync = lfs_testbd_sync, .sync = lfs2_testbd_sync,
.read_size = LFS_READ_SIZE, .read_size = LFS2_READ_SIZE,
.prog_size = LFS_PROG_SIZE, .prog_size = LFS2_PROG_SIZE,
.block_size = LFS_BLOCK_SIZE, .block_size = LFS2_BLOCK_SIZE,
.block_count = LFS_BLOCK_COUNT, .block_count = LFS2_BLOCK_COUNT,
.block_cycles = LFS_BLOCK_CYCLES, .block_cycles = LFS2_BLOCK_CYCLES,
.cache_size = LFS_CACHE_SIZE, .cache_size = LFS2_CACHE_SIZE,
.lookahead_size = LFS_LOOKAHEAD_SIZE, .lookahead_size = LFS2_LOOKAHEAD_SIZE,
}; };
__attribute__((unused)) const struct lfs_testbd_config bdcfg = { __attribute__((unused)) const struct lfs2_testbd_config bdcfg = {
.erase_value = LFS_ERASE_VALUE, .erase_value = LFS2_ERASE_VALUE,
.erase_cycles = LFS_ERASE_CYCLES, .erase_cycles = LFS2_ERASE_CYCLES,
.badblock_behavior = LFS_BADBLOCK_BEHAVIOR, .badblock_behavior = LFS2_BADBLOCK_BEHAVIOR,
.power_cycles = lfs_testbd_cycles, .power_cycles = lfs2_testbd_cycles,
}; };
lfs_testbd_createcfg(&cfg, lfs_testbd_path, &bdcfg) => 0; lfs2_testbd_createcfg(&cfg, lfs2_testbd_path, &bdcfg) => 0;
""" """
EPILOGUE = """ EPILOGUE = """
// epilogue // epilogue
lfs_testbd_destroy(&cfg) => 0; lfs2_testbd_destroy(&cfg) => 0;
""" """
PASS = '\033[32m✓\033[0m' PASS = '\033[32m✓\033[0m'
FAIL = '\033[31m✗\033[0m' FAIL = '\033[31m✗\033[0m'
@@ -335,7 +335,7 @@ class ValgrindTestCase(TestCase):
def test(self, exec=[], **args): def test(self, exec=[], **args):
verbose = args.get('verbose') verbose = args.get('verbose')
uninit = (self.defines.get('LFS_ERASE_VALUE', None) == -1) uninit = (self.defines.get('LFS2_ERASE_VALUE', None) == -1)
exec = [ exec = [
'valgrind', 'valgrind',
'--leak-check=full', '--leak-check=full',
@@ -529,13 +529,13 @@ class TestSuite:
case.build(tfs[case.in_], **args) case.build(tfs[case.in_], **args)
tf.write('\n') tf.write('\n')
tf.write('const char *lfs_testbd_path;\n') tf.write('const char *lfs2_testbd_path;\n')
tf.write('uint32_t lfs_testbd_cycles;\n') tf.write('uint32_t lfs2_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')
tf.write(4*' '+'lfs_testbd_path = (argc > 3) ? argv[3] : NULL;\n') tf.write(4*' '+'lfs2_testbd_path = (argc > 3) ? argv[3] : NULL;\n')
tf.write(4*' '+'lfs_testbd_cycles = (argc > 4) ? atoi(argv[4]) : 0;\n') tf.write(4*' '+'lfs2_testbd_cycles = (argc > 4) ? atoi(argv[4]) : 0;\n')
for perm in self.perms: for perm in self.perms:
# test declaration # test declaration
tf.write(4*' '+'extern void test_case%d(%s);\n' % ( tf.write(4*' '+'extern void test_case%d(%s);\n' % (
@@ -784,13 +784,10 @@ def main(**args):
stdout=sp.PIPE if not args.get('verbose') else None, stdout=sp.PIPE if not args.get('verbose') else None,
stderr=sp.STDOUT if not args.get('verbose') else None, stderr=sp.STDOUT if not args.get('verbose') else None,
universal_newlines=True) universal_newlines=True)
stdout = []
for line in proc.stdout:
stdout.append(line)
proc.wait() proc.wait()
if proc.returncode != 0: if proc.returncode != 0:
if not args.get('verbose'): if not args.get('verbose'):
for line in stdout: for line in proc.stdout:
sys.stdout.write(line) sys.stdout.write(line)
sys.exit(-1) sys.exit(-1)
@@ -806,9 +803,9 @@ 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 (%.1f%%)' % (passed, total, print('tests passed %d/%d (%.2f%%)' % (passed, total,
100*(passed/total if total else 1.0))) 100*(passed/total if total else 1.0)))
print('tests failed %d/%d (%.1f%%)' % (failed, total, print('tests failed %d/%d (%.2f%%)' % (failed, total,
100*(failed/total if total else 1.0))) 100*(failed/total if total else 1.0)))
return 1 if failed > 0 else 0 return 1 if failed > 0 else 0

View File

@@ -1,409 +1,409 @@
# allocator tests # allocator tests
# note for these to work there are a number constraints on the device geometry # note for these to work there are a number constraints on the device geometry
if = 'LFS_BLOCK_CYCLES == -1' if = 'LFS2_BLOCK_CYCLES == -1'
[[case]] # parallel allocation test [[case]] # parallel allocation test
define.FILES = 3 define.FILES = 3
define.SIZE = '(((LFS_BLOCK_SIZE-8)*(LFS_BLOCK_COUNT-6)) / FILES)' define.SIZE = '(((LFS2_BLOCK_SIZE-8)*(LFS2_BLOCK_COUNT-6)) / FILES)'
code = ''' code = '''
const char *names[FILES] = {"bacon", "eggs", "pancakes"}; const char *names[FILES] = {"bacon", "eggs", "pancakes"};
lfs_file_t files[FILES]; lfs2_file_t files[FILES];
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_mkdir(&lfs, "breakfast") => 0; lfs2_mkdir(&lfs2, "breakfast") => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &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, lfs2_file_open(&lfs2, &files[n], path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_APPEND) => 0;
} }
for (int n = 0; n < FILES; n++) { for (int n = 0; n < FILES; n++) {
size = strlen(names[n]); size = strlen(names[n]);
for (lfs_size_t i = 0; i < SIZE; i += size) { for (lfs2_size_t i = 0; i < SIZE; i += size) {
lfs_file_write(&lfs, &files[n], names[n], size) => size; lfs2_file_write(&lfs2, &files[n], names[n], size) => size;
} }
} }
for (int n = 0; n < FILES; n++) { for (int n = 0; n < FILES; n++) {
lfs_file_close(&lfs, &files[n]) => 0; lfs2_file_close(&lfs2, &files[n]) => 0;
} }
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &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; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
size = strlen(names[n]); size = strlen(names[n]);
for (lfs_size_t i = 0; i < SIZE; i += size) { for (lfs2_size_t i = 0; i < SIZE; i += size) {
lfs_file_read(&lfs, &file, buffer, size) => size; lfs2_file_read(&lfs2, &file, buffer, size) => size;
assert(memcmp(buffer, names[n], size) == 0); assert(memcmp(buffer, names[n], size) == 0);
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
} }
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # serial allocation test [[case]] # serial allocation test
define.FILES = 3 define.FILES = 3
define.SIZE = '(((LFS_BLOCK_SIZE-8)*(LFS_BLOCK_COUNT-6)) / FILES)' define.SIZE = '(((LFS2_BLOCK_SIZE-8)*(LFS2_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; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_mkdir(&lfs, "breakfast") => 0; lfs2_mkdir(&lfs2, "breakfast") => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
for (int n = 0; n < FILES; n++) { for (int n = 0; n < FILES; n++) {
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
sprintf(path, "breakfast/%s", names[n]); sprintf(path, "breakfast/%s", names[n]);
lfs_file_open(&lfs, &file, path, lfs2_file_open(&lfs2, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_APPEND) => 0;
size = strlen(names[n]); size = strlen(names[n]);
memcpy(buffer, names[n], size); memcpy(buffer, names[n], size);
for (int i = 0; i < SIZE; i += size) { for (int i = 0; i < SIZE; i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs2_file_write(&lfs2, &file, buffer, size) => size;
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
} }
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &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; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
size = strlen(names[n]); size = strlen(names[n]);
for (int i = 0; i < SIZE; i += size) { for (int i = 0; i < SIZE; i += size) {
lfs_file_read(&lfs, &file, buffer, size) => size; lfs2_file_read(&lfs2, &file, buffer, size) => size;
assert(memcmp(buffer, names[n], size) == 0); assert(memcmp(buffer, names[n], size) == 0);
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
} }
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # parallel allocation reuse test [[case]] # parallel allocation reuse test
define.FILES = 3 define.FILES = 3
define.SIZE = '(((LFS_BLOCK_SIZE-8)*(LFS_BLOCK_COUNT-6)) / FILES)' define.SIZE = '(((LFS2_BLOCK_SIZE-8)*(LFS2_BLOCK_COUNT-6)) / FILES)'
define.CYCLES = [1, 10] define.CYCLES = [1, 10]
code = ''' code = '''
const char *names[FILES] = {"bacon", "eggs", "pancakes"}; const char *names[FILES] = {"bacon", "eggs", "pancakes"};
lfs_file_t files[FILES]; lfs2_file_t files[FILES];
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
for (int c = 0; c < CYCLES; c++) { for (int c = 0; c < CYCLES; c++) {
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_mkdir(&lfs, "breakfast") => 0; lfs2_mkdir(&lfs2, "breakfast") => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &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, lfs2_file_open(&lfs2, &files[n], path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_APPEND) => 0;
} }
for (int n = 0; n < FILES; n++) { for (int n = 0; n < FILES; n++) {
size = strlen(names[n]); size = strlen(names[n]);
for (int i = 0; i < SIZE; i += size) { for (int i = 0; i < SIZE; i += size) {
lfs_file_write(&lfs, &files[n], names[n], size) => size; lfs2_file_write(&lfs2, &files[n], names[n], size) => size;
} }
} }
for (int n = 0; n < FILES; n++) { for (int n = 0; n < FILES; n++) {
lfs_file_close(&lfs, &files[n]) => 0; lfs2_file_close(&lfs2, &files[n]) => 0;
} }
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &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; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
size = strlen(names[n]); size = strlen(names[n]);
for (int i = 0; i < SIZE; i += size) { for (int i = 0; i < SIZE; i += size) {
lfs_file_read(&lfs, &file, buffer, size) => size; lfs2_file_read(&lfs2, &file, buffer, size) => size;
assert(memcmp(buffer, names[n], size) == 0); assert(memcmp(buffer, names[n], size) == 0);
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
} }
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &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; lfs2_remove(&lfs2, path) => 0;
} }
lfs_remove(&lfs, "breakfast") => 0; lfs2_remove(&lfs2, "breakfast") => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
} }
''' '''
[[case]] # serial allocation reuse test [[case]] # serial allocation reuse test
define.FILES = 3 define.FILES = 3
define.SIZE = '(((LFS_BLOCK_SIZE-8)*(LFS_BLOCK_COUNT-6)) / FILES)' define.SIZE = '(((LFS2_BLOCK_SIZE-8)*(LFS2_BLOCK_COUNT-6)) / FILES)'
define.CYCLES = [1, 10] 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; lfs2_format(&lfs2, &cfg) => 0;
for (int c = 0; c < CYCLES; c++) { for (int c = 0; c < CYCLES; c++) {
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_mkdir(&lfs, "breakfast") => 0; lfs2_mkdir(&lfs2, "breakfast") => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
for (int n = 0; n < FILES; n++) { for (int n = 0; n < FILES; n++) {
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
sprintf(path, "breakfast/%s", names[n]); sprintf(path, "breakfast/%s", names[n]);
lfs_file_open(&lfs, &file, path, lfs2_file_open(&lfs2, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_APPEND) => 0;
size = strlen(names[n]); size = strlen(names[n]);
memcpy(buffer, names[n], size); memcpy(buffer, names[n], size);
for (int i = 0; i < SIZE; i += size) { for (int i = 0; i < SIZE; i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs2_file_write(&lfs2, &file, buffer, size) => size;
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
} }
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &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; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
size = strlen(names[n]); size = strlen(names[n]);
for (int i = 0; i < SIZE; i += size) { for (int i = 0; i < SIZE; i += size) {
lfs_file_read(&lfs, &file, buffer, size) => size; lfs2_file_read(&lfs2, &file, buffer, size) => size;
assert(memcmp(buffer, names[n], size) == 0); assert(memcmp(buffer, names[n], size) == 0);
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
} }
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &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; lfs2_remove(&lfs2, path) => 0;
} }
lfs_remove(&lfs, "breakfast") => 0; lfs2_remove(&lfs2, "breakfast") => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
} }
''' '''
[[case]] # exhaustion test [[case]] # exhaustion test
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); lfs2_file_open(&lfs2, &file, "exhaustion", LFS2_O_WRONLY | LFS2_O_CREAT);
size = strlen("exhaustion"); size = strlen("exhaustion");
memcpy(buffer, "exhaustion", size); memcpy(buffer, "exhaustion", size);
lfs_file_write(&lfs, &file, buffer, size) => size; lfs2_file_write(&lfs2, &file, buffer, size) => size;
lfs_file_sync(&lfs, &file) => 0; lfs2_file_sync(&lfs2, &file) => 0;
size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
lfs_ssize_t res; lfs2_ssize_t res;
while (true) { while (true) {
res = lfs_file_write(&lfs, &file, buffer, size); res = lfs2_file_write(&lfs2, &file, buffer, size);
if (res < 0) { if (res < 0) {
break; break;
} }
res => size; res => size;
} }
res => LFS_ERR_NOSPC; res => LFS2_ERR_NOSPC;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_RDONLY); lfs2_file_open(&lfs2, &file, "exhaustion", LFS2_O_RDONLY);
size = strlen("exhaustion"); size = strlen("exhaustion");
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs2_file_read(&lfs2, &file, buffer, size) => size;
memcmp(buffer, "exhaustion", size) => 0; memcmp(buffer, "exhaustion", size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # exhaustion wraparound test [[case]] # exhaustion wraparound test
define.SIZE = '(((LFS_BLOCK_SIZE-8)*(LFS_BLOCK_COUNT-4)) / 3)' define.SIZE = '(((LFS2_BLOCK_SIZE-8)*(LFS2_BLOCK_COUNT-4)) / 3)'
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "padding", LFS_O_WRONLY | LFS_O_CREAT); lfs2_file_open(&lfs2, &file, "padding", LFS2_O_WRONLY | LFS2_O_CREAT);
size = strlen("buffering"); size = strlen("buffering");
memcpy(buffer, "buffering", size); memcpy(buffer, "buffering", size);
for (int i = 0; i < SIZE; i += size) { for (int i = 0; i < SIZE; i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs2_file_write(&lfs2, &file, buffer, size) => size;
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_remove(&lfs, "padding") => 0; lfs2_remove(&lfs2, "padding") => 0;
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); lfs2_file_open(&lfs2, &file, "exhaustion", LFS2_O_WRONLY | LFS2_O_CREAT);
size = strlen("exhaustion"); size = strlen("exhaustion");
memcpy(buffer, "exhaustion", size); memcpy(buffer, "exhaustion", size);
lfs_file_write(&lfs, &file, buffer, size) => size; lfs2_file_write(&lfs2, &file, buffer, size) => size;
lfs_file_sync(&lfs, &file) => 0; lfs2_file_sync(&lfs2, &file) => 0;
size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
lfs_ssize_t res; lfs2_ssize_t res;
while (true) { while (true) {
res = lfs_file_write(&lfs, &file, buffer, size); res = lfs2_file_write(&lfs2, &file, buffer, size);
if (res < 0) { if (res < 0) {
break; break;
} }
res => size; res => size;
} }
res => LFS_ERR_NOSPC; res => LFS2_ERR_NOSPC;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_RDONLY); lfs2_file_open(&lfs2, &file, "exhaustion", LFS2_O_RDONLY);
size = strlen("exhaustion"); size = strlen("exhaustion");
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs2_file_read(&lfs2, &file, buffer, size) => size;
memcmp(buffer, "exhaustion", size) => 0; memcmp(buffer, "exhaustion", size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_remove(&lfs, "exhaustion") => 0; lfs2_remove(&lfs2, "exhaustion") => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # dir exhaustion test [[case]] # dir exhaustion test
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
// find out max file size // find out max file size
lfs_mkdir(&lfs, "exhaustiondir") => 0; lfs2_mkdir(&lfs2, "exhaustiondir") => 0;
size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); lfs2_file_open(&lfs2, &file, "exhaustion", LFS2_O_WRONLY | LFS2_O_CREAT);
int count = 0; int count = 0;
while (true) { while (true) {
err = lfs_file_write(&lfs, &file, buffer, size); err = lfs2_file_write(&lfs2, &file, buffer, size);
if (err < 0) { if (err < 0) {
break; break;
} }
count += 1; count += 1;
} }
err => LFS_ERR_NOSPC; err => LFS2_ERR_NOSPC;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_remove(&lfs, "exhaustion") => 0; lfs2_remove(&lfs2, "exhaustion") => 0;
lfs_remove(&lfs, "exhaustiondir") => 0; lfs2_remove(&lfs2, "exhaustiondir") => 0;
// see if dir fits with max file size // see if dir fits with max file size
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); lfs2_file_open(&lfs2, &file, "exhaustion", LFS2_O_WRONLY | LFS2_O_CREAT);
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs2_file_write(&lfs2, &file, buffer, size) => size;
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_mkdir(&lfs, "exhaustiondir") => 0; lfs2_mkdir(&lfs2, "exhaustiondir") => 0;
lfs_remove(&lfs, "exhaustiondir") => 0; lfs2_remove(&lfs2, "exhaustiondir") => 0;
lfs_remove(&lfs, "exhaustion") => 0; lfs2_remove(&lfs2, "exhaustion") => 0;
// see if dir fits with > max file size // see if dir fits with > max file size
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); lfs2_file_open(&lfs2, &file, "exhaustion", LFS2_O_WRONLY | LFS2_O_CREAT);
for (int i = 0; i < count+1; i++) { for (int i = 0; i < count+1; i++) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs2_file_write(&lfs2, &file, buffer, size) => size;
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_mkdir(&lfs, "exhaustiondir") => LFS_ERR_NOSPC; lfs2_mkdir(&lfs2, "exhaustiondir") => LFS2_ERR_NOSPC;
lfs_remove(&lfs, "exhaustion") => 0; lfs2_remove(&lfs2, "exhaustion") => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # what if we have a bad block during an allocation scan? [[case]] # what if we have a bad block during an allocation scan?
in = "lfs.c" in = "lfs2.c"
define.LFS_ERASE_CYCLES = 0xffffffff define.LFS2_ERASE_CYCLES = 0xffffffff
define.LFS_BADBLOCK_BEHAVIOR = 'LFS_TESTBD_BADBLOCK_READERROR' define.LFS2_BADBLOCK_BEHAVIOR = 'LFS2_TESTBD_BADBLOCK_READERROR'
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &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; lfs2_file_open(&lfs2, &file, "pacman", LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
strcpy((char*)buffer, "waka"); strcpy((char*)buffer, "waka");
size = strlen("waka"); size = strlen("waka");
lfs_size_t filesize = 0; lfs2_size_t filesize = 0;
while (true) { while (true) {
lfs_ssize_t res = lfs_file_write(&lfs, &file, buffer, size); lfs2_ssize_t res = lfs2_file_write(&lfs2, &file, buffer, size);
assert(res == (lfs_ssize_t)size || res == LFS_ERR_NOSPC); assert(res == (lfs2_ssize_t)size || res == LFS2_ERR_NOSPC);
if (res == LFS_ERR_NOSPC) { if (res == LFS2_ERR_NOSPC) {
break; break;
} }
filesize += size; filesize += size;
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// now fill all but a couple of blocks of the filesystem with data // now fill all but a couple of blocks of the filesystem with data
filesize -= 3*LFS_BLOCK_SIZE; filesize -= 3*LFS2_BLOCK_SIZE;
lfs_file_open(&lfs, &file, "pacman", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs2_file_open(&lfs2, &file, "pacman", LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
strcpy((char*)buffer, "waka"); strcpy((char*)buffer, "waka");
size = strlen("waka"); size = strlen("waka");
for (lfs_size_t i = 0; i < filesize/size; i++) { for (lfs2_size_t i = 0; i < filesize/size; i++) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs2_file_write(&lfs2, &file, buffer, size) => size;
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// also save head of file so we can error during lookahead scan // also save head of file so we can error during lookahead scan
lfs_block_t fileblock = file.ctz.head; lfs2_block_t fileblock = file.ctz.head;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
// remount to force an alloc scan // remount to force an alloc scan
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &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; lfs2_testbd_setwear(&cfg, fileblock, 0xffffffff) => 0;
lfs_file_open(&lfs, &file, "ghost", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs2_file_open(&lfs2, &file, "ghost", LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
strcpy((char*)buffer, "chomp"); strcpy((char*)buffer, "chomp");
size = strlen("chomp"); size = strlen("chomp");
while (true) { while (true) {
lfs_ssize_t res = lfs_file_write(&lfs, &file, buffer, size); lfs2_ssize_t res = lfs2_file_write(&lfs2, &file, buffer, size);
assert(res == (lfs_ssize_t)size || res == LFS_ERR_CORRUPT); assert(res == (lfs2_ssize_t)size || res == LFS2_ERR_CORRUPT);
if (res == LFS_ERR_CORRUPT) { if (res == LFS2_ERR_CORRUPT) {
break; break;
} }
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// 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; lfs2_testbd_setwear(&cfg, fileblock, 0) => 0;
lfs_file_open(&lfs, &file, "ghost", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs2_file_open(&lfs2, &file, "ghost", LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
strcpy((char*)buffer, "chomp"); strcpy((char*)buffer, "chomp");
size = strlen("chomp"); size = strlen("chomp");
while (true) { while (true) {
lfs_ssize_t res = lfs_file_write(&lfs, &file, buffer, size); lfs2_ssize_t res = lfs2_file_write(&lfs2, &file, buffer, size);
assert(res == (lfs_ssize_t)size || res == LFS_ERR_NOSPC); assert(res == (lfs2_ssize_t)size || res == LFS2_ERR_NOSPC);
if (res == LFS_ERR_NOSPC) { if (res == LFS2_ERR_NOSPC) {
break; break;
} }
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
// check that the disk isn't hurt // check that the disk isn't hurt
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "pacman", LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, "pacman", LFS2_O_RDONLY) => 0;
strcpy((char*)buffer, "waka"); strcpy((char*)buffer, "waka");
size = strlen("waka"); size = strlen("waka");
for (lfs_size_t i = 0; i < filesize/size; i++) { for (lfs2_size_t i = 0; i < filesize/size; i++) {
uint8_t rbuffer[4]; uint8_t rbuffer[4];
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
assert(memcmp(rbuffer, buffer, size) == 0); assert(memcmp(rbuffer, buffer, size) == 0);
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
@@ -412,242 +412,242 @@ code = '''
# should be removed and replaced with generalized tests. # should be removed and replaced with generalized tests.
[[case]] # chained dir exhaustion test [[case]] # chained dir exhaustion test
define.LFS_BLOCK_SIZE = 512 define.LFS2_BLOCK_SIZE = 512
define.LFS_BLOCK_COUNT = 1024 define.LFS2_BLOCK_COUNT = 1024
if = 'LFS_BLOCK_SIZE == 512 && LFS_BLOCK_COUNT == 1024' if = 'LFS2_BLOCK_SIZE == 512 && LFS2_BLOCK_COUNT == 1024'
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
// find out max file size // find out max file size
lfs_mkdir(&lfs, "exhaustiondir") => 0; lfs2_mkdir(&lfs2, "exhaustiondir") => 0;
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
sprintf(path, "dirwithanexhaustivelylongnameforpadding%d", i); sprintf(path, "dirwithanexhaustivelylongnameforpadding%d", i);
lfs_mkdir(&lfs, path) => 0; lfs2_mkdir(&lfs2, path) => 0;
} }
size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); lfs2_file_open(&lfs2, &file, "exhaustion", LFS2_O_WRONLY | LFS2_O_CREAT);
int count = 0; int count = 0;
while (true) { while (true) {
err = lfs_file_write(&lfs, &file, buffer, size); err = lfs2_file_write(&lfs2, &file, buffer, size);
if (err < 0) { if (err < 0) {
break; break;
} }
count += 1; count += 1;
} }
err => LFS_ERR_NOSPC; err => LFS2_ERR_NOSPC;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_remove(&lfs, "exhaustion") => 0; lfs2_remove(&lfs2, "exhaustion") => 0;
lfs_remove(&lfs, "exhaustiondir") => 0; lfs2_remove(&lfs2, "exhaustiondir") => 0;
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
sprintf(path, "dirwithanexhaustivelylongnameforpadding%d", i); sprintf(path, "dirwithanexhaustivelylongnameforpadding%d", i);
lfs_remove(&lfs, path) => 0; lfs2_remove(&lfs2, path) => 0;
} }
// see that chained dir fails // see that chained dir fails
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); lfs2_file_open(&lfs2, &file, "exhaustion", LFS2_O_WRONLY | LFS2_O_CREAT);
for (int i = 0; i < count+1; i++) { for (int i = 0; i < count+1; i++) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs2_file_write(&lfs2, &file, buffer, size) => size;
} }
lfs_file_sync(&lfs, &file) => 0; lfs2_file_sync(&lfs2, &file) => 0;
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
sprintf(path, "dirwithanexhaustivelylongnameforpadding%d", i); sprintf(path, "dirwithanexhaustivelylongnameforpadding%d", i);
lfs_mkdir(&lfs, path) => 0; lfs2_mkdir(&lfs2, path) => 0;
} }
lfs_mkdir(&lfs, "exhaustiondir") => LFS_ERR_NOSPC; lfs2_mkdir(&lfs2, "exhaustiondir") => LFS2_ERR_NOSPC;
// shorten file to try a second chained dir // shorten file to try a second chained dir
while (true) { while (true) {
err = lfs_mkdir(&lfs, "exhaustiondir"); err = lfs2_mkdir(&lfs2, "exhaustiondir");
if (err != LFS_ERR_NOSPC) { if (err != LFS2_ERR_NOSPC) {
break; break;
} }
lfs_ssize_t filesize = lfs_file_size(&lfs, &file); lfs2_ssize_t filesize = lfs2_file_size(&lfs2, &file);
filesize > 0 => true; filesize > 0 => true;
lfs_file_truncate(&lfs, &file, filesize - size) => 0; lfs2_file_truncate(&lfs2, &file, filesize - size) => 0;
lfs_file_sync(&lfs, &file) => 0; lfs2_file_sync(&lfs2, &file) => 0;
} }
err => 0; err => 0;
lfs_mkdir(&lfs, "exhaustiondir2") => LFS_ERR_NOSPC; lfs2_mkdir(&lfs2, "exhaustiondir2") => LFS2_ERR_NOSPC;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # split dir test [[case]] # split dir test
define.LFS_BLOCK_SIZE = 512 define.LFS2_BLOCK_SIZE = 512
define.LFS_BLOCK_COUNT = 1024 define.LFS2_BLOCK_COUNT = 1024
if = 'LFS_BLOCK_SIZE == 512 && LFS_BLOCK_COUNT == 1024' if = 'LFS2_BLOCK_SIZE == 512 && LFS2_BLOCK_COUNT == 1024'
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &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; lfs2_file_open(&lfs2, &file, "bump", LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
for (lfs_size_t i = 0; i < cfg.block_size; i += 2) { for (lfs2_size_t i = 0; i < cfg.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; lfs2_file_write(&lfs2, &file, buffer, cfg.block_size) => cfg.block_size;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); lfs2_file_open(&lfs2, &file, "exhaustion", LFS2_O_WRONLY | LFS2_O_CREAT);
size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0; for (lfs2_size_t i = 0;
i < (cfg.block_count-4)*(cfg.block_size-8); i < (cfg.block_count-4)*(cfg.block_size-8);
i += size) { i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs2_file_write(&lfs2, &file, buffer, size) => size;
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// remount to force reset of lookahead // remount to force reset of lookahead
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
// open hole // open hole
lfs_remove(&lfs, "bump") => 0; lfs2_remove(&lfs2, "bump") => 0;
lfs_mkdir(&lfs, "splitdir") => 0; lfs2_mkdir(&lfs2, "splitdir") => 0;
lfs_file_open(&lfs, &file, "splitdir/bump", lfs2_file_open(&lfs2, &file, "splitdir/bump",
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
for (lfs_size_t i = 0; i < cfg.block_size; i += 2) { for (lfs2_size_t i = 0; i < cfg.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; lfs2_file_write(&lfs2, &file, buffer, 2*cfg.block_size) => LFS2_ERR_NOSPC;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # outdated lookahead test [[case]] # outdated lookahead test
define.LFS_BLOCK_SIZE = 512 define.LFS2_BLOCK_SIZE = 512
define.LFS_BLOCK_COUNT = 1024 define.LFS2_BLOCK_COUNT = 1024
if = 'LFS_BLOCK_SIZE == 512 && LFS_BLOCK_COUNT == 1024' if = 'LFS2_BLOCK_SIZE == 512 && LFS2_BLOCK_COUNT == 1024'
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
// fill completely with two files // fill completely with two files
lfs_file_open(&lfs, &file, "exhaustion1", lfs2_file_open(&lfs2, &file, "exhaustion1",
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0; for (lfs2_size_t i = 0;
i < ((cfg.block_count-2)/2)*(cfg.block_size-8); i < ((cfg.block_count-2)/2)*(cfg.block_size-8);
i += size) { i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs2_file_write(&lfs2, &file, buffer, size) => size;
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_file_open(&lfs, &file, "exhaustion2", lfs2_file_open(&lfs2, &file, "exhaustion2",
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0; for (lfs2_size_t i = 0;
i < ((cfg.block_count-2+1)/2)*(cfg.block_size-8); i < ((cfg.block_count-2+1)/2)*(cfg.block_size-8);
i += size) { i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs2_file_write(&lfs2, &file, buffer, size) => size;
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// remount to force reset of lookahead // remount to force reset of lookahead
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
// rewrite one file // rewrite one file
lfs_file_open(&lfs, &file, "exhaustion1", lfs2_file_open(&lfs2, &file, "exhaustion1",
LFS_O_WRONLY | LFS_O_TRUNC) => 0; LFS2_O_WRONLY | LFS2_O_TRUNC) => 0;
lfs_file_sync(&lfs, &file) => 0; lfs2_file_sync(&lfs2, &file) => 0;
size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0; for (lfs2_size_t i = 0;
i < ((cfg.block_count-2)/2)*(cfg.block_size-8); i < ((cfg.block_count-2)/2)*(cfg.block_size-8);
i += size) { i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs2_file_write(&lfs2, &file, buffer, size) => size;
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// rewrite second file, this requires lookahead does not // rewrite second file, this requires lookahead does not
// use old population // use old population
lfs_file_open(&lfs, &file, "exhaustion2", lfs2_file_open(&lfs2, &file, "exhaustion2",
LFS_O_WRONLY | LFS_O_TRUNC) => 0; LFS2_O_WRONLY | LFS2_O_TRUNC) => 0;
lfs_file_sync(&lfs, &file) => 0; lfs2_file_sync(&lfs2, &file) => 0;
size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0; for (lfs2_size_t i = 0;
i < ((cfg.block_count-2+1)/2)*(cfg.block_size-8); i < ((cfg.block_count-2+1)/2)*(cfg.block_size-8);
i += size) { i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs2_file_write(&lfs2, &file, buffer, size) => size;
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # outdated lookahead and split dir test [[case]] # outdated lookahead and split dir test
define.LFS_BLOCK_SIZE = 512 define.LFS2_BLOCK_SIZE = 512
define.LFS_BLOCK_COUNT = 1024 define.LFS2_BLOCK_COUNT = 1024
if = 'LFS_BLOCK_SIZE == 512 && LFS_BLOCK_COUNT == 1024' if = 'LFS2_BLOCK_SIZE == 512 && LFS2_BLOCK_COUNT == 1024'
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
// fill completely with two files // fill completely with two files
lfs_file_open(&lfs, &file, "exhaustion1", lfs2_file_open(&lfs2, &file, "exhaustion1",
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0; for (lfs2_size_t i = 0;
i < ((cfg.block_count-2)/2)*(cfg.block_size-8); i < ((cfg.block_count-2)/2)*(cfg.block_size-8);
i += size) { i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs2_file_write(&lfs2, &file, buffer, size) => size;
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_file_open(&lfs, &file, "exhaustion2", lfs2_file_open(&lfs2, &file, "exhaustion2",
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0; for (lfs2_size_t i = 0;
i < ((cfg.block_count-2+1)/2)*(cfg.block_size-8); i < ((cfg.block_count-2+1)/2)*(cfg.block_size-8);
i += size) { i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs2_file_write(&lfs2, &file, buffer, size) => size;
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// remount to force reset of lookahead // remount to force reset of lookahead
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &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", lfs2_file_open(&lfs2, &file, "exhaustion1",
LFS_O_WRONLY | LFS_O_TRUNC) => 0; LFS2_O_WRONLY | LFS2_O_TRUNC) => 0;
lfs_file_sync(&lfs, &file) => 0; lfs2_file_sync(&lfs2, &file) => 0;
size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0; for (lfs2_size_t i = 0;
i < ((cfg.block_count-2)/2 - 1)*(cfg.block_size-8); i < ((cfg.block_count-2)/2 - 1)*(cfg.block_size-8);
i += size) { i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs2_file_write(&lfs2, &file, buffer, size) => size;
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// try to allocate a directory, should fail! // try to allocate a directory, should fail!
lfs_mkdir(&lfs, "split") => LFS_ERR_NOSPC; lfs2_mkdir(&lfs2, "split") => LFS2_ERR_NOSPC;
// file should not fail // file should not fail
lfs_file_open(&lfs, &file, "notasplit", lfs2_file_open(&lfs2, &file, "notasplit",
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
lfs_file_write(&lfs, &file, "hi", 2) => 2; lfs2_file_write(&lfs2, &file, "hi", 2) => 2;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''

View File

@@ -1,304 +1,304 @@
[[case]] # set/get attribute [[case]] # set/get attribute
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_mkdir(&lfs, "hello") => 0; lfs2_mkdir(&lfs2, "hello") => 0;
lfs_file_open(&lfs, &file, "hello/hello", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs2_file_open(&lfs2, &file, "hello/hello", LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
lfs_file_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello"); lfs2_file_write(&lfs2, &file, "hello", strlen("hello")) => strlen("hello");
lfs_file_close(&lfs, &file); lfs2_file_close(&lfs2, &file);
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
memset(buffer, 0, sizeof(buffer)); memset(buffer, 0, sizeof(buffer));
lfs_setattr(&lfs, "hello", 'A', "aaaa", 4) => 0; lfs2_setattr(&lfs2, "hello", 'A', "aaaa", 4) => 0;
lfs_setattr(&lfs, "hello", 'B', "bbbbbb", 6) => 0; lfs2_setattr(&lfs2, "hello", 'B', "bbbbbb", 6) => 0;
lfs_setattr(&lfs, "hello", 'C', "ccccc", 5) => 0; lfs2_setattr(&lfs2, "hello", 'C', "ccccc", 5) => 0;
lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4; lfs2_getattr(&lfs2, "hello", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => 6; lfs2_getattr(&lfs2, "hello", 'B', buffer+4, 6) => 6;
lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; lfs2_getattr(&lfs2, "hello", 'C', buffer+10, 5) => 5;
memcmp(buffer, "aaaa", 4) => 0; memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "bbbbbb", 6) => 0; memcmp(buffer+4, "bbbbbb", 6) => 0;
memcmp(buffer+10, "ccccc", 5) => 0; memcmp(buffer+10, "ccccc", 5) => 0;
lfs_setattr(&lfs, "hello", 'B', "", 0) => 0; lfs2_setattr(&lfs2, "hello", 'B', "", 0) => 0;
lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4; lfs2_getattr(&lfs2, "hello", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => 0; lfs2_getattr(&lfs2, "hello", 'B', buffer+4, 6) => 0;
lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; lfs2_getattr(&lfs2, "hello", 'C', buffer+10, 5) => 5;
memcmp(buffer, "aaaa", 4) => 0; memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "\0\0\0\0\0\0", 6) => 0; memcmp(buffer+4, "\0\0\0\0\0\0", 6) => 0;
memcmp(buffer+10, "ccccc", 5) => 0; memcmp(buffer+10, "ccccc", 5) => 0;
lfs_removeattr(&lfs, "hello", 'B') => 0; lfs2_removeattr(&lfs2, "hello", 'B') => 0;
lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4; lfs2_getattr(&lfs2, "hello", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => LFS_ERR_NOATTR; lfs2_getattr(&lfs2, "hello", 'B', buffer+4, 6) => LFS2_ERR_NOATTR;
lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; lfs2_getattr(&lfs2, "hello", 'C', buffer+10, 5) => 5;
memcmp(buffer, "aaaa", 4) => 0; memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "\0\0\0\0\0\0", 6) => 0; memcmp(buffer+4, "\0\0\0\0\0\0", 6) => 0;
memcmp(buffer+10, "ccccc", 5) => 0; memcmp(buffer+10, "ccccc", 5) => 0;
lfs_setattr(&lfs, "hello", 'B', "dddddd", 6) => 0; lfs2_setattr(&lfs2, "hello", 'B', "dddddd", 6) => 0;
lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4; lfs2_getattr(&lfs2, "hello", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => 6; lfs2_getattr(&lfs2, "hello", 'B', buffer+4, 6) => 6;
lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; lfs2_getattr(&lfs2, "hello", 'C', buffer+10, 5) => 5;
memcmp(buffer, "aaaa", 4) => 0; memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "dddddd", 6) => 0; memcmp(buffer+4, "dddddd", 6) => 0;
memcmp(buffer+10, "ccccc", 5) => 0; memcmp(buffer+10, "ccccc", 5) => 0;
lfs_setattr(&lfs, "hello", 'B', "eee", 3) => 0; lfs2_setattr(&lfs2, "hello", 'B', "eee", 3) => 0;
lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4; lfs2_getattr(&lfs2, "hello", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => 3; lfs2_getattr(&lfs2, "hello", 'B', buffer+4, 6) => 3;
lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; lfs2_getattr(&lfs2, "hello", 'C', buffer+10, 5) => 5;
memcmp(buffer, "aaaa", 4) => 0; memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "eee\0\0\0", 6) => 0; memcmp(buffer+4, "eee\0\0\0", 6) => 0;
memcmp(buffer+10, "ccccc", 5) => 0; memcmp(buffer+10, "ccccc", 5) => 0;
lfs_setattr(&lfs, "hello", 'A', buffer, LFS_ATTR_MAX+1) => LFS_ERR_NOSPC; lfs2_setattr(&lfs2, "hello", 'A', buffer, LFS2_ATTR_MAX+1) => LFS2_ERR_NOSPC;
lfs_setattr(&lfs, "hello", 'B', "fffffffff", 9) => 0; lfs2_setattr(&lfs2, "hello", 'B', "fffffffff", 9) => 0;
lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4; lfs2_getattr(&lfs2, "hello", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => 9; lfs2_getattr(&lfs2, "hello", 'B', buffer+4, 6) => 9;
lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; lfs2_getattr(&lfs2, "hello", 'C', buffer+10, 5) => 5;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
memset(buffer, 0, sizeof(buffer)); memset(buffer, 0, sizeof(buffer));
lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4; lfs2_getattr(&lfs2, "hello", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "hello", 'B', buffer+4, 9) => 9; lfs2_getattr(&lfs2, "hello", 'B', buffer+4, 9) => 9;
lfs_getattr(&lfs, "hello", 'C', buffer+13, 5) => 5; lfs2_getattr(&lfs2, "hello", 'C', buffer+13, 5) => 5;
memcmp(buffer, "aaaa", 4) => 0; memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "fffffffff", 9) => 0; memcmp(buffer+4, "fffffffff", 9) => 0;
memcmp(buffer+13, "ccccc", 5) => 0; memcmp(buffer+13, "ccccc", 5) => 0;
lfs_file_open(&lfs, &file, "hello/hello", LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, "hello/hello", LFS2_O_RDONLY) => 0;
lfs_file_read(&lfs, &file, buffer, sizeof(buffer)) => strlen("hello"); lfs2_file_read(&lfs2, &file, buffer, sizeof(buffer)) => strlen("hello");
memcmp(buffer, "hello", strlen("hello")) => 0; memcmp(buffer, "hello", strlen("hello")) => 0;
lfs_file_close(&lfs, &file); lfs2_file_close(&lfs2, &file);
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # set/get root attribute [[case]] # set/get root attribute
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_mkdir(&lfs, "hello") => 0; lfs2_mkdir(&lfs2, "hello") => 0;
lfs_file_open(&lfs, &file, "hello/hello", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs2_file_open(&lfs2, &file, "hello/hello", LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
lfs_file_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello"); lfs2_file_write(&lfs2, &file, "hello", strlen("hello")) => strlen("hello");
lfs_file_close(&lfs, &file); lfs2_file_close(&lfs2, &file);
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
memset(buffer, 0, sizeof(buffer)); memset(buffer, 0, sizeof(buffer));
lfs_setattr(&lfs, "/", 'A', "aaaa", 4) => 0; lfs2_setattr(&lfs2, "/", 'A', "aaaa", 4) => 0;
lfs_setattr(&lfs, "/", 'B', "bbbbbb", 6) => 0; lfs2_setattr(&lfs2, "/", 'B', "bbbbbb", 6) => 0;
lfs_setattr(&lfs, "/", 'C', "ccccc", 5) => 0; lfs2_setattr(&lfs2, "/", 'C', "ccccc", 5) => 0;
lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4; lfs2_getattr(&lfs2, "/", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 6; lfs2_getattr(&lfs2, "/", 'B', buffer+4, 6) => 6;
lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; lfs2_getattr(&lfs2, "/", 'C', buffer+10, 5) => 5;
memcmp(buffer, "aaaa", 4) => 0; memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "bbbbbb", 6) => 0; memcmp(buffer+4, "bbbbbb", 6) => 0;
memcmp(buffer+10, "ccccc", 5) => 0; memcmp(buffer+10, "ccccc", 5) => 0;
lfs_setattr(&lfs, "/", 'B', "", 0) => 0; lfs2_setattr(&lfs2, "/", 'B', "", 0) => 0;
lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4; lfs2_getattr(&lfs2, "/", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 0; lfs2_getattr(&lfs2, "/", 'B', buffer+4, 6) => 0;
lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; lfs2_getattr(&lfs2, "/", 'C', buffer+10, 5) => 5;
memcmp(buffer, "aaaa", 4) => 0; memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "\0\0\0\0\0\0", 6) => 0; memcmp(buffer+4, "\0\0\0\0\0\0", 6) => 0;
memcmp(buffer+10, "ccccc", 5) => 0; memcmp(buffer+10, "ccccc", 5) => 0;
lfs_removeattr(&lfs, "/", 'B') => 0; lfs2_removeattr(&lfs2, "/", 'B') => 0;
lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4; lfs2_getattr(&lfs2, "/", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => LFS_ERR_NOATTR; lfs2_getattr(&lfs2, "/", 'B', buffer+4, 6) => LFS2_ERR_NOATTR;
lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; lfs2_getattr(&lfs2, "/", 'C', buffer+10, 5) => 5;
memcmp(buffer, "aaaa", 4) => 0; memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "\0\0\0\0\0\0", 6) => 0; memcmp(buffer+4, "\0\0\0\0\0\0", 6) => 0;
memcmp(buffer+10, "ccccc", 5) => 0; memcmp(buffer+10, "ccccc", 5) => 0;
lfs_setattr(&lfs, "/", 'B', "dddddd", 6) => 0; lfs2_setattr(&lfs2, "/", 'B', "dddddd", 6) => 0;
lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4; lfs2_getattr(&lfs2, "/", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 6; lfs2_getattr(&lfs2, "/", 'B', buffer+4, 6) => 6;
lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; lfs2_getattr(&lfs2, "/", 'C', buffer+10, 5) => 5;
memcmp(buffer, "aaaa", 4) => 0; memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "dddddd", 6) => 0; memcmp(buffer+4, "dddddd", 6) => 0;
memcmp(buffer+10, "ccccc", 5) => 0; memcmp(buffer+10, "ccccc", 5) => 0;
lfs_setattr(&lfs, "/", 'B', "eee", 3) => 0; lfs2_setattr(&lfs2, "/", 'B', "eee", 3) => 0;
lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4; lfs2_getattr(&lfs2, "/", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 3; lfs2_getattr(&lfs2, "/", 'B', buffer+4, 6) => 3;
lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; lfs2_getattr(&lfs2, "/", 'C', buffer+10, 5) => 5;
memcmp(buffer, "aaaa", 4) => 0; memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "eee\0\0\0", 6) => 0; memcmp(buffer+4, "eee\0\0\0", 6) => 0;
memcmp(buffer+10, "ccccc", 5) => 0; memcmp(buffer+10, "ccccc", 5) => 0;
lfs_setattr(&lfs, "/", 'A', buffer, LFS_ATTR_MAX+1) => LFS_ERR_NOSPC; lfs2_setattr(&lfs2, "/", 'A', buffer, LFS2_ATTR_MAX+1) => LFS2_ERR_NOSPC;
lfs_setattr(&lfs, "/", 'B', "fffffffff", 9) => 0; lfs2_setattr(&lfs2, "/", 'B', "fffffffff", 9) => 0;
lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4; lfs2_getattr(&lfs2, "/", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 9; lfs2_getattr(&lfs2, "/", 'B', buffer+4, 6) => 9;
lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; lfs2_getattr(&lfs2, "/", 'C', buffer+10, 5) => 5;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
memset(buffer, 0, sizeof(buffer)); memset(buffer, 0, sizeof(buffer));
lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4; lfs2_getattr(&lfs2, "/", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "/", 'B', buffer+4, 9) => 9; lfs2_getattr(&lfs2, "/", 'B', buffer+4, 9) => 9;
lfs_getattr(&lfs, "/", 'C', buffer+13, 5) => 5; lfs2_getattr(&lfs2, "/", 'C', buffer+13, 5) => 5;
memcmp(buffer, "aaaa", 4) => 0; memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "fffffffff", 9) => 0; memcmp(buffer+4, "fffffffff", 9) => 0;
memcmp(buffer+13, "ccccc", 5) => 0; memcmp(buffer+13, "ccccc", 5) => 0;
lfs_file_open(&lfs, &file, "hello/hello", LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, "hello/hello", LFS2_O_RDONLY) => 0;
lfs_file_read(&lfs, &file, buffer, sizeof(buffer)) => strlen("hello"); lfs2_file_read(&lfs2, &file, buffer, sizeof(buffer)) => strlen("hello");
memcmp(buffer, "hello", strlen("hello")) => 0; memcmp(buffer, "hello", strlen("hello")) => 0;
lfs_file_close(&lfs, &file); lfs2_file_close(&lfs2, &file);
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # set/get file attribute [[case]] # set/get file attribute
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_mkdir(&lfs, "hello") => 0; lfs2_mkdir(&lfs2, "hello") => 0;
lfs_file_open(&lfs, &file, "hello/hello", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs2_file_open(&lfs2, &file, "hello/hello", LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
lfs_file_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello"); lfs2_file_write(&lfs2, &file, "hello", strlen("hello")) => strlen("hello");
lfs_file_close(&lfs, &file); lfs2_file_close(&lfs2, &file);
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
memset(buffer, 0, sizeof(buffer)); memset(buffer, 0, sizeof(buffer));
struct lfs_attr attrs1[] = { struct lfs2_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 lfs2_file_config cfg1 = {.attrs=attrs1, .attr_count=3};
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0; lfs2_file_opencfg(&lfs2, &file, "hello/hello", LFS2_O_WRONLY, &cfg1) => 0;
memcpy(buffer, "aaaa", 4); memcpy(buffer, "aaaa", 4);
memcpy(buffer+4, "bbbbbb", 6); memcpy(buffer+4, "bbbbbb", 6);
memcpy(buffer+10, "ccccc", 5); memcpy(buffer+10, "ccccc", 5);
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
memset(buffer, 0, 15); memset(buffer, 0, 15);
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0; lfs2_file_opencfg(&lfs2, &file, "hello/hello", LFS2_O_RDONLY, &cfg1) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
memcmp(buffer, "aaaa", 4) => 0; memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "bbbbbb", 6) => 0; memcmp(buffer+4, "bbbbbb", 6) => 0;
memcmp(buffer+10, "ccccc", 5) => 0; memcmp(buffer+10, "ccccc", 5) => 0;
attrs1[1].size = 0; attrs1[1].size = 0;
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0; lfs2_file_opencfg(&lfs2, &file, "hello/hello", LFS2_O_WRONLY, &cfg1) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
memset(buffer, 0, 15); memset(buffer, 0, 15);
attrs1[1].size = 6; attrs1[1].size = 6;
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0; lfs2_file_opencfg(&lfs2, &file, "hello/hello", LFS2_O_RDONLY, &cfg1) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
memcmp(buffer, "aaaa", 4) => 0; memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "\0\0\0\0\0\0", 6) => 0; memcmp(buffer+4, "\0\0\0\0\0\0", 6) => 0;
memcmp(buffer+10, "ccccc", 5) => 0; memcmp(buffer+10, "ccccc", 5) => 0;
attrs1[1].size = 6; attrs1[1].size = 6;
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0; lfs2_file_opencfg(&lfs2, &file, "hello/hello", LFS2_O_WRONLY, &cfg1) => 0;
memcpy(buffer+4, "dddddd", 6); memcpy(buffer+4, "dddddd", 6);
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
memset(buffer, 0, 15); memset(buffer, 0, 15);
attrs1[1].size = 6; attrs1[1].size = 6;
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0; lfs2_file_opencfg(&lfs2, &file, "hello/hello", LFS2_O_RDONLY, &cfg1) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
memcmp(buffer, "aaaa", 4) => 0; memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "dddddd", 6) => 0; memcmp(buffer+4, "dddddd", 6) => 0;
memcmp(buffer+10, "ccccc", 5) => 0; memcmp(buffer+10, "ccccc", 5) => 0;
attrs1[1].size = 3; attrs1[1].size = 3;
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0; lfs2_file_opencfg(&lfs2, &file, "hello/hello", LFS2_O_WRONLY, &cfg1) => 0;
memcpy(buffer+4, "eee", 3); memcpy(buffer+4, "eee", 3);
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
memset(buffer, 0, 15); memset(buffer, 0, 15);
attrs1[1].size = 6; attrs1[1].size = 6;
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0; lfs2_file_opencfg(&lfs2, &file, "hello/hello", LFS2_O_RDONLY, &cfg1) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
memcmp(buffer, "aaaa", 4) => 0; memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "eee\0\0\0", 6) => 0; memcmp(buffer+4, "eee\0\0\0", 6) => 0;
memcmp(buffer+10, "ccccc", 5) => 0; memcmp(buffer+10, "ccccc", 5) => 0;
attrs1[0].size = LFS_ATTR_MAX+1; attrs1[0].size = LFS2_ATTR_MAX+1;
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) lfs2_file_opencfg(&lfs2, &file, "hello/hello", LFS2_O_WRONLY, &cfg1)
=> LFS_ERR_NOSPC; => LFS2_ERR_NOSPC;
struct lfs_attr attrs2[] = { struct lfs2_attr attrs2[] = {
{'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 cfg2 = {.attrs=attrs2, .attr_count=3}; struct lfs2_file_config cfg2 = {.attrs=attrs2, .attr_count=3};
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDWR, &cfg2) => 0; lfs2_file_opencfg(&lfs2, &file, "hello/hello", LFS2_O_RDWR, &cfg2) => 0;
memcpy(buffer+4, "fffffffff", 9); memcpy(buffer+4, "fffffffff", 9);
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
attrs1[0].size = 4; attrs1[0].size = 4;
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0; lfs2_file_opencfg(&lfs2, &file, "hello/hello", LFS2_O_RDONLY, &cfg1) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
memset(buffer, 0, sizeof(buffer)); memset(buffer, 0, sizeof(buffer));
struct lfs_attr attrs3[] = { struct lfs2_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 lfs2_file_config cfg3 = {.attrs=attrs3, .attr_count=3};
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg3) => 0; lfs2_file_opencfg(&lfs2, &file, "hello/hello", LFS2_O_RDONLY, &cfg3) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
memcmp(buffer, "aaaa", 4) => 0; memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "fffffffff", 9) => 0; memcmp(buffer+4, "fffffffff", 9) => 0;
memcmp(buffer+13, "ccccc", 5) => 0; memcmp(buffer+13, "ccccc", 5) => 0;
lfs_file_open(&lfs, &file, "hello/hello", LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, "hello/hello", LFS2_O_RDONLY) => 0;
lfs_file_read(&lfs, &file, buffer, sizeof(buffer)) => strlen("hello"); lfs2_file_read(&lfs2, &file, buffer, sizeof(buffer)) => strlen("hello");
memcmp(buffer, "hello", strlen("hello")) => 0; memcmp(buffer, "hello", strlen("hello")) => 0;
lfs_file_close(&lfs, &file); lfs2_file_close(&lfs2, &file);
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # deferred file attributes [[case]] # deferred file attributes
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_mkdir(&lfs, "hello") => 0; lfs2_mkdir(&lfs2, "hello") => 0;
lfs_file_open(&lfs, &file, "hello/hello", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs2_file_open(&lfs2, &file, "hello/hello", LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
lfs_file_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello"); lfs2_file_write(&lfs2, &file, "hello", strlen("hello")) => strlen("hello");
lfs_file_close(&lfs, &file); lfs2_file_close(&lfs2, &file);
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_setattr(&lfs, "hello/hello", 'B', "fffffffff", 9) => 0; lfs2_setattr(&lfs2, "hello/hello", 'B', "fffffffff", 9) => 0;
lfs_setattr(&lfs, "hello/hello", 'C', "ccccc", 5) => 0; lfs2_setattr(&lfs2, "hello/hello", 'C', "ccccc", 5) => 0;
memset(buffer, 0, sizeof(buffer)); memset(buffer, 0, sizeof(buffer));
struct lfs_attr attrs1[] = { struct lfs2_attr attrs1[] = {
{'B', "gggg", 4}, {'B', "gggg", 4},
{'C', "", 0}, {'C', "", 0},
{'D', "hhhh", 4}, {'D', "hhhh", 4},
}; };
struct lfs_file_config cfg1 = {.attrs=attrs1, .attr_count=3}; struct lfs2_file_config cfg1 = {.attrs=attrs1, .attr_count=3};
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0; lfs2_file_opencfg(&lfs2, &file, "hello/hello", LFS2_O_WRONLY, &cfg1) => 0;
lfs_getattr(&lfs, "hello/hello", 'B', buffer, 9) => 9; lfs2_getattr(&lfs2, "hello/hello", 'B', buffer, 9) => 9;
lfs_getattr(&lfs, "hello/hello", 'C', buffer+9, 9) => 5; lfs2_getattr(&lfs2, "hello/hello", 'C', buffer+9, 9) => 5;
lfs_getattr(&lfs, "hello/hello", 'D', buffer+18, 9) => LFS_ERR_NOATTR; lfs2_getattr(&lfs2, "hello/hello", 'D', buffer+18, 9) => LFS2_ERR_NOATTR;
memcmp(buffer, "fffffffff", 9) => 0; memcmp(buffer, "fffffffff", 9) => 0;
memcmp(buffer+9, "ccccc\0\0\0\0", 9) => 0; memcmp(buffer+9, "ccccc\0\0\0\0", 9) => 0;
memcmp(buffer+18, "\0\0\0\0\0\0\0\0\0", 9) => 0; memcmp(buffer+18, "\0\0\0\0\0\0\0\0\0", 9) => 0;
lfs_file_sync(&lfs, &file) => 0; lfs2_file_sync(&lfs2, &file) => 0;
lfs_getattr(&lfs, "hello/hello", 'B', buffer, 9) => 4; lfs2_getattr(&lfs2, "hello/hello", 'B', buffer, 9) => 4;
lfs_getattr(&lfs, "hello/hello", 'C', buffer+9, 9) => 0; lfs2_getattr(&lfs2, "hello/hello", 'C', buffer+9, 9) => 0;
lfs_getattr(&lfs, "hello/hello", 'D', buffer+18, 9) => 4; lfs2_getattr(&lfs2, "hello/hello", 'D', buffer+18, 9) => 4;
memcmp(buffer, "gggg\0\0\0\0\0", 9) => 0; memcmp(buffer, "gggg\0\0\0\0\0", 9) => 0;
memcmp(buffer+9, "\0\0\0\0\0\0\0\0\0", 9) => 0; memcmp(buffer+9, "\0\0\0\0\0\0\0\0\0", 9) => 0;
memcmp(buffer+18, "hhhh\0\0\0\0\0", 9) => 0; memcmp(buffer+18, "hhhh\0\0\0\0\0", 9) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''

View File

@@ -1,241 +1,241 @@
# bad blocks with block cycles should be tested in test_relocations # bad blocks with block cycles should be tested in test_relocations
if = 'LFS_BLOCK_CYCLES == -1' if = 'LFS2_BLOCK_CYCLES == -1'
[[case]] # single bad blocks [[case]] # single bad blocks
define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster define.LFS2_BLOCK_COUNT = 256 # small bd so test runs faster
define.LFS_ERASE_CYCLES = 0xffffffff define.LFS2_ERASE_CYCLES = 0xffffffff
define.LFS_ERASE_VALUE = [0x00, 0xff, -1] define.LFS2_ERASE_VALUE = [0x00, 0xff, -1]
define.LFS_BADBLOCK_BEHAVIOR = [ define.LFS2_BADBLOCK_BEHAVIOR = [
'LFS_TESTBD_BADBLOCK_PROGERROR', 'LFS2_TESTBD_BADBLOCK_PROGERROR',
'LFS_TESTBD_BADBLOCK_ERASEERROR', 'LFS2_TESTBD_BADBLOCK_ERASEERROR',
'LFS_TESTBD_BADBLOCK_READERROR', 'LFS2_TESTBD_BADBLOCK_READERROR',
'LFS_TESTBD_BADBLOCK_PROGNOOP', 'LFS2_TESTBD_BADBLOCK_PROGNOOP',
'LFS_TESTBD_BADBLOCK_ERASENOOP', 'LFS2_TESTBD_BADBLOCK_ERASENOOP',
] ]
define.NAMEMULT = 64 define.NAMEMULT = 64
define.FILEMULT = 1 define.FILEMULT = 1
code = ''' code = '''
for (lfs_block_t badblock = 2; badblock < LFS_BLOCK_COUNT; badblock++) { for (lfs2_block_t badblock = 2; badblock < LFS2_BLOCK_COUNT; badblock++) {
lfs_testbd_setwear(&cfg, badblock-1, 0) => 0; lfs2_testbd_setwear(&cfg, badblock-1, 0) => 0;
lfs_testbd_setwear(&cfg, badblock, 0xffffffff) => 0; lfs2_testbd_setwear(&cfg, badblock, 0xffffffff) => 0;
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &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;
} }
buffer[NAMEMULT] = '\0'; buffer[NAMEMULT] = '\0';
lfs_mkdir(&lfs, (char*)buffer) => 0; lfs2_mkdir(&lfs2, (char*)buffer) => 0;
buffer[NAMEMULT] = '/'; buffer[NAMEMULT] = '/';
for (int j = 0; j < NAMEMULT; j++) { for (int j = 0; j < NAMEMULT; j++) {
buffer[j+NAMEMULT+1] = '0'+i; buffer[j+NAMEMULT+1] = '0'+i;
} }
buffer[2*NAMEMULT+1] = '\0'; buffer[2*NAMEMULT+1] = '\0';
lfs_file_open(&lfs, &file, (char*)buffer, lfs2_file_open(&lfs2, &file, (char*)buffer,
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
size = NAMEMULT; size = NAMEMULT;
for (int j = 0; j < i*FILEMULT; j++) { for (int j = 0; j < i*FILEMULT; j++) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs2_file_write(&lfs2, &file, buffer, size) => size;
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
} }
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &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;
} }
buffer[NAMEMULT] = '\0'; buffer[NAMEMULT] = '\0';
lfs_stat(&lfs, (char*)buffer, &info) => 0; lfs2_stat(&lfs2, (char*)buffer, &info) => 0;
info.type => LFS_TYPE_DIR; info.type => LFS2_TYPE_DIR;
buffer[NAMEMULT] = '/'; buffer[NAMEMULT] = '/';
for (int j = 0; j < NAMEMULT; j++) { for (int j = 0; j < NAMEMULT; j++) {
buffer[j+NAMEMULT+1] = '0'+i; buffer[j+NAMEMULT+1] = '0'+i;
} }
buffer[2*NAMEMULT+1] = '\0'; buffer[2*NAMEMULT+1] = '\0';
lfs_file_open(&lfs, &file, (char*)buffer, LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, (char*)buffer, LFS2_O_RDONLY) => 0;
size = NAMEMULT; size = NAMEMULT;
for (int j = 0; j < i*FILEMULT; j++) { for (int j = 0; j < i*FILEMULT; j++) {
uint8_t rbuffer[1024]; uint8_t rbuffer[1024];
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
memcmp(buffer, rbuffer, size) => 0; memcmp(buffer, rbuffer, size) => 0;
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
} }
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
} }
''' '''
[[case]] # region corruption (causes cascading failures) [[case]] # region corruption (causes cascading failures)
define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster define.LFS2_BLOCK_COUNT = 256 # small bd so test runs faster
define.LFS_ERASE_CYCLES = 0xffffffff define.LFS2_ERASE_CYCLES = 0xffffffff
define.LFS_ERASE_VALUE = [0x00, 0xff, -1] define.LFS2_ERASE_VALUE = [0x00, 0xff, -1]
define.LFS_BADBLOCK_BEHAVIOR = [ define.LFS2_BADBLOCK_BEHAVIOR = [
'LFS_TESTBD_BADBLOCK_PROGERROR', 'LFS2_TESTBD_BADBLOCK_PROGERROR',
'LFS_TESTBD_BADBLOCK_ERASEERROR', 'LFS2_TESTBD_BADBLOCK_ERASEERROR',
'LFS_TESTBD_BADBLOCK_READERROR', 'LFS2_TESTBD_BADBLOCK_READERROR',
'LFS_TESTBD_BADBLOCK_PROGNOOP', 'LFS2_TESTBD_BADBLOCK_PROGNOOP',
'LFS_TESTBD_BADBLOCK_ERASENOOP', 'LFS2_TESTBD_BADBLOCK_ERASENOOP',
] ]
define.NAMEMULT = 64 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 (lfs2_block_t i = 0; i < (LFS2_BLOCK_COUNT-2)/2; i++) {
lfs_testbd_setwear(&cfg, i+2, 0xffffffff) => 0; lfs2_testbd_setwear(&cfg, i+2, 0xffffffff) => 0;
} }
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &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;
} }
buffer[NAMEMULT] = '\0'; buffer[NAMEMULT] = '\0';
lfs_mkdir(&lfs, (char*)buffer) => 0; lfs2_mkdir(&lfs2, (char*)buffer) => 0;
buffer[NAMEMULT] = '/'; buffer[NAMEMULT] = '/';
for (int j = 0; j < NAMEMULT; j++) { for (int j = 0; j < NAMEMULT; j++) {
buffer[j+NAMEMULT+1] = '0'+i; buffer[j+NAMEMULT+1] = '0'+i;
} }
buffer[2*NAMEMULT+1] = '\0'; buffer[2*NAMEMULT+1] = '\0';
lfs_file_open(&lfs, &file, (char*)buffer, lfs2_file_open(&lfs2, &file, (char*)buffer,
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
size = NAMEMULT; size = NAMEMULT;
for (int j = 0; j < i*FILEMULT; j++) { for (int j = 0; j < i*FILEMULT; j++) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs2_file_write(&lfs2, &file, buffer, size) => size;
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
} }
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &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;
} }
buffer[NAMEMULT] = '\0'; buffer[NAMEMULT] = '\0';
lfs_stat(&lfs, (char*)buffer, &info) => 0; lfs2_stat(&lfs2, (char*)buffer, &info) => 0;
info.type => LFS_TYPE_DIR; info.type => LFS2_TYPE_DIR;
buffer[NAMEMULT] = '/'; buffer[NAMEMULT] = '/';
for (int j = 0; j < NAMEMULT; j++) { for (int j = 0; j < NAMEMULT; j++) {
buffer[j+NAMEMULT+1] = '0'+i; buffer[j+NAMEMULT+1] = '0'+i;
} }
buffer[2*NAMEMULT+1] = '\0'; buffer[2*NAMEMULT+1] = '\0';
lfs_file_open(&lfs, &file, (char*)buffer, LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, (char*)buffer, LFS2_O_RDONLY) => 0;
size = NAMEMULT; size = NAMEMULT;
for (int j = 0; j < i*FILEMULT; j++) { for (int j = 0; j < i*FILEMULT; j++) {
uint8_t rbuffer[1024]; uint8_t rbuffer[1024];
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
memcmp(buffer, rbuffer, size) => 0; memcmp(buffer, rbuffer, size) => 0;
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
} }
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # alternating corruption (causes cascading failures) [[case]] # alternating corruption (causes cascading failures)
define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster define.LFS2_BLOCK_COUNT = 256 # small bd so test runs faster
define.LFS_ERASE_CYCLES = 0xffffffff define.LFS2_ERASE_CYCLES = 0xffffffff
define.LFS_ERASE_VALUE = [0x00, 0xff, -1] define.LFS2_ERASE_VALUE = [0x00, 0xff, -1]
define.LFS_BADBLOCK_BEHAVIOR = [ define.LFS2_BADBLOCK_BEHAVIOR = [
'LFS_TESTBD_BADBLOCK_PROGERROR', 'LFS2_TESTBD_BADBLOCK_PROGERROR',
'LFS_TESTBD_BADBLOCK_ERASEERROR', 'LFS2_TESTBD_BADBLOCK_ERASEERROR',
'LFS_TESTBD_BADBLOCK_READERROR', 'LFS2_TESTBD_BADBLOCK_READERROR',
'LFS_TESTBD_BADBLOCK_PROGNOOP', 'LFS2_TESTBD_BADBLOCK_PROGNOOP',
'LFS_TESTBD_BADBLOCK_ERASENOOP', 'LFS2_TESTBD_BADBLOCK_ERASENOOP',
] ]
define.NAMEMULT = 64 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 (lfs2_block_t i = 0; i < (LFS2_BLOCK_COUNT-2)/2; i++) {
lfs_testbd_setwear(&cfg, (2*i) + 2, 0xffffffff) => 0; lfs2_testbd_setwear(&cfg, (2*i) + 2, 0xffffffff) => 0;
} }
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &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;
} }
buffer[NAMEMULT] = '\0'; buffer[NAMEMULT] = '\0';
lfs_mkdir(&lfs, (char*)buffer) => 0; lfs2_mkdir(&lfs2, (char*)buffer) => 0;
buffer[NAMEMULT] = '/'; buffer[NAMEMULT] = '/';
for (int j = 0; j < NAMEMULT; j++) { for (int j = 0; j < NAMEMULT; j++) {
buffer[j+NAMEMULT+1] = '0'+i; buffer[j+NAMEMULT+1] = '0'+i;
} }
buffer[2*NAMEMULT+1] = '\0'; buffer[2*NAMEMULT+1] = '\0';
lfs_file_open(&lfs, &file, (char*)buffer, lfs2_file_open(&lfs2, &file, (char*)buffer,
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
size = NAMEMULT; size = NAMEMULT;
for (int j = 0; j < i*FILEMULT; j++) { for (int j = 0; j < i*FILEMULT; j++) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs2_file_write(&lfs2, &file, buffer, size) => size;
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
} }
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &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;
} }
buffer[NAMEMULT] = '\0'; buffer[NAMEMULT] = '\0';
lfs_stat(&lfs, (char*)buffer, &info) => 0; lfs2_stat(&lfs2, (char*)buffer, &info) => 0;
info.type => LFS_TYPE_DIR; info.type => LFS2_TYPE_DIR;
buffer[NAMEMULT] = '/'; buffer[NAMEMULT] = '/';
for (int j = 0; j < NAMEMULT; j++) { for (int j = 0; j < NAMEMULT; j++) {
buffer[j+NAMEMULT+1] = '0'+i; buffer[j+NAMEMULT+1] = '0'+i;
} }
buffer[2*NAMEMULT+1] = '\0'; buffer[2*NAMEMULT+1] = '\0';
lfs_file_open(&lfs, &file, (char*)buffer, LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, (char*)buffer, LFS2_O_RDONLY) => 0;
size = NAMEMULT; size = NAMEMULT;
for (int j = 0; j < i*FILEMULT; j++) { for (int j = 0; j < i*FILEMULT; j++) {
uint8_t rbuffer[1024]; uint8_t rbuffer[1024];
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
memcmp(buffer, rbuffer, size) => 0; memcmp(buffer, rbuffer, size) => 0;
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
} }
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
# other corner cases # other corner cases
[[case]] # bad superblocks (corrupt 1 or 0) [[case]] # bad superblocks (corrupt 1 or 0)
define.LFS_ERASE_CYCLES = 0xffffffff define.LFS2_ERASE_CYCLES = 0xffffffff
define.LFS_ERASE_VALUE = [0x00, 0xff, -1] define.LFS2_ERASE_VALUE = [0x00, 0xff, -1]
define.LFS_BADBLOCK_BEHAVIOR = [ define.LFS2_BADBLOCK_BEHAVIOR = [
'LFS_TESTBD_BADBLOCK_PROGERROR', 'LFS2_TESTBD_BADBLOCK_PROGERROR',
'LFS_TESTBD_BADBLOCK_ERASEERROR', 'LFS2_TESTBD_BADBLOCK_ERASEERROR',
'LFS_TESTBD_BADBLOCK_READERROR', 'LFS2_TESTBD_BADBLOCK_READERROR',
'LFS_TESTBD_BADBLOCK_PROGNOOP', 'LFS2_TESTBD_BADBLOCK_PROGNOOP',
'LFS_TESTBD_BADBLOCK_ERASENOOP', 'LFS2_TESTBD_BADBLOCK_ERASENOOP',
] ]
code = ''' code = '''
lfs_testbd_setwear(&cfg, 0, 0xffffffff) => 0; lfs2_testbd_setwear(&cfg, 0, 0xffffffff) => 0;
lfs_testbd_setwear(&cfg, 1, 0xffffffff) => 0; lfs2_testbd_setwear(&cfg, 1, 0xffffffff) => 0;
lfs_format(&lfs, &cfg) => LFS_ERR_NOSPC; lfs2_format(&lfs2, &cfg) => LFS2_ERR_NOSPC;
lfs_mount(&lfs, &cfg) => LFS_ERR_CORRUPT; lfs2_mount(&lfs2, &cfg) => LFS2_ERR_CORRUPT;
''' '''

File diff suppressed because it is too large Load Diff

View File

@@ -2,96 +2,96 @@
# Note that these tests are intended for 512 byte inline sizes. They should # Note that these tests are intended for 512 byte inline sizes. They should
# still pass with other inline sizes but wouldn't be testing anything. # still pass with other inline sizes but wouldn't be testing anything.
define.LFS_CACHE_SIZE = 512 define.LFS2_CACHE_SIZE = 512
if = 'LFS_CACHE_SIZE % LFS_PROG_SIZE == 0 && LFS_CACHE_SIZE == 512' if = 'LFS2_CACHE_SIZE % LFS2_PROG_SIZE == 0 && LFS2_CACHE_SIZE == 512'
[[case]] # entry grow test [[case]] # entry grow test
code = ''' code = '''
uint8_t wbuffer[1024]; uint8_t wbuffer[1024];
uint8_t rbuffer[1024]; uint8_t rbuffer[1024];
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
// write hi0 20 // write hi0 20
sprintf(path, "hi0"); size = 20; sprintf(path, "hi0"); size = 20;
lfs_file_open(&lfs, &file, path, lfs2_file_open(&lfs2, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
memset(wbuffer, 'c', size); memset(wbuffer, 'c', size);
lfs_file_write(&lfs, &file, wbuffer, size) => size; lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// write hi1 20 // write hi1 20
sprintf(path, "hi1"); size = 20; sprintf(path, "hi1"); size = 20;
lfs_file_open(&lfs, &file, path, lfs2_file_open(&lfs2, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
memset(wbuffer, 'c', size); memset(wbuffer, 'c', size);
lfs_file_write(&lfs, &file, wbuffer, size) => size; lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// write hi2 20 // write hi2 20
sprintf(path, "hi2"); size = 20; sprintf(path, "hi2"); size = 20;
lfs_file_open(&lfs, &file, path, lfs2_file_open(&lfs2, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
memset(wbuffer, 'c', size); memset(wbuffer, 'c', size);
lfs_file_write(&lfs, &file, wbuffer, size) => size; lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// write hi3 20 // write hi3 20
sprintf(path, "hi3"); size = 20; sprintf(path, "hi3"); size = 20;
lfs_file_open(&lfs, &file, path, lfs2_file_open(&lfs2, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
memset(wbuffer, 'c', size); memset(wbuffer, 'c', size);
lfs_file_write(&lfs, &file, wbuffer, size) => size; lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// read hi1 20 // read hi1 20
sprintf(path, "hi1"); size = 20; sprintf(path, "hi1"); size = 20;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0; memcmp(rbuffer, wbuffer, size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// write hi1 200 // write hi1 200
sprintf(path, "hi1"); size = 200; sprintf(path, "hi1"); size = 200;
lfs_file_open(&lfs, &file, path, lfs2_file_open(&lfs2, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
memset(wbuffer, 'c', size); memset(wbuffer, 'c', size);
lfs_file_write(&lfs, &file, wbuffer, size) => size; lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// read hi0 20 // read hi0 20
sprintf(path, "hi0"); size = 20; sprintf(path, "hi0"); size = 20;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0; memcmp(rbuffer, wbuffer, size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// read hi1 200 // read hi1 200
sprintf(path, "hi1"); size = 200; sprintf(path, "hi1"); size = 200;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0; memcmp(rbuffer, wbuffer, size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// read hi2 20 // read hi2 20
sprintf(path, "hi2"); size = 20; sprintf(path, "hi2"); size = 20;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0; memcmp(rbuffer, wbuffer, size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// read hi3 20 // read hi3 20
sprintf(path, "hi3"); size = 20; sprintf(path, "hi3"); size = 20;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0; memcmp(rbuffer, wbuffer, size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # entry shrink test [[case]] # entry shrink test
@@ -99,88 +99,88 @@ code = '''
uint8_t wbuffer[1024]; uint8_t wbuffer[1024];
uint8_t rbuffer[1024]; uint8_t rbuffer[1024];
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
// write hi0 20 // write hi0 20
sprintf(path, "hi0"); size = 20; sprintf(path, "hi0"); size = 20;
lfs_file_open(&lfs, &file, path, lfs2_file_open(&lfs2, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
memset(wbuffer, 'c', size); memset(wbuffer, 'c', size);
lfs_file_write(&lfs, &file, wbuffer, size) => size; lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// write hi1 200 // write hi1 200
sprintf(path, "hi1"); size = 200; sprintf(path, "hi1"); size = 200;
lfs_file_open(&lfs, &file, path, lfs2_file_open(&lfs2, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
memset(wbuffer, 'c', size); memset(wbuffer, 'c', size);
lfs_file_write(&lfs, &file, wbuffer, size) => size; lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// write hi2 20 // write hi2 20
sprintf(path, "hi2"); size = 20; sprintf(path, "hi2"); size = 20;
lfs_file_open(&lfs, &file, path, lfs2_file_open(&lfs2, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
memset(wbuffer, 'c', size); memset(wbuffer, 'c', size);
lfs_file_write(&lfs, &file, wbuffer, size) => size; lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// write hi3 20 // write hi3 20
sprintf(path, "hi3"); size = 20; sprintf(path, "hi3"); size = 20;
lfs_file_open(&lfs, &file, path, lfs2_file_open(&lfs2, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
memset(wbuffer, 'c', size); memset(wbuffer, 'c', size);
lfs_file_write(&lfs, &file, wbuffer, size) => size; lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// read hi1 200 // read hi1 200
sprintf(path, "hi1"); size = 200; sprintf(path, "hi1"); size = 200;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0; memcmp(rbuffer, wbuffer, size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// write hi1 20 // write hi1 20
sprintf(path, "hi1"); size = 20; sprintf(path, "hi1"); size = 20;
lfs_file_open(&lfs, &file, path, lfs2_file_open(&lfs2, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
memset(wbuffer, 'c', size); memset(wbuffer, 'c', size);
lfs_file_write(&lfs, &file, wbuffer, size) => size; lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// read hi0 20 // read hi0 20
sprintf(path, "hi0"); size = 20; sprintf(path, "hi0"); size = 20;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0; memcmp(rbuffer, wbuffer, size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// read hi1 20 // read hi1 20
sprintf(path, "hi1"); size = 20; sprintf(path, "hi1"); size = 20;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0; memcmp(rbuffer, wbuffer, size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// read hi2 20 // read hi2 20
sprintf(path, "hi2"); size = 20; sprintf(path, "hi2"); size = 20;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0; memcmp(rbuffer, wbuffer, size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// read hi3 20 // read hi3 20
sprintf(path, "hi3"); size = 20; sprintf(path, "hi3"); size = 20;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0; memcmp(rbuffer, wbuffer, size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # entry spill test [[case]] # entry spill test
@@ -188,72 +188,72 @@ code = '''
uint8_t wbuffer[1024]; uint8_t wbuffer[1024];
uint8_t rbuffer[1024]; uint8_t rbuffer[1024];
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
// write hi0 200 // write hi0 200
sprintf(path, "hi0"); size = 200; sprintf(path, "hi0"); size = 200;
lfs_file_open(&lfs, &file, path, lfs2_file_open(&lfs2, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
memset(wbuffer, 'c', size); memset(wbuffer, 'c', size);
lfs_file_write(&lfs, &file, wbuffer, size) => size; lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// write hi1 200 // write hi1 200
sprintf(path, "hi1"); size = 200; sprintf(path, "hi1"); size = 200;
lfs_file_open(&lfs, &file, path, lfs2_file_open(&lfs2, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
memset(wbuffer, 'c', size); memset(wbuffer, 'c', size);
lfs_file_write(&lfs, &file, wbuffer, size) => size; lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// write hi2 200 // write hi2 200
sprintf(path, "hi2"); size = 200; sprintf(path, "hi2"); size = 200;
lfs_file_open(&lfs, &file, path, lfs2_file_open(&lfs2, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
memset(wbuffer, 'c', size); memset(wbuffer, 'c', size);
lfs_file_write(&lfs, &file, wbuffer, size) => size; lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// write hi3 200 // write hi3 200
sprintf(path, "hi3"); size = 200; sprintf(path, "hi3"); size = 200;
lfs_file_open(&lfs, &file, path, lfs2_file_open(&lfs2, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
memset(wbuffer, 'c', size); memset(wbuffer, 'c', size);
lfs_file_write(&lfs, &file, wbuffer, size) => size; lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// read hi0 200 // read hi0 200
sprintf(path, "hi0"); size = 200; sprintf(path, "hi0"); size = 200;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0; memcmp(rbuffer, wbuffer, size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// read hi1 200 // read hi1 200
sprintf(path, "hi1"); size = 200; sprintf(path, "hi1"); size = 200;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0; memcmp(rbuffer, wbuffer, size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// read hi2 200 // read hi2 200
sprintf(path, "hi2"); size = 200; sprintf(path, "hi2"); size = 200;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0; memcmp(rbuffer, wbuffer, size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// read hi3 200 // read hi3 200
sprintf(path, "hi3"); size = 200; sprintf(path, "hi3"); size = 200;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0; memcmp(rbuffer, wbuffer, size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # entry push spill test [[case]] # entry push spill test
@@ -261,88 +261,88 @@ code = '''
uint8_t wbuffer[1024]; uint8_t wbuffer[1024];
uint8_t rbuffer[1024]; uint8_t rbuffer[1024];
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
// write hi0 200 // write hi0 200
sprintf(path, "hi0"); size = 200; sprintf(path, "hi0"); size = 200;
lfs_file_open(&lfs, &file, path, lfs2_file_open(&lfs2, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
memset(wbuffer, 'c', size); memset(wbuffer, 'c', size);
lfs_file_write(&lfs, &file, wbuffer, size) => size; lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// write hi1 20 // write hi1 20
sprintf(path, "hi1"); size = 20; sprintf(path, "hi1"); size = 20;
lfs_file_open(&lfs, &file, path, lfs2_file_open(&lfs2, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
memset(wbuffer, 'c', size); memset(wbuffer, 'c', size);
lfs_file_write(&lfs, &file, wbuffer, size) => size; lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// write hi2 200 // write hi2 200
sprintf(path, "hi2"); size = 200; sprintf(path, "hi2"); size = 200;
lfs_file_open(&lfs, &file, path, lfs2_file_open(&lfs2, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
memset(wbuffer, 'c', size); memset(wbuffer, 'c', size);
lfs_file_write(&lfs, &file, wbuffer, size) => size; lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// write hi3 200 // write hi3 200
sprintf(path, "hi3"); size = 200; sprintf(path, "hi3"); size = 200;
lfs_file_open(&lfs, &file, path, lfs2_file_open(&lfs2, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
memset(wbuffer, 'c', size); memset(wbuffer, 'c', size);
lfs_file_write(&lfs, &file, wbuffer, size) => size; lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// read hi1 20 // read hi1 20
sprintf(path, "hi1"); size = 20; sprintf(path, "hi1"); size = 20;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0; memcmp(rbuffer, wbuffer, size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// write hi1 200 // write hi1 200
sprintf(path, "hi1"); size = 200; sprintf(path, "hi1"); size = 200;
lfs_file_open(&lfs, &file, path, lfs2_file_open(&lfs2, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
memset(wbuffer, 'c', size); memset(wbuffer, 'c', size);
lfs_file_write(&lfs, &file, wbuffer, size) => size; lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// read hi0 200 // read hi0 200
sprintf(path, "hi0"); size = 200; sprintf(path, "hi0"); size = 200;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0; memcmp(rbuffer, wbuffer, size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// read hi1 200 // read hi1 200
sprintf(path, "hi1"); size = 200; sprintf(path, "hi1"); size = 200;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0; memcmp(rbuffer, wbuffer, size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// read hi2 200 // read hi2 200
sprintf(path, "hi2"); size = 200; sprintf(path, "hi2"); size = 200;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0; memcmp(rbuffer, wbuffer, size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// read hi3 200 // read hi3 200
sprintf(path, "hi3"); size = 200; sprintf(path, "hi3"); size = 200;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0; memcmp(rbuffer, wbuffer, size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # entry push spill two test [[case]] # entry push spill two test
@@ -350,103 +350,103 @@ code = '''
uint8_t wbuffer[1024]; uint8_t wbuffer[1024];
uint8_t rbuffer[1024]; uint8_t rbuffer[1024];
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
// write hi0 200 // write hi0 200
sprintf(path, "hi0"); size = 200; sprintf(path, "hi0"); size = 200;
lfs_file_open(&lfs, &file, path, lfs2_file_open(&lfs2, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
memset(wbuffer, 'c', size); memset(wbuffer, 'c', size);
lfs_file_write(&lfs, &file, wbuffer, size) => size; lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// write hi1 20 // write hi1 20
sprintf(path, "hi1"); size = 20; sprintf(path, "hi1"); size = 20;
lfs_file_open(&lfs, &file, path, lfs2_file_open(&lfs2, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
memset(wbuffer, 'c', size); memset(wbuffer, 'c', size);
lfs_file_write(&lfs, &file, wbuffer, size) => size; lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// write hi2 200 // write hi2 200
sprintf(path, "hi2"); size = 200; sprintf(path, "hi2"); size = 200;
lfs_file_open(&lfs, &file, path, lfs2_file_open(&lfs2, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
memset(wbuffer, 'c', size); memset(wbuffer, 'c', size);
lfs_file_write(&lfs, &file, wbuffer, size) => size; lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// write hi3 200 // write hi3 200
sprintf(path, "hi3"); size = 200; sprintf(path, "hi3"); size = 200;
lfs_file_open(&lfs, &file, path, lfs2_file_open(&lfs2, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
memset(wbuffer, 'c', size); memset(wbuffer, 'c', size);
lfs_file_write(&lfs, &file, wbuffer, size) => size; lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// write hi4 200 // write hi4 200
sprintf(path, "hi4"); size = 200; sprintf(path, "hi4"); size = 200;
lfs_file_open(&lfs, &file, path, lfs2_file_open(&lfs2, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
memset(wbuffer, 'c', size); memset(wbuffer, 'c', size);
lfs_file_write(&lfs, &file, wbuffer, size) => size; lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// read hi1 20 // read hi1 20
sprintf(path, "hi1"); size = 20; sprintf(path, "hi1"); size = 20;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0; memcmp(rbuffer, wbuffer, size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// write hi1 200 // write hi1 200
sprintf(path, "hi1"); size = 200; sprintf(path, "hi1"); size = 200;
lfs_file_open(&lfs, &file, path, lfs2_file_open(&lfs2, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
memset(wbuffer, 'c', size); memset(wbuffer, 'c', size);
lfs_file_write(&lfs, &file, wbuffer, size) => size; lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// read hi0 200 // read hi0 200
sprintf(path, "hi0"); size = 200; sprintf(path, "hi0"); size = 200;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0; memcmp(rbuffer, wbuffer, size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// read hi1 200 // read hi1 200
sprintf(path, "hi1"); size = 200; sprintf(path, "hi1"); size = 200;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0; memcmp(rbuffer, wbuffer, size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// read hi2 200 // read hi2 200
sprintf(path, "hi2"); size = 200; sprintf(path, "hi2"); size = 200;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0; memcmp(rbuffer, wbuffer, size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// read hi3 200 // read hi3 200
sprintf(path, "hi3"); size = 200; sprintf(path, "hi3"); size = 200;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0; memcmp(rbuffer, wbuffer, size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// read hi4 200 // read hi4 200
sprintf(path, "hi4"); size = 200; sprintf(path, "hi4"); size = 200;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0; memcmp(rbuffer, wbuffer, size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # entry drop test [[case]] # entry drop test
@@ -454,158 +454,158 @@ code = '''
uint8_t wbuffer[1024]; uint8_t wbuffer[1024];
uint8_t rbuffer[1024]; uint8_t rbuffer[1024];
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
// write hi0 200 // write hi0 200
sprintf(path, "hi0"); size = 200; sprintf(path, "hi0"); size = 200;
lfs_file_open(&lfs, &file, path, lfs2_file_open(&lfs2, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
memset(wbuffer, 'c', size); memset(wbuffer, 'c', size);
lfs_file_write(&lfs, &file, wbuffer, size) => size; lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// write hi1 200 // write hi1 200
sprintf(path, "hi1"); size = 200; sprintf(path, "hi1"); size = 200;
lfs_file_open(&lfs, &file, path, lfs2_file_open(&lfs2, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
memset(wbuffer, 'c', size); memset(wbuffer, 'c', size);
lfs_file_write(&lfs, &file, wbuffer, size) => size; lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// write hi2 200 // write hi2 200
sprintf(path, "hi2"); size = 200; sprintf(path, "hi2"); size = 200;
lfs_file_open(&lfs, &file, path, lfs2_file_open(&lfs2, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
memset(wbuffer, 'c', size); memset(wbuffer, 'c', size);
lfs_file_write(&lfs, &file, wbuffer, size) => size; lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// write hi3 200 // write hi3 200
sprintf(path, "hi3"); size = 200; sprintf(path, "hi3"); size = 200;
lfs_file_open(&lfs, &file, path, lfs2_file_open(&lfs2, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
memset(wbuffer, 'c', size); memset(wbuffer, 'c', size);
lfs_file_write(&lfs, &file, wbuffer, size) => size; lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_remove(&lfs, "hi1") => 0; lfs2_remove(&lfs2, "hi1") => 0;
lfs_stat(&lfs, "hi1", &info) => LFS_ERR_NOENT; lfs2_stat(&lfs2, "hi1", &info) => LFS2_ERR_NOENT;
// read hi0 200 // read hi0 200
sprintf(path, "hi0"); size = 200; sprintf(path, "hi0"); size = 200;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0; memcmp(rbuffer, wbuffer, size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// read hi2 200 // read hi2 200
sprintf(path, "hi2"); size = 200; sprintf(path, "hi2"); size = 200;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0; memcmp(rbuffer, wbuffer, size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// read hi3 200 // read hi3 200
sprintf(path, "hi3"); size = 200; sprintf(path, "hi3"); size = 200;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0; memcmp(rbuffer, wbuffer, size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_remove(&lfs, "hi2") => 0; lfs2_remove(&lfs2, "hi2") => 0;
lfs_stat(&lfs, "hi2", &info) => LFS_ERR_NOENT; lfs2_stat(&lfs2, "hi2", &info) => LFS2_ERR_NOENT;
// read hi0 200 // read hi0 200
sprintf(path, "hi0"); size = 200; sprintf(path, "hi0"); size = 200;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0; memcmp(rbuffer, wbuffer, size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// read hi3 200 // read hi3 200
sprintf(path, "hi3"); size = 200; sprintf(path, "hi3"); size = 200;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0; memcmp(rbuffer, wbuffer, size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_remove(&lfs, "hi3") => 0; lfs2_remove(&lfs2, "hi3") => 0;
lfs_stat(&lfs, "hi3", &info) => LFS_ERR_NOENT; lfs2_stat(&lfs2, "hi3", &info) => LFS2_ERR_NOENT;
// read hi0 200 // read hi0 200
sprintf(path, "hi0"); size = 200; sprintf(path, "hi0"); size = 200;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0; memcmp(rbuffer, wbuffer, size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_remove(&lfs, "hi0") => 0; lfs2_remove(&lfs2, "hi0") => 0;
lfs_stat(&lfs, "hi0", &info) => LFS_ERR_NOENT; lfs2_stat(&lfs2, "hi0", &info) => LFS2_ERR_NOENT;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # create too big [[case]] # create too big
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
memset(path, 'm', 200); memset(path, 'm', 200);
path[200] = '\0'; path[200] = '\0';
size = 400; size = 400;
lfs_file_open(&lfs, &file, path, lfs2_file_open(&lfs2, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
uint8_t wbuffer[1024]; uint8_t wbuffer[1024];
memset(wbuffer, 'c', size); memset(wbuffer, 'c', size);
lfs_file_write(&lfs, &file, wbuffer, size) => size; lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
size = 400; size = 400;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
uint8_t rbuffer[1024]; uint8_t rbuffer[1024];
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0; memcmp(rbuffer, wbuffer, size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # resize too big [[case]] # resize too big
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
memset(path, 'm', 200); memset(path, 'm', 200);
path[200] = '\0'; path[200] = '\0';
size = 40; size = 40;
lfs_file_open(&lfs, &file, path, lfs2_file_open(&lfs2, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
uint8_t wbuffer[1024]; uint8_t wbuffer[1024];
memset(wbuffer, 'c', size); memset(wbuffer, 'c', size);
lfs_file_write(&lfs, &file, wbuffer, size) => size; lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
size = 40; size = 40;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
uint8_t rbuffer[1024]; uint8_t rbuffer[1024];
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0; memcmp(rbuffer, wbuffer, size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
size = 400; size = 400;
lfs_file_open(&lfs, &file, path, lfs2_file_open(&lfs2, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
memset(wbuffer, 'c', size); memset(wbuffer, 'c', size);
lfs_file_write(&lfs, &file, wbuffer, size) => size; lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
size = 400; size = 400;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0; memcmp(rbuffer, wbuffer, size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''

View File

@@ -4,285 +4,285 @@
# invalid pointer tests (outside of block_count) # invalid pointer tests (outside of block_count)
[[case]] # invalid tail-pointer test [[case]] # invalid tail-pointer test
define.TAIL_TYPE = ['LFS_TYPE_HARDTAIL', 'LFS_TYPE_SOFTTAIL'] define.TAIL_TYPE = ['LFS2_TYPE_HARDTAIL', 'LFS2_TYPE_SOFTTAIL']
define.INVALSET = [0x3, 0x1, 0x2] define.INVALSET = [0x3, 0x1, 0x2]
in = "lfs.c" in = "lfs2.c"
code = ''' code = '''
// create littlefs // create littlefs
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
// change tail-pointer to invalid pointers // change tail-pointer to invalid pointers
lfs_init(&lfs, &cfg) => 0; lfs2_init(&lfs2, &cfg) => 0;
lfs_mdir_t mdir; lfs2_mdir_t mdir;
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; lfs2_dir_fetch(&lfs2, &mdir, (lfs2_block_t[2]){0, 1}) => 0;
lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS( lfs2_dir_commit(&lfs2, &mdir, LFS2_MKATTRS(
{LFS_MKTAG(LFS_TYPE_HARDTAIL, 0x3ff, 8), {LFS2_MKTAG(LFS2_TYPE_HARDTAIL, 0x3ff, 8),
(lfs_block_t[2]){ (lfs2_block_t[2]){
(INVALSET & 0x1) ? 0xcccccccc : 0, (INVALSET & 0x1) ? 0xcccccccc : 0,
(INVALSET & 0x2) ? 0xcccccccc : 0}})) => 0; (INVALSET & 0x2) ? 0xcccccccc : 0}})) => 0;
lfs_deinit(&lfs) => 0; lfs2_deinit(&lfs2) => 0;
// test that mount fails gracefully // test that mount fails gracefully
lfs_mount(&lfs, &cfg) => LFS_ERR_CORRUPT; lfs2_mount(&lfs2, &cfg) => LFS2_ERR_CORRUPT;
''' '''
[[case]] # invalid dir pointer test [[case]] # invalid dir pointer test
define.INVALSET = [0x3, 0x1, 0x2] define.INVALSET = [0x3, 0x1, 0x2]
in = "lfs.c" in = "lfs2.c"
code = ''' code = '''
// create littlefs // create littlefs
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
// make a dir // make a dir
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_mkdir(&lfs, "dir_here") => 0; lfs2_mkdir(&lfs2, "dir_here") => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
// change the dir pointer to be invalid // change the dir pointer to be invalid
lfs_init(&lfs, &cfg) => 0; lfs2_init(&lfs2, &cfg) => 0;
lfs_mdir_t mdir; lfs2_mdir_t mdir;
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; lfs2_dir_fetch(&lfs2, &mdir, (lfs2_block_t[2]){0, 1}) => 0;
// make sure id 1 == our directory // make sure id 1 == our directory
lfs_dir_get(&lfs, &mdir, lfs2_dir_get(&lfs2, &mdir,
LFS_MKTAG(0x700, 0x3ff, 0), LFS2_MKTAG(0x700, 0x3ff, 0),
LFS_MKTAG(LFS_TYPE_NAME, 1, strlen("dir_here")), buffer) LFS2_MKTAG(LFS2_TYPE_NAME, 1, strlen("dir_here")), buffer)
=> LFS_MKTAG(LFS_TYPE_DIR, 1, strlen("dir_here")); => LFS2_MKTAG(LFS2_TYPE_DIR, 1, strlen("dir_here"));
assert(memcmp((char*)buffer, "dir_here", strlen("dir_here")) == 0); assert(memcmp((char*)buffer, "dir_here", strlen("dir_here")) == 0);
// change dir pointer // change dir pointer
lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS( lfs2_dir_commit(&lfs2, &mdir, LFS2_MKATTRS(
{LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 1, 8), {LFS2_MKTAG(LFS2_TYPE_DIRSTRUCT, 1, 8),
(lfs_block_t[2]){ (lfs2_block_t[2]){
(INVALSET & 0x1) ? 0xcccccccc : 0, (INVALSET & 0x1) ? 0xcccccccc : 0,
(INVALSET & 0x2) ? 0xcccccccc : 0}})) => 0; (INVALSET & 0x2) ? 0xcccccccc : 0}})) => 0;
lfs_deinit(&lfs) => 0; lfs2_deinit(&lfs2) => 0;
// 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; lfs2_mount(&lfs2, &cfg) => 0;
lfs_stat(&lfs, "dir_here", &info) => 0; lfs2_stat(&lfs2, "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 == LFS2_TYPE_DIR);
lfs_dir_open(&lfs, &dir, "dir_here") => LFS_ERR_CORRUPT; lfs2_dir_open(&lfs2, &dir, "dir_here") => LFS2_ERR_CORRUPT;
lfs_stat(&lfs, "dir_here/file_here", &info) => LFS_ERR_CORRUPT; lfs2_stat(&lfs2, "dir_here/file_here", &info) => LFS2_ERR_CORRUPT;
lfs_dir_open(&lfs, &dir, "dir_here/dir_here") => LFS_ERR_CORRUPT; lfs2_dir_open(&lfs2, &dir, "dir_here/dir_here") => LFS2_ERR_CORRUPT;
lfs_file_open(&lfs, &file, "dir_here/file_here", lfs2_file_open(&lfs2, &file, "dir_here/file_here",
LFS_O_RDONLY) => LFS_ERR_CORRUPT; LFS2_O_RDONLY) => LFS2_ERR_CORRUPT;
lfs_file_open(&lfs, &file, "dir_here/file_here", lfs2_file_open(&lfs2, &file, "dir_here/file_here",
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_CORRUPT; LFS2_O_WRONLY | LFS2_O_CREAT) => LFS2_ERR_CORRUPT;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # invalid file pointer test [[case]] # invalid file pointer test
in = "lfs.c" in = "lfs2.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; lfs2_format(&lfs2, &cfg) => 0;
// make a file // make a file
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "file_here", lfs2_file_open(&lfs2, &file, "file_here",
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
// change the file pointer to be invalid // change the file pointer to be invalid
lfs_init(&lfs, &cfg) => 0; lfs2_init(&lfs2, &cfg) => 0;
lfs_mdir_t mdir; lfs2_mdir_t mdir;
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; lfs2_dir_fetch(&lfs2, &mdir, (lfs2_block_t[2]){0, 1}) => 0;
// make sure id 1 == our file // make sure id 1 == our file
lfs_dir_get(&lfs, &mdir, lfs2_dir_get(&lfs2, &mdir,
LFS_MKTAG(0x700, 0x3ff, 0), LFS2_MKTAG(0x700, 0x3ff, 0),
LFS_MKTAG(LFS_TYPE_NAME, 1, strlen("file_here")), buffer) LFS2_MKTAG(LFS2_TYPE_NAME, 1, strlen("file_here")), buffer)
=> LFS_MKTAG(LFS_TYPE_REG, 1, strlen("file_here")); => LFS2_MKTAG(LFS2_TYPE_REG, 1, strlen("file_here"));
assert(memcmp((char*)buffer, "file_here", strlen("file_here")) == 0); assert(memcmp((char*)buffer, "file_here", strlen("file_here")) == 0);
// change file pointer // change file pointer
lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS( lfs2_dir_commit(&lfs2, &mdir, LFS2_MKATTRS(
{LFS_MKTAG(LFS_TYPE_CTZSTRUCT, 1, sizeof(struct lfs_ctz)), {LFS2_MKTAG(LFS2_TYPE_CTZSTRUCT, 1, sizeof(struct lfs2_ctz)),
&(struct lfs_ctz){0xcccccccc, lfs_tole32(SIZE)}})) => 0; &(struct lfs2_ctz){0xcccccccc, lfs2_tole32(SIZE)}})) => 0;
lfs_deinit(&lfs) => 0; lfs2_deinit(&lfs2) => 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; lfs2_mount(&lfs2, &cfg) => 0;
lfs_stat(&lfs, "file_here", &info) => 0; lfs2_stat(&lfs2, "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 == LFS2_TYPE_REG);
assert(info.size == SIZE); assert(info.size == SIZE);
lfs_file_open(&lfs, &file, "file_here", LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, "file_here", LFS2_O_RDONLY) => 0;
lfs_file_read(&lfs, &file, buffer, SIZE) => LFS_ERR_CORRUPT; lfs2_file_read(&lfs2, &file, buffer, SIZE) => LFS2_ERR_CORRUPT;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// any allocs that traverse CTZ must unfortunately must fail // any allocs that traverse CTZ must unfortunately must fail
if (SIZE > 2*LFS_BLOCK_SIZE) { if (SIZE > 2*LFS2_BLOCK_SIZE) {
lfs_mkdir(&lfs, "dir_here") => LFS_ERR_CORRUPT; lfs2_mkdir(&lfs2, "dir_here") => LFS2_ERR_CORRUPT;
} }
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # invalid pointer in CTZ skip-list test [[case]] # invalid pointer in CTZ skip-list test
define.SIZE = ['2*LFS_BLOCK_SIZE', '3*LFS_BLOCK_SIZE', '4*LFS_BLOCK_SIZE'] define.SIZE = ['2*LFS2_BLOCK_SIZE', '3*LFS2_BLOCK_SIZE', '4*LFS2_BLOCK_SIZE']
in = "lfs.c" in = "lfs2.c"
code = ''' code = '''
// create littlefs // create littlefs
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
// make a file // make a file
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "file_here", lfs2_file_open(&lfs2, &file, "file_here",
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
for (int i = 0; i < SIZE; i++) { for (int i = 0; i < SIZE; i++) {
char c = 'c'; char c = 'c';
lfs_file_write(&lfs, &file, &c, 1) => 1; lfs2_file_write(&lfs2, &file, &c, 1) => 1;
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
// change pointer in CTZ skip-list to be invalid // change pointer in CTZ skip-list to be invalid
lfs_init(&lfs, &cfg) => 0; lfs2_init(&lfs2, &cfg) => 0;
lfs_mdir_t mdir; lfs2_mdir_t mdir;
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; lfs2_dir_fetch(&lfs2, &mdir, (lfs2_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
lfs_dir_get(&lfs, &mdir, lfs2_dir_get(&lfs2, &mdir,
LFS_MKTAG(0x700, 0x3ff, 0), LFS2_MKTAG(0x700, 0x3ff, 0),
LFS_MKTAG(LFS_TYPE_NAME, 1, strlen("file_here")), buffer) LFS2_MKTAG(LFS2_TYPE_NAME, 1, strlen("file_here")), buffer)
=> LFS_MKTAG(LFS_TYPE_REG, 1, strlen("file_here")); => LFS2_MKTAG(LFS2_TYPE_REG, 1, strlen("file_here"));
assert(memcmp((char*)buffer, "file_here", strlen("file_here")) == 0); assert(memcmp((char*)buffer, "file_here", strlen("file_here")) == 0);
struct lfs_ctz ctz; struct lfs2_ctz ctz;
lfs_dir_get(&lfs, &mdir, lfs2_dir_get(&lfs2, &mdir,
LFS_MKTAG(0x700, 0x3ff, 0), LFS2_MKTAG(0x700, 0x3ff, 0),
LFS_MKTAG(LFS_TYPE_STRUCT, 1, sizeof(struct lfs_ctz)), &ctz) LFS2_MKTAG(LFS2_TYPE_STRUCT, 1, sizeof(struct lfs2_ctz)), &ctz)
=> LFS_MKTAG(LFS_TYPE_CTZSTRUCT, 1, sizeof(struct lfs_ctz)); => LFS2_MKTAG(LFS2_TYPE_CTZSTRUCT, 1, sizeof(struct lfs2_ctz));
lfs_ctz_fromle32(&ctz); lfs2_ctz_fromle32(&ctz);
// rewrite block to contain bad pointer // rewrite block to contain bad pointer
uint8_t bbuffer[LFS_BLOCK_SIZE]; uint8_t bbuffer[LFS2_BLOCK_SIZE];
cfg.read(&cfg, ctz.head, 0, bbuffer, LFS_BLOCK_SIZE) => 0; cfg.read(&cfg, ctz.head, 0, bbuffer, LFS2_BLOCK_SIZE) => 0;
uint32_t bad = lfs_tole32(0xcccccccc); uint32_t bad = lfs2_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; cfg.erase(&cfg, ctz.head) => 0;
cfg.prog(&cfg, ctz.head, 0, bbuffer, LFS_BLOCK_SIZE) => 0; cfg.prog(&cfg, ctz.head, 0, bbuffer, LFS2_BLOCK_SIZE) => 0;
lfs_deinit(&lfs) => 0; lfs2_deinit(&lfs2) => 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; lfs2_mount(&lfs2, &cfg) => 0;
lfs_stat(&lfs, "file_here", &info) => 0; lfs2_stat(&lfs2, "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 == LFS2_TYPE_REG);
assert(info.size == SIZE); assert(info.size == SIZE);
lfs_file_open(&lfs, &file, "file_here", LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, "file_here", LFS2_O_RDONLY) => 0;
lfs_file_read(&lfs, &file, buffer, SIZE) => LFS_ERR_CORRUPT; lfs2_file_read(&lfs2, &file, buffer, SIZE) => LFS2_ERR_CORRUPT;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// any allocs that traverse CTZ must unfortunately must fail // any allocs that traverse CTZ must unfortunately must fail
if (SIZE > 2*LFS_BLOCK_SIZE) { if (SIZE > 2*LFS2_BLOCK_SIZE) {
lfs_mkdir(&lfs, "dir_here") => LFS_ERR_CORRUPT; lfs2_mkdir(&lfs2, "dir_here") => LFS2_ERR_CORRUPT;
} }
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # invalid gstate pointer [[case]] # invalid gstate pointer
define.INVALSET = [0x3, 0x1, 0x2] define.INVALSET = [0x3, 0x1, 0x2]
in = "lfs.c" in = "lfs2.c"
code = ''' code = '''
// create littlefs // create littlefs
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
// create an invalid gstate // create an invalid gstate
lfs_init(&lfs, &cfg) => 0; lfs2_init(&lfs2, &cfg) => 0;
lfs_mdir_t mdir; lfs2_mdir_t mdir;
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; lfs2_dir_fetch(&lfs2, &mdir, (lfs2_block_t[2]){0, 1}) => 0;
lfs_fs_prepmove(&lfs, 1, (lfs_block_t [2]){ lfs2_fs_prepmove(&lfs2, 1, (lfs2_block_t [2]){
(INVALSET & 0x1) ? 0xcccccccc : 0, (INVALSET & 0x1) ? 0xcccccccc : 0,
(INVALSET & 0x2) ? 0xcccccccc : 0}); (INVALSET & 0x2) ? 0xcccccccc : 0});
lfs_dir_commit(&lfs, &mdir, NULL, 0) => 0; lfs2_dir_commit(&lfs2, &mdir, NULL, 0) => 0;
lfs_deinit(&lfs) => 0; lfs2_deinit(&lfs2) => 0;
// 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; lfs2_mount(&lfs2, &cfg) => 0;
lfs_mkdir(&lfs, "should_fail") => LFS_ERR_CORRUPT; lfs2_mkdir(&lfs2, "should_fail") => LFS2_ERR_CORRUPT;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
# cycle detection/recovery tests # cycle detection/recovery tests
[[case]] # metadata-pair threaded-list loop test [[case]] # metadata-pair threaded-list loop test
in = "lfs.c" in = "lfs2.c"
code = ''' code = '''
// create littlefs // create littlefs
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
// change tail-pointer to point to ourself // change tail-pointer to point to ourself
lfs_init(&lfs, &cfg) => 0; lfs2_init(&lfs2, &cfg) => 0;
lfs_mdir_t mdir; lfs2_mdir_t mdir;
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; lfs2_dir_fetch(&lfs2, &mdir, (lfs2_block_t[2]){0, 1}) => 0;
lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS( lfs2_dir_commit(&lfs2, &mdir, LFS2_MKATTRS(
{LFS_MKTAG(LFS_TYPE_HARDTAIL, 0x3ff, 8), {LFS2_MKTAG(LFS2_TYPE_HARDTAIL, 0x3ff, 8),
(lfs_block_t[2]){0, 1}})) => 0; (lfs2_block_t[2]){0, 1}})) => 0;
lfs_deinit(&lfs) => 0; lfs2_deinit(&lfs2) => 0;
// test that mount fails gracefully // test that mount fails gracefully
lfs_mount(&lfs, &cfg) => LFS_ERR_CORRUPT; lfs2_mount(&lfs2, &cfg) => LFS2_ERR_CORRUPT;
''' '''
[[case]] # metadata-pair threaded-list 2-length loop test [[case]] # metadata-pair threaded-list 2-length loop test
in = "lfs.c" in = "lfs2.c"
code = ''' code = '''
// create littlefs with child dir // create littlefs with child dir
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_mkdir(&lfs, "child") => 0; lfs2_mkdir(&lfs2, "child") => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
// find child // find child
lfs_init(&lfs, &cfg) => 0; lfs2_init(&lfs2, &cfg) => 0;
lfs_mdir_t mdir; lfs2_mdir_t mdir;
lfs_block_t pair[2]; lfs2_block_t pair[2];
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; lfs2_dir_fetch(&lfs2, &mdir, (lfs2_block_t[2]){0, 1}) => 0;
lfs_dir_get(&lfs, &mdir, lfs2_dir_get(&lfs2, &mdir,
LFS_MKTAG(0x7ff, 0x3ff, 0), LFS2_MKTAG(0x7ff, 0x3ff, 0),
LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 1, sizeof(pair)), pair) LFS2_MKTAG(LFS2_TYPE_DIRSTRUCT, 1, sizeof(pair)), pair)
=> LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 1, sizeof(pair)); => LFS2_MKTAG(LFS2_TYPE_DIRSTRUCT, 1, sizeof(pair));
lfs_pair_fromle32(pair); lfs2_pair_fromle32(pair);
// change tail-pointer to point to root // change tail-pointer to point to root
lfs_dir_fetch(&lfs, &mdir, pair) => 0; lfs2_dir_fetch(&lfs2, &mdir, pair) => 0;
lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS( lfs2_dir_commit(&lfs2, &mdir, LFS2_MKATTRS(
{LFS_MKTAG(LFS_TYPE_HARDTAIL, 0x3ff, 8), {LFS2_MKTAG(LFS2_TYPE_HARDTAIL, 0x3ff, 8),
(lfs_block_t[2]){0, 1}})) => 0; (lfs2_block_t[2]){0, 1}})) => 0;
lfs_deinit(&lfs) => 0; lfs2_deinit(&lfs2) => 0;
// test that mount fails gracefully // test that mount fails gracefully
lfs_mount(&lfs, &cfg) => LFS_ERR_CORRUPT; lfs2_mount(&lfs2, &cfg) => LFS2_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 = "lfs2.c"
code = ''' code = '''
// create littlefs with child dir // create littlefs with child dir
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_mkdir(&lfs, "child") => 0; lfs2_mkdir(&lfs2, "child") => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
// find child // find child
lfs_init(&lfs, &cfg) => 0; lfs2_init(&lfs2, &cfg) => 0;
lfs_mdir_t mdir; lfs2_mdir_t mdir;
lfs_block_t pair[2]; lfs2_block_t pair[2];
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; lfs2_dir_fetch(&lfs2, &mdir, (lfs2_block_t[2]){0, 1}) => 0;
lfs_dir_get(&lfs, &mdir, lfs2_dir_get(&lfs2, &mdir,
LFS_MKTAG(0x7ff, 0x3ff, 0), LFS2_MKTAG(0x7ff, 0x3ff, 0),
LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 1, sizeof(pair)), pair) LFS2_MKTAG(LFS2_TYPE_DIRSTRUCT, 1, sizeof(pair)), pair)
=> LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 1, sizeof(pair)); => LFS2_MKTAG(LFS2_TYPE_DIRSTRUCT, 1, sizeof(pair));
lfs_pair_fromle32(pair); lfs2_pair_fromle32(pair);
// change tail-pointer to point to ourself // change tail-pointer to point to ourself
lfs_dir_fetch(&lfs, &mdir, pair) => 0; lfs2_dir_fetch(&lfs2, &mdir, pair) => 0;
lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS( lfs2_dir_commit(&lfs2, &mdir, LFS2_MKATTRS(
{LFS_MKTAG(LFS_TYPE_HARDTAIL, 0x3ff, 8), pair})) => 0; {LFS2_MKTAG(LFS2_TYPE_HARDTAIL, 0x3ff, 8), pair})) => 0;
lfs_deinit(&lfs) => 0; lfs2_deinit(&lfs2) => 0;
// test that mount fails gracefully // test that mount fails gracefully
lfs_mount(&lfs, &cfg) => LFS_ERR_CORRUPT; lfs2_mount(&lfs2, &cfg) => LFS2_ERR_CORRUPT;
''' '''

View File

@@ -1,49 +1,49 @@
[[case]] # test running a filesystem to exhaustion [[case]] # test running a filesystem to exhaustion
define.LFS_ERASE_CYCLES = 10 define.LFS2_ERASE_CYCLES = 10
define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster define.LFS2_BLOCK_COUNT = 256 # small bd so test runs faster
define.LFS_BLOCK_CYCLES = 'LFS_ERASE_CYCLES / 2' define.LFS2_BLOCK_CYCLES = 'LFS2_ERASE_CYCLES / 2'
define.LFS_BADBLOCK_BEHAVIOR = [ define.LFS2_BADBLOCK_BEHAVIOR = [
'LFS_TESTBD_BADBLOCK_PROGERROR', 'LFS2_TESTBD_BADBLOCK_PROGERROR',
'LFS_TESTBD_BADBLOCK_ERASEERROR', 'LFS2_TESTBD_BADBLOCK_ERASEERROR',
'LFS_TESTBD_BADBLOCK_READERROR', 'LFS2_TESTBD_BADBLOCK_READERROR',
'LFS_TESTBD_BADBLOCK_PROGNOOP', 'LFS2_TESTBD_BADBLOCK_PROGNOOP',
'LFS_TESTBD_BADBLOCK_ERASENOOP', 'LFS2_TESTBD_BADBLOCK_ERASENOOP',
] ]
define.FILES = 10 define.FILES = 10
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_mkdir(&lfs, "roadrunner") => 0; lfs2_mkdir(&lfs2, "roadrunner") => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
uint32_t cycle = 0; uint32_t cycle = 0;
while (true) { while (true) {
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &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);
srand(cycle * i); srand(cycle * i);
size = 1 << ((rand() % 10)+2); size = 1 << ((rand() % 10)+2);
lfs_file_open(&lfs, &file, path, lfs2_file_open(&lfs2, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
for (lfs_size_t j = 0; j < size; j++) { for (lfs2_size_t j = 0; j < size; j++) {
char c = 'a' + (rand() % 26); char c = 'a' + (rand() % 26);
lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1); lfs2_ssize_t res = lfs2_file_write(&lfs2, &file, &c, 1);
assert(res == 1 || res == LFS_ERR_NOSPC); assert(res == 1 || res == LFS2_ERR_NOSPC);
if (res == LFS_ERR_NOSPC) { if (res == LFS2_ERR_NOSPC) {
err = lfs_file_close(&lfs, &file); err = lfs2_file_close(&lfs2, &file);
assert(err == 0 || err == LFS_ERR_NOSPC); assert(err == 0 || err == LFS2_ERR_NOSPC);
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
goto exhausted; goto exhausted;
} }
} }
err = lfs_file_close(&lfs, &file); err = lfs2_file_close(&lfs2, &file);
assert(err == 0 || err == LFS_ERR_NOSPC); assert(err == 0 || err == LFS2_ERR_NOSPC);
if (err == LFS_ERR_NOSPC) { if (err == LFS2_ERR_NOSPC) {
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
goto exhausted; goto exhausted;
} }
} }
@@ -54,78 +54,78 @@ code = '''
srand(cycle * i); srand(cycle * i);
size = 1 << ((rand() % 10)+2); size = 1 << ((rand() % 10)+2);
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
for (lfs_size_t j = 0; j < size; j++) { for (lfs2_size_t j = 0; j < size; j++) {
char c = 'a' + (rand() % 26); char c = 'a' + (rand() % 26);
char r; char r;
lfs_file_read(&lfs, &file, &r, 1) => 1; lfs2_file_read(&lfs2, &file, &r, 1) => 1;
assert(r == c); assert(r == c);
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
} }
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
cycle += 1; cycle += 1;
} }
exhausted: exhausted:
// should still be readable // should still be readable
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &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);
lfs_stat(&lfs, path, &info) => 0; lfs2_stat(&lfs2, path, &info) => 0;
} }
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
LFS_WARN("completed %d cycles", cycle); LFS2_WARN("completed %d cycles", cycle);
''' '''
[[case]] # test running a filesystem to exhaustion [[case]] # test running a filesystem to exhaustion
# which also requires expanding superblocks # which also requires expanding superblocks
define.LFS_ERASE_CYCLES = 10 define.LFS2_ERASE_CYCLES = 10
define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster define.LFS2_BLOCK_COUNT = 256 # small bd so test runs faster
define.LFS_BLOCK_CYCLES = 'LFS_ERASE_CYCLES / 2' define.LFS2_BLOCK_CYCLES = 'LFS2_ERASE_CYCLES / 2'
define.LFS_BADBLOCK_BEHAVIOR = [ define.LFS2_BADBLOCK_BEHAVIOR = [
'LFS_TESTBD_BADBLOCK_PROGERROR', 'LFS2_TESTBD_BADBLOCK_PROGERROR',
'LFS_TESTBD_BADBLOCK_ERASEERROR', 'LFS2_TESTBD_BADBLOCK_ERASEERROR',
'LFS_TESTBD_BADBLOCK_READERROR', 'LFS2_TESTBD_BADBLOCK_READERROR',
'LFS_TESTBD_BADBLOCK_PROGNOOP', 'LFS2_TESTBD_BADBLOCK_PROGNOOP',
'LFS_TESTBD_BADBLOCK_ERASENOOP', 'LFS2_TESTBD_BADBLOCK_ERASENOOP',
] ]
define.FILES = 10 define.FILES = 10
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
uint32_t cycle = 0; uint32_t cycle = 0;
while (true) { while (true) {
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &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);
srand(cycle * i); srand(cycle * i);
size = 1 << ((rand() % 10)+2); size = 1 << ((rand() % 10)+2);
lfs_file_open(&lfs, &file, path, lfs2_file_open(&lfs2, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
for (lfs_size_t j = 0; j < size; j++) { for (lfs2_size_t j = 0; j < size; j++) {
char c = 'a' + (rand() % 26); char c = 'a' + (rand() % 26);
lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1); lfs2_ssize_t res = lfs2_file_write(&lfs2, &file, &c, 1);
assert(res == 1 || res == LFS_ERR_NOSPC); assert(res == 1 || res == LFS2_ERR_NOSPC);
if (res == LFS_ERR_NOSPC) { if (res == LFS2_ERR_NOSPC) {
err = lfs_file_close(&lfs, &file); err = lfs2_file_close(&lfs2, &file);
assert(err == 0 || err == LFS_ERR_NOSPC); assert(err == 0 || err == LFS2_ERR_NOSPC);
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
goto exhausted; goto exhausted;
} }
} }
err = lfs_file_close(&lfs, &file); err = lfs2_file_close(&lfs2, &file);
assert(err == 0 || err == LFS_ERR_NOSPC); assert(err == 0 || err == LFS2_ERR_NOSPC);
if (err == LFS_ERR_NOSPC) { if (err == LFS2_ERR_NOSPC) {
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
goto exhausted; goto exhausted;
} }
} }
@@ -136,32 +136,32 @@ code = '''
srand(cycle * i); srand(cycle * i);
size = 1 << ((rand() % 10)+2); size = 1 << ((rand() % 10)+2);
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
for (lfs_size_t j = 0; j < size; j++) { for (lfs2_size_t j = 0; j < size; j++) {
char c = 'a' + (rand() % 26); char c = 'a' + (rand() % 26);
char r; char r;
lfs_file_read(&lfs, &file, &r, 1) => 1; lfs2_file_read(&lfs2, &file, &r, 1) => 1;
assert(r == c); assert(r == c);
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
} }
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
cycle += 1; cycle += 1;
} }
exhausted: exhausted:
// should still be readable // should still be readable
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &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);
lfs_stat(&lfs, path, &info) => 0; lfs2_stat(&lfs2, path, &info) => 0;
} }
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
LFS_WARN("completed %d cycles", cycle); LFS2_WARN("completed %d cycles", cycle);
''' '''
# These are a sort of high-level litmus test for wear-leveling. One definition # These are a sort of high-level litmus test for wear-leveling. One definition
@@ -170,53 +170,53 @@ exhausted:
# check for. # check for.
[[case]] # wear-level test running a filesystem to exhaustion [[case]] # wear-level test running a filesystem to exhaustion
define.LFS_ERASE_CYCLES = 20 define.LFS2_ERASE_CYCLES = 20
define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster define.LFS2_BLOCK_COUNT = 256 # small bd so test runs faster
define.LFS_BLOCK_CYCLES = 'LFS_ERASE_CYCLES / 2' define.LFS2_BLOCK_CYCLES = 'LFS2_ERASE_CYCLES / 2'
define.FILES = 10 define.FILES = 10
code = ''' code = '''
uint32_t run_cycles[2]; uint32_t run_cycles[2];
const uint32_t run_block_count[2] = {LFS_BLOCK_COUNT/2, LFS_BLOCK_COUNT}; const uint32_t run_block_count[2] = {LFS2_BLOCK_COUNT/2, LFS2_BLOCK_COUNT};
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 (lfs2_block_t b = 0; b < LFS2_BLOCK_COUNT; b++) {
lfs_testbd_setwear(&cfg, b, lfs2_testbd_setwear(&cfg, b,
(b < run_block_count[run]) ? 0 : LFS_ERASE_CYCLES) => 0; (b < run_block_count[run]) ? 0 : LFS2_ERASE_CYCLES) => 0;
} }
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_mkdir(&lfs, "roadrunner") => 0; lfs2_mkdir(&lfs2, "roadrunner") => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
uint32_t cycle = 0; uint32_t cycle = 0;
while (true) { while (true) {
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &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);
srand(cycle * i); srand(cycle * i);
size = 1 << ((rand() % 10)+2); size = 1 << ((rand() % 10)+2);
lfs_file_open(&lfs, &file, path, lfs2_file_open(&lfs2, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
for (lfs_size_t j = 0; j < size; j++) { for (lfs2_size_t j = 0; j < size; j++) {
char c = 'a' + (rand() % 26); char c = 'a' + (rand() % 26);
lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1); lfs2_ssize_t res = lfs2_file_write(&lfs2, &file, &c, 1);
assert(res == 1 || res == LFS_ERR_NOSPC); assert(res == 1 || res == LFS2_ERR_NOSPC);
if (res == LFS_ERR_NOSPC) { if (res == LFS2_ERR_NOSPC) {
err = lfs_file_close(&lfs, &file); err = lfs2_file_close(&lfs2, &file);
assert(err == 0 || err == LFS_ERR_NOSPC); assert(err == 0 || err == LFS2_ERR_NOSPC);
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
goto exhausted; goto exhausted;
} }
} }
err = lfs_file_close(&lfs, &file); err = lfs2_file_close(&lfs2, &file);
assert(err == 0 || err == LFS_ERR_NOSPC); assert(err == 0 || err == LFS2_ERR_NOSPC);
if (err == LFS_ERR_NOSPC) { if (err == LFS2_ERR_NOSPC) {
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
goto exhausted; goto exhausted;
} }
} }
@@ -227,85 +227,85 @@ code = '''
srand(cycle * i); srand(cycle * i);
size = 1 << ((rand() % 10)+2); size = 1 << ((rand() % 10)+2);
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
for (lfs_size_t j = 0; j < size; j++) { for (lfs2_size_t j = 0; j < size; j++) {
char c = 'a' + (rand() % 26); char c = 'a' + (rand() % 26);
char r; char r;
lfs_file_read(&lfs, &file, &r, 1) => 1; lfs2_file_read(&lfs2, &file, &r, 1) => 1;
assert(r == c); assert(r == c);
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
} }
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
cycle += 1; cycle += 1;
} }
exhausted: exhausted:
// should still be readable // should still be readable
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &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);
lfs_stat(&lfs, path, &info) => 0; lfs2_stat(&lfs2, path, &info) => 0;
} }
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
run_cycles[run] = cycle; run_cycles[run] = cycle;
LFS_WARN("completed %d blocks %d cycles", LFS2_WARN("completed %d blocks %d cycles",
run_block_count[run], run_cycles[run]); run_block_count[run], run_cycles[run]);
} }
// check we increased the lifetime by 2x with ~10% error // check we increased the lifetime by 2x with ~10% error
LFS_ASSERT(run_cycles[1]*110/100 > 2*run_cycles[0]); LFS2_ASSERT(run_cycles[1]*110/100 > 2*run_cycles[0]);
''' '''
[[case]] # wear-level test + expanding superblock [[case]] # wear-level test + expanding superblock
define.LFS_ERASE_CYCLES = 20 define.LFS2_ERASE_CYCLES = 20
define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster define.LFS2_BLOCK_COUNT = 256 # small bd so test runs faster
define.LFS_BLOCK_CYCLES = 'LFS_ERASE_CYCLES / 2' define.LFS2_BLOCK_CYCLES = 'LFS2_ERASE_CYCLES / 2'
define.FILES = 10 define.FILES = 10
code = ''' code = '''
uint32_t run_cycles[2]; uint32_t run_cycles[2];
const uint32_t run_block_count[2] = {LFS_BLOCK_COUNT/2, LFS_BLOCK_COUNT}; const uint32_t run_block_count[2] = {LFS2_BLOCK_COUNT/2, LFS2_BLOCK_COUNT};
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 (lfs2_block_t b = 0; b < LFS2_BLOCK_COUNT; b++) {
lfs_testbd_setwear(&cfg, b, lfs2_testbd_setwear(&cfg, b,
(b < run_block_count[run]) ? 0 : LFS_ERASE_CYCLES) => 0; (b < run_block_count[run]) ? 0 : LFS2_ERASE_CYCLES) => 0;
} }
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
uint32_t cycle = 0; uint32_t cycle = 0;
while (true) { while (true) {
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &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);
srand(cycle * i); srand(cycle * i);
size = 1 << ((rand() % 10)+2); size = 1 << ((rand() % 10)+2);
lfs_file_open(&lfs, &file, path, lfs2_file_open(&lfs2, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
for (lfs_size_t j = 0; j < size; j++) { for (lfs2_size_t j = 0; j < size; j++) {
char c = 'a' + (rand() % 26); char c = 'a' + (rand() % 26);
lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1); lfs2_ssize_t res = lfs2_file_write(&lfs2, &file, &c, 1);
assert(res == 1 || res == LFS_ERR_NOSPC); assert(res == 1 || res == LFS2_ERR_NOSPC);
if (res == LFS_ERR_NOSPC) { if (res == LFS2_ERR_NOSPC) {
err = lfs_file_close(&lfs, &file); err = lfs2_file_close(&lfs2, &file);
assert(err == 0 || err == LFS_ERR_NOSPC); assert(err == 0 || err == LFS2_ERR_NOSPC);
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
goto exhausted; goto exhausted;
} }
} }
err = lfs_file_close(&lfs, &file); err = lfs2_file_close(&lfs2, &file);
assert(err == 0 || err == LFS_ERR_NOSPC); assert(err == 0 || err == LFS2_ERR_NOSPC);
if (err == LFS_ERR_NOSPC) { if (err == LFS2_ERR_NOSPC) {
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
goto exhausted; goto exhausted;
} }
} }
@@ -316,81 +316,81 @@ code = '''
srand(cycle * i); srand(cycle * i);
size = 1 << ((rand() % 10)+2); size = 1 << ((rand() % 10)+2);
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
for (lfs_size_t j = 0; j < size; j++) { for (lfs2_size_t j = 0; j < size; j++) {
char c = 'a' + (rand() % 26); char c = 'a' + (rand() % 26);
char r; char r;
lfs_file_read(&lfs, &file, &r, 1) => 1; lfs2_file_read(&lfs2, &file, &r, 1) => 1;
assert(r == c); assert(r == c);
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
} }
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
cycle += 1; cycle += 1;
} }
exhausted: exhausted:
// should still be readable // should still be readable
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &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);
lfs_stat(&lfs, path, &info) => 0; lfs2_stat(&lfs2, path, &info) => 0;
} }
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
run_cycles[run] = cycle; run_cycles[run] = cycle;
LFS_WARN("completed %d blocks %d cycles", LFS2_WARN("completed %d blocks %d cycles",
run_block_count[run], run_cycles[run]); run_block_count[run], run_cycles[run]);
} }
// check we increased the lifetime by 2x with ~10% error // check we increased the lifetime by 2x with ~10% error
LFS_ASSERT(run_cycles[1]*110/100 > 2*run_cycles[0]); LFS2_ASSERT(run_cycles[1]*110/100 > 2*run_cycles[0]);
''' '''
[[case]] # test that we wear blocks roughly evenly [[case]] # test that we wear blocks roughly evenly
define.LFS_ERASE_CYCLES = 0xffffffff define.LFS2_ERASE_CYCLES = 0xffffffff
define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster define.LFS2_BLOCK_COUNT = 256 # small bd so test runs faster
define.LFS_BLOCK_CYCLES = [5, 4, 3, 2, 1] define.LFS2_BLOCK_CYCLES = [5, 4, 3, 2, 1]
define.CYCLES = 100 define.CYCLES = 100
define.FILES = 10 define.FILES = 10
if = 'LFS_BLOCK_CYCLES < CYCLES/10' if = 'LFS2_BLOCK_CYCLES < CYCLES/10'
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_mkdir(&lfs, "roadrunner") => 0; lfs2_mkdir(&lfs2, "roadrunner") => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
uint32_t cycle = 0; uint32_t cycle = 0;
while (cycle < CYCLES) { while (cycle < CYCLES) {
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &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);
srand(cycle * i); srand(cycle * i);
size = 1 << 4; //((rand() % 10)+2); size = 1 << 4; //((rand() % 10)+2);
lfs_file_open(&lfs, &file, path, lfs2_file_open(&lfs2, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
for (lfs_size_t j = 0; j < size; j++) { for (lfs2_size_t j = 0; j < size; j++) {
char c = 'a' + (rand() % 26); char c = 'a' + (rand() % 26);
lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1); lfs2_ssize_t res = lfs2_file_write(&lfs2, &file, &c, 1);
assert(res == 1 || res == LFS_ERR_NOSPC); assert(res == 1 || res == LFS2_ERR_NOSPC);
if (res == LFS_ERR_NOSPC) { if (res == LFS2_ERR_NOSPC) {
err = lfs_file_close(&lfs, &file); err = lfs2_file_close(&lfs2, &file);
assert(err == 0 || err == LFS_ERR_NOSPC); assert(err == 0 || err == LFS2_ERR_NOSPC);
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
goto exhausted; goto exhausted;
} }
} }
err = lfs_file_close(&lfs, &file); err = lfs2_file_close(&lfs2, &file);
assert(err == 0 || err == LFS_ERR_NOSPC); assert(err == 0 || err == LFS2_ERR_NOSPC);
if (err == LFS_ERR_NOSPC) { if (err == LFS2_ERR_NOSPC) {
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
goto exhausted; goto exhausted;
} }
} }
@@ -401,40 +401,40 @@ code = '''
srand(cycle * i); srand(cycle * i);
size = 1 << 4; //((rand() % 10)+2); size = 1 << 4; //((rand() % 10)+2);
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
for (lfs_size_t j = 0; j < size; j++) { for (lfs2_size_t j = 0; j < size; j++) {
char c = 'a' + (rand() % 26); char c = 'a' + (rand() % 26);
char r; char r;
lfs_file_read(&lfs, &file, &r, 1) => 1; lfs2_file_read(&lfs2, &file, &r, 1) => 1;
assert(r == c); assert(r == c);
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
} }
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
cycle += 1; cycle += 1;
} }
exhausted: exhausted:
// should still be readable // should still be readable
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &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);
lfs_stat(&lfs, path, &info) => 0; lfs2_stat(&lfs2, path, &info) => 0;
} }
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
LFS_WARN("completed %d cycles", cycle); LFS2_WARN("completed %d cycles", cycle);
// check the wear on our block device // check the wear on our block device
lfs_testbd_wear_t minwear = -1; lfs2_testbd_wear_t minwear = -1;
lfs_testbd_wear_t totalwear = 0; lfs2_testbd_wear_t totalwear = 0;
lfs_testbd_wear_t maxwear = 0; lfs2_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 (lfs2_block_t b = 2; b < LFS2_BLOCK_COUNT; b++) {
lfs_testbd_wear_t wear = lfs_testbd_getwear(&cfg, b); lfs2_testbd_wear_t wear = lfs2_testbd_getwear(&cfg, 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) {
@@ -445,21 +445,21 @@ exhausted:
} }
totalwear += wear; totalwear += wear;
} }
lfs_testbd_wear_t avgwear = totalwear / LFS_BLOCK_COUNT; lfs2_testbd_wear_t avgwear = totalwear / LFS2_BLOCK_COUNT;
LFS_WARN("max wear: %d cycles", maxwear); LFS2_WARN("max wear: %d cycles", maxwear);
LFS_WARN("avg wear: %d cycles", totalwear / LFS_BLOCK_COUNT); LFS2_WARN("avg wear: %d cycles", totalwear / LFS2_BLOCK_COUNT);
LFS_WARN("min wear: %d cycles", minwear); LFS2_WARN("min wear: %d cycles", minwear);
// find standard deviation^2 // find standard deviation^2
lfs_testbd_wear_t dev2 = 0; lfs2_testbd_wear_t dev2 = 0;
for (lfs_block_t b = 2; b < LFS_BLOCK_COUNT; b++) { for (lfs2_block_t b = 2; b < LFS2_BLOCK_COUNT; b++) {
lfs_testbd_wear_t wear = lfs_testbd_getwear(&cfg, b); lfs2_testbd_wear_t wear = lfs2_testbd_getwear(&cfg, b);
assert(wear >= 0); assert(wear >= 0);
lfs_testbd_swear_t diff = wear - avgwear; lfs2_testbd_swear_t diff = wear - avgwear;
dev2 += diff*diff; dev2 += diff*diff;
} }
dev2 /= totalwear; dev2 /= totalwear;
LFS_WARN("std dev^2: %d", dev2); LFS2_WARN("std dev^2: %d", dev2);
assert(dev2 < 8); assert(dev2 < 8);
''' '''

View File

@@ -1,60 +1,60 @@
[[case]] # simple file test [[case]] # simple file test
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "hello", lfs2_file_open(&lfs2, &file, "hello",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0;
size = strlen("Hello World!")+1; size = strlen("Hello World!")+1;
strcpy((char*)buffer, "Hello World!"); strcpy((char*)buffer, "Hello World!");
lfs_file_write(&lfs, &file, buffer, size) => size; lfs2_file_write(&lfs2, &file, buffer, size) => size;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "hello", LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, "hello", LFS2_O_RDONLY) => 0;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs2_file_read(&lfs2, &file, buffer, size) => size;
assert(strcmp((char*)buffer, "Hello World!") == 0); assert(strcmp((char*)buffer, "Hello World!") == 0);
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # larger files [[case]] # larger files
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; lfs2_format(&lfs2, &cfg) => 0;
// write // write
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", lfs2_file_open(&lfs2, &file, "avacado",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0;
srand(1); srand(1);
for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) { for (lfs2_size_t i = 0; i < SIZE; i += CHUNKSIZE) {
lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i); lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE-i);
for (lfs_size_t b = 0; b < chunk; b++) { for (lfs2_size_t b = 0; b < chunk; b++) {
buffer[b] = rand() & 0xff; buffer[b] = rand() & 0xff;
} }
lfs_file_write(&lfs, &file, buffer, chunk) => chunk; lfs2_file_write(&lfs2, &file, buffer, chunk) => chunk;
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
// read // read
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => SIZE; lfs2_file_size(&lfs2, &file) => SIZE;
srand(1); srand(1);
for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) { for (lfs2_size_t i = 0; i < SIZE; i += CHUNKSIZE) {
lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i); lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE-i);
lfs_file_read(&lfs, &file, buffer, chunk) => chunk; lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk;
for (lfs_size_t b = 0; b < chunk; b++) { for (lfs2_size_t b = 0; b < chunk; b++) {
assert(buffer[b] == (rand() & 0xff)); assert(buffer[b] == (rand() & 0xff));
} }
} }
lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; lfs2_file_read(&lfs2, &file, buffer, CHUNKSIZE) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # rewriting files [[case]] # rewriting files
@@ -62,81 +62,81 @@ 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; lfs2_format(&lfs2, &cfg) => 0;
// write // write
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", lfs2_file_open(&lfs2, &file, "avacado",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0;
srand(1); srand(1);
for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { for (lfs2_size_t i = 0; i < SIZE1; i += CHUNKSIZE) {
lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i); lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE1-i);
for (lfs_size_t b = 0; b < chunk; b++) { for (lfs2_size_t b = 0; b < chunk; b++) {
buffer[b] = rand() & 0xff; buffer[b] = rand() & 0xff;
} }
lfs_file_write(&lfs, &file, buffer, chunk) => chunk; lfs2_file_write(&lfs2, &file, buffer, chunk) => chunk;
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
// read // read
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => SIZE1; lfs2_file_size(&lfs2, &file) => SIZE1;
srand(1); srand(1);
for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { for (lfs2_size_t i = 0; i < SIZE1; i += CHUNKSIZE) {
lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i); lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE1-i);
lfs_file_read(&lfs, &file, buffer, chunk) => chunk; lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk;
for (lfs_size_t b = 0; b < chunk; b++) { for (lfs2_size_t b = 0; b < chunk; b++) {
assert(buffer[b] == (rand() & 0xff)); assert(buffer[b] == (rand() & 0xff));
} }
} }
lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; lfs2_file_read(&lfs2, &file, buffer, CHUNKSIZE) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
// rewrite // rewrite
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY) => 0; lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_WRONLY) => 0;
srand(2); srand(2);
for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { for (lfs2_size_t i = 0; i < SIZE2; i += CHUNKSIZE) {
lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i); lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE2-i);
for (lfs_size_t b = 0; b < chunk; b++) { for (lfs2_size_t b = 0; b < chunk; b++) {
buffer[b] = rand() & 0xff; buffer[b] = rand() & 0xff;
} }
lfs_file_write(&lfs, &file, buffer, chunk) => chunk; lfs2_file_write(&lfs2, &file, buffer, chunk) => chunk;
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
// read // read
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => lfs_max(SIZE1, SIZE2); lfs2_file_size(&lfs2, &file) => lfs2_max(SIZE1, SIZE2);
srand(2); srand(2);
for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { for (lfs2_size_t i = 0; i < SIZE2; i += CHUNKSIZE) {
lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i); lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE2-i);
lfs_file_read(&lfs, &file, buffer, chunk) => chunk; lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk;
for (lfs_size_t b = 0; b < chunk; b++) { for (lfs2_size_t b = 0; b < chunk; b++) {
assert(buffer[b] == (rand() & 0xff)); assert(buffer[b] == (rand() & 0xff));
} }
} }
if (SIZE1 > SIZE2) { if (SIZE1 > SIZE2) {
srand(1); srand(1);
for (lfs_size_t b = 0; b < SIZE2; b++) { for (lfs2_size_t b = 0; b < SIZE2; b++) {
rand(); rand();
} }
for (lfs_size_t i = SIZE2; i < SIZE1; i += CHUNKSIZE) { for (lfs2_size_t i = SIZE2; i < SIZE1; i += CHUNKSIZE) {
lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i); lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE1-i);
lfs_file_read(&lfs, &file, buffer, chunk) => chunk; lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk;
for (lfs_size_t b = 0; b < chunk; b++) { for (lfs2_size_t b = 0; b < chunk; b++) {
assert(buffer[b] == (rand() & 0xff)); assert(buffer[b] == (rand() & 0xff));
} }
} }
} }
lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; lfs2_file_read(&lfs2, &file, buffer, CHUNKSIZE) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # appending files [[case]] # appending files
@@ -144,76 +144,76 @@ 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; lfs2_format(&lfs2, &cfg) => 0;
// write // write
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", lfs2_file_open(&lfs2, &file, "avacado",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0;
srand(1); srand(1);
for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { for (lfs2_size_t i = 0; i < SIZE1; i += CHUNKSIZE) {
lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i); lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE1-i);
for (lfs_size_t b = 0; b < chunk; b++) { for (lfs2_size_t b = 0; b < chunk; b++) {
buffer[b] = rand() & 0xff; buffer[b] = rand() & 0xff;
} }
lfs_file_write(&lfs, &file, buffer, chunk) => chunk; lfs2_file_write(&lfs2, &file, buffer, chunk) => chunk;
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
// read // read
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => SIZE1; lfs2_file_size(&lfs2, &file) => SIZE1;
srand(1); srand(1);
for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { for (lfs2_size_t i = 0; i < SIZE1; i += CHUNKSIZE) {
lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i); lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE1-i);
lfs_file_read(&lfs, &file, buffer, chunk) => chunk; lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk;
for (lfs_size_t b = 0; b < chunk; b++) { for (lfs2_size_t b = 0; b < chunk; b++) {
assert(buffer[b] == (rand() & 0xff)); assert(buffer[b] == (rand() & 0xff));
} }
} }
lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; lfs2_file_read(&lfs2, &file, buffer, CHUNKSIZE) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
// append // append
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY | LFS_O_APPEND) => 0; lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_WRONLY | LFS2_O_APPEND) => 0;
srand(2); srand(2);
for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { for (lfs2_size_t i = 0; i < SIZE2; i += CHUNKSIZE) {
lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i); lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE2-i);
for (lfs_size_t b = 0; b < chunk; b++) { for (lfs2_size_t b = 0; b < chunk; b++) {
buffer[b] = rand() & 0xff; buffer[b] = rand() & 0xff;
} }
lfs_file_write(&lfs, &file, buffer, chunk) => chunk; lfs2_file_write(&lfs2, &file, buffer, chunk) => chunk;
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
// read // read
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => SIZE1 + SIZE2; lfs2_file_size(&lfs2, &file) => SIZE1 + SIZE2;
srand(1); srand(1);
for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { for (lfs2_size_t i = 0; i < SIZE1; i += CHUNKSIZE) {
lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i); lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE1-i);
lfs_file_read(&lfs, &file, buffer, chunk) => chunk; lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk;
for (lfs_size_t b = 0; b < chunk; b++) { for (lfs2_size_t b = 0; b < chunk; b++) {
assert(buffer[b] == (rand() & 0xff)); assert(buffer[b] == (rand() & 0xff));
} }
} }
srand(2); srand(2);
for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { for (lfs2_size_t i = 0; i < SIZE2; i += CHUNKSIZE) {
lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i); lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE2-i);
lfs_file_read(&lfs, &file, buffer, chunk) => chunk; lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk;
for (lfs_size_t b = 0; b < chunk; b++) { for (lfs2_size_t b = 0; b < chunk; b++) {
assert(buffer[b] == (rand() & 0xff)); assert(buffer[b] == (rand() & 0xff));
} }
} }
lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; lfs2_file_read(&lfs2, &file, buffer, CHUNKSIZE) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # truncating files [[case]] # truncating files
@@ -221,68 +221,68 @@ 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; lfs2_format(&lfs2, &cfg) => 0;
// write // write
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", lfs2_file_open(&lfs2, &file, "avacado",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0;
srand(1); srand(1);
for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { for (lfs2_size_t i = 0; i < SIZE1; i += CHUNKSIZE) {
lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i); lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE1-i);
for (lfs_size_t b = 0; b < chunk; b++) { for (lfs2_size_t b = 0; b < chunk; b++) {
buffer[b] = rand() & 0xff; buffer[b] = rand() & 0xff;
} }
lfs_file_write(&lfs, &file, buffer, chunk) => chunk; lfs2_file_write(&lfs2, &file, buffer, chunk) => chunk;
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
// read // read
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => SIZE1; lfs2_file_size(&lfs2, &file) => SIZE1;
srand(1); srand(1);
for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { for (lfs2_size_t i = 0; i < SIZE1; i += CHUNKSIZE) {
lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i); lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE1-i);
lfs_file_read(&lfs, &file, buffer, chunk) => chunk; lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk;
for (lfs_size_t b = 0; b < chunk; b++) { for (lfs2_size_t b = 0; b < chunk; b++) {
assert(buffer[b] == (rand() & 0xff)); assert(buffer[b] == (rand() & 0xff));
} }
} }
lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; lfs2_file_read(&lfs2, &file, buffer, CHUNKSIZE) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
// truncate // truncate
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY | LFS_O_TRUNC) => 0; lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_WRONLY | LFS2_O_TRUNC) => 0;
srand(2); srand(2);
for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { for (lfs2_size_t i = 0; i < SIZE2; i += CHUNKSIZE) {
lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i); lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE2-i);
for (lfs_size_t b = 0; b < chunk; b++) { for (lfs2_size_t b = 0; b < chunk; b++) {
buffer[b] = rand() & 0xff; buffer[b] = rand() & 0xff;
} }
lfs_file_write(&lfs, &file, buffer, chunk) => chunk; lfs2_file_write(&lfs2, &file, buffer, chunk) => chunk;
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
// read // read
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => SIZE2; lfs2_file_size(&lfs2, &file) => SIZE2;
srand(2); srand(2);
for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { for (lfs2_size_t i = 0; i < SIZE2; i += CHUNKSIZE) {
lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i); lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE2-i);
lfs_file_read(&lfs, &file, buffer, chunk) => chunk; lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk;
for (lfs_size_t b = 0; b < chunk; b++) { for (lfs2_size_t b = 0; b < chunk; b++) {
assert(buffer[b] == (rand() & 0xff)); assert(buffer[b] == (rand() & 0xff));
} }
} }
lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; lfs2_file_read(&lfs2, &file, buffer, CHUNKSIZE) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # reentrant file writing [[case]] # reentrant file writing
@@ -290,197 +290,197 @@ 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 = lfs2_mount(&lfs2, &cfg);
if (err) { if (err) {
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
} }
err = lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY); err = lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_RDONLY);
assert(err == LFS_ERR_NOENT || err == 0); assert(err == LFS2_ERR_NOENT || err == 0);
if (err == 0) { if (err == 0) {
// can only be 0 (new file) or full size // can only be 0 (new file) or full size
size = lfs_file_size(&lfs, &file); size = lfs2_file_size(&lfs2, &file);
assert(size == 0 || size == SIZE); assert(size == 0 || size == SIZE);
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
} }
// write // write
lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
srand(1); srand(1);
for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) { for (lfs2_size_t i = 0; i < SIZE; i += CHUNKSIZE) {
lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i); lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE-i);
for (lfs_size_t b = 0; b < chunk; b++) { for (lfs2_size_t b = 0; b < chunk; b++) {
buffer[b] = rand() & 0xff; buffer[b] = rand() & 0xff;
} }
lfs_file_write(&lfs, &file, buffer, chunk) => chunk; lfs2_file_write(&lfs2, &file, buffer, chunk) => chunk;
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// read // read
lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => SIZE; lfs2_file_size(&lfs2, &file) => SIZE;
srand(1); srand(1);
for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) { for (lfs2_size_t i = 0; i < SIZE; i += CHUNKSIZE) {
lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i); lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE-i);
lfs_file_read(&lfs, &file, buffer, chunk) => chunk; lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk;
for (lfs_size_t b = 0; b < chunk; b++) { for (lfs2_size_t b = 0; b < chunk; b++) {
assert(buffer[b] == (rand() & 0xff)); assert(buffer[b] == (rand() & 0xff));
} }
} }
lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; lfs2_file_read(&lfs2, &file, buffer, CHUNKSIZE) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # reentrant file writing with syncs [[case]] # reentrant file writing with syncs
define = [ define = [
# append (O(n)) # append (O(n))
{MODE='LFS_O_APPEND', SIZE=[32, 0, 7, 2049], CHUNKSIZE=[31, 16, 65]}, {MODE='LFS2_O_APPEND', SIZE=[32, 0, 7, 2049], CHUNKSIZE=[31, 16, 65]},
# truncate (O(n^2)) # truncate (O(n^2))
{MODE='LFS_O_TRUNC', SIZE=[32, 0, 7, 200], CHUNKSIZE=[31, 16, 65]}, {MODE='LFS2_O_TRUNC', SIZE=[32, 0, 7, 200], CHUNKSIZE=[31, 16, 65]},
# rewrite (O(n^2)) # rewrite (O(n^2))
{MODE=0, SIZE=[32, 0, 7, 200], CHUNKSIZE=[31, 16, 65]}, {MODE=0, SIZE=[32, 0, 7, 200], CHUNKSIZE=[31, 16, 65]},
] ]
reentrant = true reentrant = true
code = ''' code = '''
err = lfs_mount(&lfs, &cfg); err = lfs2_mount(&lfs2, &cfg);
if (err) { if (err) {
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
} }
err = lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY); err = lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_RDONLY);
assert(err == LFS_ERR_NOENT || err == 0); assert(err == LFS2_ERR_NOENT || err == 0);
if (err == 0) { if (err == 0) {
// with syncs we could be any size, but it at least must be valid data // with syncs we could be any size, but it at least must be valid data
size = lfs_file_size(&lfs, &file); size = lfs2_file_size(&lfs2, &file);
assert(size <= SIZE); assert(size <= SIZE);
srand(1); srand(1);
for (lfs_size_t i = 0; i < size; i += CHUNKSIZE) { for (lfs2_size_t i = 0; i < size; i += CHUNKSIZE) {
lfs_size_t chunk = lfs_min(CHUNKSIZE, size-i); lfs2_size_t chunk = lfs2_min(CHUNKSIZE, size-i);
lfs_file_read(&lfs, &file, buffer, chunk) => chunk; lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk;
for (lfs_size_t b = 0; b < chunk; b++) { for (lfs2_size_t b = 0; b < chunk; b++) {
assert(buffer[b] == (rand() & 0xff)); assert(buffer[b] == (rand() & 0xff));
} }
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
} }
// write // write
lfs_file_open(&lfs, &file, "avacado", lfs2_file_open(&lfs2, &file, "avacado",
LFS_O_WRONLY | LFS_O_CREAT | MODE) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | MODE) => 0;
size = lfs_file_size(&lfs, &file); size = lfs2_file_size(&lfs2, &file);
assert(size <= SIZE); assert(size <= SIZE);
srand(1); srand(1);
lfs_size_t skip = (MODE == LFS_O_APPEND) ? size : 0; lfs2_size_t skip = (MODE == LFS2_O_APPEND) ? size : 0;
for (lfs_size_t b = 0; b < skip; b++) { for (lfs2_size_t b = 0; b < skip; b++) {
rand(); rand();
} }
for (lfs_size_t i = skip; i < SIZE; i += CHUNKSIZE) { for (lfs2_size_t i = skip; i < SIZE; i += CHUNKSIZE) {
lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i); lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE-i);
for (lfs_size_t b = 0; b < chunk; b++) { for (lfs2_size_t b = 0; b < chunk; b++) {
buffer[b] = rand() & 0xff; buffer[b] = rand() & 0xff;
} }
lfs_file_write(&lfs, &file, buffer, chunk) => chunk; lfs2_file_write(&lfs2, &file, buffer, chunk) => chunk;
lfs_file_sync(&lfs, &file) => 0; lfs2_file_sync(&lfs2, &file) => 0;
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// read // read
lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => SIZE; lfs2_file_size(&lfs2, &file) => SIZE;
srand(1); srand(1);
for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) { for (lfs2_size_t i = 0; i < SIZE; i += CHUNKSIZE) {
lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i); lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE-i);
lfs_file_read(&lfs, &file, buffer, chunk) => chunk; lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk;
for (lfs_size_t b = 0; b < chunk; b++) { for (lfs2_size_t b = 0; b < chunk; b++) {
assert(buffer[b] == (rand() & 0xff)); assert(buffer[b] == (rand() & 0xff));
} }
} }
lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; lfs2_file_read(&lfs2, &file, buffer, CHUNKSIZE) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # many files [[case]] # many files
define.N = 300 define.N = 300
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
// create N files of 7 bytes // create N files of 7 bytes
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &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, lfs2_file_open(&lfs2, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0;
char wbuffer[1024]; char wbuffer[1024];
size = 7; size = 7;
snprintf(wbuffer, size, "Hi %03d", i); snprintf(wbuffer, size, "Hi %03d", i);
lfs_file_write(&lfs, &file, wbuffer, size) => size; lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
char rbuffer[1024]; char rbuffer[1024];
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
assert(strcmp(rbuffer, wbuffer) == 0); assert(strcmp(rbuffer, wbuffer) == 0);
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
} }
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[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; lfs2_format(&lfs2, &cfg) => 0;
// create N files of 7 bytes // create N files of 7 bytes
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &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, lfs2_file_open(&lfs2, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0;
char wbuffer[1024]; char wbuffer[1024];
size = 7; size = 7;
snprintf(wbuffer, size, "Hi %03d", i); snprintf(wbuffer, size, "Hi %03d", i);
lfs_file_write(&lfs, &file, wbuffer, size) => size; lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
char rbuffer[1024]; char rbuffer[1024];
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
assert(strcmp(rbuffer, wbuffer) == 0); assert(strcmp(rbuffer, wbuffer) == 0);
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
} }
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # many files with power loss [[case]] # many files with power loss
define.N = 300 define.N = 300
reentrant = true reentrant = true
code = ''' code = '''
err = lfs_mount(&lfs, &cfg); err = lfs2_mount(&lfs2, &cfg);
if (err) { if (err) {
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &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++) {
sprintf(path, "file_%03d", i); sprintf(path, "file_%03d", i);
err = lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT); err = lfs2_file_open(&lfs2, &file, path, LFS2_O_WRONLY | LFS2_O_CREAT);
char wbuffer[1024]; char wbuffer[1024];
size = 7; size = 7;
snprintf(wbuffer, size, "Hi %03d", i); snprintf(wbuffer, size, "Hi %03d", i);
if ((lfs_size_t)lfs_file_size(&lfs, &file) != size) { if ((lfs2_size_t)lfs2_file_size(&lfs2, &file) != size) {
lfs_file_write(&lfs, &file, wbuffer, size) => size; lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
char rbuffer[1024]; char rbuffer[1024];
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
assert(strcmp(rbuffer, wbuffer) == 0); assert(strcmp(rbuffer, wbuffer) == 0);
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
} }
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''

View File

@@ -3,60 +3,60 @@
define.SIZE = [10, 100] define.SIZE = [10, 100]
define.FILES = [4, 10, 26] define.FILES = [4, 10, 26]
code = ''' code = '''
lfs_file_t files[FILES]; lfs2_file_t files[FILES];
const char alphas[] = "abcdefghijklmnopqrstuvwxyz"; const char alphas[] = "abcdefghijklmnopqrstuvwxyz";
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &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, lfs2_file_open(&lfs2, &files[j], path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0;
} }
for (int i = 0; i < SIZE; i++) { for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < FILES; j++) { for (int j = 0; j < FILES; j++) {
lfs_file_write(&lfs, &files[j], &alphas[j], 1) => 1; lfs2_file_write(&lfs2, &files[j], &alphas[j], 1) => 1;
} }
} }
for (int j = 0; j < FILES; j++) { for (int j = 0; j < FILES; j++) {
lfs_file_close(&lfs, &files[j]); lfs2_file_close(&lfs2, &files[j]);
} }
lfs_dir_open(&lfs, &dir, "/") => 0; lfs2_dir_open(&lfs2, &dir, "/") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs2_dir_read(&lfs2, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS2_TYPE_DIR);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs2_dir_read(&lfs2, &dir, &info) => 1;
assert(strcmp(info.name, "..") == 0); assert(strcmp(info.name, "..") == 0);
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS2_TYPE_DIR);
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_dir_read(&lfs, &dir, &info) => 1; lfs2_dir_read(&lfs2, &dir, &info) => 1;
assert(strcmp(info.name, path) == 0); assert(strcmp(info.name, path) == 0);
assert(info.type == LFS_TYPE_REG); assert(info.type == LFS2_TYPE_REG);
assert(info.size == SIZE); assert(info.size == SIZE);
} }
lfs_dir_read(&lfs, &dir, &info) => 0; lfs2_dir_read(&lfs2, &dir, &info) => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs2_dir_close(&lfs2, &dir) => 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_O_RDONLY) => 0; lfs2_file_open(&lfs2, &files[j], path, LFS2_O_RDONLY) => 0;
} }
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
for (int j = 0; j < FILES; j++) { for (int j = 0; j < FILES; j++) {
lfs_file_read(&lfs, &files[j], buffer, 1) => 1; lfs2_file_read(&lfs2, &files[j], buffer, 1) => 1;
assert(buffer[0] == alphas[j]); assert(buffer[0] == alphas[j]);
} }
} }
for (int j = 0; j < FILES; j++) { for (int j = 0; j < FILES; j++) {
lfs_file_close(&lfs, &files[j]); lfs2_file_close(&lfs2, &files[j]);
} }
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # interspersed remove file test [[case]] # interspersed remove file test
@@ -64,112 +64,112 @@ 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; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &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, lfs2_file_open(&lfs2, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0;
for (int i = 0; i < SIZE; i++) { for (int i = 0; i < SIZE; i++) {
lfs_file_write(&lfs, &file, &alphas[j], 1) => 1; lfs2_file_write(&lfs2, &file, &alphas[j], 1) => 1;
} }
lfs_file_close(&lfs, &file); lfs2_file_close(&lfs2, &file);
} }
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "zzz", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs2_file_open(&lfs2, &file, "zzz", LFS2_O_WRONLY | LFS2_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; lfs2_file_write(&lfs2, &file, (const void*)"~", 1) => 1;
lfs_file_sync(&lfs, &file) => 0; lfs2_file_sync(&lfs2, &file) => 0;
sprintf(path, "%c", alphas[j]); sprintf(path, "%c", alphas[j]);
lfs_remove(&lfs, path) => 0; lfs2_remove(&lfs2, path) => 0;
} }
lfs_file_close(&lfs, &file); lfs2_file_close(&lfs2, &file);
lfs_dir_open(&lfs, &dir, "/") => 0; lfs2_dir_open(&lfs2, &dir, "/") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs2_dir_read(&lfs2, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS2_TYPE_DIR);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs2_dir_read(&lfs2, &dir, &info) => 1;
assert(strcmp(info.name, "..") == 0); assert(strcmp(info.name, "..") == 0);
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS2_TYPE_DIR);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs2_dir_read(&lfs2, &dir, &info) => 1;
assert(strcmp(info.name, "zzz") == 0); assert(strcmp(info.name, "zzz") == 0);
assert(info.type == LFS_TYPE_REG); assert(info.type == LFS2_TYPE_REG);
assert(info.size == FILES); assert(info.size == FILES);
lfs_dir_read(&lfs, &dir, &info) => 0; lfs2_dir_read(&lfs2, &dir, &info) => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs2_dir_close(&lfs2, &dir) => 0;
lfs_file_open(&lfs, &file, "zzz", LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, "zzz", LFS2_O_RDONLY) => 0;
for (int i = 0; i < FILES; i++) { for (int i = 0; i < FILES; i++) {
lfs_file_read(&lfs, &file, buffer, 1) => 1; lfs2_file_read(&lfs2, &file, buffer, 1) => 1;
assert(buffer[0] == '~'); assert(buffer[0] == '~');
} }
lfs_file_close(&lfs, &file); lfs2_file_close(&lfs2, &file);
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # remove inconveniently test [[case]] # remove inconveniently test
define.SIZE = [10, 100] define.SIZE = [10, 100]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_t files[3]; lfs2_file_t files[3];
lfs_file_open(&lfs, &files[0], "e", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs2_file_open(&lfs2, &files[0], "e", LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
lfs_file_open(&lfs, &files[1], "f", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs2_file_open(&lfs2, &files[1], "f", LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
lfs_file_open(&lfs, &files[2], "g", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs2_file_open(&lfs2, &files[2], "g", LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
for (int i = 0; i < SIZE/2; i++) { for (int i = 0; i < SIZE/2; i++) {
lfs_file_write(&lfs, &files[0], (const void*)"e", 1) => 1; lfs2_file_write(&lfs2, &files[0], (const void*)"e", 1) => 1;
lfs_file_write(&lfs, &files[1], (const void*)"f", 1) => 1; lfs2_file_write(&lfs2, &files[1], (const void*)"f", 1) => 1;
lfs_file_write(&lfs, &files[2], (const void*)"g", 1) => 1; lfs2_file_write(&lfs2, &files[2], (const void*)"g", 1) => 1;
} }
lfs_remove(&lfs, "f") => 0; lfs2_remove(&lfs2, "f") => 0;
for (int i = 0; i < SIZE/2; i++) { for (int i = 0; i < SIZE/2; i++) {
lfs_file_write(&lfs, &files[0], (const void*)"e", 1) => 1; lfs2_file_write(&lfs2, &files[0], (const void*)"e", 1) => 1;
lfs_file_write(&lfs, &files[1], (const void*)"f", 1) => 1; lfs2_file_write(&lfs2, &files[1], (const void*)"f", 1) => 1;
lfs_file_write(&lfs, &files[2], (const void*)"g", 1) => 1; lfs2_file_write(&lfs2, &files[2], (const void*)"g", 1) => 1;
} }
lfs_file_close(&lfs, &files[0]); lfs2_file_close(&lfs2, &files[0]);
lfs_file_close(&lfs, &files[1]); lfs2_file_close(&lfs2, &files[1]);
lfs_file_close(&lfs, &files[2]); lfs2_file_close(&lfs2, &files[2]);
lfs_dir_open(&lfs, &dir, "/") => 0; lfs2_dir_open(&lfs2, &dir, "/") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs2_dir_read(&lfs2, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS2_TYPE_DIR);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs2_dir_read(&lfs2, &dir, &info) => 1;
assert(strcmp(info.name, "..") == 0); assert(strcmp(info.name, "..") == 0);
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS2_TYPE_DIR);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs2_dir_read(&lfs2, &dir, &info) => 1;
assert(strcmp(info.name, "e") == 0); assert(strcmp(info.name, "e") == 0);
assert(info.type == LFS_TYPE_REG); assert(info.type == LFS2_TYPE_REG);
assert(info.size == SIZE); assert(info.size == SIZE);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs2_dir_read(&lfs2, &dir, &info) => 1;
assert(strcmp(info.name, "g") == 0); assert(strcmp(info.name, "g") == 0);
assert(info.type == LFS_TYPE_REG); assert(info.type == LFS2_TYPE_REG);
assert(info.size == SIZE); assert(info.size == SIZE);
lfs_dir_read(&lfs, &dir, &info) => 0; lfs2_dir_read(&lfs2, &dir, &info) => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs2_dir_close(&lfs2, &dir) => 0;
lfs_file_open(&lfs, &files[0], "e", LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &files[0], "e", LFS2_O_RDONLY) => 0;
lfs_file_open(&lfs, &files[1], "g", LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &files[1], "g", LFS2_O_RDONLY) => 0;
for (int i = 0; i < SIZE; i++) { for (int i = 0; i < SIZE; i++) {
lfs_file_read(&lfs, &files[0], buffer, 1) => 1; lfs2_file_read(&lfs2, &files[0], buffer, 1) => 1;
assert(buffer[0] == 'e'); assert(buffer[0] == 'e');
lfs_file_read(&lfs, &files[1], buffer, 1) => 1; lfs2_file_read(&lfs2, &files[1], buffer, 1) => 1;
assert(buffer[0] == 'g'); assert(buffer[0] == 'g');
} }
lfs_file_close(&lfs, &files[0]); lfs2_file_close(&lfs2, &files[0]);
lfs_file_close(&lfs, &files[1]); lfs2_file_close(&lfs2, &files[1]);
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # reentrant interspersed file test [[case]] # reentrant interspersed file test
@@ -177,68 +177,68 @@ define.SIZE = [10, 100]
define.FILES = [4, 10, 26] define.FILES = [4, 10, 26]
reentrant = true reentrant = true
code = ''' code = '''
lfs_file_t files[FILES]; lfs2_file_t files[FILES];
const char alphas[] = "abcdefghijklmnopqrstuvwxyz"; const char alphas[] = "abcdefghijklmnopqrstuvwxyz";
err = lfs_mount(&lfs, &cfg); err = lfs2_mount(&lfs2, &cfg);
if (err) { if (err) {
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &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, lfs2_file_open(&lfs2, &files[j], path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_APPEND) => 0;
} }
for (int i = 0; i < SIZE; i++) { for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < FILES; j++) { for (int j = 0; j < FILES; j++) {
size = lfs_file_size(&lfs, &files[j]); size = lfs2_file_size(&lfs2, &files[j]);
assert((int)size >= 0); assert((int)size >= 0);
if ((int)size <= i) { if ((int)size <= i) {
lfs_file_write(&lfs, &files[j], &alphas[j], 1) => 1; lfs2_file_write(&lfs2, &files[j], &alphas[j], 1) => 1;
lfs_file_sync(&lfs, &files[j]) => 0; lfs2_file_sync(&lfs2, &files[j]) => 0;
} }
} }
} }
for (int j = 0; j < FILES; j++) { for (int j = 0; j < FILES; j++) {
lfs_file_close(&lfs, &files[j]); lfs2_file_close(&lfs2, &files[j]);
} }
lfs_dir_open(&lfs, &dir, "/") => 0; lfs2_dir_open(&lfs2, &dir, "/") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs2_dir_read(&lfs2, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS2_TYPE_DIR);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs2_dir_read(&lfs2, &dir, &info) => 1;
assert(strcmp(info.name, "..") == 0); assert(strcmp(info.name, "..") == 0);
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS2_TYPE_DIR);
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_dir_read(&lfs, &dir, &info) => 1; lfs2_dir_read(&lfs2, &dir, &info) => 1;
assert(strcmp(info.name, path) == 0); assert(strcmp(info.name, path) == 0);
assert(info.type == LFS_TYPE_REG); assert(info.type == LFS2_TYPE_REG);
assert(info.size == SIZE); assert(info.size == SIZE);
} }
lfs_dir_read(&lfs, &dir, &info) => 0; lfs2_dir_read(&lfs2, &dir, &info) => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs2_dir_close(&lfs2, &dir) => 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_O_RDONLY) => 0; lfs2_file_open(&lfs2, &files[j], path, LFS2_O_RDONLY) => 0;
} }
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
for (int j = 0; j < FILES; j++) { for (int j = 0; j < FILES; j++) {
lfs_file_read(&lfs, &files[j], buffer, 1) => 1; lfs2_file_read(&lfs2, &files[j], buffer, 1) => 1;
assert(buffer[0] == alphas[j]); assert(buffer[0] == alphas[j]);
} }
} }
for (int j = 0; j < FILES; j++) { for (int j = 0; j < FILES; j++) {
lfs_file_close(&lfs, &files[j]); lfs2_file_close(&lfs2, &files[j]);
} }
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''

File diff suppressed because it is too large Load Diff

View File

@@ -1,75 +1,75 @@
[[case]] # orphan test [[case]] # orphan test
in = "lfs.c" in = "lfs2.c"
if = 'LFS_PROG_SIZE <= 0x3fe' # only works with one crc per commit if = 'LFS2_PROG_SIZE <= 0x3fe' # only works with one crc per commit
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_mkdir(&lfs, "parent") => 0; lfs2_mkdir(&lfs2, "parent") => 0;
lfs_mkdir(&lfs, "parent/orphan") => 0; lfs2_mkdir(&lfs2, "parent/orphan") => 0;
lfs_mkdir(&lfs, "parent/child") => 0; lfs2_mkdir(&lfs2, "parent/child") => 0;
lfs_remove(&lfs, "parent/orphan") => 0; lfs2_remove(&lfs2, "parent/orphan") => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
// 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; lfs2_mount(&lfs2, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "parent/child") => 0; lfs2_dir_open(&lfs2, &dir, "parent/child") => 0;
lfs_block_t block = dir.m.pair[0]; lfs2_block_t block = dir.m.pair[0];
lfs_dir_close(&lfs, &dir) => 0; lfs2_dir_close(&lfs2, &dir) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
uint8_t bbuffer[LFS_BLOCK_SIZE]; uint8_t bbuffer[LFS2_BLOCK_SIZE];
cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; cfg.read(&cfg, block, 0, bbuffer, LFS2_BLOCK_SIZE) => 0;
int off = LFS_BLOCK_SIZE-1; int off = LFS2_BLOCK_SIZE-1;
while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { while (off >= 0 && bbuffer[off] == LFS2_ERASE_VALUE) {
off -= 1; off -= 1;
} }
memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); memset(&bbuffer[off-3], LFS2_BLOCK_SIZE, 3);
cfg.erase(&cfg, block) => 0; cfg.erase(&cfg, block) => 0;
cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; cfg.prog(&cfg, block, 0, bbuffer, LFS2_BLOCK_SIZE) => 0;
cfg.sync(&cfg) => 0; cfg.sync(&cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT; lfs2_stat(&lfs2, "parent/orphan", &info) => LFS2_ERR_NOENT;
lfs_stat(&lfs, "parent/child", &info) => 0; lfs2_stat(&lfs2, "parent/child", &info) => 0;
lfs_fs_size(&lfs) => 8; lfs2_fs_size(&lfs2) => 8;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT; lfs2_stat(&lfs2, "parent/orphan", &info) => LFS2_ERR_NOENT;
lfs_stat(&lfs, "parent/child", &info) => 0; lfs2_stat(&lfs2, "parent/child", &info) => 0;
lfs_fs_size(&lfs) => 8; lfs2_fs_size(&lfs2) => 8;
// this mkdir should both create a dir and deorphan, so size // this mkdir should both create a dir and deorphan, so size
// should be unchanged // should be unchanged
lfs_mkdir(&lfs, "parent/otherchild") => 0; lfs2_mkdir(&lfs2, "parent/otherchild") => 0;
lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT; lfs2_stat(&lfs2, "parent/orphan", &info) => LFS2_ERR_NOENT;
lfs_stat(&lfs, "parent/child", &info) => 0; lfs2_stat(&lfs2, "parent/child", &info) => 0;
lfs_stat(&lfs, "parent/otherchild", &info) => 0; lfs2_stat(&lfs2, "parent/otherchild", &info) => 0;
lfs_fs_size(&lfs) => 8; lfs2_fs_size(&lfs2) => 8;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT; lfs2_stat(&lfs2, "parent/orphan", &info) => LFS2_ERR_NOENT;
lfs_stat(&lfs, "parent/child", &info) => 0; lfs2_stat(&lfs2, "parent/child", &info) => 0;
lfs_stat(&lfs, "parent/otherchild", &info) => 0; lfs2_stat(&lfs2, "parent/otherchild", &info) => 0;
lfs_fs_size(&lfs) => 8; lfs2_fs_size(&lfs2) => 8;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[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 && LFS2_CACHE_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 = lfs2_mount(&lfs2, &cfg);
if (err) { if (err) {
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
} }
srand(1); srand(1);
@@ -82,39 +82,39 @@ code = '''
} }
// if it does not exist, we create it, else we destroy // if it does not exist, we create it, else we destroy
int res = lfs_stat(&lfs, full_path, &info); int res = lfs2_stat(&lfs2, full_path, &info);
if (res == LFS_ERR_NOENT) { if (res == LFS2_ERR_NOENT) {
// create each directory in turn, ignore if dir already exists // create each directory in turn, ignore if dir already exists
for (int d = 0; d < DEPTH; d++) { for (int d = 0; d < DEPTH; d++) {
strcpy(path, full_path); strcpy(path, full_path);
path[2*d+2] = '\0'; path[2*d+2] = '\0';
err = lfs_mkdir(&lfs, path); err = lfs2_mkdir(&lfs2, path);
assert(!err || err == LFS_ERR_EXIST); assert(!err || err == LFS2_ERR_EXIST);
} }
for (int d = 0; d < DEPTH; d++) { for (int d = 0; d < DEPTH; d++) {
strcpy(path, full_path); strcpy(path, full_path);
path[2*d+2] = '\0'; path[2*d+2] = '\0';
lfs_stat(&lfs, path, &info) => 0; lfs2_stat(&lfs2, path, &info) => 0;
assert(strcmp(info.name, &path[2*d+1]) == 0); assert(strcmp(info.name, &path[2*d+1]) == 0);
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS2_TYPE_DIR);
} }
} else { } else {
// is valid dir? // is valid dir?
assert(strcmp(info.name, &full_path[2*(DEPTH-1)+1]) == 0); assert(strcmp(info.name, &full_path[2*(DEPTH-1)+1]) == 0);
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS2_TYPE_DIR);
// try to delete path in reverse order, ignore if dir is not empty // try to delete path in reverse order, ignore if dir is not empty
for (int d = DEPTH-1; d >= 0; d--) { for (int d = DEPTH-1; d >= 0; d--) {
strcpy(path, full_path); strcpy(path, full_path);
path[2*d+2] = '\0'; path[2*d+2] = '\0';
err = lfs_remove(&lfs, path); err = lfs2_remove(&lfs2, path);
assert(!err || err == LFS_ERR_NOTEMPTY); assert(!err || err == LFS2_ERR_NOTEMPTY);
} }
lfs_stat(&lfs, full_path, &info) => LFS_ERR_NOENT; lfs2_stat(&lfs2, full_path, &info) => LFS2_ERR_NOENT;
} }
} }
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''

View File

@@ -1,293 +1,293 @@
[[case]] # simple path test [[case]] # simple path test
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_mkdir(&lfs, "tea") => 0; lfs2_mkdir(&lfs2, "tea") => 0;
lfs_mkdir(&lfs, "tea/hottea") => 0; lfs2_mkdir(&lfs2, "tea/hottea") => 0;
lfs_mkdir(&lfs, "tea/warmtea") => 0; lfs2_mkdir(&lfs2, "tea/warmtea") => 0;
lfs_mkdir(&lfs, "tea/coldtea") => 0; lfs2_mkdir(&lfs2, "tea/coldtea") => 0;
lfs_stat(&lfs, "tea/hottea", &info) => 0; lfs2_stat(&lfs2, "tea/hottea", &info) => 0;
assert(strcmp(info.name, "hottea") == 0); assert(strcmp(info.name, "hottea") == 0);
lfs_stat(&lfs, "/tea/hottea", &info) => 0; lfs2_stat(&lfs2, "/tea/hottea", &info) => 0;
assert(strcmp(info.name, "hottea") == 0); assert(strcmp(info.name, "hottea") == 0);
lfs_mkdir(&lfs, "/milk") => 0; lfs2_mkdir(&lfs2, "/milk") => 0;
lfs_stat(&lfs, "/milk", &info) => 0; lfs2_stat(&lfs2, "/milk", &info) => 0;
assert(strcmp(info.name, "milk") == 0); assert(strcmp(info.name, "milk") == 0);
lfs_stat(&lfs, "milk", &info) => 0; lfs2_stat(&lfs2, "milk", &info) => 0;
assert(strcmp(info.name, "milk") == 0); assert(strcmp(info.name, "milk") == 0);
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # redundant slashes [[case]] # redundant slashes
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_mkdir(&lfs, "tea") => 0; lfs2_mkdir(&lfs2, "tea") => 0;
lfs_mkdir(&lfs, "tea/hottea") => 0; lfs2_mkdir(&lfs2, "tea/hottea") => 0;
lfs_mkdir(&lfs, "tea/warmtea") => 0; lfs2_mkdir(&lfs2, "tea/warmtea") => 0;
lfs_mkdir(&lfs, "tea/coldtea") => 0; lfs2_mkdir(&lfs2, "tea/coldtea") => 0;
lfs_stat(&lfs, "/tea/hottea", &info) => 0; lfs2_stat(&lfs2, "/tea/hottea", &info) => 0;
assert(strcmp(info.name, "hottea") == 0); assert(strcmp(info.name, "hottea") == 0);
lfs_stat(&lfs, "//tea//hottea", &info) => 0; lfs2_stat(&lfs2, "//tea//hottea", &info) => 0;
assert(strcmp(info.name, "hottea") == 0); assert(strcmp(info.name, "hottea") == 0);
lfs_stat(&lfs, "///tea///hottea", &info) => 0; lfs2_stat(&lfs2, "///tea///hottea", &info) => 0;
assert(strcmp(info.name, "hottea") == 0); assert(strcmp(info.name, "hottea") == 0);
lfs_mkdir(&lfs, "////milk") => 0; lfs2_mkdir(&lfs2, "////milk") => 0;
lfs_stat(&lfs, "////milk", &info) => 0; lfs2_stat(&lfs2, "////milk", &info) => 0;
assert(strcmp(info.name, "milk") == 0); assert(strcmp(info.name, "milk") == 0);
lfs_stat(&lfs, "milk", &info) => 0; lfs2_stat(&lfs2, "milk", &info) => 0;
assert(strcmp(info.name, "milk") == 0); assert(strcmp(info.name, "milk") == 0);
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # dot path test [[case]] # dot path test
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_mkdir(&lfs, "tea") => 0; lfs2_mkdir(&lfs2, "tea") => 0;
lfs_mkdir(&lfs, "tea/hottea") => 0; lfs2_mkdir(&lfs2, "tea/hottea") => 0;
lfs_mkdir(&lfs, "tea/warmtea") => 0; lfs2_mkdir(&lfs2, "tea/warmtea") => 0;
lfs_mkdir(&lfs, "tea/coldtea") => 0; lfs2_mkdir(&lfs2, "tea/coldtea") => 0;
lfs_stat(&lfs, "./tea/hottea", &info) => 0; lfs2_stat(&lfs2, "./tea/hottea", &info) => 0;
assert(strcmp(info.name, "hottea") == 0); assert(strcmp(info.name, "hottea") == 0);
lfs_stat(&lfs, "/./tea/hottea", &info) => 0; lfs2_stat(&lfs2, "/./tea/hottea", &info) => 0;
assert(strcmp(info.name, "hottea") == 0); assert(strcmp(info.name, "hottea") == 0);
lfs_stat(&lfs, "/././tea/hottea", &info) => 0; lfs2_stat(&lfs2, "/././tea/hottea", &info) => 0;
assert(strcmp(info.name, "hottea") == 0); assert(strcmp(info.name, "hottea") == 0);
lfs_stat(&lfs, "/./tea/./hottea", &info) => 0; lfs2_stat(&lfs2, "/./tea/./hottea", &info) => 0;
assert(strcmp(info.name, "hottea") == 0); assert(strcmp(info.name, "hottea") == 0);
lfs_mkdir(&lfs, "/./milk") => 0; lfs2_mkdir(&lfs2, "/./milk") => 0;
lfs_stat(&lfs, "/./milk", &info) => 0; lfs2_stat(&lfs2, "/./milk", &info) => 0;
assert(strcmp(info.name, "milk") == 0); assert(strcmp(info.name, "milk") == 0);
lfs_stat(&lfs, "milk", &info) => 0; lfs2_stat(&lfs2, "milk", &info) => 0;
assert(strcmp(info.name, "milk") == 0); assert(strcmp(info.name, "milk") == 0);
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # dot dot path test [[case]] # dot dot path test
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_mkdir(&lfs, "tea") => 0; lfs2_mkdir(&lfs2, "tea") => 0;
lfs_mkdir(&lfs, "tea/hottea") => 0; lfs2_mkdir(&lfs2, "tea/hottea") => 0;
lfs_mkdir(&lfs, "tea/warmtea") => 0; lfs2_mkdir(&lfs2, "tea/warmtea") => 0;
lfs_mkdir(&lfs, "tea/coldtea") => 0; lfs2_mkdir(&lfs2, "tea/coldtea") => 0;
lfs_mkdir(&lfs, "coffee") => 0; lfs2_mkdir(&lfs2, "coffee") => 0;
lfs_mkdir(&lfs, "coffee/hotcoffee") => 0; lfs2_mkdir(&lfs2, "coffee/hotcoffee") => 0;
lfs_mkdir(&lfs, "coffee/warmcoffee") => 0; lfs2_mkdir(&lfs2, "coffee/warmcoffee") => 0;
lfs_mkdir(&lfs, "coffee/coldcoffee") => 0; lfs2_mkdir(&lfs2, "coffee/coldcoffee") => 0;
lfs_stat(&lfs, "coffee/../tea/hottea", &info) => 0; lfs2_stat(&lfs2, "coffee/../tea/hottea", &info) => 0;
assert(strcmp(info.name, "hottea") == 0); assert(strcmp(info.name, "hottea") == 0);
lfs_stat(&lfs, "tea/coldtea/../hottea", &info) => 0; lfs2_stat(&lfs2, "tea/coldtea/../hottea", &info) => 0;
assert(strcmp(info.name, "hottea") == 0); assert(strcmp(info.name, "hottea") == 0);
lfs_stat(&lfs, "coffee/coldcoffee/../../tea/hottea", &info) => 0; lfs2_stat(&lfs2, "coffee/coldcoffee/../../tea/hottea", &info) => 0;
assert(strcmp(info.name, "hottea") == 0); assert(strcmp(info.name, "hottea") == 0);
lfs_stat(&lfs, "coffee/../coffee/../tea/hottea", &info) => 0; lfs2_stat(&lfs2, "coffee/../coffee/../tea/hottea", &info) => 0;
assert(strcmp(info.name, "hottea") == 0); assert(strcmp(info.name, "hottea") == 0);
lfs_mkdir(&lfs, "coffee/../milk") => 0; lfs2_mkdir(&lfs2, "coffee/../milk") => 0;
lfs_stat(&lfs, "coffee/../milk", &info) => 0; lfs2_stat(&lfs2, "coffee/../milk", &info) => 0;
strcmp(info.name, "milk") => 0; strcmp(info.name, "milk") => 0;
lfs_stat(&lfs, "milk", &info) => 0; lfs2_stat(&lfs2, "milk", &info) => 0;
strcmp(info.name, "milk") => 0; strcmp(info.name, "milk") => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # trailing dot path test [[case]] # trailing dot path test
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_mkdir(&lfs, "tea") => 0; lfs2_mkdir(&lfs2, "tea") => 0;
lfs_mkdir(&lfs, "tea/hottea") => 0; lfs2_mkdir(&lfs2, "tea/hottea") => 0;
lfs_mkdir(&lfs, "tea/warmtea") => 0; lfs2_mkdir(&lfs2, "tea/warmtea") => 0;
lfs_mkdir(&lfs, "tea/coldtea") => 0; lfs2_mkdir(&lfs2, "tea/coldtea") => 0;
lfs_stat(&lfs, "tea/hottea/", &info) => 0; lfs2_stat(&lfs2, "tea/hottea/", &info) => 0;
assert(strcmp(info.name, "hottea") == 0); assert(strcmp(info.name, "hottea") == 0);
lfs_stat(&lfs, "tea/hottea/.", &info) => 0; lfs2_stat(&lfs2, "tea/hottea/.", &info) => 0;
assert(strcmp(info.name, "hottea") == 0); assert(strcmp(info.name, "hottea") == 0);
lfs_stat(&lfs, "tea/hottea/./.", &info) => 0; lfs2_stat(&lfs2, "tea/hottea/./.", &info) => 0;
assert(strcmp(info.name, "hottea") == 0); assert(strcmp(info.name, "hottea") == 0);
lfs_stat(&lfs, "tea/hottea/..", &info) => 0; lfs2_stat(&lfs2, "tea/hottea/..", &info) => 0;
assert(strcmp(info.name, "tea") == 0); assert(strcmp(info.name, "tea") == 0);
lfs_stat(&lfs, "tea/hottea/../.", &info) => 0; lfs2_stat(&lfs2, "tea/hottea/../.", &info) => 0;
assert(strcmp(info.name, "tea") == 0); assert(strcmp(info.name, "tea") == 0);
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # leading dot path test [[case]] # leading dot path test
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_mkdir(&lfs, ".milk") => 0; lfs2_mkdir(&lfs2, ".milk") => 0;
lfs_stat(&lfs, ".milk", &info) => 0; lfs2_stat(&lfs2, ".milk", &info) => 0;
strcmp(info.name, ".milk") => 0; strcmp(info.name, ".milk") => 0;
lfs_stat(&lfs, "tea/.././.milk", &info) => 0; lfs2_stat(&lfs2, "tea/.././.milk", &info) => 0;
strcmp(info.name, ".milk") => 0; strcmp(info.name, ".milk") => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # root dot dot path test [[case]] # root dot dot path test
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_mkdir(&lfs, "tea") => 0; lfs2_mkdir(&lfs2, "tea") => 0;
lfs_mkdir(&lfs, "tea/hottea") => 0; lfs2_mkdir(&lfs2, "tea/hottea") => 0;
lfs_mkdir(&lfs, "tea/warmtea") => 0; lfs2_mkdir(&lfs2, "tea/warmtea") => 0;
lfs_mkdir(&lfs, "tea/coldtea") => 0; lfs2_mkdir(&lfs2, "tea/coldtea") => 0;
lfs_mkdir(&lfs, "coffee") => 0; lfs2_mkdir(&lfs2, "coffee") => 0;
lfs_mkdir(&lfs, "coffee/hotcoffee") => 0; lfs2_mkdir(&lfs2, "coffee/hotcoffee") => 0;
lfs_mkdir(&lfs, "coffee/warmcoffee") => 0; lfs2_mkdir(&lfs2, "coffee/warmcoffee") => 0;
lfs_mkdir(&lfs, "coffee/coldcoffee") => 0; lfs2_mkdir(&lfs2, "coffee/coldcoffee") => 0;
lfs_stat(&lfs, "coffee/../../../../../../tea/hottea", &info) => 0; lfs2_stat(&lfs2, "coffee/../../../../../../tea/hottea", &info) => 0;
strcmp(info.name, "hottea") => 0; strcmp(info.name, "hottea") => 0;
lfs_mkdir(&lfs, "coffee/../../../../../../milk") => 0; lfs2_mkdir(&lfs2, "coffee/../../../../../../milk") => 0;
lfs_stat(&lfs, "coffee/../../../../../../milk", &info) => 0; lfs2_stat(&lfs2, "coffee/../../../../../../milk", &info) => 0;
strcmp(info.name, "milk") => 0; strcmp(info.name, "milk") => 0;
lfs_stat(&lfs, "milk", &info) => 0; lfs2_stat(&lfs2, "milk", &info) => 0;
strcmp(info.name, "milk") => 0; strcmp(info.name, "milk") => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # invalid path tests [[case]] # invalid path tests
code = ''' code = '''
lfs_format(&lfs, &cfg); lfs2_format(&lfs2, &cfg);
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_stat(&lfs, "dirt", &info) => LFS_ERR_NOENT; lfs2_stat(&lfs2, "dirt", &info) => LFS2_ERR_NOENT;
lfs_stat(&lfs, "dirt/ground", &info) => LFS_ERR_NOENT; lfs2_stat(&lfs2, "dirt/ground", &info) => LFS2_ERR_NOENT;
lfs_stat(&lfs, "dirt/ground/earth", &info) => LFS_ERR_NOENT; lfs2_stat(&lfs2, "dirt/ground/earth", &info) => LFS2_ERR_NOENT;
lfs_remove(&lfs, "dirt") => LFS_ERR_NOENT; lfs2_remove(&lfs2, "dirt") => LFS2_ERR_NOENT;
lfs_remove(&lfs, "dirt/ground") => LFS_ERR_NOENT; lfs2_remove(&lfs2, "dirt/ground") => LFS2_ERR_NOENT;
lfs_remove(&lfs, "dirt/ground/earth") => LFS_ERR_NOENT; lfs2_remove(&lfs2, "dirt/ground/earth") => LFS2_ERR_NOENT;
lfs_mkdir(&lfs, "dirt/ground") => LFS_ERR_NOENT; lfs2_mkdir(&lfs2, "dirt/ground") => LFS2_ERR_NOENT;
lfs_file_open(&lfs, &file, "dirt/ground", LFS_O_WRONLY | LFS_O_CREAT) lfs2_file_open(&lfs2, &file, "dirt/ground", LFS2_O_WRONLY | LFS2_O_CREAT)
=> LFS_ERR_NOENT; => LFS2_ERR_NOENT;
lfs_mkdir(&lfs, "dirt/ground/earth") => LFS_ERR_NOENT; lfs2_mkdir(&lfs2, "dirt/ground/earth") => LFS2_ERR_NOENT;
lfs_file_open(&lfs, &file, "dirt/ground/earth", LFS_O_WRONLY | LFS_O_CREAT) lfs2_file_open(&lfs2, &file, "dirt/ground/earth", LFS2_O_WRONLY | LFS2_O_CREAT)
=> LFS_ERR_NOENT; => LFS2_ERR_NOENT;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # root operations [[case]] # root operations
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_stat(&lfs, "/", &info) => 0; lfs2_stat(&lfs2, "/", &info) => 0;
assert(strcmp(info.name, "/") == 0); assert(strcmp(info.name, "/") == 0);
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS2_TYPE_DIR);
lfs_mkdir(&lfs, "/") => LFS_ERR_EXIST; lfs2_mkdir(&lfs2, "/") => LFS2_ERR_EXIST;
lfs_file_open(&lfs, &file, "/", LFS_O_WRONLY | LFS_O_CREAT) lfs2_file_open(&lfs2, &file, "/", LFS2_O_WRONLY | LFS2_O_CREAT)
=> LFS_ERR_ISDIR; => LFS2_ERR_ISDIR;
lfs_remove(&lfs, "/") => LFS_ERR_INVAL; lfs2_remove(&lfs2, "/") => LFS2_ERR_INVAL;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # root representations [[case]] # root representations
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_stat(&lfs, "/", &info) => 0; lfs2_stat(&lfs2, "/", &info) => 0;
assert(strcmp(info.name, "/") == 0); assert(strcmp(info.name, "/") == 0);
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS2_TYPE_DIR);
lfs_stat(&lfs, "", &info) => 0; lfs2_stat(&lfs2, "", &info) => 0;
assert(strcmp(info.name, "/") == 0); assert(strcmp(info.name, "/") == 0);
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS2_TYPE_DIR);
lfs_stat(&lfs, ".", &info) => 0; lfs2_stat(&lfs2, ".", &info) => 0;
assert(strcmp(info.name, "/") == 0); assert(strcmp(info.name, "/") == 0);
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS2_TYPE_DIR);
lfs_stat(&lfs, "..", &info) => 0; lfs2_stat(&lfs2, "..", &info) => 0;
assert(strcmp(info.name, "/") == 0); assert(strcmp(info.name, "/") == 0);
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS2_TYPE_DIR);
lfs_stat(&lfs, "//", &info) => 0; lfs2_stat(&lfs2, "//", &info) => 0;
assert(strcmp(info.name, "/") == 0); assert(strcmp(info.name, "/") == 0);
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS2_TYPE_DIR);
lfs_stat(&lfs, "./", &info) => 0; lfs2_stat(&lfs2, "./", &info) => 0;
assert(strcmp(info.name, "/") == 0); assert(strcmp(info.name, "/") == 0);
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS2_TYPE_DIR);
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # superblock conflict test [[case]] # superblock conflict test
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_stat(&lfs, "littlefs", &info) => LFS_ERR_NOENT; lfs2_stat(&lfs2, "littlefs", &info) => LFS2_ERR_NOENT;
lfs_remove(&lfs, "littlefs") => LFS_ERR_NOENT; lfs2_remove(&lfs2, "littlefs") => LFS2_ERR_NOENT;
lfs_mkdir(&lfs, "littlefs") => 0; lfs2_mkdir(&lfs2, "littlefs") => 0;
lfs_stat(&lfs, "littlefs", &info) => 0; lfs2_stat(&lfs2, "littlefs", &info) => 0;
assert(strcmp(info.name, "littlefs") == 0); assert(strcmp(info.name, "littlefs") == 0);
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS2_TYPE_DIR);
lfs_remove(&lfs, "littlefs") => 0; lfs2_remove(&lfs2, "littlefs") => 0;
lfs_stat(&lfs, "littlefs", &info) => LFS_ERR_NOENT; lfs2_stat(&lfs2, "littlefs", &info) => LFS2_ERR_NOENT;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # max path test [[case]] # max path test
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_mkdir(&lfs, "coffee") => 0; lfs2_mkdir(&lfs2, "coffee") => 0;
lfs_mkdir(&lfs, "coffee/hotcoffee") => 0; lfs2_mkdir(&lfs2, "coffee/hotcoffee") => 0;
lfs_mkdir(&lfs, "coffee/warmcoffee") => 0; lfs2_mkdir(&lfs2, "coffee/warmcoffee") => 0;
lfs_mkdir(&lfs, "coffee/coldcoffee") => 0; lfs2_mkdir(&lfs2, "coffee/coldcoffee") => 0;
memset(path, 'w', LFS_NAME_MAX+1); memset(path, 'w', LFS2_NAME_MAX+1);
path[LFS_NAME_MAX+1] = '\0'; path[LFS2_NAME_MAX+1] = '\0';
lfs_mkdir(&lfs, path) => LFS_ERR_NAMETOOLONG; lfs2_mkdir(&lfs2, path) => LFS2_ERR_NAMETOOLONG;
lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT) lfs2_file_open(&lfs2, &file, path, LFS2_O_WRONLY | LFS2_O_CREAT)
=> LFS_ERR_NAMETOOLONG; => LFS2_ERR_NAMETOOLONG;
memcpy(path, "coffee/", strlen("coffee/")); memcpy(path, "coffee/", strlen("coffee/"));
memset(path+strlen("coffee/"), 'w', LFS_NAME_MAX+1); memset(path+strlen("coffee/"), 'w', LFS2_NAME_MAX+1);
path[strlen("coffee/")+LFS_NAME_MAX+1] = '\0'; path[strlen("coffee/")+LFS2_NAME_MAX+1] = '\0';
lfs_mkdir(&lfs, path) => LFS_ERR_NAMETOOLONG; lfs2_mkdir(&lfs2, path) => LFS2_ERR_NAMETOOLONG;
lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT) lfs2_file_open(&lfs2, &file, path, LFS2_O_WRONLY | LFS2_O_CREAT)
=> LFS_ERR_NAMETOOLONG; => LFS2_ERR_NAMETOOLONG;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # really big path test [[case]] # really big path test
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_mkdir(&lfs, "coffee") => 0; lfs2_mkdir(&lfs2, "coffee") => 0;
lfs_mkdir(&lfs, "coffee/hotcoffee") => 0; lfs2_mkdir(&lfs2, "coffee/hotcoffee") => 0;
lfs_mkdir(&lfs, "coffee/warmcoffee") => 0; lfs2_mkdir(&lfs2, "coffee/warmcoffee") => 0;
lfs_mkdir(&lfs, "coffee/coldcoffee") => 0; lfs2_mkdir(&lfs2, "coffee/coldcoffee") => 0;
memset(path, 'w', LFS_NAME_MAX); memset(path, 'w', LFS2_NAME_MAX);
path[LFS_NAME_MAX] = '\0'; path[LFS2_NAME_MAX] = '\0';
lfs_mkdir(&lfs, path) => 0; lfs2_mkdir(&lfs2, path) => 0;
lfs_remove(&lfs, path) => 0; lfs2_remove(&lfs2, path) => 0;
lfs_file_open(&lfs, &file, path, lfs2_file_open(&lfs2, &file, path,
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_remove(&lfs, path) => 0; lfs2_remove(&lfs2, path) => 0;
memcpy(path, "coffee/", strlen("coffee/")); memcpy(path, "coffee/", strlen("coffee/"));
memset(path+strlen("coffee/"), 'w', LFS_NAME_MAX); memset(path+strlen("coffee/"), 'w', LFS2_NAME_MAX);
path[strlen("coffee/")+LFS_NAME_MAX] = '\0'; path[strlen("coffee/")+LFS2_NAME_MAX] = '\0';
lfs_mkdir(&lfs, path) => 0; lfs2_mkdir(&lfs2, path) => 0;
lfs_remove(&lfs, path) => 0; lfs2_remove(&lfs2, path) => 0;
lfs_file_open(&lfs, &file, path, lfs2_file_open(&lfs2, &file, path,
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_remove(&lfs, path) => 0; lfs2_remove(&lfs2, path) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''

View File

@@ -2,39 +2,39 @@
[[case]] # dangling split dir test [[case]] # dangling split dir test
define.ITERATIONS = 20 define.ITERATIONS = 20
define.COUNT = 10 define.COUNT = 10
define.LFS_BLOCK_CYCLES = [8, 1] define.LFS2_BLOCK_CYCLES = [8, 1]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &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; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "padding", LFS_O_CREAT | LFS_O_WRONLY) => 0; lfs2_file_open(&lfs2, &file, "padding", LFS2_O_CREAT | LFS2_O_WRONLY) => 0;
memset(buffer, 0, 512); memset(buffer, 0, 512);
while (LFS_BLOCK_COUNT - lfs_fs_size(&lfs) > 16) { while (LFS2_BLOCK_COUNT - lfs2_fs_size(&lfs2) > 16) {
lfs_file_write(&lfs, &file, buffer, 512) => 512; lfs2_file_write(&lfs2, &file, buffer, 512) => 512;
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// make a child dir to use in bounded space // make a child dir to use in bounded space
lfs_mkdir(&lfs, "child") => 0; lfs2_mkdir(&lfs2, "child") => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &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);
lfs_file_open(&lfs, &file, path, LFS_O_CREAT | LFS_O_WRONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_CREAT | LFS2_O_WRONLY) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
} }
lfs_dir_open(&lfs, &dir, "child") => 0; lfs2_dir_open(&lfs2, &dir, "child") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs2_dir_read(&lfs2, &dir, &info) => 1;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs2_dir_read(&lfs2, &dir, &info) => 1;
for (int i = 0; i < COUNT; i++) { for (int i = 0; i < COUNT; i++) {
sprintf(path, "test%03d_loooooooooooooooooong_name", i); sprintf(path, "test%03d_loooooooooooooooooong_name", i);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs2_dir_read(&lfs2, &dir, &info) => 1;
strcmp(info.name, path) => 0; strcmp(info.name, path) => 0;
} }
lfs_dir_read(&lfs, &dir, &info) => 0; lfs2_dir_read(&lfs2, &dir, &info) => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs2_dir_close(&lfs2, &dir) => 0;
if (j == ITERATIONS-1) { if (j == ITERATIONS-1) {
break; break;
@@ -42,105 +42,105 @@ code = '''
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);
lfs_remove(&lfs, path) => 0; lfs2_remove(&lfs2, path) => 0;
} }
} }
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "child") => 0; lfs2_dir_open(&lfs2, &dir, "child") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs2_dir_read(&lfs2, &dir, &info) => 1;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs2_dir_read(&lfs2, &dir, &info) => 1;
for (int i = 0; i < COUNT; i++) { for (int i = 0; i < COUNT; i++) {
sprintf(path, "test%03d_loooooooooooooooooong_name", i); sprintf(path, "test%03d_loooooooooooooooooong_name", i);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs2_dir_read(&lfs2, &dir, &info) => 1;
strcmp(info.name, path) => 0; strcmp(info.name, path) => 0;
} }
lfs_dir_read(&lfs, &dir, &info) => 0; lfs2_dir_read(&lfs2, &dir, &info) => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs2_dir_close(&lfs2, &dir) => 0;
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);
lfs_remove(&lfs, path) => 0; lfs2_remove(&lfs2, path) => 0;
} }
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # outdated head test [[case]] # outdated head test
define.ITERATIONS = 20 define.ITERATIONS = 20
define.COUNT = 10 define.COUNT = 10
define.LFS_BLOCK_CYCLES = [8, 1] define.LFS2_BLOCK_CYCLES = [8, 1]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &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; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "padding", LFS_O_CREAT | LFS_O_WRONLY) => 0; lfs2_file_open(&lfs2, &file, "padding", LFS2_O_CREAT | LFS2_O_WRONLY) => 0;
memset(buffer, 0, 512); memset(buffer, 0, 512);
while (LFS_BLOCK_COUNT - lfs_fs_size(&lfs) > 16) { while (LFS2_BLOCK_COUNT - lfs2_fs_size(&lfs2) > 16) {
lfs_file_write(&lfs, &file, buffer, 512) => 512; lfs2_file_write(&lfs2, &file, buffer, 512) => 512;
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// make a child dir to use in bounded space // make a child dir to use in bounded space
lfs_mkdir(&lfs, "child") => 0; lfs2_mkdir(&lfs2, "child") => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &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);
lfs_file_open(&lfs, &file, path, LFS_O_CREAT | LFS_O_WRONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_CREAT | LFS2_O_WRONLY) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
} }
lfs_dir_open(&lfs, &dir, "child") => 0; lfs2_dir_open(&lfs2, &dir, "child") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs2_dir_read(&lfs2, &dir, &info) => 1;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs2_dir_read(&lfs2, &dir, &info) => 1;
for (int i = 0; i < COUNT; i++) { for (int i = 0; i < COUNT; i++) {
sprintf(path, "test%03d_loooooooooooooooooong_name", i); sprintf(path, "test%03d_loooooooooooooooooong_name", i);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs2_dir_read(&lfs2, &dir, &info) => 1;
strcmp(info.name, path) => 0; strcmp(info.name, path) => 0;
info.size => 0; info.size => 0;
sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); sprintf(path, "child/test%03d_loooooooooooooooooong_name", i);
lfs_file_open(&lfs, &file, path, LFS_O_WRONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_WRONLY) => 0;
lfs_file_write(&lfs, &file, "hi", 2) => 2; lfs2_file_write(&lfs2, &file, "hi", 2) => 2;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
} }
lfs_dir_read(&lfs, &dir, &info) => 0; lfs2_dir_read(&lfs2, &dir, &info) => 0;
lfs_dir_rewind(&lfs, &dir) => 0; lfs2_dir_rewind(&lfs2, &dir) => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs2_dir_read(&lfs2, &dir, &info) => 1;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs2_dir_read(&lfs2, &dir, &info) => 1;
for (int i = 0; i < COUNT; i++) { for (int i = 0; i < COUNT; i++) {
sprintf(path, "test%03d_loooooooooooooooooong_name", i); sprintf(path, "test%03d_loooooooooooooooooong_name", i);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs2_dir_read(&lfs2, &dir, &info) => 1;
strcmp(info.name, path) => 0; strcmp(info.name, path) => 0;
info.size => 2; info.size => 2;
sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); sprintf(path, "child/test%03d_loooooooooooooooooong_name", i);
lfs_file_open(&lfs, &file, path, LFS_O_WRONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_WRONLY) => 0;
lfs_file_write(&lfs, &file, "hi", 2) => 2; lfs2_file_write(&lfs2, &file, "hi", 2) => 2;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
} }
lfs_dir_read(&lfs, &dir, &info) => 0; lfs2_dir_read(&lfs2, &dir, &info) => 0;
lfs_dir_rewind(&lfs, &dir) => 0; lfs2_dir_rewind(&lfs2, &dir) => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs2_dir_read(&lfs2, &dir, &info) => 1;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs2_dir_read(&lfs2, &dir, &info) => 1;
for (int i = 0; i < COUNT; i++) { for (int i = 0; i < COUNT; i++) {
sprintf(path, "test%03d_loooooooooooooooooong_name", i); sprintf(path, "test%03d_loooooooooooooooooong_name", i);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs2_dir_read(&lfs2, &dir, &info) => 1;
strcmp(info.name, path) => 0; strcmp(info.name, path) => 0;
info.size => 2; info.size => 2;
} }
lfs_dir_read(&lfs, &dir, &info) => 0; lfs2_dir_read(&lfs2, &dir, &info) => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs2_dir_close(&lfs2, &dir) => 0;
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);
lfs_remove(&lfs, path) => 0; lfs2_remove(&lfs2, path) => 0;
} }
} }
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # reentrant testing for relocations, this is the same as the [[case]] # reentrant testing for relocations, this is the same as the
@@ -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 && LFS2_CACHE_SIZE != 64)'
define = [ define = [
{FILES=6, DEPTH=1, CYCLES=20, LFS_BLOCK_CYCLES=1}, {FILES=6, DEPTH=1, CYCLES=20, LFS2_BLOCK_CYCLES=1},
{FILES=26, DEPTH=1, CYCLES=20, LFS_BLOCK_CYCLES=1}, {FILES=26, DEPTH=1, CYCLES=20, LFS2_BLOCK_CYCLES=1},
{FILES=3, DEPTH=3, CYCLES=20, LFS_BLOCK_CYCLES=1}, {FILES=3, DEPTH=3, CYCLES=20, LFS2_BLOCK_CYCLES=1},
] ]
code = ''' code = '''
err = lfs_mount(&lfs, &cfg); err = lfs2_mount(&lfs2, &cfg);
if (err) { if (err) {
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
} }
srand(1); srand(1);
@@ -171,56 +171,56 @@ code = '''
} }
// if it does not exist, we create it, else we destroy // if it does not exist, we create it, else we destroy
int res = lfs_stat(&lfs, full_path, &info); int res = lfs2_stat(&lfs2, full_path, &info);
if (res == LFS_ERR_NOENT) { if (res == LFS2_ERR_NOENT) {
// create each directory in turn, ignore if dir already exists // create each directory in turn, ignore if dir already exists
for (int d = 0; d < DEPTH; d++) { for (int d = 0; d < DEPTH; d++) {
strcpy(path, full_path); strcpy(path, full_path);
path[2*d+2] = '\0'; path[2*d+2] = '\0';
err = lfs_mkdir(&lfs, path); err = lfs2_mkdir(&lfs2, path);
assert(!err || err == LFS_ERR_EXIST); assert(!err || err == LFS2_ERR_EXIST);
} }
for (int d = 0; d < DEPTH; d++) { for (int d = 0; d < DEPTH; d++) {
strcpy(path, full_path); strcpy(path, full_path);
path[2*d+2] = '\0'; path[2*d+2] = '\0';
lfs_stat(&lfs, path, &info) => 0; lfs2_stat(&lfs2, path, &info) => 0;
assert(strcmp(info.name, &path[2*d+1]) == 0); assert(strcmp(info.name, &path[2*d+1]) == 0);
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS2_TYPE_DIR);
} }
} else { } else {
// is valid dir? // is valid dir?
assert(strcmp(info.name, &full_path[2*(DEPTH-1)+1]) == 0); assert(strcmp(info.name, &full_path[2*(DEPTH-1)+1]) == 0);
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS2_TYPE_DIR);
// try to delete path in reverse order, ignore if dir is not empty // try to delete path in reverse order, ignore if dir is not empty
for (int d = DEPTH-1; d >= 0; d--) { for (int d = DEPTH-1; d >= 0; d--) {
strcpy(path, full_path); strcpy(path, full_path);
path[2*d+2] = '\0'; path[2*d+2] = '\0';
err = lfs_remove(&lfs, path); err = lfs2_remove(&lfs2, path);
assert(!err || err == LFS_ERR_NOTEMPTY); assert(!err || err == LFS2_ERR_NOTEMPTY);
} }
lfs_stat(&lfs, full_path, &info) => LFS_ERR_NOENT; lfs2_stat(&lfs2, full_path, &info) => LFS2_ERR_NOENT;
} }
} }
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[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 && LFS2_CACHE_SIZE != 64)'
define = [ define = [
{FILES=6, DEPTH=1, CYCLES=20, LFS_BLOCK_CYCLES=1}, {FILES=6, DEPTH=1, CYCLES=20, LFS2_BLOCK_CYCLES=1},
{FILES=26, DEPTH=1, CYCLES=20, LFS_BLOCK_CYCLES=1}, {FILES=26, DEPTH=1, CYCLES=20, LFS2_BLOCK_CYCLES=1},
{FILES=3, DEPTH=3, CYCLES=20, LFS_BLOCK_CYCLES=1}, {FILES=3, DEPTH=3, CYCLES=20, LFS2_BLOCK_CYCLES=1},
] ]
code = ''' code = '''
err = lfs_mount(&lfs, &cfg); err = lfs2_mount(&lfs2, &cfg);
if (err) { if (err) {
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
} }
srand(1); srand(1);
@@ -233,27 +233,27 @@ code = '''
} }
// if it does not exist, we create it, else we destroy // if it does not exist, we create it, else we destroy
int res = lfs_stat(&lfs, full_path, &info); int res = lfs2_stat(&lfs2, full_path, &info);
assert(!res || res == LFS_ERR_NOENT); assert(!res || res == LFS2_ERR_NOENT);
if (res == LFS_ERR_NOENT) { if (res == LFS2_ERR_NOENT) {
// create each directory in turn, ignore if dir already exists // create each directory in turn, ignore if dir already exists
for (int d = 0; d < DEPTH; d++) { for (int d = 0; d < DEPTH; d++) {
strcpy(path, full_path); strcpy(path, full_path);
path[2*d+2] = '\0'; path[2*d+2] = '\0';
err = lfs_mkdir(&lfs, path); err = lfs2_mkdir(&lfs2, path);
assert(!err || err == LFS_ERR_EXIST); assert(!err || err == LFS2_ERR_EXIST);
} }
for (int d = 0; d < DEPTH; d++) { for (int d = 0; d < DEPTH; d++) {
strcpy(path, full_path); strcpy(path, full_path);
path[2*d+2] = '\0'; path[2*d+2] = '\0';
lfs_stat(&lfs, path, &info) => 0; lfs2_stat(&lfs2, path, &info) => 0;
assert(strcmp(info.name, &path[2*d+1]) == 0); assert(strcmp(info.name, &path[2*d+1]) == 0);
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS2_TYPE_DIR);
} }
} else { } else {
assert(strcmp(info.name, &full_path[2*(DEPTH-1)+1]) == 0); assert(strcmp(info.name, &full_path[2*(DEPTH-1)+1]) == 0);
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS2_TYPE_DIR);
// create new random path // create new random path
char new_path[256]; char new_path[256];
@@ -262,17 +262,17 @@ code = '''
} }
// if new path does not exist, rename, otherwise destroy // if new path does not exist, rename, otherwise destroy
res = lfs_stat(&lfs, new_path, &info); res = lfs2_stat(&lfs2, new_path, &info);
assert(!res || res == LFS_ERR_NOENT); assert(!res || res == LFS2_ERR_NOENT);
if (res == LFS_ERR_NOENT) { if (res == LFS2_ERR_NOENT) {
// stop once some dir is renamed // stop once some dir is renamed
for (int d = 0; d < DEPTH; d++) { for (int d = 0; d < DEPTH; d++) {
strcpy(&path[2*d], &full_path[2*d]); strcpy(&path[2*d], &full_path[2*d]);
path[2*d+2] = '\0'; path[2*d+2] = '\0';
strcpy(&path[128+2*d], &new_path[2*d]); strcpy(&path[128+2*d], &new_path[2*d]);
path[128+2*d+2] = '\0'; path[128+2*d+2] = '\0';
err = lfs_rename(&lfs, path, path+128); err = lfs2_rename(&lfs2, path, path+128);
assert(!err || err == LFS_ERR_NOTEMPTY); assert(!err || err == LFS2_ERR_NOTEMPTY);
if (!err) { if (!err) {
strcpy(path, path+128); strcpy(path, path+128);
} }
@@ -281,25 +281,25 @@ code = '''
for (int d = 0; d < DEPTH; d++) { for (int d = 0; d < DEPTH; d++) {
strcpy(path, new_path); strcpy(path, new_path);
path[2*d+2] = '\0'; path[2*d+2] = '\0';
lfs_stat(&lfs, path, &info) => 0; lfs2_stat(&lfs2, path, &info) => 0;
assert(strcmp(info.name, &path[2*d+1]) == 0); assert(strcmp(info.name, &path[2*d+1]) == 0);
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS2_TYPE_DIR);
} }
lfs_stat(&lfs, full_path, &info) => LFS_ERR_NOENT; lfs2_stat(&lfs2, full_path, &info) => LFS2_ERR_NOENT;
} else { } else {
// try to delete path in reverse order, // try to delete path in reverse order,
// ignore if dir is not empty // ignore if dir is not empty
for (int d = DEPTH-1; d >= 0; d--) { for (int d = DEPTH-1; d >= 0; d--) {
strcpy(path, full_path); strcpy(path, full_path);
path[2*d+2] = '\0'; path[2*d+2] = '\0';
err = lfs_remove(&lfs, path); err = lfs2_remove(&lfs2, path);
assert(!err || err == LFS_ERR_NOTEMPTY); assert(!err || err == LFS2_ERR_NOTEMPTY);
} }
lfs_stat(&lfs, full_path, &info) => LFS_ERR_NOENT; lfs2_stat(&lfs2, full_path, &info) => LFS2_ERR_NOENT;
} }
} }
} }
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''

View File

@@ -9,63 +9,63 @@ define = [
{COUNT=4, SKIP=2}, {COUNT=4, SKIP=2},
] ]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "kitty", lfs2_file_open(&lfs2, &file, "kitty",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_APPEND) => 0;
size = strlen("kittycatcat"); size = strlen("kittycatcat");
memcpy(buffer, "kittycatcat", size); memcpy(buffer, "kittycatcat", size);
for (int j = 0; j < COUNT; j++) { for (int j = 0; j < COUNT; j++) {
lfs_file_write(&lfs, &file, buffer, size); lfs2_file_write(&lfs2, &file, buffer, size);
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "kitty", LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, "kitty", LFS2_O_RDONLY) => 0;
lfs_soff_t pos = -1; lfs2_soff_t pos = -1;
size = strlen("kittycatcat"); size = strlen("kittycatcat");
for (int i = 0; i < SKIP; i++) { for (int i = 0; i < SKIP; i++) {
lfs_file_read(&lfs, &file, buffer, size) => size; lfs2_file_read(&lfs2, &file, buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
pos = lfs_file_tell(&lfs, &file); pos = lfs2_file_tell(&lfs2, &file);
} }
assert(pos >= 0); assert(pos >= 0);
lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos; lfs2_file_seek(&lfs2, &file, pos, LFS2_SEEK_SET) => pos;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs2_file_read(&lfs2, &file, buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
lfs_file_rewind(&lfs, &file) => 0; lfs2_file_rewind(&lfs2, &file) => 0;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs2_file_read(&lfs2, &file, buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
lfs_file_seek(&lfs, &file, 0, LFS_SEEK_CUR) => size; lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_CUR) => size;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs2_file_read(&lfs2, &file, buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
lfs_file_seek(&lfs, &file, size, LFS_SEEK_CUR) => 3*size; lfs2_file_seek(&lfs2, &file, size, LFS2_SEEK_CUR) => 3*size;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs2_file_read(&lfs2, &file, buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos; lfs2_file_seek(&lfs2, &file, pos, LFS2_SEEK_SET) => pos;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs2_file_read(&lfs2, &file, buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
lfs_file_seek(&lfs, &file, -size, LFS_SEEK_CUR) => pos; lfs2_file_seek(&lfs2, &file, -size, LFS2_SEEK_CUR) => pos;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs2_file_read(&lfs2, &file, buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
lfs_file_seek(&lfs, &file, -size, LFS_SEEK_END) >= 0 => 1; lfs2_file_seek(&lfs2, &file, -size, LFS2_SEEK_END) >= 0 => 1;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs2_file_read(&lfs2, &file, buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
size = lfs_file_size(&lfs, &file); size = lfs2_file_size(&lfs2, &file);
lfs_file_seek(&lfs, &file, 0, LFS_SEEK_CUR) => size; lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_CUR) => size;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # simple file seek and write [[case]] # simple file seek and write
@@ -78,109 +78,109 @@ define = [
{COUNT=4, SKIP=2}, {COUNT=4, SKIP=2},
] ]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "kitty", lfs2_file_open(&lfs2, &file, "kitty",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_APPEND) => 0;
size = strlen("kittycatcat"); size = strlen("kittycatcat");
memcpy(buffer, "kittycatcat", size); memcpy(buffer, "kittycatcat", size);
for (int j = 0; j < COUNT; j++) { for (int j = 0; j < COUNT; j++) {
lfs_file_write(&lfs, &file, buffer, size); lfs2_file_write(&lfs2, &file, buffer, size);
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0; lfs2_file_open(&lfs2, &file, "kitty", LFS2_O_RDWR) => 0;
lfs_soff_t pos = -1; lfs2_soff_t pos = -1;
size = strlen("kittycatcat"); size = strlen("kittycatcat");
for (int i = 0; i < SKIP; i++) { for (int i = 0; i < SKIP; i++) {
lfs_file_read(&lfs, &file, buffer, size) => size; lfs2_file_read(&lfs2, &file, buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
pos = lfs_file_tell(&lfs, &file); pos = lfs2_file_tell(&lfs2, &file);
} }
assert(pos >= 0); assert(pos >= 0);
memcpy(buffer, "doggodogdog", size); memcpy(buffer, "doggodogdog", size);
lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos; lfs2_file_seek(&lfs2, &file, pos, LFS2_SEEK_SET) => pos;
lfs_file_write(&lfs, &file, buffer, size) => size; lfs2_file_write(&lfs2, &file, buffer, size) => size;
lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos; lfs2_file_seek(&lfs2, &file, pos, LFS2_SEEK_SET) => pos;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs2_file_read(&lfs2, &file, buffer, size) => size;
memcmp(buffer, "doggodogdog", size) => 0; memcmp(buffer, "doggodogdog", size) => 0;
lfs_file_rewind(&lfs, &file) => 0; lfs2_file_rewind(&lfs2, &file) => 0;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs2_file_read(&lfs2, &file, buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos; lfs2_file_seek(&lfs2, &file, pos, LFS2_SEEK_SET) => pos;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs2_file_read(&lfs2, &file, buffer, size) => size;
memcmp(buffer, "doggodogdog", size) => 0; memcmp(buffer, "doggodogdog", size) => 0;
lfs_file_seek(&lfs, &file, -size, LFS_SEEK_END) >= 0 => 1; lfs2_file_seek(&lfs2, &file, -size, LFS2_SEEK_END) >= 0 => 1;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs2_file_read(&lfs2, &file, buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
size = lfs_file_size(&lfs, &file); size = lfs2_file_size(&lfs2, &file);
lfs_file_seek(&lfs, &file, 0, LFS_SEEK_CUR) => size; lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_CUR) => size;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # boundary seek and writes [[case]] # boundary seek and writes
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; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "kitty", lfs2_file_open(&lfs2, &file, "kitty",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_APPEND) => 0;
size = strlen("kittycatcat"); size = strlen("kittycatcat");
memcpy(buffer, "kittycatcat", size); memcpy(buffer, "kittycatcat", size);
for (int j = 0; j < COUNT; j++) { for (int j = 0; j < COUNT; j++) {
lfs_file_write(&lfs, &file, buffer, size); lfs2_file_write(&lfs2, &file, buffer, size);
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0; lfs2_file_open(&lfs2, &file, "kitty", LFS2_O_RDWR) => 0;
size = strlen("hedgehoghog"); size = strlen("hedgehoghog");
const lfs_soff_t offsets[] = OFFSETS; const lfs2_soff_t offsets[] = OFFSETS;
for (unsigned i = 0; i < sizeof(offsets) / sizeof(offsets[0]); i++) { for (unsigned i = 0; i < sizeof(offsets) / sizeof(offsets[0]); i++) {
lfs_soff_t off = offsets[i]; lfs2_soff_t off = offsets[i];
memcpy(buffer, "hedgehoghog", size); memcpy(buffer, "hedgehoghog", size);
lfs_file_seek(&lfs, &file, off, LFS_SEEK_SET) => off; lfs2_file_seek(&lfs2, &file, off, LFS2_SEEK_SET) => off;
lfs_file_write(&lfs, &file, buffer, size) => size; lfs2_file_write(&lfs2, &file, buffer, size) => size;
lfs_file_seek(&lfs, &file, off, LFS_SEEK_SET) => off; lfs2_file_seek(&lfs2, &file, off, LFS2_SEEK_SET) => off;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs2_file_read(&lfs2, &file, buffer, size) => size;
memcmp(buffer, "hedgehoghog", size) => 0; memcmp(buffer, "hedgehoghog", size) => 0;
lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0; lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_SET) => 0;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs2_file_read(&lfs2, &file, buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
lfs_file_seek(&lfs, &file, off, LFS_SEEK_SET) => off; lfs2_file_seek(&lfs2, &file, off, LFS2_SEEK_SET) => off;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs2_file_read(&lfs2, &file, buffer, size) => size;
memcmp(buffer, "hedgehoghog", size) => 0; memcmp(buffer, "hedgehoghog", size) => 0;
lfs_file_sync(&lfs, &file) => 0; lfs2_file_sync(&lfs2, &file) => 0;
lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0; lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_SET) => 0;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs2_file_read(&lfs2, &file, buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
lfs_file_seek(&lfs, &file, off, LFS_SEEK_SET) => off; lfs2_file_seek(&lfs2, &file, off, LFS2_SEEK_SET) => off;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs2_file_read(&lfs2, &file, buffer, size) => size;
memcmp(buffer, "hedgehoghog", size) => 0; memcmp(buffer, "hedgehoghog", size) => 0;
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # out of bounds seek [[case]] # out of bounds seek
@@ -193,116 +193,116 @@ define = [
{COUNT=4, SKIP=3}, {COUNT=4, SKIP=3},
] ]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "kitty", lfs2_file_open(&lfs2, &file, "kitty",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_APPEND) => 0;
size = strlen("kittycatcat"); size = strlen("kittycatcat");
memcpy(buffer, "kittycatcat", size); memcpy(buffer, "kittycatcat", size);
for (int j = 0; j < COUNT; j++) { for (int j = 0; j < COUNT; j++) {
lfs_file_write(&lfs, &file, buffer, size); lfs2_file_write(&lfs2, &file, buffer, size);
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0; lfs2_file_open(&lfs2, &file, "kitty", LFS2_O_RDWR) => 0;
size = strlen("kittycatcat"); size = strlen("kittycatcat");
lfs_file_size(&lfs, &file) => COUNT*size; lfs2_file_size(&lfs2, &file) => COUNT*size;
lfs_file_seek(&lfs, &file, (COUNT+SKIP)*size, lfs2_file_seek(&lfs2, &file, (COUNT+SKIP)*size,
LFS_SEEK_SET) => (COUNT+SKIP)*size; LFS2_SEEK_SET) => (COUNT+SKIP)*size;
lfs_file_read(&lfs, &file, buffer, size) => 0; lfs2_file_read(&lfs2, &file, buffer, size) => 0;
memcpy(buffer, "porcupineee", size); memcpy(buffer, "porcupineee", size);
lfs_file_write(&lfs, &file, buffer, size) => size; lfs2_file_write(&lfs2, &file, buffer, size) => size;
lfs_file_seek(&lfs, &file, (COUNT+SKIP)*size, lfs2_file_seek(&lfs2, &file, (COUNT+SKIP)*size,
LFS_SEEK_SET) => (COUNT+SKIP)*size; LFS2_SEEK_SET) => (COUNT+SKIP)*size;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs2_file_read(&lfs2, &file, buffer, size) => size;
memcmp(buffer, "porcupineee", size) => 0; memcmp(buffer, "porcupineee", size) => 0;
lfs_file_seek(&lfs, &file, COUNT*size, lfs2_file_seek(&lfs2, &file, COUNT*size,
LFS_SEEK_SET) => COUNT*size; LFS2_SEEK_SET) => COUNT*size;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs2_file_read(&lfs2, &file, buffer, size) => size;
memcmp(buffer, "\0\0\0\0\0\0\0\0\0\0\0", size) => 0; memcmp(buffer, "\0\0\0\0\0\0\0\0\0\0\0", size) => 0;
lfs_file_seek(&lfs, &file, -((COUNT+SKIP)*size), lfs2_file_seek(&lfs2, &file, -((COUNT+SKIP)*size),
LFS_SEEK_CUR) => LFS_ERR_INVAL; LFS2_SEEK_CUR) => LFS2_ERR_INVAL;
lfs_file_tell(&lfs, &file) => (COUNT+1)*size; lfs2_file_tell(&lfs2, &file) => (COUNT+1)*size;
lfs_file_seek(&lfs, &file, -((COUNT+2*SKIP)*size), lfs2_file_seek(&lfs2, &file, -((COUNT+2*SKIP)*size),
LFS_SEEK_END) => LFS_ERR_INVAL; LFS2_SEEK_END) => LFS2_ERR_INVAL;
lfs_file_tell(&lfs, &file) => (COUNT+1)*size; lfs2_file_tell(&lfs2, &file) => (COUNT+1)*size;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[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; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "tinykitty", lfs2_file_open(&lfs2, &file, "tinykitty",
LFS_O_RDWR | LFS_O_CREAT) => 0; LFS2_O_RDWR | LFS2_O_CREAT) => 0;
int j = 0; int j = 0;
int k = 0; int k = 0;
memcpy(buffer, "abcdefghijklmnopqrstuvwxyz", 26); memcpy(buffer, "abcdefghijklmnopqrstuvwxyz", 26);
for (unsigned i = 0; i < SIZE; i++) { for (unsigned i = 0; i < SIZE; i++) {
lfs_file_write(&lfs, &file, &buffer[j++ % 26], 1) => 1; lfs2_file_write(&lfs2, &file, &buffer[j++ % 26], 1) => 1;
lfs_file_tell(&lfs, &file) => i+1; lfs2_file_tell(&lfs2, &file) => i+1;
lfs_file_size(&lfs, &file) => i+1; lfs2_file_size(&lfs2, &file) => i+1;
} }
lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0; lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_SET) => 0;
lfs_file_tell(&lfs, &file) => 0; lfs2_file_tell(&lfs2, &file) => 0;
lfs_file_size(&lfs, &file) => SIZE; lfs2_file_size(&lfs2, &file) => SIZE;
for (unsigned i = 0; i < SIZE; i++) { for (unsigned i = 0; i < SIZE; i++) {
uint8_t c; uint8_t c;
lfs_file_read(&lfs, &file, &c, 1) => 1; lfs2_file_read(&lfs2, &file, &c, 1) => 1;
c => buffer[k++ % 26]; c => buffer[k++ % 26];
} }
lfs_file_sync(&lfs, &file) => 0; lfs2_file_sync(&lfs2, &file) => 0;
lfs_file_tell(&lfs, &file) => SIZE; lfs2_file_tell(&lfs2, &file) => SIZE;
lfs_file_size(&lfs, &file) => SIZE; lfs2_file_size(&lfs2, &file) => SIZE;
lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0; lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_SET) => 0;
for (unsigned i = 0; i < SIZE; i++) { for (unsigned i = 0; i < SIZE; i++) {
lfs_file_write(&lfs, &file, &buffer[j++ % 26], 1) => 1; lfs2_file_write(&lfs2, &file, &buffer[j++ % 26], 1) => 1;
lfs_file_tell(&lfs, &file) => i+1; lfs2_file_tell(&lfs2, &file) => i+1;
lfs_file_size(&lfs, &file) => SIZE; lfs2_file_size(&lfs2, &file) => SIZE;
lfs_file_sync(&lfs, &file) => 0; lfs2_file_sync(&lfs2, &file) => 0;
lfs_file_tell(&lfs, &file) => i+1; lfs2_file_tell(&lfs2, &file) => i+1;
lfs_file_size(&lfs, &file) => SIZE; lfs2_file_size(&lfs2, &file) => SIZE;
if (i < SIZE-2) { if (i < SIZE-2) {
uint8_t c[3]; uint8_t c[3];
lfs_file_seek(&lfs, &file, -1, LFS_SEEK_CUR) => i; lfs2_file_seek(&lfs2, &file, -1, LFS2_SEEK_CUR) => i;
lfs_file_read(&lfs, &file, &c, 3) => 3; lfs2_file_read(&lfs2, &file, &c, 3) => 3;
lfs_file_tell(&lfs, &file) => i+3; lfs2_file_tell(&lfs2, &file) => i+3;
lfs_file_size(&lfs, &file) => SIZE; lfs2_file_size(&lfs2, &file) => SIZE;
lfs_file_seek(&lfs, &file, i+1, LFS_SEEK_SET) => i+1; lfs2_file_seek(&lfs2, &file, i+1, LFS2_SEEK_SET) => i+1;
lfs_file_tell(&lfs, &file) => i+1; lfs2_file_tell(&lfs2, &file) => i+1;
lfs_file_size(&lfs, &file) => SIZE; lfs2_file_size(&lfs2, &file) => SIZE;
} }
} }
lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0; lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_SET) => 0;
lfs_file_tell(&lfs, &file) => 0; lfs2_file_tell(&lfs2, &file) => 0;
lfs_file_size(&lfs, &file) => SIZE; lfs2_file_size(&lfs2, &file) => SIZE;
for (unsigned i = 0; i < SIZE; i++) { for (unsigned i = 0; i < SIZE; i++) {
uint8_t c; uint8_t c;
lfs_file_read(&lfs, &file, &c, 1) => 1; lfs2_file_read(&lfs2, &file, &c, 1) => 1;
c => buffer[k++ % 26]; c => buffer[k++ % 26];
} }
lfs_file_sync(&lfs, &file) => 0; lfs2_file_sync(&lfs2, &file) => 0;
lfs_file_tell(&lfs, &file) => SIZE; lfs2_file_tell(&lfs2, &file) => SIZE;
lfs_file_size(&lfs, &file) => SIZE; lfs2_file_size(&lfs2, &file) => SIZE;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # file seek and write with power-loss [[case]] # file seek and write with power-loss
@@ -310,71 +310,71 @@ code = '''
define.COUNT = [4, 64, 128] define.COUNT = [4, 64, 128]
reentrant = true reentrant = true
code = ''' code = '''
err = lfs_mount(&lfs, &cfg); err = lfs2_mount(&lfs2, &cfg);
if (err) { if (err) {
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
} }
err = lfs_file_open(&lfs, &file, "kitty", LFS_O_RDONLY); err = lfs2_file_open(&lfs2, &file, "kitty", LFS2_O_RDONLY);
assert(!err || err == LFS_ERR_NOENT); assert(!err || err == LFS2_ERR_NOENT);
if (!err) { if (!err) {
if (lfs_file_size(&lfs, &file) != 0) { if (lfs2_file_size(&lfs2, &file) != 0) {
lfs_file_size(&lfs, &file) => 11*COUNT; lfs2_file_size(&lfs2, &file) => 11*COUNT;
for (int j = 0; j < COUNT; j++) { for (int j = 0; j < COUNT; j++) {
memset(buffer, 0, 11+1); memset(buffer, 0, 11+1);
lfs_file_read(&lfs, &file, buffer, 11) => 11; lfs2_file_read(&lfs2, &file, buffer, 11) => 11;
assert(memcmp(buffer, "kittycatcat", 11) == 0 || assert(memcmp(buffer, "kittycatcat", 11) == 0 ||
memcmp(buffer, "doggodogdog", 11) == 0); memcmp(buffer, "doggodogdog", 11) == 0);
} }
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
} }
lfs_file_open(&lfs, &file, "kitty", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs2_file_open(&lfs2, &file, "kitty", LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
if (lfs_file_size(&lfs, &file) == 0) { if (lfs2_file_size(&lfs2, &file) == 0) {
for (int j = 0; j < COUNT; j++) { for (int j = 0; j < COUNT; j++) {
strcpy((char*)buffer, "kittycatcat"); strcpy((char*)buffer, "kittycatcat");
size = strlen((char*)buffer); size = strlen((char*)buffer);
lfs_file_write(&lfs, &file, buffer, size) => size; lfs2_file_write(&lfs2, &file, buffer, size) => size;
} }
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
strcpy((char*)buffer, "doggodogdog"); strcpy((char*)buffer, "doggodogdog");
size = strlen((char*)buffer); size = strlen((char*)buffer);
lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0; lfs2_file_open(&lfs2, &file, "kitty", LFS2_O_RDWR) => 0;
lfs_file_size(&lfs, &file) => COUNT*size; lfs2_file_size(&lfs2, &file) => COUNT*size;
// seek and write using quadratic probing to touch all // seek and write using quadratic probing to touch all
// 11-byte words in the file // 11-byte words in the file
lfs_off_t off = 0; lfs2_off_t off = 0;
for (int j = 0; j < COUNT; j++) { for (int j = 0; j < COUNT; j++) {
off = (5*off + 1) % COUNT; off = (5*off + 1) % COUNT;
lfs_file_seek(&lfs, &file, off*size, LFS_SEEK_SET) => off*size; lfs2_file_seek(&lfs2, &file, off*size, LFS2_SEEK_SET) => off*size;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs2_file_read(&lfs2, &file, buffer, size) => size;
assert(memcmp(buffer, "kittycatcat", size) == 0 || assert(memcmp(buffer, "kittycatcat", size) == 0 ||
memcmp(buffer, "doggodogdog", size) == 0); memcmp(buffer, "doggodogdog", size) == 0);
if (memcmp(buffer, "doggodogdog", size) != 0) { if (memcmp(buffer, "doggodogdog", size) != 0) {
lfs_file_seek(&lfs, &file, off*size, LFS_SEEK_SET) => off*size; lfs2_file_seek(&lfs2, &file, off*size, LFS2_SEEK_SET) => off*size;
strcpy((char*)buffer, "doggodogdog"); strcpy((char*)buffer, "doggodogdog");
lfs_file_write(&lfs, &file, buffer, size) => size; lfs2_file_write(&lfs2, &file, buffer, size) => size;
lfs_file_seek(&lfs, &file, off*size, LFS_SEEK_SET) => off*size; lfs2_file_seek(&lfs2, &file, off*size, LFS2_SEEK_SET) => off*size;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs2_file_read(&lfs2, &file, buffer, size) => size;
assert(memcmp(buffer, "doggodogdog", size) == 0); assert(memcmp(buffer, "doggodogdog", size) == 0);
lfs_file_sync(&lfs, &file) => 0; lfs2_file_sync(&lfs2, &file) => 0;
lfs_file_seek(&lfs, &file, off*size, LFS_SEEK_SET) => off*size; lfs2_file_seek(&lfs2, &file, off*size, LFS2_SEEK_SET) => off*size;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs2_file_read(&lfs2, &file, buffer, size) => size;
assert(memcmp(buffer, "doggodogdog", size) == 0); assert(memcmp(buffer, "doggodogdog", size) == 0);
} }
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0; lfs2_file_open(&lfs2, &file, "kitty", LFS2_O_RDWR) => 0;
lfs_file_size(&lfs, &file) => COUNT*size; lfs2_file_size(&lfs2, &file) => COUNT*size;
for (int j = 0; j < COUNT; j++) { for (int j = 0; j < COUNT; j++) {
lfs_file_read(&lfs, &file, buffer, size) => size; lfs2_file_read(&lfs2, &file, buffer, size) => size;
assert(memcmp(buffer, "doggodogdog", size) == 0); assert(memcmp(buffer, "doggodogdog", size) == 0);
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''

View File

@@ -1,127 +1,127 @@
[[case]] # simple formatting test [[case]] # simple formatting test
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
''' '''
[[case]] # mount/unmount [[case]] # mount/unmount
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # reentrant format [[case]] # reentrant format
reentrant = true reentrant = true
code = ''' code = '''
err = lfs_mount(&lfs, &cfg); err = lfs2_mount(&lfs2, &cfg);
if (err) { if (err) {
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
} }
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # invalid mount [[case]] # invalid mount
code = ''' code = '''
lfs_mount(&lfs, &cfg) => LFS_ERR_CORRUPT; lfs2_mount(&lfs2, &cfg) => LFS2_ERR_CORRUPT;
''' '''
[[case]] # expanding superblock [[case]] # expanding superblock
define.LFS_BLOCK_CYCLES = [32, 33, 1] define.LFS2_BLOCK_CYCLES = [32, 33, 1]
define.N = [10, 100, 1000] define.N = [10, 100, 1000]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
lfs_file_open(&lfs, &file, "dummy", lfs2_file_open(&lfs2, &file, "dummy",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_stat(&lfs, "dummy", &info) => 0; lfs2_stat(&lfs2, "dummy", &info) => 0;
assert(strcmp(info.name, "dummy") == 0); assert(strcmp(info.name, "dummy") == 0);
assert(info.type == LFS_TYPE_REG); assert(info.type == LFS2_TYPE_REG);
lfs_remove(&lfs, "dummy") => 0; lfs2_remove(&lfs2, "dummy") => 0;
} }
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
// one last check after power-cycle // one last check after power-cycle
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "dummy", lfs2_file_open(&lfs2, &file, "dummy",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_stat(&lfs, "dummy", &info) => 0; lfs2_stat(&lfs2, "dummy", &info) => 0;
assert(strcmp(info.name, "dummy") == 0); assert(strcmp(info.name, "dummy") == 0);
assert(info.type == LFS_TYPE_REG); assert(info.type == LFS2_TYPE_REG);
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # expanding superblock with power cycle [[case]] # expanding superblock with power cycle
define.LFS_BLOCK_CYCLES = [32, 33, 1] define.LFS2_BLOCK_CYCLES = [32, 33, 1]
define.N = [10, 100, 1000] define.N = [10, 100, 1000]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
// remove lingering dummy? // remove lingering dummy?
err = lfs_stat(&lfs, "dummy", &info); err = lfs2_stat(&lfs2, "dummy", &info);
assert(err == 0 || (err == LFS_ERR_NOENT && i == 0)); assert(err == 0 || (err == LFS2_ERR_NOENT && i == 0));
if (!err) { if (!err) {
assert(strcmp(info.name, "dummy") == 0); assert(strcmp(info.name, "dummy") == 0);
assert(info.type == LFS_TYPE_REG); assert(info.type == LFS2_TYPE_REG);
lfs_remove(&lfs, "dummy") => 0; lfs2_remove(&lfs2, "dummy") => 0;
} }
lfs_file_open(&lfs, &file, "dummy", lfs2_file_open(&lfs2, &file, "dummy",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_stat(&lfs, "dummy", &info) => 0; lfs2_stat(&lfs2, "dummy", &info) => 0;
assert(strcmp(info.name, "dummy") == 0); assert(strcmp(info.name, "dummy") == 0);
assert(info.type == LFS_TYPE_REG); assert(info.type == LFS2_TYPE_REG);
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
} }
// one last check after power-cycle // one last check after power-cycle
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_stat(&lfs, "dummy", &info) => 0; lfs2_stat(&lfs2, "dummy", &info) => 0;
assert(strcmp(info.name, "dummy") == 0); assert(strcmp(info.name, "dummy") == 0);
assert(info.type == LFS_TYPE_REG); assert(info.type == LFS2_TYPE_REG);
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # reentrant expanding superblock [[case]] # reentrant expanding superblock
define.LFS_BLOCK_CYCLES = [2, 1] define.LFS2_BLOCK_CYCLES = [2, 1]
define.N = 24 define.N = 24
reentrant = true reentrant = true
code = ''' code = '''
err = lfs_mount(&lfs, &cfg); err = lfs2_mount(&lfs2, &cfg);
if (err) { if (err) {
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
} }
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
// remove lingering dummy? // remove lingering dummy?
err = lfs_stat(&lfs, "dummy", &info); err = lfs2_stat(&lfs2, "dummy", &info);
assert(err == 0 || (err == LFS_ERR_NOENT && i == 0)); assert(err == 0 || (err == LFS2_ERR_NOENT && i == 0));
if (!err) { if (!err) {
assert(strcmp(info.name, "dummy") == 0); assert(strcmp(info.name, "dummy") == 0);
assert(info.type == LFS_TYPE_REG); assert(info.type == LFS2_TYPE_REG);
lfs_remove(&lfs, "dummy") => 0; lfs2_remove(&lfs2, "dummy") => 0;
} }
lfs_file_open(&lfs, &file, "dummy", lfs2_file_open(&lfs2, &file, "dummy",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_stat(&lfs, "dummy", &info) => 0; lfs2_stat(&lfs2, "dummy", &info) => 0;
assert(strcmp(info.name, "dummy") == 0); assert(strcmp(info.name, "dummy") == 0);
assert(info.type == LFS_TYPE_REG); assert(info.type == LFS2_TYPE_REG);
} }
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
// one last check after power-cycle // one last check after power-cycle
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_stat(&lfs, "dummy", &info) => 0; lfs2_stat(&lfs2, "dummy", &info) => 0;
assert(strcmp(info.name, "dummy") == 0); assert(strcmp(info.name, "dummy") == 0);
assert(info.type == LFS_TYPE_REG); assert(info.type == LFS2_TYPE_REG);
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''

View File

@@ -2,198 +2,198 @@
define.MEDIUMSIZE = [32, 2048] define.MEDIUMSIZE = [32, 2048]
define.LARGESIZE = 8192 define.LARGESIZE = 8192
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "baldynoop", lfs2_file_open(&lfs2, &file, "baldynoop",
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
strcpy((char*)buffer, "hair"); strcpy((char*)buffer, "hair");
size = strlen((char*)buffer); size = strlen((char*)buffer);
for (lfs_off_t j = 0; j < LARGESIZE; j += size) { for (lfs2_off_t j = 0; j < LARGESIZE; j += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs2_file_write(&lfs2, &file, buffer, size) => size;
} }
lfs_file_size(&lfs, &file) => LARGESIZE; lfs2_file_size(&lfs2, &file) => LARGESIZE;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "baldynoop", LFS_O_RDWR) => 0; lfs2_file_open(&lfs2, &file, "baldynoop", LFS2_O_RDWR) => 0;
lfs_file_size(&lfs, &file) => LARGESIZE; lfs2_file_size(&lfs2, &file) => LARGESIZE;
lfs_file_truncate(&lfs, &file, MEDIUMSIZE) => 0; lfs2_file_truncate(&lfs2, &file, MEDIUMSIZE) => 0;
lfs_file_size(&lfs, &file) => MEDIUMSIZE; lfs2_file_size(&lfs2, &file) => MEDIUMSIZE;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "baldynoop", LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, "baldynoop", LFS2_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => MEDIUMSIZE; lfs2_file_size(&lfs2, &file) => MEDIUMSIZE;
size = strlen("hair"); size = strlen("hair");
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { for (lfs2_off_t j = 0; j < MEDIUMSIZE; j += size) {
lfs_file_read(&lfs, &file, buffer, size) => size; lfs2_file_read(&lfs2, &file, buffer, size) => size;
memcmp(buffer, "hair", size) => 0; memcmp(buffer, "hair", size) => 0;
} }
lfs_file_read(&lfs, &file, buffer, size) => 0; lfs2_file_read(&lfs2, &file, buffer, size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # truncate and read [[case]] # truncate and read
define.MEDIUMSIZE = [32, 2048] define.MEDIUMSIZE = [32, 2048]
define.LARGESIZE = 8192 define.LARGESIZE = 8192
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "baldyread", lfs2_file_open(&lfs2, &file, "baldyread",
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
strcpy((char*)buffer, "hair"); strcpy((char*)buffer, "hair");
size = strlen((char*)buffer); size = strlen((char*)buffer);
for (lfs_off_t j = 0; j < LARGESIZE; j += size) { for (lfs2_off_t j = 0; j < LARGESIZE; j += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs2_file_write(&lfs2, &file, buffer, size) => size;
} }
lfs_file_size(&lfs, &file) => LARGESIZE; lfs2_file_size(&lfs2, &file) => LARGESIZE;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "baldyread", LFS_O_RDWR) => 0; lfs2_file_open(&lfs2, &file, "baldyread", LFS2_O_RDWR) => 0;
lfs_file_size(&lfs, &file) => LARGESIZE; lfs2_file_size(&lfs2, &file) => LARGESIZE;
lfs_file_truncate(&lfs, &file, MEDIUMSIZE) => 0; lfs2_file_truncate(&lfs2, &file, MEDIUMSIZE) => 0;
lfs_file_size(&lfs, &file) => MEDIUMSIZE; lfs2_file_size(&lfs2, &file) => MEDIUMSIZE;
size = strlen("hair"); size = strlen("hair");
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { for (lfs2_off_t j = 0; j < MEDIUMSIZE; j += size) {
lfs_file_read(&lfs, &file, buffer, size) => size; lfs2_file_read(&lfs2, &file, buffer, size) => size;
memcmp(buffer, "hair", size) => 0; memcmp(buffer, "hair", size) => 0;
} }
lfs_file_read(&lfs, &file, buffer, size) => 0; lfs2_file_read(&lfs2, &file, buffer, size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "baldyread", LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, "baldyread", LFS2_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => MEDIUMSIZE; lfs2_file_size(&lfs2, &file) => MEDIUMSIZE;
size = strlen("hair"); size = strlen("hair");
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { for (lfs2_off_t j = 0; j < MEDIUMSIZE; j += size) {
lfs_file_read(&lfs, &file, buffer, size) => size; lfs2_file_read(&lfs2, &file, buffer, size) => size;
memcmp(buffer, "hair", size) => 0; memcmp(buffer, "hair", size) => 0;
} }
lfs_file_read(&lfs, &file, buffer, size) => 0; lfs2_file_read(&lfs2, &file, buffer, size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # write, truncate, and read [[case]] # write, truncate, and read
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "sequence", lfs2_file_open(&lfs2, &file, "sequence",
LFS_O_RDWR | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS2_O_RDWR | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
size = lfs_min(lfs.cfg->cache_size, sizeof(buffer)/2); size = lfs2_min(lfs2.cfg->cache_size, sizeof(buffer)/2);
lfs_size_t qsize = size / 4; lfs2_size_t qsize = size / 4;
uint8_t *wb = buffer; uint8_t *wb = buffer;
uint8_t *rb = buffer + size; uint8_t *rb = buffer + size;
for (lfs_off_t j = 0; j < size; ++j) { for (lfs2_off_t j = 0; j < size; ++j) {
wb[j] = j; wb[j] = j;
} }
/* Spread sequence over size */ /* Spread sequence over size */
lfs_file_write(&lfs, &file, wb, size) => size; lfs2_file_write(&lfs2, &file, wb, size) => size;
lfs_file_size(&lfs, &file) => size; lfs2_file_size(&lfs2, &file) => size;
lfs_file_tell(&lfs, &file) => size; lfs2_file_tell(&lfs2, &file) => size;
lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0; lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_SET) => 0;
lfs_file_tell(&lfs, &file) => 0; lfs2_file_tell(&lfs2, &file) => 0;
/* Chop off the last quarter */ /* Chop off the last quarter */
lfs_size_t trunc = size - qsize; lfs2_size_t trunc = size - qsize;
lfs_file_truncate(&lfs, &file, trunc) => 0; lfs2_file_truncate(&lfs2, &file, trunc) => 0;
lfs_file_tell(&lfs, &file) => 0; lfs2_file_tell(&lfs2, &file) => 0;
lfs_file_size(&lfs, &file) => trunc; lfs2_file_size(&lfs2, &file) => trunc;
/* Read should produce first 3/4 */ /* Read should produce first 3/4 */
lfs_file_read(&lfs, &file, rb, size) => trunc; lfs2_file_read(&lfs2, &file, rb, size) => trunc;
memcmp(rb, wb, trunc) => 0; memcmp(rb, wb, trunc) => 0;
/* Move to 1/4 */ /* Move to 1/4 */
lfs_file_size(&lfs, &file) => trunc; lfs2_file_size(&lfs2, &file) => trunc;
lfs_file_seek(&lfs, &file, qsize, LFS_SEEK_SET) => qsize; lfs2_file_seek(&lfs2, &file, qsize, LFS2_SEEK_SET) => qsize;
lfs_file_tell(&lfs, &file) => qsize; lfs2_file_tell(&lfs2, &file) => qsize;
/* Chop to 1/2 */ /* Chop to 1/2 */
trunc -= qsize; trunc -= qsize;
lfs_file_truncate(&lfs, &file, trunc) => 0; lfs2_file_truncate(&lfs2, &file, trunc) => 0;
lfs_file_tell(&lfs, &file) => qsize; lfs2_file_tell(&lfs2, &file) => qsize;
lfs_file_size(&lfs, &file) => trunc; lfs2_file_size(&lfs2, &file) => trunc;
/* Read should produce second quarter */ /* Read should produce second quarter */
lfs_file_read(&lfs, &file, rb, size) => trunc - qsize; lfs2_file_read(&lfs2, &file, rb, size) => trunc - qsize;
memcmp(rb, wb + qsize, trunc - qsize) => 0; memcmp(rb, wb + qsize, trunc - qsize) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # truncate and write [[case]] # truncate and write
define.MEDIUMSIZE = [32, 2048] define.MEDIUMSIZE = [32, 2048]
define.LARGESIZE = 8192 define.LARGESIZE = 8192
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "baldywrite", lfs2_file_open(&lfs2, &file, "baldywrite",
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
strcpy((char*)buffer, "hair"); strcpy((char*)buffer, "hair");
size = strlen((char*)buffer); size = strlen((char*)buffer);
for (lfs_off_t j = 0; j < LARGESIZE; j += size) { for (lfs2_off_t j = 0; j < LARGESIZE; j += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs2_file_write(&lfs2, &file, buffer, size) => size;
} }
lfs_file_size(&lfs, &file) => LARGESIZE; lfs2_file_size(&lfs2, &file) => LARGESIZE;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "baldywrite", LFS_O_RDWR) => 0; lfs2_file_open(&lfs2, &file, "baldywrite", LFS2_O_RDWR) => 0;
lfs_file_size(&lfs, &file) => LARGESIZE; lfs2_file_size(&lfs2, &file) => LARGESIZE;
lfs_file_truncate(&lfs, &file, MEDIUMSIZE) => 0; lfs2_file_truncate(&lfs2, &file, MEDIUMSIZE) => 0;
lfs_file_size(&lfs, &file) => MEDIUMSIZE; lfs2_file_size(&lfs2, &file) => MEDIUMSIZE;
strcpy((char*)buffer, "bald"); strcpy((char*)buffer, "bald");
size = strlen((char*)buffer); size = strlen((char*)buffer);
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { for (lfs2_off_t j = 0; j < MEDIUMSIZE; j += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs2_file_write(&lfs2, &file, buffer, size) => size;
} }
lfs_file_size(&lfs, &file) => MEDIUMSIZE; lfs2_file_size(&lfs2, &file) => MEDIUMSIZE;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "baldywrite", LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, "baldywrite", LFS2_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => MEDIUMSIZE; lfs2_file_size(&lfs2, &file) => MEDIUMSIZE;
size = strlen("bald"); size = strlen("bald");
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { for (lfs2_off_t j = 0; j < MEDIUMSIZE; j += size) {
lfs_file_read(&lfs, &file, buffer, size) => size; lfs2_file_read(&lfs2, &file, buffer, size) => size;
memcmp(buffer, "bald", size) => 0; memcmp(buffer, "bald", size) => 0;
} }
lfs_file_read(&lfs, &file, buffer, size) => 0; lfs2_file_read(&lfs2, &file, buffer, size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # truncate write under powerloss [[case]] # truncate write under powerloss
@@ -202,64 +202,64 @@ define.MEDIUMSIZE = [32, 1024]
define.LARGESIZE = 2048 define.LARGESIZE = 2048
reentrant = true reentrant = true
code = ''' code = '''
err = lfs_mount(&lfs, &cfg); err = lfs2_mount(&lfs2, &cfg);
if (err) { if (err) {
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
} }
err = lfs_file_open(&lfs, &file, "baldy", LFS_O_RDONLY); err = lfs2_file_open(&lfs2, &file, "baldy", LFS2_O_RDONLY);
assert(!err || err == LFS_ERR_NOENT); assert(!err || err == LFS2_ERR_NOENT);
if (!err) { if (!err) {
size = lfs_file_size(&lfs, &file); size = lfs2_file_size(&lfs2, &file);
assert(size == 0 || assert(size == 0 ||
size == LARGESIZE || size == LARGESIZE ||
size == MEDIUMSIZE || size == MEDIUMSIZE ||
size == SMALLSIZE); size == SMALLSIZE);
for (lfs_off_t j = 0; j < size; j += 4) { for (lfs2_off_t j = 0; j < size; j += 4) {
lfs_file_read(&lfs, &file, buffer, 4) => 4; lfs2_file_read(&lfs2, &file, buffer, 4) => 4;
assert(memcmp(buffer, "hair", 4) == 0 || assert(memcmp(buffer, "hair", 4) == 0 ||
memcmp(buffer, "bald", 4) == 0 || memcmp(buffer, "bald", 4) == 0 ||
memcmp(buffer, "comb", 4) == 0); memcmp(buffer, "comb", 4) == 0);
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
} }
lfs_file_open(&lfs, &file, "baldy", lfs2_file_open(&lfs2, &file, "baldy",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs_file_size(&lfs, &file) => 0; lfs2_file_size(&lfs2, &file) => 0;
strcpy((char*)buffer, "hair"); strcpy((char*)buffer, "hair");
size = strlen((char*)buffer); size = strlen((char*)buffer);
for (lfs_off_t j = 0; j < LARGESIZE; j += size) { for (lfs2_off_t j = 0; j < LARGESIZE; j += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs2_file_write(&lfs2, &file, buffer, size) => size;
} }
lfs_file_size(&lfs, &file) => LARGESIZE; lfs2_file_size(&lfs2, &file) => LARGESIZE;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_file_open(&lfs, &file, "baldy", LFS_O_RDWR) => 0; lfs2_file_open(&lfs2, &file, "baldy", LFS2_O_RDWR) => 0;
lfs_file_size(&lfs, &file) => LARGESIZE; lfs2_file_size(&lfs2, &file) => LARGESIZE;
lfs_file_truncate(&lfs, &file, MEDIUMSIZE) => 0; lfs2_file_truncate(&lfs2, &file, MEDIUMSIZE) => 0;
lfs_file_size(&lfs, &file) => MEDIUMSIZE; lfs2_file_size(&lfs2, &file) => MEDIUMSIZE;
strcpy((char*)buffer, "bald"); strcpy((char*)buffer, "bald");
size = strlen((char*)buffer); size = strlen((char*)buffer);
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { for (lfs2_off_t j = 0; j < MEDIUMSIZE; j += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs2_file_write(&lfs2, &file, buffer, size) => size;
} }
lfs_file_size(&lfs, &file) => MEDIUMSIZE; lfs2_file_size(&lfs2, &file) => MEDIUMSIZE;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_file_open(&lfs, &file, "baldy", LFS_O_RDWR) => 0; lfs2_file_open(&lfs2, &file, "baldy", LFS2_O_RDWR) => 0;
lfs_file_size(&lfs, &file) => MEDIUMSIZE; lfs2_file_size(&lfs2, &file) => MEDIUMSIZE;
lfs_file_truncate(&lfs, &file, SMALLSIZE) => 0; lfs2_file_truncate(&lfs2, &file, SMALLSIZE) => 0;
lfs_file_size(&lfs, &file) => SMALLSIZE; lfs2_file_size(&lfs2, &file) => SMALLSIZE;
strcpy((char*)buffer, "comb"); strcpy((char*)buffer, "comb");
size = strlen((char*)buffer); size = strlen((char*)buffer);
for (lfs_off_t j = 0; j < SMALLSIZE; j += size) { for (lfs2_off_t j = 0; j < SMALLSIZE; j += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs2_file_write(&lfs2, &file, buffer, size) => size;
} }
lfs_file_size(&lfs, &file) => SMALLSIZE; lfs2_file_size(&lfs2, &file) => SMALLSIZE;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # more aggressive general truncation tests [[case]] # more aggressive general truncation tests
@@ -270,10 +270,10 @@ define.LARGESIZE = 8192
code = ''' code = '''
#define COUNT 5 #define COUNT 5
const struct { const struct {
lfs_off_t startsizes[COUNT]; lfs2_off_t startsizes[COUNT];
lfs_off_t startseeks[COUNT]; lfs2_off_t startseeks[COUNT];
lfs_off_t hotsizes[COUNT]; lfs2_off_t hotsizes[COUNT];
lfs_off_t coldsizes[COUNT]; lfs2_off_t coldsizes[COUNT];
} configs[] = { } configs[] = {
// cold shrinking // cold shrinking
{{2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}, {{2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE},
@@ -307,133 +307,133 @@ code = '''
{2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}}, {2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}},
}; };
const lfs_off_t *startsizes = configs[CONFIG].startsizes; const lfs2_off_t *startsizes = configs[CONFIG].startsizes;
const lfs_off_t *startseeks = configs[CONFIG].startseeks; const lfs2_off_t *startseeks = configs[CONFIG].startseeks;
const lfs_off_t *hotsizes = configs[CONFIG].hotsizes; const lfs2_off_t *hotsizes = configs[CONFIG].hotsizes;
const lfs_off_t *coldsizes = configs[CONFIG].coldsizes; const lfs2_off_t *coldsizes = configs[CONFIG].coldsizes;
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &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);
lfs_file_open(&lfs, &file, path, lfs2_file_open(&lfs2, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
strcpy((char*)buffer, "hair"); strcpy((char*)buffer, "hair");
size = strlen((char*)buffer); size = strlen((char*)buffer);
for (lfs_off_t j = 0; j < startsizes[i]; j += size) { for (lfs2_off_t j = 0; j < startsizes[i]; j += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs2_file_write(&lfs2, &file, buffer, size) => size;
} }
lfs_file_size(&lfs, &file) => startsizes[i]; lfs2_file_size(&lfs2, &file) => startsizes[i];
if (startseeks[i] != startsizes[i]) { if (startseeks[i] != startsizes[i]) {
lfs_file_seek(&lfs, &file, lfs2_file_seek(&lfs2, &file,
startseeks[i], LFS_SEEK_SET) => startseeks[i]; startseeks[i], LFS2_SEEK_SET) => startseeks[i];
} }
lfs_file_truncate(&lfs, &file, hotsizes[i]) => 0; lfs2_file_truncate(&lfs2, &file, hotsizes[i]) => 0;
lfs_file_size(&lfs, &file) => hotsizes[i]; lfs2_file_size(&lfs2, &file) => hotsizes[i];
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
} }
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &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);
lfs_file_open(&lfs, &file, path, LFS_O_RDWR) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDWR) => 0;
lfs_file_size(&lfs, &file) => hotsizes[i]; lfs2_file_size(&lfs2, &file) => hotsizes[i];
size = strlen("hair"); size = strlen("hair");
lfs_off_t j = 0; lfs2_off_t j = 0;
for (; j < startsizes[i] && j < hotsizes[i]; j += size) { for (; j < startsizes[i] && j < hotsizes[i]; j += size) {
lfs_file_read(&lfs, &file, buffer, size) => size; lfs2_file_read(&lfs2, &file, buffer, size) => size;
memcmp(buffer, "hair", size) => 0; memcmp(buffer, "hair", size) => 0;
} }
for (; j < hotsizes[i]; j += size) { for (; j < hotsizes[i]; j += size) {
lfs_file_read(&lfs, &file, buffer, size) => size; lfs2_file_read(&lfs2, &file, buffer, size) => size;
memcmp(buffer, "\0\0\0\0", size) => 0; memcmp(buffer, "\0\0\0\0", size) => 0;
} }
lfs_file_truncate(&lfs, &file, coldsizes[i]) => 0; lfs2_file_truncate(&lfs2, &file, coldsizes[i]) => 0;
lfs_file_size(&lfs, &file) => coldsizes[i]; lfs2_file_size(&lfs2, &file) => coldsizes[i];
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
} }
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &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);
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => coldsizes[i]; lfs2_file_size(&lfs2, &file) => coldsizes[i];
size = strlen("hair"); size = strlen("hair");
lfs_off_t j = 0; lfs2_off_t j = 0;
for (; j < startsizes[i] && j < hotsizes[i] && j < coldsizes[i]; for (; j < startsizes[i] && j < hotsizes[i] && j < coldsizes[i];
j += size) { j += size) {
lfs_file_read(&lfs, &file, buffer, size) => size; lfs2_file_read(&lfs2, &file, buffer, size) => size;
memcmp(buffer, "hair", size) => 0; memcmp(buffer, "hair", size) => 0;
} }
for (; j < coldsizes[i]; j += size) { for (; j < coldsizes[i]; j += size) {
lfs_file_read(&lfs, &file, buffer, size) => size; lfs2_file_read(&lfs2, &file, buffer, size) => size;
memcmp(buffer, "\0\0\0\0", size) => 0; memcmp(buffer, "\0\0\0\0", size) => 0;
} }
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
} }
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
[[case]] # noop truncate [[case]] # noop truncate
define.MEDIUMSIZE = [32, 2048] define.MEDIUMSIZE = [32, 2048]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs2_format(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "baldynoop", lfs2_file_open(&lfs2, &file, "baldynoop",
LFS_O_RDWR | LFS_O_CREAT) => 0; LFS2_O_RDWR | LFS2_O_CREAT) => 0;
strcpy((char*)buffer, "hair"); strcpy((char*)buffer, "hair");
size = strlen((char*)buffer); size = strlen((char*)buffer);
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { for (lfs2_off_t j = 0; j < MEDIUMSIZE; j += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs2_file_write(&lfs2, &file, buffer, size) => size;
// this truncate should do nothing // this truncate should do nothing
lfs_file_truncate(&lfs, &file, j+size) => 0; lfs2_file_truncate(&lfs2, &file, j+size) => 0;
} }
lfs_file_size(&lfs, &file) => MEDIUMSIZE; lfs2_file_size(&lfs2, &file) => MEDIUMSIZE;
lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0; lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_SET) => 0;
// should do nothing again // should do nothing again
lfs_file_truncate(&lfs, &file, MEDIUMSIZE) => 0; lfs2_file_truncate(&lfs2, &file, MEDIUMSIZE) => 0;
lfs_file_size(&lfs, &file) => MEDIUMSIZE; lfs2_file_size(&lfs2, &file) => MEDIUMSIZE;
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { for (lfs2_off_t j = 0; j < MEDIUMSIZE; j += size) {
lfs_file_read(&lfs, &file, buffer, size) => size; lfs2_file_read(&lfs2, &file, buffer, size) => size;
memcmp(buffer, "hair", size) => 0; memcmp(buffer, "hair", size) => 0;
} }
lfs_file_read(&lfs, &file, buffer, size) => 0; lfs2_file_read(&lfs2, &file, buffer, size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
// still there after reboot? // still there after reboot?
lfs_mount(&lfs, &cfg) => 0; lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_open(&lfs, &file, "baldynoop", LFS_O_RDWR) => 0; lfs2_file_open(&lfs2, &file, "baldynoop", LFS2_O_RDWR) => 0;
lfs_file_size(&lfs, &file) => MEDIUMSIZE; lfs2_file_size(&lfs2, &file) => MEDIUMSIZE;
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { for (lfs2_off_t j = 0; j < MEDIUMSIZE; j += size) {
lfs_file_read(&lfs, &file, buffer, size) => size; lfs2_file_read(&lfs2, &file, buffer, size) => size;
memcmp(buffer, "hair", size) => 0; memcmp(buffer, "hair", size) => 0;
} }
lfs_file_read(&lfs, &file, buffer, size) => 0; lfs2_file_read(&lfs2, &file, buffer, size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
lfs_unmount(&lfs) => 0; lfs2_unmount(&lfs2) => 0;
''' '''