Compare commits

..

103 Commits

Author SHA1 Message Date
Christopher Haster
74477526f6 WIP Fixed minor memory leak 2018-08-10 10:36:16 -05:00
Christopher Haster
24eaf86b0e WIP Added allocation randomization for dynamic wear-leveling 2018-08-09 12:16:46 -05:00
Christopher Haster
67bbee56f5 WIP added framework for full dynamic wear-leveling 2018-08-08 22:20:37 -05:00
Christopher Haster
efc491facb WIP Fixed issue with big-endian ctz lists intertwined in commit logic 2018-08-08 09:37:43 -05:00
Christopher Haster
fd9e609eb7 WIP Changed name of lfs_crc to match more common API 2018-08-07 14:59:44 -05:00
Christopher Haster
88f15a8d41 WIP fixed issues with expanding directories in tests
(Some where legitimate test failures)
2018-08-07 14:44:26 -05:00
Christopher Haster
2da9392fbf WIP modified ctz type tag for future compatibility with erased files 2018-08-07 09:57:54 -05:00
Christopher Haster
5422566b6a WIP Added expading superblocks and root entries 2018-08-06 20:07:09 -05:00
Christopher Haster
e0e289207a WIP Changed superblock id to acocunt for future compatibility
With expanding superblocks
2018-08-06 13:30:51 -05:00
Christopher Haster
f96e8c130d WIP Made naming consistent for internal functions 2018-08-04 23:57:43 -05:00
Christopher Haster
78b460a907 Merge remote-tracking branch 'origin/master' into v2-alpha 2018-08-04 22:01:44 -05:00
Christopher Haster
a64ff4fb95 WIP Changed littlefs-fuse target for testing 2018-08-04 20:24:02 -05:00
Christopher Haster
4f0d248e09 WIP Changed name of upper-limits from blah_size to blah_max 2018-08-04 20:24:01 -05:00
Christopher Haster
7ffbe81bb2 WIP Changed LFS_ERR_CORRUPT to match EILSEQ instead of EBADE 2018-08-04 20:24:01 -05:00
Christopher Haster
2f73652937 WIP Documented custom attribute API and changed behaviour around
nonexisting attributes
2018-08-04 20:23:51 -05:00
Christopher Haster
c3480c8c92 WIP Added test for global state stealing 2018-08-04 18:55:04 -05:00
Christopher Haster
2bcec45c1b WIP cleaned up config options 2018-08-04 16:04:24 -05:00
Christopher Haster
a98affc951 WIP Added support for cache_size as alternative to read_size and
prog_size
2018-08-04 14:48:27 -05:00
Christopher Haster
e7c4465bf5 WIP simplified and aligned globals
by storing deorphaned in the globals tag itself
2018-08-03 21:07:04 -05:00
Christopher Haster
597249eea0 WIP Added files to dir list and squished the lists together
Now with better tracking of changes to long lasting metadata pairs
2018-08-03 21:06:59 -05:00
Christopher Haster
67cf4e10f4 WIP fixed several TODOs 2018-08-01 06:43:46 -05:00
Christopher Haster
14469059bc WIP Removed redundant lfs_scan 2018-08-01 01:05:04 -05:00
Christopher Haster
3bb37d4aaf WIP Reimplemented big-endian support on top of new structures 2018-08-01 18:50:54 -05:00
Christopher Haster
a703859615 WIP added deorphan bit to globals 2018-07-31 19:41:12 -05:00
Christopher Haster
10f063571a WIP Fixed ENOSPC issues with zero-granularity blocks 2018-07-30 21:12:00 -05:00
Christopher Haster
7f41aa05a9 WIP Cleaned up file config usage 2018-07-30 16:19:09 -05:00
Christopher Haster
b8290e306c WIP removed lfs parameter to lfs traverse 2018-07-30 14:41:17 -05:00
Christopher Haster
c74bcec184 WIP fixed corruption tests 2018-07-30 14:23:51 -05:00
Christopher Haster
868099836d WIP Fixed deorphan test 2018-07-30 09:10:04 -05:00
Christopher Haster
c3c15d7636 Added support for custom attributes 2 2018-07-30 08:15:58 -05:00
Christopher Haster
3a70619f41 WIP Added support for custom attributes 1 2018-07-29 15:28:41 -05:00
Christopher Haster
22e3d33ada Picked up path corner case fixes 2018-07-28 12:07:18 -05:00
Christopher Haster
439a76e3e1 WIP Refactor file/dir iteration for dir update checks 2018-07-28 09:47:57 -05:00
Christopher Haster
236d46ad17 Fixed move handling when caught in update 2018-07-17 18:31:30 -05:00
Christopher Haster
f1719e3310 WIP cleaned up commit logic 2018-07-14 04:26:05 -05:00
Christopher Haster
37cf030445 WIP cleaned up commit logic 2018-07-13 22:51:43 -05:00
Christopher Haster
7ec75a55f2 WIP additional cleanup around attributes 2018-07-13 12:42:30 -05:00
Christopher Haster
dcfe94412a WIP other minor adjustments 2018-07-12 20:43:55 -05:00
Christopher Haster
6a99f6c8fc WIP Changed internal API to return tags over pointers 2018-07-12 20:22:06 -05:00
Christopher Haster
e6d49feb4a WIP renamed tag related things 2018-07-12 19:07:56 -05:00
Christopher Haster
f6347db3da WIP moved things around in get/traverse functions 2018-07-12 18:11:18 -05:00
Christopher Haster
48cc58e25c WIP Tweaked results from find-like functions 2018-07-11 07:18:30 -05:00
Christopher Haster
92d957ab40 WIP Consolidated get functions into one 2018-07-11 05:52:50 -05:00
Christopher Haster
5152b973f0 WIP Moved findscan into fetch as primitive 2018-07-11 04:00:34 -05:00
Christopher Haster
43e6aadef6 WIP consolidated find/parent scanning functions 2018-07-09 17:29:40 -05:00
Christopher Haster
0276e00fac WIP reclaimed 0x3ff as invalid id 2018-07-09 14:53:55 -05:00
Christopher Haster
5b9755f141 WIP restructured tags for more flexible bit encoding 2018-07-09 14:13:31 -05:00
Christopher Haster
f5488f7192 WIP changed type to be retrieved from name not struct 2018-07-09 13:09:23 -05:00
Christopher Haster
2947006660 WIP removed old move logic 2018-07-09 11:47:04 -05:00
Christopher Haster
d5f0e236b8 WIP fixed bug with globals poisoning from dirs
Needs to be cleaned up
2018-07-08 14:21:29 -05:00
Christopher Haster
0d3350665e WIP Fixed issues around wrong ids after bad commits 2018-07-04 01:35:04 -05:00
Christopher Haster
5064cf82fd WIP switched back to deorphan for remove
Utilizing moves wouldn't have worked for rename anyways, and it requires
additional code for much less traveled code path (directory removes)
2018-07-01 22:29:42 -05:00
Christopher Haster
ff13345e96 WIP Restructured tags for better support for global things 2018-05-29 20:08:42 -05:00
Christopher Haster
82948861d2 WIP TEMP move work 2018-05-29 12:35:23 -05:00
Christopher Haster
e9bf206c54 WIP Adopted ISDIR as internal error for root as argument 2018-05-29 01:22:09 -05:00
Christopher Haster
2223bef125 WIP Restructured metadata dir structures 2018-05-29 01:11:26 -05:00
Christopher Haster
d56f326dfb WIP better structure for dir/file lists 2018-05-29 00:51:21 -05:00
Christopher Haster
09b69c5b2a WIP name updates 2018-05-28 19:49:20 -05:00
Christopher Haster
a848b0ebbd WIP almost got move working 2018-05-28 17:46:32 -05:00
Christopher Haster
6cda0442ea WIP made basic tests pass
(format/dirs/files/seek/truncate/interspersed/paths)
2018-05-28 09:43:51 -05:00
Christopher Haster
0e0f015fbd WIP WIP yes two wips 2018-05-28 02:08:16 -05:00
Christopher Haster
fbd25ac533 WIP minor change to fix rename issue 2018-05-27 11:46:22 -05:00
Christopher Haster
de0b719b56 WIP progress so far 2018-05-27 10:15:28 -05:00
Christopher Haster
ca9e43158d WIP fixed enough things to pass basic file testing 2018-05-26 13:50:06 -05:00
Christopher Haster
cd045ed2eb WIP Moved move things into a better place 2018-05-25 19:22:19 -05:00
Christopher Haster
39267fd8b2 WIP file stuff 2018-05-22 23:57:19 -05:00
Christopher Haster
6c2c7e3f3d WIP more progressed 2018-05-22 21:58:14 -05:00
Christopher Haster
2759f012c0 WIP progressed more 2018-05-21 00:56:20 -05:00
Christopher Haster
f4d6ca5552 WIP fixed up dir find 2018-05-20 14:01:11 -05:00
Christopher Haster
57fbc52cfc WIP added wip journalling things for dirs 2018-05-19 18:25:47 -05:00
Christopher Haster
c8323112ee WIP Added tests over entries + attributes 2018-04-16 02:37:32 -05:00
Christopher Haster
7d3c2be49a WIP Fixed big-endian support 2018-04-11 01:29:59 -05:00
Christopher Haster
0e4eb788fe WIP added test config for no inline files 2018-04-11 01:29:59 -05:00
Christopher Haster
6af43aec5b Added lfs_fs_size function for finding a count of used blocks
This has existed for some time in the form of the lfs_traverse
function, however lfs_traverse is relatively unconventional and
has proven to not have been the most intuitive for users.
2018-04-11 01:29:59 -05:00
Christopher Haster
9af404db09 WIP added file/fs set/get attr implementations 2018-04-11 01:29:59 -05:00
Christopher Haster
0347416b89 WIP simplified attribute handling a bit to better match commit regions 2018-04-11 01:29:59 -05:00
Christopher Haster
eb70143469 WIP Clumsy setattrs/getattrs 2018-04-11 01:29:59 -05:00
Christopher Haster
2aee22aa49 WIP custom attributes 2018-04-11 01:29:59 -05:00
Christopher Haster
a82ea60658 WIP added some comments 2018-04-11 01:29:59 -05:00
Christopher Haster
7c0f32dc0b WIP Bumped versions 2018-04-11 01:29:59 -05:00
Christopher Haster
e48a2c488b WIP cleaned up TODOs 2018-04-11 01:29:59 -05:00
Christopher Haster
f37fa75d66 WIP added support for inline files up to 1023 bytes 2018-04-11 01:29:59 -05:00
Christopher Haster
bba71b23f4 WIP Added limits on name/attrs/inline sizes 2018-04-11 01:29:59 -05:00
Christopher Haster
e4a35b78e7 WIP Refactored lfs_dir_set function to umbrella append/update/remove 2018-04-11 01:29:59 -05:00
Christopher Haster
b56d82ff34 WIP Added lfs_dir_get 2018-04-11 01:29:59 -05:00
Christopher Haster
ab9750f5ed WIP moved superblock to entry append 2018-04-11 01:29:59 -05:00
Christopher Haster
2f32222914 WIP fixed bugs 2018-04-11 01:29:59 -05:00
Christopher Haster
7ad2d58ed0 WIP Fixed issue with modifying dir after append in update 2018-04-11 01:29:59 -05:00
Christopher Haster
689159e31d WIP Better implementation of inline files, now with overflowing 2018-04-11 01:29:59 -05:00
Christopher Haster
9a97a97e4c WIP moved asserts out 2018-04-11 01:29:59 -05:00
Christopher Haster
345f7f3235 WIP added hacky taped on inline files 2018-04-11 01:29:59 -05:00
Christopher Haster
a418c2068d WIP Fixed big-endian support 2018-04-11 01:29:59 -05:00
Christopher Haster
d7ed7a41e9 WIP added entry size field 2018-04-11 01:29:59 -05:00
Christopher Haster
960e152261 WIP separated dir_remove for two types of arguments 2018-04-11 01:29:59 -05:00
Christopher Haster
28a5a27bb9 WIP minor improvement to from-memory commits 2018-04-11 01:29:59 -05:00
Christopher Haster
72475f64f6 WIP Allowed taking advantage of empty space earlier in dir search 2018-04-11 01:29:59 -05:00
Christopher Haster
8773d7c81f WIP added callbacks for stuff 2018-04-11 01:29:59 -05:00
Christopher Haster
d636299daf WIP Moved entry tag updates out 2018-04-11 01:29:59 -05:00
Christopher Haster
2d6a37f775 WIP Naive implementation of resizable entries 2018-04-11 01:29:59 -05:00
Christopher Haster
f58408c974 WIP something something flexible updates 2018-04-11 01:29:59 -05:00
Christopher Haster
e1f05ee046 WIP adopted lisp-like dsl for more flexibility 2018-04-11 01:29:59 -05:00
Christopher Haster
f54ad304fc WIP Changed commit DSL to support disk->disk copies 2018-04-11 01:29:59 -05:00
Christopher Haster
2a738463b3 Separated type/struct fields in dir entries
The separation of data-structure vs entry type has been implicit for a
while now, and even taken advantage of to simplify the traverse logic.
2018-04-11 01:29:59 -05:00
33 changed files with 4502 additions and 8036 deletions

View File

@@ -20,23 +20,11 @@ script:
# run tests with a few different configurations # run tests with a few different configurations
- make test QUIET=1 CFLAGS+="-DLFS_READ_SIZE=1 -DLFS_CACHE_SIZE=4" - make test QUIET=1 CFLAGS+="-DLFS_READ_SIZE=1 -DLFS_CACHE_SIZE=4"
- make test QUIET=1 CFLAGS+="-DLFS_READ_SIZE=512 -DLFS_CACHE_SIZE=512 -DLFS_BLOCK_CYCLES=16" - make test QUIET=1 CFLAGS+="-DLFS_READ_SIZE=512 -DLFS_CACHE_SIZE=512 -DLFS_BLOCK_CYCLES=16"
- make test QUIET=1 CFLAGS+="-DLFS_BLOCK_COUNT=1023 -DLFS_LOOKAHEAD_SIZE=256" - make test QUIET=1 CFLAGS+="-DLFS_BLOCK_COUNT=1023 -DLFS_LOOKAHEAD=2048"
- make clean test QUIET=1 CFLAGS+="-DLFS_INLINE_MAX=0" - make clean test QUIET=1 CFLAGS+="-DLFS_INLINE_MAX=0"
- make clean test QUIET=1 CFLAGS+="-DLFS_EMUBD_ERASE_VALUE=0xff"
- make clean test QUIET=1 CFLAGS+="-DLFS_NO_INTRINSICS" - make clean test QUIET=1 CFLAGS+="-DLFS_NO_INTRINSICS"
# additional configurations that don't support all tests (this should be
# fixed but at the moment it is what it is)
- make test_files QUIET=1
CFLAGS+="-DLFS_READ_SIZE=1 -DLFS_BLOCK_SIZE=4096"
- make test_files QUIET=1
CFLAGS+="-DLFS_READ_SIZE=\(2*1024\) -DLFS_BLOCK_SIZE=\(64*1024\)"
- make test_files QUIET=1
CFLAGS+="-DLFS_READ_SIZE=\(8*1024\) -DLFS_BLOCK_SIZE=\(64*1024\)"
- make test_files QUIET=1
CFLAGS+="-DLFS_READ_SIZE=11 -DLFS_BLOCK_SIZE=704"
# compile and find the code size with the smallest configuration # compile and find the code size with the smallest configuration
- make clean size - make clean size
OBJ="$(ls lfs*.o | tr '\n' ' ')" OBJ="$(ls lfs*.o | tr '\n' ' ')"
@@ -48,7 +36,7 @@ script:
if [ "$TRAVIS_TEST_RESULT" -eq 0 ] if [ "$TRAVIS_TEST_RESULT" -eq 0 ]
then then
CURR=$(tail -n1 sizes | awk '{print $1}') CURR=$(tail -n1 sizes | awk '{print $1}')
PREV=$(curl -u "$GEKY_BOT_STATUSES" https://api.github.com/repos/$TRAVIS_REPO_SLUG/status/master \ PREV=$(curl -u $GEKY_BOT_STATUSES https://api.github.com/repos/$TRAVIS_REPO_SLUG/status/master \
| jq -re "select(.sha != \"$TRAVIS_COMMIT\") | jq -re "select(.sha != \"$TRAVIS_COMMIT\")
| .statuses[] | select(.context == \"$STAGE/$NAME\").description | .statuses[] | select(.context == \"$STAGE/$NAME\").description
| capture(\"code size is (?<size>[0-9]+)\").size" \ | capture(\"code size is (?<size>[0-9]+)\").size" \
@@ -78,10 +66,7 @@ jobs:
- CC="arm-linux-gnueabi-gcc --static -mthumb" - CC="arm-linux-gnueabi-gcc --static -mthumb"
- EXEC="qemu-arm" - EXEC="qemu-arm"
install: install:
- sudo apt-get install - sudo apt-get install gcc-arm-linux-gnueabi qemu-user
gcc-arm-linux-gnueabi
libc6-dev-armel-cross
qemu-user
- arm-linux-gnueabi-gcc --version - arm-linux-gnueabi-gcc --version
- qemu-arm -version - qemu-arm -version
@@ -93,10 +78,7 @@ jobs:
- CC="powerpc-linux-gnu-gcc --static" - CC="powerpc-linux-gnu-gcc --static"
- EXEC="qemu-ppc" - EXEC="qemu-ppc"
install: install:
- sudo apt-get install - sudo apt-get install gcc-powerpc-linux-gnu qemu-user
gcc-powerpc-linux-gnu
libc6-dev-powerpc-cross
qemu-user
- powerpc-linux-gnu-gcc --version - powerpc-linux-gnu-gcc --version
- qemu-ppc -version - qemu-ppc -version
@@ -108,10 +90,9 @@ jobs:
- CC="mips-linux-gnu-gcc --static" - CC="mips-linux-gnu-gcc --static"
- EXEC="qemu-mips" - EXEC="qemu-mips"
install: install:
- sudo apt-get install - sudo add-apt-repository -y "deb http://archive.ubuntu.com/ubuntu/ xenial main universe"
gcc-mips-linux-gnu - sudo apt-get -qq update
libc6-dev-mips-cross - sudo apt-get install gcc-mips-linux-gnu qemu-user
qemu-user
- mips-linux-gnu-gcc --version - mips-linux-gnu-gcc --version
- qemu-mips -version - qemu-mips -version
@@ -120,10 +101,9 @@ jobs:
env: env:
- STAGE=test - STAGE=test
- NAME=littlefs-fuse - NAME=littlefs-fuse
if: branch !~ -prefix$
install: install:
- sudo apt-get install libfuse-dev - sudo apt-get install libfuse-dev
- git clone --depth 1 https://github.com/geky/littlefs-fuse -b v2 - git clone --depth 1 https://github.com/geky/littlefs-fuse -b v2-alpha
- fusermount -V - fusermount -V
- gcc --version - gcc --version
before_script: before_script:
@@ -133,7 +113,7 @@ jobs:
- mkdir mount - mkdir mount
- sudo chmod a+rw /dev/loop0 - sudo chmod a+rw /dev/loop0
- dd if=/dev/zero bs=512 count=4096 of=disk - dd if=/dev/zero bs=512 count=2048 of=disk
- losetup /dev/loop0 disk - losetup /dev/loop0 disk
script: script:
# self-host test # self-host test
@@ -146,140 +126,59 @@ jobs:
- mkdir mount/littlefs - mkdir mount/littlefs
- cp -r $(git ls-tree --name-only HEAD) mount/littlefs - cp -r $(git ls-tree --name-only HEAD) mount/littlefs
- cd mount/littlefs - cd mount/littlefs
- stat . - ls
- ls -flh
- make -B test_dirs test_files QUIET=1 - make -B test_dirs test_files QUIET=1
# self-host with littlefs-fuse for fuzz test # Automatically update releases
- stage: test
env:
- STAGE=test
- NAME=littlefs-migration
if: branch !~ -prefix$
install:
- sudo apt-get install libfuse-dev
- git clone --depth 1 https://github.com/geky/littlefs-fuse -b v2 v2
- git clone --depth 1 https://github.com/geky/littlefs-fuse -b v1 v1
- fusermount -V
- gcc --version
before_script:
# setup disk for littlefs-fuse
- rm -rf v2/littlefs/*
- cp -r $(git ls-tree --name-only HEAD) v2/littlefs
- mkdir mount
- sudo chmod a+rw /dev/loop0
- dd if=/dev/zero bs=512 count=4096 of=disk
- losetup /dev/loop0 disk
script:
# compile v1 and v2
- make -C v1
- make -C v2
# run self-host test with v1
- v1/lfs --format /dev/loop0
- v1/lfs /dev/loop0 mount
- ls mount
- mkdir mount/littlefs
- cp -r $(git ls-tree --name-only HEAD) mount/littlefs
- cd mount/littlefs
- stat .
- ls -flh
- make -B test_dirs test_files QUIET=1
# attempt to migrate
- cd ../..
- fusermount -u mount
- v2/lfs --migrate /dev/loop0
- v2/lfs /dev/loop0 mount
# run self-host test with v2 right where we left off
- ls mount
- cd mount/littlefs
- stat .
- ls -flh
- make -B test_dirs test_files QUIET=1
# Automatically create releases
- stage: deploy - stage: deploy
env: env:
- STAGE=deploy - STAGE=deploy
- NAME=deploy - NAME=deploy
script: script:
# Find version defined in lfs.h
- LFS_VERSION=$(grep -ox '#define LFS_VERSION .*' lfs.h | cut -d ' ' -f3)
- LFS_VERSION_MAJOR=$((0xffff & ($LFS_VERSION >> 16)))
- LFS_VERSION_MINOR=$((0xffff & ($LFS_VERSION >> 0)))
# Grab latests patch from repo tags, default to 0
- LFS_VERSION_PATCH=$(curl -f -u "$GEKY_BOT_RELEASES"
https://api.github.com/repos/$TRAVIS_REPO_SLUG/git/refs
| jq 'map(.ref | match(
"refs/tags/v'"$LFS_VERSION_MAJOR"'\\.'"$LFS_VERSION_MINOR"'\\.(.*)$")
.captures[].string | tonumber + 1) | max // 0')
# We have our new version
- LFS_VERSION="v$LFS_VERSION_MAJOR.$LFS_VERSION_MINOR.$LFS_VERSION_PATCH"
- echo "VERSION $LFS_VERSION"
- | - |
bash << 'SCRIPT'
set -ev
# Find version defined in lfs.h
LFS_VERSION=$(grep -ox '#define LFS_VERSION .*' lfs.h | cut -d ' ' -f3)
LFS_VERSION_MAJOR=$((0xffff & ($LFS_VERSION >> 16)))
LFS_VERSION_MINOR=$((0xffff & ($LFS_VERSION >> 0)))
# Grab latests patch from repo tags, default to 0, needs finagling
# to get past github's pagination api
PREV_URL=https://api.github.com/repos/$TRAVIS_REPO_SLUG/git/refs/tags/v$LFS_VERSION_MAJOR.$LFS_VERSION_MINOR.
PREV_URL=$(curl -u "$GEKY_BOT_RELEASES" "$PREV_URL" -I \
| sed -n '/^Link/{s/.*<\(.*\)>; rel="last"/\1/;p;q0};$q1' \
|| echo $PREV_URL)
LFS_VERSION_PATCH=$(curl -u "$GEKY_BOT_RELEASES" "$PREV_URL" \
| jq 'map(.ref | match("\\bv.*\\..*\\.(.*)$";"g")
.captures[].string | tonumber) | max + 1' \
|| echo 0)
# We have our new version
LFS_VERSION="v$LFS_VERSION_MAJOR.$LFS_VERSION_MINOR.$LFS_VERSION_PATCH"
echo "VERSION $LFS_VERSION"
# Check that we're the most recent commit # Check that we're the most recent commit
CURRENT_COMMIT=$(curl -f -u "$GEKY_BOT_RELEASES" \ CURRENT_COMMIT=$(curl -f -u "$GEKY_BOT_RELEASES" \
https://api.github.com/repos/$TRAVIS_REPO_SLUG/commits/master \ https://api.github.com/repos/$TRAVIS_REPO_SLUG/commits/master \
| jq -re '.sha') | jq -re '.sha')
[ "$TRAVIS_COMMIT" == "$CURRENT_COMMIT" ] || exit 0 if [ "$TRAVIS_COMMIT" == "$CURRENT_COMMIT" ]
# Create major branch
git branch v$LFS_VERSION_MAJOR HEAD
# Create major prefix branch
git config user.name "geky bot"
git config user.email "bot@geky.net"
git fetch https://github.com/$TRAVIS_REPO_SLUG.git \
--depth=50 v$LFS_VERSION_MAJOR-prefix || true
./scripts/prefix.py lfs$LFS_VERSION_MAJOR
git branch v$LFS_VERSION_MAJOR-prefix $( \
git commit-tree $(git write-tree) \
$(git rev-parse --verify -q FETCH_HEAD | sed -e 's/^/-p /') \
-p HEAD \
-m "Generated v$LFS_VERSION_MAJOR prefixes")
git reset --hard
# Update major version branches (vN and vN-prefix)
git push --atomic https://$GEKY_BOT_RELEASES@github.com/$TRAVIS_REPO_SLUG.git \
v$LFS_VERSION_MAJOR \
v$LFS_VERSION_MAJOR-prefix
# Build release notes
PREV=$(git tag --sort=-v:refname -l "v*" | head -1)
if [ ! -z "$PREV" ]
then then
echo "PREV $PREV" # Build release notes
CHANGES=$(git log --oneline $PREV.. --grep='^Merge' --invert-grep) PREV=$(git tag --sort=-v:refname -l "v*" | head -1)
printf "CHANGES\n%s\n\n" "$CHANGES" if [ ! -z "$PREV" ]
then
echo "PREV $PREV"
CHANGES=$'### Changes\n\n'$( \
git log --oneline $PREV.. --grep='^Merge' --invert-grep)
printf "CHANGES\n%s\n\n" "$CHANGES"
fi
# Create the release
curl -f -u "$GEKY_BOT_RELEASES" -X POST \
https://api.github.com/repos/$TRAVIS_REPO_SLUG/releases \
-d "{
\"tag_name\": \"$LFS_VERSION\",
\"target_commitish\": \"$TRAVIS_COMMIT\",
\"name\": \"${LFS_VERSION%.0}\",
\"body\": $(jq -sR '.' <<< "$CHANGES")
}"
fi fi
case ${GEKY_BOT_DRAFT:-minor} in
true) DRAFT=true ;;
minor) DRAFT=$(jq -R 'endswith(".0")' <<< "$LFS_VERSION") ;;
false) DRAFT=false ;;
esac
# Create the release and patch version tag (vN.N.N)
curl -f -u "$GEKY_BOT_RELEASES" -X POST \
https://api.github.com/repos/$TRAVIS_REPO_SLUG/releases \
-d "{
\"tag_name\": \"$LFS_VERSION\",
\"name\": \"${LFS_VERSION%.0}\",
\"target_commitish\": \"$TRAVIS_COMMIT\",
\"draft\": $DRAFT,
\"body\": $(jq -sR '.' <<< "$CHANGES")
}" #"
SCRIPT
# Manage statuses # Manage statuses
before_install: before_install:
- | - |
curl -u "$GEKY_BOT_STATUSES" -X POST \ curl -u $GEKY_BOT_STATUSES -X POST \
https://api.github.com/repos/$TRAVIS_REPO_SLUG/statuses/${TRAVIS_PULL_REQUEST_SHA:-$TRAVIS_COMMIT} \ https://api.github.com/repos/$TRAVIS_REPO_SLUG/statuses/${TRAVIS_PULL_REQUEST_SHA:-$TRAVIS_COMMIT} \
-d "{ -d "{
\"context\": \"$STAGE/$NAME\", \"context\": \"$STAGE/$NAME\",
@@ -290,7 +189,7 @@ before_install:
after_failure: after_failure:
- | - |
curl -u "$GEKY_BOT_STATUSES" -X POST \ curl -u $GEKY_BOT_STATUSES -X POST \
https://api.github.com/repos/$TRAVIS_REPO_SLUG/statuses/${TRAVIS_PULL_REQUEST_SHA:-$TRAVIS_COMMIT} \ https://api.github.com/repos/$TRAVIS_REPO_SLUG/statuses/${TRAVIS_PULL_REQUEST_SHA:-$TRAVIS_COMMIT} \
-d "{ -d "{
\"context\": \"$STAGE/$NAME\", \"context\": \"$STAGE/$NAME\",
@@ -301,7 +200,7 @@ after_failure:
after_success: after_success:
- | - |
curl -u "$GEKY_BOT_STATUSES" -X POST \ curl -u $GEKY_BOT_STATUSES -X POST \
https://api.github.com/repos/$TRAVIS_REPO_SLUG/statuses/${TRAVIS_PULL_REQUEST_SHA:-$TRAVIS_COMMIT} \ https://api.github.com/repos/$TRAVIS_REPO_SLUG/statuses/${TRAVIS_PULL_REQUEST_SHA:-$TRAVIS_COMMIT} \
-d "{ -d "{
\"context\": \"$STAGE/$NAME\", \"context\": \"$STAGE/$NAME\",

2873
DESIGN.md

File diff suppressed because it is too large Load Diff

View File

@@ -24,14 +24,8 @@ endif
ifdef WORD ifdef WORD
override CFLAGS += -m$(WORD) override CFLAGS += -m$(WORD)
endif endif
ifdef TRACE
override CFLAGS += -DLFS_YES_TRACE
endif
override CFLAGS += -I. override CFLAGS += -I.
override CFLAGS += -std=c99 -Wall -pedantic override CFLAGS += -std=c99 -Wall -pedantic -Wshadow -Wunused-parameter
override CFLAGS += -Wextra -Wshadow -Wjump-misses-init -Wundef
# Remove missing-field-initializers because of GCC bug
override CFLAGS += -Wno-missing-field-initializers
all: $(TARGET) all: $(TARGET)
@@ -42,25 +36,14 @@ size: $(OBJ)
$(SIZE) -t $^ $(SIZE) -t $^
.SUFFIXES: .SUFFIXES:
test: \ test: test_format test_dirs test_files test_seek test_truncate \
test_format \ test_entries test_interspersed test_alloc test_paths test_attrs \
test_dirs \ test_move test_orphan test_corrupt
test_files \
test_seek \
test_truncate \
test_entries \
test_interspersed \
test_alloc \
test_paths \
test_attrs \
test_move \
test_orphan \
test_corrupt
@rm test.c @rm test.c
test_%: tests/test_%.sh test_%: tests/test_%.sh
ifdef QUIET ifdef QUIET
@./$< | sed -nu '/^[-=]/p' @./$< | sed -n '/^[-=]/p'
else else
./$< ./$<
endif endif

158
README.md
View File

@@ -1,6 +1,6 @@
## littlefs ## The little filesystem
A little fail-safe filesystem designed for microcontrollers. A little fail-safe filesystem designed for embedded systems.
``` ```
| | | .---._____ | | | .---._____
@@ -11,19 +11,17 @@ A little fail-safe filesystem designed for microcontrollers.
| | | | | |
``` ```
**Power-loss resilience** - littlefs is designed to handle random power **Bounded RAM/ROM** - The littlefs is designed to work with a limited amount
failures. All file operations have strong copy-on-write guarantees and if of memory. Recursion is avoided and dynamic memory is limited to configurable
power is lost the filesystem will fall back to the last known good state. buffers that can be provided statically.
**Dynamic wear leveling** - littlefs is designed with flash in mind, and **Power-loss resilient** - The littlefs is designed for systems that may have
provides wear leveling over dynamic blocks. Additionally, littlefs can random power failures. The littlefs has strong copy-on-write guarantees and
detect bad blocks and work around them. storage on disk is always kept in a valid state.
**Bounded RAM/ROM** - littlefs is designed to work with a small amount of **Wear leveling** - Since the most common form of embedded storage is erodible
memory. RAM usage is strictly bounded, which means RAM consumption does not flash memories, littlefs provides a form of dynamic wear leveling for systems
change as the filesystem grows. The filesystem contains no unbounded that can not fit a full flash translation layer.
recursion and dynamic memory is limited to configurable buffers that can be
provided statically.
## Example ## Example
@@ -51,9 +49,7 @@ const struct lfs_config cfg = {
.prog_size = 16, .prog_size = 16,
.block_size = 4096, .block_size = 4096,
.block_count = 128, .block_count = 128,
.cache_size = 16, .lookahead = 128,
.lookahead_size = 16,
.block_cycles = 500,
}; };
// entry point // entry point
@@ -94,11 +90,11 @@ int main(void) {
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 [lfs.h](lfs.h).
littlefs takes in a configuration structure that defines how the filesystem As you may have noticed, littlefs takes in a configuration structure that
operates. The configuration struct provides the filesystem with the block defines how the filesystem operates. The configuration struct provides the
device operations and dimensions, tweakable parameters that tradeoff memory filesystem with the block device operations and dimensions, tweakable
usage for performance, and optional static buffers if the user wants to avoid parameters that tradeoff memory usage for performance, and optional
dynamic memory. static buffers if the user wants to avoid 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 `lfs_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
@@ -110,14 +106,14 @@ directory functions, with the deviation that the allocation of filesystem
structures must be provided by the user. structures must be provided by the user.
All POSIX operations, such as remove and rename, are atomic, even in event All POSIX operations, such as remove and rename, are atomic, even in event
of power-loss. Additionally, no file updates are not actually committed to of power-loss. Additionally, no file updates are actually committed to the
the filesystem until sync or close is called on the file. filesystem until sync or close is called on the file.
## Other notes ## Other notes
All littlefs calls have the potential to return a negative error code. The All littlefs have the potential to return a negative error code. The errors
errors can be either one of those found in the `enum lfs_error` in can be either one of those found in the `enum lfs_error` in [lfs.h](lfs.h),
[lfs.h](lfs.h), or an error returned by the user's block device operations. 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 `LFS_ERR_CORRUPT` error if the implementation already can
@@ -131,60 +127,14 @@ from memory, otherwise data integrity can not be guaranteed. If the `write`
function does not perform caching, and therefore each `read` or `write` call function does not perform caching, and therefore each `read` or `write` call
hits the memory, the `sync` function can simply return 0. hits the memory, the `sync` function can simply return 0.
## Design ## Reference material
At a high level, littlefs is a block based filesystem that uses small logs to [DESIGN.md](DESIGN.md) - DESIGN.md contains a fully detailed dive into how
store metadata and larger copy-on-write (COW) structures to store file data. littlefs actually works. I would encourage you to read it since the
solutions and tradeoffs at work here are quite interesting.
In littlefs, these ingredients form a sort of two-layered cake, with the small [SPEC.md](SPEC.md) - SPEC.md contains the on-disk specification of littlefs
logs (called metadata pairs) providing fast updates to metadata anywhere on with all the nitty-gritty details. Can be useful for developing tooling.
storage, while the COW structures store file data compactly and without any
wear amplification cost.
Both of these data structures are built out of blocks, which are fed by a
common block allocator. By limiting the number of erases allowed on a block
per allocation, the allocator provides dynamic wear leveling over the entire
filesystem.
```
root
.--------.--------.
| A'| B'| |
| | |-> |
| | | |
'--------'--------'
.----' '--------------.
A v B v
.--------.--------. .--------.--------.
| C'| D'| | | E'|new| |
| | |-> | | | E'|-> |
| | | | | | | |
'--------'--------' '--------'--------'
.-' '--. | '------------------.
v v .-' v
.--------. .--------. v .--------.
| C | | D | .--------. write | new E |
| | | | | E | ==> | |
| | | | | | | |
'--------' '--------' | | '--------'
'--------' .-' |
.-' '-. .-------------|------'
v v v v
.--------. .--------. .--------.
| F | | G | | new F |
| | | | | |
| | | | | |
'--------' '--------' '--------'
```
More details on how littlefs works can be found in [DESIGN.md](DESIGN.md) and
[SPEC.md](SPEC.md).
- [DESIGN.md](DESIGN.md) - A fully detailed dive into how littlefs works.
I would suggest reading it as the tradeoffs at work are quite interesting.
- [SPEC.md](SPEC.md) - The on-disk specification of littlefs with all the
nitty-gritty details. May be useful for tooling development.
## Testing ## Testing
@@ -198,9 +148,9 @@ make test
## License ## License
The littlefs is provided under the [BSD-3-Clause] license. See The littlefs is provided under the [BSD-3-Clause](https://spdx.org/licenses/BSD-3-Clause.html)
[LICENSE.md](LICENSE.md) for more information. Contributions to this project license. See [LICENSE.md](LICENSE.md) for more information. Contributions to
are accepted under the same license. this project are accepted under the same license.
Individual files contain the following tag instead of the full license text. Individual files contain the following tag instead of the full license text.
@@ -211,39 +161,17 @@ License Identifiers that are here available: http://spdx.org/licenses/
## Related projects ## Related projects
- [littlefs-fuse] - A [FUSE] wrapper for littlefs. The project allows you to [Mbed OS](https://github.com/ARMmbed/mbed-os/tree/master/features/filesystem/littlefs) -
mount littlefs directly on a Linux machine. Can be useful for debugging The easiest way to get started with littlefs is to jump into [Mbed](https://os.mbed.com/),
littlefs if you have an SD card handy. which already has block device drivers for most forms of embedded storage. The
littlefs is available in Mbed OS as the [LittleFileSystem](https://os.mbed.com/docs/latest/reference/littlefilesystem.html)
class.
- [littlefs-js] - A javascript wrapper for littlefs. I'm not sure why you would [littlefs-fuse](https://github.com/geky/littlefs-fuse) - A [FUSE](https://github.com/libfuse/libfuse)
want this, but it is handy for demos. You can see it in action wrapper for littlefs. The project allows you to mount littlefs directly on a
[here][littlefs-js-demo]. Linux machine. Can be useful for debugging littlefs if you have an SD card
handy.
- [mklfs] - A command line tool built by the [Lua RTOS] guys for making [littlefs-js](https://github.com/geky/littlefs-js) - A javascript wrapper for
littlefs images from a host PC. Supports Windows, Mac OS, and Linux. littlefs. I'm not sure why you would want this, but it is handy for demos.
You can see it in action [here](http://littlefs.geky.net/demo.html).
- [Mbed OS] - The easiest way to get started with littlefs is to jump into Mbed
which already has block device drivers for most forms of embedded storage.
littlefs is available in Mbed OS as the [LittleFileSystem] class.
- [SPIFFS] - Another excellent embedded filesystem for NOR flash. As a more
traditional logging filesystem with full static wear-leveling, SPIFFS will
likely outperform littlefs on small memories such as the internal flash on
microcontrollers.
- [Dhara] - An interesting NAND flash translation layer designed for small
MCUs. It offers static wear-leveling and power-resilience with only a fixed
_O(|address|)_ pointer structure stored on each block and in RAM.
[BSD-3-Clause]: https://spdx.org/licenses/BSD-3-Clause.html
[littlefs-fuse]: https://github.com/geky/littlefs-fuse
[FUSE]: https://github.com/libfuse/libfuse
[littlefs-js]: https://github.com/geky/littlefs-js
[littlefs-js-demo]:http://littlefs.geky.net/demo.html
[mklfs]: https://github.com/whitecatboard/Lua-RTOS-ESP32/tree/master/components/mklfs/src
[Lua RTOS]: https://github.com/whitecatboard/Lua-RTOS-ESP32
[Mbed OS]: https://github.com/armmbed/mbed-os
[LittleFileSystem]: https://os.mbed.com/docs/mbed-os/v5.12/apis/littlefilesystem.html
[SPIFFS]: https://github.com/pellepl/spiffs
[Dhara]: https://github.com/dlbeer/dhara

1043
SPEC.md

File diff suppressed because it is too large Load Diff

View File

@@ -11,6 +11,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <limits.h> #include <limits.h>
#include <dirent.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
#include <assert.h> #include <assert.h>
@@ -29,7 +30,7 @@ static inline void lfs_emubd_tole32(lfs_emubd_t *emu) {
emu->stats.prog_count = lfs_tole32(emu->stats.prog_count); emu->stats.prog_count = lfs_tole32(emu->stats.prog_count);
emu->stats.erase_count = lfs_tole32(emu->stats.erase_count); emu->stats.erase_count = lfs_tole32(emu->stats.erase_count);
for (unsigned i = 0; i < sizeof(emu->history.blocks) / for (int i = 0; i < sizeof(emu->history.blocks) /
sizeof(emu->history.blocks[0]); i++) { sizeof(emu->history.blocks[0]); i++) {
emu->history.blocks[i] = lfs_tole32(emu->history.blocks[i]); emu->history.blocks[i] = lfs_tole32(emu->history.blocks[i]);
} }
@@ -45,7 +46,7 @@ static inline void lfs_emubd_fromle32(lfs_emubd_t *emu) {
emu->stats.prog_count = lfs_fromle32(emu->stats.prog_count); emu->stats.prog_count = lfs_fromle32(emu->stats.prog_count);
emu->stats.erase_count = lfs_fromle32(emu->stats.erase_count); emu->stats.erase_count = lfs_fromle32(emu->stats.erase_count);
for (unsigned i = 0; i < sizeof(emu->history.blocks) / for (int i = 0; i < sizeof(emu->history.blocks) /
sizeof(emu->history.blocks[0]); i++) { sizeof(emu->history.blocks[0]); i++) {
emu->history.blocks[i] = lfs_fromle32(emu->history.blocks[i]); emu->history.blocks[i] = lfs_fromle32(emu->history.blocks[i]);
} }
@@ -54,15 +55,6 @@ static inline void lfs_emubd_fromle32(lfs_emubd_t *emu) {
// Block device emulated on existing filesystem // Block device emulated on existing filesystem
int lfs_emubd_create(const struct lfs_config *cfg, const char *path) { int lfs_emubd_create(const struct lfs_config *cfg, const char *path) {
LFS_TRACE("lfs_emubd_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);
lfs_emubd_t *emu = cfg->context; lfs_emubd_t *emu = cfg->context;
emu->cfg.read_size = cfg->read_size; emu->cfg.read_size = cfg->read_size;
emu->cfg.prog_size = cfg->prog_size; emu->cfg.prog_size = cfg->prog_size;
@@ -73,9 +65,7 @@ int lfs_emubd_create(const struct lfs_config *cfg, const char *path) {
size_t pathlen = strlen(path); size_t pathlen = strlen(path);
emu->path = malloc(pathlen + 1 + LFS_NAME_MAX + 1); emu->path = malloc(pathlen + 1 + LFS_NAME_MAX + 1);
if (!emu->path) { if (!emu->path) {
int err = -ENOMEM; return -ENOMEM;
LFS_TRACE("lfs_emubd_create -> %"PRId32, err);
return err;
} }
strcpy(emu->path, path); strcpy(emu->path, path);
@@ -86,31 +76,24 @@ int lfs_emubd_create(const struct lfs_config *cfg, const char *path) {
// Create directory if it doesn't exist // Create directory if it doesn't exist
int err = mkdir(path, 0777); int err = mkdir(path, 0777);
if (err && errno != EEXIST) { if (err && errno != EEXIST) {
err = -errno; return -errno;
LFS_TRACE("lfs_emubd_create -> %"PRId32, err);
return err;
} }
// Load stats to continue incrementing // Load stats to continue incrementing
snprintf(emu->child, LFS_NAME_MAX, ".stats"); snprintf(emu->child, LFS_NAME_MAX, ".stats");
FILE *f = fopen(emu->path, "r"); FILE *f = fopen(emu->path, "r");
if (!f) { if (!f) {
memset(&emu->stats, LFS_EMUBD_ERASE_VALUE, sizeof(emu->stats)); memset(&emu->stats, 0, sizeof(emu->stats));
} else { } else {
size_t res = fread(&emu->stats, sizeof(emu->stats), 1, f); size_t res = fread(&emu->stats, sizeof(emu->stats), 1, f);
lfs_emubd_fromle32(emu); lfs_emubd_fromle32(emu);
if (res < 1) { if (res < 1) {
err = -errno; return -errno;
LFS_TRACE("lfs_emubd_create -> %"PRId32, err);
fclose(f);
return err;
} }
err = fclose(f); err = fclose(f);
if (err) { if (err) {
err = -errno; return -errno;
LFS_TRACE("lfs_emubd_create -> %"PRId32, err);
return err;
} }
} }
@@ -123,37 +106,27 @@ int lfs_emubd_create(const struct lfs_config *cfg, const char *path) {
size_t res = fread(&emu->history, sizeof(emu->history), 1, f); size_t res = fread(&emu->history, sizeof(emu->history), 1, f);
lfs_emubd_fromle32(emu); lfs_emubd_fromle32(emu);
if (res < 1) { if (res < 1) {
err = -errno; return -errno;
LFS_TRACE("lfs_emubd_create -> %"PRId32, err);
fclose(f);
return err;
} }
err = fclose(f); err = fclose(f);
if (err) { if (err) {
err = -errno; return -errno;
LFS_TRACE("lfs_emubd_create -> %"PRId32, err);
return err;
} }
} }
LFS_TRACE("lfs_emubd_create -> %"PRId32, 0);
return 0; return 0;
} }
void lfs_emubd_destroy(const struct lfs_config *cfg) { void lfs_emubd_destroy(const struct lfs_config *cfg) {
LFS_TRACE("lfs_emubd_destroy(%p)", (void*)cfg);
lfs_emubd_sync(cfg); lfs_emubd_sync(cfg);
lfs_emubd_t *emu = cfg->context; lfs_emubd_t *emu = cfg->context;
free(emu->path); free(emu->path);
LFS_TRACE("lfs_emubd_destroy -> %s", "void");
} }
int lfs_emubd_read(const struct lfs_config *cfg, lfs_block_t block, int lfs_emubd_read(const struct lfs_config *cfg, lfs_block_t block,
lfs_off_t off, void *buffer, lfs_size_t size) { lfs_off_t off, void *buffer, lfs_size_t size) {
LFS_TRACE("lfs_emubd_read(%p, 0x%"PRIx32", %"PRIu32", %p, %"PRIu32")",
(void*)cfg, block, off, buffer, size);
lfs_emubd_t *emu = cfg->context; lfs_emubd_t *emu = cfg->context;
uint8_t *data = buffer; uint8_t *data = buffer;
@@ -170,45 +143,32 @@ int lfs_emubd_read(const struct lfs_config *cfg, lfs_block_t block,
FILE *f = fopen(emu->path, "rb"); FILE *f = fopen(emu->path, "rb");
if (!f && errno != ENOENT) { if (!f && errno != ENOENT) {
int err = -errno; return -errno;
LFS_TRACE("lfs_emubd_read -> %d", err);
return err;
} }
if (f) { if (f) {
int err = fseek(f, off, SEEK_SET); int err = fseek(f, off, SEEK_SET);
if (err) { if (err) {
err = -errno; return -errno;
LFS_TRACE("lfs_emubd_read -> %d", err);
fclose(f);
return err;
} }
size_t res = fread(data, 1, size, f); size_t res = fread(data, 1, size, f);
if (res < size && !feof(f)) { if (res < size && !feof(f)) {
err = -errno; return -errno;
LFS_TRACE("lfs_emubd_read -> %d", err);
fclose(f);
return err;
} }
err = fclose(f); err = fclose(f);
if (err) { if (err) {
err = -errno; return -errno;
LFS_TRACE("lfs_emubd_read -> %d", err);
return err;
} }
} }
emu->stats.read_count += size; emu->stats.read_count += 1;
LFS_TRACE("lfs_emubd_read -> %d", 0);
return 0; return 0;
} }
int lfs_emubd_prog(const struct lfs_config *cfg, lfs_block_t block, int lfs_emubd_prog(const struct lfs_config *cfg, lfs_block_t block,
lfs_off_t off, const void *buffer, lfs_size_t size) { lfs_off_t off, const void *buffer, lfs_size_t size) {
LFS_TRACE("lfs_emubd_prog(%p, 0x%"PRIx32", %"PRIu32", %p, %"PRIu32")",
(void*)cfg, block, off, buffer, size);
lfs_emubd_t *emu = cfg->context; lfs_emubd_t *emu = cfg->context;
const uint8_t *data = buffer; const uint8_t *data = buffer;
@@ -222,9 +182,7 @@ int lfs_emubd_prog(const struct lfs_config *cfg, lfs_block_t block,
FILE *f = fopen(emu->path, "r+b"); FILE *f = fopen(emu->path, "r+b");
if (!f) { if (!f) {
int err = (errno == EACCES) ? 0 : -errno; return (errno == EACCES) ? 0 : -errno;
LFS_TRACE("lfs_emubd_prog -> %d", err);
return err;
} }
// Check that file was erased // Check that file was erased
@@ -232,58 +190,42 @@ int lfs_emubd_prog(const struct lfs_config *cfg, lfs_block_t block,
int err = fseek(f, off, SEEK_SET); int err = fseek(f, off, SEEK_SET);
if (err) { if (err) {
err = -errno; return -errno;
LFS_TRACE("lfs_emubd_prog -> %d", err);
fclose(f);
return err;
} }
size_t res = fwrite(data, 1, size, f); size_t res = fwrite(data, 1, size, f);
if (res < size) { if (res < size) {
err = -errno; return -errno;
LFS_TRACE("lfs_emubd_prog -> %d", err);
fclose(f);
return err;
} }
err = fseek(f, off, SEEK_SET); err = fseek(f, off, SEEK_SET);
if (err) { if (err) {
err = -errno; return -errno;
LFS_TRACE("lfs_emubd_prog -> %d", err);
fclose(f);
return err;
} }
uint8_t dat; uint8_t dat;
res = fread(&dat, 1, 1, f); res = fread(&dat, 1, 1, f);
if (res < 1) { if (res < 1) {
err = -errno; return -errno;
LFS_TRACE("lfs_emubd_prog -> %d", err);
fclose(f);
return err;
} }
err = fclose(f); err = fclose(f);
if (err) { if (err) {
err = -errno; return -errno;
LFS_TRACE("lfs_emubd_prog -> %d", err);
return err;
} }
// update history and stats // update history and stats
if (block != emu->history.blocks[0]) { if (block != emu->history.blocks[0]) {
memmove(&emu->history.blocks[1], &emu->history.blocks[0], memcpy(&emu->history.blocks[1], &emu->history.blocks[0],
sizeof(emu->history) - sizeof(emu->history.blocks[0])); sizeof(emu->history) - sizeof(emu->history.blocks[0]));
emu->history.blocks[0] = block; emu->history.blocks[0] = block;
} }
emu->stats.prog_count += size; emu->stats.prog_count += 1;
LFS_TRACE("lfs_emubd_prog -> %d", 0);
return 0; return 0;
} }
int lfs_emubd_erase(const struct lfs_config *cfg, lfs_block_t block) { int lfs_emubd_erase(const struct lfs_config *cfg, lfs_block_t block) {
LFS_TRACE("lfs_emubd_erase(%p, 0x%"PRIx32")", (void*)cfg, block);
lfs_emubd_t *emu = cfg->context; lfs_emubd_t *emu = cfg->context;
// Check if erase is valid // Check if erase is valid
@@ -294,121 +236,89 @@ int lfs_emubd_erase(const struct lfs_config *cfg, lfs_block_t block) {
struct stat st; struct stat st;
int err = stat(emu->path, &st); int err = stat(emu->path, &st);
if (err && errno != ENOENT) { if (err && errno != ENOENT) {
err = -errno; return -errno;
LFS_TRACE("lfs_emubd_erase -> %d", err);
return err;
} }
if (!err && S_ISREG(st.st_mode) && (S_IWUSR & st.st_mode)) { if (!err && S_ISREG(st.st_mode) && (S_IWUSR & st.st_mode)) {
err = unlink(emu->path); err = unlink(emu->path);
if (err) { if (err) {
err = -errno; return -errno;
LFS_TRACE("lfs_emubd_erase -> %d", err);
return err;
} }
} }
if (err || (S_ISREG(st.st_mode) && (S_IWUSR & st.st_mode))) { if (err || (S_ISREG(st.st_mode) && (S_IWUSR & st.st_mode))) {
FILE *f = fopen(emu->path, "w"); FILE *f = fopen(emu->path, "w");
if (!f) { if (!f) {
err = -errno; return -errno;
LFS_TRACE("lfs_emubd_erase -> %d", err);
return err;
} }
err = fclose(f); err = fclose(f);
if (err) { if (err) {
err = -errno; return -errno;
LFS_TRACE("lfs_emubd_erase -> %d", err);
return err;
} }
} }
emu->stats.erase_count += cfg->block_size; emu->stats.erase_count += 1;
LFS_TRACE("lfs_emubd_erase -> %d", 0);
return 0; return 0;
} }
int lfs_emubd_sync(const struct lfs_config *cfg) { int lfs_emubd_sync(const struct lfs_config *cfg) {
LFS_TRACE("lfs_emubd_sync(%p)", (void*)cfg);
lfs_emubd_t *emu = cfg->context; lfs_emubd_t *emu = cfg->context;
// Just write out info/stats for later lookup // Just write out info/stats for later lookup
snprintf(emu->child, LFS_NAME_MAX, ".config"); snprintf(emu->child, LFS_NAME_MAX, ".config");
FILE *f = fopen(emu->path, "w"); FILE *f = fopen(emu->path, "w");
if (!f) { if (!f) {
int err = -errno; return -errno;
LFS_TRACE("lfs_emubd_sync -> %d", err);
return err;
} }
lfs_emubd_tole32(emu); lfs_emubd_tole32(emu);
size_t res = fwrite(&emu->cfg, sizeof(emu->cfg), 1, f); size_t res = fwrite(&emu->cfg, sizeof(emu->cfg), 1, f);
lfs_emubd_fromle32(emu); lfs_emubd_fromle32(emu);
if (res < 1) { if (res < 1) {
int err = -errno; return -errno;
LFS_TRACE("lfs_emubd_sync -> %d", err);
fclose(f);
return err;
} }
int err = fclose(f); int err = fclose(f);
if (err) { if (err) {
err = -errno; return -errno;
LFS_TRACE("lfs_emubd_sync -> %d", err);
return err;
} }
snprintf(emu->child, LFS_NAME_MAX, ".stats"); snprintf(emu->child, LFS_NAME_MAX, ".stats");
f = fopen(emu->path, "w"); f = fopen(emu->path, "w");
if (!f) { if (!f) {
err = -errno; return -errno;
LFS_TRACE("lfs_emubd_sync -> %d", err);
return err;
} }
lfs_emubd_tole32(emu); lfs_emubd_tole32(emu);
res = fwrite(&emu->stats, sizeof(emu->stats), 1, f); res = fwrite(&emu->stats, sizeof(emu->stats), 1, f);
lfs_emubd_fromle32(emu); lfs_emubd_fromle32(emu);
if (res < 1) { if (res < 1) {
err = -errno; return -errno;
LFS_TRACE("lfs_emubd_sync -> %d", err);
fclose(f);
return err;
} }
err = fclose(f); err = fclose(f);
if (err) { if (err) {
err = -errno; return -errno;
LFS_TRACE("lfs_emubd_sync -> %d", err);
return err;
} }
snprintf(emu->child, LFS_NAME_MAX, ".history"); snprintf(emu->child, LFS_NAME_MAX, ".history");
f = fopen(emu->path, "w"); f = fopen(emu->path, "w");
if (!f) { if (!f) {
err = -errno; return -errno;
LFS_TRACE("lfs_emubd_sync -> %d", err);
return err;
} }
lfs_emubd_tole32(emu); lfs_emubd_tole32(emu);
res = fwrite(&emu->history, sizeof(emu->history), 1, f); res = fwrite(&emu->history, sizeof(emu->history), 1, f);
lfs_emubd_fromle32(emu); lfs_emubd_fromle32(emu);
if (res < 1) { if (res < 1) {
err = -errno; return -errno;
LFS_TRACE("lfs_emubd_sync -> %d", err);
fclose(f);
return err;
} }
err = fclose(f); err = fclose(f);
if (err) { if (err) {
err = -errno; return -errno;
LFS_TRACE("lfs_emubd_sync -> %d", err);
return err;
} }
LFS_TRACE("lfs_emubd_sync -> %d", 0);
return 0; return 0;
} }

View File

@@ -17,8 +17,20 @@ extern "C"
// Config options // Config options
#ifndef LFS_EMUBD_ERASE_VALUE #ifndef LFS_EMUBD_READ_SIZE
#define LFS_EMUBD_ERASE_VALUE 0x00 #define LFS_EMUBD_READ_SIZE 1
#endif
#ifndef LFS_EMUBD_PROG_SIZE
#define LFS_EMUBD_PROG_SIZE 1
#endif
#ifndef LFS_EMUBD_ERASE_SIZE
#define LFS_EMUBD_ERASE_SIZE 512
#endif
#ifndef LFS_EMUBD_TOTAL_SIZE
#define LFS_EMUBD_TOTAL_SIZE 524288
#endif #endif

4673
lfs.c

File diff suppressed because it is too large Load Diff

302
lfs.h
View File

@@ -21,7 +21,7 @@ extern "C"
// Software library version // Software library version
// Major (top-nibble), incremented on backwards incompatible changes // Major (top-nibble), incremented on backwards incompatible changes
// Minor (bottom-nibble), incremented on feature additions // Minor (bottom-nibble), incremented on feature additions
#define LFS_VERSION 0x00020001 #define LFS_VERSION 0x00020000
#define LFS_VERSION_MAJOR (0xffff & (LFS_VERSION >> 16)) #define LFS_VERSION_MAJOR (0xffff & (LFS_VERSION >> 16))
#define LFS_VERSION_MINOR (0xffff & (LFS_VERSION >> 0)) #define LFS_VERSION_MINOR (0xffff & (LFS_VERSION >> 0))
@@ -44,26 +44,27 @@ typedef int32_t lfs_soff_t;
typedef uint32_t lfs_block_t; typedef uint32_t lfs_block_t;
// Maximum name size in bytes, may be redefined to reduce the size of the // Maximum size of all attributes per file in bytes, may be redefined but a
// info struct. Limited to <= 1022. Stored in superblock and must be // a smaller LFS_ATTR_MAX has no benefit. Stored in 12-bits and limited
// respected by other littlefs drivers. // to <= 0xfff. Stored in superblock and must be respected by other
#ifndef LFS_NAME_MAX // littlefs drivers.
#define LFS_NAME_MAX 255
#endif
// Maximum size of a file in bytes, may be redefined to limit to support other
// drivers. Limited on disk to <= 4294967296. However, above 2147483647 the
// functions lfs_file_seek, lfs_file_size, and lfs_file_tell will return
// incorrect values due to using signed integers. Stored in superblock and
// must be respected by other littlefs drivers.
#ifndef LFS_FILE_MAX
#define LFS_FILE_MAX 2147483647
#endif
// 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.
#ifndef LFS_ATTR_MAX #ifndef LFS_ATTR_MAX
#define LFS_ATTR_MAX 1022 #define LFS_ATTR_MAX 0xfff
#endif
// Maximum name size in bytes, may be redefined to reduce the size of the
// info struct. Limited to <= LFS_ATTR_MAX. Stored in superblock and must
// be respected by other littlefs drivers.
#ifndef LFS_NAME_MAX
#define LFS_NAME_MAX 0xff
#endif
// Maximum inline file size in bytes. Large inline files require a larger
// cache size, but if a file can be inline it does not need its own data
// block. Limited to <= LFS_ATTR_MAX and <= cache_size. Stored in superblock
// and must be respected by other littlefs drivers.
#ifndef LFS_INLINE_MAX
#define LFS_INLINE_MAX 0xfff
#endif #endif
// Possible error codes, these are negative to allow // Possible error codes, these are negative to allow
@@ -78,11 +79,9 @@ enum lfs_error {
LFS_ERR_ISDIR = -21, // Entry is a dir LFS_ERR_ISDIR = -21, // Entry is a dir
LFS_ERR_NOTEMPTY = -39, // Dir is not empty LFS_ERR_NOTEMPTY = -39, // Dir is not empty
LFS_ERR_BADF = -9, // Bad file number LFS_ERR_BADF = -9, // Bad file number
LFS_ERR_FBIG = -27, // File too large
LFS_ERR_INVAL = -22, // Invalid parameter LFS_ERR_INVAL = -22, // Invalid parameter
LFS_ERR_NOSPC = -28, // No space left on device LFS_ERR_NOSPC = -28, // No space left on device
LFS_ERR_NOMEM = -12, // No more memory available LFS_ERR_NOMEM = -12, // No more memory available
LFS_ERR_NOATTR = -61, // No data/attr available
LFS_ERR_NAMETOOLONG = -36, // File name too long LFS_ERR_NAMETOOLONG = -36, // File name too long
}; };
@@ -93,30 +92,28 @@ enum lfs_type {
LFS_TYPE_DIR = 0x002, LFS_TYPE_DIR = 0x002,
// internally used types // internally used types
LFS_TYPE_SPLICE = 0x400, LFS_TYPE_USER = 0x100,
LFS_TYPE_SUPERBLOCK = 0x011,
LFS_TYPE_ROOT = 0x012,
LFS_TYPE_NAME = 0x000, LFS_TYPE_NAME = 0x000,
LFS_TYPE_STRUCT = 0x200, LFS_TYPE_DELETE = 0x030,
LFS_TYPE_USERATTR = 0x300, LFS_TYPE_STRUCT = 0x040,
LFS_TYPE_FROM = 0x100, LFS_TYPE_GLOBALS = 0x080,
LFS_TYPE_TAIL = 0x600, LFS_TYPE_TAIL = 0x0c0,
LFS_TYPE_GLOBALS = 0x700, LFS_TYPE_SOFTTAIL = 0x0c0,
LFS_TYPE_CRC = 0x500, LFS_TYPE_HARDTAIL = 0x0c1,
LFS_TYPE_CRC = 0x0f0,
// internally used type specializations LFS_TYPE_DIRSTRUCT = 0x040,
LFS_TYPE_CREATE = 0x401, LFS_TYPE_INLINESTRUCT = 0x041,
LFS_TYPE_DELETE = 0x4ff, LFS_TYPE_CTZSTRUCT = 0x042,
LFS_TYPE_SUPERBLOCK = 0x0ff,
LFS_TYPE_DIRSTRUCT = 0x200,
LFS_TYPE_CTZSTRUCT = 0x202,
LFS_TYPE_INLINESTRUCT = 0x201,
LFS_TYPE_SOFTTAIL = 0x600,
LFS_TYPE_HARDTAIL = 0x601,
LFS_TYPE_MOVESTATE = 0x7ff,
// internal chip sources // internal chip sources
LFS_FROM_NOOP = 0x000, LFS_FROM_REGION = 0x000,
LFS_FROM_MOVE = 0x101, LFS_FROM_DISK = 0x200,
LFS_FROM_USERATTRS = 0x102, LFS_FROM_MOVE = 0x050,
LFS_FROM_ATTRS = 0x060,
LFS_FROM_SUPERBLOCK = 0x070,
}; };
// File open flags // File open flags
@@ -136,7 +133,6 @@ enum lfs_open_flags {
LFS_F_READING = 0x040000, // File has been read since last flush LFS_F_READING = 0x040000, // File has been read since last flush
LFS_F_ERRED = 0x080000, // An error occured during write LFS_F_ERRED = 0x080000, // An error occured during write
LFS_F_INLINE = 0x100000, // Currently inlined in directory entry LFS_F_INLINE = 0x100000, // Currently inlined in directory entry
LFS_F_OPENED = 0x200000, // File has been opened
}; };
// File seek flags // File seek flags
@@ -183,63 +179,59 @@ struct lfs_config {
lfs_size_t prog_size; lfs_size_t prog_size;
// Size of an erasable block. This does not impact ram consumption and // Size of an erasable block. This does not impact ram consumption and
// may be larger than the physical erase size. However, non-inlined files // may be larger than the physical erase size. However, this should be
// take up at minimum one block. Must be a multiple of the read // kept small as each file currently takes up an entire block.
// and program sizes. // Must be a multiple of the read, program, and cache sizes.
lfs_size_t block_size; lfs_size_t block_size;
// Number of erasable blocks on the device. // Number of erasable blocks on the device.
lfs_size_t block_count; lfs_size_t block_count;
// Number of erase cycles before littlefs evicts metadata logs and moves // Number of erase cycles before we should move data to another block.
// the metadata to another block. Suggested values are in the // May be zero to never move data, in which case no block-level
// range 100-1000, with large values having better performance at the cost // wear-leveling is performed.
// of less consistent wear distribution. uint32_t block_cycles;
//
// Set to -1 to disable block-level wear-leveling.
int32_t block_cycles;
// Size of block caches. Each cache buffers a portion of a block in RAM. // Size of block caches. Each cache buffers a portion of a block in RAM.
// The littlefs needs a read cache, a program cache, and one additional // This determines the size of the read cache, the program cache, and a
// 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 // data. Must be a multiple of the read and program sizes.
// the read and program sizes, and a factor of the block size.
lfs_size_t cache_size; lfs_size_t cache_size;
// Size of the lookahead buffer in bytes. A larger lookahead buffer // Number of blocks to lookahead during block allocation. A larger
// increases the number of blocks found during an allocation pass. The // lookahead reduces the number of passes required to allocate a block.
// lookahead buffer is stored as a compact bitmap, so each byte of RAM // The lookahead buffer requires only 1 bit per block so it can be quite
// can track 8 blocks. Must be a multiple of 8. // large with little ram impact. Should be a multiple of 32.
lfs_size_t lookahead_size; lfs_size_t lookahead;
// Optional statically allocated read buffer. Must be cache_size. // Optional, statically allocated read buffer. Must be read sized.
// By default lfs_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 program sized.
// By default lfs_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 1 bit per
// and aligned to a 32-bit boundary. By default lfs_malloc is used to // lookahead block.
// allocate this buffer.
void *lookahead_buffer; void *lookahead_buffer;
// Optional upper limit on file attributes in bytes. No downside for larger
// attributes size but must be less than LFS_ATTR_MAX. Defaults to
// LFS_ATTR_MAX when zero.Stored in superblock and must be respected by
// other littlefs drivers.
lfs_size_t attr_max;
// Optional upper limit on length of file names in bytes. No downside for // Optional upper limit on length of file names in bytes. No downside for
// larger names except the size of the info struct which is controlled by // larger names except the size of the info struct which is controlled by
// the LFS_NAME_MAX define. Defaults to LFS_NAME_MAX when zero. Stored in // the LFS_NAME_MAX define. Defaults to LFS_NAME_MAX when zero. Stored in
// superblock and must be respected by other littlefs drivers. // superblock and must be respected by other littlefs drivers.
lfs_size_t name_max; lfs_size_t name_max;
// Optional upper limit on files in bytes. No downside for larger files // Optional upper limit on inlined files in bytes. Large inline files
// but must be <= LFS_FILE_MAX. Defaults to LFS_FILE_MAX when zero. Stored // require a larger cache size, but if a file can be inlined it does not
// in superblock and must be respected by other littlefs drivers. // need its own data block. Must be smaller than cache_size and less than
lfs_size_t file_max; // LFS_INLINE_MAX. Defaults to min(LFS_INLINE_MAX, read_size) when zero.
// Stored in superblock and must be respected by other littlefs drivers.
// Optional upper limit on custom attributes in bytes. No downside for lfs_size_t inline_max;
// larger attributes size but must be <= LFS_ATTR_MAX. Defaults to
// LFS_ATTR_MAX when zero.
lfs_size_t attr_max;
}; };
// File info structure // File info structure
@@ -247,18 +239,14 @@ struct lfs_info {
// Type of the file, either LFS_TYPE_REG or LFS_TYPE_DIR // Type of the file, either LFS_TYPE_REG or LFS_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
lfs_size_t size; lfs_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
// LFS_NAME_MAX+1, which can be changed by redefining LFS_NAME_MAX to
// reduce RAM. LFS_NAME_MAX is stored in superblock and must be
// respected by other littlefs drivers.
char name[LFS_NAME_MAX+1]; char name[LFS_NAME_MAX+1];
}; };
// Custom attribute structure, used to describe custom attributes // Custom attribute structure
// committed atomically during file writes.
struct lfs_attr { struct lfs_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
@@ -269,16 +257,19 @@ struct lfs_attr {
// Size of attribute in bytes, limited to LFS_ATTR_MAX // Size of attribute in bytes, limited to LFS_ATTR_MAX
lfs_size_t size; lfs_size_t size;
// Pointer to next attribute in linked list
struct lfs_attr *next;
}; };
// Optional configuration provided during lfs_file_opencfg // Optional configuration provided during lfs_file_opencfg
struct lfs_file_config { struct lfs_file_config {
// Optional statically allocated file buffer. Must be cache_size. // Optional, statically allocated buffer for files. Must be program sized.
// By default lfs_malloc is used to allocate this buffer. // If NULL, malloc will be used by default.
void *buffer; void *buffer;
// Optional list of custom attributes related to the file. If the file // Optional, linked list of custom attributes related to the file. If the
// is opened with read access, these attributes will be read from disk // file is opened with read access, the attributes will be read from
// during the open call. If the file is opened with write access, the // during the open call. If the file is opened with write access, the
// attributes will be written to disk every file sync or close. This // attributes will be written to disk every file sync or close. This
// write occurs atomically with update to the file's contents. // write occurs atomically with update to the file's contents.
@@ -289,13 +280,16 @@ struct lfs_file_config {
// 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 lfs_attr *attrs;
// Number of custom attributes in the list
lfs_size_t attr_count;
}; };
/// internal littlefs data structures /// /// littlefs data structures ///
typedef struct lfs_mattr {
int32_t tag;
const void *buffer;
const struct lfs_mattr *next;
} lfs_mattr_t;
typedef struct lfs_cache { typedef struct lfs_cache {
lfs_block_t block; lfs_block_t block;
lfs_off_t off; lfs_off_t off;
@@ -303,18 +297,34 @@ typedef struct lfs_cache {
uint8_t *buffer; uint8_t *buffer;
} lfs_cache_t; } lfs_cache_t;
typedef union lfs_global {
uint32_t u32[3];
struct {
lfs_block_t movepair[2];
uint16_t moveid;
bool deorphaned;
} s;
} lfs_global_t;
typedef struct lfs_mdir { typedef struct lfs_mdir {
lfs_block_t pair[2]; lfs_block_t pair[2];
uint32_t rev; uint32_t rev;
lfs_off_t off;
uint32_t etag; uint32_t etag;
lfs_off_t off;
uint16_t count; uint16_t count;
bool erased; bool erased;
bool split; bool split;
lfs_block_t tail[2]; lfs_block_t tail[2];
lfs_global_t locals;
} lfs_mdir_t; } lfs_mdir_t;
// littlefs directory type typedef struct lfs_mlist {
struct lfs_mlist *next;
uint16_t id;
uint8_t type;
lfs_mdir_t m;
} lfs_mlist_t;
typedef struct lfs_dir { typedef struct lfs_dir {
struct lfs_dir *next; struct lfs_dir *next;
uint16_t id; uint16_t id;
@@ -325,7 +335,6 @@ typedef struct lfs_dir {
lfs_block_t head[2]; lfs_block_t head[2];
} lfs_dir_t; } lfs_dir_t;
// littlefs file type
typedef struct lfs_file { typedef struct lfs_file {
struct lfs_file *next; struct lfs_file *next;
uint16_t id; uint16_t id;
@@ -347,49 +356,44 @@ typedef struct lfs_file {
} lfs_file_t; } lfs_file_t;
typedef struct lfs_superblock { typedef struct lfs_superblock {
char magic[8];
uint32_t version; uint32_t version;
lfs_size_t block_size; lfs_size_t block_size;
lfs_size_t block_count; lfs_size_t block_count;
lfs_size_t name_max;
lfs_size_t file_max;
lfs_size_t attr_max; lfs_size_t attr_max;
lfs_size_t name_max;
lfs_size_t inline_max;
} lfs_superblock_t; } lfs_superblock_t;
// The littlefs filesystem type typedef struct lfs_free {
lfs_block_t off;
lfs_block_t size;
lfs_block_t i;
lfs_block_t ack;
uint32_t *buffer;
} lfs_free_t;
// The littlefs type
typedef struct lfs { typedef struct lfs {
lfs_cache_t rcache; lfs_cache_t rcache;
lfs_cache_t pcache; lfs_cache_t pcache;
lfs_block_t root[2]; lfs_block_t root[2];
struct lfs_mlist { lfs_mlist_t *mlist;
struct lfs_mlist *next;
uint16_t id;
uint8_t type;
lfs_mdir_t m;
} *mlist;
uint32_t seed; uint32_t seed;
struct lfs_gstate { lfs_global_t globals;
uint32_t tag; lfs_global_t locals;
lfs_block_t pair[2]; lfs_free_t free;
} gstate, gpending, gdelta;
struct lfs_free {
lfs_block_t off;
lfs_block_t size;
lfs_block_t i;
lfs_block_t ack;
uint32_t *buffer;
} free;
const struct lfs_config *cfg; const struct lfs_config *cfg;
lfs_size_t name_max; lfs_size_t block_size;
lfs_size_t file_max; lfs_size_t block_count;
lfs_size_t attr_max; lfs_size_t attr_max;
lfs_size_t name_max;
#ifdef LFS_MIGRATE lfs_size_t inline_max;
struct lfs1 *lfs1;
#endif
} lfs_t; } lfs_t;
@@ -447,8 +451,7 @@ int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info);
// 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 LFS_ATTR_MAX bytes. When read, if the stored attribute is smaller than
// the buffer, it will be padded with zeros. If the stored attribute is larger, // 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.
// LFS_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
@@ -461,19 +464,13 @@ lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path,
// //
// 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 LFS_ATTR_MAX bytes. If an attribute is not found, it will be
// implicitly created. // implicitly created, and setting the size of an attribute to zero deletes
// the attribute.
// //
// Returns a negative error code on failure. // Returns a negative error code on failure.
int lfs_setattr(lfs_t *lfs, const char *path, int lfs_setattr(lfs_t *lfs, const char *path,
uint8_t type, const void *buffer, lfs_size_t size); uint8_t type, const void *buffer, lfs_size_t size);
// Removes a custom attribute
//
// If an attribute is not found, nothing happens.
//
// Returns a negative error code on failure.
int lfs_removeattr(lfs_t *lfs, const char *path, uint8_t type);
/// File operations /// /// File operations ///
@@ -533,7 +530,7 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file,
// 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 old position of the file, or a negative error code on failure.
lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file, lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file,
lfs_soff_t off, int whence); lfs_soff_t off, int whence);
@@ -550,7 +547,7 @@ lfs_soff_t lfs_file_tell(lfs_t *lfs, lfs_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 lfs_file_seek(lfs, file, 0, LFS_SEEK_CUR)
// 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 lfs_file_rewind(lfs_t *lfs, lfs_file_t *file);
@@ -583,8 +580,7 @@ int lfs_dir_close(lfs_t *lfs, lfs_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 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 lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info);
// Change the position of the directory // Change the position of the directory
@@ -628,20 +624,34 @@ lfs_ssize_t lfs_fs_size(lfs_t *lfs);
// Returns a negative error code on failure. // Returns a negative error code on failure.
int lfs_fs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data); int lfs_fs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data);
#ifdef LFS_MIGRATE // Get custom attributes on the filesystem
// Attempts to migrate a previous version of littlefs
// //
// Behaves similarly to the lfs_format function. Attempts to mount // Custom attributes are uniquely identified by an 8-bit type and limited
// the previous version of littlefs and update the filesystem so it can be // to LFS_ATTR_MAX bytes. When read, if the stored attribute is smaller than
// mounted with the current version of littlefs. // the buffer, it will be padded with zeros. If the stored attribute is larger,
// then it will be silently truncated.
// //
// Requires a littlefs object and config struct. This clobbers the littlefs // Note, filesystem-level attributes are not available for wear-leveling
// object, and does not leave the filesystem mounted. The config struct must //
// be zeroed for defaults and backwards compatibility. // 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
// of the size of the buffer. This can be used to dynamically allocate a buffer
// or check for existance.
lfs_ssize_t lfs_fs_getattr(lfs_t *lfs,
uint8_t type, void *buffer, lfs_size_t size);
// Set custom attributes on the filesystem
//
// 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
// implicitly created, and setting the size of an attribute to zero deletes
// the attribute.
//
// Note, filesystem-level attributes are not available for wear-leveling
// //
// Returns a negative error code on failure. // Returns a negative error code on failure.
int lfs_migrate(lfs_t *lfs, const struct lfs_config *cfg); int lfs_fs_setattr(lfs_t *lfs,
#endif uint8_t type, const void *buffer, lfs_size_t size);
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -11,7 +11,7 @@
// 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 lfs_crc32(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

@@ -31,10 +31,7 @@
#ifndef LFS_NO_ASSERT #ifndef LFS_NO_ASSERT
#include <assert.h> #include <assert.h>
#endif #endif
#if !defined(LFS_NO_DEBUG) || \ #if !defined(LFS_NO_DEBUG) || !defined(LFS_NO_WARN) || !defined(LFS_NO_ERROR)
!defined(LFS_NO_WARN) || \
!defined(LFS_NO_ERROR) || \
defined(LFS_YES_TRACE)
#include <stdio.h> #include <stdio.h>
#endif #endif
@@ -49,30 +46,23 @@ extern "C"
// code footprint // code footprint
// Logging functions // Logging functions
#ifdef LFS_YES_TRACE
#define LFS_TRACE(fmt, ...) \
printf("lfs_trace:%d: " fmt "\n", __LINE__, __VA_ARGS__)
#else
#define LFS_TRACE(fmt, ...)
#endif
#ifndef LFS_NO_DEBUG #ifndef LFS_NO_DEBUG
#define LFS_DEBUG(fmt, ...) \ #define LFS_DEBUG(fmt, ...) \
printf("lfs_debug:%d: " fmt "\n", __LINE__, __VA_ARGS__) printf("lfs debug:%d: " fmt "\n", __LINE__, __VA_ARGS__)
#else #else
#define LFS_DEBUG(fmt, ...) #define LFS_DEBUG(fmt, ...)
#endif #endif
#ifndef LFS_NO_WARN #ifndef LFS_NO_WARN
#define LFS_WARN(fmt, ...) \ #define LFS_WARN(fmt, ...) \
printf("lfs_warn:%d: " fmt "\n", __LINE__, __VA_ARGS__) printf("lfs warn:%d: " fmt "\n", __LINE__, __VA_ARGS__)
#else #else
#define LFS_WARN(fmt, ...) #define LFS_WARN(fmt, ...)
#endif #endif
#ifndef LFS_NO_ERROR #ifndef LFS_NO_ERROR
#define LFS_ERROR(fmt, ...) \ #define LFS_ERROR(fmt, ...) \
printf("lfs_error:%d: " fmt "\n", __LINE__, __VA_ARGS__) printf("lfs error:%d: " fmt "\n", __LINE__, __VA_ARGS__)
#else #else
#define LFS_ERROR(fmt, ...) #define LFS_ERROR(fmt, ...)
#endif #endif
@@ -153,14 +143,14 @@ static inline int lfs_scmp(uint32_t a, uint32_t 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 lfs_fromle32(uint32_t a) {
#if !defined(LFS_NO_INTRINSICS) && ( \ #if !defined(LFS_NO_INTRINSICS) && ( \
(defined( BYTE_ORDER ) && defined( ORDER_LITTLE_ENDIAN ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \ (defined( BYTE_ORDER ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \
(defined(__BYTE_ORDER ) && defined(__ORDER_LITTLE_ENDIAN ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \ (defined(__BYTE_ORDER ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \
(defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
return a; return a;
#elif !defined(LFS_NO_INTRINSICS) && ( \ #elif !defined(LFS_NO_INTRINSICS) && ( \
(defined( BYTE_ORDER ) && defined( ORDER_BIG_ENDIAN ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \ (defined( BYTE_ORDER ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \
(defined(__BYTE_ORDER ) && defined(__ORDER_BIG_ENDIAN ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \ (defined(__BYTE_ORDER ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \
(defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
return __builtin_bswap32(a); return __builtin_bswap32(a);
#else #else
return (((uint8_t*)&a)[0] << 0) | return (((uint8_t*)&a)[0] << 0) |
@@ -174,35 +164,32 @@ static inline uint32_t lfs_tole32(uint32_t a) {
return lfs_fromle32(a); return lfs_fromle32(a);
} }
// Convert between 32-bit big-endian and native order // Convert between 16-bit little-endian and native order
static inline uint32_t lfs_frombe32(uint32_t a) { static inline uint16_t lfs_fromle16(uint16_t a) {
#if !defined(LFS_NO_INTRINSICS) && ( \ #if !defined(LFS_NO_INTRINSICS) && ( \
(defined( BYTE_ORDER ) && defined( ORDER_LITTLE_ENDIAN ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \ (defined( BYTE_ORDER ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \
(defined(__BYTE_ORDER ) && defined(__ORDER_LITTLE_ENDIAN ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \ (defined(__BYTE_ORDER ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \
(defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
return __builtin_bswap32(a);
#elif !defined(LFS_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__))
return a; return a;
#elif !defined(LFS_NO_INTRINSICS) && ( \
(defined( BYTE_ORDER ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \
(defined(__BYTE_ORDER ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \
(defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
return __builtin_bswap16(a);
#else #else
return (((uint8_t*)&a)[0] << 24) | return (((uint8_t*)&a)[0] << 0) |
(((uint8_t*)&a)[1] << 16) | (((uint8_t*)&a)[1] << 8);
(((uint8_t*)&a)[2] << 8) |
(((uint8_t*)&a)[3] << 0);
#endif #endif
} }
static inline uint32_t lfs_tobe32(uint32_t a) { static inline uint16_t lfs_tole16(uint16_t a) {
return lfs_frombe32(a); return lfs_fromle16(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 lfs_crc32(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
static inline void *lfs_malloc(size_t size) { static inline void *lfs_malloc(size_t size) {
#ifndef LFS_NO_MALLOC #ifndef LFS_NO_MALLOC
return malloc(size); return malloc(size);

View File

@@ -1,112 +0,0 @@
#!/usr/bin/env python2
import struct
import binascii
TYPES = {
(0x700, 0x400): 'splice',
(0x7ff, 0x401): 'create',
(0x7ff, 0x4ff): 'delete',
(0x700, 0x000): 'name',
(0x7ff, 0x001): 'name reg',
(0x7ff, 0x002): 'name dir',
(0x7ff, 0x0ff): 'name superblock',
(0x700, 0x200): 'struct',
(0x7ff, 0x200): 'struct dir',
(0x7ff, 0x202): 'struct ctz',
(0x7ff, 0x201): 'struct inline',
(0x700, 0x300): 'userattr',
(0x700, 0x600): 'tail',
(0x7ff, 0x600): 'tail soft',
(0x7ff, 0x601): 'tail hard',
(0x700, 0x700): 'gstate',
(0x7ff, 0x7ff): 'gstate move',
(0x700, 0x500): 'crc',
}
def typeof(type):
for prefix in range(12):
mask = 0x7ff & ~((1 << prefix)-1)
if (mask, type & mask) in TYPES:
return TYPES[mask, type & mask] + (
' %0*x' % (prefix/4, type & ((1 << prefix)-1))
if prefix else '')
else:
return '%02x' % type
def main(*blocks):
# find most recent block
file = None
rev = None
crc = None
versions = []
for block in blocks:
try:
nfile = open(block, 'rb')
ndata = nfile.read(4)
ncrc = binascii.crc32(ndata)
nrev, = struct.unpack('<I', ndata)
assert rev != nrev
if not file or ((rev - nrev) & 0x80000000):
file = nfile
rev = nrev
crc = ncrc
versions.append((nrev, '%s (rev %d)' % (block, nrev)))
except (IOError, struct.error):
pass
if not file:
print 'Bad metadata pair {%s}' % ', '.join(blocks)
return 1
print "--- %s ---" % ', '.join(v for _,v in sorted(versions, reverse=True))
# go through each tag, print useful information
print "%-4s %-8s %-14s %3s %4s %s" % (
'off', 'tag', 'type', 'id', 'len', 'dump')
tag = 0xffffffff
off = 4
while True:
try:
data = file.read(4)
crc = binascii.crc32(data, crc)
ntag, = struct.unpack('>I', data)
except struct.error:
break
tag ^= ntag
off += 4
type = (tag & 0x7ff00000) >> 20
id = (tag & 0x000ffc00) >> 10
size = (tag & 0x000003ff) >> 0
iscrc = (type & 0x700) == 0x500
data = file.read(size if size != 0x3ff else 0)
if iscrc:
crc = binascii.crc32(data[:4], crc)
else:
crc = binascii.crc32(data, crc)
print '%04x: %08x %-15s %3s %4s %-23s %-8s' % (
off, tag,
typeof(type) + (' bad!' if iscrc and ~crc else ''),
hex(id)[2:] if id != 0x3ff else '.',
size if size != 0x3ff else 'x',
' '.join('%02x' % ord(c) for c in data[:8]),
''.join(c if c >= ' ' and c <= '~' else '.' for c in data[:8]))
off += size if size != 0x3ff else 0
if iscrc:
crc = 0
tag ^= (type & 1) << 31
return 0
if __name__ == "__main__":
import sys
sys.exit(main(*sys.argv[1:]))

View File

@@ -1,61 +0,0 @@
#!/usr/bin/env python2
# This script replaces prefixes of files, and symbols in that file.
# Useful for creating different versions of the codebase that don't
# conflict at compile time.
#
# example:
# $ ./scripts/prefix.py lfs2
import os
import os.path
import re
import glob
import itertools
import tempfile
import shutil
import subprocess
DEFAULT_PREFIX = "lfs"
def subn(from_prefix, to_prefix, name):
name, count1 = re.subn('\\b'+from_prefix, to_prefix, name)
name, count2 = re.subn('\\b'+from_prefix.upper(), to_prefix.upper(), name)
name, count3 = re.subn('\\B-D'+from_prefix.upper(),
'-D'+to_prefix.upper(), name)
return name, count1+count2+count3
def main(from_prefix, to_prefix=None, files=None):
if not to_prefix:
from_prefix, to_prefix = DEFAULT_PREFIX, from_prefix
if not files:
files = subprocess.check_output([
'git', 'ls-tree', '-r', '--name-only', 'HEAD']).split()
for oldname in files:
# Rename any matching file names
newname, namecount = subn(from_prefix, to_prefix, oldname)
if namecount:
subprocess.check_call(['git', 'mv', oldname, newname])
# Rename any prefixes in file
count = 0
with open(newname+'~', 'w') as tempf:
with open(newname) as newf:
for line in newf:
line, n = subn(from_prefix, to_prefix, line)
count += n
tempf.write(line)
shutil.copystat(newname, newname+'~')
os.rename(newname+'~', newname)
subprocess.check_call(['git', 'add', newname])
# Summary
print '%s: %d replacements' % (
'%s -> %s' % (oldname, newname) if namecount else oldname,
count)
if __name__ == "__main__":
import sys
sys.exit(main(*sys.argv[1:]))

View File

@@ -1,28 +0,0 @@
#!/usr/bin/env python2
import struct
import sys
import time
import os
import re
def main():
with open('blocks/.config') as file:
read_size, prog_size, block_size, block_count = (
struct.unpack('<LLLL', file.read()))
real_size = sum(
os.path.getsize(os.path.join('blocks', f))
for f in os.listdir('blocks') if re.match('\d+', f))
with open('blocks/.stats') as file:
read_count, prog_count, erase_count = (
struct.unpack('<QQQ', file.read()))
runtime = time.time() - os.stat('blocks').st_ctime
print 'results: %dB %dB %dB %.3fs' % (
read_count, prog_count, erase_count, runtime)
if __name__ == "__main__":
main(*sys.argv[1:])

View File

@@ -1,81 +0,0 @@
#!/usr/bin/env python2
import re
import sys
import subprocess
import os
def generate(test):
with open("scripts/template.fmt") as file:
template = file.read()
haslines = 'TEST_LINE' in os.environ and 'TEST_FILE' in os.environ
lines = []
for offset, line in enumerate(
re.split('(?<=(?:.;| [{}]))\n', test.read())):
match = re.match('((?: *\n)*)( *)(.*)=>(.*);',
line, re.DOTALL | re.MULTILINE)
if match:
preface, tab, test, expect = match.groups()
lines.extend(['']*preface.count('\n'))
lines.append(tab+'test_assert({test}, {expect});'.format(
test=test.strip(), expect=expect.strip()))
else:
lines.append(line)
# Create test file
with open('test.c', 'w') as file:
if 'TEST_LINE' in os.environ and 'TEST_FILE' in os.environ:
lines.insert(0, '#line %d "%s"' % (
int(os.environ['TEST_LINE']) + 1,
os.environ['TEST_FILE']))
lines.append('#line %d "test.c"' % (
template[:template.find('{tests}')].count('\n')
+ len(lines) + 2))
file.write(template.format(tests='\n'.join(lines)))
# Remove build artifacts to force rebuild
try:
os.remove('test.o')
os.remove('lfs')
except OSError:
pass
def compile():
subprocess.check_call([
os.environ.get('MAKE', 'make'),
'--no-print-directory', '-s'])
def execute():
if 'EXEC' in os.environ:
subprocess.check_call([os.environ['EXEC'], "./lfs"])
else:
subprocess.check_call(["./lfs"])
def main(test=None):
try:
if test and not test.startswith('-'):
with open(test) as file:
generate(file)
else:
generate(sys.stdin)
compile()
if test == '-s':
sys.exit(1)
execute()
except subprocess.CalledProcessError:
# Python stack trace is counterproductive, just exit
sys.exit(2)
except KeyboardInterrupt:
# Python stack trace is counterproductive, just exit
sys.exit(3)
if __name__ == "__main__":
main(*sys.argv[1:])

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python2 #!/usr/bin/env python
import struct import struct
import sys import sys
@@ -11,19 +11,18 @@ def corrupt(block):
file.read(4) file.read(4)
# go to last commit # go to last commit
tag = 0xffffffff tag = 0
while True: while True:
try: try:
ntag, = struct.unpack('>I', file.read(4)) ntag, = struct.unpack('<I', file.read(4))
except struct.error: except struct.error:
break break
tag ^= ntag tag ^= ntag
size = (tag & 0x3ff) if (tag & 0x3ff) != 0x3ff else 0 file.seek(tag & 0xfff, os.SEEK_CUR)
file.seek(size, os.SEEK_CUR)
# lob off last 3 bytes # lob off last 3 bytes
file.seek(-(size + 3), os.SEEK_CUR) file.seek(-((tag & 0xfff) + 3), os.SEEK_CUR)
file.truncate() file.truncate()
def main(args): def main(args):

98
tests/debug.py Executable file
View File

@@ -0,0 +1,98 @@
#!/usr/bin/env python2
import struct
import binascii
TYPES = {
(0x1ff, 0x001): 'reg',
(0x1ff, 0x002): 'dir',
(0x1ff, 0x011): 'superblock',
(0x1ff, 0x012): 'root',
(0x1ff, 0x030): 'delete',
(0x1f0, 0x080): 'globals',
(0x1ff, 0x0c0): 'tail soft',
(0x1ff, 0x0c1): 'tail hard',
(0x1ff, 0x0f0): 'crc',
(0x1ff, 0x040): 'struct dir',
(0x1ff, 0x041): 'struct inline',
(0x1ff, 0x042): 'struct ctz',
(0x100, 0x100): 'attr',
}
def typeof(type):
for prefix in range(9):
mask = 0x1ff & ~((1 << prefix)-1)
if (mask, type & mask) in TYPES:
return TYPES[mask, type & mask] + (
' [%0*x]' % (prefix/4, type & ((1 << prefix)-1))
if prefix else '')
else:
return '[%02x]' % type
def main(*blocks):
# find most recent block
file = None
rev = None
crc = None
versions = []
for block in blocks:
try:
nfile = open(block, 'rb')
ndata = nfile.read(4)
ncrc = binascii.crc32(ndata)
nrev, = struct.unpack('<I', ndata)
assert rev != nrev
if not file or ((rev - nrev) & 0x80000000):
file = nfile
rev = nrev
crc = ncrc
versions.append((nrev, '%s (rev %d)' % (block, nrev)))
except IOError:
pass
print "--- %s ---" % ', '.join(v for _,v in sorted(versions, reverse=True))
# go through each tag, print useful information
print "%-4s %-8s %-14s %3s %3s %s" % (
'off', 'tag', 'type', 'id', 'len', 'dump')
tag = 0
off = 4
while True:
try:
data = file.read(4)
crc = binascii.crc32(data, crc)
ntag, = struct.unpack('<I', data)
except struct.error:
break
tag ^= ntag
off += 4
type = (tag & 0x7fc00000) >> 22
id = (tag & 0x003ff000) >> 12
size = (tag & 0x00000fff) >> 0
data = file.read(size)
if type == 0x0f0:
crc = binascii.crc32(data[:4], crc)
else:
crc = binascii.crc32(data, crc)
print '%04x: %08x %-14s %3s %3d %-23s %-8s' % (
off, tag,
typeof(type) + (' bad!' if type == 0x0f0 and ~crc else ''),
id if id != 0x3ff else '.', size,
' '.join('%02x' % ord(c) for c in data[:8]),
''.join(c if c >= ' ' and c <= '~' else '.' for c in data[:8]))
off += tag & 0xfff
if type == 0x0f0:
crc = 0
if __name__ == "__main__":
import sys
main(*sys.argv[1:])

30
tests/stats.py Executable file
View File

@@ -0,0 +1,30 @@
#!/usr/bin/env python
import struct
import sys
import time
import os
import re
def main():
with open('blocks/.config') as file:
s = struct.unpack('<LLLL', file.read())
print 'read_size: %d' % s[0]
print 'prog_size: %d' % s[1]
print 'block_size: %d' % s[2]
print 'block_size: %d' % s[3]
print 'real_size: %d' % sum(
os.path.getsize(os.path.join('blocks', f))
for f in os.listdir('blocks') if re.match('\d+', f))
with open('blocks/.stats') as file:
s = struct.unpack('<QQQ', file.read())
print 'read_count: %d' % s[0]
print 'prog_count: %d' % s[1]
print 'erase_count: %d' % s[2]
print 'runtime: %.3f' % (time.time() - os.stat('blocks').st_ctime)
if __name__ == "__main__":
main(*sys.argv[1:])

View File

@@ -7,21 +7,34 @@
// test stuff // test stuff
static void test_log(const char *s, uintmax_t v) {{
printf("%s: %jd\n", s, v);
}}
static void test_assert(const char *file, unsigned line, static void test_assert(const char *file, unsigned line,
const char *s, uintmax_t v, uintmax_t e) {{ const char *s, uintmax_t v, uintmax_t e) {{
static const char *last[6] = {{0, 0}};
if (v != e || !(last[0] == s || last[1] == s ||
last[2] == s || last[3] == s ||
last[4] == s || last[5] == s)) {{
test_log(s, v);
last[0] = last[1];
last[1] = last[2];
last[2] = last[3];
last[3] = last[4];
last[4] = last[5];
last[5] = s;
}}
if (v != e) {{ if (v != e) {{
fprintf(stderr, "\033[97m%s:%u: \033[91m" fprintf(stderr, "\033[31m%s:%u: assert %s failed with %jd, "
"assert failed with %jd, expected %jd\033[0m\n" "expected %jd\033[0m\n", file, line, s, v, e);
" %s\n\n", file, line, v, e, s);
exit(-2); exit(-2);
}} }}
}} }}
#define test_assert(v, e) \ #define test_assert(s, v, e) test_assert(__FILE__, __LINE__, s, v, e)
test_assert(__FILE__, __LINE__, #v " => " #e, v, e)
// implicit variable for asserts
uintmax_t test;
// utility functions for traversals // utility functions for traversals
static int __attribute__((used)) test_count(void *p, lfs_block_t b) {{ static int __attribute__((used)) test_count(void *p, lfs_block_t b) {{
@@ -31,17 +44,23 @@ static int __attribute__((used)) test_count(void *p, lfs_block_t b) {{
return 0; return 0;
}} }}
// lfs declarations // lfs declarations
lfs_t lfs; lfs_t lfs;
lfs_emubd_t bd; lfs_emubd_t bd;
// other declarations for convenience lfs_file_t file[4];
lfs_file_t file; lfs_dir_t dir[4];
lfs_dir_t dir;
struct lfs_info info; struct lfs_info info;
uint8_t buffer[1024];
char path[1024];
// test configuration options uint8_t buffer[1024];
uint8_t wbuffer[1024];
uint8_t rbuffer[1024];
lfs_size_t size;
lfs_size_t wsize;
lfs_size_t rsize;
uintmax_t test;
#ifndef LFS_READ_SIZE #ifndef LFS_READ_SIZE
#define LFS_READ_SIZE 16 #define LFS_READ_SIZE 16
#endif #endif
@@ -63,11 +82,11 @@ char path[1024];
#endif #endif
#ifndef LFS_CACHE_SIZE #ifndef LFS_CACHE_SIZE
#define LFS_CACHE_SIZE (64 % LFS_PROG_SIZE == 0 ? 64 : LFS_PROG_SIZE) #define LFS_CACHE_SIZE 64
#endif #endif
#ifndef LFS_LOOKAHEAD_SIZE #ifndef LFS_LOOKAHEAD
#define LFS_LOOKAHEAD_SIZE 16 #define LFS_LOOKAHEAD 128
#endif #endif
const struct lfs_config cfg = {{ const struct lfs_config cfg = {{
@@ -77,13 +96,13 @@ const struct lfs_config cfg = {{
.erase = &lfs_emubd_erase, .erase = &lfs_emubd_erase,
.sync = &lfs_emubd_sync, .sync = &lfs_emubd_sync,
.read_size = LFS_READ_SIZE, .read_size = LFS_READ_SIZE,
.prog_size = LFS_PROG_SIZE, .prog_size = LFS_PROG_SIZE,
.block_size = LFS_BLOCK_SIZE, .block_size = LFS_BLOCK_SIZE,
.block_count = LFS_BLOCK_COUNT, .block_count = LFS_BLOCK_COUNT,
.block_cycles = LFS_BLOCK_CYCLES, .block_cycles = LFS_BLOCK_CYCLES,
.cache_size = LFS_CACHE_SIZE, .cache_size = LFS_CACHE_SIZE,
.lookahead_size = LFS_LOOKAHEAD_SIZE, .lookahead = LFS_LOOKAHEAD,
}}; }};
@@ -92,5 +111,6 @@ int main(void) {{
lfs_emubd_create(&cfg, "blocks"); lfs_emubd_create(&cfg, "blocks");
{tests} {tests}
lfs_emubd_destroy(&cfg); lfs_emubd_destroy(&cfg);
}} }}

61
tests/test.py Executable file
View File

@@ -0,0 +1,61 @@
#!/usr/bin/env python
import re
import sys
import subprocess
import os
def generate(test):
with open("tests/template.fmt") as file:
template = file.read()
lines = []
for line in re.split('(?<=(?:.;| [{}]))\n', test.read()):
match = re.match('(?: *\n)*( *)(.*)=>(.*);', line, re.DOTALL | re.MULTILINE)
if match:
tab, test, expect = match.groups()
lines.append(tab+'test = {test};'.format(test=test.strip()))
lines.append(tab+'test_assert("{name}", test, {expect});'.format(
name = re.match('\w*', test.strip()).group(),
expect = expect.strip()))
else:
lines.append(line)
# Create test file
with open('test.c', 'w') as file:
file.write(template.format(tests='\n'.join(lines)))
# Remove build artifacts to force rebuild
try:
os.remove('test.o')
os.remove('lfs')
except OSError:
pass
def compile():
subprocess.check_call([
os.environ.get('MAKE', 'make'),
'--no-print-directory', '-s'])
def execute():
if 'EXEC' in os.environ:
subprocess.check_call([os.environ['EXEC'], "./lfs"])
else:
subprocess.check_call(["./lfs"])
def main(test=None):
if test and not test.startswith('-'):
with open(test) as file:
generate(file)
else:
generate(sys.stdin)
compile()
if test == '-s':
sys.exit(1)
execute()
if __name__ == "__main__":
main(*sys.argv[1:])

View File

@@ -1,18 +1,16 @@
#!/bin/bash #!/bin/bash
set -euE set -eu
export TEST_FILE=$0
trap 'export TEST_LINE=$LINENO' DEBUG
echo "=== Allocator tests ===" echo "=== Allocator tests ==="
rm -rf blocks rm -rf blocks
scripts/test.py << TEST tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0; lfs_format(&lfs, &cfg) => 0;
TEST TEST
SIZE=15000 SIZE=15000
lfs_mkdir() { lfs_mkdir() {
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "$1") => 0; lfs_mkdir(&lfs, "$1") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
@@ -20,7 +18,7 @@ TEST
} }
lfs_remove() { lfs_remove() {
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_remove(&lfs, "$1/eggs") => 0; lfs_remove(&lfs, "$1/eggs") => 0;
lfs_remove(&lfs, "$1/bacon") => 0; lfs_remove(&lfs, "$1/bacon") => 0;
@@ -31,23 +29,22 @@ TEST
} }
lfs_alloc_singleproc() { lfs_alloc_singleproc() {
scripts/test.py << TEST tests/test.py << TEST
const char *names[] = {"bacon", "eggs", "pancakes"}; const char *names[] = {"bacon", "eggs", "pancakes"};
lfs_file_t files[sizeof(names)/sizeof(names[0])];
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
for (unsigned n = 0; n < sizeof(names)/sizeof(names[0]); n++) { for (int n = 0; n < sizeof(names)/sizeof(names[0]); n++) {
sprintf(path, "$1/%s", names[n]); sprintf((char*)buffer, "$1/%s", names[n]);
lfs_file_open(&lfs, &files[n], path, lfs_file_open(&lfs, &file[n], (char*)buffer,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
} }
for (unsigned n = 0; n < sizeof(names)/sizeof(names[0]); n++) { for (int n = 0; n < sizeof(names)/sizeof(names[0]); n++) {
lfs_size_t size = strlen(names[n]); size = strlen(names[n]);
for (int i = 0; i < $SIZE; i++) { for (int i = 0; i < $SIZE; i++) {
lfs_file_write(&lfs, &files[n], names[n], size) => size; lfs_file_write(&lfs, &file[n], names[n], size) => size;
} }
} }
for (unsigned n = 0; n < sizeof(names)/sizeof(names[0]); n++) { for (int n = 0; n < sizeof(names)/sizeof(names[0]); n++) {
lfs_file_close(&lfs, &files[n]) => 0; lfs_file_close(&lfs, &file[n]) => 0;
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
@@ -56,16 +53,16 @@ TEST
lfs_alloc_multiproc() { lfs_alloc_multiproc() {
for name in bacon eggs pancakes for name in bacon eggs pancakes
do do
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "$1/$name", lfs_file_open(&lfs, &file[0], "$1/$name",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
lfs_size_t size = strlen("$name"); size = strlen("$name");
memcpy(buffer, "$name", size); memcpy(buffer, "$name", size);
for (int i = 0; i < $SIZE; i++) { for (int i = 0; i < $SIZE; i++) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file[0], buffer, size) => size;
} }
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
done done
@@ -74,15 +71,15 @@ done
lfs_verify() { lfs_verify() {
for name in bacon eggs pancakes for name in bacon eggs pancakes
do do
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "$1/$name", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file[0], "$1/$name", LFS_O_RDONLY) => 0;
lfs_size_t size = strlen("$name"); size = strlen("$name");
for (int i = 0; i < $SIZE; i++) { for (int i = 0; i < $SIZE; i++) {
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "$name", size) => 0; memcmp(buffer, "$name", size) => 0;
} }
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
done done
@@ -118,19 +115,19 @@ lfs_remove multiprocreuse
lfs_remove singleprocreuse lfs_remove singleprocreuse
echo "--- Exhaustion test ---" echo "--- Exhaustion test ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
lfs_size_t size = strlen("exhaustion"); size = strlen("exhaustion");
memcpy(buffer, "exhaustion", size); memcpy(buffer, "exhaustion", size);
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file[0], buffer, size) => size;
lfs_file_sync(&lfs, &file) => 0; lfs_file_sync(&lfs, &file[0]) => 0;
size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
lfs_ssize_t res; lfs_ssize_t res;
while (true) { while (true) {
res = lfs_file_write(&lfs, &file, buffer, size); res = lfs_file_write(&lfs, &file[0], buffer, size);
if (res < 0) { if (res < 0) {
break; break;
} }
@@ -139,45 +136,45 @@ scripts/test.py << TEST
} }
res => LFS_ERR_NOSPC; res => LFS_ERR_NOSPC;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_RDONLY); lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_RDONLY);
lfs_size_t size = strlen("exhaustion"); size = strlen("exhaustion");
lfs_file_size(&lfs, &file) => size; lfs_file_size(&lfs, &file[0]) => size;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "exhaustion", size) => 0; memcmp(buffer, "exhaustion", size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Exhaustion wraparound test ---" echo "--- Exhaustion wraparound test ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_remove(&lfs, "exhaustion") => 0; lfs_remove(&lfs, "exhaustion") => 0;
lfs_file_open(&lfs, &file, "padding", LFS_O_WRONLY | LFS_O_CREAT); lfs_file_open(&lfs, &file[0], "padding", LFS_O_WRONLY | LFS_O_CREAT);
lfs_size_t size = strlen("buffering"); size = strlen("buffering");
memcpy(buffer, "buffering", size); memcpy(buffer, "buffering", size);
for (int i = 0; i < $SIZE; i++) { for (int i = 0; i < $SIZE; i++) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file[0], buffer, size) => size;
} }
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
lfs_remove(&lfs, "padding") => 0; lfs_remove(&lfs, "padding") => 0;
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
size = strlen("exhaustion"); size = strlen("exhaustion");
memcpy(buffer, "exhaustion", size); memcpy(buffer, "exhaustion", size);
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file[0], buffer, size) => size;
lfs_file_sync(&lfs, &file) => 0; lfs_file_sync(&lfs, &file[0]) => 0;
size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
lfs_ssize_t res; lfs_ssize_t res;
while (true) { while (true) {
res = lfs_file_write(&lfs, &file, buffer, size); res = lfs_file_write(&lfs, &file[0], buffer, size);
if (res < 0) { if (res < 0) {
break; break;
} }
@@ -186,34 +183,34 @@ scripts/test.py << TEST
} }
res => LFS_ERR_NOSPC; res => LFS_ERR_NOSPC;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_RDONLY); lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_RDONLY);
lfs_size_t size = strlen("exhaustion"); size = strlen("exhaustion");
lfs_file_size(&lfs, &file) => size; lfs_file_size(&lfs, &file[0]) => size;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "exhaustion", size) => 0; memcmp(buffer, "exhaustion", size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
lfs_remove(&lfs, "exhaustion") => 0; lfs_remove(&lfs, "exhaustion") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Dir exhaustion test ---" echo "--- Dir exhaustion test ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
// find out max file size // find out max file size
lfs_mkdir(&lfs, "exhaustiondir") => 0; lfs_mkdir(&lfs, "exhaustiondir") => 0;
lfs_size_t 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); lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
int count = 0; int count = 0;
int err; int err;
while (true) { while (true) {
err = lfs_file_write(&lfs, &file, buffer, size); err = lfs_file_write(&lfs, &file[0], buffer, size);
if (err < 0) { if (err < 0) {
break; break;
} }
@@ -221,28 +218,28 @@ scripts/test.py << TEST
count += 1; count += 1;
} }
err => LFS_ERR_NOSPC; err => LFS_ERR_NOSPC;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
lfs_remove(&lfs, "exhaustion") => 0; lfs_remove(&lfs, "exhaustion") => 0;
lfs_remove(&lfs, "exhaustiondir") => 0; lfs_remove(&lfs, "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); lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file[0], buffer, size) => size;
} }
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
lfs_mkdir(&lfs, "exhaustiondir") => 0; lfs_mkdir(&lfs, "exhaustiondir") => 0;
lfs_remove(&lfs, "exhaustiondir") => 0; lfs_remove(&lfs, "exhaustiondir") => 0;
lfs_remove(&lfs, "exhaustion") => 0; lfs_remove(&lfs, "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); lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_WRONLY | LFS_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; lfs_file_write(&lfs, &file[0], buffer, size) => size;
} }
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
lfs_mkdir(&lfs, "exhaustiondir") => LFS_ERR_NOSPC; lfs_mkdir(&lfs, "exhaustiondir") => LFS_ERR_NOSPC;
@@ -251,22 +248,22 @@ scripts/test.py << TEST
TEST TEST
echo "--- Chained dir exhaustion test ---" echo "--- Chained dir exhaustion test ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
// find out max file size // find out max file size
lfs_mkdir(&lfs, "exhaustiondir") => 0; lfs_mkdir(&lfs, "exhaustiondir") => 0;
for (int i = 0; i < 10; i++) { for (int i = 0; i < 9; i++) {
sprintf(path, "dirwithanexhaustivelylongnameforpadding%d", i); sprintf((char*)buffer, "dirwithanexhaustivelylongnameforpadding%d", i);
lfs_mkdir(&lfs, path) => 0; lfs_mkdir(&lfs, (char*)buffer) => 0;
} }
lfs_size_t 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); lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
int count = 0; int count = 0;
int err; int err;
while (true) { while (true) {
err = lfs_file_write(&lfs, &file, buffer, size); err = lfs_file_write(&lfs, &file[0], buffer, size);
if (err < 0) { if (err < 0) {
break; break;
} }
@@ -274,25 +271,25 @@ scripts/test.py << TEST
count += 1; count += 1;
} }
err => LFS_ERR_NOSPC; err => LFS_ERR_NOSPC;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
lfs_remove(&lfs, "exhaustion") => 0; lfs_remove(&lfs, "exhaustion") => 0;
lfs_remove(&lfs, "exhaustiondir") => 0; lfs_remove(&lfs, "exhaustiondir") => 0;
for (int i = 0; i < 10; i++) { for (int i = 0; i < 9; i++) {
sprintf(path, "dirwithanexhaustivelylongnameforpadding%d", i); sprintf((char*)buffer, "dirwithanexhaustivelylongnameforpadding%d", i);
lfs_remove(&lfs, path) => 0; lfs_remove(&lfs, (char*)buffer) => 0;
} }
// see that chained dir fails // see that chained dir fails
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_WRONLY | LFS_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; lfs_file_write(&lfs, &file[0], buffer, size) => size;
} }
lfs_file_sync(&lfs, &file) => 0; lfs_file_sync(&lfs, &file[0]) => 0;
for (int i = 0; i < 10; i++) { for (int i = 0; i < 9; i++) {
sprintf(path, "dirwithanexhaustivelylongnameforpadding%d", i); sprintf((char*)buffer, "dirwithanexhaustivelylongnameforpadding%d", i);
lfs_mkdir(&lfs, path) => 0; lfs_mkdir(&lfs, (char*)buffer) => 0;
} }
lfs_mkdir(&lfs, "exhaustiondir") => LFS_ERR_NOSPC; lfs_mkdir(&lfs, "exhaustiondir") => LFS_ERR_NOSPC;
@@ -304,181 +301,183 @@ scripts/test.py << TEST
break; break;
} }
lfs_ssize_t filesize = lfs_file_size(&lfs, &file); lfs_ssize_t filesize = lfs_file_size(&lfs, &file[0]);
filesize > 0 => true; filesize > 0 => true;
lfs_file_truncate(&lfs, &file, filesize - size) => 0; lfs_file_truncate(&lfs, &file[0], filesize - size) => 0;
lfs_file_sync(&lfs, &file) => 0; lfs_file_sync(&lfs, &file[0]) => 0;
} }
err => 0; err => 0;
lfs_mkdir(&lfs, "exhaustiondir2") => LFS_ERR_NOSPC; lfs_mkdir(&lfs, "exhaustiondir2") => LFS_ERR_NOSPC;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Split dir test ---" echo "--- Split dir test ---"
scripts/test.py << TEST rm -rf blocks
tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0; lfs_format(&lfs, &cfg) => 0;
TEST TEST
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
// create one block hole for half a directory // create one block hole for half a directory
lfs_file_open(&lfs, &file, "bump", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs_file_open(&lfs, &file[0], "bump", LFS_O_WRONLY | LFS_O_CREAT) => 0;
for (lfs_size_t i = 0; i < cfg.block_size; i += 2) { for (lfs_size_t i = 0; i < 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; lfs_file_write(&lfs, &file[0], buffer, cfg.block_size) => cfg.block_size;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
lfs_size_t size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0; for (lfs_size_t i = 0;
i < (cfg.block_count-4)*(cfg.block_size-8); i < (cfg.block_count-4)*(cfg.block_size-8);
i += size) { i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file[0], buffer, size) => size;
} }
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
// remount to force reset of lookahead
lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0;
// open hole // open hole
lfs_remove(&lfs, "bump") => 0; lfs_remove(&lfs, "bump") => 0;
lfs_mkdir(&lfs, "splitdir") => 0; lfs_mkdir(&lfs, "splitdir") => 0;
lfs_file_open(&lfs, &file, "splitdir/bump", lfs_file_open(&lfs, &file[0], "splitdir/bump",
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS_O_WRONLY | LFS_O_CREAT) => 0;
for (lfs_size_t i = 0; i < cfg.block_size; i += 2) { for (lfs_size_t i = 0; i < 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; lfs_file_write(&lfs, &file[0], buffer, cfg.block_size) => LFS_ERR_NOSPC;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Outdated lookahead test ---" echo "--- Outdated lookahead test ---"
scripts/test.py << TEST rm -rf blocks
tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0; lfs_format(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
// fill completely with two files // fill completely with two files
lfs_file_open(&lfs, &file, "exhaustion1", lfs_file_open(&lfs, &file[0], "exhaustion1",
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_size_t size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0; for (lfs_size_t i = 0;
i < ((cfg.block_count-2)/2)*(cfg.block_size-8); i < ((cfg.block_count-2)/2)*(cfg.block_size-8);
i += size) { i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file[0], buffer, size) => size;
} }
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
lfs_file_open(&lfs, &file, "exhaustion2", lfs_file_open(&lfs, &file[0], "exhaustion2",
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS_O_WRONLY | LFS_O_CREAT) => 0;
size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0; for (lfs_size_t i = 0;
i < ((cfg.block_count-2+1)/2)*(cfg.block_size-8); i < ((cfg.block_count-2+1)/2)*(cfg.block_size-8);
i += size) { i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file[0], buffer, size) => size;
} }
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
// remount to force reset of lookahead // remount to force reset of lookahead
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
// rewrite one file // rewrite one file
lfs_file_open(&lfs, &file, "exhaustion1", lfs_file_open(&lfs, &file[0], "exhaustion1",
LFS_O_WRONLY | LFS_O_TRUNC) => 0; LFS_O_WRONLY | LFS_O_TRUNC) => 0;
lfs_file_sync(&lfs, &file) => 0; lfs_file_sync(&lfs, &file[0]) => 0;
size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0; for (lfs_size_t i = 0;
i < ((cfg.block_count-2)/2)*(cfg.block_size-8); i < ((cfg.block_count-2)/2)*(cfg.block_size-8);
i += size) { i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file[0], buffer, size) => size;
} }
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 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", lfs_file_open(&lfs, &file[0], "exhaustion2",
LFS_O_WRONLY | LFS_O_TRUNC) => 0; LFS_O_WRONLY | LFS_O_TRUNC) => 0;
lfs_file_sync(&lfs, &file) => 0; lfs_file_sync(&lfs, &file[0]) => 0;
size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0; for (lfs_size_t i = 0;
i < ((cfg.block_count-2+1)/2)*(cfg.block_size-8); i < ((cfg.block_count-2+1)/2)*(cfg.block_size-8);
i += size) { i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file[0], buffer, size) => size;
} }
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
TEST TEST
echo "--- Outdated lookahead and split dir test ---" echo "--- Outdated lookahead and split dir test ---"
scripts/test.py << TEST rm -rf blocks
tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0; lfs_format(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
// fill completely with two files // fill completely with two files
lfs_file_open(&lfs, &file, "exhaustion1", lfs_file_open(&lfs, &file[0], "exhaustion1",
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_size_t size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0; for (lfs_size_t i = 0;
i < ((cfg.block_count-2)/2)*(cfg.block_size-8); i < ((cfg.block_count-2)/2)*(cfg.block_size-8);
i += size) { i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file[0], buffer, size) => size;
} }
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
lfs_file_open(&lfs, &file, "exhaustion2", lfs_file_open(&lfs, &file[0], "exhaustion2",
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS_O_WRONLY | LFS_O_CREAT) => 0;
size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0; for (lfs_size_t i = 0;
i < ((cfg.block_count-2+1)/2)*(cfg.block_size-8); i < ((cfg.block_count-2+1)/2)*(cfg.block_size-8);
i += size) { i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file[0], buffer, size) => size;
} }
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
// remount to force reset of lookahead // remount to force reset of lookahead
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
// rewrite one file with a hole of one block // rewrite one file with a hole of one block
lfs_file_open(&lfs, &file, "exhaustion1", lfs_file_open(&lfs, &file[0], "exhaustion1",
LFS_O_WRONLY | LFS_O_TRUNC) => 0; LFS_O_WRONLY | LFS_O_TRUNC) => 0;
lfs_file_sync(&lfs, &file) => 0; lfs_file_sync(&lfs, &file[0]) => 0;
size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0; for (lfs_size_t i = 0;
i < ((cfg.block_count-2)/2 - 1)*(cfg.block_size-8); i < ((cfg.block_count-2)/2 - 1)*(cfg.block_size-8);
i += size) { i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file[0], buffer, size) => size;
} }
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
// try to allocate a directory, should fail! // try to allocate a directory, should fail!
lfs_mkdir(&lfs, "split") => LFS_ERR_NOSPC; lfs_mkdir(&lfs, "split") => LFS_ERR_NOSPC;
// file should not fail // file should not fail
lfs_file_open(&lfs, &file, "notasplit", lfs_file_open(&lfs, &file[0], "notasplit",
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_write(&lfs, &file, "hi", 2) => 2; lfs_file_write(&lfs, &file[0], "hi", 2) => 2;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
scripts/results.py echo "--- Results ---"
tests/stats.py

View File

@@ -1,27 +1,24 @@
#!/bin/bash #!/bin/bash
set -eu set -eu
export TEST_FILE=$0
trap 'export TEST_LINE=$LINENO' DEBUG
echo "=== Attr tests ===" echo "=== Attr tests ==="
rm -rf blocks rm -rf blocks
scripts/test.py << TEST tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0; lfs_format(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "hello") => 0; lfs_mkdir(&lfs, "hello") => 0;
lfs_file_open(&lfs, &file, "hello/hello", lfs_file_open(&lfs, &file[0], "hello/hello",
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_write(&lfs, &file, "hello", strlen("hello")) lfs_file_write(&lfs, &file[0], "hello", strlen("hello"))
=> strlen("hello"); => strlen("hello");
lfs_file_close(&lfs, &file); lfs_file_close(&lfs, &file[0]);
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Set/get attribute ---" echo "--- Set/get attribute ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
memset(buffer, 0, sizeof(buffer));
lfs_setattr(&lfs, "hello", 'A', "aaaa", 4) => 0; lfs_setattr(&lfs, "hello", 'A', "aaaa", 4) => 0;
lfs_setattr(&lfs, "hello", 'B', "bbbbbb", 6) => 0; lfs_setattr(&lfs, "hello", 'B', "bbbbbb", 6) => 0;
lfs_setattr(&lfs, "hello", 'C', "ccccc", 5) => 0; lfs_setattr(&lfs, "hello", 'C', "ccccc", 5) => 0;
@@ -40,14 +37,6 @@ scripts/test.py << TEST
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;
lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => LFS_ERR_NOATTR;
lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5;
memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "\0\0\0\0\0\0", 6) => 0;
memcmp(buffer+10, "ccccc", 5) => 0;
lfs_setattr(&lfs, "hello", 'B', "dddddd", 6) => 0; lfs_setattr(&lfs, "hello", 'B', "dddddd", 6) => 0;
lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4; lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => 6; lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => 6;
@@ -72,9 +61,8 @@ scripts/test.py << TEST
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
memset(buffer, 0, sizeof(buffer));
lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4; lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "hello", 'B', buffer+4, 9) => 9; lfs_getattr(&lfs, "hello", 'B', buffer+4, 9) => 9;
lfs_getattr(&lfs, "hello", 'C', buffer+13, 5) => 5; lfs_getattr(&lfs, "hello", 'C', buffer+13, 5) => 5;
@@ -82,204 +70,183 @@ scripts/test.py << TEST
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; lfs_file_open(&lfs, &file[0], "hello/hello", LFS_O_RDONLY) => 0;
lfs_file_read(&lfs, &file, buffer, sizeof(buffer)) => strlen("hello"); lfs_file_read(&lfs, &file[0], buffer, sizeof(buffer)) => strlen("hello");
memcmp(buffer, "hello", strlen("hello")) => 0; memcmp(buffer, "hello", strlen("hello")) => 0;
lfs_file_close(&lfs, &file); lfs_file_close(&lfs, &file[0]);
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Set/get root attribute ---" echo "--- Set/get fs attribute ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
memset(buffer, 0, sizeof(buffer)); lfs_fs_setattr(&lfs, 'A', "aaaa", 4) => 0;
lfs_setattr(&lfs, "/", 'A', "aaaa", 4) => 0; lfs_fs_setattr(&lfs, 'B', "bbbbbb", 6) => 0;
lfs_setattr(&lfs, "/", 'B', "bbbbbb", 6) => 0; lfs_fs_setattr(&lfs, 'C', "ccccc", 5) => 0;
lfs_setattr(&lfs, "/", 'C', "ccccc", 5) => 0; lfs_fs_getattr(&lfs, 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4; lfs_fs_getattr(&lfs, 'B', buffer+4, 6) => 6;
lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 6; lfs_fs_getattr(&lfs, 'C', buffer+10, 5) => 5;
lfs_getattr(&lfs, "/", '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; lfs_fs_setattr(&lfs, 'B', "", 0) => 0;
lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4; lfs_fs_getattr(&lfs, 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 0; lfs_fs_getattr(&lfs, 'B', buffer+4, 6) => 0;
lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; lfs_fs_getattr(&lfs, '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; lfs_fs_setattr(&lfs, 'B', "dddddd", 6) => 0;
lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4; lfs_fs_getattr(&lfs, 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => LFS_ERR_NOATTR; lfs_fs_getattr(&lfs, 'B', buffer+4, 6) => 6;
lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; lfs_fs_getattr(&lfs, 'C', buffer+10, 5) => 5;
memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "\0\0\0\0\0\0", 6) => 0;
memcmp(buffer+10, "ccccc", 5) => 0;
lfs_setattr(&lfs, "/", 'B', "dddddd", 6) => 0;
lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 6;
lfs_getattr(&lfs, "/", '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; lfs_fs_setattr(&lfs, 'B', "eee", 3) => 0;
lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4; lfs_fs_getattr(&lfs, 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 3; lfs_fs_getattr(&lfs, 'B', buffer+4, 6) => 3;
lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; lfs_fs_getattr(&lfs, '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; lfs_fs_setattr(&lfs, 'A', buffer, LFS_ATTR_MAX+1) => LFS_ERR_NOSPC;
lfs_setattr(&lfs, "/", 'B', "fffffffff", 9) => 0; lfs_fs_setattr(&lfs, 'B', "fffffffff", 9) => 0;
lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4; lfs_fs_getattr(&lfs, 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 9; lfs_fs_getattr(&lfs, 'B', buffer+4, 6) => 9;
lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; lfs_fs_getattr(&lfs, 'C', buffer+10, 5) => 5;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
memset(buffer, 0, sizeof(buffer)); lfs_fs_getattr(&lfs, 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4; lfs_fs_getattr(&lfs, 'B', buffer+4, 9) => 9;
lfs_getattr(&lfs, "/", 'B', buffer+4, 9) => 9; lfs_fs_getattr(&lfs, 'C', buffer+13, 5) => 5;
lfs_getattr(&lfs, "/", '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; lfs_file_open(&lfs, &file[0], "hello/hello", LFS_O_RDONLY) => 0;
lfs_file_read(&lfs, &file, buffer, sizeof(buffer)) => strlen("hello"); lfs_file_read(&lfs, &file[0], buffer, sizeof(buffer)) => strlen("hello");
memcmp(buffer, "hello", strlen("hello")) => 0; memcmp(buffer, "hello", strlen("hello")) => 0;
lfs_file_close(&lfs, &file); lfs_file_close(&lfs, &file[0]);
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Set/get file attribute ---" echo "--- Set/get file attribute ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
memset(buffer, 0, sizeof(buffer)); struct lfs_attr a1 = {'A', buffer, 4};
struct lfs_attr attrs1[] = { struct lfs_attr b1 = {'B', buffer+4, 6, &a1};
{'A', buffer, 4}, struct lfs_attr c1 = {'C', buffer+10, 5, &b1};
{'B', buffer+4, 6}, struct lfs_file_config cfg1 = {.attrs = &c1};
{'C', buffer+10, 5},
};
struct lfs_file_config cfg1 = {.attrs=attrs1, .attr_count=3};
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0; lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_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; lfs_file_close(&lfs, &file[0]) => 0;
memset(buffer, 0, 15); memset(buffer, 0, 15);
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0; lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_RDONLY, &cfg1) => 0;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 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; b1.size = 0;
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0; lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_WRONLY, &cfg1) => 0;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
memset(buffer, 0, 15); memset(buffer, 0, 15);
attrs1[1].size = 6; b1.size = 6;
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0; lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_RDONLY, &cfg1) => 0;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 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; b1.size = 6;
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0; lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_WRONLY, &cfg1) => 0;
memcpy(buffer+4, "dddddd", 6); memcpy(buffer+4, "dddddd", 6);
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
memset(buffer, 0, 15); memset(buffer, 0, 15);
attrs1[1].size = 6; b1.size = 6;
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0; lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_RDONLY, &cfg1) => 0;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 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; b1.size = 3;
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0; lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_WRONLY, &cfg1) => 0;
memcpy(buffer+4, "eee", 3); memcpy(buffer+4, "eee", 3);
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
memset(buffer, 0, 15); memset(buffer, 0, 15);
attrs1[1].size = 6; b1.size = 6;
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0; lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_RDONLY, &cfg1) => 0;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 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; a1.size = LFS_ATTR_MAX+1;
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_WRONLY, &cfg1)
=> LFS_ERR_NOSPC; => LFS_ERR_NOSPC;
struct lfs_attr attrs2[] = { struct lfs_attr a2 = {'A', buffer, 4};
{'A', buffer, 4}, struct lfs_attr b2 = {'B', buffer+4, 9, &a2};
{'B', buffer+4, 9}, struct lfs_attr c2 = {'C', buffer+13, 5, &b2};
{'C', buffer+13, 5}, struct lfs_file_config cfg2 = {.attrs = &c2};
}; lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_RDWR, &cfg2) => 0;
struct lfs_file_config cfg2 = {.attrs=attrs2, .attr_count=3};
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDWR, &cfg2) => 0;
memcpy(buffer+4, "fffffffff", 9); memcpy(buffer+4, "fffffffff", 9);
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
attrs1[0].size = 4; a1.size = 4;
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0; lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_RDONLY, &cfg1) => 0;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
memset(buffer, 0, sizeof(buffer)); struct lfs_attr a2 = {'A', buffer, 4};
struct lfs_attr attrs2[] = { struct lfs_attr b2 = {'B', buffer+4, 9, &a2};
{'A', buffer, 4}, struct lfs_attr c2 = {'C', buffer+13, 5, &b2};
{'B', buffer+4, 9}, struct lfs_file_config cfg2 = {.attrs = &c2};
{'C', buffer+13, 5},
};
struct lfs_file_config cfg2 = {.attrs=attrs2, .attr_count=3};
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg2) => 0; lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_RDONLY, &cfg2) => 0;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 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; lfs_file_open(&lfs, &file[0], "hello/hello", LFS_O_RDONLY) => 0;
lfs_file_read(&lfs, &file, buffer, sizeof(buffer)) => strlen("hello"); lfs_file_read(&lfs, &file[0], buffer, sizeof(buffer)) => strlen("hello");
memcmp(buffer, "hello", strlen("hello")) => 0; memcmp(buffer, "hello", strlen("hello")) => 0;
lfs_file_close(&lfs, &file); lfs_file_close(&lfs, &file[0]);
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Deferred file attributes ---" echo "--- Deferred file attributes ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
memset(buffer, 0, sizeof(buffer)); struct lfs_attr a1 = {'B', "gggg", 4};
struct lfs_attr attrs1[] = { struct lfs_attr b1 = {'C', "", 0, &a1};
{'B', "gggg", 4}, struct lfs_attr c1 = {'D', "hhhh", 4, &b1};
{'C', "", 0}, struct lfs_file_config cfg1 = {.attrs = &c1};
{'D', "hhhh", 4},
};
struct lfs_file_config cfg1 = {.attrs=attrs1, .attr_count=3};
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0; lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_WRONLY, &cfg1) => 0;
lfs_getattr(&lfs, "hello/hello", 'B', buffer, 9) => 9; lfs_getattr(&lfs, "hello/hello", 'B', buffer, 9) => 9;
lfs_getattr(&lfs, "hello/hello", 'C', buffer+9, 9) => 5; lfs_getattr(&lfs, "hello/hello", 'C', buffer+9, 9) => 5;
lfs_getattr(&lfs, "hello/hello", 'D', buffer+18, 9) => LFS_ERR_NOATTR; lfs_getattr(&lfs, "hello/hello", 'D', buffer+18, 9) => 0;
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; lfs_file_sync(&lfs, &file[0]) => 0;
lfs_getattr(&lfs, "hello/hello", 'B', buffer, 9) => 4; lfs_getattr(&lfs, "hello/hello", 'B', buffer, 9) => 4;
lfs_getattr(&lfs, "hello/hello", 'C', buffer+9, 9) => 0; lfs_getattr(&lfs, "hello/hello", 'C', buffer+9, 9) => 0;
lfs_getattr(&lfs, "hello/hello", 'D', buffer+18, 9) => 4; lfs_getattr(&lfs, "hello/hello", 'D', buffer+18, 9) => 4;
@@ -287,8 +254,9 @@ scripts/test.py << TEST
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; lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
scripts/results.py echo "--- Results ---"
tests/stats.py

View File

@@ -1,7 +1,5 @@
#!/bin/bash #!/bin/bash
set -eu set -eu
export TEST_FILE=$0
trap 'export TEST_LINE=$LINENO' DEBUG
echo "=== Corrupt tests ===" echo "=== Corrupt tests ==="
@@ -9,7 +7,7 @@ NAMEMULT=64
FILEMULT=1 FILEMULT=1
lfs_mktree() { lfs_mktree() {
scripts/test.py ${1:-} << TEST tests/test.py ${1:-} << TEST
lfs_format(&lfs, &cfg) => 0; lfs_format(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
@@ -25,22 +23,22 @@ scripts/test.py ${1:-} << TEST
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_file_open(&lfs, &file[0], (char*)buffer,
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_size_t 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; lfs_file_write(&lfs, &file[0], buffer, size) => size;
} }
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
} }
lfs_chktree() { lfs_chktree() {
scripts/test.py ${1:-} << TEST tests/test.py ${1:-} << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
for (int i = 1; i < 10; i++) { for (int i = 1; i < 10; i++) {
for (int j = 0; j < $NAMEMULT; j++) { for (int j = 0; j < $NAMEMULT; j++) {
@@ -55,16 +53,15 @@ scripts/test.py ${1:-} << TEST
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; lfs_file_open(&lfs, &file[0], (char*)buffer, LFS_O_RDONLY) => 0;
lfs_size_t size = $NAMEMULT; size = $NAMEMULT;
for (int j = 0; j < i*$FILEMULT; j++) { for (int j = 0; j < i*$FILEMULT; j++) {
uint8_t rbuffer[1024]; lfs_file_read(&lfs, &file[0], rbuffer, size) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
memcmp(buffer, rbuffer, size) => 0; memcmp(buffer, rbuffer, size) => 0;
} }
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
@@ -92,7 +89,7 @@ do
rm -rf blocks rm -rf blocks
mkdir blocks mkdir blocks
lfs_mktree lfs_mktree
chmod a-w blocks/$b || true chmod a-w blocks/$b
lfs_mktree lfs_mktree
lfs_chktree lfs_chktree
done done
@@ -117,4 +114,5 @@ done
lfs_mktree lfs_mktree
lfs_chktree lfs_chktree
scripts/results.py echo "--- Results ---"
tests/stats.py

View File

@@ -1,191 +1,188 @@
#!/bin/bash #!/bin/bash
set -eu set -eu
export TEST_FILE=$0
trap 'export TEST_LINE=$LINENO' DEBUG
echo "=== Directory tests ==="
LARGESIZE=128 LARGESIZE=128
echo "=== Directory tests ==="
rm -rf blocks rm -rf blocks
scripts/test.py << TEST tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0; lfs_format(&lfs, &cfg) => 0;
TEST TEST
echo "--- Root directory ---" echo "--- Root directory ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir[0], "/") => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Directory creation ---" echo "--- Directory creation ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "potato") => 0; lfs_mkdir(&lfs, "potato") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- File creation ---" echo "--- File creation ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "burito", LFS_O_CREAT | LFS_O_WRONLY) => 0; lfs_file_open(&lfs, &file[0], "burito", LFS_O_CREAT | LFS_O_WRONLY) => 0;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Directory iteration ---" echo "--- Directory iteration ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir[0], "/") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "burito") => 0;
info.type => LFS_TYPE_REG;
lfs_dir_read(&lfs, &dir, &info) => 1;
strcmp(info.name, "potato") => 0; strcmp(info.name, "potato") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_read(&lfs, &dir[0], &info) => 1;
lfs_dir_close(&lfs, &dir) => 0; strcmp(info.name, "burito") => 0;
info.type => LFS_TYPE_REG;
lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Directory failures ---" echo "--- Directory failures ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "potato") => LFS_ERR_EXIST; lfs_mkdir(&lfs, "potato") => LFS_ERR_EXIST;
lfs_dir_open(&lfs, &dir, "tomato") => LFS_ERR_NOENT; lfs_dir_open(&lfs, &dir[0], "tomato") => LFS_ERR_NOENT;
lfs_dir_open(&lfs, &dir, "burito") => LFS_ERR_NOTDIR; lfs_dir_open(&lfs, &dir[0], "burito") => LFS_ERR_NOTDIR;
lfs_file_open(&lfs, &file, "tomato", LFS_O_RDONLY) => LFS_ERR_NOENT; lfs_file_open(&lfs, &file[0], "tomato", LFS_O_RDONLY) => LFS_ERR_NOENT;
lfs_file_open(&lfs, &file, "potato", LFS_O_RDONLY) => LFS_ERR_ISDIR; lfs_file_open(&lfs, &file[0], "potato", LFS_O_RDONLY) => LFS_ERR_ISDIR;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Nested directories ---" echo "--- Nested directories ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "potato/baked") => 0; lfs_mkdir(&lfs, "potato/baked") => 0;
lfs_mkdir(&lfs, "potato/sweet") => 0; lfs_mkdir(&lfs, "potato/sweet") => 0;
lfs_mkdir(&lfs, "potato/fried") => 0; lfs_mkdir(&lfs, "potato/fried") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "potato") => 0; lfs_dir_open(&lfs, &dir[0], "potato") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "baked") => 0; strcmp(info.name, "baked") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "fried") => 0;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 1;
strcmp(info.name, "sweet") => 0; strcmp(info.name, "sweet") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_read(&lfs, &dir[0], &info) => 1;
lfs_dir_close(&lfs, &dir) => 0; strcmp(info.name, "fried") => 0;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Multi-block directory ---" echo "--- Multi-block directory ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "cactus") => 0; lfs_mkdir(&lfs, "cactus") => 0;
for (int i = 0; i < $LARGESIZE; i++) { for (int i = 0; i < $LARGESIZE; i++) {
sprintf(path, "cactus/test%03d", i); sprintf((char*)buffer, "cactus/test%d", i);
lfs_mkdir(&lfs, path) => 0; lfs_mkdir(&lfs, (char*)buffer) => 0;
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "cactus") => 0; lfs_dir_open(&lfs, &dir[0], "cactus") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
for (int i = 0; i < $LARGESIZE; i++) { for (int i = 0; i < $LARGESIZE; i++) {
sprintf(path, "test%03d", i); sprintf((char*)buffer, "test%d", i);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, path) => 0; strcmp(info.name, (char*)buffer) => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
} }
lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Directory remove ---" echo "--- Directory remove ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_remove(&lfs, "potato") => LFS_ERR_NOTEMPTY; lfs_remove(&lfs, "potato") => LFS_ERR_NOTEMPTY;
lfs_remove(&lfs, "potato/sweet") => 0; lfs_remove(&lfs, "potato/sweet") => 0;
lfs_remove(&lfs, "potato/baked") => 0; lfs_remove(&lfs, "potato/baked") => 0;
lfs_remove(&lfs, "potato/fried") => 0; lfs_remove(&lfs, "potato/fried") => 0;
lfs_dir_open(&lfs, &dir, "potato") => 0; lfs_dir_open(&lfs, &dir[0], "potato") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_remove(&lfs, "potato") => 0; lfs_remove(&lfs, "potato") => 0;
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir[0], "/") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "burito") => 0; strcmp(info.name, "burito") => 0;
info.type => LFS_TYPE_REG; info.type => LFS_TYPE_REG;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "cactus") => 0; strcmp(info.name, "cactus") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir[0], "/") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "burito") => 0; strcmp(info.name, "burito") => 0;
info.type => LFS_TYPE_REG; info.type => LFS_TYPE_REG;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "cactus") => 0; strcmp(info.name, "cactus") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Directory rename ---" echo "--- Directory rename ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "coldpotato") => 0; lfs_mkdir(&lfs, "coldpotato") => 0;
lfs_mkdir(&lfs, "coldpotato/baked") => 0; lfs_mkdir(&lfs, "coldpotato/baked") => 0;
@@ -193,34 +190,34 @@ scripts/test.py << TEST
lfs_mkdir(&lfs, "coldpotato/fried") => 0; lfs_mkdir(&lfs, "coldpotato/fried") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_rename(&lfs, "coldpotato", "hotpotato") => 0; lfs_rename(&lfs, "coldpotato", "hotpotato") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "hotpotato") => 0; lfs_dir_open(&lfs, &dir[0], "hotpotato") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "baked") => 0; strcmp(info.name, "baked") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "fried") => 0;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 1;
strcmp(info.name, "sweet") => 0; strcmp(info.name, "sweet") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_read(&lfs, &dir[0], &info) => 1;
lfs_dir_close(&lfs, &dir) => 0; strcmp(info.name, "fried") => 0;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "warmpotato") => 0; lfs_mkdir(&lfs, "warmpotato") => 0;
lfs_mkdir(&lfs, "warmpotato/mushy") => 0; lfs_mkdir(&lfs, "warmpotato/mushy") => 0;
@@ -231,29 +228,29 @@ scripts/test.py << TEST
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "warmpotato") => 0; lfs_dir_open(&lfs, &dir[0], "warmpotato") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "baked") => 0; strcmp(info.name, "baked") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "fried") => 0;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 1;
strcmp(info.name, "sweet") => 0; strcmp(info.name, "sweet") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_read(&lfs, &dir[0], &info) => 1;
lfs_dir_close(&lfs, &dir) => 0; strcmp(info.name, "fried") => 0;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "coldpotato") => 0; lfs_mkdir(&lfs, "coldpotato") => 0;
lfs_rename(&lfs, "warmpotato/baked", "coldpotato/baked") => 0; lfs_rename(&lfs, "warmpotato/baked", "coldpotato/baked") => 0;
@@ -263,227 +260,166 @@ scripts/test.py << TEST
lfs_remove(&lfs, "warmpotato") => 0; lfs_remove(&lfs, "warmpotato") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "coldpotato") => 0; lfs_dir_open(&lfs, &dir[0], "coldpotato") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "baked") => 0; strcmp(info.name, "baked") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "fried") => 0;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 1;
strcmp(info.name, "sweet") => 0; strcmp(info.name, "sweet") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_read(&lfs, &dir[0], &info) => 1;
lfs_dir_close(&lfs, &dir) => 0; strcmp(info.name, "fried") => 0;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Recursive remove ---" echo "--- Recursive remove ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_remove(&lfs, "coldpotato") => LFS_ERR_NOTEMPTY; lfs_remove(&lfs, "coldpotato") => LFS_ERR_NOTEMPTY;
lfs_dir_open(&lfs, &dir, "coldpotato") => 0; lfs_dir_open(&lfs, &dir[0], "coldpotato") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
while (true) { while (true) {
int err = lfs_dir_read(&lfs, &dir, &info); int err = lfs_dir_read(&lfs, &dir[0], &info);
err >= 0 => 1; err >= 0 => 1;
if (err == 0) { if (err == 0) {
break; break;
} }
strcpy(path, "coldpotato/"); strcpy((char*)buffer, "coldpotato/");
strcat(path, info.name); strcat((char*)buffer, info.name);
lfs_remove(&lfs, path) => 0; lfs_remove(&lfs, (char*)buffer) => 0;
} }
lfs_remove(&lfs, "coldpotato") => 0; lfs_remove(&lfs, "coldpotato") => 0;
TEST TEST
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir[0], "/") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "burito") => 0; strcmp(info.name, "burito") => 0;
info.type => LFS_TYPE_REG; info.type => LFS_TYPE_REG;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "cactus") => 0; strcmp(info.name, "cactus") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Multi-block rename ---"
scripts/test.py << TEST
lfs_mount(&lfs, &cfg) => 0;
for (int i = 0; i < $LARGESIZE; i++) {
char oldpath[1024];
char newpath[1024];
sprintf(oldpath, "cactus/test%03d", i);
sprintf(newpath, "cactus/tedd%03d", i);
lfs_rename(&lfs, oldpath, newpath) => 0;
}
lfs_unmount(&lfs) => 0;
TEST
scripts/test.py << TEST
lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "cactus") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1;
strcmp(info.name, ".") => 0;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 1;
strcmp(info.name, "..") => 0;
info.type => LFS_TYPE_DIR;
for (int i = 0; i < $LARGESIZE; i++) {
sprintf(path, "tedd%03d", i);
lfs_dir_read(&lfs, &dir, &info) => 1;
strcmp(info.name, path) => 0;
info.type => LFS_TYPE_DIR;
}
lfs_dir_read(&lfs, &dir, &info) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Multi-block remove ---" echo "--- Multi-block remove ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_remove(&lfs, "cactus") => LFS_ERR_NOTEMPTY; lfs_remove(&lfs, "cactus") => LFS_ERR_NOTEMPTY;
for (int i = 0; i < $LARGESIZE; i++) { for (int i = 0; i < $LARGESIZE; i++) {
sprintf(path, "cactus/tedd%03d", i); sprintf((char*)buffer, "cactus/test%d", i);
lfs_remove(&lfs, path) => 0; lfs_remove(&lfs, (char*)buffer) => 0;
} }
lfs_remove(&lfs, "cactus") => 0; lfs_remove(&lfs, "cactus") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir[0], "/") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "burito") => 0; strcmp(info.name, "burito") => 0;
info.type => LFS_TYPE_REG; info.type => LFS_TYPE_REG;
lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Multi-block directory with files ---" echo "--- Multi-block directory with files ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "prickly-pear") => 0; lfs_mkdir(&lfs, "prickly-pear") => 0;
for (int i = 0; i < $LARGESIZE; i++) { for (int i = 0; i < $LARGESIZE; i++) {
sprintf(path, "prickly-pear/test%03d", i); sprintf((char*)buffer, "prickly-pear/test%d", i);
lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs_file_open(&lfs, &file[0], (char*)buffer,
lfs_size_t size = 6; LFS_O_WRONLY | LFS_O_CREAT) => 0;
memcpy(buffer, "Hello", size); size = 6;
lfs_file_write(&lfs, &file, buffer, size) => size; memcpy(wbuffer, "Hello", size);
lfs_file_close(&lfs, &file) => 0; lfs_file_write(&lfs, &file[0], wbuffer, size) => size;
lfs_file_close(&lfs, &file[0]) => 0;
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "prickly-pear") => 0; lfs_dir_open(&lfs, &dir[0], "prickly-pear") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
for (int i = 0; i < $LARGESIZE; i++) { for (int i = 0; i < $LARGESIZE; i++) {
sprintf(path, "test%03d", i); sprintf((char*)buffer, "test%d", i);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, path) => 0; strcmp(info.name, (char*)buffer) => 0;
info.type => LFS_TYPE_REG; info.type => LFS_TYPE_REG;
info.size => 6; info.size => 6;
} }
lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Multi-block rename with files ---"
scripts/test.py << TEST
lfs_mount(&lfs, &cfg) => 0;
for (int i = 0; i < $LARGESIZE; i++) {
char oldpath[1024];
char newpath[1024];
sprintf(oldpath, "prickly-pear/test%03d", i);
sprintf(newpath, "prickly-pear/tedd%03d", i);
lfs_rename(&lfs, oldpath, newpath) => 0;
}
lfs_unmount(&lfs) => 0;
TEST
scripts/test.py << TEST
lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "prickly-pear") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1;
strcmp(info.name, ".") => 0;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 1;
strcmp(info.name, "..") => 0;
info.type => LFS_TYPE_DIR;
for (int i = 0; i < $LARGESIZE; i++) {
sprintf(path, "tedd%03d", i);
lfs_dir_read(&lfs, &dir, &info) => 1;
strcmp(info.name, path) => 0;
info.type => LFS_TYPE_REG;
info.size => 6;
}
lfs_dir_read(&lfs, &dir, &info) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Multi-block remove with files ---" echo "--- Multi-block remove with files ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_remove(&lfs, "prickly-pear") => LFS_ERR_NOTEMPTY; lfs_remove(&lfs, "prickly-pear") => LFS_ERR_NOTEMPTY;
for (int i = 0; i < $LARGESIZE; i++) { for (int i = 0; i < $LARGESIZE; i++) {
sprintf(path, "prickly-pear/tedd%03d", i); sprintf((char*)buffer, "prickly-pear/test%d", i);
lfs_remove(&lfs, path) => 0; lfs_remove(&lfs, (char*)buffer) => 0;
} }
lfs_remove(&lfs, "prickly-pear") => 0; lfs_remove(&lfs, "prickly-pear") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir[0], "/") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "burito") => 0; strcmp(info.name, "burito") => 0;
info.type => LFS_TYPE_REG; info.type => LFS_TYPE_REG;
lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
scripts/results.py echo "--- Results ---"
tests/stats.py

View File

@@ -1,22 +1,19 @@
#!/bin/bash #!/bin/bash
set -eu set -eu
export TEST_FILE=$0
trap 'export TEST_LINE=$LINENO' DEBUG
echo "=== Entry tests ==="
# Note: These tests are intended for 512 byte inline size at different # Note: These tests are intended for 512 byte inline size at different
# inline sizes they should still pass, but won't be testing anything # inline sizes they should still pass, but won't be testing anything
echo "=== Entry tests ==="
rm -rf blocks rm -rf blocks
function read_file { function read_file {
cat << TEST cat << TEST
size = $2; size = $2;
lfs_file_open(&lfs, &file, "$1", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file[0], "$1", LFS_O_RDONLY) => 0;
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs_file_read(&lfs, &file[0], rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0; memcmp(rbuffer, wbuffer, size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
TEST TEST
} }
@@ -24,22 +21,18 @@ function write_file {
cat << TEST cat << TEST
size = $2; size = $2;
lfs_file_open(&lfs, &file, "$1", lfs_file_open(&lfs, &file[0], "$1",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size); memset(wbuffer, 'c', size);
lfs_file_write(&lfs, &file, wbuffer, size) => size; lfs_file_write(&lfs, &file[0], wbuffer, size) => size;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
TEST TEST
} }
echo "--- Entry grow test ---" echo "--- Entry grow test ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0; lfs_format(&lfs, &cfg) => 0;
uint8_t wbuffer[1024];
uint8_t rbuffer[1024];
lfs_size_t size;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
$(write_file "hi0" 20) $(write_file "hi0" 20)
$(write_file "hi1" 20) $(write_file "hi1" 20)
@@ -57,13 +50,9 @@ scripts/test.py << TEST
TEST TEST
echo "--- Entry shrink test ---" echo "--- Entry shrink test ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0; lfs_format(&lfs, &cfg) => 0;
uint8_t wbuffer[1024];
uint8_t rbuffer[1024];
lfs_size_t size;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
$(write_file "hi0" 20) $(write_file "hi0" 20)
$(write_file "hi1" 200) $(write_file "hi1" 200)
@@ -81,13 +70,9 @@ scripts/test.py << TEST
TEST TEST
echo "--- Entry spill test ---" echo "--- Entry spill test ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0; lfs_format(&lfs, &cfg) => 0;
uint8_t wbuffer[1024];
uint8_t rbuffer[1024];
lfs_size_t size;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
$(write_file "hi0" 200) $(write_file "hi0" 200)
$(write_file "hi1" 200) $(write_file "hi1" 200)
@@ -102,13 +87,9 @@ scripts/test.py << TEST
TEST TEST
echo "--- Entry push spill test ---" echo "--- Entry push spill test ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0; lfs_format(&lfs, &cfg) => 0;
uint8_t wbuffer[1024];
uint8_t rbuffer[1024];
lfs_size_t size;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
$(write_file "hi0" 200) $(write_file "hi0" 200)
$(write_file "hi1" 20) $(write_file "hi1" 20)
@@ -126,13 +107,9 @@ scripts/test.py << TEST
TEST TEST
echo "--- Entry push spill two test ---" echo "--- Entry push spill two test ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0; lfs_format(&lfs, &cfg) => 0;
uint8_t wbuffer[1024];
uint8_t rbuffer[1024];
lfs_size_t size;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
$(write_file "hi0" 200) $(write_file "hi0" 200)
$(write_file "hi1" 20) $(write_file "hi1" 20)
@@ -152,13 +129,9 @@ scripts/test.py << TEST
TEST TEST
echo "--- Entry drop test ---" echo "--- Entry drop test ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0; lfs_format(&lfs, &cfg) => 0;
uint8_t wbuffer[1024];
uint8_t rbuffer[1024];
lfs_size_t size;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
$(write_file "hi0" 200) $(write_file "hi0" 200)
$(write_file "hi1" 200) $(write_file "hi1" 200)
@@ -186,66 +159,63 @@ scripts/test.py << TEST
TEST TEST
echo "--- Create too big ---" echo "--- Create too big ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0; lfs_format(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
memset(path, 'm', 200); memset(buffer, 'm', 200);
path[200] = '\0'; buffer[200] = '\0';
lfs_size_t size = 400;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
uint8_t wbuffer[1024];
memset(wbuffer, 'c', size);
lfs_file_write(&lfs, &file, wbuffer, size) => size;
lfs_file_close(&lfs, &file) => 0;
size = 400; size = 400;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file[0], (char*)buffer,
uint8_t rbuffer[1024]; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
lfs_file_read(&lfs, &file, rbuffer, size) => size; memset(wbuffer, 'c', size);
lfs_file_write(&lfs, &file[0], wbuffer, size) => size;
lfs_file_close(&lfs, &file[0]) => 0;
size = 400;
lfs_file_open(&lfs, &file[0], (char*)buffer, LFS_O_RDONLY) => 0;
lfs_file_read(&lfs, &file[0], rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0; memcmp(rbuffer, wbuffer, size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Resize too big ---" echo "--- Resize too big ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0; lfs_format(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
memset(path, 'm', 200); memset(buffer, 'm', 200);
path[200] = '\0'; buffer[200] = '\0';
lfs_size_t size = 40;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
uint8_t wbuffer[1024];
memset(wbuffer, 'c', size);
lfs_file_write(&lfs, &file, wbuffer, size) => size;
lfs_file_close(&lfs, &file) => 0;
size = 40; size = 40;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file[0], (char*)buffer,
uint8_t rbuffer[1024];
lfs_file_read(&lfs, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0;
lfs_file_close(&lfs, &file) => 0;
size = 400;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size); memset(wbuffer, 'c', size);
lfs_file_write(&lfs, &file, wbuffer, size) => size; lfs_file_write(&lfs, &file[0], wbuffer, size) => size;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
size = 40;
lfs_file_open(&lfs, &file[0], (char*)buffer, LFS_O_RDONLY) => 0;
lfs_file_read(&lfs, &file[0], rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
size = 400; size = 400;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file[0], (char*)buffer,
lfs_file_read(&lfs, &file, rbuffer, size) => size; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size);
lfs_file_write(&lfs, &file[0], wbuffer, size) => size;
lfs_file_close(&lfs, &file[0]) => 0;
size = 400;
lfs_file_open(&lfs, &file[0], (char*)buffer, LFS_O_RDONLY) => 0;
lfs_file_read(&lfs, &file[0], rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0; memcmp(rbuffer, wbuffer, size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
scripts/results.py echo "--- Results ---"
tests/stats.py

View File

@@ -1,76 +1,71 @@
#!/bin/bash #!/bin/bash
set -eu set -eu
export TEST_FILE=$0
trap 'export TEST_LINE=$LINENO' DEBUG
echo "=== File tests ==="
SMALLSIZE=32 SMALLSIZE=32
MEDIUMSIZE=8192 MEDIUMSIZE=8192
LARGESIZE=262144 LARGESIZE=262144
echo "=== File tests ==="
rm -rf blocks rm -rf blocks
scripts/test.py << TEST tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0; lfs_format(&lfs, &cfg) => 0;
TEST TEST
echo "--- Simple file test ---" echo "--- Simple file test ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "hello", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs_file_open(&lfs, &file[0], "hello", LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_size_t size = strlen("Hello World!\n");
uint8_t wbuffer[1024];
memcpy(wbuffer, "Hello World!\n", size);
lfs_file_write(&lfs, &file, wbuffer, size) => size;
lfs_file_close(&lfs, &file) => 0;
lfs_file_open(&lfs, &file, "hello", LFS_O_RDONLY) => 0;
size = strlen("Hello World!\n"); size = strlen("Hello World!\n");
uint8_t rbuffer[1024]; memcpy(wbuffer, "Hello World!\n", size);
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs_file_write(&lfs, &file[0], wbuffer, size) => size;
lfs_file_close(&lfs, &file[0]) => 0;
lfs_file_open(&lfs, &file[0], "hello", LFS_O_RDONLY) => 0;
size = strlen("Hello World!\n");
lfs_file_read(&lfs, &file[0], rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0; memcmp(rbuffer, wbuffer, size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
w_test() { w_test() {
scripts/test.py ${4:-} << TEST tests/test.py << TEST
lfs_size_t size = $1; size = $1;
lfs_size_t chunk = 31; lfs_size_t chunk = 31;
srand(0); srand(0);
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "$2", lfs_file_open(&lfs, &file[0], "$2",
${3:-LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC}) => 0; ${3:-LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC}) => 0;
for (lfs_size_t i = 0; i < size; i += chunk) { for (lfs_size_t i = 0; i < size; i += chunk) {
chunk = (chunk < size - i) ? chunk : size - i; chunk = (chunk < size - i) ? chunk : size - i;
for (lfs_size_t b = 0; b < chunk; b++) { for (lfs_size_t b = 0; b < chunk; b++) {
buffer[b] = rand() & 0xff; buffer[b] = rand() & 0xff;
} }
lfs_file_write(&lfs, &file, buffer, chunk) => chunk; lfs_file_write(&lfs, &file[0], buffer, chunk) => chunk;
} }
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
} }
r_test() { r_test() {
scripts/test.py << TEST tests/test.py << TEST
lfs_size_t size = $1; size = $1;
lfs_size_t chunk = 29; lfs_size_t chunk = 29;
srand(0); srand(0);
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_stat(&lfs, "$2", &info) => 0; lfs_stat(&lfs, "$2", &info) => 0;
info.type => LFS_TYPE_REG; info.type => LFS_TYPE_REG;
info.size => size; info.size => size;
lfs_file_open(&lfs, &file, "$2", ${3:-LFS_O_RDONLY}) => 0; lfs_file_open(&lfs, &file[0], "$2", ${3:-LFS_O_RDONLY}) => 0;
for (lfs_size_t i = 0; i < size; i += chunk) { for (lfs_size_t i = 0; i < size; i += chunk) {
chunk = (chunk < size - i) ? chunk : size - i; chunk = (chunk < size - i) ? chunk : size - i;
lfs_file_read(&lfs, &file, buffer, chunk) => chunk; lfs_file_read(&lfs, &file[0], buffer, chunk) => chunk;
for (lfs_size_t b = 0; b < chunk && i+b < size; b++) { for (lfs_size_t b = 0; b < chunk && i+b < size; b++) {
buffer[b] => rand() & 0xff; buffer[b] => rand() & 0xff;
} }
} }
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
} }
@@ -110,112 +105,54 @@ r_test $LARGESIZE largeavacado
r_test 0 noavacado r_test 0 noavacado
echo "--- Dir check ---" echo "--- Dir check ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir[0], "/") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "hello") => 0; strcmp(info.name, "hello") => 0;
info.type => LFS_TYPE_REG; info.type => LFS_TYPE_REG;
info.size => strlen("Hello World!\n"); info.size => strlen("Hello World!\n");
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "largeavacado") => 0;
info.type => LFS_TYPE_REG;
info.size => $LARGESIZE;
lfs_dir_read(&lfs, &dir, &info) => 1;
strcmp(info.name, "mediumavacado") => 0;
info.type => LFS_TYPE_REG;
info.size => $MEDIUMSIZE;
lfs_dir_read(&lfs, &dir, &info) => 1;
strcmp(info.name, "noavacado") => 0;
info.type => LFS_TYPE_REG;
info.size => 0;
lfs_dir_read(&lfs, &dir, &info) => 1;
strcmp(info.name, "smallavacado") => 0; strcmp(info.name, "smallavacado") => 0;
info.type => LFS_TYPE_REG; info.type => LFS_TYPE_REG;
info.size => $SMALLSIZE; info.size => $SMALLSIZE;
lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_read(&lfs, &dir[0], &info) => 1;
lfs_dir_close(&lfs, &dir) => 0; strcmp(info.name, "mediumavacado") => 0;
info.type => LFS_TYPE_REG;
info.size => $MEDIUMSIZE;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "largeavacado") => 0;
info.type => LFS_TYPE_REG;
info.size => $LARGESIZE;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "noavacado") => 0;
info.type => LFS_TYPE_REG;
info.size => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Many files test ---" echo "--- Many file test ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0; lfs_format(&lfs, &cfg) => 0;
TEST TEST
scripts/test.py << TEST tests/test.py << TEST
// Create 300 files of 7 bytes // Create 300 files of 6 bytes
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "directory") => 0;
for (unsigned i = 0; i < 300; i++) { for (unsigned i = 0; i < 300; i++) {
sprintf(path, "file_%03d", i); snprintf((char*)buffer, sizeof(buffer), "file_%03d", i);
lfs_file_open(&lfs, &file, path, lfs_file_open(&lfs, &file[0], (char*)buffer, LFS_O_WRONLY | LFS_O_CREAT) => 0;
LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL) => 0; size = 6;
lfs_size_t size = 7; memcpy(wbuffer, "Hello", size);
uint8_t wbuffer[1024]; lfs_file_write(&lfs, &file[0], wbuffer, size) => size;
uint8_t rbuffer[1024]; lfs_file_close(&lfs, &file[0]) => 0;
snprintf((char*)wbuffer, size, "Hi %03d", i);
lfs_file_write(&lfs, &file, wbuffer, size) => size;
lfs_file_rewind(&lfs, &file) => 0;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
memcmp(wbuffer, rbuffer, size) => 0;
lfs_file_close(&lfs, &file) => 0;
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Many files with flush test ---" echo "--- Results ---"
scripts/test.py << TEST tests/stats.py
lfs_format(&lfs, &cfg) => 0;
TEST
scripts/test.py << TEST
// Create 300 files of 7 bytes
lfs_mount(&lfs, &cfg) => 0;
for (unsigned i = 0; i < 300; i++) {
sprintf(path, "file_%03d", i);
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
lfs_size_t size = 7;
uint8_t wbuffer[1024];
uint8_t rbuffer[1024];
snprintf((char*)wbuffer, size, "Hi %03d", i);
lfs_file_write(&lfs, &file, wbuffer, size) => size;
lfs_file_close(&lfs, &file) => 0;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
memcmp(wbuffer, rbuffer, size) => 0;
lfs_file_close(&lfs, &file) => 0;
}
lfs_unmount(&lfs) => 0;
TEST
echo "--- Many files with power cycle test ---"
scripts/test.py << TEST
lfs_format(&lfs, &cfg) => 0;
TEST
scripts/test.py << TEST
// Create 300 files of 7 bytes
lfs_mount(&lfs, &cfg) => 0;
for (unsigned i = 0; i < 300; i++) {
sprintf(path, "file_%03d", i);
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
lfs_size_t size = 7;
uint8_t wbuffer[1024];
uint8_t rbuffer[1024];
snprintf((char*)wbuffer, size, "Hi %03d", i);
lfs_file_write(&lfs, &file, wbuffer, size) => size;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
memcmp(wbuffer, rbuffer, size) => 0;
lfs_file_close(&lfs, &file) => 0;
}
lfs_unmount(&lfs) => 0;
TEST
scripts/results.py

View File

@@ -1,20 +1,19 @@
#!/bin/bash #!/bin/bash
set -eu set -eu
export TEST_FILE=$0
trap 'export TEST_LINE=$LINENO' DEBUG
echo "=== Formatting tests ===" echo "=== Formatting tests ==="
rm -rf blocks rm -rf blocks
echo "--- Basic formatting ---" echo "--- Basic formatting ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0; lfs_format(&lfs, &cfg) => 0;
TEST TEST
echo "--- Basic mounting ---" echo "--- Basic mounting ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0; lfs_format(&lfs, &cfg) => 0;
TEST
tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
@@ -22,18 +21,18 @@ TEST
echo "--- Invalid superblocks ---" echo "--- Invalid superblocks ---"
ln -f -s /dev/zero blocks/0 ln -f -s /dev/zero blocks/0
ln -f -s /dev/zero blocks/1 ln -f -s /dev/zero blocks/1
scripts/test.py << TEST tests/test.py << TEST
lfs_format(&lfs, &cfg) => LFS_ERR_NOSPC; lfs_format(&lfs, &cfg) => LFS_ERR_CORRUPT;
TEST TEST
rm blocks/0 blocks/1 rm blocks/0 blocks/1
echo "--- Invalid mount ---" echo "--- Invalid mount ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => LFS_ERR_CORRUPT; lfs_mount(&lfs, &cfg) => LFS_ERR_CORRUPT;
TEST TEST
echo "--- Expanding superblock ---" echo "--- Expanding superblock ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0; lfs_format(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
for (int i = 0; i < 100; i++) { for (int i = 0; i < 100; i++) {
@@ -42,10 +41,11 @@ scripts/test.py << TEST
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "dummy") => 0; lfs_mkdir(&lfs, "dummy") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
scripts/results.py echo "--- Results ---"
tests/stats.py

View File

@@ -1,93 +1,89 @@
#!/bin/bash #!/bin/bash
set -eu set -eu
export TEST_FILE=$0
trap 'export TEST_LINE=$LINENO' DEBUG
echo "=== Interspersed tests ===" echo "=== Interspersed tests ==="
rm -rf blocks rm -rf blocks
scripts/test.py << TEST tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0; lfs_format(&lfs, &cfg) => 0;
TEST TEST
echo "--- Interspersed file test ---" echo "--- Interspersed file test ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_file_t files[4]; lfs_file_open(&lfs, &file[0], "a", LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_open(&lfs, &files[0], "a", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs_file_open(&lfs, &file[1], "b", LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_open(&lfs, &files[1], "b", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs_file_open(&lfs, &file[2], "c", LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_open(&lfs, &files[2], "c", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs_file_open(&lfs, &file[3], "d", LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_open(&lfs, &files[3], "d", LFS_O_WRONLY | LFS_O_CREAT) => 0;
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
lfs_file_write(&lfs, &files[0], (const void*)"a", 1) => 1; lfs_file_write(&lfs, &file[0], (const void*)"a", 1) => 1;
lfs_file_write(&lfs, &files[1], (const void*)"b", 1) => 1; lfs_file_write(&lfs, &file[1], (const void*)"b", 1) => 1;
lfs_file_write(&lfs, &files[2], (const void*)"c", 1) => 1; lfs_file_write(&lfs, &file[2], (const void*)"c", 1) => 1;
lfs_file_write(&lfs, &files[3], (const void*)"d", 1) => 1; lfs_file_write(&lfs, &file[3], (const void*)"d", 1) => 1;
} }
lfs_file_close(&lfs, &files[0]); lfs_file_close(&lfs, &file[0]);
lfs_file_close(&lfs, &files[1]); lfs_file_close(&lfs, &file[1]);
lfs_file_close(&lfs, &files[2]); lfs_file_close(&lfs, &file[2]);
lfs_file_close(&lfs, &files[3]); lfs_file_close(&lfs, &file[3]);
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir[0], "/") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "a") => 0; strcmp(info.name, "a") => 0;
info.type => LFS_TYPE_REG; info.type => LFS_TYPE_REG;
info.size => 10; info.size => 10;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "b") => 0; strcmp(info.name, "b") => 0;
info.type => LFS_TYPE_REG; info.type => LFS_TYPE_REG;
info.size => 10; info.size => 10;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "c") => 0; strcmp(info.name, "c") => 0;
info.type => LFS_TYPE_REG; info.type => LFS_TYPE_REG;
info.size => 10; info.size => 10;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "d") => 0; strcmp(info.name, "d") => 0;
info.type => LFS_TYPE_REG; info.type => LFS_TYPE_REG;
info.size => 10; info.size => 10;
lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_file_open(&lfs, &files[0], "a", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file[0], "a", LFS_O_RDONLY) => 0;
lfs_file_open(&lfs, &files[1], "b", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file[1], "b", LFS_O_RDONLY) => 0;
lfs_file_open(&lfs, &files[2], "c", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file[2], "c", LFS_O_RDONLY) => 0;
lfs_file_open(&lfs, &files[3], "d", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file[3], "d", LFS_O_RDONLY) => 0;
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
lfs_file_read(&lfs, &files[0], buffer, 1) => 1; lfs_file_read(&lfs, &file[0], buffer, 1) => 1;
buffer[0] => 'a'; buffer[0] => 'a';
lfs_file_read(&lfs, &files[1], buffer, 1) => 1; lfs_file_read(&lfs, &file[1], buffer, 1) => 1;
buffer[0] => 'b'; buffer[0] => 'b';
lfs_file_read(&lfs, &files[2], buffer, 1) => 1; lfs_file_read(&lfs, &file[2], buffer, 1) => 1;
buffer[0] => 'c'; buffer[0] => 'c';
lfs_file_read(&lfs, &files[3], buffer, 1) => 1; lfs_file_read(&lfs, &file[3], buffer, 1) => 1;
buffer[0] => 'd'; buffer[0] => 'd';
} }
lfs_file_close(&lfs, &files[0]); lfs_file_close(&lfs, &file[0]);
lfs_file_close(&lfs, &files[1]); lfs_file_close(&lfs, &file[1]);
lfs_file_close(&lfs, &files[2]); lfs_file_close(&lfs, &file[2]);
lfs_file_close(&lfs, &files[3]); lfs_file_close(&lfs, &file[3]);
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Interspersed remove file test ---" echo "--- Interspersed remove file test ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_file_t files[4]; lfs_file_open(&lfs, &file[0], "e", LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_open(&lfs, &files[0], "e", LFS_O_WRONLY | LFS_O_CREAT) => 0;
for (int i = 0; i < 5; i++) { for (int i = 0; i < 5; i++) {
lfs_file_write(&lfs, &files[0], (const void*)"e", 1) => 1; lfs_file_write(&lfs, &file[0], (const void*)"e", 1) => 1;
} }
lfs_remove(&lfs, "a") => 0; lfs_remove(&lfs, "a") => 0;
@@ -96,95 +92,95 @@ scripts/test.py << TEST
lfs_remove(&lfs, "d") => 0; lfs_remove(&lfs, "d") => 0;
for (int i = 0; i < 5; i++) { for (int i = 0; i < 5; i++) {
lfs_file_write(&lfs, &files[0], (const void*)"e", 1) => 1; lfs_file_write(&lfs, &file[0], (const void*)"e", 1) => 1;
} }
lfs_file_close(&lfs, &files[0]); lfs_file_close(&lfs, &file[0]);
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir[0], "/") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "e") => 0; strcmp(info.name, "e") => 0;
info.type => LFS_TYPE_REG; info.type => LFS_TYPE_REG;
info.size => 10; info.size => 10;
lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_file_open(&lfs, &files[0], "e", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file[0], "e", LFS_O_RDONLY) => 0;
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
lfs_file_read(&lfs, &files[0], buffer, 1) => 1; lfs_file_read(&lfs, &file[0], buffer, 1) => 1;
buffer[0] => 'e'; buffer[0] => 'e';
} }
lfs_file_close(&lfs, &files[0]); lfs_file_close(&lfs, &file[0]);
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Remove inconveniently test ---" echo "--- Remove inconveniently test ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_file_t files[4]; lfs_file_open(&lfs, &file[0], "e", LFS_O_WRONLY | LFS_O_TRUNC) => 0;
lfs_file_open(&lfs, &files[0], "e", LFS_O_WRONLY | LFS_O_TRUNC) => 0; lfs_file_open(&lfs, &file[1], "f", LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_open(&lfs, &files[1], "f", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs_file_open(&lfs, &file[2], "g", LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_open(&lfs, &files[2], "g", LFS_O_WRONLY | LFS_O_CREAT) => 0;
for (int i = 0; i < 5; i++) { for (int i = 0; i < 5; i++) {
lfs_file_write(&lfs, &files[0], (const void*)"e", 1) => 1; lfs_file_write(&lfs, &file[0], (const void*)"e", 1) => 1;
lfs_file_write(&lfs, &files[1], (const void*)"f", 1) => 1; lfs_file_write(&lfs, &file[1], (const void*)"f", 1) => 1;
lfs_file_write(&lfs, &files[2], (const void*)"g", 1) => 1; lfs_file_write(&lfs, &file[2], (const void*)"g", 1) => 1;
} }
lfs_remove(&lfs, "f") => 0; lfs_remove(&lfs, "f") => 0;
for (int i = 0; i < 5; i++) { for (int i = 0; i < 5; i++) {
lfs_file_write(&lfs, &files[0], (const void*)"e", 1) => 1; lfs_file_write(&lfs, &file[0], (const void*)"e", 1) => 1;
lfs_file_write(&lfs, &files[1], (const void*)"f", 1) => 1; lfs_file_write(&lfs, &file[1], (const void*)"f", 1) => 1;
lfs_file_write(&lfs, &files[2], (const void*)"g", 1) => 1; lfs_file_write(&lfs, &file[2], (const void*)"g", 1) => 1;
} }
lfs_file_close(&lfs, &files[0]); lfs_file_close(&lfs, &file[0]);
lfs_file_close(&lfs, &files[1]); lfs_file_close(&lfs, &file[1]);
lfs_file_close(&lfs, &files[2]); lfs_file_close(&lfs, &file[2]);
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir[0], "/") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "e") => 0; strcmp(info.name, "e") => 0;
info.type => LFS_TYPE_REG; info.type => LFS_TYPE_REG;
info.size => 10; info.size => 10;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "g") => 0; strcmp(info.name, "g") => 0;
info.type => LFS_TYPE_REG; info.type => LFS_TYPE_REG;
info.size => 10; info.size => 10;
lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_file_open(&lfs, &files[0], "e", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file[0], "e", LFS_O_RDONLY) => 0;
lfs_file_open(&lfs, &files[1], "g", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file[1], "g", LFS_O_RDONLY) => 0;
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
lfs_file_read(&lfs, &files[0], buffer, 1) => 1; lfs_file_read(&lfs, &file[0], buffer, 1) => 1;
buffer[0] => 'e'; buffer[0] => 'e';
lfs_file_read(&lfs, &files[1], buffer, 1) => 1; lfs_file_read(&lfs, &file[1], buffer, 1) => 1;
buffer[0] => 'g'; buffer[0] => 'g';
} }
lfs_file_close(&lfs, &files[0]); lfs_file_close(&lfs, &file[0]);
lfs_file_close(&lfs, &files[1]); lfs_file_close(&lfs, &file[1]);
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
scripts/results.py echo "--- Results ---"
tests/stats.py

View File

@@ -1,11 +1,9 @@
#!/bin/bash #!/bin/bash
set -eu set -eu
export TEST_FILE=$0
trap 'export TEST_LINE=$LINENO' DEBUG
echo "=== Move tests ===" echo "=== Move tests ==="
rm -rf blocks rm -rf blocks
scripts/test.py << TEST tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0; lfs_format(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
@@ -19,272 +17,272 @@ scripts/test.py << TEST
lfs_mkdir(&lfs, "a/hi/bonjour") => 0; lfs_mkdir(&lfs, "a/hi/bonjour") => 0;
lfs_mkdir(&lfs, "a/hi/ohayo") => 0; lfs_mkdir(&lfs, "a/hi/ohayo") => 0;
lfs_file_open(&lfs, &file, "a/hello", LFS_O_CREAT | LFS_O_WRONLY) => 0; lfs_file_open(&lfs, &file[0], "a/hello", LFS_O_CREAT | LFS_O_WRONLY) => 0;
lfs_file_write(&lfs, &file, "hola\n", 5) => 5; lfs_file_write(&lfs, &file[0], "hola\n", 5) => 5;
lfs_file_write(&lfs, &file, "bonjour\n", 8) => 8; lfs_file_write(&lfs, &file[0], "bonjour\n", 8) => 8;
lfs_file_write(&lfs, &file, "ohayo\n", 6) => 6; lfs_file_write(&lfs, &file[0], "ohayo\n", 6) => 6;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Move file ---" echo "--- Move file ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_rename(&lfs, "a/hello", "b/hello") => 0; lfs_rename(&lfs, "a/hello", "b/hello") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "a") => 0; lfs_dir_open(&lfs, &dir[0], "a") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "hi") => 0; strcmp(info.name, "hi") => 0;
lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_dir_open(&lfs, &dir, "b") => 0; lfs_dir_open(&lfs, &dir[0], "b") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "hello") => 0; strcmp(info.name, "hello") => 0;
lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Move file corrupt source ---" echo "--- Move file corrupt source ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_rename(&lfs, "b/hello", "c/hello") => 0; lfs_rename(&lfs, "b/hello", "c/hello") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
scripts/corrupt.py -n 1 tests/corrupt.py -n 1
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "b") => 0; lfs_dir_open(&lfs, &dir[0], "b") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_dir_open(&lfs, &dir, "c") => 0; lfs_dir_open(&lfs, &dir[0], "c") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "hello") => 0; strcmp(info.name, "hello") => 0;
lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Move file corrupt source and dest ---" echo "--- Move file corrupt source and dest ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_rename(&lfs, "c/hello", "d/hello") => 0; lfs_rename(&lfs, "c/hello", "d/hello") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
scripts/corrupt.py -n 2 tests/corrupt.py -n 2
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "c") => 0; lfs_dir_open(&lfs, &dir[0], "c") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "hello") => 0; strcmp(info.name, "hello") => 0;
lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_dir_open(&lfs, &dir, "d") => 0; lfs_dir_open(&lfs, &dir[0], "d") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Move file after corrupt ---" echo "--- Move file after corrupt ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_rename(&lfs, "c/hello", "d/hello") => 0; lfs_rename(&lfs, "c/hello", "d/hello") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "c") => 0; lfs_dir_open(&lfs, &dir[0], "c") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_dir_open(&lfs, &dir, "d") => 0; lfs_dir_open(&lfs, &dir[0], "d") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "hello") => 0; strcmp(info.name, "hello") => 0;
lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Move dir ---" echo "--- Move dir ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_rename(&lfs, "a/hi", "b/hi") => 0; lfs_rename(&lfs, "a/hi", "b/hi") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "a") => 0; lfs_dir_open(&lfs, &dir[0], "a") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_dir_open(&lfs, &dir, "b") => 0; lfs_dir_open(&lfs, &dir[0], "b") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "hi") => 0; strcmp(info.name, "hi") => 0;
lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Move dir corrupt source ---" echo "--- Move dir corrupt source ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_rename(&lfs, "b/hi", "c/hi") => 0; lfs_rename(&lfs, "b/hi", "c/hi") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
scripts/corrupt.py -n 1 tests/corrupt.py -n 1
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "b") => 0; lfs_dir_open(&lfs, &dir[0], "b") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_dir_open(&lfs, &dir, "c") => 0; lfs_dir_open(&lfs, &dir[0], "c") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "hi") => 0; strcmp(info.name, "hi") => 0;
lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Move dir corrupt source and dest ---" echo "--- Move dir corrupt source and dest ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_rename(&lfs, "c/hi", "d/hi") => 0; lfs_rename(&lfs, "c/hi", "d/hi") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
scripts/corrupt.py -n 2 tests/corrupt.py -n 2
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "c") => 0; lfs_dir_open(&lfs, &dir[0], "c") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "hi") => 0; strcmp(info.name, "hi") => 0;
lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_dir_open(&lfs, &dir, "d") => 0; lfs_dir_open(&lfs, &dir[0], "d") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "hello") => 0; strcmp(info.name, "hello") => 0;
lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Move dir after corrupt ---" echo "--- Move dir after corrupt ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_rename(&lfs, "c/hi", "d/hi") => 0; lfs_rename(&lfs, "c/hi", "d/hi") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "c") => 0; lfs_dir_open(&lfs, &dir[0], "c") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_dir_open(&lfs, &dir, "d") => 0; lfs_dir_open(&lfs, &dir[0], "d") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "hello") => 0; strcmp(info.name, "hello") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "hi") => 0; strcmp(info.name, "hi") => 0;
lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Move check ---" echo "--- Move check ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "a/hi") => LFS_ERR_NOENT; lfs_dir_open(&lfs, &dir[0], "a/hi") => LFS_ERR_NOENT;
lfs_dir_open(&lfs, &dir, "b/hi") => LFS_ERR_NOENT; lfs_dir_open(&lfs, &dir[0], "b/hi") => LFS_ERR_NOENT;
lfs_dir_open(&lfs, &dir, "c/hi") => LFS_ERR_NOENT; lfs_dir_open(&lfs, &dir[0], "c/hi") => LFS_ERR_NOENT;
lfs_dir_open(&lfs, &dir, "d/hi") => 0; lfs_dir_open(&lfs, &dir[0], "d/hi") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "bonjour") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1;
strcmp(info.name, "hola") => 0; strcmp(info.name, "hola") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "bonjour") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "ohayo") => 0; strcmp(info.name, "ohayo") => 0;
lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_dir_open(&lfs, &dir, "a/hello") => LFS_ERR_NOENT; lfs_dir_open(&lfs, &dir[0], "a/hello") => LFS_ERR_NOENT;
lfs_dir_open(&lfs, &dir, "b/hello") => LFS_ERR_NOENT; lfs_dir_open(&lfs, &dir[0], "b/hello") => LFS_ERR_NOENT;
lfs_dir_open(&lfs, &dir, "c/hello") => LFS_ERR_NOENT; lfs_dir_open(&lfs, &dir[0], "c/hello") => LFS_ERR_NOENT;
lfs_file_open(&lfs, &file, "d/hello", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file[0], "d/hello", LFS_O_RDONLY) => 0;
lfs_file_read(&lfs, &file, buffer, 5) => 5; lfs_file_read(&lfs, &file[0], buffer, 5) => 5;
memcmp(buffer, "hola\n", 5) => 0; memcmp(buffer, "hola\n", 5) => 0;
lfs_file_read(&lfs, &file, buffer, 8) => 8; lfs_file_read(&lfs, &file[0], buffer, 8) => 8;
memcmp(buffer, "bonjour\n", 8) => 0; memcmp(buffer, "bonjour\n", 8) => 0;
lfs_file_read(&lfs, &file, buffer, 6) => 6; lfs_file_read(&lfs, &file[0], buffer, 6) => 6;
memcmp(buffer, "ohayo\n", 6) => 0; memcmp(buffer, "ohayo\n", 6) => 0;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Move state stealing ---" echo "--- Move state stealing ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_remove(&lfs, "b") => 0; lfs_remove(&lfs, "b") => 0;
@@ -292,42 +290,43 @@ scripts/test.py << TEST
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "a/hi") => LFS_ERR_NOENT; lfs_dir_open(&lfs, &dir[0], "a/hi") => LFS_ERR_NOENT;
lfs_dir_open(&lfs, &dir, "b") => LFS_ERR_NOENT; lfs_dir_open(&lfs, &dir[0], "b") => LFS_ERR_NOENT;
lfs_dir_open(&lfs, &dir, "c") => LFS_ERR_NOENT; lfs_dir_open(&lfs, &dir[0], "c") => LFS_ERR_NOENT;
lfs_dir_open(&lfs, &dir, "d/hi") => 0; lfs_dir_open(&lfs, &dir[0], "d/hi") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "bonjour") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1;
strcmp(info.name, "hola") => 0; strcmp(info.name, "hola") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "bonjour") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "ohayo") => 0; strcmp(info.name, "ohayo") => 0;
lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_dir_open(&lfs, &dir, "a/hello") => LFS_ERR_NOENT; lfs_dir_open(&lfs, &dir[0], "a/hello") => LFS_ERR_NOENT;
lfs_dir_open(&lfs, &dir, "b") => LFS_ERR_NOENT; lfs_dir_open(&lfs, &dir[0], "b") => LFS_ERR_NOENT;
lfs_dir_open(&lfs, &dir, "c") => LFS_ERR_NOENT; lfs_dir_open(&lfs, &dir[0], "c") => LFS_ERR_NOENT;
lfs_file_open(&lfs, &file, "d/hello", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file[0], "d/hello", LFS_O_RDONLY) => 0;
lfs_file_read(&lfs, &file, buffer, 5) => 5; lfs_file_read(&lfs, &file[0], buffer, 5) => 5;
memcmp(buffer, "hola\n", 5) => 0; memcmp(buffer, "hola\n", 5) => 0;
lfs_file_read(&lfs, &file, buffer, 8) => 8; lfs_file_read(&lfs, &file[0], buffer, 8) => 8;
memcmp(buffer, "bonjour\n", 8) => 0; memcmp(buffer, "bonjour\n", 8) => 0;
lfs_file_read(&lfs, &file, buffer, 6) => 6; lfs_file_read(&lfs, &file[0], buffer, 6) => 6;
memcmp(buffer, "ohayo\n", 6) => 0; memcmp(buffer, "ohayo\n", 6) => 0;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
scripts/results.py echo "--- Results ---"
tests/stats.py

View File

@@ -1,16 +1,14 @@
#!/bin/bash #!/bin/bash
set -eu set -eu
export TEST_FILE=$0
trap 'export TEST_LINE=$LINENO' DEBUG
echo "=== Orphan tests ===" echo "=== Orphan tests ==="
rm -rf blocks rm -rf blocks
scripts/test.py << TEST tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0; lfs_format(&lfs, &cfg) => 0;
TEST TEST
echo "--- Orphan test ---" echo "--- Orphan test ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "parent") => 0; lfs_mkdir(&lfs, "parent") => 0;
lfs_mkdir(&lfs, "parent/orphan") => 0; lfs_mkdir(&lfs, "parent/orphan") => 0;
@@ -19,8 +17,8 @@ scripts/test.py << TEST
TEST TEST
# corrupt most recent commit, this should be the update to the previous # corrupt most recent commit, this should be the update to the previous
# linked-list entry and should orphan the child # linked-list entry and should orphan the child
scripts/corrupt.py tests/corrupt.py
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT; lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT;
@@ -43,4 +41,5 @@ scripts/test.py << TEST
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
scripts/results.py echo "--- Results ---"
tests/stats.py

View File

@@ -1,15 +1,13 @@
#!/bin/bash #!/bin/bash
set -eu set -eu
export TEST_FILE=$0
trap 'export TEST_LINE=$LINENO' DEBUG
echo "=== Path tests ===" echo "=== Path tests ==="
rm -rf blocks rm -rf blocks
scripts/test.py << TEST tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0; lfs_format(&lfs, &cfg) => 0;
TEST TEST
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "tea") => 0; lfs_mkdir(&lfs, "tea") => 0;
lfs_mkdir(&lfs, "coffee") => 0; lfs_mkdir(&lfs, "coffee") => 0;
@@ -27,7 +25,7 @@ scripts/test.py << TEST
TEST TEST
echo "--- Root path tests ---" echo "--- Root path tests ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_stat(&lfs, "tea/hottea", &info) => 0; lfs_stat(&lfs, "tea/hottea", &info) => 0;
strcmp(info.name, "hottea") => 0; strcmp(info.name, "hottea") => 0;
@@ -41,7 +39,7 @@ scripts/test.py << TEST
TEST TEST
echo "--- Redundant slash path tests ---" echo "--- Redundant slash path tests ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_stat(&lfs, "/tea/hottea", &info) => 0; lfs_stat(&lfs, "/tea/hottea", &info) => 0;
strcmp(info.name, "hottea") => 0; strcmp(info.name, "hottea") => 0;
@@ -57,7 +55,7 @@ scripts/test.py << TEST
TEST TEST
echo "--- Dot path tests ---" echo "--- Dot path tests ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_stat(&lfs, "./tea/hottea", &info) => 0; lfs_stat(&lfs, "./tea/hottea", &info) => 0;
strcmp(info.name, "hottea") => 0; strcmp(info.name, "hottea") => 0;
@@ -75,7 +73,7 @@ scripts/test.py << TEST
TEST TEST
echo "--- Dot dot path tests ---" echo "--- Dot dot path tests ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_stat(&lfs, "coffee/../tea/hottea", &info) => 0; lfs_stat(&lfs, "coffee/../tea/hottea", &info) => 0;
strcmp(info.name, "hottea") => 0; strcmp(info.name, "hottea") => 0;
@@ -93,7 +91,7 @@ scripts/test.py << TEST
TEST TEST
echo "--- Trailing dot path tests ---" echo "--- Trailing dot path tests ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_stat(&lfs, "tea/hottea/", &info) => 0; lfs_stat(&lfs, "tea/hottea/", &info) => 0;
strcmp(info.name, "hottea") => 0; strcmp(info.name, "hottea") => 0;
@@ -109,7 +107,7 @@ scripts/test.py << TEST
TEST TEST
echo "--- Root dot dot path tests ---" echo "--- Root dot dot path tests ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_stat(&lfs, "coffee/../../../../../../tea/hottea", &info) => 0; lfs_stat(&lfs, "coffee/../../../../../../tea/hottea", &info) => 0;
strcmp(info.name, "hottea") => 0; strcmp(info.name, "hottea") => 0;
@@ -121,82 +119,43 @@ scripts/test.py << TEST
TEST TEST
echo "--- Root tests ---" echo "--- Root tests ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_stat(&lfs, "/", &info) => 0; lfs_stat(&lfs, "/", &info) => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
strcmp(info.name, "/") => 0; strcmp(info.name, "/") => 0;
lfs_mkdir(&lfs, "/") => LFS_ERR_EXIST; lfs_mkdir(&lfs, "/") => LFS_ERR_EXIST;
lfs_file_open(&lfs, &file, "/", LFS_O_WRONLY | LFS_O_CREAT) lfs_file_open(&lfs, &file[0], "/", LFS_O_WRONLY | LFS_O_CREAT)
=> LFS_ERR_ISDIR; => LFS_ERR_ISDIR;
// more corner cases
lfs_remove(&lfs, "") => LFS_ERR_INVAL;
lfs_remove(&lfs, ".") => LFS_ERR_INVAL;
lfs_remove(&lfs, "..") => LFS_ERR_INVAL;
lfs_remove(&lfs, "/") => LFS_ERR_INVAL;
lfs_remove(&lfs, "//") => LFS_ERR_INVAL;
lfs_remove(&lfs, "./") => LFS_ERR_INVAL;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Sketchy path tests ---" echo "--- Sketchy path tests ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "dirt/ground") => LFS_ERR_NOENT; lfs_mkdir(&lfs, "dirt/ground") => LFS_ERR_NOENT;
lfs_mkdir(&lfs, "dirt/ground/earth") => LFS_ERR_NOENT; lfs_mkdir(&lfs, "dirt/ground/earth") => LFS_ERR_NOENT;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Superblock conflict test ---"
scripts/test.py << TEST
lfs_mount(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "littlefs") => 0;
lfs_remove(&lfs, "littlefs") => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Max path test ---" echo "--- Max path test ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
memset(path, 'w', LFS_NAME_MAX+1); memset(buffer, 'w', LFS_NAME_MAX+1);
path[LFS_NAME_MAX+2] = '\0'; buffer[LFS_NAME_MAX+2] = '\0';
lfs_mkdir(&lfs, path) => LFS_ERR_NAMETOOLONG; lfs_mkdir(&lfs, (char*)buffer) => LFS_ERR_NAMETOOLONG;
lfs_file_open(&lfs, &file, path, lfs_file_open(&lfs, &file[0], (char*)buffer,
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NAMETOOLONG; LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NAMETOOLONG;
memcpy(path, "coffee/", strlen("coffee/")); memcpy(buffer, "coffee/", strlen("coffee/"));
memset(path+strlen("coffee/"), 'w', LFS_NAME_MAX+1); memset(buffer+strlen("coffee/"), 'w', LFS_NAME_MAX+1);
path[strlen("coffee/")+LFS_NAME_MAX+2] = '\0'; buffer[strlen("coffee/")+LFS_NAME_MAX+2] = '\0';
lfs_mkdir(&lfs, path) => LFS_ERR_NAMETOOLONG; lfs_mkdir(&lfs, (char*)buffer) => LFS_ERR_NAMETOOLONG;
lfs_file_open(&lfs, &file, path, lfs_file_open(&lfs, &file[0], (char*)buffer,
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NAMETOOLONG; LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NAMETOOLONG;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Really big path test ---" echo "--- Results ---"
scripts/test.py << TEST tests/stats.py
lfs_mount(&lfs, &cfg) => 0;
memset(path, 'w', LFS_NAME_MAX);
path[LFS_NAME_MAX] = '\0';
lfs_mkdir(&lfs, path) => 0;
lfs_remove(&lfs, path) => 0;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_remove(&lfs, path) => 0;
memcpy(path, "coffee/", strlen("coffee/"));
memset(path+strlen("coffee/"), 'w', LFS_NAME_MAX);
path[strlen("coffee/")+LFS_NAME_MAX] = '\0';
lfs_mkdir(&lfs, path) => 0;
lfs_remove(&lfs, path) => 0;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_remove(&lfs, path) => 0;
lfs_unmount(&lfs) => 0;
TEST
scripts/results.py

View File

@@ -1,431 +1,361 @@
#!/bin/bash #!/bin/bash
set -eu set -eu
export TEST_FILE=$0
trap 'export TEST_LINE=$LINENO' DEBUG
echo "=== Seek tests ==="
SMALLSIZE=4 SMALLSIZE=4
MEDIUMSIZE=128 MEDIUMSIZE=128
LARGESIZE=132 LARGESIZE=132
echo "=== Seek tests ==="
rm -rf blocks rm -rf blocks
scripts/test.py << TEST tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0; lfs_format(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "hello") => 0; lfs_mkdir(&lfs, "hello") => 0;
for (int i = 0; i < $LARGESIZE; i++) { for (int i = 0; i < $LARGESIZE; i++) {
sprintf(path, "hello/kitty%03d", i); sprintf((char*)buffer, "hello/kitty%d", i);
lfs_file_open(&lfs, &file, path, lfs_file_open(&lfs, &file[0], (char*)buffer,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
lfs_size_t size = strlen("kittycatcat"); size = strlen("kittycatcat");
memcpy(buffer, "kittycatcat", size); memcpy(buffer, "kittycatcat", size);
for (int j = 0; j < $LARGESIZE; j++) { for (int j = 0; j < $LARGESIZE; j++) {
lfs_file_write(&lfs, &file, buffer, size); lfs_file_write(&lfs, &file[0], buffer, size);
} }
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Simple dir seek ---" echo "--- Simple dir seek ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "hello") => 0; lfs_dir_open(&lfs, &dir[0], "hello") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
lfs_soff_t pos; lfs_soff_t pos;
int i; int i;
for (i = 0; i < $SMALLSIZE; i++) { for (i = 0; i < $SMALLSIZE; i++) {
sprintf(path, "kitty%03d", i); sprintf((char*)buffer, "kitty%d", i);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, path) => 0; strcmp(info.name, (char*)buffer) => 0;
pos = lfs_dir_tell(&lfs, &dir); pos = lfs_dir_tell(&lfs, &dir[0]);
} }
pos >= 0 => 1; pos >= 0 => 1;
lfs_dir_seek(&lfs, &dir, pos) => 0; lfs_dir_seek(&lfs, &dir[0], pos) => 0;
sprintf(path, "kitty%03d", i); sprintf((char*)buffer, "kitty%d", i);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, path) => 0; strcmp(info.name, (char*)buffer) => 0;
lfs_dir_rewind(&lfs, &dir) => 0; lfs_dir_rewind(&lfs, &dir[0]) => 0;
sprintf(path, "kitty%03d", 0); sprintf((char*)buffer, "kitty%d", 0);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, path) => 0; strcmp(info.name, (char*)buffer) => 0;
lfs_dir_seek(&lfs, &dir, pos) => 0; lfs_dir_seek(&lfs, &dir[0], pos) => 0;
sprintf(path, "kitty%03d", i); sprintf((char*)buffer, "kitty%d", i);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, path) => 0; strcmp(info.name, (char*)buffer) => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Large dir seek ---" echo "--- Large dir seek ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir, "hello") => 0; lfs_dir_open(&lfs, &dir[0], "hello") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
lfs_soff_t pos; lfs_soff_t pos;
int i; int i;
for (i = 0; i < $MEDIUMSIZE; i++) { for (i = 0; i < $MEDIUMSIZE; i++) {
sprintf(path, "kitty%03d", i); sprintf((char*)buffer, "kitty%d", i);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, path) => 0; strcmp(info.name, (char*)buffer) => 0;
pos = lfs_dir_tell(&lfs, &dir); pos = lfs_dir_tell(&lfs, &dir[0]);
} }
pos >= 0 => 1; pos >= 0 => 1;
lfs_dir_seek(&lfs, &dir, pos) => 0; lfs_dir_seek(&lfs, &dir[0], pos) => 0;
sprintf(path, "kitty%03d", i); sprintf((char*)buffer, "kitty%d", i);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, path) => 0; strcmp(info.name, (char*)buffer) => 0;
lfs_dir_rewind(&lfs, &dir) => 0; lfs_dir_rewind(&lfs, &dir[0]) => 0;
sprintf(path, "kitty%03d", 0); sprintf((char*)buffer, "kitty%d", 0);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, path) => 0; strcmp(info.name, (char*)buffer) => 0;
lfs_dir_seek(&lfs, &dir, pos) => 0; lfs_dir_seek(&lfs, &dir[0], pos) => 0;
sprintf(path, "kitty%03d", i); sprintf((char*)buffer, "kitty%d", i);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, path) => 0; strcmp(info.name, (char*)buffer) => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Simple file seek ---" echo "--- Simple file seek ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "hello/kitty042", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file[0], "hello/kitty42", LFS_O_RDONLY) => 0;
lfs_soff_t pos; lfs_soff_t pos;
lfs_size_t size = strlen("kittycatcat"); size = strlen("kittycatcat");
for (int i = 0; i < $SMALLSIZE; i++) { for (int i = 0; i < $SMALLSIZE; i++) {
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
pos = lfs_file_tell(&lfs, &file); pos = lfs_file_tell(&lfs, &file[0]);
} }
pos >= 0 => 1; pos >= 0 => 1;
lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos; lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
lfs_file_rewind(&lfs, &file) => 0; lfs_file_rewind(&lfs, &file[0]) => 0;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
lfs_file_seek(&lfs, &file, 0, LFS_SEEK_CUR) => size; lfs_file_seek(&lfs, &file[0], 0, LFS_SEEK_CUR) => size;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
lfs_file_seek(&lfs, &file, size, LFS_SEEK_CUR) => 3*size; lfs_file_seek(&lfs, &file[0], size, LFS_SEEK_CUR) => 3*size;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos; lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
lfs_file_seek(&lfs, &file, -size, LFS_SEEK_CUR) => pos; lfs_file_seek(&lfs, &file[0], -size, LFS_SEEK_CUR) => pos;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
lfs_file_seek(&lfs, &file, -size, LFS_SEEK_END) >= 0 => 1; lfs_file_seek(&lfs, &file[0], -size, LFS_SEEK_END) >= 0 => 1;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
size = lfs_file_size(&lfs, &file); size = lfs_file_size(&lfs, &file[0]);
lfs_file_seek(&lfs, &file, 0, LFS_SEEK_CUR) => size; lfs_file_seek(&lfs, &file[0], 0, LFS_SEEK_CUR) => size;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Large file seek ---" echo "--- Large file seek ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "hello/kitty042", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file[0], "hello/kitty42", LFS_O_RDONLY) => 0;
lfs_soff_t pos; lfs_soff_t pos;
lfs_size_t size = strlen("kittycatcat"); size = strlen("kittycatcat");
for (int i = 0; i < $MEDIUMSIZE; i++) { for (int i = 0; i < $MEDIUMSIZE; i++) {
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
pos = lfs_file_tell(&lfs, &file); pos = lfs_file_tell(&lfs, &file[0]);
} }
pos >= 0 => 1; pos >= 0 => 1;
lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos; lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
lfs_file_rewind(&lfs, &file) => 0; lfs_file_rewind(&lfs, &file[0]) => 0;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
lfs_file_seek(&lfs, &file, 0, LFS_SEEK_CUR) => size; lfs_file_seek(&lfs, &file[0], 0, LFS_SEEK_CUR) => size;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
lfs_file_seek(&lfs, &file, size, LFS_SEEK_CUR) => 3*size; lfs_file_seek(&lfs, &file[0], size, LFS_SEEK_CUR) => 3*size;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos; lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
lfs_file_seek(&lfs, &file, -size, LFS_SEEK_CUR) => pos; lfs_file_seek(&lfs, &file[0], -size, LFS_SEEK_CUR) => pos;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
lfs_file_seek(&lfs, &file, -size, LFS_SEEK_END) >= 0 => 1; lfs_file_seek(&lfs, &file[0], -size, LFS_SEEK_END) >= 0 => 1;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
size = lfs_file_size(&lfs, &file); size = lfs_file_size(&lfs, &file[0]);
lfs_file_seek(&lfs, &file, 0, LFS_SEEK_CUR) => size; lfs_file_seek(&lfs, &file[0], 0, LFS_SEEK_CUR) => size;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Simple file seek and write ---" echo "--- Simple file seek and write ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "hello/kitty042", LFS_O_RDWR) => 0; lfs_file_open(&lfs, &file[0], "hello/kitty42", LFS_O_RDWR) => 0;
lfs_soff_t pos; lfs_soff_t pos;
lfs_size_t size = strlen("kittycatcat"); size = strlen("kittycatcat");
for (int i = 0; i < $SMALLSIZE; i++) { for (int i = 0; i < $SMALLSIZE; i++) {
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
pos = lfs_file_tell(&lfs, &file); pos = lfs_file_tell(&lfs, &file[0]);
} }
pos >= 0 => 1; pos >= 0 => 1;
memcpy(buffer, "doggodogdog", size); memcpy(buffer, "doggodogdog", size);
lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos; lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos;
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file[0], buffer, size) => size;
lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos; lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "doggodogdog", size) => 0; memcmp(buffer, "doggodogdog", size) => 0;
lfs_file_rewind(&lfs, &file) => 0; lfs_file_rewind(&lfs, &file[0]) => 0;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos; lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "doggodogdog", size) => 0; memcmp(buffer, "doggodogdog", size) => 0;
lfs_file_seek(&lfs, &file, -size, LFS_SEEK_END) >= 0 => 1; lfs_file_seek(&lfs, &file[0], -size, LFS_SEEK_END) >= 0 => 1;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
size = lfs_file_size(&lfs, &file); size = lfs_file_size(&lfs, &file[0]);
lfs_file_seek(&lfs, &file, 0, LFS_SEEK_CUR) => size; lfs_file_seek(&lfs, &file[0], 0, LFS_SEEK_CUR) => size;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Large file seek and write ---" echo "--- Large file seek and write ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "hello/kitty042", LFS_O_RDWR) => 0; lfs_file_open(&lfs, &file[0], "hello/kitty42", LFS_O_RDWR) => 0;
lfs_soff_t pos; lfs_soff_t pos;
lfs_size_t size = strlen("kittycatcat"); size = strlen("kittycatcat");
for (int i = 0; i < $MEDIUMSIZE; i++) { for (int i = 0; i < $MEDIUMSIZE; i++) {
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file[0], buffer, size) => size;
if (i != $SMALLSIZE) { if (i != $SMALLSIZE) {
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
} }
pos = lfs_file_tell(&lfs, &file); pos = lfs_file_tell(&lfs, &file[0]);
} }
pos >= 0 => 1; pos >= 0 => 1;
memcpy(buffer, "doggodogdog", size); memcpy(buffer, "doggodogdog", size);
lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos; lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos;
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file[0], buffer, size) => size;
lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos; lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "doggodogdog", size) => 0; memcmp(buffer, "doggodogdog", size) => 0;
lfs_file_rewind(&lfs, &file) => 0; lfs_file_rewind(&lfs, &file[0]) => 0;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos; lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "doggodogdog", size) => 0; memcmp(buffer, "doggodogdog", size) => 0;
lfs_file_seek(&lfs, &file, -size, LFS_SEEK_END) >= 0 => 1; lfs_file_seek(&lfs, &file[0], -size, LFS_SEEK_END) >= 0 => 1;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
size = lfs_file_size(&lfs, &file); size = lfs_file_size(&lfs, &file[0]);
lfs_file_seek(&lfs, &file, 0, LFS_SEEK_CUR) => size; lfs_file_seek(&lfs, &file[0], 0, LFS_SEEK_CUR) => size;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Boundary seek and write ---" echo "--- Boundary seek and write ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "hello/kitty042", LFS_O_RDWR) => 0; lfs_file_open(&lfs, &file[0], "hello/kitty42", LFS_O_RDWR) => 0;
lfs_size_t size = strlen("hedgehoghog"); size = strlen("hedgehoghog");
const lfs_soff_t offsets[] = {512, 1020, 513, 1021, 511, 1019}; const lfs_soff_t offsets[] = {512, 1020, 513, 1021, 511, 1019};
for (unsigned i = 0; i < sizeof(offsets) / sizeof(offsets[0]); i++) { for (int i = 0; i < sizeof(offsets) / sizeof(offsets[0]); i++) {
lfs_soff_t off = offsets[i]; lfs_soff_t off = offsets[i];
memcpy(buffer, "hedgehoghog", size); memcpy(buffer, "hedgehoghog", size);
lfs_file_seek(&lfs, &file, off, LFS_SEEK_SET) => off; lfs_file_seek(&lfs, &file[0], off, LFS_SEEK_SET) => off;
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file[0], buffer, size) => size;
lfs_file_seek(&lfs, &file, off, LFS_SEEK_SET) => off; lfs_file_seek(&lfs, &file[0], off, LFS_SEEK_SET) => off;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "hedgehoghog", size) => 0; memcmp(buffer, "hedgehoghog", size) => 0;
lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0; lfs_file_seek(&lfs, &file[0], 0, LFS_SEEK_SET) => 0;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
lfs_file_sync(&lfs, &file) => 0; lfs_file_sync(&lfs, &file[0]) => 0;
} }
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Out-of-bounds seek ---" echo "--- Out-of-bounds seek ---"
scripts/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "hello/kitty042", LFS_O_RDWR) => 0; lfs_file_open(&lfs, &file[0], "hello/kitty42", LFS_O_RDWR) => 0;
lfs_size_t size = strlen("kittycatcat"); size = strlen("kittycatcat");
lfs_file_size(&lfs, &file) => $LARGESIZE*size; lfs_file_size(&lfs, &file[0]) => $LARGESIZE*size;
lfs_file_seek(&lfs, &file, ($LARGESIZE+$SMALLSIZE)*size, lfs_file_seek(&lfs, &file[0], ($LARGESIZE+$SMALLSIZE)*size,
LFS_SEEK_SET) => ($LARGESIZE+$SMALLSIZE)*size; LFS_SEEK_SET) => ($LARGESIZE+$SMALLSIZE)*size;
lfs_file_read(&lfs, &file, buffer, size) => 0; lfs_file_read(&lfs, &file[0], buffer, size) => 0;
memcpy(buffer, "porcupineee", size); memcpy(buffer, "porcupineee", size);
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file[0], buffer, size) => size;
lfs_file_seek(&lfs, &file, ($LARGESIZE+$SMALLSIZE)*size, lfs_file_seek(&lfs, &file[0], ($LARGESIZE+$SMALLSIZE)*size,
LFS_SEEK_SET) => ($LARGESIZE+$SMALLSIZE)*size; LFS_SEEK_SET) => ($LARGESIZE+$SMALLSIZE)*size;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "porcupineee", size) => 0; memcmp(buffer, "porcupineee", size) => 0;
lfs_file_seek(&lfs, &file, $LARGESIZE*size, lfs_file_seek(&lfs, &file[0], $LARGESIZE*size,
LFS_SEEK_SET) => $LARGESIZE*size; LFS_SEEK_SET) => $LARGESIZE*size;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file[0], 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, -(($LARGESIZE+$SMALLSIZE)*size), lfs_file_seek(&lfs, &file[0], -(($LARGESIZE+$SMALLSIZE)*size),
LFS_SEEK_CUR) => LFS_ERR_INVAL; LFS_SEEK_CUR) => LFS_ERR_INVAL;
lfs_file_tell(&lfs, &file) => ($LARGESIZE+1)*size; lfs_file_tell(&lfs, &file[0]) => ($LARGESIZE+1)*size;
lfs_file_seek(&lfs, &file, -(($LARGESIZE+2*$SMALLSIZE)*size), lfs_file_seek(&lfs, &file[0], -(($LARGESIZE+2*$SMALLSIZE)*size),
LFS_SEEK_END) => LFS_ERR_INVAL; LFS_SEEK_END) => LFS_ERR_INVAL;
lfs_file_tell(&lfs, &file) => ($LARGESIZE+1)*size; lfs_file_tell(&lfs, &file[0]) => ($LARGESIZE+1)*size;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Inline write and seek ---" echo "--- Results ---"
for SIZE in $SMALLSIZE $MEDIUMSIZE $LARGESIZE tests/stats.py
do
scripts/test.py << TEST
lfs_mount(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "hello/tinykitty$SIZE",
LFS_O_RDWR | LFS_O_CREAT) => 0;
int j = 0;
int k = 0;
memcpy(buffer, "abcdefghijklmnopqrstuvwxyz", 26);
for (unsigned i = 0; i < $SIZE; i++) {
lfs_file_write(&lfs, &file, &buffer[j++ % 26], 1) => 1;
lfs_file_tell(&lfs, &file) => i+1;
lfs_file_size(&lfs, &file) => i+1;
}
lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0;
lfs_file_tell(&lfs, &file) => 0;
lfs_file_size(&lfs, &file) => $SIZE;
for (unsigned i = 0; i < $SIZE; i++) {
uint8_t c;
lfs_file_read(&lfs, &file, &c, 1) => 1;
c => buffer[k++ % 26];
}
lfs_file_sync(&lfs, &file) => 0;
lfs_file_tell(&lfs, &file) => $SIZE;
lfs_file_size(&lfs, &file) => $SIZE;
lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0;
for (unsigned i = 0; i < $SIZE; i++) {
lfs_file_write(&lfs, &file, &buffer[j++ % 26], 1) => 1;
lfs_file_tell(&lfs, &file) => i+1;
lfs_file_size(&lfs, &file) => $SIZE;
lfs_file_sync(&lfs, &file) => 0;
lfs_file_tell(&lfs, &file) => i+1;
lfs_file_size(&lfs, &file) => $SIZE;
if (i < $SIZE-2) {
uint8_t c[3];
lfs_file_seek(&lfs, &file, -1, LFS_SEEK_CUR) => i;
lfs_file_read(&lfs, &file, &c, 3) => 3;
lfs_file_tell(&lfs, &file) => i+3;
lfs_file_size(&lfs, &file) => $SIZE;
lfs_file_seek(&lfs, &file, i+1, LFS_SEEK_SET) => i+1;
lfs_file_tell(&lfs, &file) => i+1;
lfs_file_size(&lfs, &file) => $SIZE;
}
}
lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0;
lfs_file_tell(&lfs, &file) => 0;
lfs_file_size(&lfs, &file) => $SIZE;
for (unsigned i = 0; i < $SIZE; i++) {
uint8_t c;
lfs_file_read(&lfs, &file, &c, 1) => 1;
c => buffer[k++ % 26];
}
lfs_file_sync(&lfs, &file) => 0;
lfs_file_tell(&lfs, &file) => $SIZE;
lfs_file_size(&lfs, &file) => $SIZE;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
TEST
done
scripts/results.py

View File

@@ -1,309 +1,111 @@
#!/bin/bash #!/bin/bash
set -eu set -eu
export TEST_FILE=$0
trap 'export TEST_LINE=$LINENO' DEBUG
echo "=== Truncate tests ==="
SMALLSIZE=32 SMALLSIZE=32
MEDIUMSIZE=2048 MEDIUMSIZE=2048
LARGESIZE=8192 LARGESIZE=8192
echo "=== Truncate tests ==="
rm -rf blocks rm -rf blocks
scripts/test.py << TEST tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0; lfs_format(&lfs, &cfg) => 0;
TEST TEST
echo "--- Simple truncate ---"
scripts/test.py << TEST
lfs_mount(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "baldynoop",
LFS_O_WRONLY | LFS_O_CREAT) => 0;
strcpy((char*)buffer, "hair");
lfs_size_t size = strlen((char*)buffer);
for (lfs_off_t j = 0; j < $LARGESIZE; j += size) {
lfs_file_write(&lfs, &file, buffer, size) => size;
}
lfs_file_size(&lfs, &file) => $LARGESIZE;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
TEST
scripts/test.py << TEST
lfs_mount(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "baldynoop", LFS_O_RDWR) => 0;
lfs_file_size(&lfs, &file) => $LARGESIZE;
lfs_file_truncate(&lfs, &file, $MEDIUMSIZE) => 0;
lfs_file_size(&lfs, &file) => $MEDIUMSIZE;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
TEST
scripts/test.py << TEST
lfs_mount(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "baldynoop", LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => $MEDIUMSIZE;
lfs_size_t size = strlen("hair");
for (lfs_off_t j = 0; j < $MEDIUMSIZE; j += size) {
lfs_file_read(&lfs, &file, buffer, size) => size;
memcmp(buffer, "hair", size) => 0;
}
lfs_file_read(&lfs, &file, buffer, size) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Truncate and read ---"
scripts/test.py << TEST
lfs_mount(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "baldyread",
LFS_O_WRONLY | LFS_O_CREAT) => 0;
strcpy((char*)buffer, "hair");
lfs_size_t size = strlen((char*)buffer);
for (lfs_off_t j = 0; j < $LARGESIZE; j += size) {
lfs_file_write(&lfs, &file, buffer, size) => size;
}
lfs_file_size(&lfs, &file) => $LARGESIZE;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
TEST
scripts/test.py << TEST
lfs_mount(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "baldyread", LFS_O_RDWR) => 0;
lfs_file_size(&lfs, &file) => $LARGESIZE;
lfs_file_truncate(&lfs, &file, $MEDIUMSIZE) => 0;
lfs_file_size(&lfs, &file) => $MEDIUMSIZE;
lfs_size_t size = strlen("hair");
for (lfs_off_t j = 0; j < $MEDIUMSIZE; j += size) {
lfs_file_read(&lfs, &file, buffer, size) => size;
memcmp(buffer, "hair", size) => 0;
}
lfs_file_read(&lfs, &file, buffer, size) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
TEST
scripts/test.py << TEST
lfs_mount(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "baldyread", LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => $MEDIUMSIZE;
lfs_size_t size = strlen("hair");
for (lfs_off_t j = 0; j < $MEDIUMSIZE; j += size) {
lfs_file_read(&lfs, &file, buffer, size) => size;
memcmp(buffer, "hair", size) => 0;
}
lfs_file_read(&lfs, &file, buffer, size) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Write, truncate, and read ---"
scripts/test.py << TEST
lfs_mount(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "sequence",
LFS_O_RDWR | LFS_O_CREAT | LFS_O_TRUNC) => 0;
lfs_size_t size = lfs.cfg->cache_size;
lfs_size_t qsize = size / 4;
uint8_t *wb = buffer;
uint8_t *rb = buffer + size;
for (lfs_off_t j = 0; j < size; ++j) {
wb[j] = j;
}
/* Spread sequence over size */
lfs_file_write(&lfs, &file, wb, size) => size;
lfs_file_size(&lfs, &file) => size;
lfs_file_tell(&lfs, &file) => size;
lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0;
lfs_file_tell(&lfs, &file) => 0;
/* Chop off the last quarter */
lfs_size_t trunc = size - qsize;
lfs_file_truncate(&lfs, &file, trunc) => 0;
lfs_file_tell(&lfs, &file) => 0;
lfs_file_size(&lfs, &file) => trunc;
/* Read should produce first 3/4 */
lfs_file_read(&lfs, &file, rb, size) => trunc;
memcmp(rb, wb, trunc) => 0;
/* Move to 1/4 */
lfs_file_size(&lfs, &file) => trunc;
lfs_file_seek(&lfs, &file, qsize, LFS_SEEK_SET) => qsize;
lfs_file_tell(&lfs, &file) => qsize;
/* Chop to 1/2 */
trunc -= qsize;
lfs_file_truncate(&lfs, &file, trunc) => 0;
lfs_file_tell(&lfs, &file) => qsize;
lfs_file_size(&lfs, &file) => trunc;
/* Read should produce second quarter */
lfs_file_read(&lfs, &file, rb, size) => trunc - qsize;
memcmp(rb, wb + qsize, trunc - qsize) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Truncate and write ---"
scripts/test.py << TEST
lfs_mount(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "baldywrite",
LFS_O_WRONLY | LFS_O_CREAT) => 0;
strcpy((char*)buffer, "hair");
lfs_size_t size = strlen((char*)buffer);
for (lfs_off_t j = 0; j < $LARGESIZE; j += size) {
lfs_file_write(&lfs, &file, buffer, size) => size;
}
lfs_file_size(&lfs, &file) => $LARGESIZE;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
TEST
scripts/test.py << TEST
lfs_mount(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "baldywrite", LFS_O_RDWR) => 0;
lfs_file_size(&lfs, &file) => $LARGESIZE;
lfs_file_truncate(&lfs, &file, $MEDIUMSIZE) => 0;
lfs_file_size(&lfs, &file) => $MEDIUMSIZE;
strcpy((char*)buffer, "bald");
lfs_size_t size = strlen((char*)buffer);
for (lfs_off_t j = 0; j < $MEDIUMSIZE; j += size) {
lfs_file_write(&lfs, &file, buffer, size) => size;
}
lfs_file_size(&lfs, &file) => $MEDIUMSIZE;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
TEST
scripts/test.py << TEST
lfs_mount(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file, "baldywrite", LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => $MEDIUMSIZE;
lfs_size_t size = strlen("bald");
for (lfs_off_t j = 0; j < $MEDIUMSIZE; j += size) {
lfs_file_read(&lfs, &file, buffer, size) => size;
memcmp(buffer, "bald", size) => 0;
}
lfs_file_read(&lfs, &file, buffer, size) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
TEST
# More aggressive general truncation tests
truncate_test() { truncate_test() {
STARTSIZES="$1" STARTSIZES="$1"
STARTSEEKS="$2" STARTSEEKS="$2"
HOTSIZES="$3" HOTSIZES="$3"
COLDSIZES="$4" COLDSIZES="$4"
scripts/test.py << TEST tests/test.py << TEST
static const lfs_off_t startsizes[] = {$STARTSIZES}; static const lfs_off_t startsizes[] = {$STARTSIZES};
static const lfs_off_t startseeks[] = {$STARTSEEKS}; static const lfs_off_t startseeks[] = {$STARTSEEKS};
static const lfs_off_t hotsizes[] = {$HOTSIZES}; static const lfs_off_t hotsizes[] = {$HOTSIZES};
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
for (unsigned i = 0; i < sizeof(startsizes)/sizeof(startsizes[0]); i++) { for (int i = 0; i < sizeof(startsizes)/sizeof(startsizes[0]); i++) {
sprintf(path, "hairyhead%d", i); sprintf((char*)buffer, "hairyhead%d", i);
lfs_file_open(&lfs, &file, path, lfs_file_open(&lfs, &file[0], (const char*)buffer,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
strcpy((char*)buffer, "hair"); strcpy((char*)buffer, "hair");
lfs_size_t size = strlen((char*)buffer); size = strlen((char*)buffer);
for (lfs_off_t j = 0; j < startsizes[i]; j += size) { for (int j = 0; j < startsizes[i]; j += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file[0], buffer, size) => size;
} }
lfs_file_size(&lfs, &file) => startsizes[i]; lfs_file_size(&lfs, &file[0]) => startsizes[i];
if (startseeks[i] != startsizes[i]) { if (startseeks[i] != startsizes[i]) {
lfs_file_seek(&lfs, &file, lfs_file_seek(&lfs, &file[0],
startseeks[i], LFS_SEEK_SET) => startseeks[i]; startseeks[i], LFS_SEEK_SET) => startseeks[i];
} }
lfs_file_truncate(&lfs, &file, hotsizes[i]) => 0; lfs_file_truncate(&lfs, &file[0], hotsizes[i]) => 0;
lfs_file_size(&lfs, &file) => hotsizes[i]; lfs_file_size(&lfs, &file[0]) => hotsizes[i];
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
scripts/test.py << TEST tests/test.py << TEST
static const lfs_off_t startsizes[] = {$STARTSIZES}; static const lfs_off_t startsizes[] = {$STARTSIZES};
static const lfs_off_t hotsizes[] = {$HOTSIZES}; static const lfs_off_t hotsizes[] = {$HOTSIZES};
static const lfs_off_t coldsizes[] = {$COLDSIZES}; static const lfs_off_t coldsizes[] = {$COLDSIZES};
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
for (unsigned i = 0; i < sizeof(startsizes)/sizeof(startsizes[0]); i++) { for (int i = 0; i < sizeof(startsizes)/sizeof(startsizes[0]); i++) {
sprintf(path, "hairyhead%d", i); sprintf((char*)buffer, "hairyhead%d", i);
lfs_file_open(&lfs, &file, path, LFS_O_RDWR) => 0; lfs_file_open(&lfs, &file[0], (const char*)buffer, LFS_O_RDWR) => 0;
lfs_file_size(&lfs, &file) => hotsizes[i]; lfs_file_size(&lfs, &file[0]) => hotsizes[i];
lfs_size_t size = strlen("hair"); size = strlen("hair");
lfs_off_t j = 0; int 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; lfs_file_read(&lfs, &file[0], 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; lfs_file_read(&lfs, &file[0], 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; lfs_file_truncate(&lfs, &file[0], coldsizes[i]) => 0;
lfs_file_size(&lfs, &file) => coldsizes[i]; lfs_file_size(&lfs, &file[0]) => coldsizes[i];
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file[0]) => 0;
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
scripts/test.py << TEST tests/test.py << TEST
static const lfs_off_t startsizes[] = {$STARTSIZES}; static const lfs_off_t startsizes[] = {$STARTSIZES};
static const lfs_off_t hotsizes[] = {$HOTSIZES}; static const lfs_off_t hotsizes[] = {$HOTSIZES};
static const lfs_off_t coldsizes[] = {$COLDSIZES}; static const lfs_off_t coldsizes[] = {$COLDSIZES};
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
for (unsigned i = 0; i < sizeof(startsizes)/sizeof(startsizes[0]); i++) { for (int i = 0; i < sizeof(startsizes)/sizeof(startsizes[0]); i++) {
sprintf(path, "hairyhead%d", i); sprintf((char*)buffer, "hairyhead%d", i);
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file[0], (const char*)buffer, LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => coldsizes[i]; lfs_file_size(&lfs, &file[0]) => coldsizes[i];
lfs_size_t size = strlen("hair"); size = strlen("hair");
lfs_off_t j = 0; int 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; lfs_file_read(&lfs, &file[0], 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; lfs_file_read(&lfs, &file[0], 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; lfs_file_close(&lfs, &file[0]) => 0;
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
@@ -352,4 +154,5 @@ truncate_test \
"2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE" \ "2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE" \
"2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE" "2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE"
scripts/results.py echo "--- Results ---"
tests/stats.py